Start here

ADR-0004: The design process

Status: accepted · 2026-10-18

Context

The human gates name a brand, a design system, lo-fi, hi-fi and a screenshot direction (ADR-0001, decision 15), and the design worker has a role file. Nothing says what each stage produces, what it needs first, or what "done" means. templates/app/design/ is empty.

The first app built this way followed one order and it held up:

  • Wireframes first, every screen and its states, with the flows between them, then a one-page clickable prototype built from the wireframe files. People tapped through it before anything was drawn in colour.
  • Hi-fi on real data. Every screen in every state (loading, empty, error, offline and the screen's own), drawn with numbers and names from example API responses that a check validates against the contract. Drawing with real data found contract gaps before any app code existed.
  • One contract per screen. Each screen lists what it shows and where each value comes from. A small script prints one screen's contract, its boards and the app files that build it, so an agent building the screen reads one thing.
  • Tokens in one source, read by the app code. Pictures alone drifted from the code.
  • Store screenshots last, drawn from approved hi-fi screens.

Where the order slipped (a screen built from a lo-fi board, a value drawn that no endpoint sends), the screen was built twice.

Decision

D1. Five stages, in this order. Each is produced by the design worker in design/ and closed by a human gate. A stage starts only when the stage before it has passed its gate.

# Stage Inputs Output files Gate
1 Brand brief PRD review (problem, audience, first value) design/brand/brief.md (name, voice, mark, do and don't), design/brand/mark.svg (light and dark), 3 to 5 name options with the domain check Brand and name
2 Design system Brand brief design/system/options/ (3 to 5 options, each a token set on two sample screens), then for the chosen one design/system/design-system.md (type, colour, space, radius, components and their states) and design/system/tokens.source.json Design system choice
3 Lo-fi PRD, design system, the draft contract (docs/api/openapi.yaml) design/lofi/screens.md (every screen, its states and flows), design/lofi/wireframes/<ID>.* (one per screen), a clickable prototype built from the wireframes, linked from screens.md Lo-fi approval
4 Hi-fi Lo-fi, tokens, example API responses (docs/api/examples/) design/hifi/<ID>/screen.md (contract, a board per state, tokens used), design/hifi/<ID>/bindings.md (data-binding map, docs/templates/data-binding-map.md), the boards Hi-fi approval, per screen
5 Screenshot direction Approved hi-fi screens design/screenshots/direction.md, 2 or 3 directions for the first 3 screenshots Screenshot direction

The templates for each output are in docs/templates/ (brand-brief.md, design-system.md, lofi-screens.md, hifi-screen.md, screenshot-direction.md). The scaffold is templates/app/design/.

D2. The files are the source. A board may be drawn in any tool or a hosted canvas, but its source or an export is saved under design/, so the design is versioned with the code and an agent can read it. A link alone is not an output.

D3. The screen list is the contract of what exists. design/lofi/screens.md names every screen with a stable ID (S01, S02, …), its states, its flows and its stage (lofi, hifi or approved, with the gate issue once approved). Every screen lists at least loading, empty, error and offline, plus its own states (ready, first-run, paywall…). A screen that is not in the list is not built.

D4. Hi-fi is every screen in every state, on real-looking data. Each state has a board. Every value on a board comes from an example API response in docs/api/examples/ that is valid for its endpoint, from local state, or from the device; the data-binding map says which, field by field. A value no endpoint sends is a contract change request first (agents/orchestrator.md, step 7), then a board. Every colour, size and font on a board is a token from tokens.source.json, named in the screen's "Tokens used". Every string on a board has a key and exists in en and zh-Hans; the ready board is also drawn in zh-Hans to catch overflow. The paywall's hi-fi waits for the pricing gate.

D5. No screen is built before its hi-fi gate. No screen is built in ios/ or android/ until its row in design/lofi/screens.md is approved with the gate issue. The orchestrator marks each screen task "blocked by" that gate issue. Work that draws no screen (models, the API client, providers, navigation shell) may start after the lo-fi gate.

D6. Gates. The orchestrator opens one gate issue per stage, with the options or the boards and the checklist from docs/checklists/design-gates.md. Hi-fi may be gated in batches (one issue for a flow); each screen passes or fails on its own. Only a human approves. The design worker then moves the stage forward in the files (for hi-fi: the screen's row becomes approved with #<gate issue>) in its next PR.

D7. A later design change runs design first. A change to an approved screen is a design issue, then a new hi-fi board for the changed states (the row goes back to hifi), then its gate, then the app change, blocked by that gate. A fix that brings the app back to the approved board needs no design issue. A token change is a design-system change: a design issue, new token values, and the review of every screen that uses them.

D8. One screenshot direction for both stores. Drawn from approved hi-fi screens and real-looking data. The full sets then follow docs/checklists/app-store-assets.md and google-play-assets.md.

D9. Design CI. node design/check.mjs runs in the app's CI and fails when: the token source does not match the shape @botgumi/design-tokens reads; a screen in the list lacks one of the four states or a wireframe; a screen at hifi or approved lacks its folder, screen.md, bindings.md, a board for each listed state, or names a token that is not in the source; an approved screen names no gate issue; a hi-fi folder is not in the list. Once the token generators in @botgumi/design-tokens land, the same CI generates the CSS, Swift and Kotlin outputs and builds them.

This amends ADR-0001, decision 15: the design gates close the stages above, in order.

Consequences

  • An app screen has one place to read before it is built: design/hifi/<ID>/, with its contract, boards, bindings and tokens. Review checks the code against it.
  • App work on screens starts later than it would from lo-fi, and the contract is found incomplete earlier.
  • Example API responses become a design input, so docs/api/examples/ must exist and be validated against docs/api/openapi.yaml before hi-fi starts. That check belongs to the backend and docs tracks.
  • A design change after approval costs a gate. That is the point: code never leads the design.
  • check.mjs checks structure, not taste. The gates check taste.
  • Follow-up: implement the token generators, then add generation to the design CI; a prototype builder that stitches design/lofi/wireframes/ into one page, when the first app needs one.