Design a Fitness Tracking & Segment Leaderboard App Like Strava
A fitness tracking platform (e.g., Strava, Garmin Connect, Nike Run Club) allows athletes to record GPS activities (runs, bike rides, hikes), automatically detects when athletes pass through competitive road or trail sections (segments), ranks athletes on real-time segment leaderboards (e.g. King/Queen of the Mountain - KOM/QOM), and shares workouts on a social activity feed.
1. Understanding the Problem
Functional Requirements
- Record & Upload Activity: Athletes record GPS traces and upload standard FIT/GPX files or stream live telemetry.
- GPS Polyline Processing: Smooth GPS jitter, elevation noise, and generate map route visuals.
- Automated Segment Matching: Detect all predefined segments intersected during an activity and calculate exact elapsed split times.
- Segment Leaderboards: Maintain real-time global, gender-based, and age-group leaderboards for every segment.
- Social Activity Feed & Kudos: Athletes view friends' activities, give "Kudos" (likes), and leave comments.
Non-Functional Requirements
- High Ingestion Scale: Process millions of GPS activity uploads daily without losing recorded splits.
- Accurate Spatial Matching: Millisecond-accurate start/finish detection on segments despite GPS sensor drift.
- Low Leaderboard Query Latency: Display segment rankings in
< 50ms. - Data Durability: Raw GPS coordinates must be preserved permanently for route audits.
Capacity Estimations & Sizing
- Total Registered Athletes: 100 Million athletes.
- Daily Active Athletes (DAU): 10 Million athletes.
- Daily Activities Uploaded: 15 Million activities/day ~175 uploads/sec average (peaking at 2,000 uploads/sec on Sunday mornings).
- GPS Telemetry Sizing:
- An average 1-hour bike ride records 1 GPS point per second = 3,600 points.
- Each point:
lat(8 bytes) +lng(8 bytes) +elevation(4 bytes) +timestamp(8 bytes) +heart_rate/cadence(4 bytes) 32 bytes. - Average activity size 115 KB (compressed to ~30 KB in binary protocol buffer or FIT format).
- Daily raw GPS storage = 450 GB / day 164 TB / year (stored in S3 / cloud blob storage).
- Segments: 50 Million active global segments.
2. The Set Up
Defining the Core Entities
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ACTIVITY β
ββββββββββββββββββββ¬βββββββββββββββ¬βββββββββββββββββββββββ€
β activity_id β UUID β PRIMARY KEY β
β athlete_id β UUID β INDEX, FK β
β sport_type β VARCHAR(16) β RIDE, RUN, HIKE β
β total_distance_m β FLOAT β Meters β
β elapsed_time_sec β INT β Seconds β
β elevation_gain_m β FLOAT β Meters β
β polyline_summary β TEXT β Encoded Polyline β
β raw_fit_s3_url β VARCHAR(255) β S3 Storage Link β
β created_at β TIMESTAMP β NOT NULL β
ββββββββββββββββββββ΄βββββββββββββββ΄βββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SEGMENT β
ββββββββββββββββββββ¬βββββββββββββββ¬βββββββββββββββββββββββ€
β segment_id β UUID β PRIMARY KEY β
β name β VARCHAR(120) β e.g. "Hawk Hill" β
β start_point β GEOMETRY β Point (Lat, Lng) β
β end_point β GEOMETRY β Point (Lat, Lng) β
β bounding_box β GEOMETRY β Envelope Polygon β
β distance_m β FLOAT β Length of segment β
β avg_grade β DECIMAL(4,2) β Incline percentage β
ββββββββββββββββββββ΄βββββββββββββββ΄βββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SEGMENT_EFFORT β
ββββββββββββββββββββ¬βββββββββββββββ¬βββββββββββββββββββββββ€
β effort_id β UUID β PRIMARY KEY β
β segment_id β UUID β COMPOSITE INDEX, FK β
β athlete_id β UUID β INDEX, FK β
β activity_id β UUID β FK β
β elapsed_time_ms β INT β Milliseconds β
β rank_position β INT β Historical Rank β
β start_time β TIMESTAMP β NOT NULL β
ββββββββββββββββββββ΄βββββββββββββββ΄βββββββββββββββββββββββ
3. High-Level Design
Core Data & Matching Workflows
1. Activity Upload Pathβ
- Mobile app or GPS bike computer uploads FIT/GPX file
POST /api/v1/activities/upload. - The Upload Gateway stores the raw binary file in Raw Activity S3 Storage and publishes an
ActivityUploadedEventto Apache Kafka. - Returns
202 Acceptedto the client.
2. GPS Processing & Segment Matching Pipelineβ
- Activity Processing Worker consumes the event from Kafka:
- Step 1: Jitter Filtering: Applies a Kalman filter to smooth GPS drift and removes erroneous spikes (e.g. GPS jumping across buildings).
- Step 2: Metrics Calculation: Calculates total distance, average speed, moving time, and elevation gain.
- Step 3: Polyline Simplification: Runs the Douglas-Peucker algorithm to generate a compressed polyline string for map rendering.
- Segment Matching Engine:
- Queries a spatial R-Tree / PostGIS Index using the activity's bounding box:
SELECT segment_id FROM segments WHERE bounding_box && ST_Envelope(activity_geometry). - For each candidate segment, performs detailed vector projection to determine if the athlete followed the segment path within a 15-meter buffer.
- Computes split time: .
- Queries a spatial R-Tree / PostGIS Index using the activity's bounding box:
- Writes matched efforts to PostgreSQL and updates Redis Leaderboards.
4. Potential Deep Dives & Bottlenecks
Deep Dive 1: Scalable Segment Matching (Bounding Box Filtering + FrΓ©chet Distance)
How do we match an activity containing 4,000 GPS points against 50 Million global segments without performing slow, brute-force geometric comparisons?
Two-Stage Spatial Filtering Architecture:
Stage 1: Coarse Filtering (Spatial Bounding Box / R-Tree):
- Each segment has a pre-computed bounding box envelope.
- Query PostGIS / Spatial R-Tree in memory:
ST_Intersects(activity_bounding_box, segment_bounding_box).
β Filters 50 Million global segments down to ~5-15 local candidate segments in < 5ms!
Stage 2: Fine-Grained Path Traversal (Discrete FrΓ©chet Distance):
- Candidate segment has ordered polyline: S = [p1, p2, ..., pn].
- Activity has ordered GPS points: A = [a1, a2, ..., am].
- We verify:
1. Athlete passed within 15m of start_point (Interpolate exact millisecond crossing).
2. Athlete traversed the segment in the correct direction (bearing check).
3. Discrete FrΓ©chet distance between S and A sub-track is <= 20 meters.
4. Athlete passed within 15m of end_point.
β Precise elapsed time calculated with sub-second interpolation!
Deep Dive 2: Real-Time Segment Leaderboards (Redis Sorted Sets)
How do we maintain instant leaderboards (e.g. Top 10, personal bests, King of the Mountain) for 50 Million segments?
- Redis Sorted Set (ZSET) Per Segment:
- Key:
leaderboard:{segment_id} - Score:
elapsed_time_ms(lower is better; ascending order). - Member:
athlete_id
- Key:
- Recording a New Effort:
- Worker runs:
ZADD leaderboard:{segment_id} GT 142050 athlete_101(only updates if it beats the athlete's existing personal record).
- Worker runs:
- Querying Top 10 Athletes (KOM / QOM):
ZRANGE leaderboard:{segment_id} 0 9 WITHSCORESReturns top 10 in 0.5ms!
- Querying Athlete's Rank:
ZRANK leaderboard:{segment_id} athlete_101Returns exact global position ().
Deep Dive 3: Digital Doping & Anomaly Detection (GPS Cheating)
What happens when someone drives a car or rides an electric motorcycle and uploads it as a bicycle ride, stealing the King of the Mountain title?
- Speed & Acceleration Thresholds:
- If cycling segment speed exceeds 75 km/h on a steep uphill grade Flagged automatically.
- If instantaneous acceleration exceeds human physical limits ().
- Cadence & Heart Rate Sensor Correlation:
- Compare speed against connected ANT+ Bluetooth sensor data (zero cadence or resting heart rate of 60 bpm while climbing at 40 km/h indicates vehicle travel).
- Automated Flagging: Flagged efforts are excluded from the public leaderboard pending community or automated review.
5. Architectural Trade-Off Matrix
| Design Area | Option A | Option B | Selected Choice & Rationale |
|---|---|---|---|
| Activity Processing | Synchronous on Upload | Asynchronous Kafka Worker Pool | Asynchronous Worker Pool: Parsing raw binary FIT files and running spatial geometric algorithms takes 2β4 seconds per file. Decoupling upload returns 202 Accepted in < 100ms. |
| Leaderboard Storage | SQL ORDER BY elapsed_time ASC | In-Memory Redis Sorted Sets (ZSET) | Redis ZSET: Relational database queries across millions of efforts take hundreds of milliseconds. Redis provides sub-millisecond leaderboard retrieval and instant rank lookups. |
| Spatial Indexing | Full Vector Geometry Traversal | Two-Stage (R-Tree Bounding Box FrΓ©chet) | Two-Stage: Eliminates 99.999% of non-intersecting segments instantly via fast bounding box indexing, preserving CPU capacity. |
6. What is Expected at Each Level?
Mid-Level (L4 / IC4)
- Designs data schemas for Athletes, Activities, Segments, and Efforts.
- Understands GPS data formats (GPX/FIT) and asynchronous file processing.
- Uses basic bounding boxes to find candidate segments.
- Uses Redis Sorted Sets for basic leaderboard rankings.
Senior (L5 / IC5)
- Details the two-stage segment matching pipeline (Coarse R-Tree bounding box Fine FrΓ©chet distance).
- Solves GPS sensor drift using Kalman filtering and sub-second endpoint timestamp interpolation.
- Implements Redis ZSET leaderboards with conditional updates (
ZADD GT) to track personal records. - Explains anti-cheating anomaly detection rules (heart rate/cadence sensor correlation and gradient physics).
Staff+ (L6 / Principal)
- Designs historical segment backfilling: When a user creates a brand new segment today, how does the system retrospectively match it against 10 years of historical activities (billions of workouts) without melting the cluster?
- Architects multi-region athlete data residency and GDPR compliance for sensitive biometric GPS location tracking.
- Optimizes social feed fanout for endurance athletes followed by millions of fans (celebrity athlete hybrid timeline model).
