Repository navigation
feat(deploy): Render deployment — unified app, admin key, render.yaml - #5
Conversation
…, single-role DB
Replaces the EC2/Caddy plan with Render free tier deployment.
Changes:
app.py — unified ASGI entrypoint serving all three services on one port.
Admin key middleware (X-Admin-Key) protects non-public routes.
Checkout routes moved to /pay prefix to avoid /{link_id} wildcard collision.
Public: /health, /webhooks/*, /pay/*
Protected: /links, /merchants/*, /internal/*
render.yaml — Blueprint: one Docker web service (free) + Postgres (free).
Secrets declared sync:false. Migrations run at container start.
db/render_bootstrap.sh — startup script: wait for Postgres, run Alembic.
No role creation (Render = single DB user, not superuser).
db/migrations/012 + alembic/0006 — conditional RLS adaptation.
Rewrites payout_accounts policies from confam_app-specific to PUBLIC
only when confam_app role does not exist (Render deployments).
Append-only trigger and FORCE RLS preserved.
DEPLOYMENT.md — rewritten for Render: Blueprint setup, secrets, webhook
URL updates, admin endpoint usage, free-tier constraints (sleep,
Postgres 30-day expiry), pinger workaround documented honestly.
Removed EC2 artifacts: Caddyfile, docker-compose.prod.yml, scripts/ec2_setup.sh
Step 0 findings documented:
- PR #2/#3 merged to main ✓
- REGISTER/ONBOARD safe (HMAC-gated Meta webhook) ✓
- Render Postgres: no superuser, single-role deployment, known gap documented
114 tests passing (9 new for unified app + admin key).
DevSolex
left a comment
There was a problem hiding this comment.
Reviewed and approved.
app.py: route layout correct — /pay prefix prevents the /{link_id} wildcard from swallowing webhook and admin routes. Admin key middleware uses constant-time comparison, fails closed when ADMIN_API_KEY unset. Public route list matches spec exactly.
render.yaml: single free web service + free Postgres, secrets sync:false, health check path correct, start command runs bootstrap before uvicorn.
Migration 012: conditional on confam_app role absence — safe to apply on both local and Render without side effects. FORCE RLS preserved. Append-only trigger unaffected.
render_bootstrap.sh: waits for Postgres (Python loop, no psql dependency), sets ALEMBIC_DATABASE_URL from DATABASE_URL, runs alembic upgrade head.
DEPLOYMENT.md: free-tier constraints documented honestly including the 30-day Postgres expiry and the sleep workaround.
114 tests passing. Ready to merge.
Summary
Deploys ConFam to Render free tier for pilot testing (~5 WhatsApp testers).
Step 0 findings
Changes
app.py— unified ASGI entrypoint:X-Admin-Keyheader required for non-public routes. Constant-time comparison.ADMIN_API_KEYunset → 503 (fail closed)./payprefix to avoid/{link_id}wildcard collision/health,/webhooks/*,/pay/*/links,/merchants/*,/internal/*render.yaml— Blueprint: one Docker web service (free) + Postgres (free). Secretssync:false. Migrations at container start.db/render_bootstrap.sh— startup: wait for Postgres, runalembic upgrade head. No role creation (Render = no superuser).db/migrations/012— conditional RLS adaptation. Rewritespayout_accountspolicies fromconfam_app-specific toPUBLICwhen the role doesn't exist. Append-only trigger preserved.DEPLOYMENT.md— Render-specific: Blueprint setup, secrets, webhook URL updates, admin endpoint usage, free-tier constraints (sleep workaround, 30-day Postgres expiry).Removed:
Caddyfile,docker-compose.prod.yml,scripts/ec2_setup.shTests
114 passing (9 new: health, admin key missing/wrong/correct/unset, public routes, /pay prefix, all three services respond)