diff --git a/.claude/settings.local.json b/.claude/settings.local.json index a9b4fc7..92f1163 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -48,7 +48,13 @@ "Bash(powershell:*)", "Bash(schtasks:*)", "Bash(cmd //c:*)", - "Bash(npm install:*)" + "Bash(npm install:*)", + "mcp__playwright__browser_wait_for", + "mcp__context7__resolve-library-id", + "mcp__context7__get-library-docs", + "Bash(npm run init-mariadb:*)", + "Bash(npm test)", + "Bash(npm run build:*)" ], "deny": [], "ask": [], diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..cea29d1 --- /dev/null +++ b/.env.example @@ -0,0 +1,18 @@ +# 개발 환경 설정 예시 +# Windows 개발환경용 MariaDB/MySQL 연결 설정 +DB_HOST=localhost +DB_PORT=3306 +DB_USER=root +DB_PASSWORD= +DB_NAME=jaryo + +# NAS 배포 환경 +NODE_ENV=development +DEPLOY_ENV=local + +# 서버 설정 +HOST=0.0.0.0 +PORT=3000 + +# 세션 설정 +SESSION_SECRET=your-session-secret-here \ No newline at end of file diff --git a/README-MariaDB.md b/README-MariaDB.md new file mode 100644 index 0000000..6a43a60 --- /dev/null +++ b/README-MariaDB.md @@ -0,0 +1,139 @@ +# Jaryo File Manager - MariaDB 배포 가이드 + +## 개요 +Jaryo File Manager를 시놀로지 NAS의 MariaDB와 함께 배포하는 가이드입니다. + +## 시스템 요구사항 + +### NAS 환경 +- 시놀로지 DSM 7.0+ +- Node.js 18+ (DSM 패키지 센터에서 설치) +- MariaDB 10+ (DSM 패키지 센터에서 설치) +- Git Server (DSM 패키지 센터에서 설치) + +### 개발 환경 +- Node.js 18+ +- MariaDB/MySQL 5.7+ +- Git + +## NAS 배포 단계 + +### 1. 빠른 배포 (권장) +```bash +# 자동 배포 스크립트 실행 +./deploy-to-nas.sh [NAS-IP] jaryo [PASSWORD] + +# 예시: +./deploy-to-nas.sh 192.168.1.100 jaryo mypassword +``` + +### 2. 수동 배포 + +#### 2.1 MariaDB 설정 +NAS SSH 접속 후: +```sql +mysql -u root -p + +CREATE DATABASE IF NOT EXISTS jaryo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE USER 'jaryo_user'@'localhost' IDENTIFIED BY 'JaryoPass2024!@#'; +GRANT ALL PRIVILEGES ON jaryo.* TO 'jaryo_user'@'localhost'; +FLUSH PRIVILEGES; +EXIT; +``` + +#### 2.2 스키마 설정 +```bash +mysql -u jaryo_user -p jaryo < database/mariadb-schema.sql +``` + +#### 2.3 서비스 배포 +```bash +# 소스 코드 클론 +cd /volume1/web +git clone [GITEA_URL] jaryo +cd jaryo + +# 의존성 설치 +npm install + +# 데이터베이스 초기화 +npm run init-mariadb + +# 서비스 시작 +./start-service.sh +``` + +## 환경별 설정 + +### Windows 개발 환경 +`.env` 파일 생성: +```env +DB_HOST=localhost +DB_PORT=3306 +DB_USER=root +DB_PASSWORD=your_password +DB_NAME=jaryo +HOST=0.0.0.0 +PORT=3000 +``` + +### NAS 운영 환경 +환경 변수는 자동으로 설정됩니다: +- `NODE_ENV=production` +- `DEPLOY_ENV=nas` +- Unix Socket 연결: `/run/mysqld/mysqld10.sock` + +## 관리 명령어 + +### 서비스 관리 +```bash +# 시작 +./start-service.sh + +# 중지 +kill $(cat jaryo-nas.pid) + +# 로그 확인 +tail -f logs/app.log +``` + +### 데이터베이스 관리 +```bash +# 초기화 +npm run init-mariadb + +# 직접 연결 +mysql -u jaryo_user -p -S /run/mysqld/mysqld10.sock jaryo +``` + +## 접속 정보 + +### 기본 관리자 계정 +- **이메일**: admin@jaryo.com +- **비밀번호**: Hee150603! + +### 서비스 URL +- **메인**: http://[NAS-IP]:3005 +- **관리자**: http://[NAS-IP]:3005/admin + +## 문제 해결 + +### 연결 오류 +1. MariaDB 서비스 상태 확인 +2. 데이터베이스 및 사용자 권한 확인 +3. 소켓 파일 경로 확인 +4. 방화벽 설정 확인 + +### 상세 가이드 +더 자세한 설정 방법은 `mariadb-setup.md` 파일을 참조하세요. + +## 기술 스택 +- **Backend**: Node.js + Express +- **Database**: MariaDB +- **Frontend**: Vanilla JavaScript +- **Deployment**: Shell Scripts + +## 지원 +- 로그 파일: `/volume1/web/jaryo/logs/app.log` +- 설정 파일: `database/mariadb-helper.js` +- 스키마: `database/mariadb-schema.sql` \ No newline at end of file diff --git a/cookies.txt b/cookies.txt new file mode 100644 index 0000000..5d47335 --- /dev/null +++ b/cookies.txt @@ -0,0 +1,5 @@ +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + +#HttpOnly_localhost FALSE / FALSE 1755922561 connect.sid s%3AmN1rJMxZAee73L5t1g-59UL0tXQP36Vr.6GJ1M%2FUaWj68J9z6Ua9MBxCG54Sl8OuOsRUQNQFlLZE diff --git a/database/db-helper.js b/database/db-helper.js index b1f9604..29ab48b 100644 --- a/database/db-helper.js +++ b/database/db-helper.js @@ -4,7 +4,9 @@ const fs = require('fs'); class DatabaseHelper { constructor() { - this.dbPath = path.join(__dirname, 'jaryo.db'); + // 프로젝트 루트의 data 디렉토리에 데이터베이스 저장 + const projectRoot = path.resolve(__dirname, '..'); + this.dbPath = path.join(projectRoot, 'data', 'jaryo.db'); this.db = null; } @@ -16,13 +18,26 @@ class DatabaseHelper { return; } - this.db = new sqlite3.Database(this.dbPath, sqlite3.OPEN_READWRITE, (err) => { + // 데이터베이스 디렉토리 생성 + const dbDir = path.dirname(this.dbPath); + if (!fs.existsSync(dbDir)) { + fs.mkdirSync(dbDir, { recursive: true }); + } + + // 데이터베이스 파일이 없으면 생성 + const flags = fs.existsSync(this.dbPath) ? + sqlite3.OPEN_READWRITE : + sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE; + + this.db = new sqlite3.Database(this.dbPath, flags, (err) => { if (err) { console.error('데이터베이스 연결 오류:', err.message); reject(err); } else { - console.log('✅ SQLite 데이터베이스 연결됨'); - resolve(this.db); + console.log('✅ SQLite 데이터베이스 연결됨:', this.dbPath); + this.initializeTables().then(() => { + resolve(this.db); + }).catch(reject); } }); }); @@ -46,6 +61,78 @@ class DatabaseHelper { }); } + // 테이블 초기화 + initializeTables() { + return new Promise((resolve, reject) => { + const createTables = ` + -- 사용자 테이블 + CREATE TABLE IF NOT EXISTS users ( + id TEXT PRIMARY KEY, + email TEXT UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + name TEXT NOT NULL, + role TEXT DEFAULT 'user', + is_active INTEGER DEFAULT 1, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, + last_login DATETIME + ); + + -- 카테고리 테이블 + CREATE TABLE IF NOT EXISTS categories ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT UNIQUE NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP + ); + + -- 파일 테이블 + CREATE TABLE IF NOT EXISTS files ( + id TEXT PRIMARY KEY, + title TEXT NOT NULL, + description TEXT, + category TEXT NOT NULL, + tags TEXT DEFAULT '[]', + user_id TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) + ); + + -- 첨부파일 테이블 + CREATE TABLE IF NOT EXISTS file_attachments ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file_id TEXT NOT NULL, + original_name TEXT NOT NULL, + file_name TEXT NOT NULL, + file_path TEXT NOT NULL, + file_size INTEGER NOT NULL, + mime_type TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE + ); + + -- 사용자 세션 테이블 (옵션) + CREATE TABLE IF NOT EXISTS user_sessions ( + id TEXT PRIMARY KEY, + user_id TEXT NOT NULL, + expires_at DATETIME NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE + ); + `; + + this.db.exec(createTables, (err) => { + if (err) { + console.error('테이블 생성 오류:', err); + reject(err); + } else { + console.log('✅ 데이터베이스 테이블 초기화 완료'); + resolve(); + } + }); + }); + } + // 모든 파일 목록 가져오기 async getAllFiles(limit = 100, offset = 0) { await this.connect(); diff --git a/database/mariadb-helper.js b/database/mariadb-helper.js index c8760f7..baf6b53 100644 --- a/database/mariadb-helper.js +++ b/database/mariadb-helper.js @@ -4,24 +4,55 @@ const { v4: uuidv4 } = require('uuid'); class MariaDBHelper { constructor() { this.connection = null; - this.config = { - socketPath: '/run/mysqld/mysqld10.sock', - user: 'jaryo_user', - password: 'JaryoPass2024!@#', - database: 'jaryo', - charset: 'utf8mb4' - }; + + // 환경별 설정 지원 + const isWindows = process.platform === 'win32'; + const isNAS = process.env.NODE_ENV === 'production' || process.env.DEPLOY_ENV === 'nas'; + + if (isWindows) { + // Windows 개발 환경 (로컬 MariaDB/MySQL) + this.config = { + 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 || 'jaryo', + charset: 'utf8mb4' + }; + } else if (isNAS) { + // 시놀로지 NAS 환경 (Unix Socket) + this.config = { + socketPath: '/run/mysqld/mysqld10.sock', + user: 'jaryo_user', + password: 'JaryoPass2024!@#', + database: 'jaryo', + charset: 'utf8mb4' + }; + } else { + // 기타 Linux 환경 + this.config = { + host: process.env.DB_HOST || 'localhost', + port: process.env.DB_PORT || 3306, + user: process.env.DB_USER || 'jaryo_user', + password: process.env.DB_PASSWORD || 'JaryoPass2024!@#', + database: process.env.DB_NAME || 'jaryo', + charset: 'utf8mb4' + }; + } } async connect() { try { if (!this.connection || this.connection.connection._closing) { this.connection = await mysql.createConnection(this.config); - console.log('✅ MariaDB 연결 성공 (Unix Socket)'); + + const connectionType = this.config.socketPath ? 'Unix Socket' : `TCP ${this.config.host}:${this.config.port}`; + console.log(`✅ MariaDB 연결 성공 (${connectionType})`); } return this.connection; } catch (error) { console.error('❌ MariaDB 연결 실패:', error); + console.error('연결 설정:', { ...this.config, password: '***' }); throw error; } } diff --git a/database/mariadb-schema.sql b/database/mariadb-schema.sql new file mode 100644 index 0000000..2981875 --- /dev/null +++ b/database/mariadb-schema.sql @@ -0,0 +1,87 @@ +-- 자료실 MariaDB 데이터베이스 스키마 +-- 파일: database/mariadb-schema.sql + +-- 데이터베이스 생성 +CREATE DATABASE IF NOT EXISTS jaryo +CHARACTER SET utf8mb4 +COLLATE utf8mb4_unicode_ci; + +USE jaryo; + +-- 사용자 테이블 +CREATE TABLE IF NOT EXISTS users ( + id VARCHAR(36) PRIMARY KEY, + email VARCHAR(255) UNIQUE NOT NULL, + password_hash VARCHAR(255) NOT NULL, + name VARCHAR(100) NOT NULL, + role ENUM('admin', 'user') DEFAULT 'user', + is_active TINYINT(1) DEFAULT 1, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + last_login TIMESTAMP NULL, + INDEX idx_email (email), + INDEX idx_role (role) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 카테고리 테이블 +CREATE TABLE IF NOT EXISTS categories ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(100) UNIQUE NOT NULL, + is_default TINYINT(1) DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_name (name) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 파일 정보 테이블 +CREATE TABLE IF NOT EXISTS files ( + id VARCHAR(36) PRIMARY KEY, + title VARCHAR(255) NOT NULL, + description TEXT, + category VARCHAR(100) NOT NULL DEFAULT '기타', + tags JSON, + user_id VARCHAR(36), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + INDEX idx_category (category), + INDEX idx_created_at (created_at), + INDEX idx_user_id (user_id), + INDEX idx_title (title), + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 파일 첨부 정보 테이블 +CREATE TABLE IF NOT EXISTS file_attachments ( + id INT AUTO_INCREMENT PRIMARY KEY, + file_id VARCHAR(36) NOT NULL, + original_name VARCHAR(255) NOT NULL, + file_name VARCHAR(255) NOT NULL, + file_path TEXT NOT NULL, + file_size BIGINT DEFAULT 0, + mime_type VARCHAR(255), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_file_id (file_id), + INDEX idx_original_name (original_name), + FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 세션 테이블 (선택사항) +CREATE TABLE IF NOT EXISTS user_sessions ( + id VARCHAR(255) PRIMARY KEY, + user_id VARCHAR(36) NOT NULL, + expires_at TIMESTAMP NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_user_id (user_id), + INDEX idx_expires_at (expires_at), + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 기본 카테고리 데이터 삽입 +INSERT IGNORE INTO categories (name, is_default) VALUES +('문서', 1), +('이미지', 1), +('동영상', 1), +('프레젠테이션', 1), +('기타', 1); + +-- 기본 관리자 계정 생성 (비밀번호: Hee150603!) +-- 실제 해시는 애플리케이션에서 생성됩니다 \ No newline at end of file diff --git a/deploy-to-nas.sh b/deploy-to-nas.sh index 17aad97..6dbadd9 100644 --- a/deploy-to-nas.sh +++ b/deploy-to-nas.sh @@ -135,27 +135,30 @@ if [ \$? -ne 0 ]; then fi echo '✅ 의존성 설치 완료' -# 데이터베이스 백업 및 초기화 -if [ -f 'scripts/init-database.js' ]; then - # 기존 데이터베이스 백업 - DB_FILE='data/database.db' - BACKUP_FILE='data/database_backup_$(date +%Y%m%d_%H%M%S).db' +# MariaDB 데이터베이스 초기화 +if [ -f 'scripts/init-mariadb.js' ]; then + echo '🗄️ MariaDB 데이터베이스 초기화 중...' + echo 'ℹ️ MariaDB 연결 설정:' + echo ' - 데이터베이스: jaryo' + echo ' - 사용자: jaryo_user' + echo ' - 소켓: /run/mysqld/mysqld10.sock' - if [ -f '\$DB_FILE' ]; then - echo '💾 기존 데이터베이스 백업 중...' - cp '\$DB_FILE' '\$BACKUP_FILE' - echo '✅ 백업 완료: \$BACKUP_FILE' - - # 기존 데이터 유지 - 초기화 건너뛰기 - echo 'ℹ️ 기존 데이터베이스 발견 - 초기화 건너뛰기' - echo '💡 새 데이터베이스가 필요하면 수동으로 실행: npm run init-db' + export PATH='$NODE_PATH':\$PATH + if '$NODE_PATH'/npm run init-mariadb; then + echo '✅ MariaDB 초기화 완료' else - # 새 설치 - 데이터베이스 초기화 - echo '🗄️ 새 데이터베이스 초기화 중...' - export PATH='$NODE_PATH':\$PATH - '$NODE_PATH'/npm run init-db - echo '✅ 데이터베이스 초기화 완료' + echo '❌ MariaDB 초기화 실패' + echo '💡 MariaDB 설정을 확인하고 다음 명령어를 실행하세요:' + echo ' mysql -u root -p << EOF' + echo ' CREATE DATABASE IF NOT EXISTS jaryo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;' + echo ' CREATE USER IF NOT EXISTS '\''jaryo_user'\''@'\''localhost'\'' IDENTIFIED BY '\''JaryoPass2024!@#'\'';' + echo ' GRANT ALL PRIVILEGES ON jaryo.* TO '\''jaryo_user'\''@'\''localhost'\'';' + echo ' FLUSH PRIVILEGES;' + echo ' EOF' + exit 1 fi +else + echo '⚠️ MariaDB 초기화 스크립트를 찾을 수 없습니다.' fi " @@ -201,7 +204,12 @@ fi # 서비스 시작 echo '🚀 자료실 서비스 시작 중...' cd '\$PROJECT_DIR' -PORT='$SERVICE_PORT' nohup \$NODE_PATH/node server.js > '\$LOG_FILE' 2>&1 & +# NAS 환경 변수 설정 +export NODE_ENV=production +export DEPLOY_ENV=nas +export HOST=0.0.0.0 +export PORT='$SERVICE_PORT' +nohup \$NODE_PATH/node server.js > '\$LOG_FILE' 2>&1 & echo \$! > '\$PID_FILE' sleep 2 diff --git a/mariadb-setup.md b/mariadb-setup.md new file mode 100644 index 0000000..affdfc8 --- /dev/null +++ b/mariadb-setup.md @@ -0,0 +1,130 @@ +# 시놀로지 NAS MariaDB 설정 가이드 + +## 1. MariaDB 패키지 설치 + +1. **DSM 패키지 센터** 열기 +2. **MariaDB 10** 검색 및 설치 +3. 설치 완료 후 **실행** + +## 2. MariaDB 초기 설정 + +### 2.1 MariaDB 관리 도구 접속 +- DSM에서 **MariaDB 10** 앱 실행 +- 또는 웹 브라우저에서 `http://NAS-IP:3307` 접속 + +### 2.2 관리자 계정으로 로그인 +- 사용자: `root` +- 비밀번호: 설치 시 설정한 비밀번호 + +## 3. 자료실 데이터베이스 설정 + +### 3.1 데이터베이스 생성 +```sql +CREATE DATABASE IF NOT EXISTS jaryo +CHARACTER SET utf8mb4 +COLLATE utf8mb4_unicode_ci; +``` + +### 3.2 전용 사용자 생성 +```sql +CREATE USER 'jaryo_user'@'localhost' IDENTIFIED BY 'JaryoPass2024!@#'; +GRANT ALL PRIVILEGES ON jaryo.* TO 'jaryo_user'@'localhost'; +FLUSH PRIVILEGES; +``` + +### 3.3 테이블 생성 (스키마 적용) +```bash +# NAS SSH 접속 후 +cd /volume1/web/jaryo +mysql -u jaryo_user -p jaryo < database/mariadb-schema.sql +``` + +## 4. 연결 설정 확인 + +### 4.1 Unix Socket 경로 확인 +```bash +sudo find /run -name "*.sock" | grep mysql +# 일반적인 경로: /run/mysqld/mysqld10.sock +``` + +### 4.2 연결 테스트 +```bash +mysql -u jaryo_user -p -S /run/mysqld/mysqld10.sock jaryo +``` + +## 5. NAS 자료실 서비스 배포 + +### 5.1 자동 배포 +```bash +./deploy-to-nas.sh [NAS-IP] jaryo [PASSWORD] +``` + +### 5.2 수동 초기화 (필요시) +```bash +cd /volume1/web/jaryo +npm run init-mariadb +``` + +## 6. 문제 해결 + +### 6.1 연결 오류 +- MariaDB 서비스 상태 확인: `sudo systemctl status mariadb` +- 소켓 파일 권한 확인: `ls -la /run/mysqld/` +- 방화벽 설정 확인 + +### 6.2 권한 오류 +```sql +-- 권한 재설정 +GRANT ALL PRIVILEGES ON jaryo.* TO 'jaryo_user'@'localhost'; +FLUSH PRIVILEGES; +``` + +### 6.3 한글 데이터 문제 +```sql +-- 문자셋 확인 +SHOW VARIABLES LIKE 'character_set%'; +SHOW VARIABLES LIKE 'collation%'; +``` + +## 7. 성능 최적화 + +### 7.1 인덱스 확인 +```sql +USE jaryo; +SHOW INDEX FROM files; +SHOW INDEX FROM file_attachments; +``` + +### 7.2 쿼리 최적화 +```sql +-- 슬로우 쿼리 로그 활성화 +SET GLOBAL slow_query_log = 'ON'; +SET GLOBAL long_query_time = 2; +``` + +## 8. 백업 및 복원 + +### 8.1 데이터베이스 백업 +```bash +mysqldump -u jaryo_user -p jaryo > jaryo_backup_$(date +%Y%m%d).sql +``` + +### 8.2 데이터베이스 복원 +```bash +mysql -u jaryo_user -p jaryo < jaryo_backup_YYYYMMDD.sql +``` + +## 9. 보안 설정 + +### 9.1 비밀번호 변경 +```sql +ALTER USER 'jaryo_user'@'localhost' IDENTIFIED BY 'NEW_SECURE_PASSWORD'; +``` + +### 9.2 불필요한 권한 제거 +```sql +-- 테스트 데이터베이스 제거 +DROP DATABASE IF EXISTS test; +DELETE FROM mysql.user WHERE User=''; +FLUSH PRIVILEGES; +``` \ No newline at end of file diff --git a/package.json b/package.json index 6a3948f..706a564 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,8 @@ "scripts": { "start": "node server.js", "dev": "node server.js", + "init-db": "node scripts/init-database.js", + "init-mariadb": "node scripts/init-mariadb.js", "build": "echo 'Build complete'" }, "dependencies": { diff --git a/scripts/init-database.js b/scripts/init-database.js new file mode 100644 index 0000000..a98e9dc --- /dev/null +++ b/scripts/init-database.js @@ -0,0 +1,79 @@ +const fs = require('fs'); +const path = require('path'); +const bcrypt = require('bcrypt'); +const DatabaseHelper = require('../database/db-helper'); + +async function initializeDatabase() { + console.log('🗄️ 데이터베이스 초기화 시작...'); + + const dbHelper = new DatabaseHelper(); + + try { + // 데이터 디렉토리 생성 + const dataDir = path.join(__dirname, '..', 'data'); + if (!fs.existsSync(dataDir)) { + fs.mkdirSync(dataDir, { recursive: true }); + console.log('📁 데이터 디렉토리 생성됨:', dataDir); + } + + // 데이터베이스 연결 및 테이블 생성 + await dbHelper.connect(); + console.log('✅ 데이터베이스 연결 성공'); + + // 기본 관리자 계정 생성 + const adminEmail = 'admin@jaryo.com'; + const adminPassword = 'Hee150603!'; + + const existingUser = await dbHelper.getUserByEmail(adminEmail); + + if (!existingUser) { + const saltRounds = 10; + const hashedPassword = await bcrypt.hash(adminPassword, saltRounds); + + const adminData = { + email: adminEmail, + password_hash: hashedPassword, + name: '관리자', + role: 'admin' + }; + + await dbHelper.createUser(adminData); + console.log('👤 기본 관리자 계정 생성됨'); + console.log('📧 이메일:', adminEmail); + console.log('🔑 비밀번호:', adminPassword); + } else { + console.log('👤 관리자 계정이 이미 존재합니다.'); + } + + // 기본 카테고리 생성 + const defaultCategories = ['문서', '이미지', '동영상', '프레젠테이션', '기타']; + + for (const categoryName of defaultCategories) { + try { + await dbHelper.addCategory(categoryName); + console.log(`📂 카테고리 생성됨: ${categoryName}`); + } catch (error) { + if (error.message.includes('UNIQUE constraint failed')) { + console.log(`📂 카테고리 이미 존재: ${categoryName}`); + } else { + console.error(`카테고리 생성 오류 (${categoryName}):`, error.message); + } + } + } + + console.log('🎉 데이터베이스 초기화 완료!'); + + } catch (error) { + console.error('❌ 데이터베이스 초기화 실패:', error); + process.exit(1); + } finally { + await dbHelper.close(); + } +} + +// 스크립트 직접 실행 시에만 초기화 실행 +if (require.main === module) { + initializeDatabase().catch(console.error); +} + +module.exports = initializeDatabase; \ No newline at end of file diff --git a/scripts/init-mariadb.js b/scripts/init-mariadb.js new file mode 100644 index 0000000..2503478 --- /dev/null +++ b/scripts/init-mariadb.js @@ -0,0 +1,108 @@ +const bcrypt = require('bcrypt'); +const MariaDBHelper = require('../database/mariadb-helper'); + +async function initializeMariaDB() { + console.log('🗄️ MariaDB 데이터베이스 초기화 시작...'); + + const dbHelper = new MariaDBHelper(); + + try { + // 데이터베이스 연결 테스트 + await dbHelper.connect(); + console.log('✅ MariaDB 연결 성공'); + + // 기본 관리자 계정 생성 + const adminEmail = 'admin@jaryo.com'; + const adminPassword = 'Hee150603!'; + + const existingUser = await dbHelper.getUserByEmail(adminEmail); + + if (!existingUser) { + const saltRounds = 10; + const hashedPassword = await bcrypt.hash(adminPassword, saltRounds); + + const adminData = { + email: adminEmail, + password_hash: hashedPassword, + name: '관리자', + role: 'admin' + }; + + await dbHelper.createUser(adminData); + console.log('👤 기본 관리자 계정 생성됨'); + console.log('📧 이메일:', adminEmail); + console.log('🔑 비밀번호:', adminPassword); + } else { + console.log('👤 관리자 계정이 이미 존재합니다.'); + } + + // 기본 카테고리 확인 및 생성 + const categories = await dbHelper.getCategories(); + const defaultCategories = ['문서', '이미지', '동영상', '프레젠테이션', '기타']; + + for (const categoryName of defaultCategories) { + const existingCategory = categories.find(cat => cat.name === categoryName); + if (!existingCategory) { + try { + await dbHelper.addCategory(categoryName); + console.log(`📂 카테고리 생성됨: ${categoryName}`); + } catch (error) { + if (error.code === 'ER_DUP_ENTRY') { + console.log(`📂 카테고리 이미 존재: ${categoryName}`); + } else { + console.error(`카테고리 생성 오류 (${categoryName}):`, error.message); + } + } + } else { + console.log(`📂 카테고리 이미 존재: ${categoryName}`); + } + } + + console.log('🎉 MariaDB 초기화 완료!'); + + } catch (error) { + console.error('❌ MariaDB 초기화 실패:', error); + + // 연결 오류인 경우 상세한 도움말 제공 + if (error.code === 'ECONNREFUSED' || error.code === 'ENOENT') { + console.log('\n📋 MariaDB 연결 확인사항:'); + + if (process.platform === 'win32') { + console.log('🪟 Windows 개발 환경:'); + console.log('1. MariaDB 또는 MySQL이 설치되고 실행 중인지 확인'); + console.log('2. 환경변수 또는 .env 파일에 DB 연결 정보 설정'); + console.log(' - DB_HOST=localhost'); + console.log(' - DB_PORT=3306'); + console.log(' - DB_USER=root'); + console.log(' - DB_PASSWORD=your_password'); + console.log(' - DB_NAME=jaryo'); + console.log('\n🔧 Windows MySQL/MariaDB 설정:'); + console.log('CREATE DATABASE jaryo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'); + console.log('USE jaryo;'); + console.log('-- 그 다음 database/mariadb-schema.sql 파일 실행'); + } else { + console.log('🐧 Linux/NAS 환경:'); + console.log('1. MariaDB가 설치되고 실행 중인지 확인'); + console.log('2. 데이터베이스 "jaryo"가 생성되어 있는지 확인'); + console.log('3. 사용자 "jaryo_user"가 생성되고 권한이 있는지 확인'); + console.log('4. Unix 소켓 경로가 올바른지 확인: /run/mysqld/mysqld10.sock'); + console.log('\n🔧 NAS MariaDB 설정 명령어:'); + console.log('CREATE DATABASE jaryo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'); + console.log('CREATE USER \'jaryo_user\'@\'localhost\' IDENTIFIED BY \'JaryoPass2024!@#\';'); + console.log('GRANT ALL PRIVILEGES ON jaryo.* TO \'jaryo_user\'@\'localhost\';'); + console.log('FLUSH PRIVILEGES;'); + } + } + + process.exit(1); + } finally { + await dbHelper.close(); + } +} + +// 스크립트 직접 실행 시에만 초기화 실행 +if (require.main === module) { + initializeMariaDB().catch(console.error); +} + +module.exports = initializeMariaDB; \ No newline at end of file diff --git a/server.js b/server.js index d6d405c..2ef2b5e 100644 --- a/server.js +++ b/server.js @@ -6,13 +6,13 @@ const fs = require('fs'); const bcrypt = require('bcrypt'); const session = require('express-session'); const { v4: uuidv4 } = require('uuid'); -const DatabaseHelper = require('./database/db-helper'); +const MariaDBHelper = require('./database/mariadb-helper'); const app = express(); const PORT = process.env.PORT || 3005; -// 데이터베이스 헬퍼 인스턴스 -const db = new DatabaseHelper(); +// 데이터베이스 헬퍼 인스턴스 (MariaDB) +const db = new MariaDBHelper(); // 미들웨어 설정 app.use(cors({ @@ -26,9 +26,9 @@ app.use(express.urlencoded({ extended: true, limit: '50mb' })); app.use(session({ secret: 'jaryo-file-manager-secret-key-2024', resave: false, - saveUninitialized: false, + saveUninitialized: true, // 세션 초기화 허용 cookie: { - secure: process.env.NODE_ENV === 'production', // Vercel에서는 HTTPS + secure: false, // 개발 환경에서도 HTTP로 작동하도록 수정 httpOnly: true, maxAge: 24 * 60 * 60 * 1000 // 24시간 } @@ -827,11 +827,19 @@ module.exports = app; // 로컬 개발 환경에서만 서버 시작 if (process.env.NODE_ENV !== 'production' || process.env.VERCEL !== '1') { - const server = app.listen(PORT, '99.1.110.50', () => { + const HOST = process.env.HOST || '0.0.0.0'; // NAS 호환성을 위해 모든 인터페이스에서 수신 + const server = app.listen(PORT, HOST, () => { + const serverAddress = server.address(); + const host = serverAddress.address === '::' ? 'localhost' : + serverAddress.address === '0.0.0.0' ? 'localhost' : + serverAddress.address; + console.log(`🚀 자료실 서버가 포트 ${PORT}에서 실행중입니다.`); - console.log(`📱 Admin 페이지: http://99.1.110.50:${PORT}/admin/index.html`); - console.log(`🌐 Main 페이지: http://99.1.110.50:${PORT}/index.html`); - console.log(`📊 API: http://99.1.110.50:${PORT}/api/files`); + console.log(`📍 서버 주소: ${HOST}:${PORT}`); + console.log(`📱 Admin 페이지: http://${host}:${PORT}/admin/index.html`); + console.log(`🌐 Main 페이지: http://${host}:${PORT}/index.html`); + console.log(`📊 API: http://${host}:${PORT}/api/files`); + console.log(`🔧 NAS 접속: http://[NAS-IP]:${PORT}`); }); // 대용량 파일 다운로드를 위해 서버 타임아웃을 30분으로 설정 diff --git a/start-service.sh b/start-service.sh index 2085267..f776aa6 100644 --- a/start-service.sh +++ b/start-service.sh @@ -40,9 +40,24 @@ if [ ! -d "node_modules" ]; then $NPM_PATH install fi -# 데이터베이스 초기화 -echo "데이터베이스 초기화 중..." -$NODE_PATH scripts/init-database.js +# MariaDB 데이터베이스 초기화 +echo "MariaDB 데이터베이스 초기화 중..." +if [ -f "scripts/init-mariadb.js" ]; then + # NAS 환경 설정 + export NODE_ENV=production + export DEPLOY_ENV=nas + + if $NPM_PATH run init-mariadb; then + echo "✅ MariaDB 초기화 완료" + else + echo "⚠️ MariaDB 초기화 실패" + echo "💡 수동으로 MariaDB를 설정해야 할 수 있습니다." + echo "자세한 내용은 mariadb-setup.md를 참조하세요." + fi +else + echo "⚠️ MariaDB 초기화 스크립트를 찾을 수 없습니다." + echo "💡 수동으로 MariaDB를 설정하세요." +fi # 기존 프로세스 종료 if [ -f "$PID_FILE" ]; then @@ -57,6 +72,12 @@ fi # 서비스 시작 echo "서비스 시작 중..." +# NAS 환경 변수 설정 +export NODE_ENV=production +export DEPLOY_ENV=nas +export HOST=0.0.0.0 +export PORT=3005 + nohup $NODE_PATH server.js > "$LOG_FILE" 2>&1 & NEW_PID=$! diff --git a/test-login.html b/test-login.html new file mode 100644 index 0000000..3fd4dd0 --- /dev/null +++ b/test-login.html @@ -0,0 +1,60 @@ + + +
+