diff --git a/backend/app.js b/backend/app.js index 0ee6394..a71ce6e 100644 --- a/backend/app.js +++ b/backend/app.js @@ -25,7 +25,29 @@ const io = socketIo(server, { } }); -app.use(cors()); +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 연결 처리 @@ -82,17 +104,35 @@ const options = { // MySQL 세션 저장소 생성 const sessionStore = new MySQLStore(options); -app.use(session({ +const baseSessionOptions = { key: 'bowling_session', secret: process.env.JWT_SECRET, store: sessionStore, resave: false, saveUninitialized: false, - cookie: { - secure: process.env.NODE_ENV === 'production', - maxAge: 24 * 60 * 60 * 1000 // 1일 + 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() diff --git a/backend/controllers/clubController.js b/backend/controllers/clubController.js index a15b56a..73478d8 100644 --- a/backend/controllers/clubController.js +++ b/backend/controllers/clubController.js @@ -54,6 +54,7 @@ exports.selectClub = async (req, res) => { } req.session.clubId = clubId; + console.log(`Session clubId: ${clubId}`); res.status(200).json({ message: '클럽을 선택했습니다.' }); } catch (error) { console.error('클럽 선택 오류:', error); @@ -136,18 +137,18 @@ exports.getClubById = async (req, res) => { // 새 클럽 생성 exports.createClub = async (req, res) => { try { - const { name, location, description, ownerEmail, contact, features, sendInvite } = req.body; + const { name, location, description, averageCalculationPeriod } = req.body; // 필수 필드 검증 - if (!name || !ownerEmail) { - return res.status(400).json({ message: '클럽 이름과 모임장 이메일은 필수 항목입니다.' }); + if (!name) { + return res.status(400).json({ message: '클럽 이름은 필수 항목입니다.' }); } // 이메일로 사용자 조회 - const owner = await User.findOne({ where: { email: ownerEmail } }); + const owner = await User.findOne({ where: { id: req.user.id } }); if (!owner) { - return res.status(404).json({ message: '해당 이메일로 등록된 사용자를 찾을 수 없습니다.' }); + return res.status(404).json({ message: '해당 사용자를 찾을 수 없습니다.' }); } // 클럽 생성 @@ -155,7 +156,7 @@ exports.createClub = async (req, res) => { name, location, description, - contact, + averageCalculationPeriod, ownerId: owner.id, memberCount: 1, // 모임장 포함 status: 'active' @@ -172,25 +173,6 @@ exports.createClub = async (req, res) => { status: 'active' }); - // 선택된 기능 추가 - if (features && features.length > 0) { - const featurePromises = features.map(featureId => - ClubFeature.create({ - clubId: newClub.id, - featureId, - enabled: true - }) - ); - - await Promise.all(featurePromises); - } - - // 초대 이메일 발송 로직 (sendInvite가 true인 경우) - if (sendInvite) { - // TODO: 초대 이메일 발송 로직 구현 - console.log(`${ownerEmail}에게 초대 이메일 발송 예정`); - } - // 베이직 1개월 플랜 자동 추가 try { // 베이직 플랜 조회 (ID가 1이라고 가정, 실제 환경에 맞게 조정 필요) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 71ef029..ba2a993 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,97 +1,99 @@