A design handoff bundle generated by Claude Design (claude.ai/design) on 2026-05-02. Defines the Bloomberg/F1-pit-wall aesthetic for TRM: - ink-on-paper base + race-flag red accent (#E8412B) - square-edged everything, sharp printed offset shadows - mono numerics (JetBrains Mono) for any changing value - Goldplay (real licensed font, three weights in bundle fonts/) - four surfaces designed: dashboard / leaderboard / mobile / marketing (SPA scope is the first two) The bundle is committed in-tree at TRM_Design_System-handoff/ so 3.8 has the full source material when it picks the work up. Includes: - Top-level + project READMEs (the design spec) - chats/chat1.md (intent + iteration history) - colors_and_type.css (token set, drop-in for Tailwind 4 @theme) - fonts/ (Goldplay regular/semibold/bold) - ui_kits/ (HTML prototypes per surface) - preview/ (per-token visual reference cards) Updated phase-3-dogfood-readiness/README.md task 3.8 row to point at the bundle and document the recommended approach (retheme shadcn via CSS variable overrides + Tailwind 4 @theme, not replace). Why deferred: foundational tokens are non-blocking for Phase 1 (login + placeholder home) and Phase 2 (live map without chrome). Applying them now would either delay dogfood-blocking work or land partial styling that gets reworked when 3.8 lands the full pass.
7.2 KiB
Phase 3 — Dogfood readiness
Status: ⬜ Not started
The set of operational features that turn a working pilot into something safe to put in front of race operators on race day. None of these tasks change correctness; they change the experience when things don't go perfectly.
Outcome statement
When Phase 3 is done:
- Error boundaries wrap each major feature region (map, sidebar, header). A crash in the map widget doesn't blank the whole UI; the operator sees a "Map crashed; reload to retry" panel and can keep using the rest.
- Connection-state UI is unmissable but not noisy. WS reconnecting → small banner. WS offline > 30s → larger warning. Per-device "last seen N seconds ago" in the device sidebar.
- Mobile-responsive baseline. The SPA doesn't crash on a 375px-wide viewport. Map fills the screen; sidebar collapses to a sheet. Not a separate mobile app — the same app, usable in a marshal's pocket browser.
- Per-device detail panel. Click a device on the map → side panel showing recent positions, current vehicle/crew, last-seen, manual notes the marshal has typed. Doesn't add data flows; consumes existing snapshots.
- Operator-friendly empty / loading states. No blank screens during the snapshot fetch; "No devices reporting yet" message when the event has subscribed but no positions arrived.
- Vitest + React Testing Library set up. Unit tests for the auth store, the rAF coalescer, the position-store reducer. Not a comprehensive suite — enough that future changes don't silently regress critical paths.
Why this is a separate phase
Phase 2 produces a working live map. Phase 3 makes that map fielded — usable when networks are flaky, browsers are exotic, screens are tiny, and operators are stressed. None of these tasks block the map from working in a controlled demo, but all of them affect whether the dogfood is genuinely useful versus a mostly-working tech demo.
Tasks (sketched, not detailed)
| # | Task | Notes |
|---|---|---|
| 3.1 | Error boundaries + crash-recovery UI | One per major region (map, sidebar, header). Logs to console + optional remote-error endpoint |
| 3.2 | Connection-state UI | Banner / chip in the header; per-device last-seen in the sidebar |
| 3.3 | Mobile-responsive baseline | Tailwind breakpoints; map full-screen on mobile; sidebar → sheet |
| 3.4 | Per-device detail panel | Click → side panel; reads from Directus + position store |
| 3.5 | Empty / loading state polish | "Connecting…", "Waiting for first positions…", "No devices in this event yet" |
| 3.6 | Vitest + React Testing Library setup + targeted tests | Auth store, coalescer, position-store reducer. Not exhaustive |
| 3.7 | Production logging discipline | Console-error captures + optional remote-shipper for stage |
| 3.8 | Visual brand pass — adopt TRM design system | Apply the design handoff bundle. Bundle path + scope + recommended approach below. |
Acceptance for the phase as a whole
- All eight tasks (3.1–3.8) done.
- Pulling the network mid-session shows a clear "reconnecting" state; reconnecting works; the operator's selection / event-picker state survives the gap.
- Loading the SPA on an iPhone 12 (or equivalent) viewport doesn't break layout.
- Clicking a device opens the detail panel; the panel shows the device's current vehicle/crew (joined from Directus) and recent positions (from the store).
- Vitest runs in CI; existing tests are green; coverage is documented but not gated on a percentage threshold.
- The dogfood-day operator sign-off: a marshal can use the SPA on race day without us standing over them. (This is the real acceptance gate; the rest is observable proxy.)
Task 3.8 — TRM design system adoption (deferred from earlier)
A design handoff bundle was generated by Claude Design (claude.ai/design) on 2026-05-02 and lives at TRM_Design_System-handoff/trm-design-system/ in this repo. It defines a Bloomberg / F1-pit-wall aesthetic — high data density, ink-on-paper base with one race-flag red accent (#E8412B), mono numerics for any changing value, square-edged everything, sharp printed offset shadows (no blur), Goldplay (real licensed font with three weights in the bundle's fonts/) + JetBrains Mono + Inter. Four surfaces designed: web dashboard, live leaderboard, mobile app, marketing site — only the first two are in this SPA's scope.
The bundle's READMEs (top-level + trm-design-system/README.md + project/README.md) and chats/chat1.md are the source of truth. colors_and_type.css ships the full token set as CSS custom properties.
Recommended approach when Phase 3 picks this up — retheme shadcn, don't replace. Tailwind 4's @theme directive maps cleanly to the design's tokens; shadcn's CSS-variable-driven theming lets us keep all the existing primitives (Button / Input / Form / Card / Alert) and only swap the cosmetics. Concrete steps:
- Translate
colors_and_type.cssinto a Tailwind@themeblock — the paper / ink / night / race-accent / viz palettes all become Tailwind utilities. - Override shadcn's
--background,--foreground,--primary,--destructive,--ring,--radiusto point at the TRM tokens. - Add Goldplay as a webfont via the bundle's woff2 / ttf files (drop into
public/fonts/); register JetBrains Mono via Google Fonts. - Set the global radius to
0(square-edged) and replace shadcn's soft shadows with the printed offset utility (box-shadow: 2px 2px 0 0 var(--ink)). - Reskin shadcn primitives where defaults conflict — mainly: button radius, card border (full-ink 1 px not hairline), focus ring colour (race-flag red, 2 px outline + offset).
- Adopt night mode for the Phase 2 live-map page only (the design says night is the default for trackside / kiosk views, not a toggle); paper/ink everywhere else.
- Replace the home-page placeholder + login page with the design's chrome (56 px top bar, 240/64 px collapsible sidebar — the dashboard layout).
Out of scope for 3.8: mobile app and marketing site. Those are separate products in the design system; the SPA only adopts dashboard + leaderboard surfaces.
Open question for when 3.8 starts: the design notes the brand may have a custom icon set (cube / pixel-grid / map glyphs from the logo) — Lucide is the documented substitute. Stick with Lucide unless the custom set surfaces by then.
Why deferred: the design's foundational tokens are non-blocking for Phase 1 (login + placeholder home) and Phase 2 (live map without chrome). Adopting them now would either delay the dogfood-blocking work or land partial styling that gets reworked in 3.8 anyway. The bundle is committed alongside this plan so it's findable when Phase 3 runs.