Human-Friendly ADR Detail Page UX — Hero + Decision Cards + Phase Strip Visualization
SummaryResolve text-density issues on the ADR detail page — zero above-fold information / decisions not scan-friendly / zero Phase flow visualization / no metrics
Key Decisions
Parser metadata utilization pattern adopted
Branch-render already-classified canonical sections + prTable in the detail view — no new data source required
TL;DR auto-extraction
Frontmatter tldr takes priority / otherwise auto-extract the first list item from the "Goals" section (stripMarkdown applied)
Decision card parsing
Regex extraction of - bold: text patterns from the decisions section → 2-column card grid
Phase strip based on PR table
Implementation section prTable rows → Phase label / PR link / one-line description / Lines horizontal scroll cards
PR table column dynamic discovery
Column structure varies per sprint → findColIndex candidate-keyword matching to dynamically determine Phase/Owner/Change/Lines positions
Palette pre-approval unnecessary (Oracle ruling)
components/adr/ domain components reuse existing tokens (surface-muted, surface-elevated, border, brand) → not components/ui/ shared
3-sprint split
161 (P0 Hero/cards), 162 (P1 Mermaid activation), 163 (P2 PR table separation + callout boxes)
Goals
- Resolve text-density issues on the ADR detail page — zero above-fold information / decisions not scan-friendly / zero Phase flow visualization / no metrics
- Leverage rich metadata already produced by parser.ts (canonical sections / PR table / Impact) as visual elements in the detail view
- Execute only the P0 core out of a 3-sprint split (161~163): Hero summary + Decision cards + Phase strip
Decisions
- Parser metadata utilization pattern adopted: Branch-render already-classified canonical sections + prTable in the detail view — no new data source required
- TL;DR auto-extraction: Frontmatter
tldrtakes priority / otherwise auto-extract the first list item from the "Goals" section (stripMarkdown applied) - Decision card parsing: Regex extraction of
- **bold**: textpatterns from the decisions section → 2-column card grid - Phase strip based on PR table: Implementation section prTable rows → Phase label / PR link / one-line description / Lines horizontal scroll cards
- PR table column dynamic discovery: Column structure varies per sprint →
findColIndexcandidate-keyword matching to dynamically determine Phase/Owner/Change/Lines positions - Palette pre-approval unnecessary (Oracle ruling):
components/adr/domain components reuse existing tokens (surface-muted,surface-elevated,border,brand) → notcomponents/ui/shared - 3-sprint split: 161 (P0 Hero/cards), 162 (P1 Mermaid activation), 163 (P2 PR table separation + callout boxes)
Implementation (1 PR squash merge pending, 3 commits, origin/main 78e17c4 → f79841e)
| PR | Phase | Owner | Change | Lines |
|---|---|---|---|---|
| (PR not yet created — squash merge pending) | B | architect + critic | Hero + Decision cards + Phase strip + parser extensions + i18n | +432 −3 |
Detailed Changes
- parser.ts (+142):
extractTldr()/extractDecisionItems()/extractPhaseEntries()— 3 extraction functions + helpers (stripMarkdown/findColIndex/safeCell/extractPrUrl). Critic R1 P2 resolution: Phase column guard (bogus card prevention) + Korean header (변경/라인/담당) support - types.ts (+20):
AdrDecision/AdrPhaseEntryinterfaces +AdrMeta.tldr/AdrDoc.decisions/AdrDoc.phases - adr-hero.tsx (+114): Hero area — TL;DR text + 4 metrics (Date/Impact/PR count/Lines). Critic R2 P2 resolution: comma-separated Lines normalization
- adr-decisions-grid.tsx (+50): Decisions 2-column card grid
- adr-phase-strip.tsx (+85): Phase horizontal scroll strip + PrLink component
- adr-detail-view.tsx (+6): Hero → PhaseStrip → DecisionsGrid → prose order integration
- i18n.ts (+18): 7 keys KR+EN (
heroTldr/heroPrCount/heroLines/heroDate/heroImpact/decisionsTitle/phaseStripTitle)
Verification
| Item | Result |
|---|---|
| tsc --noEmit | clean (0 errors) |
| npm run build | 247 pages static export success |
| Existing ADRs without frontmatter tldr | "Goals" section first list item auto-extraction fallback working |
| ADRs without decisions/implementation sections | null return → component not rendered (graceful) |
Critic R1 (Codex gpt-5.5, session 019e3e8f-cd3f-7443-a10c-af523eef6e6d) | P2 2 items (bogus Phase strip guard + Korean headers) → resolved |
Critic R2 (Codex gpt-5.5, session 019e3e93-b9e2-7f40-b93e-58636638ddce) | P2 1 item (comma Lines) → resolved, P3 1 item (escaped pipes) → deferred to Sprint 162 |
| doc-ref-lint | pending verification |
Branch Discipline ✅ 29 sprints of consecutive compliance
- New branch
feat/sprint-161-adr-ux-hero-cards+ Squash merge pending - 0 direct commits to main, 0
--no-verifyuses
New Patterns
- Parser metadata → detail view visualization pattern — Branch-render canonical sections/prTable/impact created by the parser in the detail view. Data already exists; only visualization added
- TL;DR auto-extraction fallback pattern — Frontmatter priority → Goals section first list item fallback. No modification needed for existing ADRs
- PR table column dynamic discovery pattern — Column structure differs per ADR. Candidate-keyword matching for dynamic position determination (Korean/English mixed support)
- Phase column guard pattern (Critic R1 P1 institutionalized) — Early return when Phase column absent. Bogus card prevention
- Critic R1 → R2 → R3 progressive convergence — R1 P2 2 items → R2 P2 1 item + P3 1 item (deferred). Progressive convergence with P0/P1 at 0
Related Documents
- sprint-160.md — Previous sprint, Critic R1/R2 pattern inheritance
- sprint-158.md — i18n bilingual obligation principle