# 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.

```mermaid
graph TB
    subgraph "Generation 1 — MongoDB monolith (main)"
        Mono["backend/server.py<br/>~8,900-line FastAPI monolith<br/>motor / pymongo"]
    end
    subgraph "Generation 2 — Postgres backend (develop / staging)"
        PG["backend-postgres/<br/>modular FastAPI + helpers/<br/>asyncpg · 30 SQL migrations"]
    end

    Mobile["Mobile app<br/>Drape- / frontend"] --> Mono
    Web["Web tier<br/>marketing · brand · admin"] --> PG
    Mono -->|"one-way data migration"| PG
```

## 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` + a `helpers/` 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.

```text
DATABASE_URL=<postgres-url>  MONGO_URL=<mongo-url>  DB_NAME=fitpreview_db \
  python backend/scripts/migrate_mongo_to_postgres.py
```

## The honest status

:::warning[Two generations, one in-flight cut-over]
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](./system-overview.md) for how this maps across surfaces,
[Infrastructure](./infrastructure.md) for hosts, and
[Backend (MongoDB)](./backend.md) for the generation the mobile app runs on.
