F1 DataStop Docs

Architecture

Monorepo & pipeline map

Layout

f1datastop/
├── web/            # Vite React 18 + TS app (port 8080, builds to web/dist, Vercel deploys it)
├── supabase/       # functions/ (f1-proxy, bmc-webhook) + migrations/ (fresh-DB squash + forward)
├── analysis/       # Python: ingest, backfill, generate, *_export, queue processors
├── api/og.ts       # Vercel OG-image function (bot user-agent rewrite)
├── docs-site/      # THIS site — plain static HTML served by GitHub Pages
└── .github/workflows/  # pr-ci.yml (CI + cron), release.yml (manual), docs.yml (this site)

Data flow

Jolpica/Ergast ──┐
OpenF1 ──────────┼──▶ f1-proxy edge fn (+ api_cache) ──▶ web (React Query hooks)
FastF1 (Python) ─┘         │                                    ▲
                           ▼                                    │ public-read RLS
              Supabase warehouse (f1_* tables/views) ───────────┘
                           ▲
analysis/*.py (Actions cron) ──▶ Cloudflare R2 (cdn.f1datastop.com) ──▶ web Deep Dive tab

Serving rule: durable warehouse domains (results, laps, schedule) are DB-first behind the VITE_DB_SERVING_ENABLED flag (default off, rollback = flip flag). Volatile data (live timing, standings) stays on the proxy. Any DB miss falls through to proxy — a DB problem degrades to today's behavior, never a user-facing failure. Full spec: docs/DATA_BACKEND.md.

Session codes

Every layer uses the same codes: FP1 FP2 FP3 Q SQ SS S R (SQ = sprint qualifying/shootout, SS = sprint shootout legacy, S = sprint). Stored in f1_session.session_type, used by R2 paths and export scripts.

CI jobs (pr-ci.yml)

JobWhenWhat
webevery push + PRtypecheck, advisory lint, test, build
python-smokeevery push + PRpip install, byte-compile analysis/
reconcileevery 6 h + 30-min race-weekend ticksingest results, export season JSON to R2
chartsevery 2 h Fri–Sunrender Deep Dive charts for finished sessions
assets06/12/18 UTC Fri–Suntelemetry, circuits, replays, weather
digestdaily 07:17 UTCfree-tier usage digest to Slack
queueevery 5 mindrain f1_chart_requests + f1_telemetry_requests

All scheduled jobs are guarded to the main repo (github.repository == 'ibrahimroshdy/f1datastop'), so forks get zero-secret CI. Any job runs on demand via workflow_dispatch.