183 lines
5.2 KiB
JavaScript
183 lines
5.2 KiB
JavaScript
const express = require('express');
|
|
const bodyParser = require('body-parser');
|
|
const cors = require('cors');
|
|
const http = require('http');
|
|
const socketIo = require('socket.io');
|
|
|
|
const adminRoutes = require('./routes/adminRoutes');
|
|
const authRoutes = require('./routes/authRoutes');
|
|
const eventRoutes = require('./routes/eventRoutes');
|
|
const publicEventRoutes = require('./routes/publicEventRoutes');
|
|
const clubRoutes = require('./routes/clubRoutes');
|
|
const userRoutes = require('./routes/userRoutes');
|
|
const notificationRoutes = require('./routes/notificationRoutes');
|
|
const menuRoutes = require('./routes/menuRoutes');
|
|
const subscriptionRoutes = require('./routes/subscriptionRoutes');
|
|
const featureRoutes = require('./routes/featureRoutes');
|
|
const { sequelize, syncModels } = require('./models');
|
|
|
|
const app = express();
|
|
const server = http.createServer(app);
|
|
const io = socketIo(server, {
|
|
cors: {
|
|
origin: '*',
|
|
methods: ['GET', 'POST']
|
|
}
|
|
});
|
|
|
|
function getDomain(origin) {
|
|
try {
|
|
const url = new URL(origin);
|
|
return url.hostname; // 'lanebow.com', 'localhost'
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
const allowedDomains = ['lanebow.com', 'localhost'];
|
|
|
|
app.use(cors({
|
|
origin: function(origin, callback) {
|
|
if (!origin) return callback(null, true);
|
|
const domain = getDomain(origin);
|
|
if (allowedDomains.includes(domain)) {
|
|
return callback(null, true);
|
|
} else {
|
|
return callback(new Error('Not allowed by CORS'), false);
|
|
}
|
|
},
|
|
credentials: true
|
|
}));
|
|
app.use(bodyParser.json());
|
|
|
|
// Socket.IO 연결 처리
|
|
io.on('connection', (socket) => {
|
|
console.log('새로운 클라이언트 연결:', socket.id);
|
|
|
|
// 사용자 인증 및 알림 룸 참여
|
|
socket.on('authenticate', (userData) => {
|
|
if (userData && userData.id) {
|
|
socket.join(`user:${userData.id}`);
|
|
console.log(`사용자 ${userData.id}가 알림 룸에 참여했습니다.`);
|
|
}
|
|
});
|
|
|
|
// 연결 해제 처리
|
|
socket.on('disconnect', () => {
|
|
console.log('클라이언트 연결 해제:', socket.id);
|
|
});
|
|
});
|
|
|
|
// 전역 Socket.IO 인스턴스 설정
|
|
app.set('io', io);
|
|
app.set('trust proxy', 1);
|
|
// 치명적 예외/비동기 에러 글로벌 로그
|
|
process.on('uncaughtException', (err) => {
|
|
console.error('[FATAL] Uncaught Exception:', err);
|
|
});
|
|
process.on('unhandledRejection', (reason, promise) => {
|
|
console.error('[FATAL] Unhandled Rejection:', reason);
|
|
});
|
|
|
|
// app.js 또는 서버 초기화 파일
|
|
const session = require('express-session');
|
|
const MySQLStore = require('express-mysql-session')(session);
|
|
|
|
// MySQL 세션 저장소 옵션 설정
|
|
const options = {
|
|
host: process.env.DB_HOST || 'localhost',
|
|
port: process.env.DB_PORT || 3306,
|
|
user: process.env.DB_USER || 'root',
|
|
password: process.env.DB_PASSWORD || '',
|
|
database: process.env.DB_NAME || 'bowlingmanager',
|
|
// 세션 테이블 설정
|
|
schema: {
|
|
tableName: 'sessions',
|
|
columnNames: {
|
|
session_id: 'session_id',
|
|
expires: 'expires',
|
|
data: 'data'
|
|
}
|
|
}
|
|
};
|
|
|
|
// MySQL 세션 저장소 생성
|
|
const sessionStore = new MySQLStore(options);
|
|
|
|
const baseSessionOptions = {
|
|
key: 'bowling_session',
|
|
secret: process.env.JWT_SECRET,
|
|
store: sessionStore,
|
|
resave: false,
|
|
saveUninitialized: false,
|
|
cookie: {
|
|
maxAge: 24 * 60 * 60 * 1000,
|
|
secure: false,
|
|
sameSite: 'lax'
|
|
}
|
|
};
|
|
app.use(session(baseSessionOptions));
|
|
|
|
// 요청마다 secure/sameSite를 동적으로 할당
|
|
app.use((req, res, next) => {
|
|
const origin = req.headers.origin;
|
|
const domain = getDomain(origin);
|
|
if (req.session && req.session.cookie) {
|
|
if (domain === 'lanebow.com') {
|
|
req.session.cookie.secure = true;
|
|
req.session.cookie.sameSite = 'none';
|
|
} else {
|
|
req.session.cookie.secure = false;
|
|
req.session.cookie.sameSite = 'lax';
|
|
}
|
|
}
|
|
next();
|
|
});
|
|
|
|
// 데이터베이스 연결 및 모델 동기화 실행
|
|
sequelize.authenticate()
|
|
.then(() => {
|
|
console.log('데이터베이스에 연결되었습니다.');
|
|
return syncModels();
|
|
})
|
|
.then(() => {
|
|
console.log('데이터베이스 모델이 동기화되었습니다.');
|
|
})
|
|
.catch(err => {
|
|
console.error('데이터베이스 연결 또는 모델 동기화 오류:', err);
|
|
});
|
|
|
|
// Routes 설정
|
|
app.use('/api/auth', authRoutes);
|
|
app.use('/api/admin', adminRoutes);
|
|
app.use('/api/club', clubRoutes);
|
|
app.use('/api/club/events', eventRoutes);
|
|
app.use('/api/public', publicEventRoutes);
|
|
app.use('/api/features', featureRoutes);
|
|
app.use('/api/subscriptions', subscriptionRoutes);
|
|
app.use('/api/users', userRoutes);
|
|
app.use('/api/notifications', notificationRoutes);
|
|
app.use('/api/menus', menuRoutes);
|
|
|
|
// 정적 파일 제공 설정
|
|
const path = require('path');
|
|
app.use(express.static(path.join(__dirname, '../frontend/dist')));
|
|
|
|
// API 요청이 아닌 모든 요청은 Vue 앱으로 라우팅
|
|
app.get('*', (req, res, next) => {
|
|
// API 요청은 무시하고 다음 미들웨어로 전달
|
|
if (req.path.startsWith('/api/')) {
|
|
return next();
|
|
}
|
|
// Vue 앱의 index.html 반환
|
|
res.sendFile(path.join(__dirname, '../frontend/dist/index.html'));
|
|
});
|
|
|
|
// 서버 시작
|
|
const PORT = process.env.PORT || 3030;
|
|
server.listen(PORT, () => {
|
|
console.log(`서버가 ${process.env.NODE_ENV} 환경으로 포트 ${PORT}에서 실행 중입니다.`);
|
|
});
|
|
|
|
module.exports = app;
|