# ──────────────────────────────────────────────────────────────────────── # Africa Alert PWA — environment configuration template # ──────────────────────────────────────────────────────────────────────── # # Copy this file to `.env` at the repo root and fill in real values. # `.env` is gitignored; never commit secrets. # # Dev: `node server/src/index.js` loads `.env` from the server cwd # automatically (see server/src/index.js for the loader). # Prod: load .env via your orchestrator (Docker, systemd, k8s secret). # # `server/src/config/index.js` is the single source of truth for which # vars are required. The server exits non-zero on startup if a required # var is missing in production. See `.harness/docs/conventions.md` for # the environment contract. # ─── Node / runtime ──────────────────────────────────────────────────── NODE_ENV=development PORT=3001 DB_PATH=./data/school.db # ─── Auth (REQUIRED in production) ───────────────────────────────────── # HMAC secret for JWT signing/verification. # Generate with: node -e "console.log(require('crypto').randomBytes(48).toString('hex'))" JWT_SECRET=replace-me-with-64-byte-hex # Comma-separated CORS allow-list. NO wildcard allowed in production. ALLOWED_ORIGINS=http://localhost:3000 # When true, /api/auth/login response includes `offline_jwt_secret` so the # client can mint JWTs while offline. Must be 'true' or 'false'. ALLOW_CLIENT_OFFLINE_MINT=true # ─── Paynow (Zimbabwean payment gateway) ──────────────────────────────── # Credentials are issued at https://www.paynow.co.zw after registering an # integration. PAYNOW_INTEGRATION_KEY signs outbound requests AND inbound # webhooks — keep it secret. PAYNOW_INTEGRATION_ID= PAYNOW_INTEGRATION_KEY= # Where Paynow should send status updates and where users land after pay. PAYNOW_RETURN_URL=http://localhost:3000/fees PAYNOW_BLOCKING_URL=http://localhost:3000/api/payments/webhook # Set to 'true' ONLY for local dev and Playwright tests that simulate # Paynow and need to hit the webhook without a real signature. In # production leave unset — webhook signature verification is enforced. # PAYNOW_SKIP_VERIFY=false # ─── Supabase (optional — sync is no-op when empty) ─────────────────── # Server-side credentials. The sync engine skips when SUPABASE_KEY is empty. SUPABASE_URL= SUPABASE_KEY= # Same values exposed to the client bundle. The PWA reads these at build # time via Vite's import.meta.env (only VITE_-prefixed vars are inlined). VITE_SUPABASE_URL= VITE_SUPABASE_ANON_KEY= # ─── SMTP (optional — password recovery emails) ──────────────────────── # When SMTP_HOST is unset, EmailService falls back to Ethersoft preview # mode (dev only). In production set SMTP_HOST to send real mail. SMTP_HOST= SMTP_PORT=587 SMTP_SECURE=false SMTP_USER= SMTP_PASS= SMTP_FROM="NextGen Support " # ─── Sync tuning ─────────────────────────────────────────────────────── # Override the default 30s sync interval (in seconds). Empty = default. # SYNC_INTERVAL=30 # ─── Port allocation ─────────────────────────────────────────────────── # See PORTS.md for the canonical port plan. Defaults are non-colliding # so tenant + superadmin can run side-by-side. # # Tenant stack: PORT=3001 # tenant API (server/src/config/index.js) VITE_PORT=3000 # tenant client Vite (client/vite.config.ts) VITE_API_TARGET=http://127.0.0.1:3001 VITE_WS_TARGET=ws://127.0.0.1:3001 # # SuperAdmin stack: SUPERADMIN_PORT=3002 # SuperAdmin API (superadmin/server/src/index.js) # SuperAdmin client Vite uses VITE_PORT=3003 — set it in superadmin/client/.env # # Tenant → SuperAdmin JWKS (only SuperAdmin exposes JWKS; default is the # dev-proxy path; override to a full URL for cross-origin in prod). VITE_SUPERADMIN_JWKS_URL=/api/v1/auth/jwks # ─── SuperAdmin licensing (ed25519 trust anchor + heartbeat) ────────────── # Placeholder — replace with the matching SuperAdmin public key. SUPERADMIN_PUBLIC_KEY=-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAGB9...REPLACE_ME...\n-----END PUBLIC KEY----- VITE_SUPERADMIN_PUBLIC_KEY=-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAGB9...REPLACE_ME...\n-----END PUBLIC KEY----- SUPERADMIN_HEARTBEAT_URL= LICENSE_HEARTBEAT_INTERVAL_MS=300000 LICENSE_CLOCK_DRIFT_MS=300000 # Optional — service auto-detects absence and uses LRU cache only. REDIS_URL= # ─── Weekly Government Push (Monday 06:00 server local time) ──────────── # Pushes the weekly Ministry-style aggregate report # (GET /api/reports/weekly payload) to one or more government endpoints. # See server/src/services/WeeklyGovPushService.js for the cron logic. # # The four values below (URLS, AUTH, HMAC_SECRET, SCHOOL_ID) are # DEFAULTS. Admins can override them at runtime via # Settings → API & Integrations → Ministry Reporting, which writes to # the system_settings table; DB values take precedence when set. # # Set to 0 to disable the cron entirely (kill switch); default is enabled. WEEKLY_GOV_PUSH=1 # Comma-separated target URLs. Replace with real endpoints. WEEKLY_GOV_PUSH_URLS=https://mopse.gov.zw/api/v1/weekly,https://placeholder.example.gov.zw/api/v1/weekly # Full Authorization header value (e.g. "Bearer xxx"). If empty, no auth header is sent. WEEKLY_GOV_PUSH_AUTH=Bearer change-me-to-real-token # Optional HMAC-SHA256 secret — if set, the body is signed and sent as X-Signature: sha256=. WEEKLY_GOV_PUSH_HMAC_SECRET= # Per-request timeout in ms (default 15000). WEEKLY_GOV_PUSH_TIMEOUT_MS=15000 # Max attempts including the first try (default 3). Backoff is 1s, 4s, 16s. WEEKLY_GOV_PUSH_RETRIES=3 # Tick interval in ms (default 60000). The ticker checks every minute whether it's Monday 06:00. WEEKLY_GOV_PUSH_INTERVAL_MS=60000 # Optional school identifier included in the push envelope so multiple schools can share an endpoint. WEEKLY_GOV_PUSH_SCHOOL_ID=