feat(rfa-ai): Complete RFA Approval Refactor and AI Model Revision
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
---
|
||||
title: 'Data & Storage: Data Dictionary and Data Model Architecture'
|
||||
version: 1.9.0
|
||||
version: 1.9.1
|
||||
status: released
|
||||
owner: Nattanin Peancharoen
|
||||
last_updated: 2026-04-14
|
||||
last_updated: 2026-05-16
|
||||
related:
|
||||
- specs/01-requirements/02-architecture.md
|
||||
- specs/01-requirements/03-functional-requirements.md
|
||||
@@ -1372,6 +1372,7 @@ erDiagram
|
||||
| checksum | VARCHAR(64) | NULL | SHA-256 Checksum สำหรับ Verify File Integrity [Req 3.9.3] |
|
||||
| reference_date | DATE | NULL | Date used for folder structure (e.g. Issue Date) to prevent broken paths |
|
||||
| workflow_history_id | VARCHAR(36) | NULL, FK | **[ADR-021]** อ้างอิง workflow_histories.publicId — NULL = ไฟล์แนบหลักของเอกสาร; NOT NULL = ไฟล์หลักฐานประจำ Workflow Step |
|
||||
| ai_processing_status | ENUM | NOT NULL, DEFAULT 'PENDING' | **[ADR-023A]** สถานะ AI job ของไฟล์เอกสาร: PENDING / PROCESSING / DONE / FAILED |
|
||||
|
||||
**Indexes**:
|
||||
|
||||
@@ -1384,6 +1385,7 @@ erDiagram
|
||||
- INDEX (created_at)
|
||||
- INDEX (reference_date)
|
||||
- INDEX (workflow_history_id)
|
||||
- INDEX idx_attachments_ai_status (ai_processing_status)
|
||||
|
||||
**Relationships**:
|
||||
|
||||
@@ -2286,29 +2288,86 @@ PENDING_REVIEW ──→ VERIFIED ──→ IMPORTED (terminal)
|
||||
|
||||
---
|
||||
|
||||
### 19.2 `ai_audit_logs`
|
||||
### 19.1 `migration_review_queue`
|
||||
|
||||
**วัตถุประสงค์:** บันทึก Audit Trail ของ AI Interaction ทุกครั้ง ตาม ADR-018 Rule 5 — ห้ามลบ record ออก
|
||||
**วัตถุประสงค์:** ตาราง staging queue สำหรับ AI migration ตาม ADR-023A — เก็บข้อมูลเอกสาร legacy ที่ AI ประมวลผลแล้วรอ Admin ตรวจสอบ
|
||||
|
||||
| Column | Type | Nullable | Description |
|
||||
|--------|------|----------|-------------|
|
||||
| `id` | INT AUTO_INCREMENT | NO | Internal PK — ห้าม expose ใน API (ADR-019) |
|
||||
| `uuid` | UUID | NO | Public Identifier (UUIDv7) |
|
||||
| `document_public_id` | UUID | YES | UUID ของ `migration_logs` ที่เกี่ยวข้อง (Soft Reference — ไม่ใช่ FK ในระดับ TypeORM) |
|
||||
| `ai_model` | VARCHAR(50) | NO | ชื่อ AI Model เช่น `gemma4`, `paddleocr`, `gemma4:27b` |
|
||||
| `processing_time_ms` | INT | YES | เวลาประมวลผล (milliseconds) — เป้าหมาย < 15,000ms ตาม ADR-020 |
|
||||
| `confidence_score` | DECIMAL(3,2) | YES | คะแนนความมั่นใจ (0.00–1.00) |
|
||||
| `input_hash` | VARCHAR(64) | YES | SHA-256 hash ของ Input — เพื่อ Integrity Verification |
|
||||
| `output_hash` | VARCHAR(64) | YES | SHA-256 hash ของ Output — เพื่อ Integrity Verification |
|
||||
| `status` | ENUM | NO | ผลการประมวลผล: SUCCESS / FAILED / TIMEOUT |
|
||||
| `error_message` | TEXT | YES | รายละเอียด Error (เมื่อ status = FAILED หรือ TIMEOUT) |
|
||||
| `created_at` | TIMESTAMP | NO | วันที่สร้าง — เรียงตาม timestamp เพื่อ Audit |
|
||||
| `batch_id` | VARCHAR(100) | NO | n8n batch identifier |
|
||||
| `idempotency_key` | VARCHAR(200) | NO | Idempotency-Key สำหรับป้องกัน queue ซ้ำ |
|
||||
| `original_filename` | VARCHAR(500) | NO | ชื่อไฟล์ต้นฉบับจาก legacy source |
|
||||
| `storage_temp_path` | VARCHAR(1000) | NO | temp storage path ก่อน import |
|
||||
| `ai_metadata_json` | JSON | NO | AI suggestion payload เต็มสำหรับ human review |
|
||||
| `confidence_score` | DECIMAL(5,4) | NO | AI confidence score 0.0000-1.0000 |
|
||||
| `ocr_used` | TINYINT(1) | NO | ระบุว่าใช้ OCR path หรือไม่ (default: 0) |
|
||||
| `status` | ENUM | NO | สถานะ: PENDING / APPROVED / IMPORTED / REJECTED |
|
||||
| `reviewed_by` | INT | YES | Internal users.user_id ของผู้ review |
|
||||
| `reviewed_at` | DATETIME | YES | เวลาที่ review record |
|
||||
| `rejection_reason` | VARCHAR(500) | YES | เหตุผลเมื่อ reject |
|
||||
| `version` | INT | NO | Optimistic locking version |
|
||||
| `created_at` | DATETIME | NO | วันที่สร้าง |
|
||||
| `updated_at` | DATETIME | NO | วันที่แก้ไขล่าสุด |
|
||||
|
||||
**Indexes**:
|
||||
|
||||
- PRIMARY KEY (id)
|
||||
- UNIQUE KEY uq_migration_review_uuid (uuid)
|
||||
- UNIQUE KEY uq_migration_review_idempotency (idempotency_key)
|
||||
- KEY idx_migration_review_status_created (status, created_at)
|
||||
- KEY idx_migration_review_batch (batch_id)
|
||||
- KEY idx_migration_review_reviewed_by (reviewed_by)
|
||||
- CONSTRAINT fk_migration_review_reviewed_by FOREIGN KEY (reviewed_by) REFERENCES users (user_id) ON DELETE SET NULL
|
||||
|
||||
#### Business Rules
|
||||
|
||||
1. **Immutable Records** — ห้ามแก้ไขหรือลบ `ai_audit_logs` หลังสร้าง (Audit Trail)
|
||||
2. **Data Retention** — เก็บไว้อย่างน้อย 90 วัน ตาม ADR-020 Data Privacy
|
||||
3. **No FK Constraint** — `document_public_id` เป็น Soft Reference เพื่อให้ Log ยังคงอยู่แม้ MigrationLog ถูกลบ
|
||||
1. **Staging Area** — ข้อมูลที่ประมวลผลผ่าน n8n จะถูกส่งเข้าตารางนี้เสมอ
|
||||
2. **Record Lifecycle** — Record ไม่ถูกลบหลัง Import — เปลี่ยน status เป็น IMPORTED เก็บไว้ตลอดเพื่อ Debug
|
||||
3. **Status Transitions** — PENDING → IMPORTED หรือ PENDING → REJECTED
|
||||
4. **Confidence Threshold** — กำหนดผ่าน .env (AI_THRESHOLD_HIGH=0.85, AI_THRESHOLD_MID=0.60)
|
||||
|
||||
---
|
||||
|
||||
### 19.2 `ai_audit_logs`
|
||||
|
||||
**วัตถุประสงค์:** บันทึก AI Development Feedback Log ตาม ADR-023/ADR-023A — เก็บ AI Suggestion + การตัดสินใจของมนุษย์เพื่อวิเคราะห์และปรับปรุงคุณภาพโมเดล (ไม่ใช่ Compliance Audit Trail)
|
||||
|
||||
| Column | Type | Nullable | Description |
|
||||
|--------|------|----------|-------------|
|
||||
| `id` | INT AUTO_INCREMENT | NO | Internal PK — ห้าม expose ใน API (ADR-019) |
|
||||
| `uuid` | UUID | NO | Public Identifier (UUIDv7) |
|
||||
| `document_public_id` | UUID | YES | Imported document publicId when available |
|
||||
| `ai_model` | VARCHAR(50) | NO | Legacy AI model column used by current gateway service (default: gemma4) |
|
||||
| `model_name` | VARCHAR(100) | NO | Local model name used by ADR-023 AI pipeline |
|
||||
| `ai_suggestion_json` | JSON | YES | AI suggested metadata |
|
||||
| `human_override_json` | JSON | YES | Human approved or overridden metadata |
|
||||
| `processing_time_ms` | INT | YES | Legacy processing duration field |
|
||||
| `confidence_score` | DECIMAL(4,3) | YES | AI confidence score 0.000-1.000 |
|
||||
| `input_hash` | VARCHAR(64) | YES | Legacy SHA-256 input hash |
|
||||
| `output_hash` | VARCHAR(64) | YES | Legacy SHA-256 output hash |
|
||||
| `status` | ENUM | NO | Legacy processing status field: SUCCESS / FAILED / TIMEOUT |
|
||||
| `error_message` | TEXT | YES | Legacy processing error field |
|
||||
| `confirmed_by_user_id` | INT | YES | Internal users.user_id that confirmed the record |
|
||||
| `created_at` | TIMESTAMP | NO | วันที่สร้าง |
|
||||
|
||||
**Indexes**:
|
||||
|
||||
- PRIMARY KEY (id)
|
||||
- UNIQUE KEY idx_ai_audit_logs_uuid (uuid)
|
||||
- KEY idx_ai_audit_document (document_public_id)
|
||||
- KEY idx_ai_audit_model (ai_model)
|
||||
- KEY idx_ai_audit_model_name (model_name)
|
||||
- KEY idx_ai_audit_status (status)
|
||||
- KEY idx_ai_audit_confirmed_by (confirmed_by_user_id)
|
||||
- CONSTRAINT fk_ai_audit_confirmed_by_user FOREIGN KEY (confirmed_by_user_id) REFERENCES users (user_id) ON DELETE SET NULL
|
||||
|
||||
#### Business Rules
|
||||
|
||||
1. **Development Feedback Log** — เป็น log สำหรับวิเคราะห์และปรับปรุงคุณภาพโมเดล AI ไม่ใช่ Compliance Audit Trail
|
||||
2. **Data Retention** — เก็บไว้ตลอดอายุโครงการ (~5-10 ปี) — Admin สามารถ Hard Delete ได้ผ่าน Frontend
|
||||
3. **RBAC** — เฉพาะ Role SYSTEM_ADMIN เท่านั้นที่ลบได้ — การลบทุกครั้งต้องบันทึกใน audit_logs (action: 'AI_AUDIT_LOG_DELETED')
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
# Data and Storage Specifications
|
||||
|
||||
เอกสารและสคริปต์ที่เกี่ยวข้องกับการจัดการข้อมูลและการจัดเก็บสำหรับระบบ NAP-DMS (LCBP3)
|
||||
|
||||
## 📁 โครงสร้างไดเรกทอรี
|
||||
|
||||
### Schema Files (สคริปต์ฐานข้อมูล)
|
||||
|
||||
| ไฟล์ | คำอธิบาย |
|
||||
|------|-----------|
|
||||
| `lcbp3-v1.9.0-schema-01-drop.sql` | สคริปต์ลบตารางทั้งหมด (ใช้สำหรับ reset schema) |
|
||||
| `lcbp3-v1.9.0-schema-02-tables.sql` | สคริปต์สร้างตารางทั้งหมด (CREATE TABLE) |
|
||||
| `lcbp3-v1.9.0-schema-03-views-indexes.sql` | สคริปต์สร้าง Views และ Indexes |
|
||||
| `lcbp3-v1.9.0-migration.sql` | สคริปต์ migration สำหรับการอัปเกรดจากเวอร์ชันก่อนหน้า |
|
||||
| `lcbp3-v1.9.0-rfa-approval-schema.sql` | Schema เฉพาะสำหรับระบบ RFA Approval System |
|
||||
|
||||
### Seed Files (ข้อมูลเริ่มต้น)
|
||||
|
||||
| ไฟล์ | คำอธิบาย |
|
||||
|------|-----------|
|
||||
| `lcbp3-v1.9.0-seed-basic.sql` | ข้อมูลเริ่มต้นพื้นฐาน (Organizations, Users, Roles, Permissions) |
|
||||
| `lcbp3-v1.9.0-seed-permissions.sql` | ข้อมูล RBAC Permissions ตาม ADR-016 |
|
||||
| `lcbp3-v1.9.0-seed-contractdrawing.sql` | ข้อมูล Contract Drawings ตัวอย่าง |
|
||||
| `lcbp3-v1.9.0-seed-shopdrawing.sql` | ข้อมูล Shop Drawings ตัวอย่าง |
|
||||
|
||||
### Delta Files (การเปลี่ยนแปลง Schema แบบ Incremental)
|
||||
|
||||
ตั้งอยู่ใน `deltas/` - เก็บ SQL delta สำหรับการเปลี่ยนแปลง schema ตาม ADR-009 (ไม่ใช้ TypeORM migrations)
|
||||
|
||||
| ไฟล์ | คำอธิบาย |
|
||||
|------|-----------|
|
||||
| `12-unified-ai-architecture.sql` | เพิ่มตาราง AI: migration_review_queue, ai_audit_logs (ADR-023) |
|
||||
| `14-add-migration-review-queue.sql` | เพิ่มคอลัมน์ใหม่ใน migration_review_queue (ADR-023A) |
|
||||
| `15-add-ai-processing-status.sql` | เพิ่ม ai_processing_status ใน attachments (ADR-023A) |
|
||||
|
||||
### Documentation
|
||||
|
||||
| ไฟล์ | คำอธิบาย |
|
||||
|------|-----------|
|
||||
| `0.md` | ภาพรวมและแนวทางการจัดการข้อมูล |
|
||||
| `03-01-data-dictionary.md` | Data Dictionary คำอธิบายฟิลด์ทั้งหมด |
|
||||
| `03-02-db-indexing.md` | กลยุทธ์การสร้าง Indexes |
|
||||
| `03-03-file-storage.md` | กลยุทธ์การจัดเก็บไฟล์ (Two-Phase Upload) |
|
||||
| `03-04-legacy-data-migration.md` | แผนการนำเข้าข้อมูลเก่า (Legacy Migration) |
|
||||
| `03-05-n8n-migration-setup-guide.md` | คู่มือติดตั้ง n8n สำหรับ Migration Phase |
|
||||
| `03-06-migration-business-scope.md` | ขอบเขตการทำ Migration ตาม ADR-009 |
|
||||
| `03-07-OpenRAG.md` | เอกสาร RAG Implementation Guide |
|
||||
|
||||
### Configuration Files
|
||||
|
||||
| ไฟล์ | คำอธิบาย |
|
||||
|------|-----------|
|
||||
| `n8n.workflow.json` | Workflow n8n สำหรับ Legacy Document Migration |
|
||||
| `permissions-verification.sql` | สคริปต์ตรวจสอบ Permissions ที่กำหนดไว้ |
|
||||
|
||||
## 🚀 การใช้งาน
|
||||
|
||||
### การ Setup ฐานข้อมูลใหม่ (Fresh Install)
|
||||
|
||||
```bash
|
||||
# 1. ลบตารางทั้งหมด (ถ้ามี)
|
||||
mysql < lcbp3-v1.9.0-schema-01-drop.sql
|
||||
|
||||
# 2. สร้างตารางทั้งหมด
|
||||
mysql < lcbp3-v1.9.0-schema-02-tables.sql
|
||||
|
||||
# 3. สร้าง Views และ Indexes
|
||||
mysql < lcbp3-v1.9.0-schema-03-views-indexes.sql
|
||||
|
||||
# 4. เพิ่มข้อมูลเริ่มต้นพื้นฐาน
|
||||
mysql < lcbp3-v1.9.0-seed-basic.sql
|
||||
|
||||
# 5. เพิ่ม Permissions
|
||||
mysql < lcbp3-v1.9.0-seed-permissions.sql
|
||||
|
||||
# 6. เพิ่มข้อมูลตัวอย่าง (Optional)
|
||||
mysql < lcbp3-v1.9.0-seed-contractdrawing.sql
|
||||
mysql < lcbp3-v1.9.0-seed-shopdrawing.sql
|
||||
```
|
||||
|
||||
### การอัปเกรดจากเวอร์ชันก่อนหน้า
|
||||
|
||||
```bash
|
||||
# รัน migration script
|
||||
mysql < lcbp3-v1.9.0-migration.sql
|
||||
|
||||
# รัน delta files ที่ยังไม่ได้ใช้ (ตามลำดับเลข)
|
||||
mysql < deltas/12-unified-ai-architecture.sql
|
||||
mysql < deltas/14-add-migration-review-queue.sql
|
||||
mysql < deltas/15-add-ai-processing-status.sql
|
||||
```
|
||||
|
||||
## 🔗 เอกสารที่เกี่ยวข้อง
|
||||
|
||||
### ADRs (Architecture Decision Records)
|
||||
|
||||
- **ADR-009**: Database Migration Strategy - ใช้ SQL delta โดยตรง ห้ามใช้ TypeORM migrations
|
||||
- **ADR-016**: Security & Authentication - RBAC Matrix
|
||||
- **ADR-019**: Hybrid Identifier Strategy - UUID Strategy
|
||||
- **ADR-023**: Unified AI Architecture - สถาปัตยกรรม AI หลัก
|
||||
- **ADR-023A**: Unified AI Architecture (Model Revision) - อัปเดตโมเดล AI
|
||||
|
||||
### Engineering Guidelines
|
||||
|
||||
- `specs/05-Engineering-Guidelines/05-02-backend-guidelines.md` - Backend patterns
|
||||
- `specs/05-Engineering-Guidelines/05-03-frontend-guidelines.md` - Frontend patterns
|
||||
|
||||
## ⚠️ ข้อควรระวัง
|
||||
|
||||
1. **ADR-009**: ห้ามใช้ TypeORM migrations - ต้องแก้ SQL schema โดยตรงและสร้าง delta file
|
||||
2. **UUID Handling**: ใช้ UUIDv7 (MariaDB native) ตาม ADR-019 - ห้ามใช้ `parseInt()` บน UUID
|
||||
3. **AI Boundary**: ตาราง AI (migration_review_queue, ai_audit_logs) ต้องถูกจัดการผ่าน DMS API เท่านั้น (ADR-023)
|
||||
4. **File Upload**: ต้องใช้ Two-Phase Storage (Temp → Commit) ตาม ADR-016
|
||||
5. **Schema Changes**: ทุกการเปลี่ยนแปลงต้องอัปเดต Data Dictionary พร้อมกัน
|
||||
|
||||
## 📝 Change Log
|
||||
|
||||
- **2026-05-15**: เพิ่ม AI-related tables (migration_review_queue, ai_audit_logs) และ ai_processing_status column ตาม ADR-023A
|
||||
- **2026-05-14**: อัปเดต schema เป็น v1.9.0 เพื่อรองรับ RFA Approval System และ Unified AI Architecture
|
||||
|
||||
## 👥 ผู้รับผิดชอบ
|
||||
|
||||
- Database Schema: System Architect
|
||||
- Data Dictionary: Business Analyst
|
||||
- Migration Scripts: Backend Team
|
||||
- AI Integration: AI Integration Lead
|
||||
@@ -0,0 +1,56 @@
|
||||
-- File: specs/03-Data-and-Storage/deltas/14-add-migration-review-queue.sql
|
||||
-- Change Log
|
||||
-- - 2026-05-15: เพิ่ม delta สำหรับ migration_review_queue ตาม ADR-023A โดยไม่ลบ/rename column เดิม.
|
||||
-- ADR-009: ใช้ SQL delta โดยตรง ห้ามใช้ TypeORM migration
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS migration_review_queue (
|
||||
id INT NOT NULL AUTO_INCREMENT COMMENT 'Internal PK (ห้าม expose ใน API)',
|
||||
uuid UUID NOT NULL DEFAULT UUID() COMMENT 'UUID Public Identifier (ADR-019)',
|
||||
batch_id VARCHAR(100) NOT NULL COMMENT 'n8n batch identifier',
|
||||
idempotency_key VARCHAR(200) NOT NULL COMMENT 'Idempotency-Key สำหรับป้องกัน queue ซ้ำ',
|
||||
original_filename VARCHAR(500) NOT NULL COMMENT 'ชื่อไฟล์ต้นฉบับจาก legacy source',
|
||||
storage_temp_path VARCHAR(1000) NOT NULL COMMENT 'temp storage path ก่อน import',
|
||||
ai_metadata_json JSON NOT NULL COMMENT 'AI suggestion payload เต็มสำหรับ human review',
|
||||
confidence_score DECIMAL(5, 4) NOT NULL COMMENT 'AI confidence score 0.0000-1.0000',
|
||||
ocr_used TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'ระบุว่าใช้ OCR path หรือไม่',
|
||||
status ENUM('PENDING', 'IMPORTED', 'REJECTED') NOT NULL DEFAULT 'PENDING',
|
||||
reviewed_by INT NULL COMMENT 'Internal users.user_id ของผู้ review',
|
||||
reviewed_at DATETIME NULL COMMENT 'เวลาที่ review record',
|
||||
rejection_reason VARCHAR(500) NULL COMMENT 'เหตุผลเมื่อ reject',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_migration_review_uuid (uuid),
|
||||
UNIQUE KEY uq_migration_review_idempotency (idempotency_key),
|
||||
KEY idx_migration_review_status_created (status, created_at),
|
||||
KEY idx_migration_review_batch (batch_id),
|
||||
KEY idx_migration_review_reviewed_by (reviewed_by)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ADR-023A AI migration review staging queue';
|
||||
|
||||
ALTER TABLE migration_review_queue
|
||||
ADD COLUMN IF NOT EXISTS idempotency_key VARCHAR(200) NULL COMMENT 'Idempotency-Key สำหรับป้องกัน queue ซ้ำ',
|
||||
ADD COLUMN IF NOT EXISTS original_filename VARCHAR(500) NULL COMMENT 'ชื่อไฟล์ต้นฉบับจาก legacy source',
|
||||
ADD COLUMN IF NOT EXISTS storage_temp_path VARCHAR(1000) NULL COMMENT 'temp storage path ก่อน import',
|
||||
ADD COLUMN IF NOT EXISTS ai_metadata_json JSON NULL COMMENT 'AI suggestion payload เต็มสำหรับ human review',
|
||||
ADD COLUMN IF NOT EXISTS ocr_used TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'ระบุว่าใช้ OCR path หรือไม่',
|
||||
ADD COLUMN IF NOT EXISTS reviewed_by INT NULL COMMENT 'Internal users.user_id ของผู้ review',
|
||||
ADD COLUMN IF NOT EXISTS reviewed_at DATETIME NULL COMMENT 'เวลาที่ review record',
|
||||
ADD COLUMN IF NOT EXISTS rejection_reason VARCHAR(500) NULL COMMENT 'เหตุผลเมื่อ reject';
|
||||
|
||||
UPDATE migration_review_queue
|
||||
SET
|
||||
idempotency_key = COALESCE(idempotency_key, CONCAT(batch_id, ':', uuid)),
|
||||
original_filename = COALESCE(original_filename, original_file_name),
|
||||
ai_metadata_json = COALESCE(ai_metadata_json, extracted_metadata),
|
||||
rejection_reason = COALESCE(rejection_reason, error_reason)
|
||||
WHERE idempotency_key IS NULL
|
||||
OR original_filename IS NULL
|
||||
OR ai_metadata_json IS NULL
|
||||
OR rejection_reason IS NULL;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_migration_review_idempotency ON migration_review_queue (idempotency_key);
|
||||
CREATE INDEX IF NOT EXISTS idx_migration_review_status_created ON migration_review_queue (status, created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_migration_review_batch ON migration_review_queue (batch_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_migration_review_reviewed_by ON migration_review_queue (reviewed_by);
|
||||
@@ -0,0 +1,14 @@
|
||||
-- File: specs/03-Data-and-Storage/deltas/15-add-ai-processing-status.sql
|
||||
-- Change Log
|
||||
-- - 2026-05-15: เพิ่มสถานะประมวลผล AI สำหรับเอกสารตาม ADR-023A FR-018.
|
||||
-- ADR-009: ใช้ SQL delta โดยตรง ห้ามใช้ TypeORM migration
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- หมายเหตุ: schema v1.9.0 ยังไม่มีตาราง documents กลาง จึงเพิ่มให้ตาราง attachments
|
||||
-- ซึ่งเป็นตารางไฟล์เอกสารรวมที่มีอยู่จริงใน canonical schema ปัจจุบัน
|
||||
ALTER TABLE attachments
|
||||
ADD COLUMN IF NOT EXISTS ai_processing_status ENUM('PENDING', 'PROCESSING', 'DONE', 'FAILED')
|
||||
NOT NULL DEFAULT 'PENDING' COMMENT 'สถานะ AI job ของไฟล์เอกสารตาม ADR-023A';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_attachments_ai_status ON attachments (ai_processing_status);
|
||||
@@ -871,13 +871,15 @@ CREATE TABLE attachments (
|
||||
CHECKSUM VARCHAR(64) NULL COMMENT 'SHA-256 Checksum',
|
||||
reference_date DATE NULL COMMENT 'Date used for folder structure (e.g. Issue Date) to prevent broken paths',
|
||||
workflow_history_id CHAR(36) NULL COMMENT 'FK to workflow_histories.id for step-specific attachments (ADR-021). NULL = main document',
|
||||
ai_processing_status ENUM('PENDING', 'PROCESSING', 'DONE', 'FAILED') NOT NULL DEFAULT 'PENDING' COMMENT 'สถานะ AI job ของไฟล์เอกสารตาม ADR-023A',
|
||||
FOREIGN KEY (uploaded_by_user_id) REFERENCES users (user_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (workflow_history_id) REFERENCES workflow_histories (id) ON DELETE
|
||||
SET NULL ON UPDATE CASCADE,
|
||||
INDEX idx_attachments_reference_date (reference_date),
|
||||
INDEX idx_att_wfhist_created (workflow_history_id, created_at),
|
||||
INDEX idx_attachments_ai_status (ai_processing_status),
|
||||
UNIQUE INDEX idx_attachments_uuid (uuid)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "กลาง" เก็บไฟล์แนบทั้งหมดของระบบ';
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ตาราง "กลาง" เก็บไฟล์แนบทั้งหมดของระบบ';
|
||||
|
||||
-- ตารางเชื่อม correspondence_revisions กับ attachments (M:N)
|
||||
-- [FIX] FK เปลี่ยนจาก correspondences.id → correspondence_revisions.id
|
||||
@@ -1447,60 +1449,98 @@ CREATE TABLE migration_logs (
|
||||
SET NULL
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ตารางเก็บบันทึก Migration เอกสารที่ผ่าน AI Processing (Task BE-AI-02)';
|
||||
|
||||
-- ตาราง Audit Log สำหรับการทำงานของ AI ทุกครั้ง (ADR-018 Rule 5)
|
||||
-- =====================================================
|
||||
-- 12. 🤖 AI Migration Review Queue (ADR-023, ADR-023A)
|
||||
-- =====================================================
|
||||
-- ตาราง staging queue สำหรับ AI migration ตาม ADR-023A
|
||||
CREATE TABLE migration_review_queue (
|
||||
id INT NOT NULL AUTO_INCREMENT COMMENT 'Internal PK (ห้าม expose ใน API)',
|
||||
uuid UUID NOT NULL DEFAULT UUID() COMMENT 'UUID Public Identifier (ADR-019)',
|
||||
batch_id VARCHAR(100) NOT NULL COMMENT 'n8n batch identifier',
|
||||
idempotency_key VARCHAR(200) NOT NULL COMMENT 'Idempotency-Key สำหรับป้องกัน queue ซ้ำ',
|
||||
original_filename VARCHAR(500) NOT NULL COMMENT 'ชื่อไฟล์ต้นฉบับจาก legacy source',
|
||||
storage_temp_path VARCHAR(1000) NOT NULL COMMENT 'temp storage path ก่อน import',
|
||||
ai_metadata_json JSON NOT NULL COMMENT 'AI suggestion payload เต็มสำหรับ human review',
|
||||
confidence_score DECIMAL(5, 4) NOT NULL COMMENT 'AI confidence score 0.0000-1.0000',
|
||||
ocr_used TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'ระบุว่าใช้ OCR path หรือไม่',
|
||||
STATUS ENUM('PENDING', 'APPROVED', 'IMPORTED', 'REJECTED') NOT NULL DEFAULT 'PENDING',
|
||||
reviewed_by INT NULL COMMENT 'Internal users.user_id ของผู้ review',
|
||||
reviewed_at DATETIME NULL COMMENT 'เวลาที่ review record',
|
||||
rejection_reason VARCHAR(500) NULL COMMENT 'เหตุผลเมื่อ reject',
|
||||
version INT NOT NULL DEFAULT 1 COMMENT 'Optimistic locking version',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_migration_review_uuid (uuid),
|
||||
UNIQUE KEY uq_migration_review_idempotency (idempotency_key),
|
||||
KEY idx_migration_review_status_created (STATUS, created_at),
|
||||
KEY idx_migration_review_batch (batch_id),
|
||||
KEY idx_migration_review_reviewed_by (reviewed_by),
|
||||
CONSTRAINT fk_migration_review_reviewed_by FOREIGN KEY (reviewed_by) REFERENCES users (user_id) ON DELETE
|
||||
SET NULL
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ADR-023A AI migration review staging queue';
|
||||
|
||||
-- ตาราง Audit Log สำหรับการทำงานของ AI ทุกครั้ง (ADR-023, ADR-023A)
|
||||
CREATE TABLE ai_audit_logs (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY COMMENT 'Internal PK (ห้าม expose ใน API)',
|
||||
uuid UUID NOT NULL DEFAULT UUID() COMMENT 'UUID Public Identifier (ADR-019)',
|
||||
document_public_id UUID NULL COMMENT 'UUID ของ migration_logs ที่เกี่ยวข้อง',
|
||||
ai_model VARCHAR(50) NOT NULL COMMENT 'ชื่อ AI Model ที่ใช้ประมวลผล เช่น gemma4',
|
||||
processing_time_ms INT NULL COMMENT 'เวลาประมวลผล (milliseconds)',
|
||||
confidence_score DECIMAL(3, 2) NULL COMMENT 'คะแนนความมั่นใจ AI (0.00-1.00)',
|
||||
input_hash VARCHAR(64) NULL COMMENT 'SHA-256 hash ของ Input เพื่อ Audit',
|
||||
output_hash VARCHAR(64) NULL COMMENT 'SHA-256 hash ของ Output เพื่อ Audit',
|
||||
STATUS ENUM('SUCCESS', 'FAILED', 'TIMEOUT') NOT NULL COMMENT 'สถานะการประมวลผล',
|
||||
error_message TEXT NULL COMMENT 'ข้อความ Error (ถ้ามี)',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
|
||||
UNIQUE INDEX idx_ai_audit_logs_uuid (uuid),
|
||||
INDEX idx_ai_audit_document (document_public_id),
|
||||
INDEX idx_ai_audit_model (ai_model),
|
||||
INDEX idx_ai_audit_status (STATUS)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ตาราง Audit Log การทำงาน AI ทุกครั้ง (ADR-018 Rule 5 Audit Logging)';
|
||||
document_public_id UUID NULL COMMENT 'Imported document publicId when available',
|
||||
ai_model VARCHAR(50) NOT NULL DEFAULT 'gemma4' COMMENT 'Legacy AI model column used by current gateway service',
|
||||
model_name VARCHAR(100) NOT NULL COMMENT 'Local model name used by ADR-023 AI pipeline',
|
||||
ai_suggestion_json JSON NULL COMMENT 'AI suggested metadata',
|
||||
human_override_json JSON NULL COMMENT 'Human approved or overridden metadata',
|
||||
processing_time_ms INT NULL COMMENT 'Legacy processing duration field',
|
||||
confidence_score DECIMAL(4, 3) NULL COMMENT 'AI confidence score 0.000-1.000',
|
||||
input_hash VARCHAR(64) NULL COMMENT 'Legacy SHA-256 input hash',
|
||||
output_hash VARCHAR(64) NULL COMMENT 'Legacy SHA-256 output hash',
|
||||
STATUS ENUM('SUCCESS', 'FAILED', 'TIMEOUT') NOT NULL DEFAULT 'SUCCESS' COMMENT 'Legacy processing status field',
|
||||
error_message TEXT NULL COMMENT 'Legacy processing error field',
|
||||
confirmed_by_user_id INT NULL COMMENT 'Internal users.user_id that confirmed the record',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY idx_ai_audit_logs_uuid (uuid),
|
||||
KEY idx_ai_audit_document (document_public_id),
|
||||
KEY idx_ai_audit_model (ai_model),
|
||||
KEY idx_ai_audit_model_name (model_name),
|
||||
KEY idx_ai_audit_status (STATUS),
|
||||
KEY idx_ai_audit_confirmed_by (confirmed_by_user_id),
|
||||
CONSTRAINT fk_ai_audit_confirmed_by_user FOREIGN KEY (confirmed_by_user_id) REFERENCES users (user_id) ON DELETE
|
||||
SET NULL
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ADR-023 AI development feedback log';
|
||||
|
||||
-- =============================================================================
|
||||
-- 20. RFA Approval System (v1.9.0)
|
||||
-- =============================================================================
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 20.1 review_teams — ทีมตรวจสอบแยกตาม Discipline
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `review_teams` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`project_id` INT NOT NULL,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`description` VARCHAR(255) NULL,
|
||||
`default_for_rfa_types` TEXT NULL COMMENT 'Comma-separated RFA type codes e.g. SDW,DDW',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`project_id` INT NOT NULL,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`description` VARCHAR(255) NULL,
|
||||
`default_for_rfa_types` TEXT NULL COMMENT 'Comma-separated RFA type codes e.g. SDW,DDW',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_review_teams_uuid` (`uuid`),
|
||||
KEY `idx_review_teams_project` (`project_id`, `is_active`),
|
||||
CONSTRAINT `fk_review_teams_project` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 20.2 review_team_members — สมาชิกในทีมแยกตาม Discipline
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `review_team_members` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`team_id` INT NOT NULL,
|
||||
`user_id` INT NOT NULL,
|
||||
`discipline_id` INT NOT NULL,
|
||||
`role` ENUM('REVIEWER','LEAD','MANAGER') NOT NULL DEFAULT 'REVIEWER',
|
||||
`priority_order` INT NOT NULL DEFAULT 0,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`team_id` INT NOT NULL,
|
||||
`user_id` INT NOT NULL,
|
||||
`discipline_id` INT NOT NULL,
|
||||
`role` ENUM('REVIEWER', 'LEAD', 'MANAGER') NOT NULL DEFAULT 'REVIEWER',
|
||||
`priority_order` INT NOT NULL DEFAULT 0,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_review_team_members_uuid` (`uuid`),
|
||||
UNIQUE KEY `uq_team_user_discipline` (`team_id`, `user_id`, `discipline_id`),
|
||||
@@ -1509,73 +1549,91 @@ CREATE TABLE IF NOT EXISTS `review_team_members` (
|
||||
CONSTRAINT `fk_rtm_team` FOREIGN KEY (`team_id`) REFERENCES `review_teams` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_rtm_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_rtm_discipline` FOREIGN KEY (`discipline_id`) REFERENCES `disciplines` (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 20.3 response_codes — รหัสตอบกลับมาตรฐาน (Master Approval Matrix)
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `response_codes` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`code` VARCHAR(10) NOT NULL COMMENT '1A, 1B, 1C, 1D, 1E, 1F, 1G, 2, 3, 4',
|
||||
`sub_status` VARCHAR(10) NULL,
|
||||
`category` ENUM('ENGINEERING','MATERIAL','CONTRACT','TESTING','ESG') NOT NULL,
|
||||
`description_th` TEXT NOT NULL,
|
||||
`description_en` TEXT NOT NULL,
|
||||
`implications` JSON NULL COMMENT '{"affectsSchedule":bool,"affectsCost":bool,"requiresContractReview":bool}',
|
||||
`notify_roles` TEXT NULL COMMENT 'Comma-separated roles e.g. CONTRACT_MANAGER,QS_MANAGER',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`is_system` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'System default — cannot delete',
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`code` VARCHAR(10) NOT NULL COMMENT '1A, 1B, 1C, 1D, 1E, 1F, 1G, 2, 3, 4',
|
||||
`sub_status` VARCHAR(10) NULL,
|
||||
`category` ENUM(
|
||||
'ENGINEERING',
|
||||
'MATERIAL',
|
||||
'CONTRACT',
|
||||
'TESTING',
|
||||
'ESG'
|
||||
) NOT NULL,
|
||||
`description_th` TEXT NOT NULL,
|
||||
`description_en` TEXT NOT NULL,
|
||||
`implications` JSON NULL COMMENT '{"affectsSchedule":bool,"affectsCost":bool,"requiresContractReview":bool}',
|
||||
`notify_roles` TEXT NULL COMMENT 'Comma-separated roles e.g. CONTRACT_MANAGER,QS_MANAGER',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`is_system` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'System default — cannot delete',
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_response_codes_uuid` (`uuid`),
|
||||
UNIQUE KEY `uq_response_code_category` (`code`, `category`),
|
||||
KEY `idx_rc_category_active` (`category`, `is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 20.4 response_code_rules — กฎการใช้รหัสต่อโครงการ/ประเภทเอกสาร
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `response_code_rules` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`project_id` INT NULL COMMENT 'NULL = global default',
|
||||
`document_type_id` INT NOT NULL,
|
||||
`response_code_id` INT NOT NULL,
|
||||
`is_enabled` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`requires_comments` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`triggers_notification` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`parent_rule_id` INT NULL COMMENT 'For inheritance tracking',
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`project_id` INT NULL COMMENT 'NULL = global default',
|
||||
`document_type_id` INT NOT NULL,
|
||||
`response_code_id` INT NOT NULL,
|
||||
`is_enabled` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`requires_comments` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`triggers_notification` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`parent_rule_id` INT NULL COMMENT 'For inheritance tracking',
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_response_code_rules_uuid` (`uuid`),
|
||||
UNIQUE KEY `uq_rule_per_project_doctype_code` (`project_id`, `document_type_id`, `response_code_id`),
|
||||
UNIQUE KEY `uq_rule_per_project_doctype_code` (
|
||||
`project_id`,
|
||||
`document_type_id`,
|
||||
`response_code_id`
|
||||
),
|
||||
KEY `idx_response_rules_lookup` (`project_id`, `document_type_id`, `is_enabled`),
|
||||
CONSTRAINT `fk_rcr_response_code` FOREIGN KEY (`response_code_id`) REFERENCES `response_codes` (`id`),
|
||||
CONSTRAINT `fk_rcr_parent` FOREIGN KEY (`parent_rule_id`) REFERENCES `response_code_rules` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
CONSTRAINT `fk_rcr_parent` FOREIGN KEY (`parent_rule_id`) REFERENCES `response_code_rules` (`id`) ON DELETE
|
||||
SET NULL
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 20.5 review_tasks — งานตรวจสอบสำหรับแต่ละ Discipline (Parallel Review)
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `review_tasks` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`rfa_revision_id` INT NOT NULL,
|
||||
`team_id` INT NOT NULL,
|
||||
`discipline_id` INT NOT NULL,
|
||||
`assigned_to_user_id` INT NULL COMMENT 'NULL = auto-assign by discipline',
|
||||
`status` ENUM('PENDING','IN_PROGRESS','COMPLETED','DELEGATED','EXPIRED','CANCELLED') NOT NULL DEFAULT 'PENDING',
|
||||
`due_date` DATE NULL,
|
||||
`response_code_id` INT NULL,
|
||||
`comments` TEXT NULL,
|
||||
`attachments` JSON NULL COMMENT 'Array of attachment publicIds',
|
||||
`delegated_from_user_id` INT NULL COMMENT 'Original assignee when delegated',
|
||||
`completed_at` TIMESTAMP NULL,
|
||||
`version` INT NOT NULL DEFAULT 1 COMMENT 'Optimistic locking (ADR-002)',
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`rfa_revision_id` INT NOT NULL,
|
||||
`team_id` INT NOT NULL,
|
||||
`discipline_id` INT NOT NULL,
|
||||
`assigned_to_user_id` INT NULL COMMENT 'NULL = auto-assign by discipline',
|
||||
`status` ENUM(
|
||||
'PENDING',
|
||||
'IN_PROGRESS',
|
||||
'COMPLETED',
|
||||
'DELEGATED',
|
||||
'EXPIRED',
|
||||
'CANCELLED'
|
||||
) NOT NULL DEFAULT 'PENDING',
|
||||
`due_date` DATE NULL,
|
||||
`response_code_id` INT NULL,
|
||||
`comments` TEXT NULL,
|
||||
`attachments` JSON NULL COMMENT 'Array of attachment publicIds',
|
||||
`delegated_from_user_id` INT NULL COMMENT 'Original assignee when delegated',
|
||||
`completed_at` TIMESTAMP NULL,
|
||||
`version` INT NOT NULL DEFAULT 1 COMMENT 'Optimistic locking (ADR-002)',
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_review_tasks_uuid` (`uuid`),
|
||||
UNIQUE KEY `uq_review_task_per_revision_discipline` (`rfa_revision_id`, `team_id`, `discipline_id`),
|
||||
@@ -1585,95 +1643,117 @@ CREATE TABLE IF NOT EXISTS `review_tasks` (
|
||||
CONSTRAINT `fk_rt_rfa_revision` FOREIGN KEY (`rfa_revision_id`) REFERENCES `rfa_revisions` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_rt_team` FOREIGN KEY (`team_id`) REFERENCES `review_teams` (`id`),
|
||||
CONSTRAINT `fk_rt_discipline` FOREIGN KEY (`discipline_id`) REFERENCES `disciplines` (`id`),
|
||||
CONSTRAINT `fk_rt_user` FOREIGN KEY (`assigned_to_user_id`) REFERENCES `users` (`user_id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `fk_rt_response_code` FOREIGN KEY (`response_code_id`) REFERENCES `response_codes` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
CONSTRAINT `fk_rt_user` FOREIGN KEY (`assigned_to_user_id`) REFERENCES `users` (`user_id`) ON DELETE
|
||||
SET NULL,
|
||||
CONSTRAINT `fk_rt_response_code` FOREIGN KEY (`response_code_id`) REFERENCES `response_codes` (`id`) ON DELETE
|
||||
SET NULL
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 20.6 delegations — การมอบหมายงาน
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `delegations` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`delegator_user_id` INT NOT NULL COMMENT 'ผู้มอบหมาย (FK → users.user_id)',
|
||||
`delegate_user_id` INT NOT NULL COMMENT 'ผู้รับมอบหมาย (FK → users.user_id)',
|
||||
`start_date` DATE NOT NULL,
|
||||
`end_date` DATE NULL COMMENT 'BullMQ job flips is_active=0 when end_date < NOW() (ADR-008)',
|
||||
`scope` ENUM('ALL','RFA_ONLY','CORRESPONDENCE_ONLY','SPECIFIC_TYPES') NOT NULL DEFAULT 'ALL',
|
||||
`document_types` TEXT NULL COMMENT 'Comma-separated doc type codes when scope=SPECIFIC_TYPES',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1 COMMENT 'Managed by BullMQ scheduler — do not flip manually',
|
||||
`reason` TEXT NULL,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`delegator_user_id` INT NOT NULL COMMENT 'ผู้มอบหมาย (FK → users.user_id)',
|
||||
`delegate_user_id` INT NOT NULL COMMENT 'ผู้รับมอบหมาย (FK → users.user_id)',
|
||||
`start_date` DATE NOT NULL,
|
||||
`end_date` DATE NULL COMMENT 'BullMQ job flips is_active=0 when end_date < NOW() (ADR-008)',
|
||||
`scope` ENUM(
|
||||
'ALL',
|
||||
'RFA_ONLY',
|
||||
'CORRESPONDENCE_ONLY',
|
||||
'SPECIFIC_TYPES'
|
||||
) NOT NULL DEFAULT 'ALL',
|
||||
`document_types` TEXT NULL COMMENT 'Comma-separated doc type codes when scope=SPECIFIC_TYPES',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1 COMMENT 'Managed by BullMQ scheduler — do not flip manually',
|
||||
`reason` TEXT NULL,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_delegations_uuid` (`uuid`),
|
||||
KEY `idx_delegations_active` (`delegator_user_id`, `is_active`, `start_date`, `end_date`),
|
||||
KEY `idx_delegations_active` (
|
||||
`delegator_user_id`,
|
||||
`is_active`,
|
||||
`start_date`,
|
||||
`end_date`
|
||||
),
|
||||
KEY `idx_delegations_delegate` (`delegate_user_id`, `is_active`),
|
||||
CONSTRAINT `fk_del_delegator` FOREIGN KEY (`delegator_user_id`) REFERENCES `users` (`user_id`),
|
||||
CONSTRAINT `fk_del_delegate` FOREIGN KEY (`delegate_user_id`) REFERENCES `users` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 20.7 reminder_rules — กฎการแจ้งเตือน
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `reminder_rules` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`project_id` INT NULL COMMENT 'NULL = global',
|
||||
`document_type_id` INT NULL COMMENT 'NULL = all types',
|
||||
`trigger_days_before_due` INT NOT NULL DEFAULT 2,
|
||||
`escalation_days_after_due` INT NOT NULL DEFAULT 1,
|
||||
`reminder_type` ENUM('DUE_SOON','ON_DUE','OVERDUE','ESCALATION_L1','ESCALATION_L2') NOT NULL,
|
||||
`recipients` TEXT NOT NULL COMMENT 'Comma-separated: ASSIGNEE,MANAGER,PROJECT_MANAGER',
|
||||
`message_template_th` TEXT NOT NULL,
|
||||
`message_template_en` TEXT NOT NULL,
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`project_id` INT NULL COMMENT 'NULL = global',
|
||||
`document_type_id` INT NULL COMMENT 'NULL = all types',
|
||||
`trigger_days_before_due` INT NOT NULL DEFAULT 2,
|
||||
`escalation_days_after_due` INT NOT NULL DEFAULT 1,
|
||||
`reminder_type` ENUM(
|
||||
'DUE_SOON',
|
||||
'ON_DUE',
|
||||
'OVERDUE',
|
||||
'ESCALATION_L1',
|
||||
'ESCALATION_L2'
|
||||
) NOT NULL,
|
||||
`recipients` TEXT NOT NULL COMMENT 'Comma-separated: ASSIGNEE,MANAGER,PROJECT_MANAGER',
|
||||
`message_template_th` TEXT NOT NULL,
|
||||
`message_template_en` TEXT NOT NULL,
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`updated_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_reminder_rules_uuid` (`uuid`),
|
||||
KEY `idx_reminder_rules_active` (`is_active`, `project_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 20.8 distribution_matrices — ตารางกระจายเอกสาร
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `distribution_matrices` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`project_id` INT NULL COMMENT 'NULL = global',
|
||||
`document_type_id` INT NOT NULL,
|
||||
`response_code_id` INT NULL COMMENT 'NULL = applies to all codes',
|
||||
`conditions` JSON NULL COMMENT '{"codes":["1A","1B"],"excludeCodes":["3","4"]}',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()),
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`project_id` INT NULL COMMENT 'NULL = global',
|
||||
`document_type_id` INT NOT NULL,
|
||||
`response_code_id` INT NULL COMMENT 'NULL = applies to all codes',
|
||||
`conditions` JSON NULL COMMENT '{"codes":["1A","1B"],"excludeCodes":["3","4"]}',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_distribution_matrices_uuid` (`uuid`),
|
||||
KEY `idx_distribution_lookup` (`document_type_id`, `response_code_id`, `is_active`),
|
||||
CONSTRAINT `fk_dm_response_code` FOREIGN KEY (`response_code_id`) REFERENCES `response_codes` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
KEY `idx_distribution_lookup` (
|
||||
`document_type_id`,
|
||||
`response_code_id`,
|
||||
`is_active`
|
||||
),
|
||||
CONSTRAINT `fk_dm_response_code` FOREIGN KEY (`response_code_id`) REFERENCES `response_codes` (`id`) ON DELETE
|
||||
SET NULL
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 20.9 distribution_recipients — ผู้รับเอกสารใน Distribution Matrix
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `distribution_recipients` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()) COMMENT 'UUID Public Identifier (ADR-019)',
|
||||
`matrix_id` INT NOT NULL,
|
||||
`recipient_type` ENUM('USER','ORGANIZATION','TEAM','ROLE') NOT NULL,
|
||||
`recipient_public_id` UUID NOT NULL COMMENT 'publicId of target: USER=users.uuid | ORGANIZATION=organizations.uuid | TEAM=review_teams.uuid | ROLE=roles.uuid',
|
||||
`delivery_method` ENUM('EMAIL','IN_APP','BOTH') NOT NULL DEFAULT 'BOTH',
|
||||
`sequence` INT NULL COMMENT 'For ordered delivery',
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`uuid` UUID NOT NULL DEFAULT (UUID()) COMMENT 'UUID Public Identifier (ADR-019)',
|
||||
`matrix_id` INT NOT NULL,
|
||||
`recipient_type` ENUM('USER', 'ORGANIZATION', 'TEAM', 'ROLE') NOT NULL,
|
||||
`recipient_public_id` UUID NOT NULL COMMENT 'publicId of target: USER=users.uuid | ORGANIZATION=organizations.uuid | TEAM=review_teams.uuid | ROLE=roles.uuid',
|
||||
`delivery_method` ENUM('EMAIL', 'IN_APP', 'BOTH') NOT NULL DEFAULT 'BOTH',
|
||||
`sequence` INT NULL COMMENT 'For ordered delivery',
|
||||
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_distribution_recipients_uuid` (`uuid`),
|
||||
KEY `idx_dr_matrix` (`matrix_id`),
|
||||
KEY `idx_dr_type_recipient` (`recipient_type`, `recipient_public_id`),
|
||||
CONSTRAINT `fk_dr_matrix` FOREIGN KEY (`matrix_id`) REFERENCES `distribution_matrices` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Polymorphic recipients — no FK on recipient_public_id (by design). ROLE type uses roles.uuid (ADR-019)';
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Polymorphic recipients — no FK on recipient_public_id (by design). ROLE type uses roles.uuid (ADR-019)';
|
||||
|
||||
-- =============================================================================
|
||||
-- END OF SCHEMA v1.9.0
|
||||
|
||||
@@ -1066,8 +1066,6 @@ VALUES -- Contract Management
|
||||
-- ==========================================================
|
||||
-- VERIFICATION: Run permissions-verification.sql after this
|
||||
-- ==========================================================
|
||||
|
||||
|
||||
-- ==========================================================
|
||||
-- MERGED FROM fix-project-permissions.sql (v1.9.0 Update)
|
||||
-- ==========================================================
|
||||
@@ -1088,15 +1086,19 @@ VALUES (
|
||||
'project',
|
||||
1
|
||||
);
|
||||
|
||||
-- 2. Grant project.view to Superadmin (Role 1)
|
||||
INSERT IGNORE INTO role_permissions (role_id, permission_id)
|
||||
VALUES (1, 202);
|
||||
|
||||
-- 3. Grant project.view to Organization Admin (Role 2)
|
||||
INSERT IGNORE INTO role_permissions (role_id, permission_id)
|
||||
VALUES (2, 202);
|
||||
|
||||
-- 4. Grant project.view to Project Manager (Role 6)
|
||||
INSERT IGNORE INTO role_permissions (role_id, permission_id)
|
||||
VALUES (6, 202);
|
||||
|
||||
-- 5. Grant project.view to Viewer (Role 5)
|
||||
INSERT IGNORE INTO role_permissions (role_id, permission_id)
|
||||
VALUES (5, 202);
|
||||
@@ -1139,25 +1141,44 @@ VALUES (
|
||||
'Hard Delete ai_audit_logs (Superadmin Only)',
|
||||
'ai',
|
||||
1
|
||||
),
|
||||
(
|
||||
185,
|
||||
'ai.read_analytics',
|
||||
'ดู AI Analytics Summary (Confidence, Override Rate, Rejected Rate)',
|
||||
'ai',
|
||||
1
|
||||
),
|
||||
(
|
||||
186,
|
||||
'ai.delete_audit',
|
||||
'ลบ AiAuditLog เดี่ยวโดย publicId (Superadmin Only)',
|
||||
'ai',
|
||||
1
|
||||
);
|
||||
|
||||
-- Role 1: Superadmin — ได้รับทุก permission โดยอัตโนมัติผ่าน SELECT-all pattern (บรรทัด 825-829)
|
||||
-- Role 2: Org Admin — ai.suggest, ai.rag_query, ai.migration_manage
|
||||
-- Role 2: Org Admin — ai.suggest, ai.rag_query, ai.migration_manage, ai.read_analytics
|
||||
INSERT IGNORE INTO role_permissions (role_id, permission_id)
|
||||
VALUES (2, 181),
|
||||
-- ai.suggest
|
||||
(2, 182),
|
||||
-- ai.rag_query
|
||||
(2, 183);
|
||||
(2, 183),
|
||||
-- ai.migration_manage
|
||||
(2, 185);
|
||||
|
||||
-- ai.migration_manage
|
||||
-- Role 3: Document Control — ai.suggest, ai.rag_query, ai.migration_manage
|
||||
-- ai.read_analytics
|
||||
-- Role 3: Document Control — ai.suggest, ai.rag_query, ai.migration_manage, ai.read_analytics
|
||||
INSERT IGNORE INTO role_permissions (role_id, permission_id)
|
||||
VALUES (3, 181),
|
||||
-- ai.suggest
|
||||
(3, 182),
|
||||
-- ai.rag_query
|
||||
(3, 183);
|
||||
(3, 183),
|
||||
-- ai.migration_manage
|
||||
(3, 185);
|
||||
|
||||
-- ai.read_analytics
|
||||
-- ai.migration_manage
|
||||
-- ai.audit_log_delete (184) — Superadmin เท่านั้น, ไม่ grant ให้ Role อื่น
|
||||
|
||||
Reference in New Issue
Block a user