2026-08-08 23:37:40 +00:00
# MEGA INFRASTRUCTURE — Operations Dashboard
2026-09-06 17:59:52 +00:00
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
docs(ask): agent actions
docs/modules.md §7.1: threads, memory, files, free queries/virtual
datasets, the propose/confirm/apply/undo gateway, both PDF export paths
(manual answer export and Ask-made reports via make_pdf_report),
images, and change requests — with the actor/x-ask-user model and the
three new PocketBase collections.
docs/data-model.md §4.17: field-by-field ask_threads/ask_messages/
ask_log reference, cross-linked from modules.md via explicit anchors.
docs/api-reference.md §12/§12b: /api/chat's new body shape and its
thread/action/chart/image/pdf SSE events, plus every new agent-actions
route (picker, threads, attachments, confirm-card actions, memories,
change requests) and their auth-matrix entries; the pb-files proxy
entry now notes its ask_messages admin-token path.
README.md: the intro, the modules table (adds Change requests), and
the API surface summary now describe an agent that acts, not just a
read-only chat.
Also marks Tasks 1–12 and 9b's implementation checkbox done in the plan
doc (docs/superpowers/plans/2026-09-26-ask-agent-actions.md) — the
remaining unchecked box is 9b's live check, skipped because
ask_threads/ask_messages/ask_log aren't applied on the target
PocketBase yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 19:32:53 +00:00
OCR-driven receipting. Includes an LLM agent ("Ask") that reads the same
data the dashboard uses, measures anything with free queries and its own
charts, reads any file you attach, remembers lasting facts, changes data
through confirm-first proposed actions with undo, and files its own PDF
reports and app change requests — plus a read-only MCP server.
2026-09-06 17:59:52 +00:00
2026-10-09 08:16:50 +00:00
> Named PocketBase logins are required after the
2026-09-28 21:51:47 +00:00
> [login migration](./scripts/migrations/2026-09-28-users-login.py).
2026-10-09 08:16:50 +00:00
> Shared PIN sign-in is disabled. Local development uses the same named
> sign-in as production. Management planning is available only to admins.
2026-08-08 23:37:40 +00:00
---
2026-09-06 17:59:52 +00:00
## Quick start
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
```bash
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
```
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
Production build / start:
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
```bash
npm run build # icons + og-image + next build --webpack
npm run start # next start -H 0.0.0.0 -p 3000
```
2026-08-08 23:37:40 +00:00
2026-09-25 20:04:08 +00:00
Docker / Coolify: see [`COOLIFY.md` ](./COOLIFY.md ) and the
2026-09-06 17:59:52 +00:00
[`Dockerfile` ](./Dockerfile ).
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
MCP server (stdio, read-only):
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
```bash
npm run mcp # uses the PocketBase creds in .env.local
```
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
---
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
## Modules
2026-08-08 23:37:40 +00:00
docs(ask): agent actions
docs/modules.md §7.1: threads, memory, files, free queries/virtual
datasets, the propose/confirm/apply/undo gateway, both PDF export paths
(manual answer export and Ask-made reports via make_pdf_report),
images, and change requests — with the actor/x-ask-user model and the
three new PocketBase collections.
docs/data-model.md §4.17: field-by-field ask_threads/ask_messages/
ask_log reference, cross-linked from modules.md via explicit anchors.
docs/api-reference.md §12/§12b: /api/chat's new body shape and its
thread/action/chart/image/pdf SSE events, plus every new agent-actions
route (picker, threads, attachments, confirm-card actions, memories,
change requests) and their auth-matrix entries; the pb-files proxy
entry now notes its ask_messages admin-token path.
README.md: the intro, the modules table (adds Change requests), and
the API surface summary now describe an agent that acts, not just a
read-only chat.
Also marks Tasks 1–12 and 9b's implementation checkbox done in the plan
doc (docs/superpowers/plans/2026-09-26-ask-agent-actions.md) — the
remaining unchecked box is 9b's live check, skipped because
ask_threads/ask_messages/ask_log aren't applied on the target
PocketBase yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 19:32:53 +00:00
The sidebar (`src/components/layout/sidebar.tsx`) has five top-level
2026-09-25 20:04:08 +00:00
pages and three groups. Each is documented in
2026-09-06 17:59:52 +00:00
[`docs/modules.md` ](./docs/modules.md ).
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
| Path | Module | What it shows |
| --- | --- | --- |
2026-09-25 20:04:08 +00:00
| `/dashboard` | Overview | KPI tiles, fuel-attention card grouped by site, 7-day rain outlook, every site |
| `/dashboard/sites` , `/dashboard/sites/[id]` | Sites | Per-site profitability, burn, P& L, payroll, weekly & monthly trends |
| `/dashboard/workforce` | Workforce | Landing: people cost this week |
| `/dashboard/workforce/workers[/[employeeId]]` | Workers | Every worker, hours, cost, printable QR badge |
| `/dashboard/workforce/timesheets` | Timesheets | Every entry from every source; spreadsheet import |
| `/dashboard/workforce/on-site` | On site now | Today's MEGA Clock attendance + **Needs attention** (missed scan-outs) |
| `/dashboard/plant` | Plant | Landing: fuel pumped, hours run, cost |
| `/dashboard/plant/vehicles[/[vehicleId]]` | Vehicles (L/km) | Fleet fuel efficiency, variance, dismissable attention |
| `/dashboard/plant/equipment[/[vehicleId]]` | Equipment (L/h) | Plant hour-meters, L/h, billable value |
| `/dashboard/plant/fuel-logs` | Fuel logs | Every fuel log across both buckets |
| `/dashboard/plant/map` | Map | Leaflet view of each vehicle's last scanned position |
| `/dashboard/financial` | Financial | Landing: open PO value, slips received, uploads waiting |
| `/dashboard/financial/purchase-orders[/[poId]]` | Purchase Orders | Every PO, fulfilment %, line editing, verify |
| `/dashboard/financial/delivery-notes` (+ `/inbox` , `/work-queue` , `/document/[id]` ) | Delivery Notes | Upload → OCR → match → post pipeline and its review queues |
| `/dashboard/financial/suppliers[/[supplierId]]` | Suppliers | Ordered / delivered / outstanding per supplier |
docs(ask): agent actions
docs/modules.md §7.1: threads, memory, files, free queries/virtual
datasets, the propose/confirm/apply/undo gateway, both PDF export paths
(manual answer export and Ask-made reports via make_pdf_report),
images, and change requests — with the actor/x-ask-user model and the
three new PocketBase collections.
docs/data-model.md §4.17: field-by-field ask_threads/ask_messages/
ask_log reference, cross-linked from modules.md via explicit anchors.
docs/api-reference.md §12/§12b: /api/chat's new body shape and its
thread/action/chart/image/pdf SSE events, plus every new agent-actions
route (picker, threads, attachments, confirm-card actions, memories,
change requests) and their auth-matrix entries; the pb-files proxy
entry now notes its ask_messages admin-token path.
README.md: the intro, the modules table (adds Change requests), and
the API surface summary now describe an agent that acts, not just a
read-only chat.
Also marks Tasks 1–12 and 9b's implementation checkbox done in the plan
doc (docs/superpowers/plans/2026-09-26-ask-agent-actions.md) — the
remaining unchecked box is 9b's live check, skipped because
ask_threads/ask_messages/ask_log aren't applied on the target
PocketBase yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 19:32:53 +00:00
| `/dashboard/chat` | Ask | Agent: free queries + charts, files, memory, proposed data changes with undo, PDF reports, images |
| `/dashboard/change-requests` | Change requests | App changes ("can we add this page/column/button?") Ask has logged for the developer |
2026-09-25 20:04:08 +00:00
| `/clock` | MEGA Clock | Installable phone PWA: worker badge scan in/out + vehicle hour-meter scan |
Old paths (`/dashboard/employees`, `/dashboard/fuel[/id]` ,
`/dashboard/purchasing[/id]` , `/dashboard/plant/[id]` ) still work — they
redirect to the pages above and keep `?site=` .
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
---
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
## Documentation
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
| Document | What's in it |
| --- | --- |
| [`docs/architecture.md` ](./docs/architecture.md ) | Runtime topology, the two PB clients, rendering model, auth model, build/deploy |
| [`docs/data-model.md` ](./docs/data-model.md ) | Every PocketBase collection, fields, relations, the `project_code` denormalisation, indexes, API rules |
| [`docs/modules.md` ](./docs/modules.md ) | One section per dashboard module — what it reads, computes, lets the user do |
| [`docs/data-flows.md` ](./docs/data-flows.md ) | End-to-end ingestion pipelines with sequence diagrams (timesheets, fuel, plant, PO, DN) |
| [`docs/api-reference.md` ](./docs/api-reference.md ) | Every API route — method, auth, request/response, error cases |
| [`docs/operations.md` ](./docs/operations.md ) | Env vars, scripts, tests, feature flags, deploy / smoke test |
| [`docs/multi-site-assessment.md` ](./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? |
2026-09-25 20:04:08 +00:00
| [`docs/clock-daily-exceptions-rollout.md` ](./docs/clock-daily-exceptions-rollout.md ) | MEGA Clock new-day scans and the missed scan-out correction flow |
| [`docs/pwa-install-verification.md` ](./docs/pwa-install-verification.md ) | Checking the dashboard / clock PWAs install correctly on iOS + Android |
| [`docs/n8n/` ](./docs/n8n/ ) | The n8n PO-ingest and DN-OCR workflows |
| [`docs/setup/env-and-mcp.md` ](./docs/setup/env-and-mcp.md ) | Local env + MCP client setup |
2026-10-05 00:46:36 +00:00
| [`docs/setup/api-and-mcp-connections.md` ](./docs/setup/api-and-mcp-connections.md ) | Tested API/MCP settings, credential locations, examples, live results and route inventory |
2026-08-08 23:37:40 +00:00
2026-10-05 00:46:36 +00:00
The current remote purchasing MCP design and implementation plan are in
`docs/superpowers/specs/` and `docs/superpowers/plans/` ; for operational
setup and deployment status, use the linked setup guide above.
2026-08-08 23:37:40 +00:00
---
2026-09-06 17:59:52 +00:00
## Tech stack
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
- **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
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
---
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
## API surface (summary)
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
| 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) |
2026-09-25 20:04:08 +00:00
| `POST /api/plant-hours/import` , `GET /api/plant-hours/template` , `GET /api/plant-hours/exception-report/[sheetId]` , `DELETE /api/plant-hours/[id]` | server-only | Plant hours ingest + reporting |
2026-09-06 17:59:52 +00:00
| `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 |
2026-09-25 20:04:08 +00:00
| `POST /api/purchase-orders/ingest` , `GET …/[id]/status` , `POST …/[id]/retry` , `GET …/[id]/document` , `GET …/[id]/pages/[n]` , `POST …/[id]/items` , `PATCH / DELETE …/[id]/items/[itemId]` | server-only / `x-ingest-secret` (ingest) | PO queue, source document, and manual line edits (blocked once verified) |
| `POST /api/dn-batches/tick` (cron), `…/[id]/rerun` , `…/[id]/dismiss` , `…/[id]/assembly` , `GET …/[id]/pages/[n]` , `…/pages/[n]/dismiss` | `x-ingest-secret` (tick) / server-only | Staged delivery-note batches |
| `PATCH /api/dn-batches/[id]/notes/[noteId]` , `…/resolve-entities` , `…/resolve-item` , `…/post` , `…/dismiss` , `…/correct-receipt` | server-only / `RECEIPT_CORRECTION_SECRET` (correct-receipt) | Correct, match, post, or stand down one candidate note |
| `POST /api/suppliers` , `PATCH /api/suppliers/[id]` | server-only | Supplier create / rename |
| `POST /api/vehicles/import-summary` | server-only | Sync the Buildsite Vehicle Fuel Summary CSV into `vehicles` |
| `POST /api/vehicles/[id]/merge` | server-only | Merge a duplicate vehicle into another (dry run unless `confirm` ) |
| `GET /api/pb-files/[collection]/[recordId]/[...filename]` | server-only | Same-origin proxy for PocketBase files (PDF slips in iframes) |
docs(ask): agent actions
docs/modules.md §7.1: threads, memory, files, free queries/virtual
datasets, the propose/confirm/apply/undo gateway, both PDF export paths
(manual answer export and Ask-made reports via make_pdf_report),
images, and change requests — with the actor/x-ask-user model and the
three new PocketBase collections.
docs/data-model.md §4.17: field-by-field ask_threads/ask_messages/
ask_log reference, cross-linked from modules.md via explicit anchors.
docs/api-reference.md §12/§12b: /api/chat's new body shape and its
thread/action/chart/image/pdf SSE events, plus every new agent-actions
route (picker, threads, attachments, confirm-card actions, memories,
change requests) and their auth-matrix entries; the pb-files proxy
entry now notes its ask_messages admin-token path.
README.md: the intro, the modules table (adds Change requests), and
the API surface summary now describe an agent that acts, not just a
read-only chat.
Also marks Tasks 1–12 and 9b's implementation checkbox done in the plan
doc (docs/superpowers/plans/2026-09-26-ask-agent-actions.md) — the
remaining unchecked box is 9b's live check, skipped because
ask_threads/ask_messages/ask_log aren't applied on the target
PocketBase yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 19:32:53 +00:00
| `POST /api/chat` | `ENABLE_CHAT=true` , `x-ask-user` identifies (no real auth yet) | SSE chat stream — `thread` /`action`/`chart`/`image`/`pdf` events |
| `GET /api/ask/users` , `GET/POST /api/chat/threads[/[id]]` , `POST /api/chat/attachments` , `GET/POST /api/ask/memories[/[id]]` | `ENABLE_CHAT=true` + `x-ask-user` | Ask's picker, threads, attachments, memory |
| `GET /api/agent/actions/[id]` , `POST …/{apply,reject,undo}` | `ENABLE_CHAT=true` + `x-ask-user` ; confirm routes are same-origin only | Propose → confirm → apply/undo, with a before/after snapshot |
| `GET/PATCH /api/ask/change-requests[/[id]]` | server-only | App change requests Ask filed for the developer |
2026-09-25 20:04:08 +00:00
| `GET /api/clock/employee-lookup` , `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 |
| `POST /api/clock/events/[id]/correct` | same-origin + `x-app-pin` = `APP_PIN` | Record the real leaving time for a missed scan-out |
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
Full reference: [`docs/api-reference.md` ](./docs/api-reference.md ).
2026-08-08 23:37:40 +00:00
---
2026-09-06 17:59:52 +00:00
## Tests
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
```bash
npm run typecheck # tsc --noEmit
npm run test:run # vitest run
2026-09-25 20:04:08 +00:00
npm run lint # eslint . — not yet clean, see docs/operations.md §4.1
2026-08-08 23:37:40 +00:00
```
2026-09-06 17:59:52 +00:00
The metric helpers under `src/lib/metrics/*.test.ts` pin every
computation the dashboard exposes. Run after any change to the
financial roll-up.
2026-08-08 23:37:40 +00:00
---
2026-09-06 17:59:52 +00:00
## License
2026-08-08 23:37:40 +00:00
2026-09-06 17:59:52 +00:00
Proprietary. Internal use only.
2026-10-05 00:46:36 +00:00
## Remote purchasing MCP
See [remote setup and deployment ](docs/setup/remote-purchasing-mcp.md ) for the same-app `/api/mcp` endpoint, dedicated keys, purchasing writes and no-delete policy.