Add local-first race hub API

This commit is contained in:
2026-05-25 00:49:13 -04:00
parent 517c6b987b
commit e08255db70
16 changed files with 1231 additions and 118 deletions

View File

@@ -140,6 +140,11 @@ TUI requirements during v1:
- Use TanStack Query for server data.
- Use D3 for strategy, position evolution, and lap comparison visuals.
- Keep the old Web UI available until the replacement route is credible.
- This is the first frontend phase. Use Claude for this phase.
- See [13 Phase 5 React Race Hub](13-phase-5-react-race-hub.md) for the
implementation brief and
[Claude Phase 5 Prompt](claude-phase-5-react-race-hub-prompt.md) for the
frontend-agent handoff.
## Ingestion Rate-Limit Defaults

View File

@@ -0,0 +1,103 @@
# Phase 5 React Race Hub
## Purpose
Phase 5 begins the production Web UI. The backend now has the foundation needed
for a local-first Race Hub: live timing is shared, a domain store exists,
ingestion can populate it, and `/api/v1/race-hub` can read from local data with
dataset metadata.
This is the point to switch from Cursor to Claude for frontend/UI work.
## Manager Decision
Start with a focused React Race Hub slice, not a full app rewrite. The goal is
to prove the chosen frontend stack, visual language, responsive layout, and API
contract against the new local-first backend.
Keep the old Web UI available until the React route is credible.
## Scope
Add a Vite + React + TypeScript frontend foundation and build a first Race Hub
route around:
- meeting/session header;
- dataset/source status strip;
- classification table;
- starting grid table;
- driver/team color treatment;
- missing dataset states;
- compact Race Hub navigation shell;
- responsive desktop, tablet, and phone layouts.
Use `/api/v1/race-hub?session_key=...` as the primary API.
## Stack Defaults
- Vite
- React
- TypeScript
- TanStack Query
- TanStack Router, unless integration cost argues for React Router
- D3 only for bespoke charts later; do not use it for basic layout tables
- Vitest for component/unit tests
- Playwright for at least one smoke path if practical
## Visual Direction
Follow the existing mockups in `documentations/refactor/screens/`, but treat
them as direction, not rigid specs.
The UI should feel like an F1 operations room:
- dense but readable;
- technical, not generic SaaS;
- restrained use of panels;
- no card sludge;
- no decorative gradient blobs;
- strong timing-table ergonomics;
- team colors used as data, not wallpaper;
- mobile views designed directly, not merely squeezed desktop.
## Integration Policy
Do not rip out the existing static Web UI on day one. Add the React app in a way
that can coexist while the route is built and tested.
Acceptable approaches:
- add a Vite app under a dedicated frontend directory and document the dev flow;
- serve built assets from Go only after the React slice is stable;
- expose a `/react` or equivalent route temporarily if needed.
The implementation should avoid large backend changes except for tiny API
contract fixes discovered while integrating.
## Non-Goals
Do not include these in Phase 5:
- full replacement of every existing Web screen;
- live timing React rewrite;
- ingest UI;
- settings UI;
- full season/calendar rebuild;
- new backend ingestion features;
- persistence of live SignalR events.
## Acceptance Criteria
Phase 5 is complete when:
- the React app can run locally;
- a Race Hub screen loads from `/api/v1/race-hub`;
- available and missing datasets are visibly distinct;
- the layout is usable on desktop and phone widths;
- tests or smoke checks cover the Race Hub happy path;
- the old Web UI still works.
## Next Phase After This
Phase 6 should expand the React app around the Race Hub: strategy chart,
position evolution, lap comparison, and richer Data Library/status workflows.

View File

@@ -57,8 +57,10 @@ not implementation tickets yet.
coding slice for OpenF1-to-store ingestion orchestration.
- [12 Phase 4 Local-First Web API](12-phase-4-local-first-web-api.md): fourth
coding slice for store-backed Race Hub read models and Web API metadata.
- [Cursor Phase 4 Prompt](cursor-phase-4-local-first-web-api-prompt.md):
current handoff prompt for the next Cursor backend phase.
- [13 Phase 5 React Race Hub](13-phase-5-react-race-hub.md): first frontend
implementation slice for the production Web UI.
- [Claude Phase 5 Prompt](claude-phase-5-react-race-hub-prompt.md): current
handoff prompt for Claude to begin React/frontend work.
## External References

View File

@@ -0,0 +1,103 @@
# Claude Prompt: Phase 5 React Race Hub
You are the frontend/UI lead for `box-box`, an F1 local-first command center.
Backend Phases 1-4 are complete:
- `internal/live` owns shared official F1 SignalR live timing.
- `internal/store` owns the local SQLite domain DB.
- `internal/ingest` can ingest OpenF1 data into the local store.
- `internal/query` and Web API expose local-first Race Hub data at:
```text
GET /api/v1/race-hub?session_key=9472
```
Your task is Phase 5: begin the production React Web UI with a focused Race Hub
slice.
## Read First
Read these files before editing:
- `CLAUDE.md`
- `documentations/refactor/04-web-ui-product.md`
- `documentations/refactor/05-frontend-stack.md`
- `documentations/refactor/06-visual-design-direction.md`
- `documentations/refactor/12-phase-4-local-first-web-api.md`
- `documentations/refactor/13-phase-5-react-race-hub.md`
- `documentations/refactor/screens/index.html`
- `documentations/refactor/screens/race-hub.html`
- `documentations/refactor/screens/live-timing.html`
- `documentations/refactor/screens/mobile-live.html`
- `internal/web/racehub.go`
- `internal/query/racehub.go`
## Goal
Add the first production React frontend slice for Race Hub. Keep the existing
Go-served static Web UI working while the React route matures.
## Required Work
1. Add a Vite + React + TypeScript frontend foundation.
2. Use TanStack Query for API loading.
3. Use TanStack Router unless there is a clear reason to choose React Router.
4. Build a Race Hub screen backed by:
```text
/api/v1/race-hub?session_key=...
```
5. Show:
- meeting/session header;
- source/dataset status strip;
- classification table;
- starting grid table;
- driver/team identity treatment;
- missing/partial dataset states;
- desktop and phone-responsive layouts.
6. Keep old Web UI routes/assets intact.
7. Add at least basic tests or a smoke check.
8. Document how to run the React dev server and how it connects to the Go API.
## Design Guardrails
- Make it feel F1-native and operational, not like a generic SaaS dashboard.
- Avoid card sludge.
- Avoid decorative gradients, blobs, fake hero sections, and meaningless chrome.
- Prefer dense, scan-friendly timing-wall ergonomics.
- Use team colors as structured data accents.
- Do not put cards inside cards.
- Build mobile intentionally; do not just squeeze desktop.
- Use icons where appropriate, but do not overdecorate.
## Backend Guardrails
- Do not rewrite ingestion.
- Do not persist live SignalR data.
- Do not replace all Web endpoints.
- Make only small API tweaks if integration reveals a real contract problem.
- Preserve the existing static Web UI until the React slice is credible.
## Verification
Run the relevant frontend checks you add, plus:
```bash
go build -o /tmp/box-box ./cmd/main.go
```
If dependencies need to be installed, use the repo's package manager choice and
record the commands in your final response.
## Final Response
Report:
- frontend package/files added;
- dev command and URL;
- API endpoint used;
- tests/smoke checks run;
- screenshots or notes about desktop/mobile behavior if available;
- any backend contract issues discovered.

View File

@@ -1,110 +0,0 @@
# Cursor Prompt: Phase 4 Local-First Web API
You are working in the `box-box` repository.
Phases 1-3 are complete:
- `internal/live` owns shared live timing.
- `internal/store` owns the SQLite domain DB.
- `internal/ingest` can ingest initial OpenF1 data into the store.
Your task is Phase 4: add local-first backend read models and Web API support.
This is still a backend phase. Do not start the React/frontend implementation.
## Read First
Read these files before editing:
- `CLAUDE.md`
- `documentations/refactor/08-v1-scope-and-phasing.md`
- `documentations/refactor/12-phase-4-local-first-web-api.md`
- `internal/store/*`
- `internal/ingest/*`
- `internal/web/server.go`
- `internal/web/api.go`
- `cmd/main.go`
## Goal
Expose a store-backed Race Hub API that can return ingested data without making
fresh OpenF1 calls. Missing datasets must be explicit in response metadata.
## Required Work
1. Add a read-model layer, preferably `internal/query`.
2. Implement a Race Hub read model for a single `session_key`.
3. Include:
- meeting;
- session;
- drivers;
- session results enriched with driver/team fields;
- starting grid enriched with driver/team fields;
- dataset availability metadata.
4. Add a Web endpoint:
```text
GET /api/v1/race-hub?session_key=9472
```
5. Wire Web mode to optionally open the domain DB:
```bash
go run cmd/main.go --web --db /path/to/boxbox.db
```
6. Web mode must still start when the DB is absent or empty.
7. Add offline tests using temp SQLite stores.
8. Preserve existing TUI and live behavior.
## Optional Work
If straightforward, make these existing endpoints support local-first reads:
- `/api/v1/meetings`
- `/api/v1/sessions`
- `/api/v1/drivers`
- `/api/v1/results`
- `/api/v1/grid`
Use query controls such as:
```text
?source=local
?source=auto
```
Do not break the current OpenF1-backed behavior of existing endpoints.
## Guardrails
- Do not add React, Vite, TanStack, or frontend app code.
- Do not trigger ingestion from normal Web browsing.
- Do not persist SignalR live data.
- Do not rewrite every API endpoint.
- Do not add laps/stints/pits/weather/race-control read models unless you also
add tested store tables for them.
- Keep tests offline.
## Testing
Run:
```bash
go test ./internal/query/... ./internal/web/... ./internal/store/...
go build -o /tmp/box-box ./cmd/main.go
go test ./...
```
If `go test ./...` fails only because existing `internal/api` integration tests
cannot reach OpenF1, report that separately as unrelated.
## Final Response
Report:
- packages/files changed;
- endpoint(s) added;
- response metadata shape;
- tests run and results;
- any known limitations;
- whether Phase 5 can begin frontend work.