Appearance
0031 — Code-First Design Workflow and Cross-Platform Delivery ​
Status: Accepted (2026-06-22) — amends ADR 0027; amended by owner correction 2026-06-22 — see §"Amendment: Responsive Web Layout Model" below
Date: 2026-06-22
ADO work item: AB#3237 (Story — Design system / @hch/ui built and adopted); Epic AB#3074
Deciders: Kristopher Turner (platform owner)
Context ​
ADR 0027 established Claude Design as the sole sanctioned UI tool and @hch/ui as the only import path for design tokens and components. It described a workflow where the Claude Design canvas is used to design screens, and "Handoff to Claude Code" deposits generated React code into packages/ui/src/. That framing implied Claude Design was the originating source of UI work — the canvas produces the design, the Handoff produces the code.
Practice revealed that framing is backwards for a code-first project:
- The Claude Design canvas and Handoff produce scaffold, not production code. The real components in
packages/ui/src/— typed, tested, accessible, integrated with the platform — are authored in code, not generated by a canvas export. Handoff output is a starting point that requires substantial refinement before it ships. - Web (React/Vite) is the verified, first-class delivery path. The React component tree, the
@hch/uitoken set, and the PWA install path on iOS and Android home screens are operational. Native SwiftUI (iOS) and React Native (React Native) cross-platform parity through the Claude Design pipeline has not been verified — the fidelity of the canvas → Handoff → native-code round-trip for those surfaces is unknown. - The Claude Design project has value as a mockup and communication tool, not as the primary design instrument.
@dsCardHTML cards mirrored into the project give the owner a shareable, browser-viewable representation of the design system and screen layouts. This is complementary to the code, not upstream of it.
This ADR refines the source-of-truth chain and cross-platform delivery posture established by ADR 0027.
Decision ​
Real code is the source of truth for the Heritage Virginia Community Hub UI. Components and design tokens are built in
packages/ui/src/first, authored to the canonical spec indocs/internal/design/claude-design.md §4. The Claude Design project (ceb2fb20-8346-4a74-8683-a96e4663b525) receives HTML mockup cards mirrored from the code via/design-sync, giving the owner shareable visual representations — but it is not upstream of the shipped components. Web (React/Vite + PWA,apps/web) is the primary, verified cross-platform delivery path. Native iOS SwiftUI and React Native fidelity through the Claude Design pipeline are not verified; no delivery commitment depends on them.
Amended source-of-truth chain ​
The corrected direction — replacing the canvas-first loop described in ADR 0027:
text
docs/internal/design/claude-design.md §4 ← canonical visual spec (colours, type, components)
│ author components to match §4
▼
packages/ui/src/* ← REAL runtime components (source of truth)
│ extract @dsCard HTML cards from real components
▼
packages/ui/design-system/*.html ── /design-sync ──► Claude Design project
(HTML @dsCard mockups — mirrors, not originals) (shareable mockups, owner view)
│
▼
apps/web/** apps/mobile/** ← import ONLY from @hch/ui; no inline stylesKey rules that follow from this chain:
packages/ui/src/is where component work happens first. Code review gates quality here.packages/ui/design-system/holds mirror cards — HTML representations of what the real components look like. They are regenerated from real components (not hand-written) once a component is stable. The/design-syncskill pushes them into the Claude Design project.- The Claude Design canvas is for the owner to view, share, and iterate on screen layouts. The Handoff is an optional shortcut for new scaffold — always reviewed and refined before merging.
claude-design.md §4is the visual spec. When a token changes, update §4 first, thenpackages/ui/src/tokens.ts, then regenerate thedesign-system/*.htmlcard, then re-sync.
Cross-platform delivery: web/PWA primary ​
| Surface | Status | Notes |
|---|---|---|
| Web (React/Vite) | Verified | Production-deployed to heritageva.app via Azure Static Web Apps |
| Web PWA (installable) | Verified | Installs to iOS and Android home screens from heritageva.app; uses the web React codebase; no App Store required |
| React Native (iOS + Android) | Code exists (apps/mobile) | Not yet verified end-to-end through the Claude Design pipeline; fidelity of @hch/ui token consumption in RN not confirmed |
| Native iOS (SwiftUI) | Not in scope | Heritage Virginia uses React Native + Expo (ADR 0002); SwiftUI is not a delivery surface |
PWA as the cross-platform path. A PWA installed from heritageva.app runs the same React codebase on every device. This gives iOS and Android users a home-screen app with offline capability and push notification support (where the platform and OS allow), without a separate native release pipeline. This is the verified cross-platform path today.
React Native is not deprecated. apps/mobile (React Native + Expo) is the eventual native app surface per ADR 0002 and ADR 0009/0014. However, no delivery commitment in the current build phase (Epic AB#3074) depends on the React Native surface being pixel-perfect with the Claude Design pipeline output. That verification is deferred to the iOS delivery phase (AB#3077).
Design workflow in practice ​
| Step | Who | Action |
|---|---|---|
| 1 | Developer / Claude Code | Author or update a component in packages/ui/src/. Match claude-design.md §4. |
| 2 | Developer / Claude Code | Extract the @dsCard HTML card for the component into packages/ui/design-system/. |
| 3 | Claude Code | Run /design-sync to push the card to the Claude Design project. Call register_assets after each batch; reload the project in the browser. |
| 4 | Owner (browser) | View / iterate layouts in claude.ai/design against the mirrored cards. |
| 5 | Owner (browser) | Optionally: "Handoff to Claude Code" for new scaffold. |
| 6 | Claude Code | If Handoff is used: accept, review, and refine — do not merge scaffold directly. Real code goes into packages/ui/src/; Handoff is a starting point. |
The @hch/ui import rule (unchanged from ADR 0027) ​
Every page and component in apps/web and apps/mobile must:
ts
import { Button, Card, Badge, colors, fonts } from '@hch/ui';No inline style props for values covered by @hch/ui. No palette constants duplicated outside packages/ui/src/tokens.ts. This rule is unchanged from ADR 0027.
Alternatives considered ​
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
| Code-first, mirror-to-Claude Design (chosen) | Code is the authority; mockups reflect real components; no fidelity gap | Requires card extraction step after each component change | — chosen |
| Canvas-first (ADR 0027 original framing) | Visual-first design; owner drives from the canvas | Handoff output needs significant refinement; Handoff fidelity for native surfaces unverified; creates two competing sources of truth | Amended by this ADR — framing was backwards for a code-first project |
| No design tool (code only) | Eliminates the sync step | Owner has no shareable visual representation; harder to validate layout intent before code review | Rejected — the Claude Design mirror remains valuable as a communication and validation tool |
| Native React Native as primary cross-platform | Single codebase for web + native | Native pipeline unverified through Claude Design; separate release cadence (App Store / Play Store); more complex CI | Deferred to the iOS/Android phases (ADR 0009, 0014); PWA covers the interim cross-platform need |
Consequences ​
Positive ​
- The code in
packages/ui/src/is authoritative — no risk that a Handoff overwrites a manually-refined component. - The Claude Design project always reflects what actually ships (via the mirror cards), not a designer's intention that may have drifted from the real component.
- Web + PWA provides real, working cross-platform delivery today, ahead of native app release.
- The owner has a shareable browser view of the design system without waiting for native app builds.
Negative / trade-offs ​
- The
@dsCardcard extraction step (after each component change) is an additional authoring discipline. If skipped, the Claude Design mirror drifts from the real components. - The PWA-as-cross-platform path covers the current phase; native app distribution (App Store / Play Store) is still required for the iOS and Android delivery phases.
Risks ​
- Mirror drift — real components evolve but
design-system/*.htmlcards are not regenerated. Mitigation: treat card regeneration as part of the definition of done for anytokens.tsor component change. Enforce in PR review. - React Native fidelity gap — when the native app delivery phase arrives,
@hch/uimay not render identically in React Native as in React DOM. Mitigation: verify component-by-component during the iOS phase (AB#3077); scope any gaps as tasks under that Epic.
Amendment: Responsive Web Layout Model (owner correction, 2026-06-22) ​
The original framing of this ADR — and the packages/ui/design-system/screens/*.html mockups it references — described the web app as rendered inside a fixed 390px × 844px phone-frame viewport. That model is wrong. The platform owner has clarified:
The platform is ONE responsive React web application — a single codebase that adapts across desktop, tablet, and phone via fluid layouts and CSS breakpoints. It is not a fixed phone frame.
Corrected layout model ​
| Breakpoint | Viewport | Primary navigation | Content |
|---|---|---|---|
| Phone | <640px | Bottom tab bar (5 tabs: Home / Watch & Listen / Calendar / Messages / Me) | Single column, full width |
| Tablet | 640–1023px | Bottom tab bar | Single column, max 640px centered |
| Desktop | ≥1024px | Left sidebar (220px, same 5 destinations) | Fluid column, max ~860px |
The five primary destinations (Home, Watch & Listen, Calendar, Messages, Me) are unchanged. The navigation pattern changes with the viewport: bottom tab bar on phone/tablet, left sidebar on desktop. The tab-bar.html component in packages/ui/design-system/ remains authoritative for the five destinations and the bottom-tab visual style; that style becomes the phone-breakpoint nav.
What this changes ​
| Aspect | Before (wrong) | After (corrected) |
|---|---|---|
<meta viewport> in screen HTML | width=390, initial-scale=1 (fixed phone) | width=device-width, initial-scale=1 (fluid) |
body width in screen CSS | width: 390px; min-height: 844px | min-height: 100vh (no fixed width) |
| Tab bar CSS | width: 390px; left: 0 | left: 0; right: 0 (spans full viewport) |
| Desktop layout | Phone frame centered on large screen | Left sidebar 220px + fluid content area |
AppLayout.tsx shell | Fixed-width column, bottom tab always visible | Responsive: sidebar at ≥1024px, tab bar at <1024px |
The packages/ui/design-system/screens/*.html files have been updated to match this model. The claude-design.md §4 "Layout & depth" section has been amended accordingly.
Responsive layout values — resolved by ADR 0033 ​
The three choices flagged as "proposals, owner sign-off required" are now locked decisions, ratified by ADR 0033 — Platform Foundation UI & View Inventory (2026-06-22). The values already implemented in AppLayout.tsx and the existing packages/ui/design-system/screens/*.html mockups are confirmed:
- Desktop breakpoint:
1024px— locked. - Desktop nav pattern: left sidebar, 220px fixed — locked.
- Max content width on desktop:
860px— locked.
These choices affect only the desktop breakpoint. The phone/tablet layout, five primary destinations, and tab-bar.html source of truth are unchanged.
References ​
- ADR 0027 — Web frontend & design-system tooling — amended by this ADR
- ADR 0002 — Mobile: React Native + Expo
- ADR 0008 — Platform composition
- ADR 0009 — iOS app delivery
- ADR 0014 — Android app delivery
- docs/internal/design/claude-design.md — canonical visual spec + full workflow
- docs/internal/design/claude-code-design-integration.md —
/designand/design-syncskill reference - ADO: Story AB#3237, Epic AB#3074 (Platform build)