From 1a3706d7a5d564ea98acb51c824cec85116137e7 Mon Sep 17 00:00:00 2001 From: Jaybe Date: Thu, 5 Jun 2025 08:09:05 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9A=B4=EC=98=81=20=EC=9D=B4=EA=B4=80=20?= =?UTF-8?q?=EC=A4=80=EB=B9=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- backend/app.js | 45 +++++++++++-- backend/config/config.js | 33 +++++++++ backend/models/index.js | 8 +-- backend/package-lock.json | 74 +++++++++++++++++++++ backend/package.json | 4 +- frontend/src/config.js | 6 ++ frontend/src/services/scoreService.js | 2 +- frontend/src/views/club/ScoreManagement.vue | 1 - 9 files changed, 163 insertions(+), 12 deletions(-) create mode 100755 backend/config/config.js create mode 100755 frontend/src/config.js diff --git a/.gitignore b/.gitignore index 9871eef..92e6002 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ !.env.example .vite .windsurfrules -config.js backend/node_modules/* frontend/node_modules/* backend/uploads/* +frontend/dist/* \ No newline at end of file diff --git a/backend/app.js b/backend/app.js index 39e58f1..ea508cf 100644 --- a/backend/app.js +++ b/backend/app.js @@ -51,11 +51,39 @@ app.set('io', io); // 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); + app.use(session({ + key: 'bowling_session', secret: process.env.JWT_SECRET, + store: sessionStore, resave: false, saveUninitialized: false, - cookie: { secure: process.env.NODE_ENV === 'production' } // https 환경이면 true, 개발환경은 false + cookie: { + secure: process.env.NODE_ENV === 'production', + maxAge: 24 * 60 * 60 * 1000 // 1일 + } })); // 데이터베이스 연결 및 모델 동기화 실행 @@ -83,9 +111,18 @@ app.use('/api/users', userRoutes); app.use('/api/notifications', notificationRoutes); app.use('/api/menus', menuRoutes); -// 루트 경로 핸들러 -app.get('/', (req, res) => { - res.json({ message: '볼링 클럽 매니저 API 서버에 오신 것을 환영합니다!' }); +// 정적 파일 제공 설정 +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')); }); // 서버 시작 diff --git a/backend/config/config.js b/backend/config/config.js new file mode 100755 index 0000000..8cb5ede --- /dev/null +++ b/backend/config/config.js @@ -0,0 +1,33 @@ +require('dotenv').config({ + path: require('path').resolve( + process.cwd(), + `.env.${process.env.NODE_ENV || 'development'}` + ) + }); + + module.exports = { + development: { + username: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME, + host: process.env.DB_HOST, + port: process.env.DB_PORT, + dialect: 'mysql' + }, + test: { + username: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME_TEST || process.env.DB_NAME, + host: process.env.DB_HOST, + port: process.env.DB_PORT, + dialect: 'mysql' + }, + production: { + username: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME_PROD || process.env.DB_NAME, + host: process.env.DB_HOST, + port: process.env.DB_PORT, + dialect: 'mysql' + } + }; \ No newline at end of file diff --git a/backend/models/index.js b/backend/models/index.js index 0c6588a..60dfe82 100644 --- a/backend/models/index.js +++ b/backend/models/index.js @@ -23,13 +23,13 @@ const syncModels = async () => { try { // 외래 키 제약 조건을 비활성화하고 테이블 재생성 // 개발 - await sequelize.query('SET FOREIGN_KEY_CHECKS = 0'); - await sequelize.sync({ force: true }); - await sequelize.query('SET FOREIGN_KEY_CHECKS = 1'); + // await sequelize.query('SET FOREIGN_KEY_CHECKS = 0'); + // await sequelize.sync({ force: true }); + // await sequelize.query('SET FOREIGN_KEY_CHECKS = 1'); // 운영 alter: true - 구조변경만 alter처리 // await sequelize.sync({ alter: true }); - // await sequelize.sync(); + await sequelize.sync(); } catch (error) { console.error('모델 동기화 중 오류 발생:', error); } diff --git a/backend/package-lock.json b/backend/package-lock.json index 831708c..e91a680 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -16,6 +16,7 @@ "csv-parser": "^3.2.0", "dotenv": "^16.4.7", "express": "^4.21.2", + "express-mysql-session": "^3.0.3", "express-session": "^1.18.1", "express-validator": "^7.2.1", "helmet": "^8.0.0", @@ -1750,6 +1751,79 @@ "url": "https://opencollective.com/express" } }, + "node_modules/express-mysql-session": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/express-mysql-session/-/express-mysql-session-3.0.3.tgz", + "integrity": "sha512-sEYrzFrOs3er+Ie/uk1dt93qz4AQ9SU1mpJJ0HPs0MJ4t4hE9AcDRNq0sZQUwy2F/SbXusBt1E5+FY6KzSqXNg==", + "license": "MIT", + "dependencies": { + "debug": "4.3.4", + "mysql2": "3.10.2" + } + }, + "node_modules/express-mysql-session/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/express-mysql-session/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/express-mysql-session/node_modules/lru-cache": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", + "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==", + "license": "ISC", + "engines": { + "node": ">=16.14" + } + }, + "node_modules/express-mysql-session/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/express-mysql-session/node_modules/mysql2": { + "version": "3.10.2", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.10.2.tgz", + "integrity": "sha512-KCXPEvAkO0RcHPr362O5N8tFY2fXvbjfkPvRY/wGumh4EOemo9Hm5FjQZqv/pCmrnuxGu5OxnSENG0gTXqKMgQ==", + "license": "MIT", + "dependencies": { + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^5.2.1", + "lru-cache": "^8.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, "node_modules/express-session": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz", diff --git a/backend/package.json b/backend/package.json index 34ea994..8c1b5e8 100644 --- a/backend/package.json +++ b/backend/package.json @@ -7,7 +7,8 @@ "cleanup": "lsof -ti:3030 | xargs kill -9 || true", "dev": "npm run cleanup && NODE_ENV=development nodemon app.js", "test": "NODE_ENV=test jest", - "db:seed:init": "npx sequelize-cli db:seed --seed 20250423-init-admin-user.js && npx sequelize-cli db:seed --seed 20250423-init-features.js && npx sequelize-cli db:seed --seed 20250423-init-subscription-01-plans.js && npx sequelize-cli db:seed --seed 20250423-init-subscription-02-plan-features.js && npx sequelize-cli db:seed --seed 20250424-init-menus.js" + "db:seed:init": "NODE_ENV=development npx sequelize-cli db:seed --seed 20250423-init-admin-user.js && npx sequelize-cli db:seed --seed 20250423-init-features.js && npx sequelize-cli db:seed --seed 20250423-init-subscription-01-plans.js && npx sequelize-cli db:seed --seed 20250423-init-subscription-02-plan-features.js && npx sequelize-cli db:seed --seed 20250424-init-menus.js", + "db:seed:init:prod": "NODE_ENV=production npx sequelize-cli db:seed --seed 20250423-init-admin-user.js && npx sequelize-cli db:seed --seed 20250423-init-features.js && npx sequelize-cli db:seed --seed 20250423-init-subscription-01-plans.js && npx sequelize-cli db:seed --seed 20250423-init-subscription-02-plan-features.js && npx sequelize-cli db:seed --seed 20250424-init-menus.js" }, "keywords": [], "author": "", @@ -21,6 +22,7 @@ "csv-parser": "^3.2.0", "dotenv": "^16.4.7", "express": "^4.21.2", + "express-mysql-session": "^3.0.3", "express-session": "^1.18.1", "express-validator": "^7.2.1", "helmet": "^8.0.0", diff --git a/frontend/src/config.js b/frontend/src/config.js new file mode 100755 index 0000000..356ca4f --- /dev/null +++ b/frontend/src/config.js @@ -0,0 +1,6 @@ +// API 설정 +export const API_URL = 'http://localhost:3030/api'; + +// 기타 설정 값들 +export const APP_NAME = '볼링 클럽 매니저'; +export const APP_VERSION = '1.0.0'; diff --git a/frontend/src/services/scoreService.js b/frontend/src/services/scoreService.js index 6279216..4b632ac 100644 --- a/frontend/src/services/scoreService.js +++ b/frontend/src/services/scoreService.js @@ -1,4 +1,4 @@ -import apiClient from './apiClient'; +import apiClient from './api'; /** * 점수 관리 서비스 diff --git a/frontend/src/views/club/ScoreManagement.vue b/frontend/src/views/club/ScoreManagement.vue index 6cab13d..021a9d7 100644 --- a/frontend/src/views/club/ScoreManagement.vue +++ b/frontend/src/views/club/ScoreManagement.vue @@ -199,7 +199,6 @@ import { ref, reactive, computed, onMounted } from 'vue'; import { useRouter, useRoute } from 'vue-router'; import { useToast } from 'primevue/usetoast'; import scoreService from '@/services/scoreService'; -import meetingService from '@/services/meetingService'; const router = useRouter(); const route = useRoute();