Faysal Ahmed

Building an Open-Source Fleet & Asset Tracking System: Architecture Deep Dive

architectureiotmqttinfluxdbwebsocketsreal-timefleet-trackingopen-source

Fleet tracking is broken. Most operators rely on expensive SaaS platforms that charge per-vehicle per-month, or batch systems that show you where your trucks were yesterday — not where they are now. GPS telemetry, engine diagnostics, geofence alerts, and driver behaviour data live in silos, making it nearly impossible to get a unified operational picture.

So we set out to build something different: an open, self-hostable real-time fleet tracking platform that ingests IoT telemetry via MQTT, stores time-series data in InfluxDB, and streams live updates to a web dashboard over WebSockets.

Here is the architecture, the data model, and the rationale behind every layer.


The Pipeline

The system is a four-stage data pipeline:

IoT Device (GPS+CAN) → MQTT Broker → InfluxDB → API Gateway → Web Dashboard
                         ↑                            │
                     Retained messages          WebSocket (JWT)
                     Last-known position        Live updates + alerts

1. Ingestion — MQTT

Every vehicle-mounted device publishes a compact JSON payload at 1–30 second intervals to a unique topic: fleet/{vehicle_id}/telemetry. The broker (Mosquitto for single-node, EMQX if clustering is needed) authenticates devices via TLS client certificates.

Each payload carries lat/lng, speed, heading, ignition state, odometer, battery voltage, engine temperature, and fuel level:

{
  "v": 1,
  "ts": "2026-05-21T10:30:00Z",
  "lat": 23.8103,
  "lng": 90.4125,
  "speed": 45.2,
  "heading": 180,
  "ignition": true,
  "odometer": 123456.7,
  "battery_v": 12.4
}

Retained messages give us the last-known position of every vehicle for free — newly connecting clients get instant state without a separate database query.

2. Storage — InfluxDB

A bridge service (Telegraf or a custom Go binary) subscribes to fleet/+/telemetry and writes raw telemetry into InfluxDB v3 tagged by vehicle_id, fleet_id, and device_type.

Two retention tiers balance cost against queryability:

BucketRetentionGranularity
telemetry_raw7 daysFull resolution
telemetry_downsampled1 yearHourly aggregates

Geofence enter/exit events and trip summaries live in separate measurements, keeping the hot path lean and analytics queries fast.

3. Streaming — WebSockets + JWT

The API Gateway (Go with Gorilla WebSocket or Fiber) authenticates clients on connection upgrade using JWT access tokens. Once connected, a client subscribes to one or more vehicle feeds and receives push updates at a configurable rate (minimum every second).

{
  "type": "telemetry_update",
  "vehicle_id": "v-001",
  "data": {
    "lat": 23.8103,
    "lng": 90.4125,
    "speed": 45.2,
    "ts": "2026-05-21T10:30:00Z"
  }
}

Alert messages share the same WebSocket connection — speed threshold exceeded, geofence breached, ignition changed, device offline. One connection, two message types.

4. Dashboard — React + MapLibre

The frontend is a React app with MapLibre GL JS (open-source alternative to Mapbox). It shows every vehicle on a live map with heading-indicating markers, a detail panel for speed/odometer/driver info, and an alert feed. Future sprints add geofence drawing tools, historical trip playback at 1x–10x speed, and per-trip reports (distance, idle time, max speed, fuel estimate).


Why This Stack?

LayerChoiceWhy
MQTTMosquitto / EMQXPurpose-built for IoT; retained messages, QoS, TLS baked in
TSDBInfluxDB v3Native downsampling, Flux queries, built for telemetry
GatewayGoLow-latency WebSocket at scale; Gorilla WebSocket is battle-tested
FrontendReact + MapLibreLightweight map rendering; no Mapbox API key needed
AuthJWTStateless; validated on WS upgrade with zero DB hits
DeploymentDocker Compose → K8sDev/prod parity; path to production clustering

What We’re Building, Sprint by Sprint

  • Sprint 1 (Weeks 1–3): Core pipeline — MQTT broker, Telegraf bridge, InfluxDB, and a simulated device publishing test data.
  • Sprint 2 (Weeks 4–6): Live dashboard — WebSocket gateway with JWT auth, React map with real-time vehicle positions.
  • Sprint 3 (Weeks 7–9): Alerts & geofences — zone CRUD, an alert engine evaluating rules per event, in-app notifications.
  • Sprint 4 (Weeks 10–12): History & reports — trip replay on the map, distance/idle/speed reports.
  • Sprint 5 (Weeks 13–14): Production hardening — TLS everywhere, load testing at 10,000 simulated devices, Docker Compose deploy.

What’s Not in v1

We’re explicitly keeping scope tight. The first version won’t include a mobile driver app, ERP integrations, dashcam video, predictive maintenance, or multi-tenancy. The goal is a rock-solid core pipeline that operators can self-host, extend, and own.


Open Source from Day One

The entire project is open source and developed in the open. Every sprint is tracked with GitHub issues, every feature branches from develop, and every PR squashes into a clean commit history. If this sounds interesting — whether as a contributor or an operator — the codebase is at github.com/FaysalAhmed/fleet-asset-tracking.

The road from a PRD to a production dashboard is long, but the architecture is sound, the stack is proven, and the problem is worth solving.