Low Level Design: Location Sharing Service

Location Sharing Service: Low Level Design

Data Model

Location Table (Time-Series)

Location
--------
device_id       BIGINT
lat             DOUBLE PRECISION
lng             DOUBLE PRECISION
accuracy_meters FLOAT
heading         FLOAT           -- degrees 0-360
speed           FLOAT           -- m/s
timestamp       TIMESTAMPTZ

PRIMARY KEY (device_id, timestamp)
PARTITION BY RANGE (timestamp)   -- one partition per day

Raw location rows are retained for 24 hours, then dropped with the partition. The last-known location for each device is maintained separately in Redis for instant retrieval.

Share Session Table

ShareSession
------------
id              BIGINT PK
owner_device_id BIGINT
share_code      VARCHAR(8) UNIQUE   -- random token, e.g. "aB3xQr7Z"
permission      ENUM('realtime','last-known')
expires_at      TIMESTAMPTZ
max_viewers     INT
created_at      TIMESTAMPTZ
revoked_at      TIMESTAMPTZ

Live Location Updates

Ingestion API

POST /locations
Authorization: Bearer {device_token}

{
  "lat": 37.7749,
  "lng": -122.4194,
  "accuracy_meters": 5.0,
  "heading": 270.0,
  "speed": 12.5,
  "timestamp": "2024-01-01T12:00:00Z"
}

Devices POST every 5 seconds while moving, or every 30 seconds while stationary (battery optimization via adaptive frequency — determined client-side using accelerometer data).

On receipt:

  1. Write row to Location table.
  2. Update Redis key lastloc:{device_id} with the new coordinates (TTL: 7 days).
  3. PUBLISH to Redis channel share:{share_code} for all active share sessions owned by this device.

Watcher Registry and WebSocket Fan-Out

Watcher Registry

Redis Set key:  watchers:{share_code}
Members:        {node_id}:{connection_id}
TTL:            reset on each WebSocket heartbeat

When a viewer opens a WebSocket connection using a share code, their connection ID is added to the set. Multiple app server nodes each subscribe to the Redis Pub/Sub channel for every active share code they serve.

Fan-Out Flow

Device POST /locations
       │
       ▼
 Write to DB + update Redis lastloc
       │
       ▼
 PUBLISH to Redis channel "share:{share_code}"
       │
       ├──▶ Node A receives → pushes to connected WebSocket clients
       └──▶ Node B receives → pushes to connected WebSocket clients

Privacy and Access Control

  • Share code: random 8-character alphanumeric token; not guessable. Shared out-of-band (SMS, link).
  • Permission levels: realtime streams live updates; last-known returns a single snapshot.
  • Expiry: sessions have an expires_at; expired sessions reject new WebSocket connections.
  • Revocation: owner calls DELETE /share/{share_code} → sets revoked_at, closes all active WebSocket connections for that code, removes Redis set.
  • Viewer cap: max_viewers enforced at WebSocket handshake time via set cardinality check.

REST API Summary

POST   /locations                  -- ingest location update
POST   /share                      -- create share session → returns share_code
GET    /share/{share_code}/location -- get last-known location (HTTP)
WS     /share/{share_code}/live    -- real-time WebSocket stream
DELETE /share/{share_code}         -- revoke share session

Scalability Notes

  • Redis Pub/Sub fan-out decouples ingestion from delivery; any node can serve any viewer.
  • Time-series partitioning keeps the hot partition small; old partitions are dropped cheaply.
  • WebSocket nodes are stateless beyond the in-memory connection map; horizontal scaling is straightforward.
  • For very high fan-out (live event sharing with thousands of viewers), Redis Streams with consumer groups can replace simple Pub/Sub.

See also: Netflix Interview Guide 2026: Streaming Architecture, Recommendation Systems, and Engineering Excellence

See also: Uber Interview Guide 2026: Dispatch Systems, Geospatial Algorithms, and Marketplace Engineering

See also: Snap Interview Guide

Scroll to Top