Skip to content

Repository files navigation

Fleet Telemetry App

A real-time monitoring service for a fleet of ~50 autonomous industrial vehicles operating in a warehouse. Each vehicle emits a JSON telemetry event at 1 Hz. The system ingests those events, detects anomalies, tracks per-zone entry counts, and surfaces fleet state through a REST API and an operator dashboard.

Table of Contents


Architecture Overview

┌──────────────────────────────────────────────────┐
│  Vehicle Fleet  (50 vehicles, 1 Hz telemetry)    │
└────────────────────────┬─────────────────────────┘
                         │ POST /api/v1/telemetry/events
                         ▼
┌──────────────────────────────────────────────────┐
│  Django + Ninja REST API  (port 8000)            │
│  ├── fleet app      (Vehicle, Mission, Zone)     │
│  ├── telemetry app  (TelemetryEvent, ingest)     │
│  └── anomalies app  (9 detectors)                │
└───────────┬──────────────────────┬───────────────┘
            │                      │
    ┌───────▼──────┐     ┌─────────▼──────────┐
    │  PostgreSQL  │     │  Redis             │
    │  (port 5433) │     │  (zone counters,   │
    └──────────────┘     │   Celery broker)   │
                         └────────────────────┘
                                  │
                    ┌─────────────▼──────────┐
                    │  React Dashboard       │
                    │  (port 5173)           │
                    └────────────────────────┘

The backend is split into three Django apps with a one-way dependency graph: fleettelemetryanomalies.


Tech Stack

Layer Technology
Backend language Python ≥ 3.13
Web framework Django 6, Django Ninja 1.x
Schema validation Pydantic v2
Database PostgreSQL 17
Cache / broker Redis 7
Task queue Celery 5
Package manager uv
Frontend language TypeScript (strict)
Frontend framework React 19
Build tool Vite 5
State management Redux Toolkit + RTK Query
Styling Tailwind CSS v3
Backend testing pytest, factory-boy
Frontend testing Vitest, Playwright
Containerisation Docker (multi-stage)
Task runner GNU Make

Project Structure

fleet-telemetry/
├── backend/                    # Django + Ninja API
│   ├── apps/
│   │   ├── fleet/              # Vehicle, Mission, MaintenanceRecord, Zone
│   │   ├── telemetry/          # TelemetryEvent + ingest pipeline
│   │   └── anomalies/          # Anomaly model + 9 detectors
│   ├── fleet_telemetry/        # Django project (settings, urls, asgi)
│   ├── Dockerfile
│   ├── pyproject.toml
│   └── .env.example
├── frontend/                   # React + Vite operator dashboard
│   ├── src/
│   │   ├── features/
│   │   │   ├── fleet/          # Fleet state & vehicle list
│   │   │   ├── anomalies/      # Anomaly feed
│   │   │   ├── zones/          # Zone entry counters
│   │   │   ├── dashboard/      # Combined operator view
│   │   │   └── health/         # API health indicator
│   │   └── app/                # Redux store, RTK Query base
│   ├── Dockerfile
│   └── package.json
├── docs/
│   ├── ADR.md                  # Architecture Decision Record
│   └── AI_INTERACTION_LOG.md   # AI Interaction Log
├── .github/workflows/ci.yml    # GitHub Actions CI
├── docker-compose.yml          # Local dev stack
├── Makefile                    # Single entry point — `make help`
└── CLAUDE.md                   # AI-assistant project guide

Prerequisites

Tool Version
Docker & Docker Compose latest
Python ≥ 3.13
uv latest
Node.js 22 LTS
pnpm 10
GNU Make any

Getting Started

1. Clone and configure

git clone https://github.com/lfbos/fleet-telemetry.git
cd fleet-telemetry
cp backend/.env.example backend/.env   # default credentials work locally

2. Start infrastructure (Postgres + Redis)

make docker-up

Postgres is exposed on host port 5433. Redis is on 6379.

3. Install dependencies

make install        # backend (uv sync) + frontend (pnpm install)

4. Apply migrations and seed data

make be-migrate     # creates 20 zones and 50 vehicles

5. Start the servers

Open two terminals (or use separate processes):

# Terminal 1 — Django API on :8000
make be-dev

# Terminal 2 — Vite dev server on :5173
make fe-dev

Browse the interactive OpenAPI docs at http://localhost:8000/api/v1/docs.
The dashboard is at http://localhost:5173.

Docker Compose (full stack)

To run everything in containers (including hot-reload for both backend and frontend):

docker-compose up

To enable the async Celery worker (moves anomaly detection off the request thread):

docker-compose --profile async up

API Reference

All endpoints are under /api/v1. Full, interactive schema is available at /api/v1/docs.

Telemetry

Method Path Description
POST /telemetry/events Ingest a single telemetry event

Event payload:

{
  "vehicle_id": "V-001",
  "timestamp": "2026-05-15T21:00:00Z",
  "lat": 37.7749,
  "lon": -122.4194,
  "battery_pct": 82.5,
  "speed_mps": 1.2,
  "status": "moving",
  "error_codes": [],
  "zone_entered": "aisle_a",
  "idempotency_key": "optional-unique-key"
}

Fleet

Method Path Description
GET /fleet/state Per-status vehicle counts + total
GET /vehicles List all vehicles with current state
POST /vehicles/{vehicle_id}/fault Operator override: transition vehicle to fault (cancels active mission, opens maintenance record)

Zones

Method Path Description
GET /zones/counts Per-zone entry counts

Anomalies

Method Path Description
GET /anomalies List anomalies; filter by vehicle_id, from, to, limit (1–500, default 50)

Health

Method Path Description
GET /health Liveness probe

Anomaly Detection

Anomaly detection runs on every ingested event (per-event detectors) and on a schedule driven by Celery beat (see settings.CELERY_BEAT_SCHEDULE).

Per-event detectors

Code Trigger
FAULT_REPORTED Vehicle status is fault
LOW_BATTERY Battery ≤ 15 % (critical alert at ≤ 5 %)
OVERSPEED Speed exceeds warehouse limit
BATTERY_DROP_RATE Battery draining faster than expected
ACCELERATION_SPIKE Sudden speed change (throttle or brake)
BATTERY_SENSOR_STUCK Battery reading unchanged despite movement

Scheduled detectors

Code Trigger
TELEMETRY_GAP Vehicle stopped sending data
STUCK Vehicle reports moving but speed stays near zero
CHRONIC_FAULT_RATE Vehicle accumulated more than N faults over 30 days

Warehouse Zones

The warehouse is partitioned into 20 named zones:

inbound_dock_a, inbound_dock_b, receiving_staging, aisle_a, aisle_b, aisle_c, high_bay_1, high_bay_2, bulk_storage, pick_zone_1, pick_zone_2, pack_station, sort_belt, outbound_dock_a, outbound_dock_b, shipping_staging, charging_bay_1, charging_bay_2, charging_bay_3, maintenance_bay

Zone entry counts are buffered in Redis (INCR) on ingest and flushed to Postgres in batches by a Celery beat task every few seconds (see settings.CELERY_BEAT_SCHEDULE).


Development Commands

Run make help for a full list. Key targets:

# Install
make install              # all deps (backend + frontend)

# Backend
make be-dev               # Django dev server on :8000
make be-migrate           # apply migrations + seed
make be-makemigrations    # generate new migrations
make be-lint              # ruff check
make be-format            # ruff format
make be-typecheck         # mypy

# Frontend
make fe-dev               # Vite dev server on :5173
make fe-lint              # ESLint
make fe-typecheck         # tsc --noEmit
make fe-build             # production build

# Docker
make docker-up            # start Postgres + Redis
make docker-down          # stop containers
make docker-down-v        # stop + delete volumes (destructive)
make docker-logs          # tail all container logs

# Full CI suite
make ci                   # equivalent to what GitHub Actions runs

Running Tests

# All tests
make test

# Backend only (pytest)
make be-test

# Backend with HTML coverage report
make be-test-cov          # opens backend/htmlcov/index.html

# Frontend only (Vitest)
make fe-test

# Frontend with coverage
make fe-test-cov

Coverage gate: 80 % — the build fails if coverage drops below this threshold.


CI/CD

GitHub Actions runs on every push to main and on all pull requests (.github/workflows/ci.yml):

Backend job — ruff lint → mypy type-check → pytest with coverage
Frontend job — ESLint → tsc type-check → Vitest with coverage → Vite production build

Both jobs upload coverage artifacts. CI is cancelled automatically if a newer commit arrives on the same branch.


Configuration

Backend (backend/.env)

Variable Default Description
DJANGO_SECRET_KEY Django secret key (required)
DJANGO_DEBUG True Debug mode
DJANGO_ALLOWED_HOSTS localhost,127.0.0.1,backend Allowed hosts
DB_NAME fleet_telemetry Postgres database name
DB_USER postgres Postgres user
DB_PASSWORD postgres Postgres password
DB_HOST localhost Postgres host
DB_PORT 5433 Postgres port (host-side)
REDIS_URL redis://localhost:6379/0 Redis URL (required) — zone counter buffer and Celery broker
CELERY_TASK_ALWAYS_EAGER true Run Celery tasks inline (disable to use a separate worker)

Frontend (frontend/.env)

Variable Default Description
VITE_API_URL (unset) Backend API origin; leave unset in local dev to use the Vite proxy

Design Decisions

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages