MariaDB 완전 마이그레이션 및 NAS 배포 최적화
- MariaDB 환경별 자동 감지 (Windows/NAS/Linux) - Unix Socket 및 TCP 연결 지원 - 완전한 UTF8MB4 스키마 적용 - 자동 초기화 스크립트 개선 - NAS 배포 스크립트 MariaDB 지원 - 환경변수 기반 설정 시스템 - 상세한 배포 가이드 문서화 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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();
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
87
database/mariadb-schema.sql
Normal file
87
database/mariadb-schema.sql
Normal file
@@ -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!)
|
||||
-- 실제 해시는 애플리케이션에서 생성됩니다
|
Reference in New Issue
Block a user