feat: Add 5Why_ prefix to all database tables

- Rename all tables with 5Why_ prefix for namespace isolation
- Update models: User.js, Analysis.js, AuditLog.js
- Update routes: llmConfig.js
- Update scripts: seed-test-users.js, add-deepseek-config.js, add-ollama-config.js
- Add migrate-table-prefix.js script for database migration
- Update db_schema.sql with new table names
- Update views: 5Why_user_analysis_stats, 5Why_recent_analyses

Tables renamed:
- users -> 5Why_users
- analyses -> 5Why_analyses
- analysis_perspectives -> 5Why_analysis_perspectives
- analysis_whys -> 5Why_analysis_whys
- llm_configs -> 5Why_llm_configs
- system_settings -> 5Why_system_settings
- audit_logs -> 5Why_audit_logs
- sessions -> 5Why_sessions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
donald
2025-12-09 18:19:53 +08:00
parent 66cdcacce9
commit f9ee43b73c
9 changed files with 552 additions and 62 deletions

View File

@@ -13,7 +13,7 @@ class Analysis {
try {
const [result] = await pool.execute(
`INSERT INTO analyses (user_id, finding, job_content, output_language, status)
`INSERT INTO 5Why_analyses (user_id, finding, job_content, output_language, status)
VALUES (?, ?, ?, ?, 'pending')`,
[user_id, finding, job_content, output_language]
);
@@ -30,7 +30,7 @@ class Analysis {
static async findById(id) {
try {
const [rows] = await pool.execute(
'SELECT * FROM analyses WHERE id = ?',
'SELECT * FROM 5Why_analyses WHERE id = ?',
[id]
);
return rows[0] || null;
@@ -45,7 +45,7 @@ class Analysis {
static async updateStatus(id, status, errorMessage = null) {
try {
await pool.execute(
'UPDATE analyses SET status = ?, error_message = ? WHERE id = ?',
'UPDATE 5Why_analyses SET status = ?, error_message = ? WHERE id = ?',
[status, errorMessage, id]
);
} catch (error) {
@@ -66,7 +66,7 @@ class Analysis {
try {
// 更新主分析記錄
await connection.execute(
`UPDATE analyses
`UPDATE 5Why_analyses
SET problem_restatement = ?, analysis_result = ?, processing_time = ?, status = 'completed'
WHERE id = ?`,
[problem_restatement, JSON.stringify(analysis_result), processing_time, id]
@@ -76,7 +76,7 @@ class Analysis {
if (analysis_result.analyses && Array.isArray(analysis_result.analyses)) {
for (const perspective of analysis_result.analyses) {
const [perspectiveResult] = await connection.execute(
`INSERT INTO analysis_perspectives
`INSERT INTO 5Why_analysis_perspectives
(analysis_id, perspective, perspective_icon, root_cause, permanent_solution,
logic_check_forward, logic_check_backward, logic_valid)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
@@ -99,7 +99,7 @@ class Analysis {
for (const why of perspective.whys) {
if (why && why.level) {
await connection.execute(
`INSERT INTO analysis_whys
`INSERT INTO 5Why_analysis_whys
(perspective_id, level, question, answer, is_verified, verification_note)
VALUES (?, ?, ?, ?, ?, ?)`,
[
@@ -136,8 +136,8 @@ class Analysis {
*/
static async getByUserId(userId, page = 1, limit = 10, filters = {}) {
const offset = (page - 1) * limit;
let query = 'SELECT * FROM analyses WHERE user_id = ?';
let countQuery = 'SELECT COUNT(*) as total FROM analyses WHERE user_id = ?';
let query = 'SELECT * FROM 5Why_analyses WHERE user_id = ?';
let countQuery = 'SELECT COUNT(*) as total FROM 5Why_analyses WHERE user_id = ?';
const whereParams = [userId];
const whereClauses = [];
@@ -168,8 +168,9 @@ class Analysis {
query += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
try {
const [rows] = await pool.execute(query, [...whereParams, limit, offset]);
const [countResult] = await pool.execute(countQuery, whereParams);
// 使用 pool.query 而非 pool.execute因為 LIMIT/OFFSET 需要數字類型
const [rows] = await pool.query(query, [...whereParams, parseInt(limit), parseInt(offset)]);
const [countResult] = await pool.query(countQuery, whereParams);
return {
data: rows,
@@ -192,10 +193,10 @@ class Analysis {
const offset = (page - 1) * limit;
let query = `
SELECT a.*, u.username, u.employee_id
FROM analyses a
JOIN users u ON a.user_id = u.id
FROM 5Why_analyses a
JOIN 5Why_users u ON a.user_id = u.id
`;
let countQuery = 'SELECT COUNT(*) as total FROM analyses a JOIN users u ON a.user_id = u.id';
let countQuery = 'SELECT COUNT(*) as total FROM 5Why_analyses a JOIN 5Why_users u ON a.user_id = u.id';
const whereParams = [];
const whereClauses = [];
@@ -223,8 +224,9 @@ class Analysis {
query += ' ORDER BY a.created_at DESC LIMIT ? OFFSET ?';
try {
const [rows] = await pool.execute(query, [...whereParams, limit, offset]);
const [countResult] = await pool.execute(countQuery, whereParams);
// 使用 pool.query 而非 pool.execute因為 LIMIT/OFFSET 需要數字類型
const [rows] = await pool.query(query, [...whereParams, parseInt(limit), parseInt(offset)]);
const [countResult] = await pool.query(countQuery, whereParams);
return {
data: rows,
@@ -251,14 +253,14 @@ class Analysis {
// 取得分析角度
const [perspectives] = await pool.execute(
'SELECT * FROM analysis_perspectives WHERE analysis_id = ? ORDER BY id',
'SELECT * FROM 5Why_analysis_perspectives WHERE analysis_id = ? ORDER BY id',
[id]
);
// 為每個角度取得 Whys
for (const perspective of perspectives) {
const [whys] = await pool.execute(
'SELECT * FROM analysis_whys WHERE perspective_id = ? ORDER BY level',
'SELECT * FROM 5Why_analysis_whys WHERE perspective_id = ? ORDER BY level',
[perspective.id]
);
perspective.whys = whys;
@@ -277,7 +279,7 @@ class Analysis {
*/
static async delete(id) {
try {
await pool.execute('DELETE FROM analyses WHERE id = ?', [id]);
await pool.execute('DELETE FROM 5Why_analyses WHERE id = ?', [id]);
return true;
} catch (error) {
throw new Error(`Error deleting analysis: ${error.message}`);
@@ -289,9 +291,10 @@ class Analysis {
*/
static async getRecent(limit = 100) {
try {
const [rows] = await pool.execute(
'SELECT * FROM recent_analyses LIMIT ?',
[limit]
// 使用 pool.query 而非 pool.execute因為 LIMIT 需要數字類型
const [rows] = await pool.query(
'SELECT * FROM 5Why_recent_analyses LIMIT ?',
[parseInt(limit)]
);
return rows;
} catch (error) {
@@ -312,7 +315,7 @@ class Analysis {
COUNT(CASE WHEN status = 'processing' THEN 1 END) as processing,
AVG(processing_time) as avg_processing_time,
MAX(created_at) as last_analysis_at
FROM analyses
FROM 5Why_analyses
`;
const params = [];

View File

@@ -24,7 +24,7 @@ class AuditLog {
try {
await pool.execute(
`INSERT INTO audit_logs
`INSERT INTO 5Why_audit_logs
(user_id, action, entity_type, entity_id, old_value, new_value,
ip_address, user_agent, status, error_message)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
@@ -126,10 +126,10 @@ class AuditLog {
const offset = (page - 1) * limit;
let query = `
SELECT al.*, u.username, u.employee_id
FROM audit_logs al
LEFT JOIN users u ON al.user_id = u.id
FROM 5Why_audit_logs al
LEFT JOIN 5Why_users u ON al.user_id = u.id
`;
let countQuery = 'SELECT COUNT(*) as total FROM audit_logs al';
let countQuery = 'SELECT COUNT(*) as total FROM 5Why_audit_logs al';
const params = [];
const whereClauses = [];
@@ -166,11 +166,12 @@ class AuditLog {
}
query += ' ORDER BY al.created_at DESC LIMIT ? OFFSET ?';
params.push(limit, offset);
params.push(parseInt(limit), parseInt(offset));
try {
const [rows] = await pool.execute(query, params);
const [countResult] = await pool.execute(countQuery, params.slice(0, -2));
// 使用 pool.query 而非 pool.execute因為 LIMIT/OFFSET 需要數字類型
const [rows] = await pool.query(query, params);
const [countResult] = await pool.query(countQuery, params.slice(0, -2));
return {
data: rows,
@@ -199,7 +200,7 @@ class AuditLog {
static async cleanup(daysToKeep = 90) {
try {
const [result] = await pool.execute(
'DELETE FROM audit_logs WHERE created_at < DATE_SUB(NOW(), INTERVAL ? DAY)',
'DELETE FROM 5Why_audit_logs WHERE created_at < DATE_SUB(NOW(), INTERVAL ? DAY)',
[daysToKeep]
);
return result.affectedRows;

View File

@@ -12,7 +12,7 @@ class User {
static async findById(id) {
try {
const [rows] = await pool.execute(
'SELECT id, employee_id, username, email, role, department, position, is_active, created_at, last_login_at FROM users WHERE id = ?',
'SELECT id, employee_id, username, email, role, department, position, is_active, created_at, last_login_at FROM 5Why_users WHERE id = ?',
[id]
);
return rows[0] || null;
@@ -27,7 +27,7 @@ class User {
static async findByEmail(email) {
try {
const [rows] = await pool.execute(
'SELECT * FROM users WHERE email = ? AND is_active = 1',
'SELECT * FROM 5Why_users WHERE email = ? AND is_active = 1',
[email]
);
return rows[0] || null;
@@ -42,7 +42,7 @@ class User {
static async findByEmployeeId(employeeId) {
try {
const [rows] = await pool.execute(
'SELECT * FROM users WHERE employee_id = ? AND is_active = 1',
'SELECT * FROM 5Why_users WHERE employee_id = ? AND is_active = 1',
[employeeId]
);
return rows[0] || null;
@@ -69,7 +69,7 @@ class User {
const passwordHash = await bcrypt.hash(password, 10);
const [result] = await pool.execute(
`INSERT INTO users (employee_id, username, email, password_hash, role, department, position)
`INSERT INTO 5Why_users (employee_id, username, email, password_hash, role, department, position)
VALUES (?, ?, ?, ?, ?, ?, ?)`,
[employee_id, username, email, passwordHash, role, department, position]
);
@@ -91,7 +91,7 @@ class User {
try {
await pool.execute(
`UPDATE users
`UPDATE 5Why_users
SET username = ?, email = ?, role = ?, department = ?, position = ?, is_active = ?
WHERE id = ?`,
[username, email, role, department, position, is_active, id]
@@ -110,7 +110,7 @@ class User {
try {
const passwordHash = await bcrypt.hash(newPassword, 10);
await pool.execute(
'UPDATE users SET password_hash = ? WHERE id = ?',
'UPDATE 5Why_users SET password_hash = ? WHERE id = ?',
[passwordHash, id]
);
return true;
@@ -125,7 +125,7 @@ class User {
static async updateLastLogin(id) {
try {
await pool.execute(
'UPDATE users SET last_login_at = CURRENT_TIMESTAMP WHERE id = ?',
'UPDATE 5Why_users SET last_login_at = CURRENT_TIMESTAMP WHERE id = ?',
[id]
);
} catch (error) {
@@ -138,8 +138,8 @@ class User {
*/
static async getAll(page = 1, limit = 10, filters = {}) {
const offset = (page - 1) * limit;
let query = 'SELECT id, employee_id, username, email, role, department, position, is_active, created_at FROM users';
let countQuery = 'SELECT COUNT(*) as total FROM users';
let query = 'SELECT id, employee_id, username, email, role, department, position, is_active, created_at FROM 5Why_users';
let countQuery = 'SELECT COUNT(*) as total FROM 5Why_users';
const whereParams = [];
const whereClauses = [];
@@ -167,8 +167,9 @@ class User {
query += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
try {
const [rows] = await pool.execute(query, [...whereParams, limit, offset]);
const [countResult] = await pool.execute(countQuery, whereParams);
// 使用 query 而非 execute因為 LIMIT 和 OFFSET 參數需要數字類型
const [rows] = await pool.query(query, [...whereParams, parseInt(limit), parseInt(offset)]);
const [countResult] = await pool.query(countQuery, whereParams);
return {
data: rows,
@@ -190,7 +191,7 @@ class User {
static async delete(id) {
try {
await pool.execute(
'UPDATE users SET is_active = 0 WHERE id = ?',
'UPDATE 5Why_users SET is_active = 0 WHERE id = ?',
[id]
);
return true;
@@ -204,7 +205,7 @@ class User {
*/
static async hardDelete(id) {
try {
await pool.execute('DELETE FROM users WHERE id = ?', [id]);
await pool.execute('DELETE FROM 5Why_users WHERE id = ?', [id]);
return true;
} catch (error) {
throw new Error(`Error hard deleting user: ${error.message}`);
@@ -217,7 +218,7 @@ class User {
static async getStats(userId) {
try {
const [rows] = await pool.execute(
'SELECT * FROM user_analysis_stats WHERE user_id = ?',
'SELECT * FROM 5Why_user_analysis_stats WHERE user_id = ?',
[userId]
);
return rows[0] || null;