Environment variables
All variables are validated at startup by the backend (@nestjs/config + Joi).
Credentials are never committed — only the shape is documented here.
Backend (shell-backend)
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | yes | PostgreSQL connection string |
REDIS_URL | yes | Redis connection string |
FIREBASE_PROJECT_ID | yes in practice | Firebase project id. Without a service-account cert this is what the Admin SDK is initialised with; with neither, every verifyIdToken fails and all authenticated routes answer 401 |
FIREBASE_CLIENT_EMAIL | — | Admin SDK service account email |
FIREBASE_PRIVATE_KEY | — | Admin SDK private key (PEM) |
SENTRY_DSN | — | Self-hosted Sentry DSN; init is skipped when absent. Must be a real DSN (scheme://publicKey@host/projectId) — passing the ingest endpoint URL instead is rejected with Invalid Sentry Dsn and nothing is reported |
SENTRY_ENVIRONMENT | — | production / staging / development |
PORT | — | HTTP port (default 3000) |
CORS_ORIGIN | — | Allowed origin(s), comma-separated |
AUDIT_WORKER_ENABLED | — | true to run the BullMQ worker in-pod |
SWAGGER_ENABLED | — | Serves /api + /api-json as one unit. Unset => on unless NODE_ENV is production/staging |
REDIS_HOST / REDIS_PORT | — | Alternative to REDIS_URL; used only when REDIS_URL is unset |
FIREBASE_AUTH_EMULATOR_HOST | — | Read by firebase-admin itself; e.g. 127.0.0.1:9099 |
OTEL_EXPORTER_OTLP_ENDPOINT | — | Enables OpenTelemetry tracing when set |
S3_ENDPOINT | — | S3-compatible object storage endpoint (MinIO locally, DigitalOcean Spaces in cloud) |
S3_BUCKET | — | Object storage bucket name |
S3_ACCESS_KEY | — | Object storage access key id |
S3_SECRET_KEY | — | Object storage secret access key |
SMTP_HOST | — | Outbound SMTP host (Mailpit locally, SendGrid SMTP in cloud) |
SMTP_PORT | — | Outbound SMTP port (1025 for Mailpit) |
SENDGRID_API_BASE_URL | — | Base URL of the SendGrid HTTP API (WireMock on :9090 locally) |
SENDGRID_API_KEY | — | SendGrid API key with Mail Send permission |
REDIS_URL accepts rediss:// for a TLS endpoint; the scheme is what switches
the client into TLS mode.
Frontend (shell-frontend, VITE_-prefixed)
| Variable | Description |
|---|---|
VITE_API_BASE_URL | Shell API base URL (default http://localhost:3000) |
VITE_MFE1_REMOTE_URL | Product One remote entry URL |
VITE_MFE2_REMOTE_URL | Product Two remote entry URL |
VITE_FIREBASE_API_KEY | Firebase web API key. Blank (and no emulator host) leaves the shell rendering but with sign-in disabled and a "not configured" banner |
VITE_FIREBASE_AUTH_DOMAIN | Firebase auth domain, e.g. chrono-dev.firebaseapp.com |
VITE_FIREBASE_PROJECT_ID | Firebase project id; also shown as the tenant in the sidebar footer |
VITE_FIREBASE_APP_ID | Firebase web app id |
VITE_SENTRY_DSN | Sentry DSN; skip init if absent |
VITE_SENTRY_ENVIRONMENT | Sentry environment tag; production lowers the trace sample rate |
VITE_FIREBASE_AUTH_EMULATOR_HOST | e.g. 127.0.0.1:9099 — points the browser session at the Firebase Auth emulator |
Every VITE_* value is baked into the bundle at build time — changing one
needs a rebuild (locally, a dev-server restart), and the nginx runtime
environment of the shipped image cannot override it.
An empty string counts as unset for all of them: the shell falls back to the documented default rather than running on an empty URL or key.
A copy of the full annotated list lives in .env.example at the repository
root.