No description
Find a file
2026-06-08 21:46:32 +03:00
layers feat(map): toggleable overlay layers + Shell fuel stations (232) 2026-06-08 21:46:30 +03:00
.dockerignore feat: FleetNow merged live+trips map SPA (nginx/Coolify) 2026-06-05 21:56:01 +03:00
.gitignore feat: FleetNow merged live+trips map SPA (nginx/Coolify) 2026-06-05 21:56:01 +03:00
260605_fleetnow_v1.html feat(live): pair tracker+camera per vehicle — tracker default, camera fallback 2026-06-06 23:23:44 +03:00
Dockerfile feat(map): toggleable overlay layers + Shell fuel stations (232) 2026-06-08 21:46:30 +03:00
index.html feat(map): toggleable overlay layers + Shell fuel stations (232) 2026-06-08 21:46:30 +03:00
nginx.conf feat: FleetNow merged live+trips map SPA (nginx/Coolify) 2026-06-05 21:56:01 +03:00
README.md docs: mark v2 feature-frozen (2026-06-07) — two-tier dock + clustering + dedup 2026-06-07 00:43:36 +03:00

FleetNow

A single-file map console that merges live vehicle positions and historical trips into one view for the Fireside Communications / Tracksolid fleet.

Status: v2 — feature-frozen 2026-06-07 (two-tier bottom dock + clustering

  • tracker/camera dedup). Live at https://fleetnow.rahamafresh.com. Deployed from this repo via Coolify (Dockerfile → nginx). Reads the dashboard_api read-API at fleetapi.rahamafresh.com.

Deploy is manual — push, then hit Redeploy in Coolify (no auto-deploy webhook wired yet).

What it does

  • Land on the live fleet — markers carry the department (cost-centre) colour, a heading arrow, the plate tail, and a hover popup (status, driver, reverse-geocoded address, heading, odometer, last fix, source). Markers scale with the zoom level. Shape encodes recency so stakeholders read activity at a glance:
    • ● circle (full colour + heading arrow) — moving right now
    • ■ square (pastel colour, no arrow, ~half the size of a moving marker) — active within the last 24h, now stopped
    • grey ● — offline (no fix in 24h)
  • One pin per vehicle (tracker + camera dedup). Every vehicle carries a GPS tracker (X3 / GT06E / AT4) and a dashcam (JC400P) that share the same number plate. FleetNow collapses the pair to a single marker/dropdown entry: the tracker is primary; if the tracker isn't reporting (>24h), it falls back to the camera; if both report, the tracker wins. Pairing is by normalised plate, so a stray space (KDS 453 Y vs KDS 453Y) still merges.
  • Clustering (zoomed out). Vehicles group into amber count-bubbles (Folium / Leaflet.MarkerCluster style, via supercluster); click a bubble to zoom and expand it. Clusters disband into individual pins at ~city zoom (z11). Clustering honours the active filter and applies to the live view only (not trip routes).
  • Filters (bottom-right card) apply to the live map instantly:
    • Number plate — multi-select, sorted A→Z; picking a vehicle auto-fills its cost centre + city.
    • Cost centre and Assigned city — narrow the live fleet (and the KPI bar recomputes to match).
    • Time (Today / 1 week / 1 month / Custom) — applies to trips, not live.
  • Drill into history: click a vehicle's dot → Show trips, or set plate / cost centre / city + period and hit Show trips for a fleet-wide pull. The map switches to seq-coloured trip routes with start/end markers and a click-to-animate replay; the ● Live pill returns to the live snapshot.
  • In trips view a context bar (below the header) summarises the active filter (vehicle / cost centre / city) plus the first trip and last trip — each with its reverse-geocoded location and timestamp — alongside the KPI totals (trips, km, driving/idle hours, vehicles, drivers, date range).
  • Full-width map + two-tier bottom dock (no floating/side panels). All controls live in a bottom dock with two tiers: a filter tier on top and a trip-card tier beneath (selection → results hierarchy). In live mode the filter row is expanded and there are no cards; in trips mode the filters collapse to a one-line summary (Filters: KCA 542Q · roll out · nairobi · Last 1 month, with Edit to expand) and the trip cards show beneath — keeping the map tall.
  • Plate picker is a searchable combobox — type to filter, click to add a removable chip (multi-select), instead of a tall scrolling list. Cost centre / city / time stay single-line; date pickers appear only for a custom range. Trip cards scroll horizontally; click a card to fit + animate that route.

Live: https://fleetnow.rahamafresh.com

Architecture

The whole app is one self-contained index.html (inline CSS + JS; MapLibre GL JS loaded from a CDN). It has no build step and no local assets. It reads from the existing dashboard read-API — it does not talk to the database directly.

index.html      → the entire SPA
Dockerfile      → bakes index.html into an nginx:alpine image (port 80)
nginx.conf      → static serve + /healthz + no-cache on index.html

Backend it depends on

const API_BASE = 'https://fleetapi.rahamafresh.com'; (top of the <script> in index.html). That service (dashboard_api_rev.py in the tracksolid repo) exposes:

Endpoint Use
GET /webhook/live-positions live snapshot {summary, geojson}
GET /webhook/live-positions/track?vehicle_number=&hours= 1 h trail
GET /webhook/fleet-dashboard filter options (plates, cost centres)
POST /webhook/fleet-dashboard trips for a selection {summary, geojson}

CORS: the API must allow the https://fleetnow.rahamafresh.com origin (DASHBOARD_CORS_ORIGINS). It is in the code default; make sure the deployed dashboard_api container's env includes it, then restart that container.

Deploy (Coolify, git-based)

  1. In Coolify, create a new Application from this git repo (https://repo.rahamafresh.com/kianiadee/fleetnow.git), branch main, build pack Dockerfile.
  2. Set the port to 80.
  3. Add the domain fleetnow.rahamafresh.com (HTTPS / Let's Encrypt). Coolify wires Traefik on the coolify network automatically.
  4. Point DNS fleetnow.rahamafresh.com → the VPS (31.97.44.246) if not already.
  5. Deploy. Every push to main redeploys; index.html is served no-cache so changes appear immediately.

Local preview

docker build -t fleetnow . && docker run --rm -p 8080:80 fleetnow
# open http://localhost:8080

Loading from localhost will be CORS-blocked by the live API unless that origin is allow-listed. For pure UI work, run a same-origin proxy that forwards /webhook/* to fleetapi.rahamafresh.com.