import 'dotenv/config'; import express from 'express'; import cors from 'cors'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import { initDb, seedAdmin } from './db.js'; import { createAuthRouter } from './routes/auth.js'; import { createDecksRouter } from './routes/decks.js'; import { createAdminRouter } from './routes/admin.js'; import { createStatsRouter } from './routes/stats.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const PORT = Number(process.env.PORT) || 3000; const DB_PATH = process.env.DB_PATH || path.join(__dirname, '..', 'data', 'uadeck.db'); /** * package.json에서 서비스 버전을 읽는다. (실패 시 'unknown') * @returns {string} */ function readAppVersion() { try { const pkgRaw = fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'); return JSON.parse(pkgRaw).version || 'unknown'; } catch { return 'unknown'; } } const APP_VERSION = readAppVersion(); if (!process.env.DATAS_PATH) { process.env.DATAS_PATH = path.join(__dirname, '..', '..', 'datas'); } const db = initDb(DB_PATH); seedAdmin(db); const app = express(); // nginx 프록시 1홉 뒤에서 실행 → rate limit이 실제 클라이언트 IP(X-Forwarded-For)를 쓰도록 app.set('trust proxy', 1); const corsOrigins = process.env.CORS_ORIGINS ? process.env.CORS_ORIGINS.split(',').map((o) => o.trim()) : true; app.use(cors({ origin: corsOrigins, credentials: true })); app.use(express.json({ limit: '20mb' })); app.get('/api/v1/health', (_req, res) => { res.json({ ok: true, version: APP_VERSION }); }); app.use('/api/stats', createStatsRouter(db, APP_VERSION)); app.use('/api/v1/stats', createStatsRouter(db, APP_VERSION)); app.use('/api/v1/auth', createAuthRouter(db)); app.use('/api/v1/decks', createDecksRouter(db)); app.use('/api/v1/admin', createAdminRouter(db)); app.use((err, _req, res, _next) => { if (err.type === 'entity.too.large') { return res.status(413).json({ error: '요청 크기가 너무 큽니다. 고화질 옵션을 끄고 다시 저장해 주세요.', }); } console.error(err); res.status(500).json({ error: '서버 오류가 발생했습니다.' }); }); app.listen(PORT, () => { console.log(`UNIARE API v${APP_VERSION} listening on :${PORT}`); console.log(`DB: ${DB_PATH}`); console.log(`DATAS: ${process.env.DATAS_PATH || '(default ../datas)'}`); });