11import 'reflect-metadata' ;
2- import express , { Application } from 'express' ;
2+ import express , { Application , Request , Response , NextFunction } from 'express' ;
33import dotenv from 'dotenv' ;
44import cors from 'cors' ;
55import cookieParser from 'cookie-parser' ;
6- import router from './routes' ;
76import swaggerUi from 'swagger-ui-express' ;
87import swaggerJSDoc from 'swagger-jsdoc' ;
8+
9+ import logger from '@/configs/logger.config' ;
10+ import router from '@/routes' ;
11+ import { NotFoundError } from '@/exception' ;
12+
913import { options } from '@/configs/swagger.config' ;
10- import { errorHandlingMiddleware } from './middlewares/errorHandling.middleware' ;
11- import { NotFoundError } from './exception' ;
1214import { initSentry } from '@/configs/sentry.config' ;
15+ import { initCache } from '@/configs/cache.config' ;
16+ import { errorHandlingMiddleware } from '@/middlewares/errorHandling.middleware' ;
1317
1418dotenv . config ( ) ;
1519
16- // Sentry 초기화
17- initSentry ( ) ;
20+ initSentry ( ) ; // Sentry 초기화
21+ initCache ( ) ; // Redis 캐시 초기화
1822
1923const app : Application = express ( ) ;
24+
2025// 실제 클라이언트 IP를 알기 위한 trust proxy 설정
21- app . set ( 'trust proxy' , true ) ;
26+ app . set ( 'trust proxy' , process . env . NODE_ENV === 'production' ) ;
27+
2228const swaggerSpec = swaggerJSDoc ( options ) ;
2329
2430app . use ( cookieParser ( ) ) ;
25- app . use ( express . json ( ) ) ;
26- app . use ( express . urlencoded ( { extended : true } ) ) ;
31+ app . use ( express . json ( { limit : '10mb' } ) ) ; // 파일 업로드 대비
32+ app . use ( express . urlencoded ( { extended : true , limit : '10mb' } ) ) ;
33+
2734app . use (
2835 cors ( {
29- origin : process . env . NODE_ENV === 'production' ? process . env . ALLOWED_ORIGINS ?. split ( ',' ) : 'http://localhost:3000' ,
36+ origin : process . env . NODE_ENV === 'production'
37+ ? process . env . ALLOWED_ORIGINS ?. split ( ',' ) . map ( origin => origin . trim ( ) )
38+ : 'http://localhost:3000' ,
3039 methods : [ 'GET' , 'POST' ] ,
3140 allowedHeaders : [ 'Content-Type' , 'Authorization' , 'Cookie' , 'access_token' , 'refresh_token' ] ,
3241 credentials : true ,
3342 } ) ,
3443) ;
3544
36- app . use ( '/api-docs' , swaggerUi . serve , swaggerUi . setup ( swaggerSpec ) ) ;
45+ // 헬스체크 엔드포인트
46+ app . get ( '/health' , async ( req : Request , res : Response ) => {
47+ // 기본 정보
48+ const healthData = {
49+ status : 'OK' ,
50+ timestamp : new Date ( ) . toISOString ( ) ,
51+ uptime : process . uptime ( ) ,
52+ environment : process . env . NODE_ENV ,
53+ services : {
54+ sentry : false ,
55+ cache : false
56+ }
57+ } ;
58+
59+ // Sentry 상태 확인
60+ try {
61+ const { getSentryStatus } = await import ( './configs/sentry.config.ts' ) ;
62+ healthData . services . sentry = getSentryStatus ( ) ;
63+ } catch ( error ) {
64+ healthData . services . sentry = false ;
65+ logger . error ( 'Failed to health check for sentry:' , error ) ;
66+ }
67+
68+ // Cache 상태 확인
69+ try {
70+ const { getCacheStatus } = await import ( './configs/cache.config.ts' ) ;
71+ healthData . services . cache = await getCacheStatus ( ) ;
72+ } catch ( error ) {
73+ healthData . services . cache = false ;
74+ logger . error ( 'Failed to health check for cache:' , error ) ;
75+ }
76+
77+ res . status ( 200 ) . json ( healthData ) ;
78+ } ) ;
79+
80+ // Swagger는 개발 환경에서만
81+ if ( process . env . NODE_ENV !== 'production' ) {
82+ app . use ( '/api-docs' , swaggerUi . serve , swaggerUi . setup ( swaggerSpec ) ) ;
83+ }
84+
3785app . use ( '/api' , router ) ;
38- app . use ( ( req ) => {
39- throw new NotFoundError ( `${ req . url } not found` ) ;
86+
87+ // 404 에러 핸들링 수정 (throw 대신 next 사용)
88+ app . use ( ( req : Request , res : Response , next : NextFunction ) => {
89+ next ( new NotFoundError ( `${ req . url } not found` ) ) ;
4090} ) ;
4191
4292app . use ( errorHandlingMiddleware ) ;
4393
44- export default app ;
94+ export default app ;
0 commit comments