버그 수정

This commit is contained in:
2025-04-22 20:19:17 +09:00
parent 5b719b6766
commit 0306ebc890
15 changed files with 72 additions and 43 deletions
+3
View File
@@ -1,5 +1,8 @@
.history .history
.env .env
.env.*
!.env.example
.vite
.windsurfrules .windsurfrules
config.js config.js
backend/node_modules/* backend/node_modules/*
+1 -1
View File
@@ -80,7 +80,7 @@ app.get('/', (req, res) => {
// 서버 시작 // 서버 시작
const PORT = process.env.PORT || 3030; const PORT = process.env.PORT || 3030;
server.listen(PORT, () => { server.listen(PORT, () => {
console.log(`서버가 포트 ${PORT}에서 실행 중입니다.`); console.log(`서버가 ${process.env.NODE_ENV} 환경으로 포트 ${PORT}에서 실행 중입니다.`);
}); });
module.exports = app; module.exports = app;
+11 -2
View File
@@ -1,5 +1,14 @@
const { Sequelize } = require('sequelize'); const { Sequelize } = require('sequelize');
require('dotenv').config(); const path = require('path');
// 환경 변수 설정
const env = process.env.NODE_ENV || 'development';
const envPath = path.resolve(process.cwd(), `.env.${env}`);
// 환경별 .env 파일 로드
require('dotenv').config({
path: envPath
});
const sequelize = new Sequelize( const sequelize = new Sequelize(
process.env.DB_NAME, process.env.DB_NAME,
@@ -9,7 +18,7 @@ const sequelize = new Sequelize(
host: process.env.DB_HOST, host: process.env.DB_HOST,
port: process.env.DB_PORT, port: process.env.DB_PORT,
dialect: 'mysql', dialect: 'mysql',
logging: true, // 개발 중에는 true로 설정하여 SQL 쿼리 로그 확인 가능 logging: process.env.NODE_ENV === 'development' ? console.log : false, // 개발 환경에서만 로깅 활성화
pool: { pool: {
max: 5, max: 5,
min: 0, min: 0,
+11 -4
View File
@@ -32,6 +32,7 @@ exports.getAllEvents = async (req, res) => {
where: { where: {
status: { [Op.ne]: '취소' } status: { [Op.ne]: '취소' }
}, },
required: false,
include: [{ include: [{
model: Member, model: Member,
attributes: ['id', 'name', 'memberType', 'gender'] attributes: ['id', 'name', 'memberType', 'gender']
@@ -83,6 +84,7 @@ exports.getEventById = async (req, res) => {
where: { where: {
status: { [Op.ne]: '취소' } status: { [Op.ne]: '취소' }
}, },
required: false,
include: [{ include: [{
model: Member, model: Member,
attributes: ['id', 'name'] attributes: ['id', 'name']
@@ -145,7 +147,7 @@ exports.createEvent = async (req, res) => {
clubId, clubId,
title, title,
description, description,
startDate: new Date(startDate), startDate: startDate ? startDate : null,
endDate: endDateVal, endDate: endDateVal,
location, location,
maxParticipants: maxParticipants || 0, maxParticipants: maxParticipants || 0,
@@ -220,8 +222,8 @@ exports.updateEvent = async (req, res) => {
const updateData = { const updateData = {
title, title,
description, description,
startDate: startDate ? new Date(startDate) : event.startDate, startDate: startDate ? startDate : event.startDate,
endDate: endDate ? new Date(endDate) : null, endDate: endDate || null,
location, location,
maxParticipants: maxParticipants || event.maxParticipants, maxParticipants: maxParticipants || event.maxParticipants,
eventType: eventType || event.eventType, eventType: eventType || event.eventType,
@@ -246,11 +248,16 @@ exports.updateEvent = async (req, res) => {
attributes: ['id', 'status'], attributes: ['id', 'status'],
where: { where: {
status: { [Op.ne]: '취소' } status: { [Op.ne]: '취소' }
} },
required: false
} }
] ]
}); });
if (!updatedEvent) {
return res.status(404).json({ message: '이벤트를 찾을 수 없습니다.' });
}
res.json({ res.json({
message: '이벤트가 수정되었습니다.', message: '이벤트가 수정되었습니다.',
event: { event: {
+2 -1
View File
@@ -1,4 +1,5 @@
const { sequelize } = require('../config/database'); const { sequelize } = require('../config/database');
const { Op } = require('sequelize');
const User = require('./User'); const User = require('./User');
const Club = require('./Club'); const Club = require('./Club');
const Event = require('./Event'); const Event = require('./Event');
@@ -160,7 +161,7 @@ const createSampleData = async () => {
await Club.destroy({ where: {} }); await Club.destroy({ where: {} });
await Feature.destroy({ where: {} }); await Feature.destroy({ where: {} });
await SubscriptionPlan.destroy({ where: {} }); await SubscriptionPlan.destroy({ where: {} });
await User.destroy({ where: {} }); await User.destroy({ where: { email: { [Op.ne]: process.env.ADMIN_EMAIL } } });
console.log('기존 데이터가 모두 삭제되었습니다.'); console.log('기존 데이터가 모두 삭제되었습니다.');
// 2. 샘플 사용자 데이터 생성 // 2. 샘플 사용자 데이터 생성
+4 -1
View File
@@ -3,7 +3,10 @@
"version": "1.0.0", "version": "1.0.0",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "start": "NODE_ENV=production node app.js",
"cleanup": "lsof -ti:3030 | xargs kill -9 || true",
"dev": "npm run cleanup && NODE_ENV=development nodemon app.js",
"test": "NODE_ENV=test jest"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
+4
View File
@@ -1,6 +1,7 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { Club, Member, User, Feature, ClubFeature, ActivityLog, SubscriptionPlan, Meeting, MeetingParticipant, ClubSubscription } = require('../models'); const { Club, Member, User, Feature, ClubFeature, ActivityLog, SubscriptionPlan, Meeting, MeetingParticipant, ClubSubscription } = require('../models');
const clubController = require('../controllers/clubController');
const { sequelize } = require('../models/index'); const { sequelize } = require('../models/index');
const { Op } = require('sequelize'); const { Op } = require('sequelize');
const { authenticateJWT, authorizeRoles } = require('../middleware/authMiddleware'); const { authenticateJWT, authorizeRoles } = require('../middleware/authMiddleware');
@@ -1294,6 +1295,9 @@ router.get('/clubs/:id', async (req, res) => {
} }
}); });
// 새 클럽 생성
router.post('/clubs', authenticateJWT, clubController.createClub);
// 클럽 수정 // 클럽 수정
router.put('/clubs/:id', async (req, res) => { router.put('/clubs/:id', async (req, res) => {
try { try {
+2 -1
View File
@@ -4,7 +4,8 @@
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --host 0.0.0.0 --port 5173", "cleanup": "pkill -f esbuild || true",
"dev": "npm run cleanup && vite --host 0.0.0.0 --port 5173",
"build": "vite build", "build": "vite build",
"preview": "vite preview" "preview": "vite preview"
}, },
+6 -13
View File
@@ -99,6 +99,7 @@
<script setup> <script setup>
import { ref, watch, toRefs, computed } from 'vue'; import { ref, watch, toRefs, computed } from 'vue';
import dayjs from 'dayjs';
const statusOptions = [ const statusOptions = [
{ name: '준비', value: '준비' }, { name: '준비', value: '준비' },
@@ -145,9 +146,7 @@ const eventModel = ref({ ...props.event });
// 날짜 형식 변환 // 날짜 형식 변환
const formatDate = (date) => { const formatDate = (date) => {
if (!date) return null; if (!date) return null;
const d = new Date(date); return dayjs(date).toDate();
d.setHours(d.getHours() + 9); // UTC to KST
return d;
}; };
// props 변경 시 이벤트 모델 업데이트 // props 변경 시 이벤트 모델 업데이트
@@ -161,23 +160,17 @@ watch(() => props.event, (newValue) => {
eventModel.value = formattedEvent; eventModel.value = formattedEvent;
}, { deep: true }); }, { deep: true });
// 이벤트 저장 시 UTC로 변환 // 이벤트 저장
const saveEvent = () => { const saveEvent = () => {
const eventData = { ...eventModel.value }; const eventData = { ...eventModel.value };
if (eventData.startDate) { if (eventData.startDate) {
const d = new Date(eventData.startDate); eventData.startDate = dayjs(eventData.startDate).toDate();
d.setHours(d.getHours() - 9); // KST to UTC
eventData.startDate = d;
} }
if (eventData.endDate) { if (eventData.endDate) {
const d = new Date(eventData.endDate); eventData.endDate = dayjs(eventData.endDate).toDate();
d.setHours(d.getHours() - 9); // KST to UTC
eventData.endDate = d;
} }
if (eventData.registrationDeadline) { if (eventData.registrationDeadline) {
const d = new Date(eventData.registrationDeadline); eventData.registrationDeadline = dayjs(eventData.registrationDeadline).toDate();
d.setHours(d.getHours() - 9); // KST to UTC
eventData.registrationDeadline = d;
} }
emit('save', eventData); emit('save', eventData);
}; };
@@ -114,7 +114,7 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, onMounted, defineEmits } from 'vue'; import { ref, computed, onMounted } from 'vue';
import { useToast } from 'primevue/usetoast'; import { useToast } from 'primevue/usetoast';
import eventService from '@/services/eventService'; import eventService from '@/services/eventService';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
+9
View File
@@ -3,6 +3,15 @@ import { createPinia } from 'pinia'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
// dayjs configuration
import dayjs from 'dayjs'
import timezone from 'dayjs/plugin/timezone'
import utc from 'dayjs/plugin/utc'
dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.tz.setDefault('Asia/Seoul')
// PrimeVue // PrimeVue
import PrimeVue from 'primevue/config' import PrimeVue from 'primevue/config'
import 'primevue/resources/themes/lara-light-blue/theme.css' import 'primevue/resources/themes/lara-light-blue/theme.css'
+9
View File
@@ -29,6 +29,15 @@ const adminService = {
return apiClient.get(`/api/admin/clubs/${id}`); return apiClient.get(`/api/admin/clubs/${id}`);
}, },
/**
* 새 클럽 생성
* @param {Object} clubData - 클럽 정보
* @returns {Promise} - 생성된 클럽 정보
*/
createClub(clubData) {
return apiClient.post('/api/admin/clubs', clubData);
},
/** /**
* 클럽 정보 업데이트 * 클럽 정보 업데이트
* @param {Number} id - 클럽 ID * @param {Number} id - 클럽 ID
+4 -4
View File
@@ -60,8 +60,8 @@ export default {
try { try {
const formattedEvent = { const formattedEvent = {
...event, ...event,
startDate: dayjs(event.startDate).format('YYYY-MM-DD'), startDate: dayjs(event.startDate).format('YYYY-MM-DDTHH:mm:ssZ'),
endDate: event.endDate ? dayjs(event.endDate).format('YYYY-MM-DD') : null endDate: event.endDate ? dayjs(event.endDate).format('YYYY-MM-DDTHH:mm:ssZ') : null
}; };
const response = await apiClient.post('/api/club/events/create', formattedEvent); const response = await apiClient.post('/api/club/events/create', formattedEvent);
@@ -87,8 +87,8 @@ export default {
try { try {
const formattedEvent = { const formattedEvent = {
...event, ...event,
startDate: dayjs(event.startDate).format('YYYY-MM-DD'), startDate: dayjs(event.startDate).format('YYYY-MM-DDTHH:mm:ssZ'),
endDate: dayjs(event.endDate).format('YYYY-MM-DD') endDate: event.endDate ? dayjs(event.endDate).format('YYYY-MM-DDTHH:mm:ssZ') : null
}; };
const response = await apiClient.put(`/api/club/events/${event.id}`, formattedEvent); const response = await apiClient.put(`/api/club/events/${event.id}`, formattedEvent);
+4 -14
View File
@@ -114,6 +114,7 @@ import { useToast } from 'primevue/usetoast';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useClubStore } from '@/stores/clubStore'; import { useClubStore } from '@/stores/clubStore';
import eventService from '@/services/eventService'; import eventService from '@/services/eventService';
import dayjs from 'dayjs';
import clubService from '@/services/clubService'; import clubService from '@/services/clubService';
import ScoreManagement from '@/components/event/ScoreManagement.vue'; import ScoreManagement from '@/components/event/ScoreManagement.vue';
import ParticipantManagement from '@/components/event/ParticipantManagement.vue'; import ParticipantManagement from '@/components/event/ParticipantManagement.vue';
@@ -214,14 +215,7 @@ onMounted(async () => {
// 날짜 포맷 함수 // 날짜 포맷 함수
const formatDate = (date) => { const formatDate = (date) => {
if (!date) return ''; if (!date) return '';
const d = new Date(date); return dayjs(date).format('YYYY. MM. DD. HH:mm');
return d.toLocaleString('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
}; };
// 이벤트 유형에 따른 Badge 스타일 // 이벤트 유형에 따른 Badge 스타일
@@ -336,18 +330,14 @@ const saveEvent = async (eventData) => {
...eventData, ...eventData,
clubId: clubId.value clubId: clubId.value
}); });
const updatedEvent = response; await fetchEvents(); // 목록 갱신
const index = events.value.findIndex(e => e.id === updatedEvent.id);
if (index !== -1) {
events.value[index] = updatedEvent;
}
} else { } else {
// 이벤트 생성 // 이벤트 생성
const response = await eventService.createEvent({ const response = await eventService.createEvent({
...eventData, ...eventData,
clubId: clubId.value clubId: clubId.value
}); });
events.value.push(response); await fetchEvents(); // 목록 갱신
} }
toast.add({ toast.add({
severity: 'success', severity: 'success',
+1 -1
View File
@@ -13,7 +13,7 @@ export default defineConfig({
server: { server: {
host: '0.0.0.0', host: '0.0.0.0',
port: 5173, port: 5173,
//strictPort: true, strictPort: true,
proxy: { proxy: {
'/api': { '/api': {
target: 'http://localhost:3030', target: 'http://localhost:3030',