Add TeamMember model and APIs, team status UI, /admin page, local server bats, and scripts to sync data between local PostgreSQL and Render. Co-authored-by: Cursor <cursoragent@cursor.com>
62 lines
1.7 KiB
TypeScript
62 lines
1.7 KiB
TypeScript
import express from 'express';
|
|
import cors from 'cors';
|
|
import helmet from 'helmet';
|
|
import morgan from 'morgan';
|
|
import path from 'path';
|
|
import { errorHandler } from './middleware/errorHandler';
|
|
import routes from './routes';
|
|
|
|
const app = express();
|
|
|
|
app.use(helmet());
|
|
const allowedOrigins = [
|
|
'http://localhost:3000',
|
|
'http://localhost:5173',
|
|
'http://127.0.0.1:3000',
|
|
'http://172.16.8.248:3000',
|
|
'https://eene-dashboard.vercel.app',
|
|
process.env.FRONTEND_URL,
|
|
].filter(Boolean) as string[];
|
|
|
|
function isAllowedOrigin(origin: string): boolean {
|
|
if (allowedOrigins.includes(origin)) return true;
|
|
if (/^https:\/\/[\w-]+\.vercel\.app$/.test(origin)) return true;
|
|
// 로컬·사설망 프론트 (용량 절약용 로컬 서버)
|
|
if (/^http:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(origin)) return true;
|
|
if (/^http:\/\/172\.(1[6-9]|2\d|3[01])\.\d+\.\d+(:\d+)?$/.test(origin)) return true;
|
|
if (/^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/.test(origin)) return true;
|
|
if (/^http:\/\/10\.\d+\.\d+\.\d+(:\d+)?$/.test(origin)) return true;
|
|
return false;
|
|
}
|
|
|
|
app.use(
|
|
cors({
|
|
origin: (origin, callback) => {
|
|
if (!origin || isAllowedOrigin(origin)) {
|
|
callback(null, true);
|
|
} else {
|
|
callback(new Error(`CORS 차단: ${origin}`));
|
|
}
|
|
},
|
|
credentials: true,
|
|
}),
|
|
);
|
|
app.use(morgan('dev'));
|
|
app.use(express.json());
|
|
app.use(express.urlencoded({ extended: true }));
|
|
|
|
// 업로드 파일 정적 서빙
|
|
const uploadDir = path.resolve(process.env.UPLOAD_DIR || '../uploads');
|
|
app.use('/uploads', express.static(uploadDir));
|
|
|
|
// API Routes
|
|
app.use('/api', routes);
|
|
|
|
app.get('/health', (_req, res) => {
|
|
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
});
|
|
|
|
app.use(errorHandler);
|
|
|
|
export default app;
|