import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { Logger } from '@nestjs/common'; import { WinstonModule } from 'nest-winston'; import { configureApp, GLOBAL_PREFIX } from '@/app.setup'; import { isSwaggerEnabled, setupSwagger, SWAGGER_PATH, } from '@/shared/config/swagger.config'; import { winstonConfig } from '@/shared/logger/winston.config'; import { parsePositiveInt } from '@/shared/utils/env'; /** 루트 .env 에 BACKEND_PORT 가 없을 때만 쓰는 기본 포트 */ const DEFAULT_PORT = 3000; async function bootstrap() { const app = await NestFactory.create(AppModule, { logger: WinstonModule.createLogger(winstonConfig), }); // 보안 헤더·CORS·prefix·검증 파이프·응답 래퍼 등 전역 설정 — e2e 테스트와 같은 함수를 쓴다 (app.setup.ts) configureApp(app); // Swagger API 문서 — 운영에서는 기본으로 끈다 (shared/config/swagger.config.ts) const swaggerEnabled = isSwaggerEnabled(); if (swaggerEnabled) setupSwagger(app); // Graceful shutdown — SIGTERM 수신 시 새 요청을 받지 않고 // 처리 중인 요청을 마친 뒤 DB/Redis 커넥션을 정리하고 종료한다. // (이 설정이 없으면 배포·재시작 때 처리 중이던 요청이 그대로 끊긴다) app.enableShutdownHooks(); // 종료 로그는 ShutdownLogger(OnApplicationShutdown)가 남긴다. // compose 가 미정의 변수를 빈 문자열로 주입하므로 parsePositiveInt 로 방어한다 (Number('') 는 0 → 임의 포트) const port = parsePositiveInt(process.env.PORT, DEFAULT_PORT); await app.listen(port, '0.0.0.0'); Logger.log( `🚀 Backend running on http://localhost:${port}/${GLOBAL_PREFIX}`, 'Bootstrap', ); if (swaggerEnabled) { Logger.log( `📘 Swagger docs at http://localhost:${port}/${SWAGGER_PATH}`, 'Bootstrap', ); } } void bootstrap();