shipped

Spec: F19 — Design System & Responsive UI

Status: shipped · Audited: 2026-07-14 · Contract audit: partial Canonical specs: DESIGN.md (tokens, components, surfaces) + TASTE.md (anti-slop rules). This file only fixes the product-level UX bar; it does not duplicate them.

1. Problem & CEO Job

All three jobs depend on it. The product UX bar is “don’t make me think”: Vietnamese SME CEOs and warehouse staff must use Lumi with zero training. Consistency delivers it: one severity color language, button language, and loading pattern, learned once and valid everywhere.

2. Product-level UX Invariants

These bind every feature spec (F01–F25) without being repeated in each:

  1. 5am test — CEO-facing screens (Brief, Today) readable half-awake on a phone.
  2. One required field — every create flow starts with a single field (name/title); everything else is progressive disclosure.
  3. Skeletons, not spinners — layout visible immediately; spinners only full-page.
  4. Empty states teach — every empty state says what this screen will do and offers the first action. Blank pages are bugs.
  5. Positive silence — empty risk/decision lists and 0-item briefs render as good news, never as dead ends.
  6. Errors are actionable — name the fix (“kiểm tra kết nối mạng”), never just the failure.
  7. One severity palette — low/medium/high/critical map to the same colors on tasks, risks, commitments, brief items.
  8. Never lose typed text — failed submits preserve input (pulse answers above all).
  9. Mobile-first for member surfaces (pulse), phone-capable for everything.

3. Scope Boundaries

  • In: shadcn/ui (base-nova) exclusively, CSS-variable tokens, Tailwind v4 (CSS config), responsive layout, the invariants above.
  • Out: dark mode (until DESIGN.md defines it intentionally), theming/white-label, animation flourish that doesn’t clarify flow.

4. Data Model

n/a — frontend only.

5. API Contract

n/a — frontend only.

6. UI / UX

See DESIGN.md (what to use) and TASTE.md (what never to ship). Component checklist before any new UI: does shadcn cover it (frontend/src/components/ui/)? Does it pass the TASTE.md pre-flight?

7. Test Plan

Detailed proof matrix: F19 design-system test plan.

#CaseTypeWhere
1Visual audit, 55+ shots across all featurese2escreenshot-flow.spec.ts → frontend/screenshots/index.html
2Type safetyunittsc --noEmit
3Raw-Tailwind-for-UI violationsreviewmerge-blocking rule 4
4Canonical web tokens and banned escapesunitdesign-tokens.test.ts; check-design-tokens.mjs
5Shared severity languageunitStatusBadge.test.tsx
6Android app paper token matches #F4F0E8Android JVMMobilePrimitivesTest
7Vietnamese CEO surfaces at 375px and 768pxbrowsermobile-screenshot-flow.spec.ts; currently blocked by unavailable Chromium revision 1223

8. Current Behavior

Shipped as an operating contract. The design system exists through DESIGN.md, TASTE.md, shared UI components, native token mirrors, and screenshot-driven review. The 2026-07-14 contract audit found and corrected Android’s stale PaperWhite value with a red-then-green JVM regression. Focused web token and severity proofs pass locally. Browser journeys collect but did not launch because Chromium revision 1223 is unavailable; native runtime and maintained visual-diff evidence remain explicitly blocked.

9. Error States

#ErrorResponseNotes
ES1shadcn/ui import fails at runtimeEntire rendering tree collapses; no per-component fallbackNo E2E catches a broken import chain
ES2Screenshot flow visual diff failureScreenshots generated but no baseline diff; regression is human-detected onlyNo automated visual regression testing
ES3Missing CSS variable for a tokenBrowser uses inherited/unset color; element may be invisibleNo test verifies all referenced CSS variables are defined
ES4DESIGN.md vs CSS token set driftTwo PRs modifying token block can produce doc ↔ code mismatchNo automated sync check
ES5Screenshot flow missing file in galleryGallery links to missing file if screenshot not captured (test failed before snap)test.afterAll runs regardless; no guard for missing files

10. Diagrams & Docs Touched

DESIGN.md · TASTE.md · frontend/AGENTS.md → UI Rules.

11. Implementation Audit (2026-06-10)

#ClaimStatusEvidence
1shadcn/ui (base-nova) exclusively; CSS-variable tokens; Tailwind v4 CSS config✅ matchOperating contract; frontend/src/components/ui/; tsc --noEmit gate
29 UX invariants enforced via 55+ screenshot shots + TASTE.md pre-flight in review⚠️ partialscreenshot-flow.spec.ts generates review material, but no maintained baseline/diff or current human sign-off proves all nine invariants.
3Invariant 7: one severity palette — low/medium/high/critical consistent across tasks/risks/commitments/brief items✅ matchClosed 2026-07-06. StatusBadge’s statusToVariant() map is the single source of truth; StatusBadge.test.tsx now locks the severity language — the four levels map to four distinct canonical variants and aliases route to their level. Two surfaces that hand-rolled a divergent map (CompaniesPage had medium→grey; SupportListPage PRIORITY_VARIANT_MAP had medium→grey/low→outline) were migrated to statusToVariant.
4Invariant 3: skeletons on all pages — no auto-detect of new pages without skeleton states⚠️ gapE2; screenshot flow covers existing pages but can’t catch new pages missing skeletons. 2026-06-18 visual QC found 03-today screenshots could capture skeletons before the loaded page; screenshot flow now waits for [data-slot="skeleton"] to clear before snap.
5Design token usage: brand colors hardcoded in some component files (bg-[#0E3EB8], text-[#102A43])✅ matchClosed. frontend/scripts/check-design-tokens.mjs bans stock palette classes, raw/stock shadows, and arbitrary #hex in frontend/src; enforced in CI (ci-fe.yml) and by src/test/_shared/design-tokens.test.ts.
6Screenshot flow single-width only; mobile invariants (5am test, mobile-first) not verified⚠️ proof blockedImplementation closed 2026-07-06. tests/e2e/mobile-screenshot-flow.spec.ts defines phone (375) and tablet (768) journeys with horizontal-overflow assertions. The 2026-07-14 contract run could not launch either journey because Chromium revision 1223 is absent and the CDN install fails DNS; prior results are not current-commit browser evidence.
7DESIGN.md and CSS token block can drift (no automated sync)⚠️ gapES4; two PRs modifying token block independently

Summary: deterministic web token/severity checks and the Android token regression pass. Browser, native runtime, cross-platform parity, visual approval, and routed loading/empty/error-state inventory remain explicit CUE gaps; F19 is partial, not green.

Edge Cases Catalog (formerly §11, 2026-06-12; E1–E10): Key items integrated above. Remaining: E1 missing shadcn component for new pattern (governance gap, no lint rule); E3 empty state regressions (no content assertion); E7 Tailwind v4 @import path verification; E8 Base UI vs shadcn pattern mixing; E9 Lucide icon inconsistency; E10 “loaded empty” vs “not loaded” visually identical. Full catalog in git history (2026-06-12 changelog entry).

12. Open Questions

  • How should one deterministic parity checker represent the canonical values shared by DESIGN.md, web, shared KMP, Android, iOS, macOS, and Watch without making generated artifacts authoritative?
  • Which visual baselines require human approval, and what diff threshold avoids both noise and false-green screenshots?
  • Which routed pages may legitimately fast-load without skeletons, and how will the inventory prove authored empty and actionable error states?

13. Bug / Change Log

2026-07-28 — Folded-L identity replaces the clarity-star lockup

Type: Cross-platform brand-system refresh

  • Lumi now uses the supplied folded-L geometry across canonical web SVGs, Android adaptive and splash vectors, iOS/macOS app icons, Play listing artwork, and legacy Android launchers.
  • Descriptively named source exports live under brand/source/2026-folded-l/; exact duplicate exports were removed, and scripts/generate-brand-svg-assets.mjs owns canonical SVG generation plus the frontend/public/ mirrors.
  • The horizontal umi wordmark is upright. Italic or oblique letter geometry is not a supported logo variant.
  • The folded-L to u clear space is approximately 0.8× the wordmark stem width; excess separation that makes the mark and name read as unrelated elements is not a supported lockup.
  • DESIGN.md now distinguishes the folded-L identity from the separate four-point clarity motif used sparingly for verified insight.

Proof boundary:

  • Source identity, exact dimensions, digest custody, frontend compilation, and Android resource compilation are deterministic. Store rendering and named-device launcher appearance remain runtime/visual evidence, not consequences of source validation.

2026-07-19 — Native content and material hierarchy closes framework-default color leaks

Type: Mobile design-system regression fix

Acceptance contract:

  • Shared KMP content that does not declare a more specific semantic color inherits Civic Navy, never Compose’s framework-black fallback.
  • Android primary actions use Lumi Blue with white content; secondary and text actions use Lumi Blue on white or transparent surfaces.
  • Android’s complete Material 3 light scheme maps every surface/tint role to a Lumi token, keeps the app canvas Paper White without tonal elevation, and uses the canonical 4/8/12/16dp shape ladder instead of stock purple or pill defaults.
  • iOS native navigation titles use Civic Navy and navigation actions use Lumi Blue without replacing the platform’s Liquid Glass material.
  • Semantic errors use Risk Red on both platforms. Pure black remains permitted only for system chrome, vector masks, and transient scrims.

Proof boundary:

  • Deterministic policy and platform unit/build gates prove source ownership and compilation. Commit-bound simulator/emulator screenshots are required to assess rendered balance; named physical-device approval remains open.

2026-07-24 — Android splash owns background and icon separately

  • Android 12+ treats the splash screen as a window and masks the supplied icon. The app now supplies PaperWhite through windowSplashScreenBackground and the Lumi vector directly through windowSplashScreenAnimatedIcon; it no longer supplies a square-background layer list as the icon. This preserves the system’s adaptive-icon masking boundary instead of letting it crop the composed asset or reveal a mismatched background.
  • The source policy proves the theme wiring. F19.GAP002 remains the named-device rendering proof.

2026-07-19 — Native mobile chrome restores Lumi Blue authority

Type: Mobile design-system regression fix

Summary:

  • Android selected navigation had resolved through onPrimaryContainer (Civic Navy), so the active tab looked black instead of carrying the canonical Lumi Blue authority signal.
  • iOS installed a custom transparent UITabBarAppearance without assigning selected and inactive colors, allowing UIKit defaults to override the SwiftUI brand tint; the app AccentColor asset was also empty.
  • Selected navigation and key shell actions now use Lumi Blue, inactive navigation uses Soft Slate, and content remains Civic Navy on warm paper. This preserves DESIGN.md’s 3–8% blue budget instead of washing whole screens in brand color.

Proof boundary:

  • Repository policy proof guards both native shells and the iOS accent asset. Named-device visual review at normal and 200% text remains required before claiming rendered parity or subjective visual approval.

2026-07-14 — Contract audit identifies Android paper-token drift

Type: Bug Fix / Verification

Summary:

  • The canonical PaperWhite value is #F4F0E8 in DESIGN.md, web, shared KMP, and iOS, while the Android app design-system mirror used the superseded #FAF8F4 value.
  • Added the test-first F19 proof matrix, captured the Android regression red, corrected the one token, and migrated the feature into the Contract Graph with explicit browser/native/visual gaps.

Impact:

  • Android app surfaces now use the accepted cross-platform paper background. The registry is partial until remaining evidence closes.

Tests:

  • :core:designsystem:testDebugUnitTest --tests '*MobilePrimitivesTest*' failed against #FAF8F4 before the correction and passes afterward.
  • Focused web token/severity Vitest proofs pass. The 375px/768px Playwright nodes collect but remain blocked: Chromium revision 1223 is absent and its CDN install fails with getaddrinfo ENOTFOUND cdn.playwright.dev.

2026-06-18 — Visual QC screenshot flow waits for loaded UI

Type: Test / QC Harness

Summary:

  • Full frontend visual QC started by generating frontend/screenshots/index.html.
  • Initial run exposed a real install-state blocker: Vite could not resolve declared font packages because node_modules was stale. Reinstalled with lockfile-compatible pnpm@9.15.9; no lockfile change intended.
  • The first successful screenshot run then exposed a harness race: Today screenshots captured skeletons before the loaded page. screenshot-flow.spec.ts now uses canonical auth routes, Vite overlay detection, onboarding-gate clearing for demo users, and waits for skeletons to clear before screenshots.

Impact:

  • Screenshot evidence is now more trustworthy for page-by-page visual QC.
  • Remaining F19 gaps still stand: automated visual diffing, mobile breakpoint matrix, and token drift enforcement.

2026-06-18 — Restore viewport-only screenshot support for sticky-shell pages

Type: Test / QC Harness

Summary:

  • The screenshot helper had regressed to always using fullPage: true, even when a flow requested a viewport-only capture.
  • This made scrolled screenshots of sticky-shell pages like /settings look visually broken because the shell/header was duplicated inside the capture.
  • tests/e2e/snap.ts now accepts an explicit fullPage option again, so page flows can choose viewport captures where that produces truer evidence.

Impact:

  • Visual QC screenshots for sticky layouts better match what users actually see.

2026-06-14 — Restructure to TEMPLATE.md section order; expand §11 audit (SP fleet)

Type: Documentation Change

Summary:

  • Numbered “Current Behavior” as §8.
  • §8 Diagrams → §10; §9 Implementation Audit (verdict) → §11 (7-row table); §10 Open Questions → §12; §11 Edge Cases absorbed into §11 note; §12 Error States → §9; §13 Bug Log stays.
  • §11 audit: 7 rows, 2 ✅, 5 gaps (palette cross-feature, skeleton auto-detect, token hardcoding, mobile coverage, doc/CSS drift).

2026-06-12 — Add Edge Cases (E1–E10) and Error States (ES1–ES5) to F19 spec

Type: Documentation Change