- Created `recharts.types.ts` and `recharts.types.test.ts` for custom tooltip and legend props. - Added `router.types.ts` for location state management. - Implemented `session.types.ts` and corresponding tests for session metadata and telemetry arrays. - Developed utility functions in `countryUtils.ts` for country code mapping. - Added driver and car image mappings in `imageMapping.ts` for multiple seasons. - Configured TypeDoc for documentation generation. - Set up Vitest for testing with configuration in `vitest.config.ts`. |
||
|---|---|---|
| .github | ||
| .husky | ||
| public | ||
| src | ||
| .env.example | ||
| .gitignore | ||
| .npmrc | ||
| .prettierrc | ||
| bun.lockb | ||
| CODE_OF_CONDUCT.md | ||
| components.json | ||
| CONTRIBUTING.md | ||
| eslint.config.js | ||
| index.html | ||
| LICENSE | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| SECURITY.md | ||
| tsconfig.app.json | ||
| tsconfig.json | ||
| tsconfig.node.json | ||
| typedoc.json | ||
| vite.config.ts | ||
| vitest.config.ts | ||
Fastlytics
Democratising F1 telemetry data for everyone.
This README provides a comprehensive overview of the codebase, including the project structure, technology stack, API endpoints, database schema, frontend routes, and configuration.
Table of Contents
- Project Overview
- Directory Structure
- Technology Stack
- Frontend Architecture
- API Endpoints
- Database Schema
- Backend Architecture
- Configuration
- Testing
- Build and Deployment
Project Overview
Fastlytics is a Formula 1 analytics platform that provides granular telemetry analysis, real-time race data, and historical performance comparisons. The codebase consists of a React-based frontend, a Cloudflare Worker API proxy, and integration with external F1 data APIs (OpenF1) and a Supabase backend for user authentication and data storage.
Directory Structure
Fastlytics/
├── .github/ # GitHub workflows and configurations
├── .husky/ # Git hooks for pre-commit linting
├── .vscode/ # VS Code workspace settings
├── public/ # Static assets (images, icons)
│ ├── cars/ # F1 car images by year
│ └── drivers/ # Driver headshots by year
├── src/ # Main application source code
│ ├── __tests__/ # Test files
│ ├── app/ # App-specific styles
│ ├── components/ # React components
│ │ ├── activity/ # Activity-related components
│ │ ├── calendar/ # Calendar components
│ │ ├── common/ # Shared/common components
│ │ ├── dashboard/ # Dashboard-specific components
│ │ ├── landing/ # Landing page components
│ │ ├── mobile/ # Mobile-specific components
│ │ ├── replay/ # Session replay components
│ │ └── ui/ # UI component library (shadcn/ui)
│ ├── contexts/ # React contexts
│ ├── hooks/ # Custom React hooks
│ ├── lib/ # Core libraries
│ │ ├── api.ts # API client and endpoints
│ │ ├── supabase.ts # Supabase client
│ │ └── utils.ts # Utility functions
│ ├── pages/ # Page components
│ ├── types/ # TypeScript type definitions
│ └── utils/ # Utility functions
├── supabase/ # Supabase migrations
│ └── migrations/ # Database migrations
├── workers/ # Cloudflare Worker for API proxy
│ └── src/ # Worker source code
└── package.json # Root package configuration
Technology Stack
Frontend
- Framework: React 18.x with TypeScript 5.x
- Build Tool: Vite 7.x
- Routing: React Router DOM 7.x
- Styling: Tailwind CSS 4.x with shadcn/ui
- State Management: TanStack Query (React Query) 5.x
- UI Components: Radix UI primitives, Tremor 3.x
- Charts: Recharts 2.x
- Forms: React Hook Form 7.x with Zod validation
- Authentication: Supabase Auth
- Testing: Vitest with Testing Library
Backend/Infrastructure
- API Proxy: Cloudflare Workers
- Database: Supabase (PostgreSQL)
- External APIs: OpenF1 for F1 telemetry data
Frontend Architecture
Routing
The application uses React Router DOM for navigation. Routes are defined in src/App.tsx and include:
| Path | Component | Layout | Protection |
|---|---|---|---|
/ |
Landing |
LandingLayout | Public |
/about |
AboutUs |
MainLayout | Public |
/privacy-policy |
PrivacyPolicy |
MainLayout | Public |
/terms-of-service |
TermsOfService |
MainLayout | Public |
/faq |
FAQ |
MainLayout | Public |
/refund-policy |
RefundPolicy |
MainLayout | Public |
/contact |
Contact |
MainLayout | Public |
/auth |
Auth |
- | Public |
/dashboard |
Dashboard |
DashboardLayout | Public |
/race/:raceId |
Race |
DashboardLayout | Public |
/calendar |
Calendar |
DashboardLayout | Public |
/standings/teams |
TeamStandings |
DashboardLayout | Public |
/standings/drivers |
DriverStandings |
DashboardLayout | Public |
/standings/progression |
ChampionshipProgression |
DashboardLayout | Gated |
/team-pace |
TeamPaceAnalysis |
DashboardLayout | Gated |
/onboarding |
Onboarding |
- | Protected |
/account |
Account |
DashboardLayout | Protected |
/replay/:year/:event/:session |
SessionReplayPage |
DashboardLayout | Gated |
Route Protection Types:
- Public: Accessible to all users
- Gated: Shows login prompt for unauthenticated users, but allows access to basic features
- Protected: Requires authentication to access
State Management
The application uses multiple state management approaches:
-
TanStack Query: For server state (API data fetching, caching, synchronization)
- Configured in
src/App.tsxwith aQueryClientprovider
- Configured in
-
React Context:
AuthContext: Manages user authentication stateSeasonContext: Manages selected F1 season/year
-
Local Component State: Using
useStateanduseReducerfor UI-specific state
API Client
The API client is implemented in src/lib/api.ts and uses a request helper from src/lib/api-client.ts. All API calls go through the backend API proxy (Cloudflare Worker).
Key features:
- Base URL configuration via environment variable
- Automatic API key injection
- Type-safe responses using TypeScript generics
Components
The codebase contains numerous React components organized by functionality:
UI Components (shadcn/ui)
Located in src/components/ui/, these include:
button.tsxcard.tsxchart.tsxdialog.tsxdropdown-menu.tsxselect.tsxtable.tsxtabs.tsxtoast.tsx- And many more...
Chart Components
Located in src/components/, these include:
BrakeChart.tsx- Brake pressure telemetry visualizationDRSChart.tsx- DRS zone visualizationGapToLeaderChart.tsx- Gap to leader over timeGearMapChart.tsx- Gear usage visualizationPaceAnalysisChart.tsx- Pace distributionPositionChart.tsx- Position changes over lapsRPMChart.tsx- RPM telemetrySpeedTraceChart.tsx- Speed trace visualizationThrottleChart.tsx- Throttle applicationTireStrategy.tsx- Tire compound visualizationTrackEvolutionChart.tsx- Lap time evolutionCircuitComparisonChart.tsx- Driver comparisonRacingChart.tsx- Main racing telemetry chart
Mobile Components
Located in src/components/mobile/:
MobileLanding.tsxMobileCalendar.tsxMobileRace.tsxMobileTelemetry.tsxMobileDriverStandings.tsxMobileTeamStandings.tsxMobileHeadToHead.tsxMobileAuth.tsxMobileAccount.tsx
Replay Components
Located in src/components/replay/:
SessionReplay.tsx- Full session replay visualizationReplayLoader.tsx- Replay data loader
Pages
Located in src/pages/:
Dashboard.tsx- Main dashboard with widgetsRace.tsx- Race analysis page (most complex, ~87KB)Calendar.tsx- Race calendarDriverStandings.tsx- Driver championship standingsTeamStandings.tsx- Constructor championship standingsChampionshipProgression.tsx- Season progression chartsTeamPaceAnalysis.tsx- Team pace analysisAuth.tsx- Authentication pageOnboarding.tsx- User onboarding flowAccount.tsx- User account managementSessionReplayPage.tsx- Session replay viewer
Contexts
Located in src/contexts/:
AuthContext.tsx: Provides authentication state and methods (login, logout, signup) using Supabase AuthSeasonContext.tsx: Manages the selected F1 season/year for data filtering
Hooks
Located in src/hooks/:
use-mobile.tsx: Detects if the user is on a mobile deviceuse-toast.ts: Toast notification hookuseAnalytics.ts: Analytics tracking hookuseChartVisibility.ts: Manages chart visibility states
Types
Located in src/types/:
index.ts- Main type exportschart.types.ts- Chart-related typeserror.types.ts- Error handling types
Utilities
Located in src/lib/:
api.ts- API client and all endpoint functionsapi-client.ts- HTTP request helpersupabase.ts- Supabase client initializationutils.ts- General utility functionsdriverColor.ts- Driver color mappingteamUtils.ts- Team-related utilitiesseasonUtils.ts- Season utilitiessession.ts- Session utilitieschampionship.ts- Championship calculationsopenf1.ts- OpenF1 API helperslogger.ts- Logging utilityconsent.ts- Cookie consent management
API Endpoints
All API endpoints are defined in src/lib/api.ts and communicate with the backend API via the Cloudflare Worker proxy. The base URL is configured via VITE_API_BASE_URL (defaults to https://api.fastlytics.app).
Sessions API
| Function | Endpoint | Description |
|---|---|---|
fetchAvailableSessions() |
GET /api/sessions?year={year}&event={event} |
Fetches available sessions for a given event |
fetchSessionDrivers() |
GET /api/session/drivers?year={year}&event={event}&session={session} |
Fetches drivers participating in a session |
fetchDriverLapNumbers() |
GET /api/laps/driver?year={year}&event={event}&session={session}&driver={driver} |
Fetches available lap numbers for a driver |
fetchEventSessionSchedule() |
GET /api/schedule/{year}/{event}/sessions |
Fetches session schedule for an event |
Telemetry API
| Function | Endpoint | Description |
|---|---|---|
fetchTelemetrySpeed() |
GET /api/telemetry/speed?year={year}&event={event}&session={session}&driver={driver}&lap={lap} |
Speed telemetry data |
fetchTelemetryGear() |
GET /api/telemetry/gear?year={year}&event={event}&session={session}&driver={driver}&lap={lap} |
Gear shift data |
fetchGearShiftMap() |
GET /api/telemetry/gear-map?year={year}&event={event}&session={session}&driver={driver}&lap={lap} |
Gear shift map (SVG paths) |
fetchTelemetryThrottle() |
GET /api/telemetry/throttle?year={year}&event={event}&session={session}&driver={driver}&lap={lap} |
Throttle application data |
fetchTelemetryBrake() |
GET /api/telemetry/brake?year={year}&event={event}&session={session}&driver={driver}&lap={lap} |
Brake pressure data |
fetchTelemetryRPM() |
GET /api/telemetry/rpm?year={year}&event={event}&session={session}&driver={driver}&lap={lap} |
RPM data |
fetchTelemetryDRS() |
GET /api/telemetry/drs?year={year}&event={event}&session={session}&driver={driver}&lap={lap} |
DRS zone data |
fetchPaceDistribution() |
GET /api/telemetry/pace-distribution?year={year}&event={event}&session={session}&drivers={drivers} |
Pace distribution statistics |
Lap Data API
| Function | Endpoint | Description |
|---|---|---|
fetchLapTimes() |
GET /api/laptimes?year={year}&event={event}&session={session}&drivers={drivers} |
Lap time comparison for multiple drivers |
fetchLapPositions() |
GET /api/lapdata/positions?year={year}&event={event}&session={session} |
Lap-by-lap position data |
Standings API
| Function | Endpoint | Description |
|---|---|---|
fetchDriverStandings() |
GET /api/standings/drivers?year={year} |
Current driver standings |
fetchTeamStandings() |
GET /api/standings/teams?year={year} |
Current constructor standings |
fetchChampionshipProgression() |
GET /api/standings/progression?year={year} |
Championship points progression |
Results API
| Function | Endpoint | Description |
|---|---|---|
fetchRaceResults() |
GET /api/results/races?year={year} |
Race winners for a season |
fetchSpecificRaceResults() |
GET /api/results/race/{year}/{eventSlug}?session={session} |
Detailed race results |
Schedule API
| Function | Endpoint | Description |
|---|---|---|
fetchSchedule() |
GET /api/schedule/{year} |
Full season schedule |
Strategy & Analysis API
| Function | Endpoint | Description |
|---|---|---|
fetchTireStrategy() |
GET /api/strategy?year={year}&event={event}&session={session} |
Tire strategy for all drivers |
fetchStintAnalysis() |
GET /api/stint-analysis?year={year}&event={event}&session={session} |
Detailed stint analysis |
fetchTrackEvolution() |
GET /api/track-evolution?year={year}&event={event}&session={session} |
Track evolution and lap time trends |
fetchSessionIncidents() |
GET /api/incidents?year={year}&event={event}&session={session} |
SC/VSC and Red Flag periods |
Team Pace API
| Function | Endpoint | Description |
|---|---|---|
fetchTeamPaceSummary() |
GET /api/team-pace/summary?year={year} |
Team pace summary for season |
fetchTeamPaceEvent() |
GET /api/team-pace/event?year={year}&event_slug={eventSlug} |
Detailed team pace for an event |
Comparison API
| Function | Endpoint | Description |
|---|---|---|
fetchSectorComparison() |
GET /api/comparison/sectors?year={year}&event={event}&session={session}&driver1={driver1}&driver2={driver2}&lap1={lap1}&lap2={lap2} |
Sector-by-sector driver comparison |
Replay API
| Function | Endpoint | Description |
|---|---|---|
fetchSessionReplay() |
GET /api/replay/session?year={year}&event={event}&session={session} |
Full session replay data |
fetchSessionReplayMetadata() |
GET /api/replay/metadata?year={year}&event={event}&session={session} |
Replay metadata |
fetchSessionReplayChunk() |
GET /api/replay/chunk?year={year}&event={event}&session={session}&chunk_id={chunkId} |
Chunked replay data |
Driver/Team Details API
| Function | Endpoint | Description |
|---|---|---|
getDriverDetails() |
GET /api/driver/{driverId} |
Detailed driver information |
getTeamDetails() |
GET /api/team/{teamId} |
Detailed team information |
Data Types
The API uses the following main data structures (defined in src/lib/api.ts):
// Lap Time Data
interface LapTimeDataPoint {
LapNumber: number;
[driverCode: string]: number | null;
}
// Telemetry Data
interface SpeedDataPoint {
Distance: number;
Speed: number;
}
interface ThrottleDataPoint {
Distance: number;
Throttle: number;
}
interface BrakeDataPoint {
Distance: number;
Brake: number;
}
interface RPMDataPoint {
Distance: number;
RPM: number;
}
interface DRSDataPoint {
Distance: number;
DRS: number;
}
interface GearMapDataPoint {
X: number;
Y: number;
nGear: number;
}
// Race Results
interface DetailedRaceResult {
position: number | null;
driverCode: string;
fullName: string;
team: string;
points: number | null;
status: string;
gridPosition?: number | null;
teamColor: string;
isFastestLap?: boolean;
q1Time?: string | null;
q2Time?: string | null;
q3Time?: string | null;
// ... more fields
}
// Session Replay (Columnar Format)
interface SessionReplayData {
time: number[];
drivers: ReplayDriversMap;
driver_colors: { [code: string]: string };
track_statuses: { status: string; start_time: number; end_time: number | null }[];
circuit_layout: string;
race_control_messages: { time: number; category: string; message: string; flag?: string }[];
// ... more fields
}
Database Schema
Profiles Table
The main user table is profiles, created in supabase/migrations/20240523_init_profiles.sql:
CREATE TABLE profiles (
id UUID REFERENCES auth.users NOT NULL PRIMARY KEY,
updated_at TIMESTAMP WITH TIME ZONE,
username TEXT UNIQUE,
full_name TEXT,
avatar_url TEXT,
website TEXT,
favorite_driver TEXT,
favorite_team TEXT,
onboarding_completed BOOLEAN DEFAULT FALSE,
CONSTRAINT username_length CHECK (char_length(username) >= 3)
);
Row Level Security (RLS) Policies:
- Public profiles are viewable by everyone
- Users can insert their own profile
- Users can update their own profile
Migrations
Located in supabase/migrations/:
20240523_init_profiles.sql- Initial profiles table with RLS20251205_subscription_fields.sql- Subscription fields20260130_remove_subscription_fields.sql- Removed subscription fields20260228_analytics_centralization.sql- Analytics centralization
Backend Architecture
Cloudflare Worker Proxy
Located in workers/, this Cloudflare Worker proxies API requests from the frontend to the backend API, injecting the API key server-side to keep it secure.
Architecture:
Frontend → Cloudflare Worker (injects X-API-Key) → Backend API (data.fastlytics.app)
Key Features:
- CORS handling for allowed origins (
fastlytics.app,beta.fastlytics.app,www.fastlytics.app) - API key injection via
X-API-Keyheader - Proxy all
/api/*requests to backend - Special handling for
sitemap.xml
Configuration (workers/wrangler.toml):
- Worker name:
fastlytics-api - Routes: Configured for
api.fastlytics.app
Environment Variables:
FASTLYTICS_API_KEY- Secret (set viawrangler secret put)BACKEND_API_URL- Backend API URL (default:https://data.fastlytics.app)
Configuration
Environment Variables
Create a .env file based on .env.example:
# Supabase Configuration
VITE_SUPABASE_URL=your_supabase_project_url
VITE_SUPABASE_ANON_KEY=your_supabase_anon_key
# Backend API Configuration
VITE_API_BASE_URL=https://api.fastlytics.app
VITE_FASTLYTICS_API_KEY=
# Analytics (Optional)
VITE_UMAMI_WEBSITE_ID=
VITE_PUBLIC_POSTHOG_KEY=
VITE_PUBLIC_POSTHOG_HOST=
Vite Configuration
The Vite configuration (vite.config.ts) includes:
- React SWC plugin for fast builds
- Tailwind CSS plugin
- Path aliases (
@forsrc/)
TypeScript Configuration
Multiple TypeScript configs:
tsconfig.json- Base configurationtsconfig.app.json- Frontend app configtsconfig.node.json- Node.js config
Testing
The project uses Vitest for testing.
Test Files:
src/__tests__/subscription-removal.test.tssrc/lib/api-client.test.tssrc/lib/utils.test.tssrc/types/__tests__/*.test.tssrc/components/ui/button.test.tsx
Running Tests:
npm run test
Build and Deployment
Development
# Install dependencies
npm install
# Start development server
npm run dev
# Available at http://localhost:5173
Build
# Production build
npm run build
# Development build
npm run build:dev
Linting & Formatting
# Lint
npm run lint
# Fix linting issues
npm run lint:fix
# Format code
npm run format
Cloudflare Worker Deployment
cd workers
# Install dependencies
npm install
# Deploy
npm run deploy
# Local development
npm run dev
# View logs
npm run tail