Files
spa/.planning/phase-3-dogfood-readiness/README.md
T
julian 26e059fc20 feat: planning structure + task 1.2 stack rounding-out
Add .planning/ scaffolding:
- ROADMAP.md (4 phases, 8 non-negotiable design rules)
- phase-1-foundation/ README + 9 task files (1.2-1.10)
- phase-2-live-map / phase-3-dogfood-readiness / phase-4-future README placeholders

Task 1.2 — stack rounding-out:
- Tailwind 4 via @tailwindcss/vite + src/styles/globals.css
- shadcn/ui (slate, new-york) primitives in src/ui/primitives/:
  button, input, label, form, card, alert
- TanStack Router 1.169 + Query 5.100 (devtools + plugin in devDeps)
- Zustand 5, @directus/sdk 21, zod 4, react-hook-form 7 + resolvers
- Prettier 3 + eslint-config-prettier + eslint-plugin-prettier
- ESLint override disabling react-refresh/only-export-components for
  src/ui/primitives/** (intentional dual-exports in shadcn primitives)
- Path alias @/* -> ./src/* in tsconfig.json + tsconfig.app.json
  (TS 6 deprecates baseUrl; paths now resolve relative to config file).
  Pulled forward from 1.3 because shadcn add CLI needs it resolvable.
- Scripts: dev, build, preview, lint, typecheck, format, format:check,
  test (placeholder)
- App.tsx Tailwind smoke test (centred card + shadcn Button)
- README.md rewritten with stack/scripts/shadcn-add docs

All four gates green: typecheck, lint, format:check, build (222KB / 70KB gz).
2026-05-02 18:41:54 +02:00

4.3 KiB
Raw Blame History

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 Apply the actual TRM brand if one exists by then. Logo + colour palette

Acceptance for the phase as a whole

  • All eight tasks (3.13.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.)