index.js를 605줄에서 128줄로 축소 (79% 감소) 미들웨어, 라우트, 데이터베이스 설정을 별도 파일로 분리하여 코드 가독성 및 유지보수성 대폭 향상 주요 변경사항: 신규 파일 (3개): - config/database.js: DB 연결 풀 관리 (dbPool.js에서 이동) * 환경 변수 기반 설정 * 자동 재연결 로직 (최대 5회 재시도) * UTF-8MB4 문자셋 지원 * logger 통합 - config/middleware.js: 미들웨어 중앙 관리 * Helmet 보안 헤더 (security.js 사용) * CORS 설정 (cors.js 사용) * Compression (성능 최적화) * Body parser (50MB 제한) * 정적 파일 서빙 (public, uploads) * Response formatter - config/routes.js: 라우트 중앙 관리 * 모든 라우터 import 및 등록 * Rate limiting 설정 (login, API) * 인증 미들웨어 적용 * 공개 경로 관리 * Swagger 문서 설정 수정 파일 (2개): - index.js: 605줄 → 128줄 (79% 감소) * 간결한 서버 초기화 로직 * setupMiddlewares/setupRoutes 함수 사용 * Graceful shutdown 유지 * 에러 핸들러 유지 * 캐시 초기화 로직 유지 - dbPool.js: 호환성 레거시 파일로 전환 * config/database.js로 위임 * @deprecated 주석 추가 * 기존 코드 하위 호환성 유지 (22개 파일에서 사용 중) 파일 통계: - 3개 파일 추가, 2개 파일 수정 - +92 -621 (net -529 lines) - index.js: 605 → 128 lines (-477 lines, -79%) 검증 필요 사항: - [ ] 서버 정상 시작 확인 - [ ] 모든 API 엔드포인트 동작 확인 - [ ] CORS 설정 동작 확인 - [ ] 인증 미들웨어 동작 확인 - [ ] Rate limiting 동작 확인 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
129 lines
3.6 KiB
JavaScript
129 lines
3.6 KiB
JavaScript
/**
|
|
* TK-FB-Project API Server
|
|
*
|
|
* 작업 관리 시스템의 메인 서버 애플리케이션
|
|
*
|
|
* @author TK-FB-Project
|
|
* @since 2025-12-11
|
|
* @version 2.2.0
|
|
*/
|
|
|
|
require('dotenv').config();
|
|
const express = require('express');
|
|
const setupMiddlewares = require('./config/middleware');
|
|
const setupRoutes = require('./config/routes');
|
|
const { errorHandler } = require('./middlewares/errorHandler');
|
|
const logger = require('./utils/logger');
|
|
const cache = require('./utils/cache');
|
|
|
|
const app = express();
|
|
const PORT = process.env.PORT || 20005;
|
|
|
|
// Trust proxy for accurate IP addresses
|
|
app.set('trust proxy', 1);
|
|
|
|
// 미들웨어 설정
|
|
setupMiddlewares(app);
|
|
|
|
// 라우트 설정
|
|
setupRoutes(app);
|
|
|
|
// 에러 핸들러 (모든 라우트 이후에 위치)
|
|
app.use(errorHandler);
|
|
|
|
// 404 핸들러
|
|
app.use((req, res) => {
|
|
logger.warn('404 Not Found', { url: req.originalUrl, method: req.method });
|
|
res.status(404).json({
|
|
success: false,
|
|
error: '요청하신 경로를 찾을 수 없습니다',
|
|
path: req.originalUrl
|
|
});
|
|
});
|
|
|
|
// 서버 시작
|
|
const server = app.listen(PORT, () => {
|
|
logger.info(`서버 시작 완료`, {
|
|
port: PORT,
|
|
env: process.env.NODE_ENV || 'development',
|
|
nodeVersion: process.version
|
|
});
|
|
console.log(`\n🚀 서버가 포트 ${PORT}에서 실행 중입니다.`);
|
|
console.log(`📚 API 문서: http://localhost:${PORT}/api-docs\n`);
|
|
});
|
|
|
|
// Graceful Shutdown
|
|
const gracefulShutdown = (signal) => {
|
|
logger.info(`${signal} 신호 수신 - 서버 종료 시작`);
|
|
console.log(`\n🛑 ${signal} 신호를 받았습니다. 서버를 종료합니다...`);
|
|
|
|
server.close(async () => {
|
|
logger.info('HTTP 서버 종료 완료');
|
|
console.log('✅ HTTP 서버가 정상적으로 종료되었습니다.');
|
|
|
|
// 리소스 정리
|
|
try {
|
|
// DB 연결 종료는 각 요청에서 pool을 사용하므로 불필요
|
|
// Redis 종료 (사용 중인 경우)
|
|
if (cache.redis) {
|
|
await cache.redis.quit();
|
|
logger.info('캐시 시스템 종료 완료');
|
|
}
|
|
} catch (error) {
|
|
logger.error('리소스 정리 중 오류 발생', { error: error.message });
|
|
}
|
|
|
|
process.exit(0);
|
|
});
|
|
|
|
// 30초 후 강제 종료
|
|
setTimeout(() => {
|
|
logger.error('강제 종료 - 정상 종료 시간 초과');
|
|
console.error('❌ 정상 종료 실패, 강제 종료합니다.');
|
|
process.exit(1);
|
|
}, 30000);
|
|
};
|
|
|
|
// 시그널 핸들러 등록
|
|
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
|
|
// 처리되지 않은 Promise 거부
|
|
process.on('unhandledRejection', (reason, promise) => {
|
|
logger.error('처리되지 않은 Promise 거부', {
|
|
reason: reason,
|
|
promise: promise
|
|
});
|
|
console.error('⚠️ 처리되지 않은 Promise 거부:', reason);
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
process.exit(1);
|
|
}
|
|
});
|
|
|
|
// 처리되지 않은 예외
|
|
process.on('uncaughtException', (error) => {
|
|
logger.error('처리되지 않은 예외', {
|
|
error: error.message,
|
|
stack: error.stack
|
|
});
|
|
console.error('💥 처리되지 않은 예외:', error);
|
|
gracefulShutdown('UNCAUGHT_EXCEPTION');
|
|
});
|
|
|
|
// 캐시 시스템 초기화 (선택적)
|
|
(async () => {
|
|
try {
|
|
if (cache.initRedis) {
|
|
await cache.initRedis();
|
|
logger.info('캐시 시스템 초기화 완료');
|
|
console.log('✅ 캐시 시스템 초기화 완료');
|
|
}
|
|
} catch (error) {
|
|
logger.warn('캐시 시스템 초기화 실패 - 계속 진행', { error: error.message });
|
|
console.warn('⚠️ 캐시 시스템 초기화 실패:', error.message);
|
|
}
|
|
})();
|
|
|
|
module.exports = app;
|