AmanTahiliani 7a5e0a323d Update CLAUDE.md and plan.md to document the web layer
CLAUDE.md previously described only the TUI; it now covers the web
server (internal/web), React frontend, ingestion CLI, and the vitest/
playwright test commands. plan.md Phase 3 framing updated and the
championship hub recorded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 00:15:01 -04:00
2026-05-25 02:04:16 -04:00
2026-03-03 00:51:53 -05:00
2026-03-03 00:51:53 -05:00
2026-05-25 10:17:07 -04:00
2026-05-25 12:35:59 -04:00
2026-05-24 20:56:00 -04:00

box-box

"Box, box. Box, box." — Every F1 race engineer, ever.

box-box is a Formula 1 dashboard in Go with two surfaces:

  • Web UI (primary) — React + TypeScript SPA for Race Hub analytics, local data coverage, and live timing.
  • TUI (preserved) — Bubble Tea terminal app with standings, calendar, driver profiles, official live timing, track map, battles, pit window, and replay.

Historical Web data is local-first in a SQLite domain database (ingested from OpenF1). Live timing uses the official F1 SignalR feed via the Go server; the React app reads /api/v1/live/*, not OpenF1 directly.

For architecture, phase history, and design rationale, see documentations/refactor/README.md.

How it fits together

Layer Role
OpenF1 REST Backfill and ingestion source; optional paid tier via OPENF1_API_KEY. Also powers the TUIs on-demand reads and HTTP cache.
Domain SQLite (boxbox.db) Local store for meetings, sessions, Race Hub datasets, and navigation APIs used by the Web UI.
HTTP cache SQLite (cache.db) TTL cache for OpenF1 responses (TUI and legacy paths). Separate from the domain DB.
Official F1 SignalR Live timing bridge in internal/live, exposed to Web (SSE) and TUI.
Go server cmd/main.go — TUI, --web API + static SPA, or CLI ingestion.
React frontend frontend/ — production build served from frontend/dist when present.

The Web UI should call local-first Go APIs (/api/v1/...). Do not add direct OpenF1 reads in the frontend.

Prerequisites

  • Go (see go.mod for the module version)
  • Node.js 18+ and npm (Web UI dev, unit tests, Playwright)
  • Internet for ingestion and TUI OpenF1 calls
  • For E2E / visual tests: npx playwright install (Chromium) after npm install at the repo root

Install

git clone https://github.com/AmanTahiliani/box-box.git
cd box-box

npm install                    # Playwright and repo-level test scripts
npm install --prefix frontend  # Vite + React app

Build

go build -o box-box ./cmd/main.go
npm run build --prefix frontend   # writes frontend/dist (gitignored)

Run — TUI (default)

go run ./cmd/main.go
# or: ./box-box

Logs go to box-box.log in the project directory so the terminal stays clean.

TUI keybindings

Key Action
17 Home, Standings, Calendar, Race Detail, Drivers, Live, Track Map
tab / shift+tab Next / previous tab
j/k, enter, b/esc Navigate, select, back
s, b, p Live: sectors, battles, pit window
r Race replay (Race Detail, race sessions)
y Cycle season year
q / ctrl+c Quit

Run — Web (Go serves API + built React)

Build the frontend first, then start web mode. Go walks up from the cwd to find frontend/dist/index.html; if missing, it serves embedded legacy assets.

npm run build --prefix frontend
go run ./cmd/main.go --web
# → http://localhost:8080

Use a specific domain database or port:

go run ./cmd/main.go --web --db ~/.local/share/box-box/boxbox.db --port 8080

Run — Web dev (Vite + Go API)

Vite proxies /api to the Go server. Set BOXBOX_API_PORT to match the Go --port.

Terminal 1 — API (seeded DB is enough for UI work without ingesting):

go run ./scripts/seed-e2e-db/main.go --db /tmp/boxbox-dev.db
BOXBOX_DISABLE_LIVE=1 go run ./cmd/main.go --web --db /tmp/boxbox-dev.db --port 18080

Terminal 2 — frontend:

BOXBOX_API_PORT=18080 npm run dev --prefix frontend
# default Vite port 5173 → http://localhost:5173

BOXBOX_DISABLE_LIVE=1 skips starting the SignalR bridge (used in CI and local UI work).

Web routes

Route Purpose
/ Command Center — fan-facing race-weekend home with GP identity, live status, session schedule, and analysis links
/race-hub?session_key=<key> Race Hub — weekend workspace with session rail and Overview / Race Story / Strategy / Lap Data / Conditions / Race Control / Data Status tabs. Bare /race-hub auto-resolves to the focus session.
/admin Admin / Data Health — ingestion coverage, local data status, and suggested CLI commands
/data-library Legacy alias for Admin / Data Health
/live Live Timing — timing tower and race control via SSE when a session is live

Example after seeding: http://localhost:5173/race-hub?session_key=9472

Ingest historical data and briefing feeds

Ingestion is a CLI mode on the same binary. Only one of --ingest-year, --ingest-meeting, --ingest-session, or --ingest-news may be set per run.

# Season: discover and store meeting metadata (2023+)
go run ./cmd/main.go --ingest-year 2025

# Full race weekend: all sessions + Race Hub datasets
go run ./cmd/main.go --ingest-meeting 1229

# Single session only
go run ./cmd/main.go --ingest-session 9472

# Preview without writing
go run ./cmd/main.go --dry-run --ingest-meeting 1229

# Refresh Paddock Briefing RSS/Atom feeds
go run ./cmd/main.go --ingest-news

# Custom DB path (default: ~/.local/share/box-box/boxbox.db)
go run ./cmd/main.go --ingest-meeting 1229 --db /tmp/boxbox.db

Use --ingest-meeting for a complete weekend. --ingest-year lists meetings for the season; ingest meetings individually or by weekend as needed. Optional analytics fetches may partially fail without aborting the whole run.

OPENF1_API_KEY

export OPENF1_API_KEY=your_key_here
go run ./cmd/main.go --web

Without a key, the free OpenF1 tier is used. A key may be required for paid-tier behavior (e.g. live session access during API lockouts). Ingestion and TUI calls use the same client.

Local files

Path Purpose
~/.local/share/box-box/boxbox.db Domain database (default --db)
~/.cache/box-box/cache.db OpenF1 HTTP response cache (TUI / client)
box-box.log TUI application log (project root)
frontend/dist/ Production React build (gitignored — build locally, do not commit)
.playwright/*.db Seeded DBs for automated tests

Web mode logs to stderr.

Tests and QA

Go (targeted packages)

go test ./internal/live ./internal/models ./internal/store ./internal/ingest ./internal/query ./internal/web

All packages: go test ./...

OpenF1 integration tests (network, rate-limit aware): go test -v ./internal/api

Frontend unit tests and build

npm --prefix frontend test -- --run
npm --prefix frontend run build

E2E (Vite dev proxy + seeded API)

Starts seeded Go on port 18080 and Vite on 15173 (see playwright.config.ts).

npx playwright install   # first time only
npm run test:e2e

E2E production (Go serves frontend/dist)

npm run test:e2e:prod

Visual regression (screenshots)

npm run test:visual          # dev proxy stack
npm run test:visual:prod     # production serving (canonical baselines)

# after intentional UI changes
npm run test:visual:update
npm run test:visual:prod:update

Snapshots live under tests/visual/__snapshots__/.

Known limitations

  • Live timing only works when F1 is broadcasting timing data; there is no guaranteed live session for local dev.
  • E2E / visual tests use BOXBOX_DISABLE_LIVE=1 and seeded SQLite — they do not exercise full SignalR live behavior.
  • frontend/dist is generated output; build before production web mode or test:e2e:prod.
  • TUI historical views still use OpenF1 on demand with the HTTP cache; the Web UIs local-first model does not fully replace the TUI yet.
  • --ingest-year stores season meetings, not full session datasets — use --ingest-meeting or --ingest-session for Race Hub data.

License

MIT © Aman Tahiliani


Unofficial project; not associated with Formula 1 or the FIA.

Description
No description provided
Readme 69 MiB
Languages
Go 44.1%
TypeScript 41.3%
CSS 9.4%
JavaScript 2.9%
HTML 1%
Other 1.3%