| `RECEIPT_CORRECTION_SECRET` | no | yes (receipt edits) | unset | Server-only code required by `POST /api/dn-batches/[id]/notes/[noteId]/correct-receipt` to edit a posted receipt. At least 12 chars; must not reuse the PIN. `openssl rand -hex 16`. |
| `MEGA_CUSTOMER_VAT_NO` | no | yes (DN pipeline) | unset | MEGA's VAT number. The DN pipeline checks the customer identity block printed on each slip against it; a mismatch marks the note `needs_attention`. |
| `NEXT_PUBLIC_APP_NAME` | yes | no | `MEGA INFRASTRUCTURE` | Brand on the lock screen. |
| `NEXT_PUBLIC_DEFAULT_THEME` | yes | no | `light` | `light` or `dark` — pre-hydration fallback. |
| `NEXT_PUBLIC_POCKETBASE_URL` | yes | yes (PB-dependent) | `http://127.0.0.1:8090` | Browser-reachable PB URL. **Also used by `pbAdmin()` server-side.** The runtime joins file URLs off this same base. |
| `NEXT_PUBLIC_API_BASE_URL` | yes | no | unset | Legacy. Documented but unused in current code. |
| `POCKETBASE_ADMIN_EMAIL` | no | yes (server) | unset | Superuser email used by `pbAdmin()`. |
| `POCKETBASE_ADMIN_TOKEN` | no | optional | unset | If set, used in place of email + password — saves a re-auth on every cold start. Generate via PocketBase admin UI → "Generate token". |
| `N8N_PO_INGEST_URL` | no | yes (PO upload) | unset | Webhook URL the Next.js server forwards PO uploads to. Server-only. |
| `N8N_INGEST_SECRET` | no | yes (n8n callbacks) | unset | Shared secret n8n sends in `x-ingest-secret` on the ingest/process-batch/ocr-result/slip routes. Generate with `openssl rand -hex 32`. |
| `N8N_MCP_URL` | no | optional | unset | Public URL of the n8n MCP server (for the local Codex MCP config). |
| `ENABLE_CHAT` | no | **NO** (production) | unset | Master switch for `/api/chat` and `/dashboard/chat`. The `.env.local.example` warning is explicit: must stay unset in production until real authentication exists. |
| `CHAT_PROVIDER` | no | no | `anthropic` | `anthropic` or `minimax` (MiniMax OpenAI-compatible endpoint). |
| `ANTHROPIC_API_KEY` | no | conditional | unset | Anthropic API key. Leave unset to use an `ant auth login` profile instead. |
| `MINIMAX_API_KEY` | no | conditional | unset | MiniMax Open Platform API key (NOT a Token Plan subscription key). |
| `MINIMAX_BASE_URL` | no | no | `https://api.minimax.io/v1` | MiniMax OpenAI-compatible base URL. |
| `MINIMAX_MODEL` | no | no | `MiniMax-M3` | The only model in the M-series that supports BOTH vision AND tool calling (verified 2026-08-30). M2 / M2.7 accept tools but reject images. |
| `pb-bootstrap-schema.py` | Canonical schema definition for the 13 collections. Run after any schema change. | No — running twice may fail because the collections already exist. |
| `pb-relax-rules.py` | Writes the production API ruleset to every collection (`list/view/create` = any authed, `update/delete` = superuser). | Yes — re-running just rewrites the same rules. |
| `migrate-delivery-notes-ocr.py` | One-off migration that adds the OCR `processing_status` / `ocr_*` fields and seeds status on existing DNs. | No — running twice is a no-op on most steps. |
| `migrate-plant-hours-backfill-vehicle.py` | Backfills `plant_hours_log.vehicle` relations from `vehicle_qr` for pre-relation rows. | Idempotent. |
### 2.2 Build-time
| Script | Trigger | Output |
| --- | --- | --- |
| `build-icons.mjs` | `npm run build` (pre-step) | Regenerates the PWA icon set under `public/icons/` |
| `build-og-image.mjs` | `npm run build` (pre-step) | Regenerates `public/og-image.png` for OG previews |
| `patch-next-dev-blocker.cjs` | `npm install` (`postinstall` hook) | Patches Next 16's dev-only cross-site guard so `next dev` accepts any host |
| `generate-plant-hours-template.ts` | Manual | Used by `scripts/build-*.mjs` for the plant-hours template |
The `postinstall` patch is **only loaded by `next dev`** — never by
production. The Dockerfile runs `npm ci --ignore-scripts` in the `deps`
stage to skip the hook entirely (`Dockerfile:32`).
### 2.3 Migrations directory
`scripts/migrations/` holds one-off patches that the schema script
doesn't cover. Examples (without full enumeration — there are several):
- Aug 2026: `latest_consumption` field added to `fuel_logs`.
- Sep 2026: `file_hash` column added to `data_import_batches` for PO
dedup.
Always add a new entry here when running a one-off schema change. The
as evidence of how the Coolify deploy surface looks when something
breaks. This is left in-tree for context, not as a reference.
---
## 6. Feature flags
| Flag | Default | Effect when on | Effect when off |
| --- | --- | --- | --- |
| `ENABLE_CHAT` | unset (= `false`) | `/api/chat` and `/dashboard/chat` work | Both return 404 / `notFound()` |
| `NEXT_PUBLIC_DEFAULT_THEME` | `light` | Initial theme before user preference loads | " |
| `CHAT_PROVIDER` | `anthropic` | `anthropic` if `ANTHROPIC_API_KEY` is set (or `ant auth login` profile); `minimax` / `openai` if `MINIMAX_API_KEY` is set |
There is no other feature-flag mechanism. Anything else that needed to
be toggleable in the past has been either hardcoded (variance tolerances,
`RATE_PER_LITRE`) or set via env (`RATE_PER_LITRE` is in