🎯 프로젝트 리브랜딩: Kumamoto → Travel Planner v2.0
✨ 주요 변경사항: - 프로젝트 이름: kumamoto-travel-planner → travel-planner - 버전 업그레이드: v1.0.0 → v2.0.0 - 멀티유저 시스템 구현 (JWT 인증) - PostgreSQL 마이그레이션 시스템 추가 - Docker 컨테이너 이름 변경 - UI 브랜딩 업데이트 (Travel Planner) - API 서버 및 인증 시스템 추가 - 여행 공유 기능 구현 - 템플릿 시스템 추가 🔧 기술 스택: - Frontend: React + TypeScript + Vite - Backend: Node.js + Express + JWT - Database: PostgreSQL + 마이그레이션 - Infrastructure: Docker + Docker Compose 🌟 새로운 기능: - 사용자 인증 및 권한 관리 - 다중 여행 계획 관리 - 여행 템플릿 시스템 - 공유 링크 및 댓글 시스템 - 관리자 대시보드
This commit is contained in:
187
server/routes/setup.js
Normal file
187
server/routes/setup.js
Normal file
@@ -0,0 +1,187 @@
|
||||
const express = require('express');
|
||||
const bcrypt = require('bcrypt');
|
||||
const { query } = require('../db');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 설정 상태 확인
|
||||
router.get('/status', async (req, res) => {
|
||||
try {
|
||||
// 시스템 설정 확인
|
||||
const settingsResult = await query('SELECT key, value FROM system_settings');
|
||||
const settings = {};
|
||||
settingsResult.rows.forEach(row => {
|
||||
settings[row.key] = row.value;
|
||||
});
|
||||
|
||||
// 관리자 계정 존재 여부 확인
|
||||
const adminResult = await query('SELECT COUNT(*) as count FROM users WHERE role = $1', ['admin']);
|
||||
const hasAdmin = parseInt(adminResult.rows[0].count) > 0;
|
||||
|
||||
// 전체 사용자 수
|
||||
const userCountResult = await query('SELECT COUNT(*) as count FROM users');
|
||||
const totalUsers = parseInt(userCountResult.rows[0].count);
|
||||
|
||||
const isSetupComplete = settings.setup_completed === 'true' && hasAdmin;
|
||||
|
||||
res.json({
|
||||
isSetupComplete,
|
||||
is_setup_required: !isSetupComplete,
|
||||
setup_step: isSetupComplete ? 'completed' : 'initial',
|
||||
has_admin: hasAdmin,
|
||||
total_users: totalUsers,
|
||||
version: settings.app_version || '2.0.0',
|
||||
settings: {
|
||||
jwt_secret_set: settings.jwt_secret_set === 'true',
|
||||
google_maps_configured: settings.google_maps_configured === 'true',
|
||||
email_configured: settings.email_configured === 'true'
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Setup status check error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '설정 상태 확인 중 오류가 발생했습니다',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 초기 관리자 계정 생성
|
||||
router.post('/admin', async (req, res) => {
|
||||
try {
|
||||
const { name, email, password } = req.body;
|
||||
|
||||
// 입력 검증
|
||||
if (!name || !email || !password) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '이름, 이메일, 비밀번호를 모두 입력해주세요'
|
||||
});
|
||||
}
|
||||
|
||||
// 이미 관리자가 있는지 확인
|
||||
const existingAdmin = await query('SELECT id FROM users WHERE role = $1', ['admin']);
|
||||
if (existingAdmin.rows.length > 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '이미 관리자 계정이 존재합니다'
|
||||
});
|
||||
}
|
||||
|
||||
// 이메일 중복 확인
|
||||
const existingUser = await query('SELECT id FROM users WHERE email = $1', [email]);
|
||||
if (existingUser.rows.length > 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '이미 사용 중인 이메일입니다'
|
||||
});
|
||||
}
|
||||
|
||||
// 비밀번호 해시
|
||||
const saltRounds = 10;
|
||||
const passwordHash = await bcrypt.hash(password, saltRounds);
|
||||
|
||||
// 관리자 계정 생성
|
||||
const result = await query(
|
||||
'INSERT INTO users (email, password_hash, name, role) VALUES ($1, $2, $3, $4) RETURNING id, email, name, role, created_at',
|
||||
[email, passwordHash, name, 'admin']
|
||||
);
|
||||
|
||||
const admin = result.rows[0];
|
||||
|
||||
// 설정 완료 표시
|
||||
await query(
|
||||
'UPDATE system_settings SET value = $1, updated_at = CURRENT_TIMESTAMP WHERE key = $2',
|
||||
['true', 'setup_completed']
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '관리자 계정이 생성되었습니다',
|
||||
admin: {
|
||||
id: admin.id,
|
||||
email: admin.email,
|
||||
name: admin.name,
|
||||
role: admin.role,
|
||||
created_at: admin.created_at
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Admin creation error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '관리자 계정 생성 중 오류가 발생했습니다',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 환경 설정 업데이트
|
||||
router.post('/config', async (req, res) => {
|
||||
try {
|
||||
const { jwt_secret, google_maps_api_key, email_config } = req.body;
|
||||
|
||||
const updates = [];
|
||||
|
||||
// JWT 시크릿 설정
|
||||
if (jwt_secret) {
|
||||
process.env.JWT_SECRET = jwt_secret;
|
||||
updates.push(['jwt_secret_set', 'true']);
|
||||
}
|
||||
|
||||
// Google Maps API 키 설정
|
||||
if (google_maps_api_key) {
|
||||
process.env.GOOGLE_MAPS_API_KEY = google_maps_api_key;
|
||||
updates.push(['google_maps_configured', 'true']);
|
||||
}
|
||||
|
||||
// 이메일 설정
|
||||
if (email_config) {
|
||||
// 이메일 설정 로직 (SMTP 등)
|
||||
updates.push(['email_configured', 'true']);
|
||||
}
|
||||
|
||||
// 설정 업데이트
|
||||
for (const [key, value] of updates) {
|
||||
await query(
|
||||
'UPDATE system_settings SET value = $1, updated_at = CURRENT_TIMESTAMP WHERE key = $2',
|
||||
[value, key]
|
||||
);
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '환경 설정이 업데이트되었습니다',
|
||||
updated: updates.map(([key]) => key)
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Config update error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '환경 설정 업데이트 중 오류가 발생했습니다',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 데이터베이스 연결 테스트
|
||||
router.get('/test-db', async (req, res) => {
|
||||
try {
|
||||
const result = await query('SELECT NOW() as current_time, version() as db_version');
|
||||
res.json({
|
||||
success: true,
|
||||
message: '데이터베이스 연결 성공',
|
||||
data: result.rows[0]
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Database test error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '데이터베이스 연결 실패',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user