const express = require('express'); const cors = require('cors'); const bodyParser = require('body-parser'); const path = require('path'); // Oracle DB 연결 const dbConnection = require('./database/connection'); const { createTable } = require('./database/queries'); const { createAuthTables } = require('./database/auth-queries'); const { createUserTable } = require('./database/user-queries'); const { createApiLogTable } = require('./database/log-queries'); const { skipLogging } = require('./middleware/logger'); const apiRoutes = require('./routes/api'); const authRoutes = require('./routes/auth'); const usersRoutes = require('./routes/users'); const logsRoutes = require('./routes/logs'); const app = express(); const PORT = 5577; // 미들웨어 설정 app.use(cors({ origin: [ 'http://localhost:5577', 'http://127.0.0.1:5577', 'http://39.117.244.52:5577', 'https://39.117.244.52:5577' ], credentials: true, methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization', 'X-API-Key', 'X-Requested-With'], exposedHeaders: ['Content-Length', 'X-Foo', 'X-Bar'] })); app.use(bodyParser.json({ limit: '50mb' })); app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' })); // OPTIONS 요청 처리 (CORS preflight) app.options('*', (req, res) => { const origin = req.headers.origin; const allowedOrigins = [ 'http://localhost:5577', 'http://127.0.0.1:5577', 'http://39.117.244.52:5577', 'https://39.117.244.52:5577' ]; if (allowedOrigins.includes(origin)) { res.header('Access-Control-Allow-Origin', origin); } else { res.header('Access-Control-Allow-Origin', 'http://39.117.244.52:5577'); } res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Key, X-Requested-With'); res.header('Access-Control-Allow-Credentials', 'true'); res.sendStatus(200); }); // 정적 파일 서빙 (개발 환경에서 캐시 비활성화) app.use(express.static(path.join(__dirname, 'public'), { etag: false, lastModified: false, setHeaders: (res, path) => { // 개발 환경에서 캐시 비활성화 if (process.env.NODE_ENV !== 'production') { res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); res.setHeader('Pragma', 'no-cache'); res.setHeader('Expires', '0'); } } })); // API 로깅 미들웨어 (정적 파일, 헬스체크, 로그 조회는 제외) app.use(skipLogging([ '/favicon.ico', '/api/health', '/logs/api-logs', '/logs/api-logs/stats', /^\/css\//, /^\/js\//, /^\/images\//, /^\/fonts\//, /^\/auth\// // 인증 관련 경로도 제외 ])); // 요청 로깅 미들웨어 app.use((req, res, next) => { console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`); next(); }); // API 라우트 설정 app.use('/api', apiRoutes); app.use('/api/users', usersRoutes); app.use('/auth', authRoutes); app.use('/logs', logsRoutes); // 기본 라우트 - 웹 UI 서빙 app.get('/', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'index.html')); }); // API 정보 엔드포인트 app.get('/info', (req, res) => { res.json({ message: 'REST API 서버에 오신 것을 환영합니다!', version: '1.0.0', webUI: 'http://localhost:5577', endpoints: { // 인증 API login: 'POST /auth/login', register: 'POST /auth/register', createApiKey: 'POST /auth/api-keys', // 데이터 API health: 'GET /api/health', getAllData: 'GET /api/data', getDataById: 'GET /api/data/:id', createData: 'POST /api/data', updateData: 'PUT /api/data/:id', deleteData: 'DELETE /api/data/:id' } }); }); // 404 에러 핸들러 app.use('*', (req, res) => { res.status(404).json({ success: false, message: '요청한 엔드포인트를 찾을 수 없습니다' }); }); // 에러 핸들러 app.use((err, req, res, next) => { console.error('서버 에러:', err); res.status(500).json({ success: false, message: '내부 서버 오류가 발생했습니다', error: process.env.NODE_ENV === 'development' ? err.message : undefined }); }); // 서버 시작 async function startServer() { try { // Oracle DB 연결 풀 초기화 await dbConnection.initializePool(); // 테이블 생성 (존재하지 않는 경우) await createTable(); await createAuthTables(); await createUserTable(); await createApiLogTable(); // 서버 시작 app.listen(PORT, () => { console.log(`\n=================================`); console.log(`🚀 REST API 서버가 시작되었습니다!`); console.log(`📍 포트: ${PORT}`); console.log(`🌐 URL: http://localhost:${PORT}`); console.log(`📊 API 문서: http://localhost:${PORT}/api/health`); console.log(`=================================\n`); }); } catch (error) { console.error('서버 시작 실패:', error); process.exit(1); } } // 서버 종료 처리 process.on('SIGINT', async () => { console.log('\n서버를 종료합니다...'); await dbConnection.closePool(); process.exit(0); }); process.on('SIGTERM', async () => { console.log('\n서버를 종료합니다...'); await dbConnection.closePool(); process.exit(0); }); // 서버 시작 startServer();