mirror of
https://github.com/AmanTahiliani/box-box.git
synced 2026-08-07 11:54:59 -04:00
196 lines
4.9 KiB
Markdown
196 lines
4.9 KiB
Markdown
|
|
# Database Design
|
||
|
|
|
||
|
|
## Summary
|
||
|
|
|
||
|
|
SQLite should become the local source of truth for historical and completed
|
||
|
|
session data. The design should store both raw source payloads and normalized
|
||
|
|
domain rows. Raw payloads preserve source fidelity and make reprocessing
|
||
|
|
possible. Normalized rows power fast product queries, analytics, and stable Web
|
||
|
|
screens.
|
||
|
|
|
||
|
|
## Storage Strategy
|
||
|
|
|
||
|
|
Use two layers:
|
||
|
|
|
||
|
|
1. Raw source storage.
|
||
|
|
- Preserve fetched payloads exactly enough to reprocess later.
|
||
|
|
- Track source, endpoint/topic, parameters, fetch time, status, and errors.
|
||
|
|
2. Normalized domain tables.
|
||
|
|
- Queryable application data keyed by F1 identifiers.
|
||
|
|
- Built from successful source payloads.
|
||
|
|
- Safe to upsert idempotently.
|
||
|
|
|
||
|
|
## Raw Payload Tables
|
||
|
|
|
||
|
|
Candidate tables:
|
||
|
|
|
||
|
|
- `source_payloads`
|
||
|
|
- `id`
|
||
|
|
- `source`
|
||
|
|
- `resource`
|
||
|
|
- `request_key`
|
||
|
|
- `url_or_topic`
|
||
|
|
- `params_json`
|
||
|
|
- `payload_json`
|
||
|
|
- `fetched_at`
|
||
|
|
- `status`
|
||
|
|
- `error`
|
||
|
|
- `schema_version`
|
||
|
|
|
||
|
|
- `ingestion_runs`
|
||
|
|
- `id`
|
||
|
|
- `scope_type`
|
||
|
|
- `scope_key`
|
||
|
|
- `started_at`
|
||
|
|
- `finished_at`
|
||
|
|
- `status`
|
||
|
|
- `refresh`
|
||
|
|
- `summary_json`
|
||
|
|
|
||
|
|
- `ingestion_items`
|
||
|
|
- `id`
|
||
|
|
- `run_id`
|
||
|
|
- `dataset`
|
||
|
|
- `meeting_key`
|
||
|
|
- `session_key`
|
||
|
|
- `status`
|
||
|
|
- `source`
|
||
|
|
- `started_at`
|
||
|
|
- `finished_at`
|
||
|
|
- `error`
|
||
|
|
|
||
|
|
## Normalized Domain Tables
|
||
|
|
|
||
|
|
Core calendar/session tables:
|
||
|
|
|
||
|
|
- `meetings`
|
||
|
|
- `sessions`
|
||
|
|
- `circuits`
|
||
|
|
|
||
|
|
Participant tables:
|
||
|
|
|
||
|
|
- `drivers`
|
||
|
|
- `session_drivers`
|
||
|
|
- `teams` or team snapshots by season/session.
|
||
|
|
|
||
|
|
Classification and standings:
|
||
|
|
|
||
|
|
- `session_results`
|
||
|
|
- `starting_grids`
|
||
|
|
- `driver_championship_standings`
|
||
|
|
- `constructor_championship_standings`
|
||
|
|
|
||
|
|
Race/session analysis:
|
||
|
|
|
||
|
|
- `laps`
|
||
|
|
- `stints`
|
||
|
|
- `pit_stops`
|
||
|
|
- `positions`
|
||
|
|
- `intervals`
|
||
|
|
- `race_control_messages`
|
||
|
|
- `weather_samples`
|
||
|
|
- `overtakes`
|
||
|
|
|
||
|
|
Telemetry and spatial data:
|
||
|
|
|
||
|
|
- `car_data_samples`
|
||
|
|
- `location_samples`
|
||
|
|
- `track_outlines`
|
||
|
|
|
||
|
|
Media metadata:
|
||
|
|
|
||
|
|
- `team_radio_messages`
|
||
|
|
|
||
|
|
Derived/read-model candidates:
|
||
|
|
|
||
|
|
- `session_dataset_status`
|
||
|
|
- `race_key_moments`
|
||
|
|
- `driver_session_summaries`
|
||
|
|
- `race_lap_snapshots`
|
||
|
|
|
||
|
|
Derived tables should be added only when query cost or UI complexity justifies
|
||
|
|
them. Start with normalized source tables and build read models in Go unless
|
||
|
|
performance argues otherwise.
|
||
|
|
|
||
|
|
## Provenance and Freshness
|
||
|
|
|
||
|
|
Each normalized dataset should be traceable to source ingestion metadata.
|
||
|
|
|
||
|
|
Track:
|
||
|
|
|
||
|
|
- Source: OpenF1, SignalR, static archive, manual, cache.
|
||
|
|
- First ingested time.
|
||
|
|
- Last ingested time.
|
||
|
|
- Last successful refresh.
|
||
|
|
- Last error.
|
||
|
|
- Completion status.
|
||
|
|
- Whether stale fallback was used.
|
||
|
|
|
||
|
|
This metadata supports the Data Library screen and makes partial data honest.
|
||
|
|
|
||
|
|
## Immutability Policy
|
||
|
|
|
||
|
|
Completed historical sessions:
|
||
|
|
|
||
|
|
- Treat as immutable after successful ingestion.
|
||
|
|
- Do not refetch unless `--refresh` is explicitly requested.
|
||
|
|
- Allow reprocessing from raw payloads if schema or read models change.
|
||
|
|
|
||
|
|
Current/future sessions:
|
||
|
|
|
||
|
|
- Treat as refreshable.
|
||
|
|
- Allow opportunistic metadata fetches.
|
||
|
|
- Avoid high-volume refreshes without explicit action.
|
||
|
|
|
||
|
|
Live sessions:
|
||
|
|
|
||
|
|
- SignalR is authoritative for live state.
|
||
|
|
- Persist live data as an append-only event/snapshot stream after the live
|
||
|
|
bridge is extracted.
|
||
|
|
- Keep live data separate from normalized post-session OpenF1 records until
|
||
|
|
reconciliation is designed.
|
||
|
|
- Treat live data as the record of what was seen during the session, not as the
|
||
|
|
corrected final historical truth.
|
||
|
|
|
||
|
|
## Migration And File Layout
|
||
|
|
|
||
|
|
The current project already creates a SQLite cache database for raw HTTP
|
||
|
|
responses. The domain database should be introduced without breaking that cache.
|
||
|
|
|
||
|
|
Default stance:
|
||
|
|
|
||
|
|
- Existing cache tables are infrastructure, not product domain state.
|
||
|
|
- New domain tables should be owned by `internal/store`.
|
||
|
|
- A separate domain DB file is the lower-risk first implementation unless a
|
||
|
|
schema design pass shows strong reasons to reuse the same file.
|
||
|
|
- If the same file is reused, domain tables must be namespaced clearly and
|
||
|
|
migrations must avoid touching the current `cache` table except through
|
||
|
|
deliberate cache work.
|
||
|
|
- Do not auto-migrate URL-keyed cache entries into domain rows.
|
||
|
|
- Use explicit ingestion to populate the new domain tables.
|
||
|
|
|
||
|
|
## High-Volume Data
|
||
|
|
|
||
|
|
High-volume tables need careful indexing and retention decisions:
|
||
|
|
|
||
|
|
- `car_data_samples`
|
||
|
|
- `location_samples`
|
||
|
|
- `positions`
|
||
|
|
- `intervals`
|
||
|
|
- `laps` for full-season analysis
|
||
|
|
|
||
|
|
Initial policy:
|
||
|
|
|
||
|
|
- Ingest high-volume telemetry only when explicitly requested.
|
||
|
|
- Keep Race Hub v1 focused on results, strategy, laps, race control, weather,
|
||
|
|
positions, and track outlines.
|
||
|
|
|
||
|
|
## Research Questions
|
||
|
|
|
||
|
|
- Exact indexes for Race Hub, Live Replay, Driver Explorer, and Standings.
|
||
|
|
- Whether `positions` and `intervals` should be downsampled or stored in full.
|
||
|
|
- Whether `car_data_samples` and `location_samples` should be optional datasets.
|
||
|
|
- How to map official F1 static archive sessions to OpenF1 `session_key`.
|
||
|
|
- Whether to use SQLite FTS for race-control/team-radio search.
|
||
|
|
- How to version schema migrations without adding unnecessary framework weight.
|