ADR md → Human-Friendly HTML Dual Output Automation (blog integration + KR/EN UI + content i18n infra)
SummaryKeep ADR md files as LLM-friendly SSOT while automatically generating an HTML site that lets humans quickly grasp decision flow, impact, and context
Implementation Phases
Key Decisions
Build model
Integrate into blog/ Next.js 15 + MDX infrastructure as (adr) routing group (user-confirmed). Reuse single Docker image + nginx + k3s GitOps cycle — 0 new workflow files. ci.yml:132-134's blog paths filter already includes docs/adr/**
Scope
Extended (conversion + visualization + search + categories full package) — user-confirmed
PR bundling
4 PRs integrated in a single sprint (P1 / P2~P8 / P9 / P10) — inheriting Sprint 150/153/154 bundle pattern. Avoids inefficiency of 8 sequential PR merges with CI wait
i18n dimension 1 (UI)
User direct feedback ("ADR doesn't seem to work for both English and Korean") → P9 hotfix added immediately. Apply existing blog (ko)/+en/ pattern to ADR. /adr/ ↔ /en/adr/ routing + LocaleToggle + 50 dictionary keys
i18n dimension 2 (Content)
Explicit user requirement → P10 added. docs/adr-en/ separate directory (blog content/posts-en/ pattern) + loader locale extension + Claude API auto-translator + /stop workflow EN mandate
Goals
- Keep ADR md files as LLM-friendly SSOT while automatically generating an HTML site that lets humans quickly grasp decision flow, impact, and context
- 105 ADRs (8 permanent + 1 topic + 96 sprint) authored once → automatically converted via blog
(adr)routing group with visualization + search + Related ADR graph - Establish Sprint 152 seed #19 (KR/EN dual-language plan mandate) — UI i18n routing + content i18n infrastructure +
/stopworkflow obligation
Decisions
- Build model: Integrate into blog/ Next.js 15 + MDX infrastructure as
(adr)routing group (user-confirmed). Reuse single Docker image + nginx + k3s GitOps cycle — 0 new workflow files.ci.yml:132-134'sblogpaths filter already includesdocs/adr/** - Scope: Extended (conversion + visualization + search + categories full package) — user-confirmed
- PR bundling: 4 PRs integrated in a single sprint (P1 / P2~P8 / P9 / P10) — inheriting Sprint 150/153/154 bundle pattern. Avoids inefficiency of 8 sequential PR merges with CI wait
- i18n dimension 1 (UI): User direct feedback ("ADR doesn't seem to work for both English and Korean") → P9 hotfix added immediately. Apply existing blog
(ko)/+en/pattern to ADR./adr/↔/en/adr/routing + LocaleToggle + 50 dictionary keys - i18n dimension 2 (Content): Explicit user requirement → P10 added.
docs/adr-en/separate directory (blogcontent/posts-en/pattern) + loader locale extension + Claude API auto-translator +/stopworkflow EN mandate
Implementation (10 PRs squash merge, origin/main 9f1217a → 1ba57d6 + PR #262)
Workflow
Verification
- All 4 PRs CI fail 0, mergeStateStatus CLEAN ✅ (auto-merge flow)
npx tsc --noEmit— 0 errorsnpm run build— 244 static pages (KR 122 + EN 122, prior 31 → 244)node scripts/check-adr-conversion.mjs— 10 fixture pass + 105 ADRs parsed successfullynode scripts/check-adr-links.mjs blog/out/adr— 1,109 links, 0 brokennode scripts/check-adr-links.mjs blog/out/en/adr— 1,213 links, 0 brokennode scripts/check-doc-refs.mjs --include-untracked— 172 files, 0 broken refsnode scripts/check-adr-en-coverage.mjs --lint— 105 WARN (strict activation deferred to Sprint 158+)- Browser visual verification:
/adr/(index + timeline + cards) +/adr/sprints/156/(3-column TOC + body + meta sidebar + Related ADR mini-graph) +/en/adr/(English UI) +/en/adr/sprints/156/(KoreanOnlyBanner + Korean body) - Sprint 155 3-layer safety net (plan + pre-push + CI lint) effective on all sprint commits — 0 violations
Branch discipline ✅ 25 sprints consecutive compliance
All 4 PRs used new branches + Squash merge, 0 direct commits to main (since Sprint 134 violation).
New patterns
- User direct feedback → immediate hotfix cycle (inheriting Sprint 150~152 pattern) — UI i18n gap (P9), content i18n omission (P10) both addressed via separate PRs immediately. Plan-stage omissions recovered in real-time through user verification cycle
- Single sprint 4-PR bundle + auto-merge flow —
gh pr merge --squash --autoauto-merges on CI green. Avoids inefficiency of 8 sequential PR CI wait. Evolution of Sprint 150/153/154 bundle pattern - External directory static import (blog → docs/adr) —
path.resolve(process.cwd(), '..', 'docs', 'adr')+ explicitoutputFileTracingIncludes. Verified pattern for safely referencing external SSOT inoutput: 'export'static export environment - Fallback chain — no frontmatter + English section names — gray-matter failure gracefully degrades to body H1/dash-list/H2 pattern. sprint-62~87 English section alias mapping handles 90+ sprint ADRs + 8 permanent ADRs in single pipeline
hasEnTranslationflag + conditional KoreanOnlyBanner — natural English page when EN translation exists, Korean body + banner + original link when absent. Seamlessly supports gradual translation migration- Auto-translator infrastructure first → actual translation gradual —
translate-adr.mjsinfrastructure complete +/stopmandate + lint (advisory) in this sprint. 95-file batch translation immediately possible upon user API key availability. Infrastructure-first separation /stopworkflow KR+EN dual-write mandate self-bootstrap — Rule introduced this sprint (P10) immediately self-applied to this sprint's ADR creation. Meta-self-verification cycle (inheriting Sprint 154~155 pattern)
Related documents
- docs/adr/README.md — English directory guidance + auto-translator usage added
- docs/adr-en/README.md — English translation policy SSOT
- scripts/translate-adr.mjs — Claude API auto-translator
- scripts/check-adr-conversion.mjs — 10 fixture self-test
- scripts/check-adr-links.mjs — Build output link integrity
- scripts/check-adr-en-coverage.mjs — EN translation coverage lint
- sprint-152.md (KR) — Seed #19 (KR/EN dual mandate) established this sprint (EN version pending translation in Sprint 158+)
- sprint-156.md (KR) — Previous sprint, this sprint's starting point (
9f1217a) (EN version pending translation in Sprint 158+)