diff --git a/backend/src/modules/ai/ai-settings.service.ts b/backend/src/modules/ai/ai-settings.service.ts index c9a2edff..eb08b0ca 100644 --- a/backend/src/modules/ai/ai-settings.service.ts +++ b/backend/src/modules/ai/ai-settings.service.ts @@ -1,6 +1,7 @@ // File: src/modules/ai/ai-settings.service.ts // Change Log // - 2026-05-21: เพิ่ม service สำหรับอ่าน/เขียน AI feature toggle พร้อม Redis cache. +// - 2026-05-22: เพิ่ม try-catch ใน getAiFeaturesEnabled() เพื่อความยืดหยุ่นในกรณีที่ฐานข้อมูลยังไม่ได้อัปเกรดตาราง system_settings import { Injectable, Logger } from '@nestjs/common'; import { InjectRedis } from '@nestjs-modules/ioredis'; @@ -26,14 +27,21 @@ export class AiSettingsService { /** อ่านสถานะเปิด/ปิด AI features โดยใช้ Redis cache ก่อน DB */ async getAiFeaturesEnabled(): Promise { - const cachedValue = await this.getCachedValue(); - if (cachedValue !== null) return cachedValue === 'true'; - const setting = await this.settingRepo.findOne({ - where: { settingKey: AI_FEATURES_ENABLED_KEY }, - }); - const enabled = setting ? setting.settingValue === 'true' : true; - await this.setCachedValue(enabled); - return enabled; + try { + const cachedValue = await this.getCachedValue(); + if (cachedValue !== null) return cachedValue === 'true'; + const setting = await this.settingRepo.findOne({ + where: { settingKey: AI_FEATURES_ENABLED_KEY }, + }); + const enabled = setting ? setting.settingValue === 'true' : true; + await this.setCachedValue(enabled); + return enabled; + } catch (error: unknown) { + this.logger.error( + `Failed to retrieve AI features enabled setting from database: ${this.toMessage(error)}` + ); + return true; + } } /** อัปเดตสถานะ AI features ใน transaction แล้ว invalid cache หลัง DB สำเร็จ */ diff --git a/specs/03-Data-and-Storage/03-01-data-dictionary.md b/specs/03-Data-and-Storage/03-01-data-dictionary.md index 2edbcb01..43d75bb7 100644 --- a/specs/03-Data-and-Storage/03-01-data-dictionary.md +++ b/specs/03-Data-and-Storage/03-01-data-dictionary.md @@ -146,6 +146,10 @@ erDiagram AI | UNIQUE identifier | | contract_id | INT | FK, NOT NULL | ผูกกับสัญญา | | discipline_code | VARCHAR(10) | NOT NULL | รหัสสาขา (เช่น GEN, STR) | | code_name_th | VARCHAR(255) | NULL | ชื่อไทย | | code_name_en | VARCHAR(255) | NULL | ชื่ออังกฤษ | | is_active | TINYINT(1) | DEFAULT 1 | สถานะการใช้งาน | ** INDEXES \*\*: - UNIQUE (contract_id, discipline_code) --- + ### 1.6 system_settings (NEW v1.9.0) + - - Purpose **: ตารางเก็บข้อมูลการตั้งค่าระบบแบบไดนามิก (เช่น สถานะการเปิด/ปิด AI features ทั่วทั้งระบบ) | COLUMN Name | Data TYPE | Constraints | Description | |: -------------- | :----------- | :----------- | :--------------------- | + | id | INT | PK, AI | ID ของตาราง | | setting_key | VARCHAR(100) | NOT NULL, UNIQUE | คีย์การตั้งค่าระบบ (เช่น 'AI_FEATURES_ENABLED') | | setting_value | TEXT | NOT NULL | ค่าที่บันทึก (stringified) | | data_type | ENUM | NOT NULL, DEFAULT 'string' | ประเภทข้อมูลสำหรับ validation ('string', 'number', 'boolean', 'json') | | category | VARCHAR(50) | NULL | หมวดหมู่การตั้งค่า (เช่น 'ai') | | is_encrypted | TINYINT(1) | DEFAULT 0 | เข้ารหัสค่า sensitive (1 = เข้ารหัส, 0 = ไม่เข้ารหัส) | | validation_rules | JSON | NULL | กฎ validation (min, max, allowed_values) | | description | TEXT | NULL | คำอธิบายข้อมูลการตั้งค่า | | is_public | TINYINT(1) | DEFAULT 0 | เผยแพร่ให้ frontend อ่านได้หรือ admin เท่านั้น (1 = เผยแพร่, 0 = แอดมินเท่านั้น) | | updated_by | INT | FK, NULL | ผู้แก้ไขล่าสุด | | created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | เวลาสร้างเรคคอร์ด | | updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE | เวลาอัปเดตเรคคอร์ดล่าสุด | ** INDEXES \*\*: - PRIMARY KEY (id) - UNIQUE (setting_key) - FOREIGN KEY (updated_by) REFERENCES users(user_id) ON DELETE SET NULL - INDEX idx_system_settings_category (category) - INDEX idx_system_settings_is_public (is_public) ** Business Rules \*\*: - ใช้เก็บค่าการตั้งค่าระดับระบบที่ต้องการปรับเปลี่ยนแบบไดนามิกผ่านหน้า Admin Console - คีย์ `AI_FEATURES_ENABLED` ควบคุมสถานะการทำงานของฟีเจอร์ AI สำหรับผู้ใช้ทั่วไป --- + ## **2. 👥 Users & RBAC Tables (ผู้ใช้, สิทธิ์, บทบาท)** ### 2.1 users diff --git a/specs/03-Data-and-Storage/deltas/2026-05-22-create-system-settings-table.rollback.sql b/specs/03-Data-and-Storage/deltas/2026-05-22-create-system-settings-table.rollback.sql new file mode 100644 index 00000000..a38a62fa --- /dev/null +++ b/specs/03-Data-and-Storage/deltas/2026-05-22-create-system-settings-table.rollback.sql @@ -0,0 +1,10 @@ +-- Delta Rollback: ลบตาราง system_settings +-- Date: 2026-05-22 +-- Related ADR: ADR-027 +-- Applied in: v1.9.0 -> v1.9.5 + +-- ------------------------------------------------------------ +-- การย้อนกลับโครงสร้างฐานข้อมูล (Rollback changes) +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS system_settings; diff --git a/specs/03-Data-and-Storage/deltas/2026-05-22-create-system-settings-table.sql b/specs/03-Data-and-Storage/deltas/2026-05-22-create-system-settings-table.sql new file mode 100644 index 00000000..35ad797f --- /dev/null +++ b/specs/03-Data-and-Storage/deltas/2026-05-22-create-system-settings-table.sql @@ -0,0 +1,48 @@ +-- Delta: สร้างตาราง system_settings และ Seed ข้อมูล AI_FEATURES_ENABLED +-- Date: 2026-05-22 +-- Related ADR: ADR-027 +-- Applied in: v1.9.0 -> v1.9.5 + +-- ------------------------------------------------------------ +-- การเปลี่ยนแปลงโครงสร้างฐานข้อมูล (Schema changes) +-- ------------------------------------------------------------ + +CREATE TABLE IF NOT EXISTS system_settings ( + id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของตาราง', + setting_key VARCHAR(100) NOT NULL UNIQUE COMMENT 'คีย์การตั้งค่าระบบ', + setting_value TEXT NOT NULL COMMENT 'ค่าที่บันทึก (stringified)', + data_type ENUM('string', 'number', 'boolean', 'json') NOT NULL DEFAULT 'string' COMMENT 'ประเภทข้อมูลสำหรับ validation', + category VARCHAR(50) COMMENT 'หมวดหมู่', + is_encrypted TINYINT(1) DEFAULT 0 COMMENT 'เข้ารหัสค่า sensitive', + validation_rules JSON COMMENT 'กฎ validation', + description TEXT COMMENT 'คำอธิบายข้อมูลการตั้งค่า', + is_public TINYINT(1) DEFAULT 0 COMMENT 'เผยแพร่ให้ frontend อ่านได้หรือ admin only', + updated_by INT COMMENT 'ผู้แก้ไขล่าสุด', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + FOREIGN KEY (updated_by) REFERENCES users(user_id) ON DELETE SET NULL, + INDEX idx_system_settings_category (category), + INDEX idx_system_settings_is_public (is_public) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเก็บข้อมูลการตั้งค่าระบบไดนามิก'; + +-- ------------------------------------------------------------ +-- การเพิ่มข้อมูลพื้นฐาน (Seed Data) +-- ------------------------------------------------------------ + +INSERT INTO system_settings ( + setting_key, + setting_value, + data_type, + category, + description, + is_public +) +VALUES ( + 'AI_FEATURES_ENABLED', + 'true', + 'boolean', + 'ai', + 'สถานะเปิด/ปิดการใช้งานฟีเจอร์ AI ทั้งระบบ สำหรับผู้ใช้ทั่วไป', + 1 +) +ON DUPLICATE KEY UPDATE setting_key = setting_key;