Skip to content

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 command

Dependencies (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):

VariableRequiredNotes
SUPABASE_URLyesor PRODUCTION_SUPABASE_URL
SUPABASE_KEYyesservice_role key — server only
OAUTH_SESSION_SECRETyessession signing secret
API_KEYyes*bot key (* for bot features)
DISCORD_CLIENT_ID / DISCORD_CLIENT_SECRET / DISCORD_REDIRECT_URIfor loginDiscord OAuth app
SUPABASE_ANON_KEYfor Realtimepublic by design; served to sessions
SUPABASE_JWT_SECRETfor Realtimesigns browser Realtime tokens — server only
DISCORD_OAUTH_PROXY_URL / DISCORD_OAUTH_PROXY_SECREToptionalWorker proxy for token exchange
DASHBOARD_ORIGINyesallowlisted CORS origin(s), comma-separated
TRAINING_ORIGINoptionaldefault https://training.eccdps.org
ERLC_RELAY_URLS + ERLC_RELAY_TOKENyesproduction ER:LC relay (or ERLC_SERVER_KEY for local dev)
SESSION_COOKIE_SECURE / SESSION_COOKIE_SAMESITE / REALTIME_TOKEN_TTL_SECONDSoptionaldefaults true / Lax / 600
PRODUCTION_API_HOSTS / PRODUCTION_SESSION_COOKIE_NAMEoptionaldefaults api.eccdps.org / eccdps_production_session
PRODUCTION_INGRESS_SECRET / DEMO_INGRESS_SECREToptionalHMAC ingress assertion (see below)

Secrets are set in the Render dashboard — never in the repository.

Startup behavior

At boot the API:

  1. loads both environment configs (environment.py);
  2. fails fast if the production environment is not configured;
  3. validates ER:LC configuration (relay URLs + token, or server key) — missing configuration raises at import;
  4. 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 / returns DPS API Online and 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:

  1. curl https://api.eccdps.org/DPS API Online.
  2. Sign in to the dashboard (OAuth round-trip works).
  3. GET /auth/me returns your agent + permissions.
  4. Spot-check a read (GET /reports?limit=5) and a low-risk write.
  5. Check /admin/health sections are ok (or warn for known reasons).
  6. Verify the environment isolation: the demo ingress serves demo data and the production ingress serves production data.
  7. 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.