Backend
Supabase backend & warehouse
Fresh-project bootstrap
Migrations are the source of truth: 00000000000000_baseline.sql (fresh-DB squash) plus forward migrations. Source: supabase/migrations/README.md.
supabase login
supabase link --project-ref <project-ref>
supabase db push
supabase functions deploy f1-proxy
supabase functions deploy bmc-webhook --no-verify-jwt
supabase secrets set BMC_WEBHOOK_SECRET=<secret>
Then add Actions secrets: R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET, BLOB_PUBLIC_BASE, SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, SLACK_ALERTS_WEBHOOK. Note: bmc-webhook is public (verify_jwt = false in supabase/config.toml) and authenticates via BMC_WEBHOOK_SECRET.
Canonical warehouse
All tables prefixed f1_, natural keys, UPSERT-on-conflict ingestion, public-read RLS + service-role-only writes (spec: docs/DATA_BACKEND.md):
- Dimensions:
f1_driver,f1_constructor(+ career tables),f1_season,f1_circuit. - Spine:
f1_race(uniqueseason,round) +f1_session(uniqueseason,round,session_type, carries theopenf1_session_keycrosswalk — no heuristic matching). - Ergast facts:
f1_race_result,f1_qualifying_result,f1_sprint_result,f1_pit_stop,f1_lap(heavy),f1_driver_standing,f1_constructor_standing. - OpenF1 facts (2023+):
f1_session_driver(driver_number ↔ ergast_id bridge),f1_weather,f1_starting_grid,f1_overtake,f1_team_radio,f1_position(post-session snapshots; live stays on proxy). - FastF1 summaries:
f1_lap_summary,f1_stint_summary,f1_session_result_ff1(emitted bygenerate.pyat render time, zero extra fetch). - Ledger:
f1_sync_state(domain,season,round,session_type,status,…)— statusespending|partial|complete|empty|error|not_applicable. Coverage query:SELECT domain,status,count(*) FROM f1_sync_state GROUP BY domain,status;
Backfill window
Current season + last 3 ([currentYear-3 .. currentYear]) plus future scheduled rounds. Older seasons are intentionally not backfilled — the live proxy serves them. Canonical backfill is analysis/backfill.py (Python sibling of the f1-ingest edge function design):
cd analysis && . .venv/bin/activate
export SUPABASE_URL=http://127.0.0.1:54321 # LOCAL stack only — the user ships to prod
python backfill.py --from-season 2023 --to-season 2026
python backfill.py --season 2025 --dry-run # fetch + print, no writes
DB-serving cutover
Flag VITE_DB_SERVING_ENABLED (default false), independent of VITE_F1_PROXY_ENABLED. Shipping the router with the flag off is a pure no-op; rollback is flipping the flag back. Enable only after f1_sync_state coverage is proven and migrations are applied to prod.
partial with backoff retry, not complete.