import * as _cluster from 'node:cluster'; import * as os from 'node:os'; import { NestFactory } from '@nestjs/core'; import { ValidationPipe } from '@nestjs/common'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { AppModule } from './app.module'; const cluster = _cluster as any; // Cast to 'any' bypasses the missing property errors const isProduction = process.env.NODE_ENV === 'production'; // --------------------------------------------------------------------------- // Clustering — fork one worker per CPU core in production // --------------------------------------------------------------------------- const WORKERS = isProduction ? Math.min(os.cpus().length, 4) // cap at 4 workers to stay within DB pool : 1; // single process in dev if (WORKERS > 1 && cluster.isPrimary) { console.log(`Primary ${process.pid} forking ${WORKERS} workers ...`); for (let i = 0; i < WORKERS; i++) { cluster.fork(); } cluster.on('exit', (worker: any, code: number) => { console.warn(`Worker ${worker.process.pid} exited (code ${code}), restarting ...`); cluster.fork(); }); } else { bootstrap(); } // --------------------------------------------------------------------------- // NestJS bootstrap // --------------------------------------------------------------------------- async function bootstrap() { const app = await NestFactory.create(AppModule, { logger: isProduction ? ['error', 'warn', 'log'] : ['error', 'warn', 'log', 'debug', 'verbose'], }); app.setGlobalPrefix('api'); // Request logging — only in development (too noisy / slow for prod) if (!isProduction) { app.use((req: any, _res: any, next: any) => { console.log(`[REQ] ${req.method} ${req.url} auth=${req.headers.authorization ? 'yes' : 'no'}`); next(); }); } app.useGlobalPipes( new ValidationPipe({ whitelist: false, forbidNonWhitelisted: false, transform: true, }), ); // CORS — in production nginx handles this; accept all origins behind the proxy app.enableCors({ origin: isProduction ? true : ['http://localhost', 'http://localhost:5173'], credentials: true, }); // Swagger docs — available in all environments const config = new DocumentBuilder() .setTitle('HOA LedgerIQ API') .setDescription('API for the HOA LedgerIQ') .setVersion('2026.3.7') .addBearerAuth() .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api/docs', app, document); await app.listen(3000); console.log(`Backend worker ${process.pid} listening on port 3000`); }