Wireframes System
Status: Active
One config-driven wireframe per app section — real brand tokens, static-rendered (no CDN), deployed under /wireframes on the Cockpit. This is the design surface for aligning layout, hierarchy, and flow before app code. It is deliberately separate from the interactive ui_kits/mobile click-through kit.
The one rule: wireframes are grounded in the real code
The real components under packages/… are the single source of truth for what a screen is. Everything else — screen-blueprint.md, the kit *Screen.jsx mocks, these wireframes — is a subordinate representation that must track the code.
A wireframe built from a doc or a mock instead of the code caused a real drift incident: the Home wireframe was drawn as a "10-card feed" (a superseded design the
screen-blueprintstill described) when the app actually ships a 오늘/이번 주/이번 달 temporal briefing. The tripwire below exists so that can't happen silently again.
Build a section wireframe by READING the real components it mirrors — trace what the route actually renders (e.g. home-feed-screen.tsx → its views → SessionCard), not the obvious-named doc. See research-methodology.
The drift tripwire
Every section in scripts/build-wireframes.mjs declares the real files it reflects:
{ key: 'home', file: 'wireframes/home.jsx', component: 'HomeWireframe',
groundedIn: [
'packages/features/home/src/home-feed-screen.tsx',
'packages/app/src/presentation/components/sessions/session-card.tsx',
// …
] }On every build (yarn docs:wireframes, and docs:site:build inside docs:check):
- Hard-fail if a cited source no longer exists (moved/renamed ⇒ the grounding is broken). This fails the pre-push + CI gate.
- Warn if a cited source's content changed since the wireframe was last grounded — a prompt to re-verify the wireframe still reflects it.
The committed baseline of source hashes is .grounding.json. After re-verifying a board phone by phone against the real screen (list what the real screen renders top to bottom, list what the phone draws, diff them), accept the baseline for THAT board only:
REGROUND=home,notifications yarn docs:wireframesREGROUND=1 (accept everything) exists only for a first baseline. It is what let stale boards slip through on 2026-09-06: drift was accepted because the source files had changed in the same session, which is provenance, not verification. The owner then found the boards did not reflect the app. Provenance never justifies acceptance; a diff of phone versus screen does.
The four lanes
Every section carries a status in scripts/build-wireframes.mjs's SECTIONS array — 'current' | 'proposal' | 'decided' | 'superseded' — and that one field drives both the hub (/wireframes) and the top-bar Screens menu, which render the whole map as four lanes, in this order:
- For review —
status: 'proposal'. Open decisions the owner hasn't made yet. Each proposal declaresopen: ['…'](short strings) — the specific things still undecided — and the hub lists them under the board's blurb, unresolved. Approved — build queue —status: 'approved'(+approvedDate). The owner accepted the recommended path; the board is the build spec until its screens ship, then it flips todecided. Rendered between For review and Foundations only when non-empty. - Foundations — a fixed, hand-picked set (
components,detail-flat-language,session-card): the shared kit + the cross-cutting canon boards every other screen composes from. This is NOT derived fromstatus— notablydetail-flat-languageisstatus: 'decided'(ratified 2026-09-05) but stays here as the living spec rather than moving to Archive, because every other board still actively cites it as the current flat-page grammar. - Screens — the real app navigation cascade (
NAV, rooted at the 5 bottom tabs), pruned tostatus: 'current'nodes only. A non-current ancestor (a proposal, a decided/superseded board) is skipped without dropping its still-current children — they're promoted up so nothing shipped is ever hidden behind an undecided parent. A board withstale: true(its drawn grammar no longer matches the code, even though its content is otherwise current) carries a "stale — being redrawn" tag; it stays in this lane, it is not re-accepted blindly, and it is not archived — it needs a redraw, not a decision. - Archive —
status: 'decided'or'superseded'(minus whatever's already in Foundations), collapsed by default. Adecidedboard is tagged "shippeddecidedDate" — it's the historical decision record, kept for context, not a live spec. Asupersededboard is tagged "superseded →<successor title>" via itssupersededBykey, and its file moves toarchive/(see below) — it's dead weight kept only so the decision trail isn't lost.
The rule going forward: a superseded board moves to archive/ with supersededBy pointing at what replaced it; a proposal lists its open decisions so a reviewer sees exactly what's blocking it; a stale board is redrawn against the current code, never re-accepted (REGROUND=1) blindly just because the build warns. Every built page also carries a config-driven banner matching its lane — "For owner review — open: …" on a proposal, "Decided … — shipped; kept as the decision record" or "Archived — superseded by …" on a decided/superseded board — so the status is visible on the page itself, not only on the hub.
Adding or updating a section wireframe
- Read the real code the section renders (route → screen → components). Note the actual structure, section names, card anatomy, and states.
- Write/edit
wireframes/<section>.jsx— one config object → components, reusing the sharedui_kits/mobile/Primitives.jsx+_kit.jsx(WF*primitives + tokens) +colors_and_type.csstokens. Export the component onwindow. - Add/update the section entry in
scripts/build-wireframes.mjs, includinggroundedIn(the files you just read) and astatus— pickproposalif the owner hasn't decided,currentonce it ships (addstale: truelater if the code drifts out from under the drawing without a redraw yet),decidedonce a proposal is ratified (adddecidedDate), orsupersededonce something else replaces it (addsupersededBy: '<the successor's key>'andgit mvthe file intowireframes/archive/, updating itsfile:path — the URL/key never changes, only where the source lives). yarn docs:wireframes→ verify the render + the grounding manifest + that the section landed in the lane you expect on the hub. Deploy with the Cockpit (yarn docs:site:build→wrangler pages deploy).
Sections
| Section | File | Status |
|---|---|---|
| Home · 홈 | home.jsx | Faithful to home-feed-screen.tsx |
| Clubs · 클럽 | clubs.jsx | Consolidated (2026-08-01) — every club surface, one section. ui_kits/mobile/ClubSurfaces.jsx deleted (superseded, was never wired into any build). |
| Sessions · 경기 | — | Planned |
| Records · 기록 | — | Planned |
| Profile · 프로필 | — | Planned |
The full, current status of every one of the 40 sections lives in scripts/build-wireframes.mjs's SECTIONS array (the single source of truth) and on the hub (/wireframes) — this table is a historical sample, not maintained per-section; don't hand-update it when a status changes elsewhere.