No description
Find a file
DEls 068f622c0a feat(clock): photograph several pages, send them as one document
A delivery note that runs to two or three sheets has to arrive as ONE
batch. Sent a page at a time it became separate batches, and then
nothing could tell that page 2's line items belonged to page 1's note —
the totals sat on one batch and the items on another, with no way back.

Pages now accumulate. Take one, then Retake, Add page, or Send all.
A thumbnail strip shows what has been taken so far, ringed green or red
by how each page measured, so a mis-shot can be dropped without starting
the document over and nobody has to remember whether they got page 2.

Several pages are bundled into a single PDF and enter the pipeline
exactly like a scanned multi-page document: split.ts rasterises each
page, extract.ts reads each in isolation, and segment.ts decides from
the printed document numbers whether it is one note over three pages or
three separate notes. The person holding the phone does not have to know
which, which matters, because standing next to a truck they often can't.

The bundle is verified against the pipeline's own tools rather than
assumed compatible: the test writes one and runs pdfinfo and pdftoppm
over it — the exact binaries split.ts shells out to — checking the page
count, that every page rasterises, that portrait stays portrait, and
that page order survives. A bundle the pipeline could not open would
otherwise fail at the far end of an upload, on site, after the truck had
gone.

One page still uploads as its own JPEG: smaller, and it never loads the
PDF library at all. pdf-lib is imported dynamically and webpack keeps it
in a 412K chunk of its own, leaving the clock page's bundle at 24K —
checked in the build output, not hoped for.

Size is checked before sending, mirroring MAX_FILE_BYTES on the upload
route, so an oversized bundle is caught while the document is still in
front of the person rather than as a 400 afterwards.

1027 tests, typecheck clean, production build clean. The capture path
itself still needs a real phone — the browser pane here has no camera
and cannot reach localhost.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 19:10:16 +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: plan hybrid delivery note ingestion 2026-09-18 18:43:52 +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 feat(dn-batches): dismiss a single duplicate note, and stop erasing promoted counts 2026-09-18 00:44:57 +02:00
src feat(clock): photograph several pages, send them as one document 2026-09-18 19:10:16 +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): one batch per tick by default 2026-09-17 22:54:32 +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 Initial commit: MEGA INFRASTRUCTURE dashboard + Coolify Dockerfile 2026-08-09 01:37:40 +02:00
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 Initial commit: MEGA INFRASTRUCTURE dashboard + Coolify Dockerfile 2026-08-09 01:37:40 +02:00
README.md feat(dashboard): enhance operations dashboard with rain outlook and coordinate support 2026-09-06 19:59:52 +02:00
tsconfig.json Initial commit: MEGA INFRASTRUCTURE dashboard + Coolify Dockerfile 2026-08-09 01:37:40 +02:00
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.