Backend deploys (Render Mongo + ECS Postgres)
Drape ships two FastAPI backends from Drape-AI-LLC/Drape-:
| Code | Host | Trigger |
|---|---|---|
backend/ (Mongo monolith) | Render | GitHub Actions deploy hooks (this page) |
backend-postgres/ | ECS Fargate cluster drape | Dev: push to develop (backend-postgres/**); prod: workflow_dispatch only (confirm=deploy-prod) |
The Postgres path is not Render. Live AWS resources (ALB host rules, ECR
drape-backend-postgres, RDS classifications) are on
Infrastructure and the
AWS system map. The 2026-08-31 cutover
record is Production cutover.
The rest of this page is the Mongo / Render pipeline. The rationale for gating that path is ADR-0001. Postgres env split (dev vs prod, no staging) is ADR-0002.
This is a different pipeline from the web tier (Web deploys, AWS Amplify) and the mobile app (EAS).
Postgres on ECS (summary)
| Env | Service | Trigger | Workflow / gate |
|---|---|---|---|
| Dev | drape-dev | push to develop with path filter backend-postgres/** | .github/workflows/deploy-dev.yml — AWS auth via OIDC role drape-github-deploy-role |
| Prod | drape-prod | workflow_dispatch only | required confirmation input confirm=deploy-prod |
- Images: ECR
drape-backend-postgres(tagsprod/dev). - Cluster name
drape(notdrape-prod). Servicesdrape-prodanddrape-dev. api.drape.to→ ALB host rule → prod TG.dev-api.drape.toand the ALB default action → dev TG.- Secrets inject from Secrets Manager (
drape/backend/prod-keys,drape/backend/shared-keys) — names only;DATABASE_URLhost mapping is docs-supported, not secret-read proven. RDS instance classes stay on the AWS system map:drape-postgres-prod-liveACTIVE PROD (docs-supported);drape-postgresprobable ACTIVE DEV (not API-verified);drape-postgres-prodLEGACY CANDIDATE, not approved for deletion.
Mongo on Render — the two GitHub Actions workflows
| Environment | Trigger | Gate | Workflow |
|---|---|---|---|
| Staging | push to staging (backend/**) | checks pass (auto) | deploy-staging.yml |
| Production | manual — Actions → Run workflow on main | the manual trigger + checks | deploy-production.yml |
Production is manual because GitHub Environment required-reviewer protection needs GitHub Team/Enterprise for a private repo, which this org isn't on. The manual trigger is the human gate. See ADR-0001 for the rationale and the upgrade path.
Both workflows: install deps → syntax check → critical-import check → validate_env.py
(warn-only in CI) → fire the Render deploy hook → poll /api/health until the
live commit equals the pushed short SHA (so a green result means the new code is
live, not the old instance).
One-time setup
Repo side — already done (Aug 2026): the PROD_BACKEND_URL variable is set, and
production is a manual workflow_dispatch workflow (no environment protection needed
on the current plan). Nothing else is required in GitHub for production.
Render side — the remaining step (Kenji). Until the deploy-hook secret exists, the deploy job fails fast with a clear "secret not set" message.
- Render dashboard →
drape-backend→ Settings → Deploy Hook → copy the URL. - Repo → Settings → Secrets and variables → Actions → add secret
RENDER_DEPLOY_HOOK_URL(paste the hook). (Or, from a machine withgh:gh secret set RENDER_DEPLOY_HOOK_URL --body "<hook-url>".)
For staging CD (later). Create a drape-backend-staging Render service tracking
the staging branch with its own database, then add:
| Type | Name | Value |
|---|---|---|
| Secret | RENDER_STAGING_DEPLOY_HOOK_URL | staging deploy hook |
| Variable | STAGING_BACKEND_URL | the staging service URL |
Day-to-day flow
- Branch from
main, make the backend change, open a PR intomain. CI (backend-checks.yml,predeploy.yml) runs on the PR. - Apply Supabase migrations first if the change needs them — schema leads code.
- Merge to
stagingto exercise it:deploy-staging.ymlauto-deploys on green. Smoke-test againstSTAGING_BACKEND_URL. - Merge to
main. Before deploying, confirm Supabase migrations are applied andbackend/scripts/predeploy_check.shpassed locally. - Deploy production: Actions → Deploy Production (manual) → Run workflow → branch
main. It runs the checks, fires the deploy hook, and verifies the new commit is live in/api/health. (From CLI:gh workflow run deploy-production.yml --ref main.)
Rollback
Deploys are just the deploy hook pointed at a commit. To roll back:
git revertthe bad commit onmain(or check out the last good SHA), and push.- Approve the resulting
deploy-production.ymlrun. - The health poll confirms the restored commit is live.
Render's dashboard also offers "Rollback to this deploy" on a prior successful
deploy as a faster path in an incident; follow it with the git revert so the repo
and the live service don't diverge.
Related
- Decision & rationale: ADR-0001
- Local pre-push gate:
backend/scripts/predeploy_check.sh,backend/scripts/validate_env.py - Health endpoints:
/api/health(liveness +commit),/api/health/deep(read/write checks)