Environment Configuration
How config reaches the app
Locally: a .env file loaded via dotenv. In staging/production: the GitHub Actions deployment workflows (.github/workflows/{staging,production}-deployment.yaml) SSH into a GCE VM and run the app in a Docker container, passing each variable with -e KEY='${{ secrets.KEY }}' — every production env var is a GitHub Actions secret, not a committed file. There's no App Engine app.yaml in the current setup, despite older internal notes describing one — deployment is Docker-on-GCE, confirmed directly from the live workflow files.
Core
NODE_ENV=development|staging|production
PORT=8080
JWT_SECRET=...
JWT_WEB_EXPIRES_IN=7d
JWT_MOBILE_EXPIRES_IN=30d
Database & cache
DB_HOST=...
DB_USERNAME=...
DB_PASSWORD=...
DB_DATABASE=...
DB_PORT=3306
REDIS_HOST=...
REDIS_PORT=...
REDIS_PASSWORD=...
Google Cloud
GCP_PROJECT_ID=...
GCP_LOCATION=...
GCP_BUCKET_NAME=... # Cloud Storage bucket for uploads
GOOGLE_CLOUD_PROJECT=... # reused by Cloud Tasks/Scheduler/Pub-Sub client libs
GOOGLE_CLOUD_LOCATION=...
VERTEX_AI_PROJECT_ID=...
VERTEX_AI_LOCATION=...
CLOUD_TASKS_SECRET_TOKEN=... # optional extra check on top of Cloud Tasks' own headers
CLOUD_TASKS_QUEUE_NAME=...
SERVICE_URL=... # this instance's own public URL - Cloud Scheduler/Tasks call back into it
Observability (both stacks are live — see Observability)
SENTRY_DSN=... # Sentry auto-enables whenever this is set - no separate on/off flag
SENTRY_TRACES_SAMPLE_RATE=1.0 # fraction of requests traced; drop before heavy production traffic
OBSERVABILITY_ENABLED=true|false # separate master switch for Cloud Error Reporting + Profiler
OBSERVABILITY_PROFILER_ENABLED=true|false
OBSERVABILITY_SERVICE_VERSION=...
Payments & wallets
PVB_SECRET_KEY=... # PiggyVest Business
PVB_BASE_URL=...
PVB_CUSTOMER_ID=...
PVB_WALLET_ID=...
PAYSTACK_SECRET_KEY=...
PAYSTACK_PUBLIC_KEY=...
Messaging & email
TERMII_BASE_URL=... # SMS
TERMII_API_KEY=...
TERMII_SENDER_ID=...
SMTP_HOST=... SMTP_PORT=... SMTP_USER=... SMTP_PASSWORD=... # or
SES_REGION=... SES_ACCESS_KEY=... SES_ACCESS_SECRET=... # AWS SES alternative
AI / search
OPENAI_API_KEY=...
QDRANT_URL=...
QDRANT_API_KEY=...
Docs site (this site's own gating — see Architecture Overview)
DOCS_BASIC_AUTH_USER=...
DOCS_BASIC_AUTH_PASSWORD=...
Troubleshooting
- Startup fails with a missing-config error — check
src/config/env.config.tsfor what it reads before assuming a var name from an old doc is still correct; several of the above have been renamed or consolidated over time. - Cloud Tasks/Scheduler callbacks 404 or time out —
SERVICE_URLalmost certainly doesn't match the instance's actual reachable address; this is the single most common cause of "background jobs aren't running" reports. - A secret works in staging but not production (or vice versa) — each environment's secrets are configured independently in GitHub Actions; there's no shared
.envfile to diff against, only the workflow's-elist and the repo's GitHub Secrets.