Files
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
..

Phase 4 — Future / optional

Status: ❄️ Not committed

Ideas on radar that may or may not become real tasks. Captured here so they don't get forgotten and so we have a place to push scope creep that surfaces during Phases 13.

None of these are committed. Move them out of Phase 4 and into a numbered phase only when there's a concrete reason to do them.

Candidates

  • Geometry editor. Full CRUD on geofences / waypoints / speed_limit_zones via @mapbox/mapbox-gl-draw. Drawing tools, vertex snapping, polygon validation, import from roadbook coordinates. Depends on directus Phase 2 — those collections don't exist yet. When directus Phase 2 lands, promote this to its own SPA phase.

  • Replay mode. Read historical positions for an event + time range, animate them on the map at chosen playback speed. Useful for: post-race review, debugging "where did we lose position from this device", validating a new geofence against past races. Needs a Processor-side replay endpoint (mentioned in trm/processor/.planning/phase-4-future/README.md as "replay tooling").

  • Heatmaps / density visualisation via deck.gl. Layer on top of MapLibre showing position density over time. For a 24-hour rally with 500 racers, the line density on a single stage is a useful at-a-glance "where did people struggle / where was traffic" view. deck.gl integrates as a layer on top of the existing map; no architectural rework.

  • i18n (Albanian). The dogfood is closed and the operators speak English. Public-facing pages (eventually, when they exist) need Albanian. react-i18next is the boring answer; defer until there's a public surface.

  • Dark mode. shadcn/ui supports it natively via Tailwind class strategy. Trivial to add when someone wants it; not worth doing speculatively.

  • End-to-end tests with Playwright. Login → subscribe → see positions → log out, run against a stack with mocked Processor positions. Worth doing when (a) Phase 1 is stable and (b) regressions have started costing real time. Until then, manual smoke + Vitest + the dogfood itself are sufficient.

  • Per-event leaderboard / standings page. Read derived results from processor's Phase 2 timing tables (stage_results). Out of dogfood scope (manual results), but a real product feature for "after dogfood succeeds and we want to add real value."

  • Spectator-facing public live map. Same map widget, no auth, scoped to one public event. Different deployment shape (CDN-friendly, no cookies, possibly a separate origin). Requires directus Phase 4 (permissions) to be landed first so authorization makes sense.

  • Notifications. Browser push for "device went silent" or "speed-limit zone violation" alerts. Requires service worker + the Notifications API + a way for processor to push notification triggers. Material work; high operator value if we get there.

  • Operator chat / coordination. Race directors and marshals talking to each other inside the SPA during the event. Out of architectural scope (TRM is a tracking platform, not a comms platform), but easy to imagine an embedded Matrix or similar widget. Park here until someone makes the case.