Skip to content

Local dev stack — backend + postgres in Docker

Validates Prisma migrations and HTTP routes without touching prod.

One-time setup

bash
cd backend
cp .env.dev.example .env.dev      # placeholders satisfy /health gates

Edit .env.dev to fill real NewAPI / WeChat / iLink creds only if you need to exercise those code paths locally. Placeholders are enough for migration sanity-checks and route smoke tests.

Daily loop

bash
backend/scripts/dev/up.sh         # build, start, wait for /health
curl http://127.0.0.1:4000/health # follow-up checks
backend/scripts/dev/reset.sh      # wipe postgres volume when schema diverges

The postgres container binds to 127.0.0.1:5433 (host) to avoid clashing with a system Postgres on 5432. The backend binds to 127.0.0.1:4000.

Dry-run a Prisma migration against prod data

bash
backend/scripts/dev/up.sh                          # stack must be healthy
backend/scripts/dev/dry-run-migration.sh           # pg_dump prod → restore local → migrate deploy

The script SSHes to ECS via cloudflared, dumps twilight_drive, wipes the local dev DB, restores the snapshot, then runs prisma migrate deploy against the restored data. Migration breakage surfaces locally before any prod write happens.

Dump is saved at /tmp/twilight-prod-<ts>.sql for later inspection.

CI parity

.github/workflows/backend-smoke.yml runs the same flow on every PR that touches backend/:

  1. spins up postgres:16-alpine as a service
  2. npx prisma migrate deploy
  3. npx tsc --noEmit
  4. npm run build
  5. boots dist/main.js, polls /health until ok

So migration errors are caught at PR time, not at deploy time.

Pre-deploy backup (prod side)

Before applying a real migration to ECS, take a backup first:

bash
ssh -o ProxyCommand="cloudflared access ssh --hostname ssh-ecs.fsagent.cc" \
  root@ssh-ecs.fsagent.cc \
  "docker exec twilight-postgres pg_dump -U postgres twilight_drive" \
  > /tmp/twilight-backup-$(date +%s).sql

If the migration breaks, restore:

bash
ssh ... 'docker exec -i twilight-postgres psql -U postgres -d twilight_drive' \
  < /tmp/twilight-backup-<ts>.sql

Layers — what each catches

LayerCatchesWhen it runs
Local composetypos, route 500s, dev iterationevery code change
dry-run-migration.shconflicts with REAL prod databefore deploying a migration
GH Action backend-smokeregressions in PRevery PR
Pre-deploy pg_dumprollback safety netevery deploy that changes schema

Recommended discipline: run the local stack while coding, the dry-run when the PR adds a migration, and let CI catch the rest.

团队内部文档