# AWS Express Mode — Zendo (one ZIP, one container)

Express Mode expects **one source bundle → one Dockerfile → one HTTP service**. Zendo is already structured for that.

## What the ZIP contains

The full monorepo (`zendo-deploy.zip`):

- **Frontend source** (`app/`, `components/`, `lib/`, …) — built during Docker image build
- **Backend source** (`backend/`) — Bun API, tRPC, GraphQL, webhooks
- **Root `Dockerfile`** — builds web → `dist/`, then starts API + serves static files

Express Mode does **not** run mobile, workers, or multiple processes. It runs **one container** that:

1. Builds the Expo web export into `dist/`
2. Starts `backend/server.ts` (Bun) on **`0.0.0.0:8080`**
3. Serves `/` from `dist/` when `SERVE_WEB=true` (set in Dockerfile)
4. Serves API at `/api/trpc`, `/graphql`, `/admin-api`, `/webhooks/stripe`

## Deploy steps

1. Download / build **`zendo-deploy.zip`** (`npm run package:deploy` from the repo).

2. In **AWS Express Mode** → **Deploy from source bundle** → upload the ZIP.

3. Express Mode detects the root **`Dockerfile`** and builds on Fargate.

4. Configure **environment variables** (Console or CLI):

| Variable | Value |
|----------|--------|
| `JWT_SECRET` | 32+ char random string |
| `DATABASE_URL` | RDS / Aurora Postgres connection string |
| `STRIPE_SECRET_KEY` | From Stripe Dashboard |
| `STRIPE_WEBHOOK_SECRET` | From Stripe webhook |
| `CORS_ORIGINS` | Your Express Mode HTTPS URL |
| `SERVE_WEB` | `true` (already in Dockerfile) |
| `PORT` | `8080` (Express Mode may set this automatically) |

5. **Health check** (Express Mode / target group):

| Setting | Value |
|---------|--------|
| Path | `/api/health` |
| Port | `8080` |
| Success | HTTP 200 JSON `{ "status": "ok" }` |

6. **Postgres (separate from ZIP)** — create **RDS** or **Aurora Serverless v2**, then set:

```
DATABASE_URL=postgresql://user:pass@your-rds-host:5432/zendo
```

SQL migrations in `backend/db/migrations/` run on container start when `DATABASE_URL` is set.

For file-backed dev/single-user data (not recommended at scale), use EFS or skip and use Postgres only.

## Architecture

```
Users → Express Mode (HTTPS + ALB + autoscale)
           └── Fargate task (1 container)
                 ├── :8080 Bun API (backend/server.ts)
                 ├── /           → dist/index.html (Expo web)
                 └── /api/trpc   → tRPC
           └── RDS Postgres (DATABASE_URL env)
```

## Same-origin (recommended)

Leave `EXPO_PUBLIC_API_BASE_URL` empty at build time (default in Dockerfile). The web app uses the same HTTPS host as the API — no CORS issues.

## Stripe webhook

After Express Mode assigns your URL:

```
https://YOUR-EXPRESS-MODE-DOMAIN/webhooks/stripe
```

## What NOT to do in Express Mode

- Do not run `docker-compose.yml` inside Express Mode (that's for self-managed VPS / Vultr / Oracle).
- Do not deploy API-only and web-only as two Express Mode services from the same ZIP without changing the Dockerfile.
- Do not put Postgres inside the container — use RDS.

## Local test (same image Express Mode builds)

```bash
unzip zendo-deploy.zip -d zendo
cd zendo
docker build -t zendo-express .
docker run -p 8080:8080 -e JWT_SECRET=test -e DATABASE_URL=... zendo-express
open http://localhost:8080
curl http://localhost:8080/api/health
```

## Files Express Mode cares about

| File | Role |
|------|------|
| `Dockerfile` | Build web + run API on 8080 |
| `backend/server.ts` | Container entry (via `bun run server.ts`) |
| `backend/bun.lock` | Stable API dependency install |
| `package.json` + `package-lock.json` | Frontend build only (Node stage) |
