Run the whole stack in Docker

- API and web images built with turbo prune; the API image also runs the
  worker and migrations. Non-root, health-checked, Debian slim.
- docker compose up -d --build starts Postgres, Redis (persistent), a
  one-shot migrate job, API, worker and web, in dependency order.
- Fix the API production build (tsup flags moved to a config file) and
  bundle the migration script; silence Postgres NOTICE noise.
- npm run infra:up now starts only Postgres and Redis for hot-reload dev.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
This commit is contained in:
2026-10-03 16:02:38 -04:00
co-authored by Claude Opus 5.5
parent ece9c4fd64
commit 6317004004
12 changed files with 214 additions and 8 deletions
+2 -1
View File
@@ -3,6 +3,7 @@ import postgres from 'postgres';
import { env } from '../env';
import * as schema from './schema';
export const sql = postgres(env.DATABASE_URL, { max: 10 });
// onnotice: silence harmless NOTICEs (e.g. "schema already exists" on every migrate run)
export const sql = postgres(env.DATABASE_URL, { max: 10, onnotice: () => {} });
export const db = drizzle(sql, { schema });
export { schema };
+5 -1
View File
@@ -1,6 +1,10 @@
import { fileURLToPath } from 'node:url';
import { migrate } from 'drizzle-orm/postgres-js/migrator';
import { db, sql } from './index';
await migrate(db, { migrationsFolder: new URL('../../drizzle', import.meta.url).pathname });
// In the Docker image the bundled script lives in dist/, so the folder is passed explicitly.
const migrationsFolder = process.env.MIGRATIONS_DIR ?? fileURLToPath(new URL('../../drizzle', import.meta.url));
await migrate(db, { migrationsFolder });
console.log('migrations applied');
await sql.end();