Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/aswaratech_fleetco.json
T

1 line
121 KiB
JSON

{"repo": "aswaratech/fleetco", "files": {".env.production.example": {"ba1e8d797c664f9656740124e8fce484d9ca6788": {"t": 1785747100.248598, "n": 10702, "h": "74b272fd75a09516", "c": "# FleetCo production environment — TEMPLATE (ADR-0014 §4, ADR-0013 data tiers).\n#\n# Copy to a root-owned, chmod 600, gitignored `.env` on the VPS (at\n# /opt/fleetco/.env) and replace every placeholder. This file is committed and\n# MUST contain only placeholders — NEVER a real secret (CLAUDE.md, ADR-0013).\n#\n# docker-compose.prod.yml reads this file two ways:\n# - `env_file: .env` injects it into the api + web containers (runtime config).\n# - Compose interpolates ${IMAGE_TAG}, ${POSTGRES_*}, and ${PUBLIC_DOMAIN}\n# from it into the compose file itself (image tags, postgres init, Caddy).\n#\n# Data-tier legend (ADR-0013), shown per-variable on the comment line above it:\n# [T1] secret — never committed, never logged (the box's disk encryption + OS\n# access control is the trust boundary, ADR-0014 §4).\n# [T2] PII. [T4] non-sensitive config.\n# Tags ride the comment lines (not the value lines) so no annotation can ever\n# be parsed into a value.\n\n# === Image tag (Compose interpolation) ======================================\n# [T4] The GHCR tag to deploy. CI pushes images tagged by commit SHA (T3); set\n# this to that SHA on every deploy (`export IMAGE_TAG=<sha>`). `latest` is only\n# a placeholder so `docker compose config` resolves.\nIMAGE_TAG=latest\n\n# === Public origin ==========================================================\n# [T4] The single public hostname (no scheme). Caddy terminates TLS for it and\n# reads it via {$PUBLIC_DOMAIN}; BETTER_AUTH_URL / CORS_ORIGIN /\n# NEXT_PUBLIC_API_URL below are all https://<this> (ADR-0014 §2 same-origin).\nPUBLIC_DOMAIN=app.fleetco.example\n\n# === Runtime mode ===========================================================\n# [T4]\nNODE_ENV=production\n# [T4] Optional (api default: info). One of: fatal error warn info debug trace.\nLOG_LEVEL=info\n# Do NOT set PORT or HOSTNAME — the api (3001) and web (3000) ports are baked\n# into the images, the Caddyfile, and the compose healthchecks.\n\n# === PostgreSQL ==============================================================\n# The postgres container's first-run init credentials. These three MUST agree\n# with the user:password/database embedded in DATABASE_URL below.\n# [T4]\nPOSTGRES_USER=fleetco\n# [T1]\nPOSTGRES_PASSWORD=REPLACE_WITH_A_STRONG_DB_PASSWORD\n# [T4]\nPOSTGRES_DB=fleetco\n\n# === API datastores =========================================================\n# [T1] Carries the DB password (must equal POSTGRES_PASSWORD above). Host is the\n# compose service name `postgres`.\nDATABASE_URL=postgresql://fleetco:REPLACE_WITH_A_STRONG_DB_PASSWORD@postgres:5432/fleetco?schema=public\n# [T4] Host is the compose service name `redis` (no auth at this scale, ADR-0014 §1).\nREDIS_URL=redis://redis:6379\n\n# === Auth (better-auth — ADR-0015, ADR-0021) ================================\n# [T1] Session-signing secret, >=32 bytes. Generate with: openssl rand -hex 32\nBETTER_AUTH_SECRET=REPLACE_WITH_openssl_rand_hex_32_minimum_32_bytes\n\n# === GPS tracker gateway (Traccar — ADR-0042 M5/M6) =========================\n# [T1] Machine-ingest key for the Traccar → API position-forward hop, >=32\n# chars. Generate with: openssl rand -hex 32. The SAME value is injected into\n# the traccar container's forward header (M6 compose config); the ingest route\n# answers 503 while this is unset (fails closed). Before the first forward,\n# seed the credential-less gateway system user once:\n# pnpm --filter @fleetco/api exec tsx scripts/seed-gateway-user.ts\nINGEST_API_KEY=REPLACE_WITH_openssl_rand_hex_32_minimum_32_chars\n# [T1] Password for the dedicated low-privilege `traccar` Postgres role that\n# owns the separate `traccar` database in the shared postgres container\n# (ADR-0042 c3; distinct from POSTGRES_PASSWORD on purpose — the third-party\n# gateway never holds the app DB's superuser credential). Generate with:\n# openssl rand -hex 32. Compose injects it into the traccar container as\n# DATABASE_PASSWORD; the role + database are created once via the idempotent\n# snippet in docs/runbook/traccar.md (which reads this same variable).\nTRACCAR_DB_PASSWORD=REPLACE_WITH_A_STRONG_TRACCAR_DB_PASSWORD\n# [T4] The public API base URL = https://<PUBLIC_DOMAIN> (ADR-0014 §2).\nBETTER_AUTH_URL=https://app.fleetco.example\n# [T4] Same-origin allowlist = the single public origin (ADR-0014 §2).\nCORS_ORIGIN=https://app.fleetco.example\n\n# === Web admin ==============================================================\n# [T4] BAKED into the web image at build time (T3 --build-arg; deploy.md step\n# 0) — into the SERVER bundle as well as the browser bundle, so this on-box\n# line is runtime-inert for the web app and stands as the record of the baked\n# origin. Keep it equal to the public origin (ADR-0014 §2 same-origin).\nNEXT_PUBLIC_API_URL=https://app.fleetco.example\n\n# === Admin seed (one-off `db:seed`, ADR-0014 §9 / ADR-0021) =================\n# Read only by the one-time seed task to create the first admin user.\n# [T2]\nADMIN_EMAIL=admin@fleetco.example\n# [T1]\nADMIN_PASSWORD=REPLACE_WITH_THE_FIRST_ADMIN_PASSWORD\n# CREATE_USER_PASSWORD (the office-staff/admin creation path, ADR-0028) is passed\n# INLINE on the create-user command at run time, never stored here.\n\n# === AI chat agent (DeepSeek — ADR-0043) ====================================\n# [T1] when set. The agent's hosted-LLM API key. LEAVE EMPTY TO KEEP THE AGENT\n# OFF THE NETWORK: unset means the API binds the no-network MockLlmClient — the\n# production kill switch (ADR-0043 c2). Set only after the ADR-0042 deploy\n# reaches daily use AND the DeepSeek training opt-out has been requested for\n# the account (ADR-0043 c6).\nDEEPSEEK_API_KEY=\n# [T4] Optional (api default: deepseek-v4-flash). The model name the agent\n# requests; the legacy deepseek-chat / deepseek-reasoner names deprecate\n# 2026-07-24.\nDEEPSEEK_MODEL=deepseek-v4-flash\n\n# === WhatsApp agent channel (Twilio — ADR-0046) ==============================\n# ALL optional and EMPTY at the first deploy: while the TWILIO_* group is unset\n# the api binds MockWhatsAppSender and the inbound webhook fails closed (503) —\n# the channel is OFF (the DEEPSEEK_API_KEY kill-switch idiom). Activation is a\n# deliberate post-deploy step owned by docs/runbook/whatsapp-operations.md\n# (register the sender, set these five, recreate the api container, provision\n# the phone link) — set nothing here on the first pass.\n# [T1] Account SID + auth token. The token both verifies inbound\n# X-Twilio-Signature headers AND Basic-auths outbound sends — never logged,\n# never committed.\nTWILIO_ACCOUNT_SID=\nTWILIO_AUTH_TOKEN=\n# [T4] The WhatsApp-enabled sender, in Twilio's whatsapp:+<E164> form.\nTWILIO_WHATSAPP_FROM=\n# [T4] The EXACT public webhook URL registered with Twilio — signature\n# verification pins this constant byte-for-byte (scheme, host, path):\n# https://<PUBLIC_DOMAIN>/api/v1/whatsapp/inbound\nTWILIO_WEBHOOK_URL=\n# [T4] The admin web's public base URL for reply deep-links —\n# https://<PUBLIC_DOMAIN> on the single-origin deploy (ADR-0014 §2).\nWEB_PUBLIC_URL=\n\n# === Reminder delivery (Resend — ADR-0038) ==================================\n# The compliance/maintenance reminder digest (daily 01:00 UTC scan) delivers\n# ONLY when this group is set; while empty the api binds the no-network\n# MockMailer and nothing sends (the DEEPSEEK_API_KEY kill-switch idiom).\n# Activation is operator-led: verify a sending domain in Resend (SPF/DKIM/\n# DMARC — ADR-0038 c9), then set both and recreate the api container.\n# [T1] The Resend API key — never logged, never committed.\nRESEND_API_KEY=\n# [T4] The sending address on the VERIFIED domain, e.g.\n# \"FleetCo <reminders@yourdomain.com.np>\". Unset falls back to a reserved\n# `.example` placeholder that can never deliver — set it with the key.\nRESEND_FROM=\n# [T2] Optional comma-separated extra recipients added to the ADMIN users'\n# emails (a shared inbox, the accountant). Addresses are PII — never logged.\nNOTIFICATION_RECIPIENTS=\n\n# === Object storage (Cloudflare R2 — ADR-0039 c7 / ADR-0044 V2) =============\n# Required for invoice ISSUE (the PDF is stored at issue time) and for agent\n# photo attachments + fleet documents (ADR-0049); while ANY is empty the api\n# binds an in-memory mock store and invoice issue() refuses with a clear 422 —\n# so the api never reaches R2 until the operator configures it.\n#\n# SHARED BUCKET (ADR-0014 §6): this is the SAME R2 bucket the nightly backup\n# uses (deploy/backup.env's R2_BUCKET) — one bucket for the whole project. The\n# app writes under the `invoices/`, `documents/`, and `agent-attachments/`\n# key PREFIXES; the backups sit at the bucket ROOT as `fleetco-<date>.sql.gz.age`.\n# The backup's 30-day prune is filename-scoped (`--include /fleetco-*.sql.gz.age`)\n# so it NEVER deletes an app object — see deploy/backup.sh. If you instead want a\n# separate bucket, point this at that bucket and give it its own scoped token.\n# From the Cloudflare dashboard: an R2 API token scoped to this bucket.\n# [T4] The S3 API endpoint, https://<accountid>.r2.cloudflarestorage.com\nR2_ENDPOINT=\n# [T1] The R2 API token pair — never logged, never committed. May be the SAME\n# token the backup rclone remote uses, or a distinct app-scoped token (a\n# distinct token limits blast radius: the app key then cannot read/delete the\n# encrypted backups, your disaster-recovery lifeline).\nR2_ACCESS_KEY_ID=\nR2_SECRET_ACCESS_KEY=\n# [T4] The bucket name — the SAME value as the backup's R2_BUCKET when sharing.\nR2_BUCKET=\n\n# === Invoice supplier identity (ADR-0039 c9) ================================\n# Required before issuing a REAL invoice (issue() refuses 422 while the PAN is\n# empty). Operator/accountant-verified values only — never fabricated.\n# [T3] FleetCo's OWN supplier PAN/VAT number printed on every tax invoice.\nINVOICE_SUPPLIER_PAN=\n# [T4] The registered business name for the invoice header (api default:\n# \"FleetCo\").\nINVOICE_SUPPLIER_NAME=\n\n# === Observability (optional — ADR-0024) ====================================\n# [T1] when set (ADR-0014 §4). Leave empty to disable.\nSENTRY_DSN=\n# [T4] Leave empty to disable.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# --- Agent document extraction (ADR-0044 Box B: self-hosted OCR sidecar) ----\n# LEAVE EMPTY AT THE FIRST DEPLOY. Set only when the OCR sidecar container is\n# up on the box (its own compose service + runbook step, ticket V6+; the\n# sidecar needs ~5 GB resident — the VPS sizing note in ADR-0044 Box B).\n# Unsetting this is the image-extraction kill switch (the DEEPSEEK_API_KEY\n# pattern): chat keeps working, attachments degrade to an honest notice.\nAGENT_OCR_URL=\n# Defaults to the ADR-0044-pinned model id; self-quantizing from the official\n# weights is the recorded production preference.\n#AGENT_OCR_MODEL=huggingface.co/sahilchachra/unlimited-ocr-gguf:Q4_K_M\n"}, "636ba2586183a8d800e726032b3c7b102657a00f": {"t": 1785770422.657841, "n": 10702, "h": "74b272fd75a09516", "c": "# FleetCo production environment — TEMPLATE (ADR-0014 §4, ADR-0013 data tiers).\n#\n# Copy to a root-owned, chmod 600, gitignored `.env` on the VPS (at\n# /opt/fleetco/.env) and replace every placeholder. This file is committed and\n# MUST contain only placeholders — NEVER a real secret (CLAUDE.md, ADR-0013).\n#\n# docker-compose.prod.yml reads this file two ways:\n# - `env_file: .env` injects it into the api + web containers (runtime config).\n# - Compose interpolates ${IMAGE_TAG}, ${POSTGRES_*}, and ${PUBLIC_DOMAIN}\n# from it into the compose file itself (image tags, postgres init, Caddy).\n#\n# Data-tier legend (ADR-0013), shown per-variable on the comment line above it:\n# [T1] secret — never committed, never logged (the box's disk encryption + OS\n# access control is the trust boundary, ADR-0014 §4).\n# [T2] PII. [T4] non-sensitive config.\n# Tags ride the comment lines (not the value lines) so no annotation can ever\n# be parsed into a value.\n\n# === Image tag (Compose interpolation) ======================================\n# [T4] The GHCR tag to deploy. CI pushes images tagged by commit SHA (T3); set\n# this to that SHA on every deploy (`export IMAGE_TAG=<sha>`). `latest` is only\n# a placeholder so `docker compose config` resolves.\nIMAGE_TAG=latest\n\n# === Public origin ==========================================================\n# [T4] The single public hostname (no scheme). Caddy terminates TLS for it and\n# reads it via {$PUBLIC_DOMAIN}; BETTER_AUTH_URL / CORS_ORIGIN /\n# NEXT_PUBLIC_API_URL below are all https://<this> (ADR-0014 §2 same-origin).\nPUBLIC_DOMAIN=app.fleetco.example\n\n# === Runtime mode ===========================================================\n# [T4]\nNODE_ENV=production\n# [T4] Optional (api default: info). One of: fatal error warn info debug trace.\nLOG_LEVEL=info\n# Do NOT set PORT or HOSTNAME — the api (3001) and web (3000) ports are baked\n# into the images, the Caddyfile, and the compose healthchecks.\n\n# === PostgreSQL ==============================================================\n# The postgres container's first-run init credentials. These three MUST agree\n# with the user:password/database embedded in DATABASE_URL below.\n# [T4]\nPOSTGRES_USER=fleetco\n# [T1]\nPOSTGRES_PASSWORD=REPLACE_WITH_A_STRONG_DB_PASSWORD\n# [T4]\nPOSTGRES_DB=fleetco\n\n# === API datastores =========================================================\n# [T1] Carries the DB password (must equal POSTGRES_PASSWORD above). Host is the\n# compose service name `postgres`.\nDATABASE_URL=postgresql://fleetco:REPLACE_WITH_A_STRONG_DB_PASSWORD@postgres:5432/fleetco?schema=public\n# [T4] Host is the compose service name `redis` (no auth at this scale, ADR-0014 §1).\nREDIS_URL=redis://redis:6379\n\n# === Auth (better-auth — ADR-0015, ADR-0021) ================================\n# [T1] Session-signing secret, >=32 bytes. Generate with: openssl rand -hex 32\nBETTER_AUTH_SECRET=REPLACE_WITH_openssl_rand_hex_32_minimum_32_bytes\n\n# === GPS tracker gateway (Traccar — ADR-0042 M5/M6) =========================\n# [T1] Machine-ingest key for the Traccar → API position-forward hop, >=32\n# chars. Generate with: openssl rand -hex 32. The SAME value is injected into\n# the traccar container's forward header (M6 compose config); the ingest route\n# answers 503 while this is unset (fails closed). Before the first forward,\n# seed the credential-less gateway system user once:\n# pnpm --filter @fleetco/api exec tsx scripts/seed-gateway-user.ts\nINGEST_API_KEY=REPLACE_WITH_openssl_rand_hex_32_minimum_32_chars\n# [T1] Password for the dedicated low-privilege `traccar` Postgres role that\n# owns the separate `traccar` database in the shared postgres container\n# (ADR-0042 c3; distinct from POSTGRES_PASSWORD on purpose — the third-party\n# gateway never holds the app DB's superuser credential). Generate with:\n# openssl rand -hex 32. Compose injects it into the traccar container as\n# DATABASE_PASSWORD; the role + database are created once via the idempotent\n# snippet in docs/runbook/traccar.md (which reads this same variable).\nTRACCAR_DB_PASSWORD=REPLACE_WITH_A_STRONG_TRACCAR_DB_PASSWORD\n# [T4] The public API base URL = https://<PUBLIC_DOMAIN> (ADR-0014 §2).\nBETTER_AUTH_URL=https://app.fleetco.example\n# [T4] Same-origin allowlist = the single public origin (ADR-0014 §2).\nCORS_ORIGIN=https://app.fleetco.example\n\n# === Web admin ==============================================================\n# [T4] BAKED into the web image at build time (T3 --build-arg; deploy.md step\n# 0) — into the SERVER bundle as well as the browser bundle, so this on-box\n# line is runtime-inert for the web app and stands as the record of the baked\n# origin. Keep it equal to the public origin (ADR-0014 §2 same-origin).\nNEXT_PUBLIC_API_URL=https://app.fleetco.example\n\n# === Admin seed (one-off `db:seed`, ADR-0014 §9 / ADR-0021) =================\n# Read only by the one-time seed task to create the first admin user.\n# [T2]\nADMIN_EMAIL=admin@fleetco.example\n# [T1]\nADMIN_PASSWORD=REPLACE_WITH_THE_FIRST_ADMIN_PASSWORD\n# CREATE_USER_PASSWORD (the office-staff/admin creation path, ADR-0028) is passed\n# INLINE on the create-user command at run time, never stored here.\n\n# === AI chat agent (DeepSeek — ADR-0043) ====================================\n# [T1] when set. The agent's hosted-LLM API key. LEAVE EMPTY TO KEEP THE AGENT\n# OFF THE NETWORK: unset means the API binds the no-network MockLlmClient — the\n# production kill switch (ADR-0043 c2). Set only after the ADR-0042 deploy\n# reaches daily use AND the DeepSeek training opt-out has been requested for\n# the account (ADR-0043 c6).\nDEEPSEEK_API_KEY=\n# [T4] Optional (api default: deepseek-v4-flash). The model name the agent\n# requests; the legacy deepseek-chat / deepseek-reasoner names deprecate\n# 2026-07-24.\nDEEPSEEK_MODEL=deepseek-v4-flash\n\n# === WhatsApp agent channel (Twilio — ADR-0046) ==============================\n# ALL optional and EMPTY at the first deploy: while the TWILIO_* group is unset\n# the api binds MockWhatsAppSender and the inbound webhook fails closed (503) —\n# the channel is OFF (the DEEPSEEK_API_KEY kill-switch idiom). Activation is a\n# deliberate post-deploy step owned by docs/runbook/whatsapp-operations.md\n# (register the sender, set these five, recreate the api container, provision\n# the phone link) — set nothing here on the first pass.\n# [T1] Account SID + auth token. The token both verifies inbound\n# X-Twilio-Signature headers AND Basic-auths outbound sends — never logged,\n# never committed.\nTWILIO_ACCOUNT_SID=\nTWILIO_AUTH_TOKEN=\n# [T4] The WhatsApp-enabled sender, in Twilio's whatsapp:+<E164> form.\nTWILIO_WHATSAPP_FROM=\n# [T4] The EXACT public webhook URL registered with Twilio — signature\n# verification pins this constant byte-for-byte (scheme, host, path):\n# https://<PUBLIC_DOMAIN>/api/v1/whatsapp/inbound\nTWILIO_WEBHOOK_URL=\n# [T4] The admin web's public base URL for reply deep-links —\n# https://<PUBLIC_DOMAIN> on the single-origin deploy (ADR-0014 §2).\nWEB_PUBLIC_URL=\n\n# === Reminder delivery (Resend — ADR-0038) ==================================\n# The compliance/maintenance reminder digest (daily 01:00 UTC scan) delivers\n# ONLY when this group is set; while empty the api binds the no-network\n# MockMailer and nothing sends (the DEEPSEEK_API_KEY kill-switch idiom).\n# Activation is operator-led: verify a sending domain in Resend (SPF/DKIM/\n# DMARC — ADR-0038 c9), then set both and recreate the api container.\n# [T1] The Resend API key — never logged, never committed.\nRESEND_API_KEY=\n# [T4] The sending address on the VERIFIED domain, e.g.\n# \"FleetCo <reminders@yourdomain.com.np>\". Unset falls back to a reserved\n# `.example` placeholder that can never deliver — set it with the key.\nRESEND_FROM=\n# [T2] Optional comma-separated extra recipients added to the ADMIN users'\n# emails (a shared inbox, the accountant). Addresses are PII — never logged.\nNOTIFICATION_RECIPIENTS=\n\n# === Object storage (Cloudflare R2 — ADR-0039 c7 / ADR-0044 V2) =============\n# Required for invoice ISSUE (the PDF is stored at issue time) and for agent\n# photo attachments + fleet documents (ADR-0049); while ANY is empty the api\n# binds an in-memory mock store and invoice issue() refuses with a clear 422 —\n# so the api never reaches R2 until the operator configures it.\n#\n# SHARED BUCKET (ADR-0014 §6): this is the SAME R2 bucket the nightly backup\n# uses (deploy/backup.env's R2_BUCKET) — one bucket for the whole project. The\n# app writes under the `invoices/`, `documents/`, and `agent-attachments/`\n# key PREFIXES; the backups sit at the bucket ROOT as `fleetco-<date>.sql.gz.age`.\n# The backup's 30-day prune is filename-scoped (`--include /fleetco-*.sql.gz.age`)\n# so it NEVER deletes an app object — see deploy/backup.sh. If you instead want a\n# separate bucket, point this at that bucket and give it its own scoped token.\n# From the Cloudflare dashboard: an R2 API token scoped to this bucket.\n# [T4] The S3 API endpoint, https://<accountid>.r2.cloudflarestorage.com\nR2_ENDPOINT=\n# [T1] The R2 API token pair — never logged, never committed. May be the SAME\n# token the backup rclone remote uses, or a distinct app-scoped token (a\n# distinct token limits blast radius: the app key then cannot read/delete the\n# encrypted backups, your disaster-recovery lifeline).\nR2_ACCESS_KEY_ID=\nR2_SECRET_ACCESS_KEY=\n# [T4] The bucket name — the SAME value as the backup's R2_BUCKET when sharing.\nR2_BUCKET=\n\n# === Invoice supplier identity (ADR-0039 c9) ================================\n# Required before issuing a REAL invoice (issue() refuses 422 while the PAN is\n# empty). Operator/accountant-verified values only — never fabricated.\n# [T3] FleetCo's OWN supplier PAN/VAT number printed on every tax invoice.\nINVOICE_SUPPLIER_PAN=\n# [T4] The registered business name for the invoice header (api default:\n# \"FleetCo\").\nINVOICE_SUPPLIER_NAME=\n\n# === Observability (optional — ADR-0024) ====================================\n# [T1] when set (ADR-0014 §4). Leave empty to disable.\nSENTRY_DSN=\n# [T4] Leave empty to disable.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# --- Agent document extraction (ADR-0044 Box B: self-hosted OCR sidecar) ----\n# LEAVE EMPTY AT THE FIRST DEPLOY. Set only when the OCR sidecar container is\n# up on the box (its own compose service + runbook step, ticket V6+; the\n# sidecar needs ~5 GB resident — the VPS sizing note in ADR-0044 Box B).\n# Unsetting this is the image-extraction kill switch (the DEEPSEEK_API_KEY\n# pattern): chat keeps working, attachments degrade to an honest notice.\nAGENT_OCR_URL=\n# Defaults to the ADR-0044-pinned model id; self-quantizing from the official\n# weights is the recorded production preference.\n#AGENT_OCR_MODEL=huggingface.co/sahilchachra/unlimited-ocr-gguf:Q4_K_M\n"}, "ec12fce376de62635a0cff58fb1967ee932c4730": {"t": 1785770423.882125, "n": 9869, "h": "9506bf988ae143b1", "c": "# FleetCo production environment — TEMPLATE (ADR-0014 §4, ADR-0013 data tiers).\n#\n# Copy to a root-owned, chmod 600, gitignored `.env` on the VPS (at\n# /opt/fleetco/.env) and replace every placeholder. This file is committed and\n# MUST contain only placeholders — NEVER a real secret (CLAUDE.md, ADR-0013).\n#\n# docker-compose.prod.yml reads this file two ways:\n# - `env_file: .env` injects it into the api + web containers (runtime config).\n# - Compose interpolates ${IMAGE_TAG}, ${POSTGRES_*}, and ${PUBLIC_DOMAIN}\n# from it into the compose file itself (image tags, postgres init, Caddy).\n#\n# Data-tier legend (ADR-0013), shown per-variable on the comment line above it:\n# [T1] secret — never committed, never logged (the box's disk encryption + OS\n# access control is the trust boundary, ADR-0014 §4).\n# [T2] PII. [T4] non-sensitive config.\n# Tags ride the comment lines (not the value lines) so no annotation can ever\n# be parsed into a value.\n\n# === Image tag (Compose interpolation) ======================================\n# [T4] The GHCR tag to deploy. CI pushes images tagged by commit SHA (T3); set\n# this to that SHA on every deploy (`export IMAGE_TAG=<sha>`). `latest` is only\n# a placeholder so `docker compose config` resolves.\nIMAGE_TAG=latest\n\n# === Public origin ==========================================================\n# [T4] The single public hostname (no scheme). Caddy terminates TLS for it and\n# reads it via {$PUBLIC_DOMAIN}; BETTER_AUTH_URL / CORS_ORIGIN /\n# NEXT_PUBLIC_API_URL below are all https://<this> (ADR-0014 §2 same-origin).\nPUBLIC_DOMAIN=app.fleetco.example\n\n# === Runtime mode ===========================================================\n# [T4]\nNODE_ENV=production\n# [T4] Optional (api default: info). One of: fatal error warn info debug trace.\nLOG_LEVEL=info\n# Do NOT set PORT or HOSTNAME — the api (3001) and web (3000) ports are baked\n# into the images, the Caddyfile, and the compose healthchecks.\n\n# === PostgreSQL ==============================================================\n# The postgres container's first-run init credentials. These three MUST agree\n# with the user:password/database embedded in DATABASE_URL below.\n# [T4]\nPOSTGRES_USER=fleetco\n# [T1]\nPOSTGRES_PASSWORD=REPLACE_WITH_A_STRONG_DB_PASSWORD\n# [T4]\nPOSTGRES_DB=fleetco\n\n# === API datastores =========================================================\n# [T1] Carries the DB password (must equal POSTGRES_PASSWORD above). Host is the\n# compose service name `postgres`.\nDATABASE_URL=postgresql://fleetco:REPLACE_WITH_A_STRONG_DB_PASSWORD@postgres:5432/fleetco?schema=public\n# [T4] Host is the compose service name `redis` (no auth at this scale, ADR-0014 §1).\nREDIS_URL=redis://redis:6379\n\n# === Auth (better-auth — ADR-0015, ADR-0021) ================================\n# [T1] Session-signing secret, >=32 bytes. Generate with: openssl rand -hex 32\nBETTER_AUTH_SECRET=REPLACE_WITH_openssl_rand_hex_32_minimum_32_bytes\n\n# === GPS tracker gateway (Traccar — ADR-0042 M5/M6) =========================\n# [T1] Machine-ingest key for the Traccar → API position-forward hop, >=32\n# chars. Generate with: openssl rand -hex 32. The SAME value is injected into\n# the traccar container's forward header (M6 compose config); the ingest route\n# answers 503 while this is unset (fails closed). Before the first forward,\n# seed the credential-less gateway system user once:\n# pnpm --filter @fleetco/api exec tsx scripts/seed-gateway-user.ts\nINGEST_API_KEY=REPLACE_WITH_openssl_rand_hex_32_minimum_32_chars\n# [T1] Password for the dedicated low-privilege `traccar` Postgres role that\n# owns the separate `traccar` database in the shared postgres container\n# (ADR-0042 c3; distinct from POSTGRES_PASSWORD on purpose — the third-party\n# gateway never holds the app DB's superuser credential). Generate with:\n# openssl rand -hex 32. Compose injects it into the traccar container as\n# DATABASE_PASSWORD; the role + database are created once via the idempotent\n# snippet in docs/runbook/traccar.md (which reads this same variable).\nTRACCAR_DB_PASSWORD=REPLACE_WITH_A_STRONG_TRACCAR_DB_PASSWORD\n# [T4] The public API base URL = https://<PUBLIC_DOMAIN> (ADR-0014 §2).\nBETTER_AUTH_URL=https://app.fleetco.example\n# [T4] Same-origin allowlist = the single public origin (ADR-0014 §2).\nCORS_ORIGIN=https://app.fleetco.example\n\n# === Web admin ==============================================================\n# [T4] BAKED into the web image at build time (T3 --build-arg; deploy.md step\n# 0) — into the SERVER bundle as well as the browser bundle, so this on-box\n# line is runtime-inert for the web app and stands as the record of the baked\n# origin. Keep it equal to the public origin (ADR-0014 §2 same-origin).\nNEXT_PUBLIC_API_URL=https://app.fleetco.example\n\n# === Admin seed (one-off `db:seed`, ADR-0014 §9 / ADR-0021) =================\n# Read only by the one-time seed task to create the first admin user.\n# [T2]\nADMIN_EMAIL=admin@fleetco.example\n# [T1]\nADMIN_PASSWORD=REPLACE_WITH_THE_FIRST_ADMIN_PASSWORD\n# CREATE_USER_PASSWORD (the office-staff/admin creation path, ADR-0028) is passed\n# INLINE on the create-user command at run time, never stored here.\n\n# === AI chat agent (DeepSeek — ADR-0043) ====================================\n# [T1] when set. The agent's hosted-LLM API key. LEAVE EMPTY TO KEEP THE AGENT\n# OFF THE NETWORK: unset means the API binds the no-network MockLlmClient — the\n# production kill switch (ADR-0043 c2). Set only after the ADR-0042 deploy\n# reaches daily use AND the DeepSeek training opt-out has been requested for\n# the account (ADR-0043 c6).\nDEEPSEEK_API_KEY=\n# [T4] Optional (api default: deepseek-v4-flash). The model name the agent\n# requests; the legacy deepseek-chat / deepseek-reasoner names deprecate\n# 2026-07-24.\nDEEPSEEK_MODEL=deepseek-v4-flash\n\n# === WhatsApp agent channel (Twilio — ADR-0046) ==============================\n# ALL optional and EMPTY at the first deploy: while the TWILIO_* group is unset\n# the api binds MockWhatsAppSender and the inbound webhook fails closed (503) —\n# the channel is OFF (the DEEPSEEK_API_KEY kill-switch idiom). Activation is a\n# deliberate post-deploy step owned by docs/runbook/whatsapp-operations.md\n# (register the sender, set these five, recreate the api container, provision\n# the phone link) — set nothing here on the first pass.\n# [T1] Account SID + auth token. The token both verifies inbound\n# X-Twilio-Signature headers AND Basic-auths outbound sends — never logged,\n# never committed.\nTWILIO_ACCOUNT_SID=\nTWILIO_AUTH_TOKEN=\n# [T4] The WhatsApp-enabled sender, in Twilio's whatsapp:+<E164> form.\nTWILIO_WHATSAPP_FROM=\n# [T4] The EXACT public webhook URL registered with Twilio — signature\n# verification pins this constant byte-for-byte (scheme, host, path):\n# https://<PUBLIC_DOMAIN>/api/v1/whatsapp/inbound\nTWILIO_WEBHOOK_URL=\n# [T4] The admin web's public base URL for reply deep-links —\n# https://<PUBLIC_DOMAIN> on the single-origin deploy (ADR-0014 §2).\nWEB_PUBLIC_URL=\n\n# === Reminder delivery (Resend — ADR-0038) ==================================\n# The compliance/maintenance reminder digest (daily 01:00 UTC scan) delivers\n# ONLY when this group is set; while empty the api binds the no-network\n# MockMailer and nothing sends (the DEEPSEEK_API_KEY kill-switch idiom).\n# Activation is operator-led: verify a sending domain in Resend (SPF/DKIM/\n# DMARC — ADR-0038 c9), then set both and recreate the api container.\n# [T1] The Resend API key — never logged, never committed.\nRESEND_API_KEY=\n# [T4] The sending address on the VERIFIED domain, e.g.\n# \"FleetCo <reminders@yourdomain.com.np>\". Unset falls back to a reserved\n# `.example` placeholder that can never deliver — set it with the key.\nRESEND_FROM=\n# [T2] Optional comma-separated extra recipients added to the ADMIN users'\n# emails (a shared inbox, the accountant). Addresses are PII — never logged.\nNOTIFICATION_RECIPIENTS=\n\n# === Object storage (Cloudflare R2 — ADR-0039 c7 / ADR-0044 V2) =============\n# Required for invoice ISSUE (the PDF is stored at issue time) and for agent\n# photo attachments; while ANY is empty the api binds an in-memory mock store\n# and invoice issue() refuses with a clear 422 — so the api never reaches R2\n# until the operator configures it. From the Cloudflare dashboard: create a\n# bucket + an R2 API token scoped to it.\n# [T4] The S3 API endpoint, https://<accountid>.r2.cloudflarestorage.com\nR2_ENDPOINT=\n# [T1] The R2 API token pair — never logged, never committed.\nR2_ACCESS_KEY_ID=\nR2_SECRET_ACCESS_KEY=\n# [T4] The bucket name, e.g. fleetco-production.\nR2_BUCKET=\n\n# === Invoice supplier identity (ADR-0039 c9) ================================\n# Required before issuing a REAL invoice (issue() refuses 422 while the PAN is\n# empty). Operator/accountant-verified values only — never fabricated.\n# [T3] FleetCo's OWN supplier PAN/VAT number printed on every tax invoice.\nINVOICE_SUPPLIER_PAN=\n# [T4] The registered business name for the invoice header (api default:\n# \"FleetCo\").\nINVOICE_SUPPLIER_NAME=\n\n# === Observability (optional — ADR-0024) ====================================\n# [T1] when set (ADR-0014 §4). Leave empty to disable.\nSENTRY_DSN=\n# [T4] Leave empty to disable.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# --- Agent document extraction (ADR-0044 Box B: self-hosted OCR sidecar) ----\n# LEAVE EMPTY AT THE FIRST DEPLOY. Set only when the OCR sidecar container is\n# up on the box (its own compose service + runbook step, ticket V6+; the\n# sidecar needs ~5 GB resident — the VPS sizing note in ADR-0044 Box B).\n# Unsetting this is the image-extraction kill switch (the DEEPSEEK_API_KEY\n# pattern): chat keeps working, attachments degrade to an honest notice.\nAGENT_OCR_URL=\n# Defaults to the ADR-0044-pinned model id; self-quantizing from the official\n# weights is the recorded production preference.\n#AGENT_OCR_MODEL=huggingface.co/sahilchachra/unlimited-ocr-gguf:Q4_K_M\n"}, "93f9d7554247ed545fac4fd7bedb2bbb03f2af79": {"t": 1785770425.2741263, "n": 7842, "h": "443803e07285af9c", "c": "# FleetCo production environment — TEMPLATE (ADR-0014 §4, ADR-0013 data tiers).\n#\n# Copy to a root-owned, chmod 600, gitignored `.env` on the VPS (at\n# /opt/fleetco/.env) and replace every placeholder. This file is committed and\n# MUST contain only placeholders — NEVER a real secret (CLAUDE.md, ADR-0013).\n#\n# docker-compose.prod.yml reads this file two ways:\n# - `env_file: .env` injects it into the api + web containers (runtime config).\n# - Compose interpolates ${IMAGE_TAG}, ${POSTGRES_*}, and ${PUBLIC_DOMAIN}\n# from it into the compose file itself (image tags, postgres init, Caddy).\n#\n# Data-tier legend (ADR-0013), shown per-variable on the comment line above it:\n# [T1] secret — never committed, never logged (the box's disk encryption + OS\n# access control is the trust boundary, ADR-0014 §4).\n# [T2] PII. [T4] non-sensitive config.\n# Tags ride the comment lines (not the value lines) so no annotation can ever\n# be parsed into a value.\n\n# === Image tag (Compose interpolation) ======================================\n# [T4] The GHCR tag to deploy. CI pushes images tagged by commit SHA (T3); set\n# this to that SHA on every deploy (`export IMAGE_TAG=<sha>`). `latest` is only\n# a placeholder so `docker compose config` resolves.\nIMAGE_TAG=latest\n\n# === Public origin ==========================================================\n# [T4] The single public hostname (no scheme). Caddy terminates TLS for it and\n# reads it via {$PUBLIC_DOMAIN}; BETTER_AUTH_URL / CORS_ORIGIN /\n# NEXT_PUBLIC_API_URL below are all https://<this> (ADR-0014 §2 same-origin).\nPUBLIC_DOMAIN=app.fleetco.example\n\n# === Runtime mode ===========================================================\n# [T4]\nNODE_ENV=production\n# [T4] Optional (api default: info). One of: fatal error warn info debug trace.\nLOG_LEVEL=info\n# Do NOT set PORT or HOSTNAME — the api (3001) and web (3000) ports are baked\n# into the images, the Caddyfile, and the compose healthchecks.\n\n# === PostgreSQL ==============================================================\n# The postgres container's first-run init credentials. These three MUST agree\n# with the user:password/database embedded in DATABASE_URL below.\n# [T4]\nPOSTGRES_USER=fleetco\n# [T1]\nPOSTGRES_PASSWORD=REPLACE_WITH_A_STRONG_DB_PASSWORD\n# [T4]\nPOSTGRES_DB=fleetco\n\n# === API datastores =========================================================\n# [T1] Carries the DB password (must equal POSTGRES_PASSWORD above). Host is the\n# compose service name `postgres`.\nDATABASE_URL=postgresql://fleetco:REPLACE_WITH_A_STRONG_DB_PASSWORD@postgres:5432/fleetco?schema=public\n# [T4] Host is the compose service name `redis` (no auth at this scale, ADR-0014 §1).\nREDIS_URL=redis://redis:6379\n\n# === Auth (better-auth — ADR-0015, ADR-0021) ================================\n# [T1] Session-signing secret, >=32 bytes. Generate with: openssl rand -hex 32\nBETTER_AUTH_SECRET=REPLACE_WITH_openssl_rand_hex_32_minimum_32_bytes\n\n# === GPS tracker gateway (Traccar — ADR-0042 M5/M6) =========================\n# [T1] Machine-ingest key for the Traccar → API position-forward hop, >=32\n# chars. Generate with: openssl rand -hex 32. The SAME value is injected into\n# the traccar container's forward header (M6 compose config); the ingest route\n# answers 503 while this is unset (fails closed). Before the first forward,\n# seed the credential-less gateway system user once:\n# pnpm --filter @fleetco/api exec tsx scripts/seed-gateway-user.ts\nINGEST_API_KEY=REPLACE_WITH_openssl_rand_hex_32_minimum_32_chars\n# [T1] Password for the dedicated low-privilege `traccar` Postgres role that\n# owns the separate `traccar` database in the shared postgres container\n# (ADR-0042 c3; distinct from POSTGRES_PASSWORD on purpose — the third-party\n# gateway never holds the app DB's superuser credential). Generate with:\n# openssl rand -hex 32. Compose injects it into the traccar container as\n# DATABASE_PASSWORD; the role + database are created once via the idempotent\n# snippet in docs/runbook/traccar.md (which reads this same variable).\nTRACCAR_DB_PASSWORD=REPLACE_WITH_A_STRONG_TRACCAR_DB_PASSWORD\n# [T4] The public API base URL = https://<PUBLIC_DOMAIN> (ADR-0014 §2).\nBETTER_AUTH_URL=https://app.fleetco.example\n# [T4] Same-origin allowlist = the single public origin (ADR-0014 §2).\nCORS_ORIGIN=https://app.fleetco.example\n\n# === Web admin ==============================================================\n# [T4] BAKED into the web image at build time (T3 --build-arg; deploy.md step\n# 0) — into the SERVER bundle as well as the browser bundle, so this on-box\n# line is runtime-inert for the web app and stands as the record of the baked\n# origin. Keep it equal to the public origin (ADR-0014 §2 same-origin).\nNEXT_PUBLIC_API_URL=https://app.fleetco.example\n\n# === Admin seed (one-off `db:seed`, ADR-0014 §9 / ADR-0021) =================\n# Read only by the one-time seed task to create the first admin user.\n# [T2]\nADMIN_EMAIL=admin@fleetco.example\n# [T1]\nADMIN_PASSWORD=REPLACE_WITH_THE_FIRST_ADMIN_PASSWORD\n# CREATE_USER_PASSWORD (the office-staff/admin creation path, ADR-0028) is passed\n# INLINE on the create-user command at run time, never stored here.\n\n# === AI chat agent (DeepSeek — ADR-0043) ====================================\n# [T1] when set. The agent's hosted-LLM API key. LEAVE EMPTY TO KEEP THE AGENT\n# OFF THE NETWORK: unset means the API binds the no-network MockLlmClient — the\n# production kill switch (ADR-0043 c2). Set only after the ADR-0042 deploy\n# reaches daily use AND the DeepSeek training opt-out has been requested for\n# the account (ADR-0043 c6).\nDEEPSEEK_API_KEY=\n# [T4] Optional (api default: deepseek-v4-flash). The model name the agent\n# requests; the legacy deepseek-chat / deepseek-reasoner names deprecate\n# 2026-07-24.\nDEEPSEEK_MODEL=deepseek-v4-flash\n\n# === WhatsApp agent channel (Twilio — ADR-0046) ==============================\n# ALL optional and EMPTY at the first deploy: while the TWILIO_* group is unset\n# the api binds MockWhatsAppSender and the inbound webhook fails closed (503) —\n# the channel is OFF (the DEEPSEEK_API_KEY kill-switch idiom). Activation is a\n# deliberate post-deploy step owned by docs/runbook/whatsapp-operations.md\n# (register the sender, set these five, recreate the api container, provision\n# the phone link) — set nothing here on the first pass.\n# [T1] Account SID + auth token. The token both verifies inbound\n# X-Twilio-Signature headers AND Basic-auths outbound sends — never logged,\n# never committed.\nTWILIO_ACCOUNT_SID=\nTWILIO_AUTH_TOKEN=\n# [T4] The WhatsApp-enabled sender, in Twilio's whatsapp:+<E164> form.\nTWILIO_WHATSAPP_FROM=\n# [T4] The EXACT public webhook URL registered with Twilio — signature\n# verification pins this constant byte-for-byte (scheme, host, path):\n# https://<PUBLIC_DOMAIN>/api/v1/whatsapp/inbound\nTWILIO_WEBHOOK_URL=\n# [T4] The admin web's public base URL for reply deep-links —\n# https://<PUBLIC_DOMAIN> on the single-origin deploy (ADR-0014 §2).\nWEB_PUBLIC_URL=\n\n# === Observability (optional — ADR-0024) ====================================\n# [T1] when set (ADR-0014 §4). Leave empty to disable.\nSENTRY_DSN=\n# [T4] Leave empty to disable.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# --- Agent document extraction (ADR-0044 Box B: self-hosted OCR sidecar) ----\n# LEAVE EMPTY AT THE FIRST DEPLOY. Set only when the OCR sidecar container is\n# up on the box (its own compose service + runbook step, ticket V6+; the\n# sidecar needs ~5 GB resident — the VPS sizing note in ADR-0044 Box B).\n# Unsetting this is the image-extraction kill switch (the DEEPSEEK_API_KEY\n# pattern): chat keeps working, attachments degrade to an honest notice.\nAGENT_OCR_URL=\n# Defaults to the ADR-0044-pinned model id; self-quantizing from the official\n# weights is the recorded production preference.\n#AGENT_OCR_MODEL=huggingface.co/sahilchachra/unlimited-ocr-gguf:Q4_K_M\n"}, "9f38c7d46c3c3676ed01a0dabb4fa8b9632d5c51": {"t": 1785770426.8431835, "n": 6663, "h": "7d9ce5919961dc2d", "c": "# FleetCo production environment — TEMPLATE (ADR-0014 §4, ADR-0013 data tiers).\n#\n# Copy to a root-owned, chmod 600, gitignored `.env` on the VPS (at\n# /opt/fleetco/.env) and replace every placeholder. This file is committed and\n# MUST contain only placeholders — NEVER a real secret (CLAUDE.md, ADR-0013).\n#\n# docker-compose.prod.yml reads this file two ways:\n# - `env_file: .env` injects it into the api + web containers (runtime config).\n# - Compose interpolates ${IMAGE_TAG}, ${POSTGRES_*}, and ${PUBLIC_DOMAIN}\n# from it into the compose file itself (image tags, postgres init, Caddy).\n#\n# Data-tier legend (ADR-0013), shown per-variable on the comment line above it:\n# [T1] secret — never committed, never logged (the box's disk encryption + OS\n# access control is the trust boundary, ADR-0014 §4).\n# [T2] PII. [T4] non-sensitive config.\n# Tags ride the comment lines (not the value lines) so no annotation can ever\n# be parsed into a value.\n\n# === Image tag (Compose interpolation) ======================================\n# [T4] The GHCR tag to deploy. CI pushes images tagged by commit SHA (T3); set\n# this to that SHA on every deploy (`export IMAGE_TAG=<sha>`). `latest` is only\n# a placeholder so `docker compose config` resolves.\nIMAGE_TAG=latest\n\n# === Public origin ==========================================================\n# [T4] The single public hostname (no scheme). Caddy terminates TLS for it and\n# reads it via {$PUBLIC_DOMAIN}; BETTER_AUTH_URL / CORS_ORIGIN /\n# NEXT_PUBLIC_API_URL below are all https://<this> (ADR-0014 §2 same-origin).\nPUBLIC_DOMAIN=app.fleetco.example\n\n# === Runtime mode ===========================================================\n# [T4]\nNODE_ENV=production\n# [T4] Optional (api default: info). One of: fatal error warn info debug trace.\nLOG_LEVEL=info\n# Do NOT set PORT or HOSTNAME — the api (3001) and web (3000) ports are baked\n# into the images, the Caddyfile, and the compose healthchecks.\n\n# === PostgreSQL ==============================================================\n# The postgres container's first-run init credentials. These three MUST agree\n# with the user:password/database embedded in DATABASE_URL below.\n# [T4]\nPOSTGRES_USER=fleetco\n# [T1]\nPOSTGRES_PASSWORD=REPLACE_WITH_A_STRONG_DB_PASSWORD\n# [T4]\nPOSTGRES_DB=fleetco\n\n# === API datastores =========================================================\n# [T1] Carries the DB password (must equal POSTGRES_PASSWORD above). Host is the\n# compose service name `postgres`.\nDATABASE_URL=postgresql://fleetco:REPLACE_WITH_A_STRONG_DB_PASSWORD@postgres:5432/fleetco?schema=public\n# [T4] Host is the compose service name `redis` (no auth at this scale, ADR-0014 §1).\nREDIS_URL=redis://redis:6379\n\n# === Auth (better-auth — ADR-0015, ADR-0021) ================================\n# [T1] Session-signing secret, >=32 bytes. Generate with: openssl rand -hex 32\nBETTER_AUTH_SECRET=REPLACE_WITH_openssl_rand_hex_32_minimum_32_bytes\n\n# === GPS tracker gateway (Traccar — ADR-0042 M5/M6) =========================\n# [T1] Machine-ingest key for the Traccar → API position-forward hop, >=32\n# chars. Generate with: openssl rand -hex 32. The SAME value is injected into\n# the traccar container's forward header (M6 compose config); the ingest route\n# answers 503 while this is unset (fails closed). Before the first forward,\n# seed the credential-less gateway system user once:\n# pnpm --filter @fleetco/api exec tsx scripts/seed-gateway-user.ts\nINGEST_API_KEY=REPLACE_WITH_openssl_rand_hex_32_minimum_32_chars\n# [T1] Password for the dedicated low-privilege `traccar` Postgres role that\n# owns the separate `traccar` database in the shared postgres container\n# (ADR-0042 c3; distinct from POSTGRES_PASSWORD on purpose — the third-party\n# gateway never holds the app DB's superuser credential). Generate with:\n# openssl rand -hex 32. Compose injects it into the traccar container as\n# DATABASE_PASSWORD; the role + database are created once via the idempotent\n# snippet in docs/runbook/traccar.md (which reads this same variable).\nTRACCAR_DB_PASSWORD=REPLACE_WITH_A_STRONG_TRACCAR_DB_PASSWORD\n# [T4] The public API base URL = https://<PUBLIC_DOMAIN> (ADR-0014 §2).\nBETTER_AUTH_URL=https://app.fleetco.example\n# [T4] Same-origin allowlist = the single public origin (ADR-0014 §2).\nCORS_ORIGIN=https://app.fleetco.example\n\n# === Web admin ==============================================================\n# [T4] BAKED into the web image at build time (T3 --build-arg; deploy.md step\n# 0) — into the SERVER bundle as well as the browser bundle, so this on-box\n# line is runtime-inert for the web app and stands as the record of the baked\n# origin. Keep it equal to the public origin (ADR-0014 §2 same-origin).\nNEXT_PUBLIC_API_URL=https://app.fleetco.example\n\n# === Admin seed (one-off `db:seed`, ADR-0014 §9 / ADR-0021) =================\n# Read only by the one-time seed task to create the first admin user.\n# [T2]\nADMIN_EMAIL=admin@fleetco.example\n# [T1]\nADMIN_PASSWORD=REPLACE_WITH_THE_FIRST_ADMIN_PASSWORD\n# CREATE_USER_PASSWORD (the office-staff/admin creation path, ADR-0028) is passed\n# INLINE on the create-user command at run time, never stored here.\n\n# === AI chat agent (DeepSeek — ADR-0043) ====================================\n# [T1] when set. The agent's hosted-LLM API key. LEAVE EMPTY TO KEEP THE AGENT\n# OFF THE NETWORK: unset means the API binds the no-network MockLlmClient — the\n# production kill switch (ADR-0043 c2). Set only after the ADR-0042 deploy\n# reaches daily use AND the DeepSeek training opt-out has been requested for\n# the account (ADR-0043 c6).\nDEEPSEEK_API_KEY=\n# [T4] Optional (api default: deepseek-v4-flash). The model name the agent\n# requests; the legacy deepseek-chat / deepseek-reasoner names deprecate\n# 2026-07-24.\nDEEPSEEK_MODEL=deepseek-v4-flash\n\n# === Observability (optional — ADR-0024) ====================================\n# [T1] when set (ADR-0014 §4). Leave empty to disable.\nSENTRY_DSN=\n# [T4] Leave empty to disable.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# --- Agent document extraction (ADR-0044 Box B: self-hosted OCR sidecar) ----\n# LEAVE EMPTY AT THE FIRST DEPLOY. Set only when the OCR sidecar container is\n# up on the box (its own compose service + runbook step, ticket V6+; the\n# sidecar needs ~5 GB resident — the VPS sizing note in ADR-0044 Box B).\n# Unsetting this is the image-extraction kill switch (the DEEPSEEK_API_KEY\n# pattern): chat keeps working, attachments degrade to an honest notice.\nAGENT_OCR_URL=\n# Defaults to the ADR-0044-pinned model id; self-quantizing from the official\n# weights is the recorded production preference.\n#AGENT_OCR_MODEL=huggingface.co/sahilchachra/unlimited-ocr-gguf:Q4_K_M\n"}, "8ce8455fd542dc7346b6ff5a7b1dd170ffb5dfa1": {"t": 1785770428.379977, "n": 6551, "h": "619451ae243877cb", "c": "# FleetCo production environment — TEMPLATE (ADR-0014 §4, ADR-0013 data tiers).\n#\n# Copy to a root-owned, chmod 600, gitignored `.env` on the VPS (at\n# /opt/fleetco/.env) and replace every placeholder. This file is committed and\n# MUST contain only placeholders — NEVER a real secret (CLAUDE.md, ADR-0013).\n#\n# docker-compose.prod.yml reads this file two ways:\n# - `env_file: .env` injects it into the api + web containers (runtime config).\n# - Compose interpolates ${IMAGE_TAG}, ${POSTGRES_*}, and ${PUBLIC_DOMAIN}\n# from it into the compose file itself (image tags, postgres init, Caddy).\n#\n# Data-tier legend (ADR-0013), shown per-variable on the comment line above it:\n# [T1] secret — never committed, never logged (the box's disk encryption + OS\n# access control is the trust boundary, ADR-0014 §4).\n# [T2] PII. [T4] non-sensitive config.\n# Tags ride the comment lines (not the value lines) so no annotation can ever\n# be parsed into a value.\n\n# === Image tag (Compose interpolation) ======================================\n# [T4] The GHCR tag to deploy. CI pushes images tagged by commit SHA (T3); set\n# this to that SHA on every deploy (`export IMAGE_TAG=<sha>`). `latest` is only\n# a placeholder so `docker compose config` resolves.\nIMAGE_TAG=latest\n\n# === Public origin ==========================================================\n# [T4] The single public hostname (no scheme). Caddy terminates TLS for it and\n# reads it via {$PUBLIC_DOMAIN}; BETTER_AUTH_URL / CORS_ORIGIN /\n# NEXT_PUBLIC_API_URL below are all https://<this> (ADR-0014 §2 same-origin).\nPUBLIC_DOMAIN=app.fleetco.example\n\n# === Runtime mode ===========================================================\n# [T4]\nNODE_ENV=production\n# [T4] Optional (api default: info). One of: fatal error warn info debug trace.\nLOG_LEVEL=info\n# Do NOT set PORT or HOSTNAME — the api (3001) and web (3000) ports are baked\n# into the images, the Caddyfile, and the compose healthchecks.\n\n# === PostgreSQL ==============================================================\n# The postgres container's first-run init credentials. These three MUST agree\n# with the user:password/database embedded in DATABASE_URL below.\n# [T4]\nPOSTGRES_USER=fleetco\n# [T1]\nPOSTGRES_PASSWORD=REPLACE_WITH_A_STRONG_DB_PASSWORD\n# [T4]\nPOSTGRES_DB=fleetco\n\n# === API datastores =========================================================\n# [T1] Carries the DB password (must equal POSTGRES_PASSWORD above). Host is the\n# compose service name `postgres`.\nDATABASE_URL=postgresql://fleetco:REPLACE_WITH_A_STRONG_DB_PASSWORD@postgres:5432/fleetco?schema=public\n# [T4] Host is the compose service name `redis` (no auth at this scale, ADR-0014 §1).\nREDIS_URL=redis://redis:6379\n\n# === Auth (better-auth — ADR-0015, ADR-0021) ================================\n# [T1] Session-signing secret, >=32 bytes. Generate with: openssl rand -hex 32\nBETTER_AUTH_SECRET=REPLACE_WITH_openssl_rand_hex_32_minimum_32_bytes\n\n# === GPS tracker gateway (Traccar — ADR-0042 M5/M6) =========================\n# [T1] Machine-ingest key for the Traccar → API position-forward hop, >=32\n# chars. Generate with: openssl rand -hex 32. The SAME value is injected into\n# the traccar container's forward header (M6 compose config); the ingest route\n# answers 503 while this is unset (fails closed). Before the first forward,\n# seed the credential-less gateway system user once:\n# pnpm --filter @fleetco/api exec tsx scripts/seed-gateway-user.ts\nINGEST_API_KEY=REPLACE_WITH_openssl_rand_hex_32_minimum_32_chars\n# [T1] Password for the dedicated low-privilege `traccar` Postgres role that\n# owns the separate `traccar` database in the shared postgres container\n# (ADR-0042 c3; distinct from POSTGRES_PASSWORD on purpose — the third-party\n# gateway never holds the app DB's superuser credential). Generate with:\n# openssl rand -hex 32. Compose injects it into the traccar container as\n# DATABASE_PASSWORD; the role + database are created once via the idempotent\n# snippet in docs/runbook/traccar.md (which reads this same variable).\nTRACCAR_DB_PASSWORD=REPLACE_WITH_A_STRONG_TRACCAR_DB_PASSWORD\n# [T4] The public API base URL = https://<PUBLIC_DOMAIN> (ADR-0014 §2).\nBETTER_AUTH_URL=https://app.fleetco.example\n# [T4] Same-origin allowlist = the single public origin (ADR-0014 §2).\nCORS_ORIGIN=https://app.fleetco.example\n\n# === Web admin ==============================================================\n# [T4] Used by the web standalone server's runtime fetches AND baked into the\n# browser bundle at image build time (T3 --build-arg). Keep both = the public\n# origin (ADR-0014 §2 same-origin).\nNEXT_PUBLIC_API_URL=https://app.fleetco.example\n\n# === Admin seed (one-off `db:seed`, ADR-0014 §9 / ADR-0021) =================\n# Read only by the one-time seed task to create the first admin user.\n# [T2]\nADMIN_EMAIL=admin@fleetco.example\n# [T1]\nADMIN_PASSWORD=REPLACE_WITH_THE_FIRST_ADMIN_PASSWORD\n# CREATE_USER_PASSWORD (the office-staff/admin creation path, ADR-0028) is passed\n# INLINE on the create-user command at run time, never stored here.\n\n# === AI chat agent (DeepSeek — ADR-0043) ====================================\n# [T1] when set. The agent's hosted-LLM API key. LEAVE EMPTY TO KEEP THE AGENT\n# OFF THE NETWORK: unset means the API binds the no-network MockLlmClient — the\n# production kill switch (ADR-0043 c2). Set only after the ADR-0042 deploy\n# reaches daily use AND the DeepSeek training opt-out has been requested for\n# the account (ADR-0043 c6).\nDEEPSEEK_API_KEY=\n# [T4] Optional (api default: deepseek-v4-flash). The model name the agent\n# requests; the legacy deepseek-chat / deepseek-reasoner names deprecate\n# 2026-07-24.\nDEEPSEEK_MODEL=deepseek-v4-flash\n\n# === Observability (optional — ADR-0024) ====================================\n# [T1] when set (ADR-0014 §4). Leave empty to disable.\nSENTRY_DSN=\n# [T4] Leave empty to disable.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# --- Agent document extraction (ADR-0044 Box B: self-hosted OCR sidecar) ----\n# LEAVE EMPTY AT THE FIRST DEPLOY. Set only when the OCR sidecar container is\n# up on the box (its own compose service + runbook step, ticket V6+; the\n# sidecar needs ~5 GB resident — the VPS sizing note in ADR-0044 Box B).\n# Unsetting this is the image-extraction kill switch (the DEEPSEEK_API_KEY\n# pattern): chat keeps working, attachments degrade to an honest notice.\nAGENT_OCR_URL=\n# Defaults to the ADR-0044-pinned model id; self-quantizing from the official\n# weights is the recorded production preference.\n#AGENT_OCR_MODEL=huggingface.co/sahilchachra/unlimited-ocr-gguf:Q4_K_M\n"}, "e74f9d8ec30fe36f6c3d863162b746b610abd527": {"t": 1785770429.9719555, "n": 5886, "h": "178368e06c49cbc3", "c": "# FleetCo production environment — TEMPLATE (ADR-0014 §4, ADR-0013 data tiers).\n#\n# Copy to a root-owned, chmod 600, gitignored `.env` on the VPS (at\n# /opt/fleetco/.env) and replace every placeholder. This file is committed and\n# MUST contain only placeholders — NEVER a real secret (CLAUDE.md, ADR-0013).\n#\n# docker-compose.prod.yml reads this file two ways:\n# - `env_file: .env` injects it into the api + web containers (runtime config).\n# - Compose interpolates ${IMAGE_TAG}, ${POSTGRES_*}, and ${PUBLIC_DOMAIN}\n# from it into the compose file itself (image tags, postgres init, Caddy).\n#\n# Data-tier legend (ADR-0013), shown per-variable on the comment line above it:\n# [T1] secret — never committed, never logged (the box's disk encryption + OS\n# access control is the trust boundary, ADR-0014 §4).\n# [T2] PII. [T4] non-sensitive config.\n# Tags ride the comment lines (not the value lines) so no annotation can ever\n# be parsed into a value.\n\n# === Image tag (Compose interpolation) ======================================\n# [T4] The GHCR tag to deploy. CI pushes images tagged by commit SHA (T3); set\n# this to that SHA on every deploy (`export IMAGE_TAG=<sha>`). `latest` is only\n# a placeholder so `docker compose config` resolves.\nIMAGE_TAG=latest\n\n# === Public origin ==========================================================\n# [T4] The single public hostname (no scheme). Caddy terminates TLS for it and\n# reads it via {$PUBLIC_DOMAIN}; BETTER_AUTH_URL / CORS_ORIGIN /\n# NEXT_PUBLIC_API_URL below are all https://<this> (ADR-0014 §2 same-origin).\nPUBLIC_DOMAIN=app.fleetco.example\n\n# === Runtime mode ===========================================================\n# [T4]\nNODE_ENV=production\n# [T4] Optional (api default: info). One of: fatal error warn info debug trace.\nLOG_LEVEL=info\n# Do NOT set PORT or HOSTNAME — the api (3001) and web (3000) ports are baked\n# into the images, the Caddyfile, and the compose healthchecks.\n\n# === PostgreSQL ==============================================================\n# The postgres container's first-run init credentials. These three MUST agree\n# with the user:password/database embedded in DATABASE_URL below.\n# [T4]\nPOSTGRES_USER=fleetco\n# [T1]\nPOSTGRES_PASSWORD=REPLACE_WITH_A_STRONG_DB_PASSWORD\n# [T4]\nPOSTGRES_DB=fleetco\n\n# === API datastores =========================================================\n# [T1] Carries the DB password (must equal POSTGRES_PASSWORD above). Host is the\n# compose service name `postgres`.\nDATABASE_URL=postgresql://fleetco:REPLACE_WITH_A_STRONG_DB_PASSWORD@postgres:5432/fleetco?schema=public\n# [T4] Host is the compose service name `redis` (no auth at this scale, ADR-0014 §1).\nREDIS_URL=redis://redis:6379\n\n# === Auth (better-auth — ADR-0015, ADR-0021) ================================\n# [T1] Session-signing secret, >=32 bytes. Generate with: openssl rand -hex 32\nBETTER_AUTH_SECRET=REPLACE_WITH_openssl_rand_hex_32_minimum_32_bytes\n\n# === GPS tracker gateway (Traccar — ADR-0042 M5/M6) =========================\n# [T1] Machine-ingest key for the Traccar → API position-forward hop, >=32\n# chars. Generate with: openssl rand -hex 32. The SAME value is injected into\n# the traccar container's forward header (M6 compose config); the ingest route\n# answers 503 while this is unset (fails closed). Before the first forward,\n# seed the credential-less gateway system user once:\n# pnpm --filter @fleetco/api exec tsx scripts/seed-gateway-user.ts\nINGEST_API_KEY=REPLACE_WITH_openssl_rand_hex_32_minimum_32_chars\n# [T1] Password for the dedicated low-privilege `traccar` Postgres role that\n# owns the separate `traccar` database in the shared postgres container\n# (ADR-0042 c3; distinct from POSTGRES_PASSWORD on purpose — the third-party\n# gateway never holds the app DB's superuser credential). Generate with:\n# openssl rand -hex 32. Compose injects it into the traccar container as\n# DATABASE_PASSWORD; the role + database are created once via the idempotent\n# snippet in docs/runbook/traccar.md (which reads this same variable).\nTRACCAR_DB_PASSWORD=REPLACE_WITH_A_STRONG_TRACCAR_DB_PASSWORD\n# [T4] The public API base URL = https://<PUBLIC_DOMAIN> (ADR-0014 §2).\nBETTER_AUTH_URL=https://app.fleetco.example\n# [T4] Same-origin allowlist = the single public origin (ADR-0014 §2).\nCORS_ORIGIN=https://app.fleetco.example\n\n# === Web admin ==============================================================\n# [T4] Used by the web standalone server's runtime fetches AND baked into the\n# browser bundle at image build time (T3 --build-arg). Keep both = the public\n# origin (ADR-0014 §2 same-origin).\nNEXT_PUBLIC_API_URL=https://app.fleetco.example\n\n# === Admin seed (one-off `db:seed`, ADR-0014 §9 / ADR-0021) =================\n# Read only by the one-time seed task to create the first admin user.\n# [T2]\nADMIN_EMAIL=admin@fleetco.example\n# [T1]\nADMIN_PASSWORD=REPLACE_WITH_THE_FIRST_ADMIN_PASSWORD\n# CREATE_USER_PASSWORD (the office-staff/admin creation path, ADR-0028) is passed\n# INLINE on the create-user command at run time, never stored here.\n\n# === AI chat agent (DeepSeek — ADR-0043) ====================================\n# [T1] when set. The agent's hosted-LLM API key. LEAVE EMPTY TO KEEP THE AGENT\n# OFF THE NETWORK: unset means the API binds the no-network MockLlmClient — the\n# production kill switch (ADR-0043 c2). Set only after the ADR-0042 deploy\n# reaches daily use AND the DeepSeek training opt-out has been requested for\n# the account (ADR-0043 c6).\nDEEPSEEK_API_KEY=\n# [T4] Optional (api default: deepseek-v4-flash). The model name the agent\n# requests; the legacy deepseek-chat / deepseek-reasoner names deprecate\n# 2026-07-24.\nDEEPSEEK_MODEL=deepseek-v4-flash\n\n# === Observability (optional — ADR-0024) ====================================\n# [T1] when set (ADR-0014 §4). Leave empty to disable.\nSENTRY_DSN=\n# [T4] Leave empty to disable.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n"}, "a3df0bfd4ddcd2983ea86433abbd61e11ae2e6d2": {"t": 1785770431.2919211, "n": 5253, "h": "60cadf93883a47f8", "c": "# FleetCo production environment — TEMPLATE (ADR-0014 §4, ADR-0013 data tiers).\n#\n# Copy to a root-owned, chmod 600, gitignored `.env` on the VPS (at\n# /opt/fleetco/.env) and replace every placeholder. This file is committed and\n# MUST contain only placeholders — NEVER a real secret (CLAUDE.md, ADR-0013).\n#\n# docker-compose.prod.yml reads this file two ways:\n# - `env_file: .env` injects it into the api + web containers (runtime config).\n# - Compose interpolates ${IMAGE_TAG}, ${POSTGRES_*}, and ${PUBLIC_DOMAIN}\n# from it into the compose file itself (image tags, postgres init, Caddy).\n#\n# Data-tier legend (ADR-0013), shown per-variable on the comment line above it:\n# [T1] secret — never committed, never logged (the box's disk encryption + OS\n# access control is the trust boundary, ADR-0014 §4).\n# [T2] PII. [T4] non-sensitive config.\n# Tags ride the comment lines (not the value lines) so no annotation can ever\n# be parsed into a value.\n\n# === Image tag (Compose interpolation) ======================================\n# [T4] The GHCR tag to deploy. CI pushes images tagged by commit SHA (T3); set\n# this to that SHA on every deploy (`export IMAGE_TAG=<sha>`). `latest` is only\n# a placeholder so `docker compose config` resolves.\nIMAGE_TAG=latest\n\n# === Public origin ==========================================================\n# [T4] The single public hostname (no scheme). Caddy terminates TLS for it and\n# reads it via {$PUBLIC_DOMAIN}; BETTER_AUTH_URL / CORS_ORIGIN /\n# NEXT_PUBLIC_API_URL below are all https://<this> (ADR-0014 §2 same-origin).\nPUBLIC_DOMAIN=app.fleetco.example\n\n# === Runtime mode ===========================================================\n# [T4]\nNODE_ENV=production\n# [T4] Optional (api default: info). One of: fatal error warn info debug trace.\nLOG_LEVEL=info\n# Do NOT set PORT or HOSTNAME — the api (3001) and web (3000) ports are baked\n# into the images, the Caddyfile, and the compose healthchecks.\n\n# === PostgreSQL ==============================================================\n# The postgres container's first-run init credentials. These three MUST agree\n# with the user:password/database embedded in DATABASE_URL below.\n# [T4]\nPOSTGRES_USER=fleetco\n# [T1]\nPOSTGRES_PASSWORD=REPLACE_WITH_A_STRONG_DB_PASSWORD\n# [T4]\nPOSTGRES_DB=fleetco\n\n# === API datastores =========================================================\n# [T1] Carries the DB password (must equal POSTGRES_PASSWORD above). Host is the\n# compose service name `postgres`.\nDATABASE_URL=postgresql://fleetco:REPLACE_WITH_A_STRONG_DB_PASSWORD@postgres:5432/fleetco?schema=public\n# [T4] Host is the compose service name `redis` (no auth at this scale, ADR-0014 §1).\nREDIS_URL=redis://redis:6379\n\n# === Auth (better-auth — ADR-0015, ADR-0021) ================================\n# [T1] Session-signing secret, >=32 bytes. Generate with: openssl rand -hex 32\nBETTER_AUTH_SECRET=REPLACE_WITH_openssl_rand_hex_32_minimum_32_bytes\n\n# === GPS tracker gateway (Traccar — ADR-0042 M5/M6) =========================\n# [T1] Machine-ingest key for the Traccar → API position-forward hop, >=32\n# chars. Generate with: openssl rand -hex 32. The SAME value is injected into\n# the traccar container's forward header (M6 compose config); the ingest route\n# answers 503 while this is unset (fails closed). Before the first forward,\n# seed the credential-less gateway system user once:\n# pnpm --filter @fleetco/api exec tsx scripts/seed-gateway-user.ts\nINGEST_API_KEY=REPLACE_WITH_openssl_rand_hex_32_minimum_32_chars\n# [T1] Password for the dedicated low-privilege `traccar` Postgres role that\n# owns the separate `traccar` database in the shared postgres container\n# (ADR-0042 c3; distinct from POSTGRES_PASSWORD on purpose — the third-party\n# gateway never holds the app DB's superuser credential). Generate with:\n# openssl rand -hex 32. Compose injects it into the traccar container as\n# DATABASE_PASSWORD; the role + database are created once via the idempotent\n# snippet in docs/runbook/traccar.md (which reads this same variable).\nTRACCAR_DB_PASSWORD=REPLACE_WITH_A_STRONG_TRACCAR_DB_PASSWORD\n# [T4] The public API base URL = https://<PUBLIC_DOMAIN> (ADR-0014 §2).\nBETTER_AUTH_URL=https://app.fleetco.example\n# [T4] Same-origin allowlist = the single public origin (ADR-0014 §2).\nCORS_ORIGIN=https://app.fleetco.example\n\n# === Web admin ==============================================================\n# [T4] Used by the web standalone server's runtime fetches AND baked into the\n# browser bundle at image build time (T3 --build-arg). Keep both = the public\n# origin (ADR-0014 §2 same-origin).\nNEXT_PUBLIC_API_URL=https://app.fleetco.example\n\n# === Admin seed (one-off `db:seed`, ADR-0014 §9 / ADR-0021) =================\n# Read only by the one-time seed task to create the first admin user.\n# [T2]\nADMIN_EMAIL=admin@fleetco.example\n# [T1]\nADMIN_PASSWORD=REPLACE_WITH_THE_FIRST_ADMIN_PASSWORD\n# CREATE_USER_PASSWORD (the office-staff/admin creation path, ADR-0028) is passed\n# INLINE on the create-user command at run time, never stored here.\n\n# === Observability (optional — ADR-0024) ====================================\n# [T1] when set (ADR-0014 §4). Leave empty to disable.\nSENTRY_DSN=\n# [T4] Leave empty to disable.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n"}, "c6b39085c5819aa929de68a05e652f1a07754d74": {"t": 1785770432.8558488, "n": 4671, "h": "e93cc6d92adf6a4c", "c": "# FleetCo production environment — TEMPLATE (ADR-0014 §4, ADR-0013 data tiers).\n#\n# Copy to a root-owned, chmod 600, gitignored `.env` on the VPS (at\n# /opt/fleetco/.env) and replace every placeholder. This file is committed and\n# MUST contain only placeholders — NEVER a real secret (CLAUDE.md, ADR-0013).\n#\n# docker-compose.prod.yml reads this file two ways:\n# - `env_file: .env` injects it into the api + web containers (runtime config).\n# - Compose interpolates ${IMAGE_TAG}, ${POSTGRES_*}, and ${PUBLIC_DOMAIN}\n# from it into the compose file itself (image tags, postgres init, Caddy).\n#\n# Data-tier legend (ADR-0013), shown per-variable on the comment line above it:\n# [T1] secret — never committed, never logged (the box's disk encryption + OS\n# access control is the trust boundary, ADR-0014 §4).\n# [T2] PII. [T4] non-sensitive config.\n# Tags ride the comment lines (not the value lines) so no annotation can ever\n# be parsed into a value.\n\n# === Image tag (Compose interpolation) ======================================\n# [T4] The GHCR tag to deploy. CI pushes images tagged by commit SHA (T3); set\n# this to that SHA on every deploy (`export IMAGE_TAG=<sha>`). `latest` is only\n# a placeholder so `docker compose config` resolves.\nIMAGE_TAG=latest\n\n# === Public origin ==========================================================\n# [T4] The single public hostname (no scheme). Caddy terminates TLS for it and\n# reads it via {$PUBLIC_DOMAIN}; BETTER_AUTH_URL / CORS_ORIGIN /\n# NEXT_PUBLIC_API_URL below are all https://<this> (ADR-0014 §2 same-origin).\nPUBLIC_DOMAIN=app.fleetco.example\n\n# === Runtime mode ===========================================================\n# [T4]\nNODE_ENV=production\n# [T4] Optional (api default: info). One of: fatal error warn info debug trace.\nLOG_LEVEL=info\n# Do NOT set PORT or HOSTNAME — the api (3001) and web (3000) ports are baked\n# into the images, the Caddyfile, and the compose healthchecks.\n\n# === PostgreSQL ==============================================================\n# The postgres container's first-run init credentials. These three MUST agree\n# with the user:password/database embedded in DATABASE_URL below.\n# [T4]\nPOSTGRES_USER=fleetco\n# [T1]\nPOSTGRES_PASSWORD=REPLACE_WITH_A_STRONG_DB_PASSWORD\n# [T4]\nPOSTGRES_DB=fleetco\n\n# === API datastores =========================================================\n# [T1] Carries the DB password (must equal POSTGRES_PASSWORD above). Host is the\n# compose service name `postgres`.\nDATABASE_URL=postgresql://fleetco:REPLACE_WITH_A_STRONG_DB_PASSWORD@postgres:5432/fleetco?schema=public\n# [T4] Host is the compose service name `redis` (no auth at this scale, ADR-0014 §1).\nREDIS_URL=redis://redis:6379\n\n# === Auth (better-auth — ADR-0015, ADR-0021) ================================\n# [T1] Session-signing secret, >=32 bytes. Generate with: openssl rand -hex 32\nBETTER_AUTH_SECRET=REPLACE_WITH_openssl_rand_hex_32_minimum_32_bytes\n\n# === GPS tracker gateway (Traccar — ADR-0042 M5/M6) =========================\n# [T1] Machine-ingest key for the Traccar → API position-forward hop, >=32\n# chars. Generate with: openssl rand -hex 32. The SAME value is injected into\n# the traccar container's forward header (M6 compose config); the ingest route\n# answers 503 while this is unset (fails closed). Before the first forward,\n# seed the credential-less gateway system user once:\n# pnpm --filter @fleetco/api exec tsx scripts/seed-gateway-user.ts\nINGEST_API_KEY=REPLACE_WITH_openssl_rand_hex_32_minimum_32_chars\n# [T4] The public API base URL = https://<PUBLIC_DOMAIN> (ADR-0014 §2).\nBETTER_AUTH_URL=https://app.fleetco.example\n# [T4] Same-origin allowlist = the single public origin (ADR-0014 §2).\nCORS_ORIGIN=https://app.fleetco.example\n\n# === Web admin ==============================================================\n# [T4] Used by the web standalone server's runtime fetches AND baked into the\n# browser bundle at image build time (T3 --build-arg). Keep both = the public\n# origin (ADR-0014 §2 same-origin).\nNEXT_PUBLIC_API_URL=https://app.fleetco.example\n\n# === Admin seed (one-off `db:seed`, ADR-0014 §9 / ADR-0021) =================\n# Read only by the one-time seed task to create the first admin user.\n# [T2]\nADMIN_EMAIL=admin@fleetco.example\n# [T1]\nADMIN_PASSWORD=REPLACE_WITH_THE_FIRST_ADMIN_PASSWORD\n# CREATE_USER_PASSWORD (the office-staff/admin creation path, ADR-0028) is passed\n# INLINE on the create-user command at run time, never stored here.\n\n# === Observability (optional — ADR-0024) ====================================\n# [T1] when set (ADR-0014 §4). Leave empty to disable.\nSENTRY_DSN=\n# [T4] Leave empty to disable.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n"}, "83209f05256eaae35942c0428912ab5c255e344b": {"t": 1785770434.3466887, "n": 4096, "h": "145e9ae8c384db2e", "c": "# FleetCo production environment — TEMPLATE (ADR-0014 §4, ADR-0013 data tiers).\n#\n# Copy to a root-owned, chmod 600, gitignored `.env` on the VPS (at\n# /opt/fleetco/.env) and replace every placeholder. This file is committed and\n# MUST contain only placeholders — NEVER a real secret (CLAUDE.md, ADR-0013).\n#\n# docker-compose.prod.yml reads this file two ways:\n# - `env_file: .env` injects it into the api + web containers (runtime config).\n# - Compose interpolates ${IMAGE_TAG}, ${POSTGRES_*}, and ${PUBLIC_DOMAIN}\n# from it into the compose file itself (image tags, postgres init, Caddy).\n#\n# Data-tier legend (ADR-0013), shown per-variable on the comment line above it:\n# [T1] secret — never committed, never logged (the box's disk encryption + OS\n# access control is the trust boundary, ADR-0014 §4).\n# [T2] PII. [T4] non-sensitive config.\n# Tags ride the comment lines (not the value lines) so no annotation can ever\n# be parsed into a value.\n\n# === Image tag (Compose interpolation) ======================================\n# [T4] The GHCR tag to deploy. CI pushes images tagged by commit SHA (T3); set\n# this to that SHA on every deploy (`export IMAGE_TAG=<sha>`). `latest` is only\n# a placeholder so `docker compose config` resolves.\nIMAGE_TAG=latest\n\n# === Public origin ==========================================================\n# [T4] The single public hostname (no scheme). Caddy terminates TLS for it and\n# reads it via {$PUBLIC_DOMAIN}; BETTER_AUTH_URL / CORS_ORIGIN /\n# NEXT_PUBLIC_API_URL below are all https://<this> (ADR-0014 §2 same-origin).\nPUBLIC_DOMAIN=app.fleetco.example\n\n# === Runtime mode ===========================================================\n# [T4]\nNODE_ENV=production\n# [T4] Optional (api default: info). One of: fatal error warn info debug trace.\nLOG_LEVEL=info\n# Do NOT set PORT or HOSTNAME — the api (3001) and web (3000) ports are baked\n# into the images, the Caddyfile, and the compose healthchecks.\n\n# === PostgreSQL ==============================================================\n# The postgres container's first-run init credentials. These three MUST agree\n# with the user:password/database embedded in DATABASE_URL below.\n# [T4]\nPOSTGRES_USER=fleetco\n# [T1]\nPOSTGRES_PASSWORD=REPLACE_WITH_A_STRONG_DB_PASSWORD\n# [T4]\nPOSTGRES_DB=fleetco\n\n# === API datastores =========================================================\n# [T1] Carries the DB password (must equal POSTGRES_PASSWORD above). Host is the\n# compose service name `postgres`.\nDATABASE_URL=postgresql://fleetco:REPLACE_WITH_A_STRONG_DB_PASSWORD@postgres:5432/fleetco?schema=public\n# [T4] Host is the compose service name `redis` (no auth at this scale, ADR-0014 §1).\nREDIS_URL=redis://redis:6379\n\n# === Auth (better-auth — ADR-0015, ADR-0021) ================================\n# [T1] Session-signing secret, >=32 bytes. Generate with: openssl rand -hex 32\nBETTER_AUTH_SECRET=REPLACE_WITH_openssl_rand_hex_32_minimum_32_bytes\n# [T4] The public API base URL = https://<PUBLIC_DOMAIN> (ADR-0014 §2).\nBETTER_AUTH_URL=https://app.fleetco.example\n# [T4] Same-origin allowlist = the single public origin (ADR-0014 §2).\nCORS_ORIGIN=https://app.fleetco.example\n\n# === Web admin ==============================================================\n# [T4] Used by the web standalone server's runtime fetches AND baked into the\n# browser bundle at image build time (T3 --build-arg). Keep both = the public\n# origin (ADR-0014 §2 same-origin).\nNEXT_PUBLIC_API_URL=https://app.fleetco.example\n\n# === Admin seed (one-off `db:seed`, ADR-0014 §9 / ADR-0021) =================\n# Read only by the one-time seed task to create the first admin user.\n# [T2]\nADMIN_EMAIL=admin@fleetco.example\n# [T1]\nADMIN_PASSWORD=REPLACE_WITH_THE_FIRST_ADMIN_PASSWORD\n# CREATE_USER_PASSWORD (the office-staff/admin creation path, ADR-0028) is passed\n# INLINE on the create-user command at run time, never stored here.\n\n# === Observability (optional — ADR-0024) ====================================\n# [T1] when set (ADR-0014 §4). Leave empty to disable.\nSENTRY_DSN=\n# [T4] Leave empty to disable.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n"}}, "apps/api/.env.example": {"ba1e8d797c664f9656740124e8fce484d9ca6788": {"t": 1785747111.1374252, "n": 7370, "h": "acea6b12f352203c", "c": "# FleetCo API local environment.\n# Copy this file to .env (which is gitignored) and fill in real values.\n# Tier 1 secrets (e.g. SENTRY_DSN, BETTER_AUTH_SECRET, ADMIN_PASSWORD, real\n# DATABASE_URL passwords) per ADR-0013 must never appear in any committed file.\n\nNODE_ENV=development\nPORT=3001\n\n# Optional. When unset, Sentry init no-ops and the process emits no\n# Sentry telemetry. In production, this is the project's DSN from the\n# Sentry dashboard.\nSENTRY_DSN=\n\n# Optional (ADR-0024). The full OTLP/HTTP traces endpoint, e.g.\n# https://collector.example.com/v1/traces. When unset, no OTLP exporter is\n# built and the API ships no OTLP telemetry (the Phase-1 default); when set,\n# spans fan out to both Sentry and this collector. A tracing backend and its\n# sampling policy are chosen in Phase 2, so this stays blank for now.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# Optional. Defaults to 'info'. One of: fatal, error, warn, info, debug,\n# trace.\nLOG_LEVEL=info\n\n# Required. Postgres connection string. The username/password below are\n# Tier 4 dev placeholders matching docker-compose.yml. Real production\n# credentials are Tier 1 and live in the secret store named by the\n# eventual deployment ADR (ADR-0014, reserved).\n#\n# If you overrode POSTGRES_PORT in the repo-root .env to avoid a sibling\n# Docker project's port collision, update the host port below to match\n# (e.g. localhost:55432). See docs/runbook/dev-setup.md.\nDATABASE_URL=postgresql://fleetco:fleetco@localhost:5432/fleetco?schema=public\n\n# Required. Redis connection string. Tier 4 in dev (placeholder), Tier 1\n# in production. Same override note as DATABASE_URL applies if you set\n# REDIS_PORT in the repo-root .env.\nREDIS_URL=redis://localhost:6379\n\n# Required. better-auth session-signing secret. Tier 1 per ADR-0013 —\n# never commit a real value here; this file only documents the variable.\n# Minimum 32 bytes (256 bits). Generate locally with:\n# pnpm --filter @fleetco/api run auth:secret\n# In production this comes from the secret store named by ADR-0014.\nBETTER_AUTH_SECRET=replace-with-32-byte-secret-from-auth:secret\n\n# Required. The API's public base URL. In local dev this matches the API's\n# own PORT; if you overrode PORT to 3011, set this to http://localhost:3011.\n# better-auth uses this for cookie scoping and origin checks.\nBETTER_AUTH_URL=http://localhost:3001\n\n# Optional. Comma-separated allowlist of origins that may post credentials\n# to the API. Defaults to http://localhost:3000 (the apps/web dev server).\nCORS_ORIGIN=http://localhost:3000\n\n# Optional at API runtime; required when running `pnpm db:seed`.\n# ADMIN_EMAIL is Tier 2 PII per ADR-0013 — the founder's email.\n# ADMIN_PASSWORD is Tier 1 per ADR-0013 — the founder's credential.\n# Set both in your local .env (never here) before running the seed script.\nADMIN_EMAIL=admin@fleetco.local\nADMIN_PASSWORD=\n\n# Optional. Transactional-email provider API key for the reminder-delivery\n# channel (ADR-0038, Program C). Tier 1 secret per ADR-0013 — never commit a\n# real value here; this file only documents the variable. In production it\n# comes from the secret store named by ADR-0014. When unset (the dev/test/CI\n# default) the API boots normally and the reminder channel cannot send — it\n# only delivers from production with this key plus a verified sending domain.\nRESEND_API_KEY=\n\n# Optional at boot; REQUIRED before issuing a real invoice (ADR-0039, Program D).\n# FleetCo's OWN supplier PAN/VAT number — the seller's tax identity printed on\n# every tax invoice, distinct from a customer's PAN. Operator-supplied; this file\n# only documents the variable (never a fabricated PAN). When unset, the API boots\n# normally but invoice issue() refuses with a clear 422 until it is configured.\n# ⚠️ PROPOSED / operator-verify: the supplier PAN and the full IRD-required\n# invoice field set must be confirmed with the operator's accountant (ADR-0039 c9).\nINVOICE_SUPPLIER_PAN=\n\n# Optional. FleetCo's OWN supplier NAME printed on the invoice header beside the\n# PAN (ADR-0039, Program D). Unlike the PAN this has a safe default (\"FleetCo\"),\n# so leaving it blank never blocks issuing — set it to the exact registered\n# business name once confirmed with the operator's accountant.\nINVOICE_SUPPLIER_NAME=\n\n# Cloudflare R2 object storage for the issued invoice PDF (ADR-0039 commitment 7 —\n# the FIRST in-app R2 use; ADR-0014 c6). All four are operator-supplied; this file\n# only documents the variables. When ANY is unset (the dev/test/CI default) the\n# API boots normally, uses an in-memory mock store, and invoice issue() refuses\n# with a clear 422 until R2 is configured — so the API never reaches R2 outside\n# production. R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY are Tier 1 secrets per\n# ADR-0013 — NEVER commit a real value here; in production they come from the\n# secret store named by ADR-0014. R2_ENDPOINT is the S3 API endpoint from the\n# Cloudflare dashboard (e.g. https://<accountid>.r2.cloudflarestorage.com).\nR2_ENDPOINT=\nR2_ACCESS_KEY_ID=\nR2_SECRET_ACCESS_KEY=\nR2_BUCKET=\n\n# Optional. DeepSeek hosted-LLM API key for the AI chat agent (ADR-0043).\n# Tier 1 secret per ADR-0013 — never commit a real value here; this file only\n# documents the variable. In production it comes from the secret store named\n# by ADR-0014. When unset (the dev/test/CI default) the API boots normally and\n# the agent module binds MockLlmClient, so no request ever leaves the box —\n# and unsetting the key in production is the agent's kill switch (ADR-0043 c2).\nDEEPSEEK_API_KEY=\n\n# Optional. The DeepSeek model the agent requests (defaults to\n# deepseek-v4-flash; the legacy deepseek-chat / deepseek-reasoner names\n# deprecate 2026-07-24). Tier-4 config — override only to track a provider\n# model rename without a deploy.\nDEEPSEEK_MODEL=deepseek-v4-flash\n\n# --- Agent document extraction (ADR-0044 Box B: self-hosted OCR) ------------\n# The OCR sidecar's OpenAI-compatible base URL. OPTIONAL — unset (the default)\n# binds the no-network MockVisionExtractor: attachment turns degrade to an\n# honest \"extraction is not configured\" notice and no image is processed.\n# Local dev under Docker Model Runner:\n# AGENT_OCR_URL=http://localhost:12434/engines/llama.cpp/v1\nAGENT_OCR_URL=\n# The OCR model id the sidecar serves. Defaults to the community GGUF quant\n# the V0 eval pinned (ADR-0044 Box B); a swap is an env edit.\n#AGENT_OCR_MODEL=huggingface.co/sahilchachra/unlimited-ocr-gguf:Q4_K_M\n\n# --- WhatsApp agent channel (Twilio — ADR-0046) ------------------------------\n# ALL optional. When the TWILIO_* group is unset (the dev/test/CI default) the\n# api binds MockWhatsAppSender and the inbound webhook fails closed (503) — the\n# channel is OFF. TWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN are Tier 1 secrets per\n# ADR-0013 — never commit real values; production values live only in the\n# on-box secret file, and activation is docs/runbook/whatsapp-operations.md's\n# procedure. TWILIO_WHATSAPP_FROM is the whatsapp:+<E164> sender;\n# TWILIO_WEBHOOK_URL is the exact public webhook URL the signature guard pins\n# byte-for-byte (scheme, host, path).\nTWILIO_ACCOUNT_SID=\nTWILIO_AUTH_TOKEN=\nTWILIO_WHATSAPP_FROM=\nTWILIO_WEBHOOK_URL=\n\n# Optional. The admin web's public base URL used to build absolute deep-links\n# in agent WhatsApp replies (ADR-0046). In local dev: http://localhost:3000.\n# When unset the renderer simply omits the deep-link.\nWEB_PUBLIC_URL=\n"}, "93f9d7554247ed545fac4fd7bedb2bbb03f2af79": {"t": 1785770422.6322398, "n": 7370, "h": "acea6b12f352203c", "c": "# FleetCo API local environment.\n# Copy this file to .env (which is gitignored) and fill in real values.\n# Tier 1 secrets (e.g. SENTRY_DSN, BETTER_AUTH_SECRET, ADMIN_PASSWORD, real\n# DATABASE_URL passwords) per ADR-0013 must never appear in any committed file.\n\nNODE_ENV=development\nPORT=3001\n\n# Optional. When unset, Sentry init no-ops and the process emits no\n# Sentry telemetry. In production, this is the project's DSN from the\n# Sentry dashboard.\nSENTRY_DSN=\n\n# Optional (ADR-0024). The full OTLP/HTTP traces endpoint, e.g.\n# https://collector.example.com/v1/traces. When unset, no OTLP exporter is\n# built and the API ships no OTLP telemetry (the Phase-1 default); when set,\n# spans fan out to both Sentry and this collector. A tracing backend and its\n# sampling policy are chosen in Phase 2, so this stays blank for now.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# Optional. Defaults to 'info'. One of: fatal, error, warn, info, debug,\n# trace.\nLOG_LEVEL=info\n\n# Required. Postgres connection string. The username/password below are\n# Tier 4 dev placeholders matching docker-compose.yml. Real production\n# credentials are Tier 1 and live in the secret store named by the\n# eventual deployment ADR (ADR-0014, reserved).\n#\n# If you overrode POSTGRES_PORT in the repo-root .env to avoid a sibling\n# Docker project's port collision, update the host port below to match\n# (e.g. localhost:55432). See docs/runbook/dev-setup.md.\nDATABASE_URL=postgresql://fleetco:fleetco@localhost:5432/fleetco?schema=public\n\n# Required. Redis connection string. Tier 4 in dev (placeholder), Tier 1\n# in production. Same override note as DATABASE_URL applies if you set\n# REDIS_PORT in the repo-root .env.\nREDIS_URL=redis://localhost:6379\n\n# Required. better-auth session-signing secret. Tier 1 per ADR-0013 —\n# never commit a real value here; this file only documents the variable.\n# Minimum 32 bytes (256 bits). Generate locally with:\n# pnpm --filter @fleetco/api run auth:secret\n# In production this comes from the secret store named by ADR-0014.\nBETTER_AUTH_SECRET=replace-with-32-byte-secret-from-auth:secret\n\n# Required. The API's public base URL. In local dev this matches the API's\n# own PORT; if you overrode PORT to 3011, set this to http://localhost:3011.\n# better-auth uses this for cookie scoping and origin checks.\nBETTER_AUTH_URL=http://localhost:3001\n\n# Optional. Comma-separated allowlist of origins that may post credentials\n# to the API. Defaults to http://localhost:3000 (the apps/web dev server).\nCORS_ORIGIN=http://localhost:3000\n\n# Optional at API runtime; required when running `pnpm db:seed`.\n# ADMIN_EMAIL is Tier 2 PII per ADR-0013 — the founder's email.\n# ADMIN_PASSWORD is Tier 1 per ADR-0013 — the founder's credential.\n# Set both in your local .env (never here) before running the seed script.\nADMIN_EMAIL=admin@fleetco.local\nADMIN_PASSWORD=\n\n# Optional. Transactional-email provider API key for the reminder-delivery\n# channel (ADR-0038, Program C). Tier 1 secret per ADR-0013 — never commit a\n# real value here; this file only documents the variable. In production it\n# comes from the secret store named by ADR-0014. When unset (the dev/test/CI\n# default) the API boots normally and the reminder channel cannot send — it\n# only delivers from production with this key plus a verified sending domain.\nRESEND_API_KEY=\n\n# Optional at boot; REQUIRED before issuing a real invoice (ADR-0039, Program D).\n# FleetCo's OWN supplier PAN/VAT number — the seller's tax identity printed on\n# every tax invoice, distinct from a customer's PAN. Operator-supplied; this file\n# only documents the variable (never a fabricated PAN). When unset, the API boots\n# normally but invoice issue() refuses with a clear 422 until it is configured.\n# ⚠️ PROPOSED / operator-verify: the supplier PAN and the full IRD-required\n# invoice field set must be confirmed with the operator's accountant (ADR-0039 c9).\nINVOICE_SUPPLIER_PAN=\n\n# Optional. FleetCo's OWN supplier NAME printed on the invoice header beside the\n# PAN (ADR-0039, Program D). Unlike the PAN this has a safe default (\"FleetCo\"),\n# so leaving it blank never blocks issuing — set it to the exact registered\n# business name once confirmed with the operator's accountant.\nINVOICE_SUPPLIER_NAME=\n\n# Cloudflare R2 object storage for the issued invoice PDF (ADR-0039 commitment 7 —\n# the FIRST in-app R2 use; ADR-0014 c6). All four are operator-supplied; this file\n# only documents the variables. When ANY is unset (the dev/test/CI default) the\n# API boots normally, uses an in-memory mock store, and invoice issue() refuses\n# with a clear 422 until R2 is configured — so the API never reaches R2 outside\n# production. R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY are Tier 1 secrets per\n# ADR-0013 — NEVER commit a real value here; in production they come from the\n# secret store named by ADR-0014. R2_ENDPOINT is the S3 API endpoint from the\n# Cloudflare dashboard (e.g. https://<accountid>.r2.cloudflarestorage.com).\nR2_ENDPOINT=\nR2_ACCESS_KEY_ID=\nR2_SECRET_ACCESS_KEY=\nR2_BUCKET=\n\n# Optional. DeepSeek hosted-LLM API key for the AI chat agent (ADR-0043).\n# Tier 1 secret per ADR-0013 — never commit a real value here; this file only\n# documents the variable. In production it comes from the secret store named\n# by ADR-0014. When unset (the dev/test/CI default) the API boots normally and\n# the agent module binds MockLlmClient, so no request ever leaves the box —\n# and unsetting the key in production is the agent's kill switch (ADR-0043 c2).\nDEEPSEEK_API_KEY=\n\n# Optional. The DeepSeek model the agent requests (defaults to\n# deepseek-v4-flash; the legacy deepseek-chat / deepseek-reasoner names\n# deprecate 2026-07-24). Tier-4 config — override only to track a provider\n# model rename without a deploy.\nDEEPSEEK_MODEL=deepseek-v4-flash\n\n# --- Agent document extraction (ADR-0044 Box B: self-hosted OCR) ------------\n# The OCR sidecar's OpenAI-compatible base URL. OPTIONAL — unset (the default)\n# binds the no-network MockVisionExtractor: attachment turns degrade to an\n# honest \"extraction is not configured\" notice and no image is processed.\n# Local dev under Docker Model Runner:\n# AGENT_OCR_URL=http://localhost:12434/engines/llama.cpp/v1\nAGENT_OCR_URL=\n# The OCR model id the sidecar serves. Defaults to the community GGUF quant\n# the V0 eval pinned (ADR-0044 Box B); a swap is an env edit.\n#AGENT_OCR_MODEL=huggingface.co/sahilchachra/unlimited-ocr-gguf:Q4_K_M\n\n# --- WhatsApp agent channel (Twilio — ADR-0046) ------------------------------\n# ALL optional. When the TWILIO_* group is unset (the dev/test/CI default) the\n# api binds MockWhatsAppSender and the inbound webhook fails closed (503) — the\n# channel is OFF. TWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN are Tier 1 secrets per\n# ADR-0013 — never commit real values; production values live only in the\n# on-box secret file, and activation is docs/runbook/whatsapp-operations.md's\n# procedure. TWILIO_WHATSAPP_FROM is the whatsapp:+<E164> sender;\n# TWILIO_WEBHOOK_URL is the exact public webhook URL the signature guard pins\n# byte-for-byte (scheme, host, path).\nTWILIO_ACCOUNT_SID=\nTWILIO_AUTH_TOKEN=\nTWILIO_WHATSAPP_FROM=\nTWILIO_WEBHOOK_URL=\n\n# Optional. The admin web's public base URL used to build absolute deep-links\n# in agent WhatsApp replies (ADR-0046). In local dev: http://localhost:3000.\n# When unset the renderer simply omits the deep-link.\nWEB_PUBLIC_URL=\n"}, "8ce8455fd542dc7346b6ff5a7b1dd170ffb5dfa1": {"t": 1785770423.8904133, "n": 6409, "h": "451c0d30f36ee497", "c": "# FleetCo API local environment.\n# Copy this file to .env (which is gitignored) and fill in real values.\n# Tier 1 secrets (e.g. SENTRY_DSN, BETTER_AUTH_SECRET, ADMIN_PASSWORD, real\n# DATABASE_URL passwords) per ADR-0013 must never appear in any committed file.\n\nNODE_ENV=development\nPORT=3001\n\n# Optional. When unset, Sentry init no-ops and the process emits no\n# Sentry telemetry. In production, this is the project's DSN from the\n# Sentry dashboard.\nSENTRY_DSN=\n\n# Optional (ADR-0024). The full OTLP/HTTP traces endpoint, e.g.\n# https://collector.example.com/v1/traces. When unset, no OTLP exporter is\n# built and the API ships no OTLP telemetry (the Phase-1 default); when set,\n# spans fan out to both Sentry and this collector. A tracing backend and its\n# sampling policy are chosen in Phase 2, so this stays blank for now.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# Optional. Defaults to 'info'. One of: fatal, error, warn, info, debug,\n# trace.\nLOG_LEVEL=info\n\n# Required. Postgres connection string. The username/password below are\n# Tier 4 dev placeholders matching docker-compose.yml. Real production\n# credentials are Tier 1 and live in the secret store named by the\n# eventual deployment ADR (ADR-0014, reserved).\n#\n# If you overrode POSTGRES_PORT in the repo-root .env to avoid a sibling\n# Docker project's port collision, update the host port below to match\n# (e.g. localhost:55432). See docs/runbook/dev-setup.md.\nDATABASE_URL=postgresql://fleetco:fleetco@localhost:5432/fleetco?schema=public\n\n# Required. Redis connection string. Tier 4 in dev (placeholder), Tier 1\n# in production. Same override note as DATABASE_URL applies if you set\n# REDIS_PORT in the repo-root .env.\nREDIS_URL=redis://localhost:6379\n\n# Required. better-auth session-signing secret. Tier 1 per ADR-0013 —\n# never commit a real value here; this file only documents the variable.\n# Minimum 32 bytes (256 bits). Generate locally with:\n# pnpm --filter @fleetco/api run auth:secret\n# In production this comes from the secret store named by ADR-0014.\nBETTER_AUTH_SECRET=replace-with-32-byte-secret-from-auth:secret\n\n# Required. The API's public base URL. In local dev this matches the API's\n# own PORT; if you overrode PORT to 3011, set this to http://localhost:3011.\n# better-auth uses this for cookie scoping and origin checks.\nBETTER_AUTH_URL=http://localhost:3001\n\n# Optional. Comma-separated allowlist of origins that may post credentials\n# to the API. Defaults to http://localhost:3000 (the apps/web dev server).\nCORS_ORIGIN=http://localhost:3000\n\n# Optional at API runtime; required when running `pnpm db:seed`.\n# ADMIN_EMAIL is Tier 2 PII per ADR-0013 — the founder's email.\n# ADMIN_PASSWORD is Tier 1 per ADR-0013 — the founder's credential.\n# Set both in your local .env (never here) before running the seed script.\nADMIN_EMAIL=admin@fleetco.local\nADMIN_PASSWORD=\n\n# Optional. Transactional-email provider API key for the reminder-delivery\n# channel (ADR-0038, Program C). Tier 1 secret per ADR-0013 — never commit a\n# real value here; this file only documents the variable. In production it\n# comes from the secret store named by ADR-0014. When unset (the dev/test/CI\n# default) the API boots normally and the reminder channel cannot send — it\n# only delivers from production with this key plus a verified sending domain.\nRESEND_API_KEY=\n\n# Optional at boot; REQUIRED before issuing a real invoice (ADR-0039, Program D).\n# FleetCo's OWN supplier PAN/VAT number — the seller's tax identity printed on\n# every tax invoice, distinct from a customer's PAN. Operator-supplied; this file\n# only documents the variable (never a fabricated PAN). When unset, the API boots\n# normally but invoice issue() refuses with a clear 422 until it is configured.\n# ⚠️ PROPOSED / operator-verify: the supplier PAN and the full IRD-required\n# invoice field set must be confirmed with the operator's accountant (ADR-0039 c9).\nINVOICE_SUPPLIER_PAN=\n\n# Optional. FleetCo's OWN supplier NAME printed on the invoice header beside the\n# PAN (ADR-0039, Program D). Unlike the PAN this has a safe default (\"FleetCo\"),\n# so leaving it blank never blocks issuing — set it to the exact registered\n# business name once confirmed with the operator's accountant.\nINVOICE_SUPPLIER_NAME=\n\n# Cloudflare R2 object storage for the issued invoice PDF (ADR-0039 commitment 7 —\n# the FIRST in-app R2 use; ADR-0014 c6). All four are operator-supplied; this file\n# only documents the variables. When ANY is unset (the dev/test/CI default) the\n# API boots normally, uses an in-memory mock store, and invoice issue() refuses\n# with a clear 422 until R2 is configured — so the API never reaches R2 outside\n# production. R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY are Tier 1 secrets per\n# ADR-0013 — NEVER commit a real value here; in production they come from the\n# secret store named by ADR-0014. R2_ENDPOINT is the S3 API endpoint from the\n# Cloudflare dashboard (e.g. https://<accountid>.r2.cloudflarestorage.com).\nR2_ENDPOINT=\nR2_ACCESS_KEY_ID=\nR2_SECRET_ACCESS_KEY=\nR2_BUCKET=\n\n# Optional. DeepSeek hosted-LLM API key for the AI chat agent (ADR-0043).\n# Tier 1 secret per ADR-0013 — never commit a real value here; this file only\n# documents the variable. In production it comes from the secret store named\n# by ADR-0014. When unset (the dev/test/CI default) the API boots normally and\n# the agent module binds MockLlmClient, so no request ever leaves the box —\n# and unsetting the key in production is the agent's kill switch (ADR-0043 c2).\nDEEPSEEK_API_KEY=\n\n# Optional. The DeepSeek model the agent requests (defaults to\n# deepseek-v4-flash; the legacy deepseek-chat / deepseek-reasoner names\n# deprecate 2026-07-24). Tier-4 config — override only to track a provider\n# model rename without a deploy.\nDEEPSEEK_MODEL=deepseek-v4-flash\n\n# --- Agent document extraction (ADR-0044 Box B: self-hosted OCR) ------------\n# The OCR sidecar's OpenAI-compatible base URL. OPTIONAL — unset (the default)\n# binds the no-network MockVisionExtractor: attachment turns degrade to an\n# honest \"extraction is not configured\" notice and no image is processed.\n# Local dev under Docker Model Runner:\n# AGENT_OCR_URL=http://localhost:12434/engines/llama.cpp/v1\nAGENT_OCR_URL=\n# The OCR model id the sidecar serves. Defaults to the community GGUF quant\n# the V0 eval pinned (ADR-0044 Box B); a swap is an env edit.\n#AGENT_OCR_MODEL=huggingface.co/sahilchachra/unlimited-ocr-gguf:Q4_K_M\n"}, "e74f9d8ec30fe36f6c3d863162b746b610abd527": {"t": 1785770425.3013842, "n": 5776, "h": "61ad3f7dc35d852a", "c": "# FleetCo API local environment.\n# Copy this file to .env (which is gitignored) and fill in real values.\n# Tier 1 secrets (e.g. SENTRY_DSN, BETTER_AUTH_SECRET, ADMIN_PASSWORD, real\n# DATABASE_URL passwords) per ADR-0013 must never appear in any committed file.\n\nNODE_ENV=development\nPORT=3001\n\n# Optional. When unset, Sentry init no-ops and the process emits no\n# Sentry telemetry. In production, this is the project's DSN from the\n# Sentry dashboard.\nSENTRY_DSN=\n\n# Optional (ADR-0024). The full OTLP/HTTP traces endpoint, e.g.\n# https://collector.example.com/v1/traces. When unset, no OTLP exporter is\n# built and the API ships no OTLP telemetry (the Phase-1 default); when set,\n# spans fan out to both Sentry and this collector. A tracing backend and its\n# sampling policy are chosen in Phase 2, so this stays blank for now.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# Optional. Defaults to 'info'. One of: fatal, error, warn, info, debug,\n# trace.\nLOG_LEVEL=info\n\n# Required. Postgres connection string. The username/password below are\n# Tier 4 dev placeholders matching docker-compose.yml. Real production\n# credentials are Tier 1 and live in the secret store named by the\n# eventual deployment ADR (ADR-0014, reserved).\n#\n# If you overrode POSTGRES_PORT in the repo-root .env to avoid a sibling\n# Docker project's port collision, update the host port below to match\n# (e.g. localhost:55432). See docs/runbook/dev-setup.md.\nDATABASE_URL=postgresql://fleetco:fleetco@localhost:5432/fleetco?schema=public\n\n# Required. Redis connection string. Tier 4 in dev (placeholder), Tier 1\n# in production. Same override note as DATABASE_URL applies if you set\n# REDIS_PORT in the repo-root .env.\nREDIS_URL=redis://localhost:6379\n\n# Required. better-auth session-signing secret. Tier 1 per ADR-0013 —\n# never commit a real value here; this file only documents the variable.\n# Minimum 32 bytes (256 bits). Generate locally with:\n# pnpm --filter @fleetco/api run auth:secret\n# In production this comes from the secret store named by ADR-0014.\nBETTER_AUTH_SECRET=replace-with-32-byte-secret-from-auth:secret\n\n# Required. The API's public base URL. In local dev this matches the API's\n# own PORT; if you overrode PORT to 3011, set this to http://localhost:3011.\n# better-auth uses this for cookie scoping and origin checks.\nBETTER_AUTH_URL=http://localhost:3001\n\n# Optional. Comma-separated allowlist of origins that may post credentials\n# to the API. Defaults to http://localhost:3000 (the apps/web dev server).\nCORS_ORIGIN=http://localhost:3000\n\n# Optional at API runtime; required when running `pnpm db:seed`.\n# ADMIN_EMAIL is Tier 2 PII per ADR-0013 — the founder's email.\n# ADMIN_PASSWORD is Tier 1 per ADR-0013 — the founder's credential.\n# Set both in your local .env (never here) before running the seed script.\nADMIN_EMAIL=admin@fleetco.local\nADMIN_PASSWORD=\n\n# Optional. Transactional-email provider API key for the reminder-delivery\n# channel (ADR-0038, Program C). Tier 1 secret per ADR-0013 — never commit a\n# real value here; this file only documents the variable. In production it\n# comes from the secret store named by ADR-0014. When unset (the dev/test/CI\n# default) the API boots normally and the reminder channel cannot send — it\n# only delivers from production with this key plus a verified sending domain.\nRESEND_API_KEY=\n\n# Optional at boot; REQUIRED before issuing a real invoice (ADR-0039, Program D).\n# FleetCo's OWN supplier PAN/VAT number — the seller's tax identity printed on\n# every tax invoice, distinct from a customer's PAN. Operator-supplied; this file\n# only documents the variable (never a fabricated PAN). When unset, the API boots\n# normally but invoice issue() refuses with a clear 422 until it is configured.\n# ⚠️ PROPOSED / operator-verify: the supplier PAN and the full IRD-required\n# invoice field set must be confirmed with the operator's accountant (ADR-0039 c9).\nINVOICE_SUPPLIER_PAN=\n\n# Optional. FleetCo's OWN supplier NAME printed on the invoice header beside the\n# PAN (ADR-0039, Program D). Unlike the PAN this has a safe default (\"FleetCo\"),\n# so leaving it blank never blocks issuing — set it to the exact registered\n# business name once confirmed with the operator's accountant.\nINVOICE_SUPPLIER_NAME=\n\n# Cloudflare R2 object storage for the issued invoice PDF (ADR-0039 commitment 7 —\n# the FIRST in-app R2 use; ADR-0014 c6). All four are operator-supplied; this file\n# only documents the variables. When ANY is unset (the dev/test/CI default) the\n# API boots normally, uses an in-memory mock store, and invoice issue() refuses\n# with a clear 422 until R2 is configured — so the API never reaches R2 outside\n# production. R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY are Tier 1 secrets per\n# ADR-0013 — NEVER commit a real value here; in production they come from the\n# secret store named by ADR-0014. R2_ENDPOINT is the S3 API endpoint from the\n# Cloudflare dashboard (e.g. https://<accountid>.r2.cloudflarestorage.com).\nR2_ENDPOINT=\nR2_ACCESS_KEY_ID=\nR2_SECRET_ACCESS_KEY=\nR2_BUCKET=\n\n# Optional. DeepSeek hosted-LLM API key for the AI chat agent (ADR-0043).\n# Tier 1 secret per ADR-0013 — never commit a real value here; this file only\n# documents the variable. In production it comes from the secret store named\n# by ADR-0014. When unset (the dev/test/CI default) the API boots normally and\n# the agent module binds MockLlmClient, so no request ever leaves the box —\n# and unsetting the key in production is the agent's kill switch (ADR-0043 c2).\nDEEPSEEK_API_KEY=\n\n# Optional. The DeepSeek model the agent requests (defaults to\n# deepseek-v4-flash; the legacy deepseek-chat / deepseek-reasoner names\n# deprecate 2026-07-24). Tier-4 config — override only to track a provider\n# model rename without a deploy.\nDEEPSEEK_MODEL=deepseek-v4-flash\n"}, "ae93c7cf14a968f0c11018b1ff2025c9e4012faa": {"t": 1785770426.855327, "n": 5016, "h": "319e466f645d05ce", "c": "# FleetCo API local environment.\n# Copy this file to .env (which is gitignored) and fill in real values.\n# Tier 1 secrets (e.g. SENTRY_DSN, BETTER_AUTH_SECRET, ADMIN_PASSWORD, real\n# DATABASE_URL passwords) per ADR-0013 must never appear in any committed file.\n\nNODE_ENV=development\nPORT=3001\n\n# Optional. When unset, Sentry init no-ops and the process emits no\n# Sentry telemetry. In production, this is the project's DSN from the\n# Sentry dashboard.\nSENTRY_DSN=\n\n# Optional (ADR-0024). The full OTLP/HTTP traces endpoint, e.g.\n# https://collector.example.com/v1/traces. When unset, no OTLP exporter is\n# built and the API ships no OTLP telemetry (the Phase-1 default); when set,\n# spans fan out to both Sentry and this collector. A tracing backend and its\n# sampling policy are chosen in Phase 2, so this stays blank for now.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# Optional. Defaults to 'info'. One of: fatal, error, warn, info, debug,\n# trace.\nLOG_LEVEL=info\n\n# Required. Postgres connection string. The username/password below are\n# Tier 4 dev placeholders matching docker-compose.yml. Real production\n# credentials are Tier 1 and live in the secret store named by the\n# eventual deployment ADR (ADR-0014, reserved).\n#\n# If you overrode POSTGRES_PORT in the repo-root .env to avoid a sibling\n# Docker project's port collision, update the host port below to match\n# (e.g. localhost:55432). See docs/runbook/dev-setup.md.\nDATABASE_URL=postgresql://fleetco:fleetco@localhost:5432/fleetco?schema=public\n\n# Required. Redis connection string. Tier 4 in dev (placeholder), Tier 1\n# in production. Same override note as DATABASE_URL applies if you set\n# REDIS_PORT in the repo-root .env.\nREDIS_URL=redis://localhost:6379\n\n# Required. better-auth session-signing secret. Tier 1 per ADR-0013 —\n# never commit a real value here; this file only documents the variable.\n# Minimum 32 bytes (256 bits). Generate locally with:\n# pnpm --filter @fleetco/api run auth:secret\n# In production this comes from the secret store named by ADR-0014.\nBETTER_AUTH_SECRET=replace-with-32-byte-secret-from-auth:secret\n\n# Required. The API's public base URL. In local dev this matches the API's\n# own PORT; if you overrode PORT to 3011, set this to http://localhost:3011.\n# better-auth uses this for cookie scoping and origin checks.\nBETTER_AUTH_URL=http://localhost:3001\n\n# Optional. Comma-separated allowlist of origins that may post credentials\n# to the API. Defaults to http://localhost:3000 (the apps/web dev server).\nCORS_ORIGIN=http://localhost:3000\n\n# Optional at API runtime; required when running `pnpm db:seed`.\n# ADMIN_EMAIL is Tier 2 PII per ADR-0013 — the founder's email.\n# ADMIN_PASSWORD is Tier 1 per ADR-0013 — the founder's credential.\n# Set both in your local .env (never here) before running the seed script.\nADMIN_EMAIL=admin@fleetco.local\nADMIN_PASSWORD=\n\n# Optional. Transactional-email provider API key for the reminder-delivery\n# channel (ADR-0038, Program C). Tier 1 secret per ADR-0013 — never commit a\n# real value here; this file only documents the variable. In production it\n# comes from the secret store named by ADR-0014. When unset (the dev/test/CI\n# default) the API boots normally and the reminder channel cannot send — it\n# only delivers from production with this key plus a verified sending domain.\nRESEND_API_KEY=\n\n# Optional at boot; REQUIRED before issuing a real invoice (ADR-0039, Program D).\n# FleetCo's OWN supplier PAN/VAT number — the seller's tax identity printed on\n# every tax invoice, distinct from a customer's PAN. Operator-supplied; this file\n# only documents the variable (never a fabricated PAN). When unset, the API boots\n# normally but invoice issue() refuses with a clear 422 until it is configured.\n# ⚠️ PROPOSED / operator-verify: the supplier PAN and the full IRD-required\n# invoice field set must be confirmed with the operator's accountant (ADR-0039 c9).\nINVOICE_SUPPLIER_PAN=\n\n# Optional. FleetCo's OWN supplier NAME printed on the invoice header beside the\n# PAN (ADR-0039, Program D). Unlike the PAN this has a safe default (\"FleetCo\"),\n# so leaving it blank never blocks issuing — set it to the exact registered\n# business name once confirmed with the operator's accountant.\nINVOICE_SUPPLIER_NAME=\n\n# Cloudflare R2 object storage for the issued invoice PDF (ADR-0039 commitment 7 —\n# the FIRST in-app R2 use; ADR-0014 c6). All four are operator-supplied; this file\n# only documents the variables. When ANY is unset (the dev/test/CI default) the\n# API boots normally, uses an in-memory mock store, and invoice issue() refuses\n# with a clear 422 until R2 is configured — so the API never reaches R2 outside\n# production. R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY are Tier 1 secrets per\n# ADR-0013 — NEVER commit a real value here; in production they come from the\n# secret store named by ADR-0014. R2_ENDPOINT is the S3 API endpoint from the\n# Cloudflare dashboard (e.g. https://<accountid>.r2.cloudflarestorage.com).\nR2_ENDPOINT=\nR2_ACCESS_KEY_ID=\nR2_SECRET_ACCESS_KEY=\nR2_BUCKET=\n"}, "f035a389ed29a6a60cbc86d29a89547541f13ec2": {"t": 1785770428.3899844, "n": 3909, "h": "ce309e9cea98587f", "c": "# FleetCo API local environment.\n# Copy this file to .env (which is gitignored) and fill in real values.\n# Tier 1 secrets (e.g. SENTRY_DSN, BETTER_AUTH_SECRET, ADMIN_PASSWORD, real\n# DATABASE_URL passwords) per ADR-0013 must never appear in any committed file.\n\nNODE_ENV=development\nPORT=3001\n\n# Optional. When unset, Sentry init no-ops and the process emits no\n# Sentry telemetry. In production, this is the project's DSN from the\n# Sentry dashboard.\nSENTRY_DSN=\n\n# Optional (ADR-0024). The full OTLP/HTTP traces endpoint, e.g.\n# https://collector.example.com/v1/traces. When unset, no OTLP exporter is\n# built and the API ships no OTLP telemetry (the Phase-1 default); when set,\n# spans fan out to both Sentry and this collector. A tracing backend and its\n# sampling policy are chosen in Phase 2, so this stays blank for now.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# Optional. Defaults to 'info'. One of: fatal, error, warn, info, debug,\n# trace.\nLOG_LEVEL=info\n\n# Required. Postgres connection string. The username/password below are\n# Tier 4 dev placeholders matching docker-compose.yml. Real production\n# credentials are Tier 1 and live in the secret store named by the\n# eventual deployment ADR (ADR-0014, reserved).\n#\n# If you overrode POSTGRES_PORT in the repo-root .env to avoid a sibling\n# Docker project's port collision, update the host port below to match\n# (e.g. localhost:55432). See docs/runbook/dev-setup.md.\nDATABASE_URL=postgresql://fleetco:fleetco@localhost:5432/fleetco?schema=public\n\n# Required. Redis connection string. Tier 4 in dev (placeholder), Tier 1\n# in production. Same override note as DATABASE_URL applies if you set\n# REDIS_PORT in the repo-root .env.\nREDIS_URL=redis://localhost:6379\n\n# Required. better-auth session-signing secret. Tier 1 per ADR-0013 —\n# never commit a real value here; this file only documents the variable.\n# Minimum 32 bytes (256 bits). Generate locally with:\n# pnpm --filter @fleetco/api run auth:secret\n# In production this comes from the secret store named by ADR-0014.\nBETTER_AUTH_SECRET=replace-with-32-byte-secret-from-auth:secret\n\n# Required. The API's public base URL. In local dev this matches the API's\n# own PORT; if you overrode PORT to 3011, set this to http://localhost:3011.\n# better-auth uses this for cookie scoping and origin checks.\nBETTER_AUTH_URL=http://localhost:3001\n\n# Optional. Comma-separated allowlist of origins that may post credentials\n# to the API. Defaults to http://localhost:3000 (the apps/web dev server).\nCORS_ORIGIN=http://localhost:3000\n\n# Optional at API runtime; required when running `pnpm db:seed`.\n# ADMIN_EMAIL is Tier 2 PII per ADR-0013 — the founder's email.\n# ADMIN_PASSWORD is Tier 1 per ADR-0013 — the founder's credential.\n# Set both in your local .env (never here) before running the seed script.\nADMIN_EMAIL=admin@fleetco.local\nADMIN_PASSWORD=\n\n# Optional. Transactional-email provider API key for the reminder-delivery\n# channel (ADR-0038, Program C). Tier 1 secret per ADR-0013 — never commit a\n# real value here; this file only documents the variable. In production it\n# comes from the secret store named by ADR-0014. When unset (the dev/test/CI\n# default) the API boots normally and the reminder channel cannot send — it\n# only delivers from production with this key plus a verified sending domain.\nRESEND_API_KEY=\n\n# Optional at boot; REQUIRED before issuing a real invoice (ADR-0039, Program D).\n# FleetCo's OWN supplier PAN/VAT number — the seller's tax identity printed on\n# every tax invoice, distinct from a customer's PAN. Operator-supplied; this file\n# only documents the variable (never a fabricated PAN). When unset, the API boots\n# normally but invoice issue() refuses with a clear 422 until it is configured.\n# ⚠️ PROPOSED / operator-verify: the supplier PAN and the full IRD-required\n# invoice field set must be confirmed with the operator's accountant (ADR-0039 c9).\nINVOICE_SUPPLIER_PAN=\n"}, "155cc285e55bbba2cfadc9f7a4a14d3d652484dc": {"t": 1785770429.9926622, "n": 3321, "h": "8e7ce06c891e3a33", "c": "# FleetCo API local environment.\n# Copy this file to .env (which is gitignored) and fill in real values.\n# Tier 1 secrets (e.g. SENTRY_DSN, BETTER_AUTH_SECRET, ADMIN_PASSWORD, real\n# DATABASE_URL passwords) per ADR-0013 must never appear in any committed file.\n\nNODE_ENV=development\nPORT=3001\n\n# Optional. When unset, Sentry init no-ops and the process emits no\n# Sentry telemetry. In production, this is the project's DSN from the\n# Sentry dashboard.\nSENTRY_DSN=\n\n# Optional (ADR-0024). The full OTLP/HTTP traces endpoint, e.g.\n# https://collector.example.com/v1/traces. When unset, no OTLP exporter is\n# built and the API ships no OTLP telemetry (the Phase-1 default); when set,\n# spans fan out to both Sentry and this collector. A tracing backend and its\n# sampling policy are chosen in Phase 2, so this stays blank for now.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# Optional. Defaults to 'info'. One of: fatal, error, warn, info, debug,\n# trace.\nLOG_LEVEL=info\n\n# Required. Postgres connection string. The username/password below are\n# Tier 4 dev placeholders matching docker-compose.yml. Real production\n# credentials are Tier 1 and live in the secret store named by the\n# eventual deployment ADR (ADR-0014, reserved).\n#\n# If you overrode POSTGRES_PORT in the repo-root .env to avoid a sibling\n# Docker project's port collision, update the host port below to match\n# (e.g. localhost:55432). See docs/runbook/dev-setup.md.\nDATABASE_URL=postgresql://fleetco:fleetco@localhost:5432/fleetco?schema=public\n\n# Required. Redis connection string. Tier 4 in dev (placeholder), Tier 1\n# in production. Same override note as DATABASE_URL applies if you set\n# REDIS_PORT in the repo-root .env.\nREDIS_URL=redis://localhost:6379\n\n# Required. better-auth session-signing secret. Tier 1 per ADR-0013 —\n# never commit a real value here; this file only documents the variable.\n# Minimum 32 bytes (256 bits). Generate locally with:\n# pnpm --filter @fleetco/api run auth:secret\n# In production this comes from the secret store named by ADR-0014.\nBETTER_AUTH_SECRET=replace-with-32-byte-secret-from-auth:secret\n\n# Required. The API's public base URL. In local dev this matches the API's\n# own PORT; if you overrode PORT to 3011, set this to http://localhost:3011.\n# better-auth uses this for cookie scoping and origin checks.\nBETTER_AUTH_URL=http://localhost:3001\n\n# Optional. Comma-separated allowlist of origins that may post credentials\n# to the API. Defaults to http://localhost:3000 (the apps/web dev server).\nCORS_ORIGIN=http://localhost:3000\n\n# Optional at API runtime; required when running `pnpm db:seed`.\n# ADMIN_EMAIL is Tier 2 PII per ADR-0013 — the founder's email.\n# ADMIN_PASSWORD is Tier 1 per ADR-0013 — the founder's credential.\n# Set both in your local .env (never here) before running the seed script.\nADMIN_EMAIL=admin@fleetco.local\nADMIN_PASSWORD=\n\n# Optional. Transactional-email provider API key for the reminder-delivery\n# channel (ADR-0038, Program C). Tier 1 secret per ADR-0013 — never commit a\n# real value here; this file only documents the variable. In production it\n# comes from the secret store named by ADR-0014. When unset (the dev/test/CI\n# default) the API boots normally and the reminder channel cannot send — it\n# only delivers from production with this key plus a verified sending domain.\nRESEND_API_KEY=\n"}, "8707be4a25d005ee35c6b567802a6d8c46e3d094": {"t": 1785770431.290542, "n": 2846, "h": "c6bee01e2e24e905", "c": "# FleetCo API local environment.\n# Copy this file to .env (which is gitignored) and fill in real values.\n# Tier 1 secrets (e.g. SENTRY_DSN, BETTER_AUTH_SECRET, ADMIN_PASSWORD, real\n# DATABASE_URL passwords) per ADR-0013 must never appear in any committed file.\n\nNODE_ENV=development\nPORT=3001\n\n# Optional. When unset, Sentry init no-ops and the process emits no\n# Sentry telemetry. In production, this is the project's DSN from the\n# Sentry dashboard.\nSENTRY_DSN=\n\n# Optional (ADR-0024). The full OTLP/HTTP traces endpoint, e.g.\n# https://collector.example.com/v1/traces. When unset, no OTLP exporter is\n# built and the API ships no OTLP telemetry (the Phase-1 default); when set,\n# spans fan out to both Sentry and this collector. A tracing backend and its\n# sampling policy are chosen in Phase 2, so this stays blank for now.\nOTEL_EXPORTER_OTLP_ENDPOINT=\n\n# Optional. Defaults to 'info'. One of: fatal, error, warn, info, debug,\n# trace.\nLOG_LEVEL=info\n\n# Required. Postgres connection string. The username/password below are\n# Tier 4 dev placeholders matching docker-compose.yml. Real production\n# credentials are Tier 1 and live in the secret store named by the\n# eventual deployment ADR (ADR-0014, reserved).\n#\n# If you overrode POSTGRES_PORT in the repo-root .env to avoid a sibling\n# Docker project's port collision, update the host port below to match\n# (e.g. localhost:55432). See docs/runbook/dev-setup.md.\nDATABASE_URL=postgresql://fleetco:fleetco@localhost:5432/fleetco?schema=public\n\n# Required. Redis connection string. Tier 4 in dev (placeholder), Tier 1\n# in production. Same override note as DATABASE_URL applies if you set\n# REDIS_PORT in the repo-root .env.\nREDIS_URL=redis://localhost:6379\n\n# Required. better-auth session-signing secret. Tier 1 per ADR-0013 —\n# never commit a real value here; this file only documents the variable.\n# Minimum 32 bytes (256 bits). Generate locally with:\n# pnpm --filter @fleetco/api run auth:secret\n# In production this comes from the secret store named by ADR-0014.\nBETTER_AUTH_SECRET=replace-with-32-byte-secret-from-auth:secret\n\n# Required. The API's public base URL. In local dev this matches the API's\n# own PORT; if you overrode PORT to 3011, set this to http://localhost:3011.\n# better-auth uses this for cookie scoping and origin checks.\nBETTER_AUTH_URL=http://localhost:3001\n\n# Optional. Comma-separated allowlist of origins that may post credentials\n# to the API. Defaults to http://localhost:3000 (the apps/web dev server).\nCORS_ORIGIN=http://localhost:3000\n\n# Optional at API runtime; required when running `pnpm db:seed`.\n# ADMIN_EMAIL is Tier 2 PII per ADR-0013 — the founder's email.\n# ADMIN_PASSWORD is Tier 1 per ADR-0013 — the founder's credential.\n# Set both in your local .env (never here) before running the seed script.\nADMIN_EMAIL=admin@fleetco.local\nADMIN_PASSWORD=\n"}, "0c839c0ccc257f8b796043f7be7a8e470a56b5ed": {"t": 1785770433.0492997, "n": 2453, "h": "707e5a2263324075", "c": "# FleetCo API local environment.\n# Copy this file to .env (which is gitignored) and fill in real values.\n# Tier 1 secrets (e.g. SENTRY_DSN, BETTER_AUTH_SECRET, ADMIN_PASSWORD, real\n# DATABASE_URL passwords) per ADR-0013 must never appear in any committed file.\n\nNODE_ENV=development\nPORT=3001\n\n# Optional. When unset, Sentry init no-ops and the process emits no\n# Sentry telemetry. In production, this is the project's DSN from the\n# Sentry dashboard.\nSENTRY_DSN=\n\n# Optional. Defaults to 'info'. One of: fatal, error, warn, info, debug,\n# trace.\nLOG_LEVEL=info\n\n# Required. Postgres connection string. The username/password below are\n# Tier 4 dev placeholders matching docker-compose.yml. Real production\n# credentials are Tier 1 and live in the secret store named by the\n# eventual deployment ADR (ADR-0014, reserved).\n#\n# If you overrode POSTGRES_PORT in the repo-root .env to avoid a sibling\n# Docker project's port collision, update the host port below to match\n# (e.g. localhost:55432). See docs/runbook/dev-setup.md.\nDATABASE_URL=postgresql://fleetco:fleetco@localhost:5432/fleetco?schema=public\n\n# Required. Redis connection string. Tier 4 in dev (placeholder), Tier 1\n# in production. Same override note as DATABASE_URL applies if you set\n# REDIS_PORT in the repo-root .env.\nREDIS_URL=redis://localhost:6379\n\n# Required. better-auth session-signing secret. Tier 1 per ADR-0013 —\n# never commit a real value here; this file only documents the variable.\n# Minimum 32 bytes (256 bits). Generate locally with:\n# pnpm --filter @fleetco/api run auth:secret\n# In production this comes from the secret store named by ADR-0014.\nBETTER_AUTH_SECRET=replace-with-32-byte-secret-from-auth:secret\n\n# Required. The API's public base URL. In local dev this matches the API's\n# own PORT; if you overrode PORT to 3011, set this to http://localhost:3011.\n# better-auth uses this for cookie scoping and origin checks.\nBETTER_AUTH_URL=http://localhost:3001\n\n# Optional. Comma-separated allowlist of origins that may post credentials\n# to the API. Defaults to http://localhost:3000 (the apps/web dev server).\nCORS_ORIGIN=http://localhost:3000\n\n# Optional at API runtime; required when running `pnpm db:seed`.\n# ADMIN_EMAIL is Tier 2 PII per ADR-0013 — the founder's email.\n# ADMIN_PASSWORD is Tier 1 per ADR-0013 — the founder's credential.\n# Set both in your local .env (never here) before running the seed script.\nADMIN_EMAIL=admin@fleetco.local\nADMIN_PASSWORD=\n"}, "7df7f873e86affcb4a3f4facfbafe48f8ca13fef": {"t": 1785770434.374228, "n": 1281, "h": "e3804ab5d03dae0e", "c": "# FleetCo API local environment.\n# Copy this file to .env (which is gitignored) and fill in real values.\n# Tier 1 secrets (e.g. SENTRY_DSN, real DATABASE_URL passwords) per\n# ADR-0013 must never appear in any committed file.\n\nNODE_ENV=development\nPORT=3001\n\n# Optional. When unset, Sentry init no-ops and the process emits no\n# Sentry telemetry. In production, this is the project's DSN from the\n# Sentry dashboard.\nSENTRY_DSN=\n\n# Optional. Defaults to 'info'. One of: fatal, error, warn, info, debug,\n# trace.\nLOG_LEVEL=info\n\n# Required. Postgres connection string. The username/password below are\n# Tier 4 dev placeholders matching docker-compose.yml. Real production\n# credentials are Tier 1 and live in the secret store named by the\n# eventual deployment ADR (ADR-0014, reserved).\n#\n# If you overrode POSTGRES_PORT in the repo-root .env to avoid a sibling\n# Docker project's port collision, update the host port below to match\n# (e.g. localhost:55432). See docs/runbook/dev-setup.md.\nDATABASE_URL=postgresql://fleetco:fleetco@localhost:5432/fleetco?schema=public\n\n# Required. Redis connection string. Tier 4 in dev (placeholder), Tier 1\n# in production. Same override note as DATABASE_URL applies if you set\n# REDIS_PORT in the repo-root .env.\nREDIS_URL=redis://localhost:6379\n"}, "f7a3d80860345335b677b79c2d47a7c1d0113636": {"t": 1785770435.7837481, "n": 497, "h": "a6bdd885682590ee", "c": "# FleetCo API local environment.\n# Copy this file to .env (which is gitignored) and fill in real values.\n# Tier 1 secrets (e.g. SENTRY_DSN) per ADR-0013 must never appear in any\n# committed file.\n\nNODE_ENV=development\nPORT=3001\n\n# Optional. When unset, Sentry init no-ops and the process emits no\n# Sentry telemetry. In production, this is the project's DSN from the\n# Sentry dashboard.\nSENTRY_DSN=\n\n# Optional. Defaults to 'info'. One of: fatal, error, warn, info, debug,\n# trace.\nLOG_LEVEL=info\n"}}}}