Backend evolution: Mongo → Postgres
The single most important thing to understand about Drape's architecture right now is that there are two backend generations running in parallel, and the platform is mid-migration between them.
Where each lives
| Generation 1 (Mongo) | Generation 2 (Postgres) | |
|---|---|---|
| Branch | main | develop, staging |
| Code | backend/server.py (one ~8,900-line file) | backend-postgres/ (modular) |
| Datastore | MongoDB (motor/pymongo) | PostgreSQL (asyncpg, DATABASE_URL) |
| Deploy | Render — drape-backend-avjg.onrender.com | ECS Fargate on cluster drape — api.drape.to (prod) / dev-api.drape.to (dev) |
| Consumers | The Expo mobile app | The marketing, brand, and admin web surfaces |
| Schema | Implicit (documents) | Explicit — 30 ordered database/migrations/*.sql |
What the Postgres backend adds
backend-postgres/ is not a like-for-like port — it is a re-architecture. It
is modular where the monolith is one file (server.py + config.py + clients.py
dependencies.py+database/connection.py+ ahelpers/package), and it carries features the Mongo backend never had:
- RBAC brand teams — roles, invites, permissions (
helpers/brand_roles.py,brand_team_invites.py,brand_permissions.py; migrations 018, 021). - Brand integrations & webhooks (
helpers/brand_webhooks.py,integrations_catalog.py; migration 023). - Live streaming via Mux (
helpers/mux_live.py). - Explore / social with realtime and comment moderation
(
helpers/explore_realtime.py; migrations 024, 029, 030). - In-store payments and store locations (migrations 020, 022).
- Admin email campaigns — templates, bulk send, inbound mailbox
(
helpers/admin_email.py,admin_inbound.py; migrations 016, 017). - Engagement — drops v2, stock waitlists, price alerts
(
helpers/price_alerts.py; migrations 026–028). - Order fulfillment and plan enforcement (
helpers/order_fulfillment.py,plan_enforcement.py; migrations 008, 009).
The ordered migration series (004 → 030) is effectively the changelog of the Postgres backend's feature build-out.
The data migration
backend/scripts/migrate_mongo_to_postgres.py (on develop/staging) is the
one-way data mover: it opens both a motor MongoDB client and an asyncpg
Postgres pool and copies collections (stores, users, products, orders, …) from the
fitpreview_db Mongo database into the Postgres schema.
DATABASE_URL=<postgres-url> MONGO_URL=<mongo-url> DB_NAME=fitpreview_db \
python backend/scripts/migrate_mongo_to_postgres.py
The honest status
The web tier is already live on the Postgres backend (brand.drape.to accepts
applications and logins today). The mobile app is still on the MongoDB monolith
in production (drape-backend-avjg.onrender.com). Postgres code lives in
backend-postgres/ on Drape-AI-LLC/Drape-; develop auto-deploys ECS
drape-dev, and prod is workflow_dispatch to ECS drape-prod.
This means Drape is running two backend generations at once, on two hosts: Render (Mongo) and AWS ECS/RDS (Postgres). Before treating any single backend as canonical, verify which host a surface calls. The rest of the architecture section documents the MongoDB backend (the one the shipped mobile app depends on) as the baseline, and flags Postgres-only capabilities where they matter.
Why this is the right frame
For a solo-founder platform, standing up the newer, richer capabilities (marketplace teams, integrations, live, social) on a relational schema while keeping the proven Mongo backend serving the shipped app is a pragmatic strangler-fig migration — the web tier leads, the mobile app follows once the Postgres backend reaches parity on the try-on path. The risk to manage is exactly the one above: clarity about which backend owns which surface at any moment. See System overview for how this maps across surfaces, Infrastructure for hosts, and Backend (MongoDB) for the generation the mobile app runs on.