No description
Find a file
DEls e66f29b124 fix(dn-pipeline): convert units before comparing nett to quantity
Delivery notes weigh in kg while the same supplier's invoices weigh in
tons, so the check was comparing 29980 kg against 30.275 tons. Also stops
failing documents that simply have no weigh section.

Also updates promote.test.ts, run.test.ts and segment.test.ts fixtures
for the new required mass_unit field on PageRead/NoteSegment (not named
in the plan's file list for this task, but required for typecheck).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 20:56:24 +02:00
.claude feat(dashboard): enhance operations dashboard with rain outlook and coordinate support 2026-09-06 19:59:52 +02:00
.freebuff feat(ocr-result, po-items): enhance PO matching logic with fuzzy search 2026-08-26 21:39:59 +02:00
.opencode/openwork/inbox/chat-attachments Update package dependencies and remove unused API routes 2026-08-19 00:14:47 +02:00
.playwright-mcp docs(spec): fuel attention dismissal design 2026-08-28 12:19:59 +02:00
docs docs(delivery-notes): add the inbox corrections implementation plan 2026-09-17 20:49:49 +02:00
public feat(clock): replace icon with clock-on-cube design + OG share preview 2026-09-13 21:55:40 +02:00
RAW_DOCS fix(vehicles): handle empty unit_type during updates 2026-08-29 19:17:14 +02:00
scripts fix(dn-batches): add uploaded_at so ordering works 2026-09-17 20:53:23 +02:00
src fix(dn-pipeline): convert units before comparing nett to quantity 2026-09-17 20:56:24 +02:00
.dockerignore Fix Coolify build: include scripts/ in Docker context 2026-08-09 20:30:29 +02:00
.env.coolify feat(delivery-notes): enhance delivery note upload and processing 2026-08-26 15:33:30 +02:00
.env.local.example feat(dn-batches): add the tick route with compare-and-set claiming 2026-09-17 14:25:25 +02:00
.gitignore chore: ignore .worktrees/ directory 2026-09-17 11:54:20 +02:00
AGENTS.md Enhance PO upload error handling and validation 2026-08-19 15:03:48 +02:00
CLAUDE.md Enhance PO upload error handling and validation 2026-08-19 15:03:48 +02:00
cooler.env Enhance PO upload error handling and validation 2026-08-19 15:03:48 +02:00
COOLIFY.md Fix Coolify build: skip postinstall in deps stage 2026-08-09 02:29:48 +02:00
Copy of THE HILLS WAGES HRS AUGUST 2026.xlsx feat(timesheets): enhance import functionality to support XLSX and CSV formats 2026-08-25 18:38:02 +02:00
deployment-vptid1uo0jnz2q4t1mcbqjj9-all-logs-2026-08-19-00-23-06.txt Refactor Purchase Order upload flow documentation 2026-08-19 02:25:11 +02:00
docker-compose.yml
Dockerfile build: add poppler-utils and pdf-lib for delivery note page splitting 2026-09-17 13:42:11 +02:00
fuel_logs_duplicates_2026-09-10.csv refactor(schema): rename received_items and timesheets to their real names 2026-09-11 11:01:40 +02:00
next.config.js fix(pwa): restore static manifest.json + remove dead next-pwa config 2026-08-30 22:33:35 +02:00
package-lock.json build: add poppler-utils and pdf-lib for delivery note page splitting 2026-09-17 13:42:11 +02:00
package.json build: add poppler-utils and pdf-lib for delivery note page splitting 2026-09-17 13:42:11 +02:00
postcss.config.mjs
README.md feat(dashboard): enhance operations dashboard with rain outlook and coordinate support 2026-09-06 19:59:52 +02:00
tsconfig.json
vitest.config.ts Add Vitest + n8n env var documentation 2026-08-19 02:21:36 +02:00

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/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

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.