import "dotenv/config"; import express from "express"; import cors from "cors"; import helmet from "helmet"; import compression from "compression"; import rateLimit from "express-rate-limit"; import path from "path"; import config from "./config/environment"; import { logger } from "./utils/logger"; import { errorHandler } from "./middleware/errorHandler"; // 라우터 임포트 import authRoutes from "./routes/authRoutes"; import adminRoutes from "./routes/adminRoutes"; import multilangRoutes from "./routes/multilangRoutes"; import tableManagementRoutes from "./routes/tableManagementRoutes"; import entityJoinRoutes from "./routes/entityJoinRoutes"; import screenManagementRoutes from "./routes/screenManagementRoutes"; import commonCodeRoutes from "./routes/commonCodeRoutes"; import dynamicFormRoutes from "./routes/dynamicFormRoutes"; import fileRoutes from "./routes/fileRoutes"; import companyManagementRoutes from "./routes/companyManagementRoutes"; // import dataflowRoutes from "./routes/dataflowRoutes"; // 임시 주석 import dataflowDiagramRoutes from "./routes/dataflowDiagramRoutes"; import webTypeStandardRoutes from "./routes/webTypeStandardRoutes"; import buttonActionStandardRoutes from "./routes/buttonActionStandardRoutes"; import screenStandardRoutes from "./routes/screenStandardRoutes"; import templateStandardRoutes from "./routes/templateStandardRoutes"; import componentStandardRoutes from "./routes/componentStandardRoutes"; import layoutRoutes from "./routes/layoutRoutes"; import dataRoutes from "./routes/dataRoutes"; import testButtonDataflowRoutes from "./routes/testButtonDataflowRoutes"; import externalDbConnectionRoutes from "./routes/externalDbConnectionRoutes"; // import userRoutes from './routes/userRoutes'; // import menuRoutes from './routes/menuRoutes'; const app = express(); // 기본 미들웨어 app.use(helmet()); app.use(compression()); app.use(express.json({ limit: "10mb" })); app.use(express.urlencoded({ extended: true, limit: "10mb" })); // 정적 파일 서빙 (업로드된 파일들) app.use( "/uploads", express.static(path.join(process.cwd(), "uploads"), { setHeaders: (res, path) => { // 파일 서빙 시 CORS 헤더 설정 res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS"); res.setHeader( "Access-Control-Allow-Headers", "Content-Type, Authorization" ); res.setHeader("Cache-Control", "public, max-age=3600"); }, }) ); // CORS 설정 - environment.ts에서 이미 올바른 형태로 처리됨 app.use( cors({ origin: config.cors.origin, // 이미 배열 또는 boolean으로 처리됨 credentials: config.cors.credentials, methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"], allowedHeaders: [ "Content-Type", "Authorization", "X-Requested-With", "Accept", "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", ], preflightContinue: false, optionsSuccessStatus: 200, }) ); // Rate Limiting (개발 환경에서는 완화) const limiter = rateLimit({ windowMs: 1 * 60 * 1000, // 1분 max: config.nodeEnv === "development" ? 1000 : 100, // 개발환경에서는 1000, 운영환경에서는 100 message: { error: "너무 많은 요청이 발생했습니다. 잠시 후 다시 시도해주세요.", }, skip: (req) => { // 헬스 체크는 Rate Limiting 제외 return req.path === "/health"; }, }); app.use("/api/", limiter); // 헬스 체크 엔드포인트 app.get("/health", (req, res) => { res.status(200).json({ status: "OK", timestamp: new Date().toISOString(), uptime: process.uptime(), environment: config.nodeEnv, }); }); // API 라우터 app.use("/api/auth", authRoutes); app.use("/api/admin", adminRoutes); app.use("/api/multilang", multilangRoutes); app.use("/api/table-management", tableManagementRoutes); app.use("/api/table-management", entityJoinRoutes); // 🎯 Entity 조인 기능 app.use("/api/screen-management", screenManagementRoutes); app.use("/api/common-codes", commonCodeRoutes); app.use("/api/dynamic-form", dynamicFormRoutes); app.use("/api/files", fileRoutes); app.use("/api/company-management", companyManagementRoutes); // app.use("/api/dataflow", dataflowRoutes); // 임시 주석 app.use("/api/dataflow-diagrams", dataflowDiagramRoutes); app.use("/api/admin/web-types", webTypeStandardRoutes); app.use("/api/admin/button-actions", buttonActionStandardRoutes); app.use("/api/admin/template-standards", templateStandardRoutes); app.use("/api/admin/component-standards", componentStandardRoutes); app.use("/api/layouts", layoutRoutes); app.use("/api/screen", screenStandardRoutes); app.use("/api/data", dataRoutes); app.use("/api/test-button-dataflow", testButtonDataflowRoutes); app.use("/api/external-db-connections", externalDbConnectionRoutes); // app.use('/api/users', userRoutes); // app.use('/api/menus', menuRoutes); // 404 핸들러 app.use("*", (req, res) => { res.status(404).json({ success: false, message: "요청한 리소스를 찾을 수 없습니다.", path: req.originalUrl, }); }); // 에러 핸들러 app.use(errorHandler); // 서버 시작 const PORT = config.port; const HOST = config.host; app.listen(PORT, HOST, () => { logger.info(`🚀 Server is running on ${HOST}:${PORT}`); logger.info(`📊 Environment: ${config.nodeEnv}`); logger.info(`🔗 Health check: http://${HOST}:${PORT}/health`); logger.info(`🌐 External access: http://39.117.244.52:${PORT}/health`); }); export default app;