Deployment
Compose files
Local (loads docker-compose.override.yml, which publishes Postgres on 55432):
docker compose up -d --build
Production — base file only, so the Postgres host port is not published:
docker compose -f docker-compose.yml up -d --build
| Service | Port |
|---|---|
| Portal | 3000 |
| Gateway | 8080 |
| Docs | 3002 |
| Database | internal only in production |
| Redis | internal only |
Hard requirements
AUTH_DEV_BYPASSmust be unset orfalsein production- TLS: gateway and portal speak plain HTTP and must sit behind a TLS-terminating reverse proxy. The gateway streams SSE — disable proxy response buffering and allow long response times for
/v1/chat/completions - Redis has no authentication in compose. Keep it on the internal network, or set a password/TLS via
REDIS_URL - Do not reuse any values from a developer's local
.env
Database migrations
The portal applies pending database migrations automatically on startup. A normal deploy needs no manual database step.
If you see a missing-column (or missing-table) error after a deploy, pull the latest release — it must include the matching migration — and redeploy. Never patch the database by hand. Migrations are forward-only; rollbacks ship as new migrations.
Probes
| Endpoint | Use |
|---|---|
GET /health/liveliness | Liveness — process is up |
GET /health/readiness | Readiness — Postgres, and Redis when REDIS_URL is set |
Invite emails (SMTP)
SMTP_HOST=smtp.office365.com
SMTP_PORT=587
SMTP_USER=zeallm@zealogics.com
SMTP_PASS=<app password>
SMTP_FROM=zeallm@zealogics.com
Without SMTP_HOST, invites still create the account.
Microsoft Entra ID SSO
- Azure portal → App registration (single tenant)
- Web redirect URI:
https://<host>/api/auth/callback/microsoft-entra-id(local:http://localhost:3000/api/auth/callback/microsoft-entra-id) - Set
AZURE_AD_CLIENT_ID,AZURE_AD_CLIENT_SECRET,AZURE_AD_TENANT_ID,ZEALLM_ALLOWED_DOMAIN,ZEALLM_ADMIN_EMAILS AUTH_DEV_BYPASS=false
The “Continue with Microsoft” button appears once all three AZURE_AD_* vars are set. Default openid profile email scopes are enough.
Load testing
A load-test script lives in loadtest/. Point it at the gateway URL, a revealed virtual key, and a model the key can access.