import 'reflect-metadata'; import helmet from 'helmet'; import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { Logger } from 'nestjs-pino'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { migrate } from 'drizzle-orm/node-postgres/migrator'; import { AppModule } from './app.module'; import { db } from './db/client'; const REQUIRED_ENV_VARS = [ 'DATABASE_URL', 'REDIS_URL', 'SUPABASE_URL', 'SUPABASE_SERVICE_ROLE_KEY', ] as const; function validateEnv(): void { const missing = REQUIRED_ENV_VARS.filter((key) => !process.env[key]); if (missing.length > 0) { throw new Error(`Missing required environment variables: ${missing.join(', ')}`); } if (!process.env.SUPABASE_JWT_SECRET) { console.warn('[WARN] SUPABASE_JWT_SECRET not set — JWT verification will use GoTrue round-trip'); } } async function bootstrap() { validateEnv(); // Apply pending DB migrations — skip if schema was pre-initialized via drizzle push try { await migrate(db, { migrationsFolder: './drizzle' }); } catch (err) { const msg = (err as Error & { message: string }).message ?? ''; if (msg.includes('already exists')) { console.warn('[bootstrap] Schema already initialized — migration skipped. Run db:migrate manually if needed.'); } else { throw err; } } const app = await NestFactory.create(AppModule, { bufferLogs: true }); app.useLogger(app.get(Logger)); app.use(helmet()); app.setGlobalPrefix('v1', { exclude: ['health'] }); app.useGlobalPipes( new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true }), ); const rawOrigins = process.env.CORS_ORIGINS ?? 'http://localhost:3000'; const allowedOrigins = rawOrigins.split(',').map((o) => o.trim()).filter(Boolean); app.enableCors({ origin: allowedOrigins, credentials: true }); if (process.env.SWAGGER_ENABLED === 'true') { const config = new DocumentBuilder() .setTitle('CEO OS API') .setVersion('0.1.0') .addBearerAuth() .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('docs', app, document); } const port = process.env.PORT ?? 3001; await app.listen(port); } bootstrap();