Skip to content

Repository files navigation

🌍 TrackPulse — Real-Time Geospatial Tracking System

A production-grade, horizontally scalable real-time location tracking system built with Node.js, TypeScript, Express, Socket.IO, and Leaflet.

Designed to handle high-frequency telemetry data, this system demonstrates advanced distributed backend patterns — token-bucket rate limiting, spatial partitioning for $O(1)$ geofencing, telemetry downsampling, and graceful degradation via Redis failovers.


🔥 Why This Project Matters

In logistics, ride-sharing, and delivery networks, ingesting live telemetry isn't just about rendering dots on a map — it's about managing chaos. Mobile networks drop connections, GPS chips teleport across cities due to signal bounce, and compromised clients can spam servers with thousands of updates per second.

This project moves beyond a basic WebSocket tutorial by tackling real-world constraints: enforcing ordered chronology, defending against backpressure, optimizing spatial mathematics, and guaranteeing graceful state failovers — all in strict TypeScript end-to-end.


🧠 Interview Highlights (TL;DR for Reviewers)

  • System Design Thinking: Actively trades strict consistency for high availability during cache failures, demonstrating applied CAP theorem principles.
  • Algorithmic Optimization: Dropped geofence complexity from $O(M)$ to $O(1)$ by mapping fences into a 2D spatial grid.
  • Defensive Engineering: Token-buckets, velocity-based drift filtering, and bounded queues protect V8 from OOM crashes and event-loop blocking.
  • Type Safety: Full TypeScript migration across backend (src/) and frontend (public/src/) with zero any leaks in interfaces.

⚡ Key Features

Backend & Distributed Architecture

  • Multi-Socket Persistent Identity: Maps JWT identity to a Set<SocketId>, natively handling tab duplication and preventing zombie drops during cell-tower handoffs.
  • Graceful State Failover: Storage layer starts on Redis (MULTI/EXEC atomic blocks) but degrades transparently to in-memory Maps if the cache node becomes unreachable.
  • Telemetry Downsampling & Bounded Queues: Samples locations (>5s intervals) and rigidly enforces history length to prevent V8 OOM crashes.

Client Resilience & Real-Time UX

  • 60FPS Rendering: requestAnimationFrame interpolation and marker clustering maintain smooth rendering under high-frequency data streams.
  • Follow Mode: Click any user to lock the camera via continuous smooth-panning (map.panTo), with a glassmorphic panel showing live Haversine distance, idle/active state, and last ping delta.
  • Distance-Aware Fleet Sidebar: Dynamically recalculates host-to-fleet distances on every tick, sorting the active user list with nearest entities first.
  • Live Activity Feed: Floating ephemeral toasts for geofence breaches, joins, and disconnects — non-blocking, auto-expiring.

🏗️ Architecture Overview

The system is a layered monolith ready for microservice extraction.

  1. Transport Layer (server.ts, locationHandler.ts) — WebSocket upgrade, JWT validation, boundary exception handling.
  2. Service Layer (locationService.ts, geofenceService.ts) — Pure business logic, rate limiting, spatial math. Fully decoupled from sockets.
  3. Storage Layer (userStore.ts) — Abstracted interface wrapping both RedisUserStore and MemoryUserStore.

🔄 Location Update Lifecycle

Each device update passes a synchronous pipeline before broadcast:

  1. Validation — Strict payload schema check.
  2. Backpressure — Token Bucket drops spam instantly ($O(1)$) before touching the event loop.
  3. Chronology Check — Monotonic timestamp ordering prevents out-of-order delivery.
  4. Velocity Drift Filter — Haversine distance ÷ Δtime; rejects GPS noise above physical speed limits.
  5. State Update — Persists sanitized location with downsampling.
  6. Geofence Evaluation$O(1)$ spatial grid cell lookup.
  7. Broadcast — Pushes finalized payload to the scoped Socket.IO room.

⚙️ Core Design Decisions & Tradeoffs

Decision Advantage Tradeoff Mitigation
In-Memory Grid vs. Redis GEORADIUS Zero network latency (~0.01ms) Requires Pub/Sub to sync new fences globally Reads outnumber writes $10^6:1$
Local Token Bucket vs. Redis Lua No network hop per frame Relies on sticky sessions for strict accuracy Accept eventual consistency
Memory Fallback vs. 503 Outage High availability Sacrifices global consistency across nodes Alerting + regional isolation
Room-Based Pub/Sub vs. Global Broadcast Caps CPU fan-out Users must subscribe to regions explicitly Default room handles unassigned clients

Edge Cases

  • Geofence Grid Boundaries: Fences spanning multiple cells are mapped to all relevant cell sets. Exit/enter detection evaluates both the current cell's candidates and any fence the user previously occupied.
  • Redis Split-Brain: On failure, the system diverges to local memory. No automatic reconciliation on recovery — requires cold restart or a background rehydration worker.

📊 Scaling Strategy

  • 100 users — Single process, <100MB RAM, grid checks <0.1ms.
  • 10,000 users — Broadcast fan-out (CPU) becomes the bottleneck. The 5m movement filter drops ~80% of idle updates. Room scoping limits blast radius.
  • 100,000+ users — Multi-node: HAProxy sticky sessions → 15+ Node.js instances → Redis Cluster for state and Pub/Sub. At this tier, Redis Pub/Sub must be replaced with partitioned message brokers (Kafka/NATS).

⚠️ Known Limitations

  • JSON Serialization: JSON.stringify on full user state at 10,000 req/sec can block the single-threaded event loop.
  • Sticky Session Fragility: In-memory rate limiting and geofence occupancy break if the load balancer shifts a user to a different node.
  • Split-Brain State: Nodes degraded to memory can't see each other's users.

🚀 Future Improvements

  • Redis HSET: Replace full JSON overwrites with partial field mutations to reduce serialization pressure.
  • Kafka / Time-Series: Migrate append-only trail history to a Kafka firehose → TimescaleDB.
  • Geohash Indexing: Replace the uniform grid with Geohash indices for variable-size fence support.

🛠️ Setup

Prerequisites

  • Node.js v18+
  • Redis (optional — required only for multi-node distributed mode)

Installation

git clone https://github.com/yourusername/RealTimeDeviceTrack.git
cd RealTimeDeviceTrack
npm install

Environment Variables

NODE_ENV=development
PORT=8000
JWT_SECRET=your_secret_here

# Location filtering
LOCATION_THROTTLE_MS=2000
MAX_SPEED_MPS=40
LOCATION_RATE_LIMIT_WINDOW_MS=10000
LOCATION_RATE_LIMIT_MAX=10

# Optional: Redis for distributed mode
REDIS_URL=redis://localhost:6379

Scripts

npm run dev        # Backend + Vite dev server (frontend TS with HMR)
npm run build      # Compile backend and bundle frontend to dist/public/
npm start          # Run compiled production build (node dist/server.js)
npm run typecheck  # Type-check both configs, no emit
npm run clean      # Wipe dist/

During development, open the app at http://localhost:5173 (Vite). The backend API and Socket.IO traffic are proxied to http://localhost:8000.

About

A production-grade, horizontally scalable real-time location tracking system built with Node.js, TypeScript, Express, Socket.IO, and Leaflet.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages