MEGAINFRA-WEBAPP/README.md
DEIs 87f75dd98f feat(plant): fleet map page with GPS-denormalised vehicles, clustering, and tile switcher
Adds /dashboard/plant/map: a Leaflet view of every vehicle scanned from
the MEGA Clock kiosk, plotted at its last known position.

Schema
- vehicles.last_latitude / last_longitude / last_scanned_at /
  last_location_accuracy_m denormalised off fuel_logs so the map page
  renders every vehicle in a single query. Same best-effort pattern as
  attention_dismissed_at; updated by /api/clock/vehicle-scan after every
  successful scan. PB init defaults new number cols to 0 (not null) —
  filter uses 'last_latitude > 0 || last_latitude < 0' to mean 'real fix'.
- Indexed via idx_vehicles_last_scanned.

Map UI
- Custom SVG markers per unit_type: car silhouette for fuel, tractor
  silhouette for plant, 24x24, drop-shadowed.
- Clustering via react-leaflet-cluster over Leaflet.markercluster.
  Cluster icons colour-ramp with size (green->sky->amber->rose) and
  scale 32->54px.
- Three-button base-layer switcher: Street (OSM), Dark (ESRI Dark
  Gray Canvas — CartoDB watermarks tiles without a key), Satellite
  (ESRI World Imagery). Last choice persists in localStorage.
- Site pins: small purple map-marker divIcon, click flies the map to
  zoom level 15.
- Empty-state is a floating chip on the map rather than a full-page
  card so the map is always visible.

APIs
- /api/clock/vehicle-scan: stores the GPS fix on the fuel_logs row
  AND denormalises onto the vehicle when present; missing-coord
  scan leaves last_* untouched.

Sidebar: new Map entry under Plant group.
2026-09-22 21:39:25 +02:00

5.8 KiB

MEGA INFRASTRUCTURE — Operations Dashboard

A Next.js 16 + TypeScript + Tailwind v4 operations dashboard for a South African civil construction company, backed by PocketBase. Tracks, per construction site: contracts, employees & timesheets, vehicles (fuel + plant), fuel logs, plant hour meters, fixed costs, income claims, purchase orders + line items, and delivery notes with OCR-driven receipting. Includes an LLM chat ("Ask") with a read-only tool layer over the same data, and a read-only MCP server.

Default login PIN is 2468. Change NEXT_PUBLIC_APP_PIN in production. Append ?demo=1 to any URL to bypass the PIN during development.


Quick start

cp .env.local.example .env.local
# edit NEXT_PUBLIC_POCKETBASE_URL, POCKETBASE_ADMIN_*, N8N_*
npm install
npm run dev    # next dev -H 0.0.0.0 -p 6004 --webpack

Production build / start:

npm run build   # icons + og-image + next build --webpack
npm run start   # next start -H 0.0.0.0 -p 3000

Docker / Coolify: see docs/COOLIFY.md and the Dockerfile.

MCP server (stdio, read-only):

npm run mcp     # uses the PocketBase creds in .env.local

Modules

The sidebar lists seven modules. Each is documented in docs/modules.md.

Path Module What it shows
/dashboard Overview KPI tiles, fuel-attention rail grouped by site, every site summary
/dashboard/sites and /dashboard/sites/[id] Sites Per-site profitability, burn, P&L, payroll, weekly & monthly trends
/dashboard/employees Workforce Per-employee hours, rates, weekly trend, casual-matrix import
/dashboard/plant and /dashboard/plant/[vehicleId] Plant & Equipment Hour-meter history, weekly logs, billable rate
/dashboard/plant/map Fleet Map Live Leaflet view of every vehicle's last scanned position
/dashboard/fuel and /dashboard/fuel/[vehicleId] Fleet & Fuel Variance per log, over-limit flags, dismissable attention
/dashboard/purchasing and /dashboard/purchasing/[poId] Purchasing Every PO, DN fulfilment %, OCR exception inbox
/dashboard/chat Ask Read-only LLM chat with the same metrics the dashboard uses

Documentation

Document What's in it
docs/architecture.md Runtime topology, the two PB clients, rendering model, auth model, build/deploy
docs/data-model.md Every PocketBase collection, fields, relations, the project_code denormalisation, indexes, API rules
docs/modules.md One section per dashboard module — what it reads, computes, lets the user do
docs/data-flows.md End-to-end ingestion pipelines with sequence diagrams (timesheets, fuel, plant, PO, DN)
docs/api-reference.md Every API route — method, auth, request/response, error cases
docs/operations.md Env vars, scripts, tests, feature flags, deploy / smoke test
docs/multi-site-assessment.md The main deliverable — will this app hold up at 50 sites? Where does it break, and what to fix in what order?

The docs/superpowers/ directory has older design notes; treat as historical, not authoritative.


Tech stack

  • Next.js 16 (App Router, modified build — see AGENTS.md)
  • React 19 + TypeScript 5.7
  • Tailwind v4 (via @tailwindcss/postcss)
  • PocketBase 0.27 (PocketBase v0.22+ schema shape, see scripts/pb-bootstrap-schema.py)
  • SheetJS (xlsx) + PapaParse (csv) for imports
  • Recharts for charts
  • Vitest for tests
  • @ducanh2912/next-pwa (Webpack-only — next dev/build pass --webpack to support it)
  • Anthropic or MiniMax as the chat LLM provider

API surface (summary)

Route group Auth Notes
GET /api/health none Docker healthcheck
POST /api/sites, PATCH /api/sites/[id], POST /api/sites/[id]/fixed-costs server-only Sites CRUD
POST / PATCH / DELETE /api/vehicles[ /[id]] server-only Vehicles CRUD (unified fuel + plant)
POST /api/plant-hours/import, GET /api/plant-hours/template, GET /api/plant-hours/exception-report/[batchId], DELETE /api/plant-hours/[id] server-only Plant hours ingest + reporting
POST /api/timesheets/import server-only Timesheet ingest (three formats auto-detected)
POST /api/fuel-logs/import server-only Fuel log ingest
POST /api/purchase-orders/upload, POST /api/purchase-orders/process-batch (n8n), GET /api/purchase-orders/by-number/[poNumber]/items, PATCH /api/purchase-orders/[id]/supplier server-only / x-ingest-secret PO ingest pipeline
POST /api/delivery-notes/upload, GET /api/delivery-notes/[id]/slip (n8n), POST /api/delivery-notes/[id]/ocr-result (n8n), POST /api/delivery-notes/[id]/assign-po server-only / x-ingest-secret DN pipeline + manual fallback
GET / POST /api/data-import-batches/[id]/status|retry server-only Batch lifecycle
POST /api/records/[collection]/[id]/verify server-only Verify toggle for POs and DNs
POST /api/chat ENABLE_CHAT=true (no user auth) SSE chat stream
POST /api/clock/scan, POST /api/clock/vehicle-lookup, POST /api/clock/vehicle-scan server-only MEGA Clock PWA: badge clock-in/out + vehicle hour-meter scan

Full reference: docs/api-reference.md.


Tests

npm run typecheck   # tsc --noEmit
npm run test:run    # vitest run

The metric helpers under src/lib/metrics/*.test.ts pin every computation the dashboard exposes. Run after any change to the financial roll-up.


License

Proprietary. Internal use only.