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>
40 lines
1.4 KiB
TypeScript
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();
|