dorfteich/apps/api/src/main.ts
Claude Fable 5 ca0f7cf4b1 Add Prisma with PostgreSQL, automatic migrations, and /readyz
apps/api gains Prisma (instance_settings as the first model) with the
initial migration applied automatically at startup via prisma migrate
deploy, a lazy-connecting PrismaService, and GET /api/v1/readyz
reporting named checks (database reachable, migrations applied) with
200/503. DATABASE_URL joins the validated environment schema;
MIGRATE_ON_START=false skips deploys for tests and tooling. An
idempotent seed script and a Compose dev overlay with PostgreSQL
(host port 5434 — 5433 is taken locally) complete the loop.

Closes #3

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:16:44 +02:00

40 lines
1.4 KiB
TypeScript

import { execFileSync } from 'node:child_process';
import { NestFactory } from '@nestjs/core';
import { apiEnvSchema, parseEnv } from '@dorfteich/shared';
import { Logger } from 'nestjs-pino';
import { AppModule } from './app.module';
import { AppConfig } from './config/app-config.service';
/**
* Apply pending migrations before the application accepts traffic, so
* self-hosters update by simply pulling a new image (ADR 0002). Prisma
* serializes concurrent deploys with a database advisory lock.
*/
function runMigrations(): void {
const prismaCli = require.resolve('prisma/build/index.js');
execFileSync(process.execPath, [prismaCli, 'migrate', 'deploy'], { stdio: 'inherit' });
}
async function bootstrap(): Promise<void> {
// Validate the environment before doing anything with it; this throws a
// readable list of problems and prevents a half-started process.
const env = parseEnv(apiEnvSchema, process.env);
if (env.MIGRATE_ON_START) {
runMigrations();
}
// bufferLogs holds early log lines until the pino logger is attached,
// so even bootstrap errors come out as structured JSON.
const app = await NestFactory.create(AppModule, { bufferLogs: true });
app.useLogger(app.get(Logger));
app.setGlobalPrefix('api/v1');
app.enableShutdownHooks();
const config = app.get(AppConfig);
await app.listen(config.env.PORT);
}
void bootstrap();