Appearance
Screen Coverage Mandate
This page is the FORWARD half. The reverse half is gated (2026-08-13)
This mandate governs designing a screen before it exists. It says nothing about whether an approved design was ever implemented — and on 2026-08-13 that gap measured nine approved merchant-mobile screens with zero implementation, two of them behind a main tab, with no artifact in the repo recording it. The Screen conformance ledger closes it: one row per approved screen, npm run check:screens in pre-commit and CI, and the unimplemented count printed on every run. Read it before starting implementation work; read this page before starting design work.
Coverage must now include screens for THREE user categories (2026-08-08)
This mandate pre-dates the three-user-category principle, so its screen inventory covers the merchant only. Three whole surfaces are missing from it and none has a design yet:
- The enterprise org-admin portal — a fourth Stack 1 tier that ADR-0011 does not contain.
- The consumer (individual-tier) dashboard — onboarding already branches to it (
stepsFor('individual')) and there is nothing on the other side. - The consumer ⇄ business context switcher — required the moment one person holds both.
Each goes through the full Claude Design process before implementation, specified in prose first (§ "A screen that does not exist yet goes through Claude Design first" on this page — moved here from CLAUDE.md on 2026-09-23, QRS-1288). Also retired from any coverage list: BioLink editor surfaces and the Studio website builder.
A governance rule and a copy-paste prompt for Claude Designs. It exists because early design output was leaning on generic screens and placeholder data. Every screen must be driven by the actual product requirements, not by assumptions.
How to use
Paste the block below into Claude Designs alongside the PDPR Design Prompt. When designing a specific screen, also paste that screen's brief — from its own per-feature spec if one exists, otherwise from Foundational Screen Prompts.
Per-feature specs are the current source of truth where they exist, because the foundational briefs were written against the retired SPA:
| Feature | Spec |
|---|---|
| Store / Catalogue | Store / Catalogue Spec |
| Public Setu Card (the customer-facing half) | Public Setu Card Spec |
| Consumer Marketplace (category 3, the whole consumer surface) | Consumer Marketplace Spec |
| Consumer identity + Marriage Biodata (context, round 1) | Consumer Context Prompt |
| Marriage Biodata editor - drawers and field controls (round 3) | Biodata editor drawer prompt |
| Marriage Biodata reader - photograph viewing and the opening block (round 4) | Biodata reader photo prompt |
| Admin Panel MVP - staff sign-in, Access control, Users, Leads, Overview (round 1) | Admin Panel round 1 prompt |
| Admin Panel MVP - what round 1 left open, and the owner's three decisions (round 2) | Admin Panel round 2 prompt |
| Admin Panel MVP - the last copy and presentation fixes (round 3) | Admin Panel round 3 prompt |
| Account holds - the public and account-holder views of a suspended or blocked account (round 1) | Account holds round 1 prompt |
| Jewellery daily rates & savings schemes (both sides) | Jewellery Rates & Schemes Spec |
| Onboarding (first-run) | Onboarding Experience Spec |
| Profile / Settings | Profile / Settings / Onboarding Spec |
| Affiliate program | Affiliate Program Spec |
| Direct seller vertical (agent journey + Meetings / Leads / Media Library modules) | Direct Seller Vertical Spec |
| Communication Hub (admin panel, WhatsApp channel mission control) | Communication Hub Spec |
⚠ A new spec is not done until it is registered. Add the page, add it to this table AND to Foundational Screen Prompts, and add it to the portal sidebar (.vitepress/config.mjs). npm run check:portal-nav fails on an unregistered page — see Quality gates § "A screen that does not exist yet goes through Claude Design first", step 3.
⚠ Extending a surface that already exists? Paste this block too
FEATURE CONTEXT WITHOUT PRODUCT CONTEXT PRODUCES A PARALLEL PRODUCT, EVERY TIME
Measured 2026-08-29 (QRS-913). The Marriage Biodata round-2 prompt gave excellent feature context — 14 answered questions, every state enumerated, a full disclosure model — and named prototype/consumer/ zero times, named not one reusable module, and never said "extend". It asked for "THE FIVE SCREENS, IN YOUR ORDER" and got five good screens in a parallel mini-app: prototype/my-qrsetu/ with its own ds-base.js, icons.js, image-slot.js, support.js, a biodata-core.js that never imports consumer-data.js, no navigation relationship to ConsumerHome.dc.html, and no entry in qr-registry.js — whose own header says a new code type is "a DATA ENTRY here and not a change to any screen."
Round 1 had understood it correctly. The round-2 prompt threw that frame away by replacing it with a screen list. A later prompt can lose context an earlier one established, so restate the product frame every round rather than assuming it carried.
Fill the bracketed values and paste alongside the PDPR block. Composing this from memory is what failed; the point of a block is that doing it right costs less than not.
text
YOU ARE EXTENDING AN EXISTING APPLICATION, NOT BUILDING A NEW ONE.
<FEATURE> is being added to the <SURFACE> app that already exists in this project. A person
using it must not be able to tell where the existing product ends and this feature begins.
STUDY THESE BEFORE PROPOSING ANYTHING. They are the product you are extending.
<folder>/ the folder this feature belongs in
<folder>/<Home>.dc.html the home surface and its navigation
<folder>/<data>.js the seed module, its tabs, sections and pure functions
<folder>/ds-base.js the shared base every screen here imports
<folder>/icons.js the icon set actually in use
<folder>/image-slot.js the image component and its geometry contract
<folder>/<prior-art>.dc.html the closest existing screen to what you are adding
<folder>/<domain>.prompt.md the persistent context for this surface
_ds/<design-system>/ tokens, styles and the component bundle
BEFORE ANY SCREEN, PRODUCE TWO LISTS.
REUSED every existing component, module, pattern, token and layout rule you will use
unchanged, naming the file.
NEW anything you must introduce, each with one sentence saying why the existing
pattern genuinely cannot carry it. A new pattern with no justification is a defect.
EVERY NEW SCREEN MUST HAVE A NAMED RELATIONSHIP to an existing screen, navigation path, user
state or workflow. A screen exists because of a journey, never because we need another screen.
PLACEMENT IS NOT INHERITANCE. Every domain folder here carries its own ds-base.js and
support.js, so a new folder placed beside them imports NOTHING unless you say so. Name the
modules to import. State where the files belong and argue for it.
Only introduce a new pattern when the use case genuinely requires it, and say why.The rule
Every feature in QRSETU must have a dedicated, approved design screen. These approved screens are the single source of truth for the product. All future implementation is driven directly from them. No assumptions based on generic screens, placeholder flows, or standard feature sets may be made unless they are explicitly documented.
markdown
# QRSETU SCREEN COVERAGE MANDATE (READ BEFORE DESIGNING ANY SCREEN)
1. Every QRSETU feature must have its own dedicated, approved design screen. The approved screens are
the single source of truth. All engineering implementation is built directly from them.
2. Do not invent screens, flows, fields, or feature sets. Design only what the provided requirements
document. Do not fall back on generic app patterns, placeholder flows, or a standard SaaS feature
set. QRSETU is a specific product with specific behavior.
3. Do not use placeholder or lorem data. Use the real field names, real labels, real steps, real
states, and real copy from the requirements. If a value is unknown, use a realistic QRSETU example
and mark it clearly as an example, do not fabricate a feature around it.
4. If a requirement is missing or ambiguous, stop and flag it as an open question. Do not assume a
behavior to fill the gap. A missing requirement is a question to ask, not a blank to guess.
5. Every screen must map to a real feature and a real route in the product, and must name that route
and its target component (see the handoff structure in the PDPR).
6. Design the complete screen, not just the happy path: include empty, loading, success, error,
permission, and edge-case states as defined for that screen.
7. Respect all global rules from the PDPR: no hardcoded colors (tokens only), the 3XL rounded corner
signature, Apple Human Interface influence, native mobile via Expo and an installed-app desktop
experience, mandatory light and dark, and no em dashes anywhere.
8. Priority order: design the core foundation first (landing, onboarding, authentication, default
dashboard, profile, settings, and the app shell), then move to individual feature screens. Do not
design a feature screen before its requirements are documented and approved.
If you would otherwise assume something, ask instead.Coverage expectation
A feature is not considered design-complete until it has an approved screen (or set of screens) for every state and every platform (mobile and desktop). Implementation must be replicable from those screens with pixel-perfect accuracy and no feature drift. See Design to Code Workflow for how screens map to code, and Foundational Screen Prompts for the first set of briefs.
⚠ Design-complete is not implementation-ready, and the two must not be conflated. A screen is only buildable when a read and write contract exists behind it. The per-screen join across design, client code and backend contract for the R1 launch vertical lives in the Festival Stall journey map & readiness matrix — measured 2026-08-11, when 18 of 19 vendor steps were designed and 4 were built end to end.
Priority foundation
Design these first, in this order, using the grounded briefs on the next page:
- Landing page
- Sign up
- Login and password reset
- Admin login
- Onboarding flow
- Default dashboard
- Profile
- Settings
- The authenticated app shell (navigation for mobile and desktop)
Any other foundational platform screen that already exists or is planned must also get a brief before its feature work begins.
Related assessments
- Desktop Journey Readiness - measured 2026-08-20: the merchant desktop console (16 screens) and desktop marketplace (3) are designed, the consumer desktop tier does not exist, and
check:screensis blind to all 19.
Receptionist (car dealership)
⭐ Receptionist screen specification — a design REQUEST, not a pull: 🧮 search space established 2026-08-24 across both ledgers plus five keyword variants, and no Receptionist screen exists in either Claude Design project.
⚠ One constraint outranks the rest and is worth reading even if you never touch this screen: the paper register it replaces takes about ten seconds, so it is the only screen in the vertical that can fail by being merely slow. If logging a walk-in is slower than the book, the receptionist keeps the book and every downstream dealership screen is fed by nothing.
📘 Two owner decisions are baked in: the receptionist captures and suggests, never assigns, and they get no personal Setu Card (the desk gets a reassignable touchpoint QR instead).
A screen that does not exist yet goes through Claude Design first (operating-manual text)
Provenance — moved from CLAUDE.md on 2026-09-23 (QRS-1288)
This is the verbatim text of CLAUDE.md § "A SCREEN THAT DOES NOT EXIST YET GOES THROUGH CLAUDE DESIGN FIRST" as of commit 00c1eca, relocated here under the context-architecture programme. Sentences of the form "this said X until [date]" are corrections recorded at the time they were made; the live rule is the corrected one. Retired vocabulary inside those corrections names what was retired and is not a live claim.
A SCREEN THAT DOES NOT EXIST YET GOES THROUGH CLAUDE DESIGN FIRST [ENFORCED — non-negotiable, 2026-08-07]
The rule above covers screens the design project already has. This covers the other case, which is the one that produces ad-hoc UI: a screen or workflow required by the product vision that has no design yet (the enterprise org-admin portal, the context switcher, the Feature Control matrix). "There is no design, so I will invent one" is exactly how the prototype acquired an Ad Manager and an in-house billing engine with no backend decision behind either.
⚠ The "consumer dashboard" was listed here as undesigned until 2026-08-13 and it is not. The design project has had a full eleven-screen
prototype/consumer/section all along, includingConsumerHome, which is what "consumer dashboard" was gesturing at. So the consumer work is a design PULL, not a design REQUEST, and sending a prompt for it would have generated a second, competing design for screens that already exist. This is the QRS-451 failure exactly — an absence proves nothing until the search space is established — and it survived here for four days after that lesson was written, in the very section that teaches it. Establish which of the two design projects a screen would live in before concluding it has no design.
The process, and it is the same for every missing screen — not just enterprise ones:
- Identify the missing screen/workflow and say so explicitly rather than filling the gap in code.
- Specify it fully in prose before asking for a design: purpose, the user categories it serves (see "Three user categories"), entry points, states (loading/empty/error/partial), data contract, permissions, and the proactive-value answer. A vague prompt produces a design that must be rejected, so this step is the work, not the paperwork.
- RECORD the specification as a portal page BEFORE sending it — and register it, which is the step that was missing until 2026-08-09 (QRS-448). All four parts are required; doing three of them produces an orphan that looks documented and is unreachable:
- Location + name:
documentation/portal/design-system/<feature>-spec.md. Match the existing siblings —onboarding-experience-spec.md,profile-settings-onboarding-spec.md,affiliate-program-spec.md. ⚠.prompt.mdis NOT the convention for a screen spec;template-authoring.prompt.mdis a manifest-authoring document and the only legitimate use of that suffix. - Sidebar: add it to
documentation/portal/.vitepress/config.mjs. A page absent from the sidebar is absent from the portal. - Cross-link: add it to the per-feature spec table in both
design-system/screen-coverage-mandate.mdanddesign-system/foundational-screens.md, which are the two pages the process tells a reader to start from. - Gated:
npm run check:portal-navfails on an orphaned page and on a dead nav link (pre-commit + CI, mutation-tested both directions).
Why this is spelled out rather than assumed. On 2026-08-09 the Store/Catalogue spec was written, placed in the right directory, and reported as documented — while being unreachable in the portal. The product owner caught it. The audit then found a second orphan,
design-system/brand-and-typography.md, which this file cites by name as its "full reference" for brand invariants. Steps 1-2 said "specify it in prose" and this step said "send it to Claude Design"; neither said where the artifact LIVES, so following the process literally produced an orphan. - Location + name:
- Send the specification to Claude Design as a prompt (
DesignSync//design-sync), following the conventions indesign-system/pdpr-prompt.mdand the screen-coverage mandate — including the no-em-dash copy rule, which is a prompt-level rule there and a gated rule here.- ⚠⚠ CARRY THE EXISTING PRODUCT'S STRUCTURE, NOT ONLY THE FEATURE'S REQUIREMENTS [QRS-913, 2026-08-29]. FEATURE CONTEXT WITHOUT PRODUCT CONTEXT PRODUCES A PARALLEL PRODUCT, EVERY TIME. Every prompt for a feature being added to a surface that already exists must name, explicitly: the folder it extends · the shared modules it must import · the navigation it plugs into · the existing screens it relates to · and the sentence "you are extending an app, not building one." Use the copy-ready block in
design-system/screen-coverage-mandate.mdrather than composing it from memory, because composing it from memory is what failed. The measured incident: the Marriage Biodata round-2 prompt gave excellent feature context (14 answered questions, states, disclosure model) and namedprototype/consumer/zero times, named not one reusable module, and never said "extend". It asked for "THE FIVE SCREENS, IN YOUR ORDER" and got five good screens in a parallel mini-app —prototype/my-qrsetu/with its ownds-base.js,icons.js,image-slot.js,support.jsand abiodata-core.jsthat never importsconsumer-data.js, no navigation relationship toConsumerHome.dc.html, and no entry inqr-registry.js— whose own header states that a new code type is "a DATA ENTRY here and not a change to any screen." 🔎 The sharpest part: round 1 had it RIGHT ("this prototype already carries a consumer app… One account, two halves. The buying half already exists and does not move") and the round-2 prompt threw that frame away by replacing it with a screen list. A later prompt can lose context an earlier one established, so each round restates the product frame rather than assuming it carried forward.
- ⚠⚠ CARRY THE EXISTING PRODUCT'S STRUCTURE, NOT ONLY THE FEATURE'S REQUIREMENTS [QRS-913, 2026-08-29]. FEATURE CONTEXT WITHOUT PRODUCT CONTEXT PRODUCES A PARALLEL PRODUCT, EVERY TIME. Every prompt for a feature being added to a surface that already exists must name, explicitly: the folder it extends · the shared modules it must import · the navigation it plugs into · the existing screens it relates to · and the sentence "you are extending an app, not building one." Use the copy-ready block in
- Generate the design in the project, so it lands beside every other screen and consumes the component vocabulary, tokens and
.prompt.mdspec convention.- ⚠ THIS STEP SAID "INHERITS" UNTIL 2026-08-29, AND THAT WORD WAS THE DEFECT. Placement next to other folders does not cause inheritance: every domain folder in the design project carries its own
ds-base.jsandsupport.js, so a new folder placed beside them imports nothing unless instructed to. Inheritance is an instruction, never a consequence of location. Name the modules to import; do not trust proximity.
- ⚠ THIS STEP SAID "INHERITS" UNTIL 2026-08-29, AND THAT WORD WAS THE DEFECT. Placement next to other folders does not cause inheritance: every domain folder in the design project carries its own
- Implement it against QRSETU's design system and architecture — pulled from the MCP project, never from a local cache.
- Refine minor adjustments internally during implementation, and record each divergence as a drift-ledger row in the same PR (ADR-0015;
check:designfails closed). Minor refinement is sanctioned; silent invention is not.
Where this interacts with ADR-0015's asymmetry, because they are easy to confuse. ADR-0015 splits on which surface (systemic packages/tokens/src/ui = design-first; screen composition = code-first). This rule splits on whether a design EXISTS at all. So screen composition stays code-first — you may freely build and refine a screen whose design you pulled — but you may not originate a screen that the design system has never seen. A brand-new screen needs a design pull; arranging existing components inside it does not.
Never send an architecture-gated question to Claude Design. If the missing screen depends on an undecided contract (the tier vocabulary, an entitlement shape, a payout state machine), resolve it as a QRS-###/ADR first and put the decided contract in the prompt. This is the exact split design-system/screen-reviews/ already draws between design-fixable and architecture-gated findings.
Modern-SaaS quality on every screen. Signature Apple-style soft corners (rounded-3xl shells, rounded-2xl inner panels) — a design invariant. Zero hard-coded colors in class strings (chart stroke/fill are the only exception). Mandatory light + dark theme driven centrally (cn() + isLight / tokens), never per-page branching. UI consistency across two idioms [ENFORCED — ADR-0011]: the frontend has two UI idioms — shadcn/ui + Tailwind (DOM) for the public + admin web (Stack 1), and RN primitives + NativeWind for the merchant app (Stack 2; gluestack-ui candidate). They implement components twice, so a single shared design-token package is the source of truth for color, spacing, radius, type scale, motion, and elevation — compiled to both a Tailwind config (DOM) and a NativeWind/JS theme (RN). Every UI/UX implementation, in either idiom, consumes those tokens — zero per-stack divergence, zero hard-coded colors. A component-parity checklist keeps the two implementations visually and behaviorally identical (watch the seam: a merchant previewing their card in-app (RN) vs the live public card (DOM) must match). Consistency invariants (radius, type scale, spacing, focus, motion, elevation) never differ per screen, per tier, or per platform. (The RN half is live: packages/tokens → apps/mobile/tailwind.config.js (NativeWind) + apps/mobile/src/ui. The DOM half arrives with apps/web; legacy/src/components/ui is prior art only.)
⚠ THE DOM HALF HAS STARTED, AND THIS PARAGRAPH SAID IT "DOES NOT EXIST" UNTIL 2026-08-22. It read: "apps/web/src/ui/ contains only a README.md — zero components". Measured 2026-08-22: four components (Button, Icon, Select, TextField) plus cn.ts, an index.ts barrel and co-located tests. Icon additionally carries the design's own TONES map and a tone() helper transcribed from desktop-kit.js. So a shared DOM primitive layer now exists and is consumed by the merchant console. Two halves of the original claim are still exactly true and are the load-bearing ones:apps/web/package.json carries no shadcn or radix dependency — though it DOES carry class-variance-authority (^0.7.1), which Button.tsx imports, so the "no cva" half of this claim was never true. These are hand-written primitives over @qrsetu/tokens, not shadcn — and component parity between the two idioms remains unverified by construction, because four DOM components against 42 RN ones is not a matched set and nothing compares them. The token package is shared (@qrsetu/tokens → Tailwind v3), so colour/spacing/radius parity holds. Treat "keep shadcn" as a decision that has still not been executed — what exists is a parallel hand-rolled set, which is a different thing and a live naming/architecture question — and do not read a green check:design as evidence that the two idioms agree. ⚠ Note the direction of this correction: the file understated what was built, which is the rarer and more expensive direction, because it invites re-building something that is already there.
Brand & typography [ENFORCED — invariants; full reference: portal design-system/brand-and-typography.md]:
- Wordmark renders lowercase "QR setu" (single space). "QR" is gradient-filled; "setu" uses the
brand-setuink token. Face = Akaya Kanadaka (fonts.brand, single 400 weight) — wordmark only. Bunya is personal-use licensed: design-time source only, never bundled (noexpo-font/@font-face). - Type faces (tokens): UI/body = Baloo 2 (
fonts.uiresolves toBaloo2_*) — ⚠ this said Plus Jakarta Sans until 2026-08-28; that iswebFonts.ui, the DOM stack, a different symbol; Devanagari/mixed = Noto Sans Devanagari (fonts.deva, viaAppText script="deva"); headline display = Baloo 2 (fonts.display, covers Deva+Latin in one family); wordmark = Akaya Kanadaka (fonts.brand); OTP/step labels =fonts.mono. - One brand gradient — the QR monogram:
brand-qr-from(43 100% 58%) →brand-qr-to(11 100% 60%), exposed asbrandQrFrom/brandQrTo. It is the only treatment for emphasis/brand-identity (wordmark "QR", app icon, headline highlights, taglines, the onboarding service-card band) — never a flat accent for those. RN<Text>can't gradient-fill, so gradient text = measured per-word<Svg>via@/uiGradientText/GradientHeadline(RNW-safe). - Highlight-marker i18n convention: emphasised words are wrapped in
*…*in the@qrsetu/i18ncopy (per-language), rendered byGradientHeadline;stripMarksyields the plain string.\nin copy = a forced line break (kept in i18n, not the component). - NO EM DASH (or en dash) IN USER-FACING COPY [ENFORCED — gated, QRS-231]. Use a comma, a colon, parentheses, or two short sentences. This rule is not new: it has been stated in four portal pages since the design system was written (
design-system/pdpr-prompt.md§1,foundational-screens.md,screen-coverage-mandate.md,onboarding-experience-spec.md) — "DO NOT use em dashes anywhere in any generated copy, documentation, labels, or examples." It is repeated here because those four pages are prompts addressed to Claude Designs, so the rule governed generated designs and never reached the implementation side: it was absent from this file, absent from the ESLint guardrails, and asserted by nothing. Six strings × three languages shipped with an em dash and every gate stayed green — not because a rule was overridden, but because no rule was ever executable. Now gated over every@qrsetu/i18ncatalog leaf (i18n-catalogs.test.ts→ "copy typography"), which is the whole user-visible surface because all copy comes from a catalog. Scope is deliberately copy, not prose: code comments, READMEs and tracker rows still use em dashes, and converting them is a separate decision, not a silent sweep. - NEVER VOLUNTEER A PRIVACY REASSURANCE AT THE POINT OF USE [ENFORCED — owner decision 2026-08-11, QRS-549]. State what the product does ("Report this shop", "Only you can see your lists"), never what it refrains from doing. The instance that produced the rule: a Report button subtitle reading "QR setu reads the chat only if you report it" — factually true, enforced in the schema, and still wrong to print, because a reassurance is only reassuring to someone who already had the worry. Volunteered next to a control, it introduces the idea that the platform reads chats to a user who was not wondering, and the takeaway from a denial is reliably the denied thing. Same reason a shop sign reading "we do not steal from customers" is worse than no sign. ⚠ This removes the SENTENCE, never the OBLIGATION — the boundary stays enforced by least privilege and stays disclosed in the privacy policy, where DPDP requires it and where a reader arrives deliberately instead of being ambushed. Reading this rule as licence to drop the enforcement would be the catastrophic misreading. A schema comment or README citing removed copy as its justification must be re-justified, not left pointing at a sentence that no longer exists.
- App-icon/monogram pipeline: SSOT
packages/tokens/assets/brand/icon.svg→sharp(dev-only dep, never bundled) rasterizes every density (1024² opaque store icon, favicon, Android adaptive background+foreground+ monochrome) →expo prebuildregenerates the native set. Splash policy: native splash is background-only (logo-less — avoids a duplicate-splash flash); the in-appBrandSplashcarries the identity + attribution. - Animation vocabulary:
@/uiEntrance(pop/fade/rise) +Loop(float), staggered reveals (final-sceneRadialHubring),FitBoxscaling — all reduced-motion-aware (dwell/entrances collapse to a short fade).
Form primitives + data-service seam [ENFORCED — convention set by onboarding]: shared form UI lives in apps/mobile/src/ui (tier-agnostic, tokens-driven, RNW-safe, each with a co-located test): Button, TextField, OtpInput, ChoiceCard/ChoiceGrid, PillSelect, StepProgress, Chip, LanguageSelect. Multi-step feature flows use a feature-local Zustand wizard store + a typed service interface in packages/data with a stub impl (real Supabase/EF wiring swaps in behind the same interface); Zod schemas in packages/schemas use the exact DB column names. Copy always via @qrsetu/i18n; an in-flow LanguageSelect (never forced device locale) is the pattern for language choice, reused later as Settings › General. See portal features/onboarding.md.