Appearance
Backend Deployment
Build/deploy process
The API is a Python Flask application deployed to Render as a web service. The repository contains no Render manifest; the service is configured in the Render dashboard and auto-deploys from main (per TRAINING_DEPLOYMENT.md and ENVIRONMENT_DEPLOYMENT.md). The deploy command is effectively:
bash
pip install -r requirements.txt
gunicorn app:app # Render web service start commandDependencies (requirements.txt): Flask, gunicorn, supabase, postgrest, PyJWT (declared explicitly because app.py imports jwt directly for Realtime token minting).
Environment variables
Configure the web service's environment in the Render dashboard. Production variables (legacy names; PRODUCTION_* overrides exist — see Environment variables reference):
| Variable | Required | Notes |
|---|---|---|
SUPABASE_URL | yes | or PRODUCTION_SUPABASE_URL |
SUPABASE_KEY | yes | service_role key — server only |
OAUTH_SESSION_SECRET | yes | session signing secret |
API_KEY | yes* | bot key (* for bot features) |
DISCORD_CLIENT_ID / DISCORD_CLIENT_SECRET / DISCORD_REDIRECT_URI | for login | Discord OAuth app |
SUPABASE_ANON_KEY | for Realtime | public by design; served to sessions |
SUPABASE_JWT_SECRET | for Realtime | signs browser Realtime tokens — server only |
DISCORD_OAUTH_PROXY_URL / DISCORD_OAUTH_PROXY_SECRET | optional | Worker proxy for token exchange |
DASHBOARD_ORIGIN | yes | allowlisted CORS origin(s), comma-separated |
TRAINING_ORIGIN | optional | default https://training.eccdps.org |
ERLC_RELAY_URLS + ERLC_RELAY_TOKEN | yes | production ER:LC relay (or ERLC_SERVER_KEY for local dev) |
SESSION_COOKIE_SECURE / SESSION_COOKIE_SAMESITE / REALTIME_TOKEN_TTL_SECONDS | optional | defaults true / Lax / 600 |
PRODUCTION_API_HOSTS / PRODUCTION_SESSION_COOKIE_NAME | optional | defaults api.eccdps.org / eccdps_production_session |
PRODUCTION_INGRESS_SECRET / DEMO_INGRESS_SECRET | optional | HMAC ingress assertion (see below) |
Secrets are set in the Render dashboard — never in the repository.
Startup behavior
At boot the API:
- loads both environment configs (
environment.py); - fails fast if the production environment is not configured;
- validates ER:LC configuration (relay URLs + token, or server key) — missing configuration raises at import;
- starts the optional demo auto-reset scheduler (
DEMO_AUTO_RESET_ENABLED).
Per request, the environment is resolved from the ingress hostname; unknown hosts fail closed with 503.
Health checks
- Liveness:
GET /returnsDPS API Onlineand is exempt from environment resolution so Render probes work even when they bypass the trusted ingress. - Deep health:
GET /admin/health(admin panel, Lead Agent+) returns the 10-section status payload (overall/database/api/actions/queue/agents/ evidence/auth/audit/events) plus incident history. It is the operational health surface, not the Render probe.
Deployment verification
After a deploy:
curl https://api.eccdps.org/→DPS API Online.- Sign in to the dashboard (OAuth round-trip works).
GET /auth/mereturns your agent + permissions.- Spot-check a read (
GET /reports?limit=5) and a low-risk write. - Check
/admin/healthsections are ok (or warn for known reasons). - Verify the environment isolation: the demo ingress serves demo data and the production ingress serves production data.
- Run the production smoke test.
Ingress and environment routing
api.eccdps.org → production, demo-api.eccdps.org → demo, everything else → 503. The direct Render hostname is not a valid environment and returns 503 for data routes; restrict direct access at the infrastructure level.
The optional signed-ingress hardening (cloudflare/ingress_worker.js + *_INGRESS_SECRET) is not currently active (see Environments for the O2O constraint and the re-enable steps documented in ENVIRONMENT_DEPLOYMENT.md §3). Current trust model: server-side hostname resolution, fail closed.
Rollback
Render supports redeploying a previous deploy. Because the API is deployed after its migrations, rollback of the API alone is safe only when the previous code is compatible with the current schema — migrations are written backward-compatible (defaulted parameters, additive columns), so reverting a deploy usually works, but verify the affected endpoints after rollback.