Updated the operations dashboard to include a rain outlook feature, providing users with a 7-day forecast based on site coordinates. Added latitude and longitude fields to the site form for better weather data integration. Enhanced the fuel log and site management functionalities to utilize dynamic fuel pricing based on historical data. Improved overall data handling and user experience across various dashboard components.
14 KiB
Prompt for MiniMax agent — Document the app + assess multi-site readiness
Paste everything below the line into the MiniMax agent. It assumes the agent has read/write access to this repository.
Role
You are a senior engineer joining the MEGA INFRASTRUCTURE codebase. Your job has two parts, in this order:
- Write the missing technical documentation for the app as it exists today.
- Deliver a multi-site readiness assessment: can this app genuinely run many construction sites at once right now, and what specifically has to change for it to do so reliably at scale?
You are producing documentation and analysis only. Do not change application code, schema, or config. The only files you create or modify are the deliverables listed at the bottom.
Ground rules
- Evidence over assumption. Every factual claim you make must cite a real
path/to/file.ts:line. If you cannot find evidence for something, write "unverified" and say what you looked at. - The
README.mdat the repo root is stale and actively wrong. It describes an earlier mock-data version. It referencessrc/lib/fuel.ts,src/lib/types.ts,src/app/api/mcp/,src/app/api/upload/, and/dashboard/orders— none of these exist. Do not use it as a source. Treat the source code as the only truth. - Read
AGENTS.mdfirst. This is a modified build of Next.js 16; conventions may differ from what you expect. Authoritative docs live innode_modules/next/dist/docs/. Read the relevant guide there before making any claim about Next.js behaviour (caching, dynamic rendering, route handlers, server components). - Do not invent severity. Distinguish clearly between: (a) a bug that breaks correctness today, (b) a limit that will break at a known threshold, (c) a design choice that is fine now but will cost more to change later.
- Verify claims by reading code. Where useful, run
npm run typecheckandnpm run test:runto confirm the suite's current state, and report the actual output.
What the app is
A Next.js 16 (App Router, React 19, Tailwind v4) operations dashboard for a South African civil construction company, backed by PocketBase. It tracks, per construction site: sites/contracts, employees & timesheets, vehicles (fuel and plant units), fuel logs, plant hour meters, fixed costs, income claims, purchase orders + line items, and delivery notes with OCR-driven receipting. There is also an LLM chat ("Ask") surface with a read-only tool layer over the same data, and an MCP server.
Key entry points to orient yourself:
| Area | Path |
|---|---|
PocketBase clients (pb browser, pbAdmin superuser) |
src/lib/pb.ts |
| Full collection type definitions | src/lib/pb-types.ts |
| Dashboard pages (server components) | src/app/dashboard/**/page.tsx |
| Route handlers | src/app/api/**/route.ts |
| Pure metric/calculation functions | src/lib/metrics/ |
| Import parsers (timesheets, fuel, plant hours, POs) | src/lib/*-parse.ts, src/lib/*-import.ts |
| Chat/agent tool layer | src/lib/agent/, src/lib/chat/ |
| Auth (PIN gate) | src/hooks/use-auth.tsx, src/components/auth-gate.tsx |
| Schema bootstrap / rules scripts | scripts/pb-bootstrap-schema.py, scripts/pb-relax-rules.py |
| Existing design/plan docs | docs/superpowers/specs/, docs/superpowers/plans/ |
Part 1 — Documentation to write
Write these as Markdown into docs/. Aim for documents a new engineer could use to become
productive without reading every file, and that a non-technical owner could use to
understand what the system does.
1. docs/architecture.md
- Runtime topology: Next.js app → PocketBase → n8n webhooks (PO ingest, delivery-note OCR) → LLM providers. Draw it as a Mermaid diagram.
- Rendering model: which pages are server components, what
export const dynamicsettings are in use, where data fetching happens, and what is client-side. - The two PocketBase clients and when each is used. Be explicit about the fact that
server routes and pages authenticate as the PocketBase superuser via
pbAdmin()(src/lib/pb.ts) and what that implies. - Auth model as it actually is today: a shared numeric PIN from
NEXT_PUBLIC_APP_PIN(default2468), held insessionStorage, with a?demo=1query-string bypass (src/hooks/use-auth.tsx). State plainly that there is no per-user identity in the application. - Build/deploy:
Dockerfile,docker-compose.yml,COOLIFY.md, the--webpackrequirement for the PWA plugin, and the icon/OG-image prebuild scripts.
2. docs/data-model.md
- Every PocketBase collection from
src/lib/pb-types.ts: fields, types, relations, and which are optional/legacy. - An entity-relationship Mermaid diagram.
- For each collection, state explicitly whether it carries a
siterelation, aproject_codestring, both, or neither. Flag the ones that carry neither and explain how those records are attributed to a site (if at all). - Document the
project_codedenormalisation: it is copied onto child records rather than read through thesiterelation. Describe the drift risk and where it is written. - Document known unique indexes and constraints you can find (e.g. the composite unique index
on
plant_hours_logreferenced insrc/app/api/plant-hours/import/route.ts), and what happens on collision. - Document PocketBase API rules as configured by
scripts/pb-relax-rules.py(list/view/create = any authenticated user; update/delete = superuser only) and what that means for who can read what.
3. docs/modules.md
One section per dashboard module (Overview, Sites, Workforce, Plant & Equipment, Fleet & Fuel, Purchasing, Ask). For each: purpose, route, which collections it reads, which metric functions it uses, what the user can do there, and which API routes it calls.
4. docs/data-flows.md
Trace each ingestion pipeline end to end, with a sequence diagram:
- Timesheet import (
/api/timesheets/import) — including the auto-create-employees path. - Fuel log import (
/api/fuel-logs/import). - Plant hours import (
/api/plant-hours/import) + exception report. - Purchase order upload → n8n →
/api/purchase-orders/ingest→process-batch. - Delivery note upload → OCR →
/api/delivery-notes/[id]/ocr-result→ received items.
For each pipeline, answer precisely: how is the target site determined for each imported row? Name the exact matching strategy and the failure behaviour when no match is found.
5. docs/api-reference.md
Every route under src/app/api/: method, path, auth/secret requirements, request shape,
response shape, error cases. Note which are protected by N8N_INGEST_SECRET and which have
no protection at all.
6. docs/operations.md
Environment variables (from .env.local.example), what each does, which are
client-exposed (NEXT_PUBLIC_), the scripts in scripts/, how to run tests, and the
existing feature flags (e.g. ENABLE_CHAT).
Part 2 — Multi-site readiness assessment
Write this as docs/multi-site-assessment.md. This is the deliverable that matters most.
The question to answer
Multiple construction sites — The Hills, Cosmo City, Castle Gate, Autumns Gate, Pitsana Mills, West Park, and more to come. This is not a question about multi-tenancy or serving multiple client companies. It is: does the existing per-site model actually hold up as the number of sites and the volume of historical data grows, and where does it break?
Structure your answer in three parts.
Part A — What works today
The data model is already site-aware. Verify and document this properly: which collections
carry a site relation, which UI surfaces group or filter by site, how per-site financials
are computed (src/lib/metrics/site-spend.ts, site-projection.ts,
income-vs-expenses.ts), and how the chat tool layer resolves a site from free text
(src/lib/agent/resolve.ts). Give a plain verdict: at what scale does the app work
correctly as-is?
Part B — Where it breaks
Investigate each of the following. These are leads I have partially verified — confirm or refute each one yourself with file:line evidence, correct me where I am wrong, and add anything I missed. Do not simply restate this list; test each claim.
-
Hard 50-site cap on the Overview page.
src/app/dashboard/page.tsx:64callspb.collection("sites").getList<SiteRecord>(1, 50, { sort: "name" }). Determine what happens to site 51+ — does it silently vanish from KPI tiles and the "Attention required" rail? Search the whole codebase for other cappedgetList(page, perPage)calls and list every one with its cap and its blast radius. There is a related comment atsrc/app/dashboard/purchasing/page.tsx:29about a previous cap that silently truncated data — treat that as evidence this class of bug has already bitten once. -
Load-everything-then-filter-in-memory. Most dashboard pages call
getFullList()on entire collections and filter in JavaScript — e.g.src/app/dashboard/page.tsx,src/app/dashboard/sites/page.tsx,src/app/dashboard/purchasing/page.tsx,src/app/dashboard/fuel/page.tsx,src/app/dashboard/employees/page.tsx. Note especiallysrc/app/dashboard/sites/[id]/page.tsx:50-56, which filters some collections bysite='<id>'server-side but pulls all timesheets and all employees regardless. Quantify: with N sites × M months of fuel logs, timesheets, POs and received items, how does page cost grow? Estimate the row counts at which pages become slow, and identify which single page falls over first. -
No global site scope. The sidebar (
src/components/layout/sidebar.tsx) has no site selector; each module handles site filtering independently, mostly client-side. Assess what this costs a user who works on one site: how many clicks/filters to see just their data, and which modules offer no site filter at all. -
Site resolution by name string. Importers match incoming rows to sites by case-insensitive
sites.namecomparison (seesrc/app/api/fuel-logs/import/route.tsaround lines 214-224 andsrc/app/api/plant-hours/import/route.tsaround lines 237-245), and PO matching goes throughsrc/lib/purchase-order-schema.ts. Evaluate the failure modes as site count grows: near-identical names, renamed sites, whitespace/casing drift, two sites sharing a name, source spreadsheets using a different label than PocketBase. What happens to a row that matches nothing — is it dropped, orphaned, or rejected? Isproject_codea more reliable key, and is it consistently present? -
Vehicles, plant and employees moving between sites. A vehicle or worker is bound to one
siteat a time. Determine what happens to historical records when that assignment changes: do past fuel logs and timesheets stay attributed to the old site, or do they follow the current assignment and silently rewrite history? Check whether logs snapshot the site at import time or read it through the relation. Note thatplant_hours_logstoresvehicle_unit_type_at_import, which suggests the codebase already understands point-in-time snapshotting — does the same discipline apply tosite? Also check the(vehicle_qr, start_date)unique index for cross-site collisions. -
Access control per site. With a single shared PIN and no user records, no user can be restricted to their own site — everyone who knows the PIN sees every site's contract values, margins and payroll. Confirm this, and confirm that server-side data access runs as PocketBase superuser (
pbAdmin()), meaning collection-level API rules do not constrain it. State whether per-site access control is achievable without introducing real user accounts. -
The chat/agent layer. Tools in
src/lib/agent/tools.tsload portfolio-wide bundles (list_sitesand friends). Assess: cost and latency growth as sites multiply, whether ambiguous site names are handled safely (src/lib/agent/resolve.ts), and whether the agent can leak one site's financials to a user who should only see another's. Note that.env.local.examplealready warnsENABLE_CHATmust stay off in production until real authentication exists — verify whether that warning is still accurate. -
Anything else you find. Cross-site data leakage, missing indexes, N+1 queries, unbounded
getFullList()calls in route handlers, aggregates that double-count when a record has a staleproject_code, and the$autoCancel: falseworkarounds insrc/lib/pb.tsand the dashboard pages — do those indicate a concurrency problem that worsens with more sites?
For every finding, give: what breaks, at what threshold, what the user sees when it breaks, and the file:line evidence.
Part C — What to change
A prioritised remediation plan. For each item: the problem, the proposed change, the files affected, rough effort (S/M/L), the risk of doing it, and the risk of not doing it. Group into:
- Tier 1 — Correctness. Things that silently produce wrong numbers or hide data today. These are not optional.
- Tier 2 — Scale. Query patterns, pagination, indexes, and server-side filtering needed
before the site count or data volume grows further. Say explicitly what the app should do
instead of
getFullList()and where PocketBase filters/indexes belong. - Tier 3 — Product. A global site scope/selector, per-site access control (and the user model it requires), site archiving for completed contracts, and point-in-time site attribution for moved assets.
End with a one-paragraph bottom line in plain English, written for the business owner, not an engineer: can this app run many sites today, how many, and what is the single most important thing to fix first.
Deliverables
Create exactly these files:
docs/architecture.md
docs/data-model.md
docs/modules.md
docs/data-flows.md
docs/api-reference.md
docs/operations.md
docs/multi-site-assessment.md
Then replace the stale root README.md with an accurate short overview that links to the
documents above. Keep it under 100 lines; the detail belongs in docs/.
Do not modify any file under src/, scripts/, or any config file.
Finish with a short summary in chat covering: your multi-site verdict, the top three things that must be fixed, and any claim in this prompt that turned out to be wrong.