- DB 테이블명 변경 마이그레이션 스크립트 추가 (migrate_v5_rename_remote.js) - Backend (server.js): 쿼리 및 매핑 로직을 asset_remote 및 remotes 속성으로 업데이트 - Frontend (HWModal.ts): 폼 필드와 데이터 바인딩을 remotes로 일괄 수정 - 유틸리티 스크립트의 레퍼런스 일괄 업데이트
213 lines
8.1 KiB
JavaScript
213 lines
8.1 KiB
JavaScript
import mysql from 'mysql2/promise';
|
|
import dotenv from 'dotenv';
|
|
|
|
dotenv.config();
|
|
|
|
const { DB_HOST, DB_USER, DB_PASS, DB_NAME, DB_PORT } = process.env;
|
|
|
|
async function migrateV2() {
|
|
const connection = await mysql.createConnection({
|
|
host: DB_HOST,
|
|
user: DB_USER,
|
|
password: DB_PASS,
|
|
database: DB_NAME,
|
|
port: parseInt(DB_PORT || '3306')
|
|
});
|
|
|
|
console.log('🚀 Phase 2: Final Migration to Normalized V2 Schema...');
|
|
|
|
try {
|
|
await connection.query('SET FOREIGN_KEY_CHECKS = 0');
|
|
|
|
// 1. Create/Enhance Core Tables
|
|
console.log('1. Creating/Enhancing Tables...');
|
|
|
|
await connection.query('DROP TABLE IF EXISTS asset_core, asset_hardware, asset_location, asset_remote');
|
|
|
|
await connection.query(`
|
|
CREATE TABLE asset_core (
|
|
id VARCHAR(50) PRIMARY KEY,
|
|
asset_code VARCHAR(100) UNIQUE NOT NULL,
|
|
category VARCHAR(100),
|
|
asset_type VARCHAR(100),
|
|
current_role VARCHAR(50) DEFAULT 'Normal' COMMENT 'Normal, Server, Personal, etc.',
|
|
asset_purpose VARCHAR(255),
|
|
service_type VARCHAR(50),
|
|
purchase_corp VARCHAR(100),
|
|
purchase_date VARCHAR(50),
|
|
purchase_amount VARCHAR(100),
|
|
purchase_vendor VARCHAR(255),
|
|
approval_document VARCHAR(255),
|
|
memo TEXT,
|
|
manager_primary VARCHAR(100),
|
|
manager_secondary VARCHAR(100),
|
|
current_dept VARCHAR(255),
|
|
previous_dept VARCHAR(255),
|
|
user_current VARCHAR(100),
|
|
previous_user VARCHAR(100),
|
|
emp_no VARCHAR(20),
|
|
user_position VARCHAR(50),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
`);
|
|
|
|
await connection.query(`
|
|
CREATE TABLE asset_hardware (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
asset_id VARCHAR(50) NOT NULL,
|
|
hw_status VARCHAR(50),
|
|
model_name VARCHAR(255),
|
|
mainboard VARCHAR(255),
|
|
os VARCHAR(100),
|
|
cpu VARCHAR(255),
|
|
ram VARCHAR(100),
|
|
gpu VARCHAR(100),
|
|
storage1 VARCHAR(255),
|
|
storage2 VARCHAR(255),
|
|
storage3 VARCHAR(255),
|
|
storage4 VARCHAR(255),
|
|
monitoring VARCHAR(100),
|
|
price VARCHAR(100),
|
|
volume VARCHAR(100),
|
|
monitor_inch VARCHAR(50),
|
|
serial_num VARCHAR(100),
|
|
FOREIGN KEY (asset_id) REFERENCES asset_core(id) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
`);
|
|
|
|
await connection.query(`
|
|
CREATE TABLE asset_location (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
asset_id VARCHAR(50) NOT NULL,
|
|
location VARCHAR(255),
|
|
location_detail VARCHAR(255),
|
|
location_photo VARCHAR(255),
|
|
loc_x VARCHAR(20),
|
|
loc_y VARCHAR(20),
|
|
is_active TINYINT(1) DEFAULT 1,
|
|
deactivated_at DATETIME NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (asset_id) REFERENCES asset_core(id) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
`);
|
|
|
|
await connection.query(`
|
|
CREATE TABLE asset_remote (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
asset_id VARCHAR(50) NOT NULL,
|
|
ip_address VARCHAR(100),
|
|
mac_address VARCHAR(100),
|
|
remote_tool VARCHAR(100),
|
|
remote_id VARCHAR(100),
|
|
remote_pw VARCHAR(100),
|
|
is_active TINYINT(1) DEFAULT 1,
|
|
deactivated_at DATETIME NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (asset_id) REFERENCES asset_core(id) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
`);
|
|
|
|
console.log('✅ V2 Schema tables created.');
|
|
|
|
// 2. Migration Logic
|
|
const legacyTables = [
|
|
{ name: 'asset_pc', defaultRole: 'Personal' },
|
|
{ name: 'asset_server', defaultRole: 'Server' },
|
|
{ name: 'asset_storage', defaultRole: 'Normal' },
|
|
{ name: 'asset_equipment', defaultRole: 'Normal' },
|
|
{ name: 'asset_office_supplies', defaultRole: 'Normal' },
|
|
{ name: 'asset_survey', defaultRole: 'Normal' },
|
|
{ name: 'asset_vip', defaultRole: 'Normal' },
|
|
{ name: 'asset_pc_parts', defaultRole: 'Normal' }
|
|
];
|
|
|
|
let totalMigrated = 0;
|
|
|
|
for (const tableInfo of legacyTables) {
|
|
const table = tableInfo.name;
|
|
try {
|
|
const [rows] = await connection.query(`SELECT * FROM ${table}`);
|
|
console.log(`- Migrating ${rows.length} records from ${table}...`);
|
|
|
|
for (const row of rows) {
|
|
// 2.1 Insert into asset_core
|
|
const role = (table === 'asset_pc' && row.asset_type === '서버PC') ? 'Server' : tableInfo.defaultRole;
|
|
|
|
await connection.query(`
|
|
INSERT IGNORE INTO asset_core (
|
|
id, asset_code, category, asset_type, current_role, asset_purpose, service_type, purchase_corp, purchase_date,
|
|
purchase_amount, purchase_vendor, approval_document, memo, manager_primary, manager_secondary,
|
|
current_dept, previous_dept, user_current, previous_user, emp_no, user_position, created_at
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`, [
|
|
row.id, row.asset_code, row.category, row.asset_type, role, row.asset_purpose, row.service_type,
|
|
row.purchase_corp, row.purchase_date, row.purchase_amount, row.purchase_vendor, row.approval_document,
|
|
row.memo, row.manager_primary, row.manager_secondary, row.current_dept, row.previous_dept,
|
|
row.user_current || row.current_user, row.previous_user, row.emp_no, row.user_position, row.created_at
|
|
]);
|
|
|
|
// 2.2 Insert into asset_hardware
|
|
await connection.query(`
|
|
INSERT INTO asset_hardware (
|
|
asset_id, hw_status, model_name, mainboard, os, cpu, ram, gpu, storage1, storage2, storage3, storage4, monitoring, price, volume, monitor_inch, serial_num
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`, [
|
|
row.id, row.hw_status, row.model_name, row.mainboard, row.os, row.cpu, row.ram, row.gpu,
|
|
row.ssd_1 || row.storage1, row.ssd_2 || row.storage2, row.hdd_1 || row.storage3, row.hdd_2, row.monitoring, row.price,
|
|
row.volume, row.monitor_inch, row.serial_num
|
|
]);
|
|
|
|
// 2.3 Insert into asset_location
|
|
if (row.location || row.location_detail) {
|
|
await connection.query(`
|
|
INSERT INTO asset_location (
|
|
asset_id, location, location_detail, location_photo, loc_x, loc_y, is_active
|
|
) VALUES (?, ?, ?, ?, ?, ?, 1)
|
|
`, [
|
|
row.id, row.location, row.location_detail, row.location_photo, row.loc_x, row.loc_y
|
|
]);
|
|
}
|
|
|
|
// 2.4 Insert into asset_remote
|
|
// Primary Network
|
|
if (row.ip_address || row.mac_address || row.remote_tool) {
|
|
await connection.query(`
|
|
INSERT INTO asset_remote (
|
|
asset_id, ip_address, mac_address, remote_tool, remote_id, remote_pw, is_active
|
|
) VALUES (?, ?, ?, ?, ?, ?, 1)
|
|
`, [
|
|
row.id, row.ip_address, row.mac_address, row.remote_tool, row.remote_id, row.remote_pw
|
|
]);
|
|
}
|
|
|
|
// Secondary Network (for servers)
|
|
if (row.ip_address_2 || row.remote_tool_2) {
|
|
await connection.query(`
|
|
INSERT INTO asset_remote (
|
|
asset_id, ip_address, remote_tool, remote_id, remote_pw, is_active
|
|
) VALUES (?, ?, ?, ?, ?, 1)
|
|
`, [
|
|
row.id, row.ip_address_2, row.remote_tool_2, row.remote_id_2, row.remote_pw_2
|
|
]);
|
|
}
|
|
|
|
totalMigrated++;
|
|
}
|
|
} catch (err) {
|
|
console.warn(`- Skipping table ${table}: ${err.message}`);
|
|
}
|
|
}
|
|
|
|
await connection.query('SET FOREIGN_KEY_CHECKS = 1');
|
|
console.log(`✅ Phase 2 Data Migration Completed. Total Assets Migrated: ${totalMigrated}`);
|
|
|
|
} catch (err) {
|
|
console.error('❌ Migration Failed:', err);
|
|
} finally {
|
|
await connection.end();
|
|
}
|
|
}
|
|
|
|
migrateV2();
|