F1 DataStop Docs

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):

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.

Never redistribute raw Ergast data to R2 — proxy-only. And never cache empty/error as final: post-session gaps are partial with backoff retry, not complete.