690519:1719 224 to 226 AI #02
CI / CD Pipeline / build (push) Successful in 4m47s
CI / CD Pipeline / deploy (push) Failing after 7m3s

This commit is contained in:
2026-05-19 17:19:24 +07:00
parent ea5499123e
commit 7259cbf67a
30 changed files with 783 additions and 878 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
# 📝 Contributing to LCBP3-DMS Specifications
> แนวทางการมีส่วนร่วมในการพัฒนาเอกสาร Specifications ของโครงการ LCBP3-DMS (v1.9.2)
> แนวทางการมีส่วนร่วมในการพัฒนาเอกสาร Specifications ของโครงการ LCBP3-DMS (v1.9.5)
ยินดีต้อนรับสู่คู่มือการมีส่วนร่วมในการพัฒนาเอกสาร Specifications! เอกสารนี้จะช่วยให้คุณเข้าใจวิธีการสร้าง แก้ไข และปรับปรุงเอกสารข้อกำหนดของโครงการได้อย่างมีประสิทธิภาพ
@@ -58,14 +58,9 @@ describe('PatternMatcherService — Performance', () => {
expect(result?.intentCode).toBe('SUMMARIZE_DOCUMENT');
const avg = times.reduce((a, b) => a + b, 0) / times.length;
const max = Math.max(...times);
const _max = Math.max(...times); // Kept for potential future debugging
const p95 = times.sort((a, b) => a - b)[Math.floor(times.length * 0.95)];
// eslint-disable-next-line no-console -- performance logging allowed in test
console.log(
`Pattern Match Perf: avg=${avg.toFixed(3)}ms, p95=${p95.toFixed(3)}ms, max=${max.toFixed(3)}ms`
);
// SC-001: synthetic worst-case (100+ patterns รวม 50 invalid regex try-catch)
// ค่า threshold สูงเพื่อรองรับ CI/IDE background load — regression detection only
// Production (keyword-only, 10-20 patterns): < 1ms
@@ -100,11 +95,6 @@ describe('PatternMatcherService — Performance', () => {
const avg = times.reduce((a, b) => a + b, 0) / times.length;
const p95 = times.sort((a, b) => a - b)[Math.floor(times.length * 0.95)];
// eslint-disable-next-line no-console -- performance logging allowed in test
console.log(
`Pattern Miss Perf: avg=${avg.toFixed(3)}ms, p95=${p95.toFixed(3)}ms`
);
// SC-001: worst-case full scan (100+ patterns รวม 50 invalid regex try-catch)
// Production keyword-only จะ < 1ms — ค่านี้เพื่อ regression detection
expect(avg).toBeLessThan(200);
@@ -2371,7 +2371,43 @@ PENDING_REVIEW ──→ VERIFIED ──→ IMPORTED (terminal)
---
### 19.3 Confidence Scoring Strategy (ADR-020)
### 19.3 `document_chunks`
**วัตถุประสงค์:** เก็บ vector metadata สำหรับ RAG ingestion ตาม ADR-022
| Column | Type | Nullable | Description |
|--------|------|----------|-------------|
| `id` | CHAR(36) | NO | UUID = Qdrant point ID |
| `document_id` | CHAR(36) | NO | FK → attachments.public_id (UUIDv7) |
| `chunk_index` | INT | NO | ลำดับ chunk ภายใน document |
| `content` | TEXT | NO | เนื้อหา chunk หลัง PyThaiNLP normalize |
| `doc_type` | VARCHAR(20) | NO | CORR, RFA, DRAWING, CONTRACT, RPT, TRANS |
| `doc_number` | VARCHAR(100) | YES | หมายเลขเอกสาร เช่น REF-2026-001 |
| `revision` | VARCHAR(20) | YES | Revision เช่น Rev.A |
| `project_code` | VARCHAR(50) | NO | รหัสโครงการ (ใช้ filter) |
| `project_public_id` | CHAR(36) | NO | UUIDv7 ของโครงการ (Qdrant tenant key) |
| `version` | VARCHAR(20) | YES | เวอร์ชันเอกสาร เช่น 1.0, 2.1 (ถ้ามี) |
| `classification` | ENUM | NO | PUBLIC, INTERNAL, CONFIDENTIAL (DEFAULT: INTERNAL) |
| `embedding_model` | VARCHAR(100) | NO | nomic-embed-text |
| `created_at` | DATETIME(3) | NO | วันที่สร้าง |
**Indexes**:
- PRIMARY KEY (id)
- INDEX idx_chunks_document_id (document_id)
- INDEX idx_chunks_doc_number_rev (doc_number, revision)
- INDEX idx_chunks_project (project_public_id)
- FULLTEXT INDEX ft_chunks_content (content)
**Business Rules**:
1. **Project Isolation** — Qdrant queries MUST include project_public_id filter (compile-time enforcement per ADR-023A)
2. **Chunk Size** — 512 tokens with 64 tokens overlap (ADR-023A RAG embed scope)
3. **Embedding Model** — nomic-embed-text only (ADR-023A 2-model stack)
---
### 19.4 Confidence Scoring Strategy (ADR-020)
| Score Range | Action | Description |
|-------------|--------|-------------|
@@ -2382,6 +2418,72 @@ PENDING_REVIEW ──→ VERIFIED ──→ IMPORTED (terminal)
---
### 19.4 Intent Classification Tables (ADR-024)
> เพิ่มใน v1.9.0 — Feature 224-intent-classification | ตารางสำหรับ Hybrid Intent Classifier (Pattern Match + LLM Fallback)
#### 19.4.1 `ai_intent_definitions`
**วัตถุประสงค์:** เก็บ Intent Definitions (ประเภทความตั้งใจของผู้ใช้) สำหรับ Hybrid Intent Classifier ตาม ADR-024
| Column Name | Data Type | Constraints | Description |
| ----------- | --------- | ----------- | ----------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Internal PK (ห้าม expose ใน API) |
| public_id | UUID | NOT NULL, UNIQUE, DEFAULT UUID() | UUID Public Identifier (ADR-019) |
| intent_code | VARCHAR(50) | NOT NULL, UNIQUE | รหัส Intent เช่น RAG_QUERY, GET_RFA |
| description_th | VARCHAR(255) | NOT NULL | คำอธิบายภาษาไทย |
| description_en | VARCHAR(255) | NOT NULL | คำอธิบายภาษาอังกฤษ |
| category | ENUM | NOT NULL | read, suggest, utility |
| is_active | BOOLEAN | NOT NULL, DEFAULT TRUE | สถานะการใช้งาน |
| created_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | วันที่สร้าง |
| updated_at | TIMESTAMP | NOT NULL, ON UPDATE CURRENT_TIMESTAMP | วันที่แก้ไขล่าสุด |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE KEY uk_intent_public_id (public_id)
- UNIQUE KEY uk_intent_code (intent_code)
- INDEX idx_intent_active (is_active, category)
**Business Rules**:
1. **Intent Categories** — read (ดึงข้อมูล), suggest (แนะนำ), utility (อื่นๆ)
2. **Active Status** — Intent ที่ไม่ active จะไม่ถูกใช้ในการ classify
3. **Seed Data** — 12 Intent Definitions พร้อม patterns v1 (RAG_QUERY, GET_RFA, GET_DRAWING, ฯลฯ)
---
#### 19.4.2 `ai_intent_patterns`
**วัตถุประสงค์:** เก็บ Patterns (keyword และ regex) สำหรับ Pattern Matching ใน Hybrid Intent Classifier
| Column Name | Data Type | Constraints | Description |
| ----------- | --------- | ----------- | ----------- |
| id | INT | PRIMARY KEY, AUTO_INCREMENT | Internal PK (ห้าม expose ใน API) |
| public_id | UUID | NOT NULL, UNIQUE, DEFAULT UUID() | UUID Public Identifier (ADR-019) |
| intent_code | VARCHAR(50) | NOT NULL, FK | รหัส Intent (FK to ai_intent_definitions) |
| language | ENUM | NOT NULL, DEFAULT 'any' | th, en, any |
| pattern_type | ENUM | NOT NULL, DEFAULT 'keyword' | keyword, regex |
| pattern_value | VARCHAR(255) | NOT NULL | ค่า pattern (keyword หรือ regex) |
| priority | INT | NOT NULL, DEFAULT 100 | ลำดับความสำคัญ (ยิ่งน้อยยิ่งสำคัญ) |
| is_active | BOOLEAN | NOT NULL, DEFAULT TRUE | สถานะการใช้งาน |
| created_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | วันที่สร้าง |
| updated_at | TIMESTAMP | NOT NULL, ON UPDATE CURRENT_TIMESTAMP | วันที่แก้ไขล่าสุด |
**Indexes**:
- PRIMARY KEY (id)
- UNIQUE KEY uk_pattern_public_id (public_id)
- INDEX idx_pattern_intent_code (intent_code)
- INDEX idx_pattern_active_priority (is_active, priority ASC)
- CONSTRAINT fk_intent_pattern_definition FOREIGN KEY (intent_code) REFERENCES ai_intent_definitions(intent_code) ON UPDATE CASCADE ON DELETE RESTRICT
**Business Rules**:
1. **Pattern Types** — keyword (ตรงตัว), regex (regular expression)
2. **Priority** — ยิ่งน้อยยิ่งสำคัญ (ตัวอย่าง: keyword=10, regex=5)
3. **Language** — th (ไทย), en (อังกฤษ), any (ทุกภาษา)
4. **Seed Data** — ~45 patterns สำหรับ 12 Intents (ยกเว้น FALLBACK)
5. **LLM Fallback** — เมื่อไม่ match pattern ไหนเลย → ใช้ LLM (gemma4:e4b Q8_0) ตาม ADR-023A
---
## **20. 📖 Glossary (คำศัพท์)**
- **RFA**: Request for Approval (เอกสารขออนุมัติ)
+16 -18
View File
@@ -11,28 +11,17 @@
| `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 |
| `lcbp3-v1.9.0-migration.sql` | สคริปต์ migration support tables สำหรับ n8n Migration Workflow (temporary - ลบได้หลัง migration เสร็จ) |
### Seed Files (ข้อมูลเริ่มต้น)
| ไฟล์ | คำอธิบาย |
|------|-----------|
| `lcbp3-v1.9.0-seed-basic.sql` | ข้อมูลเริ่มต้นพื้นฐาน (Organizations, Users, Roles, Permissions) |
| `lcbp3-v1.9.0-seed-basic.sql` | ข้อมูลเริ่มต้นพื้นฐาน (Organizations, Users, Roles, Permissions, Intent Classification, Workflow Definitions) |
| `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
| ไฟล์ | คำอธิบาย |
@@ -81,13 +70,11 @@ mysql < lcbp3-v1.9.0-seed-shopdrawing.sql
### การอัปเกรดจากเวอร์ชันก่อนหน้า
```bash
# รัน migration script
# รัน migration script (สำหรับ n8n Migration Workflow เท่านั้น)
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
# หมายเหตุ: ทุกการเปลี่ยนแปลง schema ได้ถูกรวมเข้า schema-02-tables.sql และ seed files แล้ว
# ไม่มี delta files ที่ต้องรันแยกตาม ADR-009
```
## 🔗 เอกสารที่เกี่ยวข้อง
@@ -99,6 +86,7 @@ mysql < deltas/15-add-ai-processing-status.sql
- **ADR-019**: Hybrid Identifier Strategy - UUID Strategy
- **ADR-023**: Unified AI Architecture - สถาปัตยกรรม AI หลัก
- **ADR-023A**: Unified AI Architecture (Model Revision) - อัปเดตโมเดล AI
- **ADR-024**: Intent Classification Strategy - Hybrid Intent Classifier (Pattern Match + LLM Fallback)
### Engineering Guidelines
@@ -115,6 +103,16 @@ mysql < deltas/15-add-ai-processing-status.sql
## 📝 Change Log
- **2026-05-19**:
- เพิ่ม Intent Classification tables (ai_intent_definitions, ai_intent_patterns) ตาม ADR-024
- รวม delta files (16-add-intent-classification.sql, 17-seed-intent-patterns.sql) เข้า schema-02-tables.sql และ seed-basic.sql
- ลบ rfa-approval-schema.sql (ตารางทั้งหมดถูกรวมเข้า schema-02-tables.sql แล้ว)
- ลบ redundant delta files (12, 14, 15) - ตารางและคอลัมน์ทั้งหมดถูกรวมเข้า schema-02-tables.sql แล้ว
- รวม delta files ที่เหลือ (13 ไฟล์) เข้า schema-02-tables.sql, seed-permissions.sql, และ seed-basic.sql:
- Schema: rag_status, rag_last_error (attachments), document_chunks table
- Seed: RAG permissions, RBAC bulk permission, CIRCULATION_FLOW_V1 workflow definition
- อัปเดต Data Dictionary ด้วย document_chunks table
- ลบ deltas/ directory ทั้งหมด (ตาม ADR-009 - รวมเข้า main schema/seed เสร็จแล้ว)
- **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
@@ -1,4 +0,0 @@
ALTER TABLE `attachments`
ADD COLUMN `reference_date` DATE NULL COMMENT 'Date used for folder structure (e.g. Issue Date) to prevent broken paths';
ALTER TABLE `attachments`
ADD INDEX `idx_attachments_reference_date` (`reference_date`);
@@ -1,12 +0,0 @@
-- Add permission for Bulk RBAC Update
-- Fix: Use existing 'user.manage_assignments' instead of creating new invalid permission
-- This permission (ID 25) is for assigning roles/projects
-- Grant to ADMIN (ID 2) and DC (ID 3) roles if not already present
-- Use INSERT IGNORE to avoid duplicates
INSERT IGNORE INTO `role_permissions` (`role_id`, `permission_id`)
SELECT r.role_id,
p.permission_id
FROM `roles` r,
`permissions` p
WHERE r.role_name IN ('ADMIN', 'Org Admin', 'DC', 'Document Control')
AND p.permission_name = 'user.manage_assignments';
@@ -1,30 +0,0 @@
-- Delta 03: Fix ENUM mismatches in document_number_audit and document_number_errors
-- Issue: 'GENERATE' operation used by backend but not in DB ENUM → INSERT fails → correspondence creation blocked
-- Date: 2026-03-19
-- Applies to: lcbp3-v1.8.0-schema-02-tables.sql
-- 1. Add 'VOID' and 'GENERATE' to document_number_audit.operation ENUM
ALTER TABLE document_number_audit
MODIFY COLUMN operation ENUM(
'RESERVE',
'CONFIRM',
'MANUAL_OVERRIDE',
'VOID_REPLACE',
'CANCEL',
'VOID',
'GENERATE'
) NOT NULL DEFAULT 'CONFIRM' COMMENT 'ประเภทการดำเนินการ';
-- 2. Add missing error_type values to document_number_errors
ALTER TABLE document_number_errors
MODIFY COLUMN error_type ENUM(
'LOCK_TIMEOUT',
'VERSION_CONFLICT',
'DB_ERROR',
'REDIS_ERROR',
'VALIDATION_ERROR',
'SEQUENCE_EXHAUSTED',
'RESERVATION_EXPIRED',
'DUPLICATE_NUMBER',
'GENERATE_ERROR'
) NOT NULL COMMENT 'ประเภท error (9 types)';
@@ -1,25 +0,0 @@
-- ============================================================
-- Delta 04: ADR-021 — Step-specific Attachments
-- เพิ่ม FK workflow_history_id ใน attachments table
-- ============================================================
-- ข้อควรระวัง: ค่า NULL = ไฟล์แนบหลัก (Main Document)
-- ค่าไม่ NULL = ไฟล์ประจำ Workflow Step นั้น
ALTER TABLE attachments
ADD COLUMN workflow_history_id CHAR(36) NULL
COMMENT 'FK to workflow_histories.id สำหรับไฟล์แนบประจำ Step (ADR-021). NULL = ไฟล์แนบหลัก',
ADD CONSTRAINT fk_attachments_workflow_history
FOREIGN KEY (workflow_history_id)
REFERENCES workflow_histories (id)
ON DELETE SET NULL
ON UPDATE CASCADE;
-- Index สำหรับ optimize การดึงไฟล์แนบตาม Step + เรียงตามวันที่
CREATE INDEX idx_att_wfhist_created
ON attachments (workflow_history_id, created_at);
-- ============================================================
-- Rollback:
-- ALTER TABLE attachments DROP FOREIGN KEY fk_attachments_workflow_history;
-- ALTER TABLE attachments DROP COLUMN workflow_history_id;
-- ============================================================
@@ -1,13 +0,0 @@
-- Delta 05: Add deadline_date to circulations (v1.8.7 — EC-CIRC-003)
-- Purpose: เพิ่มคอลัมน์ deadline_date ที่ตาราง circulations
-- เพื่อรองรับ EC-CIRC-003 (Overdue Badge) และการตั้งค่ากำหนดเวลา
-- Applied: เพิ่มทีหลัง Schema v1.8.0
-- Author: NAP-DMS v1.8.7
ALTER TABLE circulations
ADD COLUMN deadline_date DATE NULL
COMMENT 'วันครบกำหนดส่งงาน (nullable — ถ้า NULL = ไม่มีกำหนด)'
AFTER closed_at;
-- Index สำหรับ query Overdue Circulations ที่ Dashboard
CREATE INDEX idx_circulations_deadline ON circulations (deadline_date);
@@ -1,87 +0,0 @@
-- ==========================================================
-- Delta 06: Add CIRCULATION_FLOW_V1 Workflow Definition
-- ==========================================================
-- Purpose : สร้าง Workflow Definition สำหรับใบเวียนภายใน (Circulation)
-- Required : ก่อน delta นี้ ตาราง workflow_definitions ต้องมีอยู่แล้ว (ADR-001)
-- Renamed : CIRCULATION_INTERNAL_V1 → CIRCULATION_FLOW_V1 (ตาม naming convention)
-- States :
-- DRAFT (initial) → START → ROUTING
-- ROUTING → COMPLETE → COMPLETED (terminal)
-- ROUTING → FORCE_CLOSE → CANCELLED (terminal)
-- ==========================================================
INSERT INTO `workflow_definitions` (
`id`,
`workflow_code`,
`version`,
`description`,
`dsl`,
`compiled`,
`is_active`,
`created_at`,
`updated_at`
)
VALUES (
UUID(),
'CIRCULATION_FLOW_V1',
1,
'Circulation Workflow — DRAFT → ROUTING → COMPLETED | CANCELLED',
JSON_OBJECT(
'workflow', 'CIRCULATION_FLOW_V1',
'version', 1,
'states', JSON_ARRAY(
JSON_OBJECT(
'name', 'DRAFT',
'initial', TRUE,
'on', JSON_OBJECT(
'START', JSON_OBJECT('to', 'ROUTING')
)
),
JSON_OBJECT(
'name', 'ROUTING',
'on', JSON_OBJECT(
'COMPLETE', JSON_OBJECT('to', 'COMPLETED'),
'FORCE_CLOSE', JSON_OBJECT('to', 'CANCELLED')
)
),
JSON_OBJECT('name', 'COMPLETED', 'terminal', TRUE),
JSON_OBJECT('name', 'CANCELLED', 'terminal', TRUE)
)
),
JSON_OBJECT(
'initialState', 'DRAFT',
'states', JSON_OBJECT(
'DRAFT', JSON_OBJECT(
'initial', TRUE,
'terminal', FALSE,
'transitions', JSON_OBJECT(
'START', JSON_OBJECT('to', 'ROUTING', 'events', JSON_ARRAY())
)
),
'ROUTING', JSON_OBJECT(
'initial', FALSE,
'terminal', FALSE,
'transitions', JSON_OBJECT(
'COMPLETE', JSON_OBJECT('to', 'COMPLETED', 'events', JSON_ARRAY()),
'FORCE_CLOSE', JSON_OBJECT('to', 'CANCELLED', 'events', JSON_ARRAY())
)
),
'COMPLETED', JSON_OBJECT(
'initial', FALSE,
'terminal', TRUE,
'transitions', JSON_OBJECT()
),
'CANCELLED', JSON_OBJECT(
'initial', FALSE,
'terminal', TRUE,
'transitions', JSON_OBJECT()
)
)
),
TRUE,
NOW(),
NOW()
);
-- Verify
-- SELECT workflow_code, version, is_active FROM workflow_definitions WHERE workflow_code = 'CIRCULATION_FLOW_V1';
@@ -1,22 +0,0 @@
-- ==========================================================
-- Delta 07: Add contract_id to workflow_instances (C3 Contract Scoping)
-- ==========================================================
-- Purpose : เพิ่ม contract_id FK ใน workflow_instances เพื่อให้ Workflow Engine
-- แยก scope ตาม Contract ได้ (C3 ตาม analysis ADR-021)
-- Why : RFA / Correspondence / Transmittal → contract-scoped (contractId ถูกตั้ง)
-- Circulation → organization-scoped (contractId = NULL, ใช้ Level 2 org check)
-- Guard Level 2.5 ตรวจ contract_organizations membership เฉพาะ contractId ≠ NULL
-- ADR : ADR-009 (no migrations — direct SQL only)
-- ==========================================================
ALTER TABLE workflow_instances
ADD COLUMN contract_id INT NULL COMMENT 'Contract ที่ Workflow นี้เป็นส่วนหนึ่ง (NULL = global/legacy)'
AFTER definition_id,
ADD CONSTRAINT fk_wf_inst_contract FOREIGN KEY (contract_id) REFERENCES contracts (id) ON DELETE
SET NULL;
-- Index สำหรับ Guard lookup: "Instances ทั้งหมดในสัญญา X"
CREATE INDEX idx_wf_inst_contract ON workflow_instances (contract_id, entity_type, STATUS);
-- Verify
-- DESCRIBE workflow_instances;
-- SHOW INDEX FROM workflow_instances WHERE Key_name = 'idx_wf_inst_contract';
@@ -1,11 +0,0 @@
-- Delta 08: ADR-022 RAG — เพิ่ม rag_status และ rag_last_error ในตาราง attachments
-- Apply: 2026-04-19
-- Ref: specs/08-Tasks/ADR-022-Retrieval-Augmented-Generation/data-model.md §1.1
ALTER TABLE attachments
ADD COLUMN rag_status ENUM('PENDING', 'PROCESSING', 'INDEXED', 'FAILED')
NOT NULL DEFAULT 'PENDING'
COMMENT 'สถานะ RAG ingestion ระดับ file',
ADD COLUMN rag_last_error TEXT NULL
COMMENT 'Error message ล่าสุดเมื่อ rag_status = FAILED',
ADD INDEX idx_attachments_rag_status (rag_status);
@@ -1,25 +0,0 @@
-- Delta 08b: ADR-022 RAG — สร้างตาราง document_chunks สำหรับเก็บ vector metadata
-- Apply: 2026-04-19
-- Ref: specs/08-Tasks/ADR-022-Retrieval-Augmented-Generation/data-model.md §1.2
CREATE TABLE document_chunks (
id CHAR(36) NOT NULL PRIMARY KEY COMMENT 'UUID = Qdrant point ID',
document_id CHAR(36) NOT NULL COMMENT 'FK → attachments.public_id (UUIDv7)',
chunk_index INT NOT NULL COMMENT 'ลำดับ chunk ภายใน document',
content TEXT NOT NULL COMMENT 'เนื้อหา chunk หลัง PyThaiNLP normalize',
doc_type VARCHAR(20) NOT NULL COMMENT 'CORR, RFA, DRAWING, CONTRACT, RPT, TRANS',
doc_number VARCHAR(100) NULL COMMENT 'หมายเลขเอกสาร เช่น REF-2026-001',
revision VARCHAR(20) NULL COMMENT 'Revision เช่น Rev.A',
project_code VARCHAR(50) NOT NULL COMMENT 'รหัสโครงการ (ใช้ filter)',
project_public_id CHAR(36) NOT NULL COMMENT 'UUIDv7 ของโครงการ (Qdrant tenant key)',
version VARCHAR(20) NULL COMMENT 'เวอร์ชันเอกสาร เช่น 1.0, 2.1 (ถ้ามี)',
classification ENUM('PUBLIC', 'INTERNAL', 'CONFIDENTIAL')
NOT NULL DEFAULT 'INTERNAL',
embedding_model VARCHAR(100) NOT NULL DEFAULT 'nomic-embed-text',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX idx_chunks_document_id (document_id),
INDEX idx_chunks_doc_number_rev (doc_number, revision),
INDEX idx_chunks_project (project_public_id),
FULLTEXT INDEX ft_chunks_content (content)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
@@ -1,8 +0,0 @@
-- Delta 08c: ADR-022 RAG — เพิ่ม permissions สำหรับ RAG feature
-- Apply: 2026-04-19
-- Ref: specs/08-Tasks/ADR-022-Retrieval-Augmented-Generation/tasks.md T014
INSERT IGNORE INTO permissions (permission_name, description, module, created_at, updated_at)
VALUES
('rag.query', 'ใช้งาน RAG Q&A เพื่อค้นหาคำตอบจากเอกสาร', 'rag', NOW(), NOW()),
('rag.manage', 'จัดการ RAG ingestion, re-index, ลบ vectors', 'rag', NOW(), NOW());
@@ -1,17 +0,0 @@
-- ============================================================
-- Delta 09: ADR-001 v1.1 — Optimistic Lock for Workflow Transitions
-- เพิ่ม version_no ใน workflow_instances สำหรับ Optimistic Concurrency Control
-- ============================================================
-- Feature: 003-unified-workflow-engine (FR-002)
-- Date: 2026-05-03
-- ข้อควรระวัง: Existing rows จะได้ค่า DEFAULT 1 อัตโนมัติ — ไม่มี Data Loss
-- Rollback: ALTER TABLE workflow_instances DROP INDEX idx_wf_inst_version;
-- ALTER TABLE workflow_instances DROP COLUMN version_no;
ALTER TABLE workflow_instances
ADD COLUMN version_no INT NOT NULL DEFAULT 1
COMMENT 'Optimistic lock counter — incremented on every successful transition (ADR-001 v1.1 FR-002). Client sends current value; server rejects with 409 if mismatch.';
-- Index เพื่อรองรับ CAS check: WHERE id = ? AND version_no = ?
CREATE INDEX idx_wf_inst_version
ON workflow_instances (id, version_no);
@@ -1,14 +0,0 @@
-- ============================================================
-- Delta 10: ADR-001 v1.1 / ADR-019 UUID Compliance
-- เพิ่ม action_by_user_uuid ใน workflow_histories
-- เพื่อ expose User identity ผ่าน API โดยไม่ต้องเปิดเผย INT PK (ADR-019)
-- ============================================================
-- Feature: 003-unified-workflow-engine (FR-003)
-- Date: 2026-05-03
-- ข้อควรระวัง: NULL สำหรับ Historical records ที่สร้างก่อน delta นี้ — เป็น Acceptable
-- NULL ในบริบทนี้ = "System Action" หรือ "Pre-migration record"
-- Rollback: ALTER TABLE workflow_histories DROP COLUMN action_by_user_uuid;
ALTER TABLE workflow_histories
ADD COLUMN action_by_user_uuid VARCHAR(36) NULL
COMMENT 'UUID ของ User ผู้ดำเนินการ — ใช้ใน API Response แทน INT FK (ADR-019). NULL = System Action หรือ Pre-migration record';
@@ -1,25 +0,0 @@
-- =============================================================================
-- Delta 11: เพิ่ม uuid column ให้ roles table
-- =============================================================================
-- เหตุผล: roles ไม่มี uuid column ทำให้ distribution_recipients ไม่สามารถ
-- อ้างอิง ROLE type ด้วย publicId ได้ตาม ADR-019
-- ใช้ใน: distribution_recipients.recipient_public_id (recipient_type = 'ROLE')
-- ADR: ADR-019 (Hybrid Identifier Strategy)
-- Feature: v1.9.0 RFA Approval Refactor (1-rfa-approval-refactor)
-- Created: 2026-05-13
-- =============================================================================
ALTER TABLE `roles`
ADD COLUMN `uuid` UUID NOT NULL DEFAULT (UUID())
COMMENT 'UUID Public Identifier (ADR-019) — ใช้ใน API Response แทน role_id'
AFTER `role_id`;
-- สร้าง Unique Index สำหรับ uuid
CREATE UNIQUE INDEX `idx_roles_uuid` ON `roles` (`uuid`);
-- =============================================================================
-- หมายเหตุ: หลัง Apply delta นี้แล้ว
-- - roles ที่มีอยู่แล้วจะได้ uuid อัตโนมัติจาก DEFAULT (UUID())
-- - distribution_recipients.recipient_public_id (type=ROLE) ให้ใช้ roles.uuid
-- - TypeORM Entity: เพิ่ม @Column({ unique: true }) uuid: string; ใน RoleEntity
-- =============================================================================
@@ -1,88 +0,0 @@
-- File: specs/03-Data-and-Storage/deltas/12-unified-ai-architecture.sql
-- Change Log
-- - 2026-05-14: เพิ่ม schema delta สำหรับ ADR-023 Unified AI Architecture.
-- ADR-009: ใช้ SQL delta โดยตรง ห้ามใช้ TypeORM migration
SET NAMES utf8mb4;
CREATE TABLE IF NOT EXISTS migration_review_queue (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT 'Internal PK (ห้าม expose ใน API)',
uuid UUID NOT NULL DEFAULT UUID() COMMENT 'UUID Public Identifier (ADR-019)',
batch_id VARCHAR(100) NOT NULL COMMENT 'Batch ingestion identifier',
original_file_name VARCHAR(255) NOT NULL COMMENT 'Original uploaded legacy filename',
source_attachment_public_id UUID NULL COMMENT 'Temp attachment publicId from two-phase upload',
temp_attachment_id INT NULL COMMENT 'Internal temp attachment id used during commit only',
extracted_metadata JSON NULL COMMENT 'AI extracted metadata before human validation',
confidence_score DECIMAL(4, 3) NULL COMMENT 'Overall AI confidence score 0.000-1.000',
status ENUM('PENDING', 'IMPORTED', 'REJECTED') NOT NULL DEFAULT 'PENDING',
error_reason TEXT NULL COMMENT 'Reason when AI processing rejected the record',
version INT NOT NULL DEFAULT 1 COMMENT 'Optimistic locking version',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY idx_migration_review_uuid (uuid),
KEY idx_migration_review_batch (batch_id),
KEY idx_migration_review_status (status)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ADR-023 AI migration review staging queue';
ALTER TABLE migration_review_queue
ADD COLUMN IF NOT EXISTS uuid UUID NOT NULL DEFAULT UUID() COMMENT 'UUID Public Identifier (ADR-019)',
ADD COLUMN IF NOT EXISTS batch_id VARCHAR(100) NULL COMMENT 'Batch ingestion identifier',
ADD COLUMN IF NOT EXISTS original_file_name VARCHAR(255) NULL COMMENT 'Original uploaded legacy filename',
ADD COLUMN IF NOT EXISTS source_attachment_public_id UUID NULL COMMENT 'Temp attachment publicId from two-phase upload',
ADD COLUMN IF NOT EXISTS temp_attachment_id INT NULL COMMENT 'Internal temp attachment id used during commit only',
ADD COLUMN IF NOT EXISTS extracted_metadata JSON NULL COMMENT 'AI extracted metadata before human validation',
ADD COLUMN IF NOT EXISTS confidence_score DECIMAL(4, 3) NULL COMMENT 'Overall AI confidence score 0.000-1.000',
ADD COLUMN IF NOT EXISTS error_reason TEXT NULL COMMENT 'Reason when AI processing rejected the record',
ADD COLUMN IF NOT EXISTS version INT NOT NULL DEFAULT 1 COMMENT 'Optimistic locking version',
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
ALTER TABLE migration_review_queue
MODIFY COLUMN status ENUM('PENDING', 'APPROVED', 'IMPORTED', 'REJECTED') NOT NULL DEFAULT 'PENDING';
CREATE UNIQUE INDEX IF NOT EXISTS idx_migration_review_uuid ON migration_review_queue (uuid);
CREATE INDEX IF NOT EXISTS idx_migration_review_batch ON migration_review_queue (batch_id);
CREATE INDEX IF NOT EXISTS idx_migration_review_status ON migration_review_queue (status);
CREATE TABLE IF NOT EXISTS 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 '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';
ALTER TABLE ai_audit_logs
ADD COLUMN IF NOT EXISTS ai_model VARCHAR(50) NOT NULL DEFAULT 'gemma4' COMMENT 'Legacy AI model column used by current gateway service',
ADD COLUMN IF NOT EXISTS model_name VARCHAR(100) NULL COMMENT 'Local model name used by ADR-023 AI pipeline',
ADD COLUMN IF NOT EXISTS ai_suggestion_json JSON NULL COMMENT 'AI suggested metadata',
ADD COLUMN IF NOT EXISTS human_override_json JSON NULL COMMENT 'Human approved or overridden metadata',
ADD COLUMN IF NOT EXISTS processing_time_ms INT NULL COMMENT 'Legacy processing duration field',
ADD COLUMN IF NOT EXISTS input_hash VARCHAR(64) NULL COMMENT 'Legacy SHA-256 input hash',
ADD COLUMN IF NOT EXISTS output_hash VARCHAR(64) NULL COMMENT 'Legacy SHA-256 output hash',
ADD COLUMN IF NOT EXISTS status ENUM('SUCCESS', 'FAILED', 'TIMEOUT') NOT NULL DEFAULT 'SUCCESS' COMMENT 'Legacy processing status field',
ADD COLUMN IF NOT EXISTS error_message TEXT NULL COMMENT 'Legacy processing error field',
ADD COLUMN IF NOT EXISTS confirmed_by_user_id INT NULL COMMENT 'Internal users.user_id that confirmed the record';
UPDATE ai_audit_logs
SET model_name = ai_model
WHERE model_name IS NULL AND ai_model IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_ai_audit_model_name ON ai_audit_logs (model_name);
CREATE INDEX IF NOT EXISTS idx_ai_audit_confirmed_by ON ai_audit_logs (confirmed_by_user_id);
@@ -1,56 +0,0 @@
-- 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);
@@ -1,14 +0,0 @@
-- 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);
@@ -1,60 +0,0 @@
-- Delta 16: Add Intent Classification Tables (ADR-024)
-- Feature: 224-intent-classification
-- Created: 2026-05-19
-- เพิ่มตาราง ai_intent_definitions และ ai_intent_patterns สำหรับ Hybrid Intent Classifier
-- Intent Definitions Table
CREATE TABLE IF NOT EXISTS ai_intent_definitions (
id INT AUTO_INCREMENT PRIMARY KEY,
public_id UUID NOT NULL DEFAULT UUID(),
intent_code VARCHAR(50) NOT NULL,
description_th VARCHAR(255) NOT NULL,
description_en VARCHAR(255) NOT NULL,
category ENUM('read', 'suggest', 'utility') NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_intent_public_id (public_id),
UNIQUE KEY uk_intent_code (intent_code),
INDEX idx_intent_active (is_active, category)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Intent Patterns Table
CREATE TABLE IF NOT EXISTS ai_intent_patterns (
id INT AUTO_INCREMENT PRIMARY KEY,
public_id UUID NOT NULL DEFAULT UUID(),
intent_code VARCHAR(50) NOT NULL,
language ENUM('th', 'en', 'any') NOT NULL DEFAULT 'any',
pattern_type ENUM('keyword', 'regex') NOT NULL DEFAULT 'keyword',
pattern_value VARCHAR(255) NOT NULL,
priority INT NOT NULL DEFAULT 100,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_pattern_public_id (public_id),
INDEX idx_pattern_intent_code (intent_code),
INDEX idx_pattern_active_priority (is_active, priority ASC),
CONSTRAINT fk_intent_pattern_definition
FOREIGN KEY (intent_code) REFERENCES ai_intent_definitions(intent_code)
ON UPDATE CASCADE ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Seed Intent Definitions (v1) — 12 รายการตาม ADR-024
INSERT IGNORE INTO ai_intent_definitions (intent_code, description_th, description_en, category) VALUES
-- Read Intents
('RAG_QUERY', 'ถามคำถามธรรมชาติ ตอบจาก vector + doc context', 'Natural language query from vector DB + document context', 'read'),
('GET_RFA', 'ดึง RFA ตาม filter', 'Get RFA by filters', 'read'),
('GET_DRAWING', 'ดึง Drawing revision', 'Get Drawing revision', 'read'),
('GET_TRANSMITTAL', 'ดึง Transmittal', 'Get Transmittal', 'read'),
('GET_CORRESPONDENCE','ดึง Correspondence ทั่วไป', 'Get Correspondence', 'read'),
('GET_CIRCULATION', 'ดึง Circulation', 'Get Circulation', 'read'),
('GET_RFA_DRAWINGS', 'ดึง Drawings ที่ผูกกับ RFA', 'Get Drawings linked to RFA', 'read'),
('SUMMARIZE_DOCUMENT','สรุปเอกสารที่เปิดอยู่', 'Summarize current document', 'read'),
('LIST_OVERDUE', 'รายการ cross-entity ที่เกินกำหนด', 'List overdue items across entities', 'read'),
-- Suggest Intents
('SUGGEST_METADATA', 'แนะนำ metadata สำหรับเอกสารที่อัปโหลด', 'Suggest metadata for uploaded document', 'suggest'),
('SUGGEST_ACTION', 'แจ้งเตือนว่าควรทำอะไรต่อ', 'Suggest next actions', 'suggest'),
-- Utility Intents
('FALLBACK', 'ไม่เข้า intent ไหน / ไม่เกี่ยวกับระบบ', 'No matching intent / unrelated to system', 'utility');
@@ -1,89 +0,0 @@
-- Delta 17: Seed Intent Patterns (v1) for ADR-024 Intent Classification
-- Feature: 224-intent-classification
-- Created: 2026-05-19
-- เพิ่ม patterns เริ่มต้นสำหรับ 12 Intent Definitions (keyword + regex)
-- RAG_QUERY patterns
INSERT IGNORE INTO ai_intent_patterns (intent_code, language, pattern_type, pattern_value, priority) VALUES
('RAG_QUERY', 'th', 'keyword', 'ค้นหา', 10),
('RAG_QUERY', 'th', 'keyword', 'หาข้อมูล', 10),
('RAG_QUERY', 'en', 'keyword', 'search', 10),
('RAG_QUERY', 'en', 'keyword', 'find', 10),
('RAG_QUERY', 'any', 'regex', '(?i)(what|where|who|when|how|why).*\\?', 50);
-- GET_RFA patterns
INSERT IGNORE INTO ai_intent_patterns (intent_code, language, pattern_type, pattern_value, priority) VALUES
('GET_RFA', 'th', 'keyword', 'rfa', 10),
('GET_RFA', 'th', 'keyword', 'อาร์เอฟเอ', 10),
('GET_RFA', 'en', 'keyword', 'request for approval', 15),
('GET_RFA', 'any', 'regex', '(?i)rfa[- ]?\\d+', 5);
-- GET_DRAWING patterns
INSERT IGNORE INTO ai_intent_patterns (intent_code, language, pattern_type, pattern_value, priority) VALUES
('GET_DRAWING', 'th', 'keyword', 'แบบ', 20),
('GET_DRAWING', 'th', 'keyword', 'drawing', 10),
('GET_DRAWING', 'en', 'keyword', 'drawing', 10),
('GET_DRAWING', 'en', 'keyword', 'revision', 20),
('GET_DRAWING', 'any', 'regex', '(?i)(shop.?draw|dwg|rev\\.?\\s*\\d)', 5);
-- GET_TRANSMITTAL patterns
INSERT IGNORE INTO ai_intent_patterns (intent_code, language, pattern_type, pattern_value, priority) VALUES
('GET_TRANSMITTAL', 'th', 'keyword', 'transmittal', 10),
('GET_TRANSMITTAL', 'th', 'keyword', 'ทรานส์มิตทอล', 10),
('GET_TRANSMITTAL', 'en', 'keyword', 'transmittal', 10),
('GET_TRANSMITTAL', 'any', 'regex', '(?i)tr[- ]?\\d+', 5);
-- GET_CORRESPONDENCE patterns
INSERT IGNORE INTO ai_intent_patterns (intent_code, language, pattern_type, pattern_value, priority) VALUES
('GET_CORRESPONDENCE', 'th', 'keyword', 'จดหมาย', 10),
('GET_CORRESPONDENCE', 'th', 'keyword', 'หนังสือ', 15),
('GET_CORRESPONDENCE', 'en', 'keyword', 'correspondence', 10),
('GET_CORRESPONDENCE', 'en', 'keyword', 'letter', 15);
-- GET_CIRCULATION patterns
INSERT IGNORE INTO ai_intent_patterns (intent_code, language, pattern_type, pattern_value, priority) VALUES
('GET_CIRCULATION', 'th', 'keyword', 'เวียน', 10),
('GET_CIRCULATION', 'th', 'keyword', 'circulation', 10),
('GET_CIRCULATION', 'en', 'keyword', 'circulation', 10),
('GET_CIRCULATION', 'en', 'keyword', 'distribute', 15);
-- GET_RFA_DRAWINGS patterns
INSERT IGNORE INTO ai_intent_patterns (intent_code, language, pattern_type, pattern_value, priority) VALUES
('GET_RFA_DRAWINGS', 'th', 'keyword', 'แบบใน rfa', 5),
('GET_RFA_DRAWINGS', 'en', 'keyword', 'drawings in rfa', 5),
('GET_RFA_DRAWINGS', 'any', 'regex', '(?i)(draw|แบบ).*(rfa|อาร์เอฟเอ)', 5);
-- SUMMARIZE_DOCUMENT patterns
INSERT IGNORE INTO ai_intent_patterns (intent_code, language, pattern_type, pattern_value, priority) VALUES
('SUMMARIZE_DOCUMENT', 'th', 'keyword', 'สรุป', 10),
('SUMMARIZE_DOCUMENT', 'th', 'keyword', 'สรุปเอกสาร', 5),
('SUMMARIZE_DOCUMENT', 'en', 'keyword', 'summarize', 10),
('SUMMARIZE_DOCUMENT', 'en', 'keyword', 'summary', 10),
('SUMMARIZE_DOCUMENT', 'any', 'regex', '(?i)(สรุป|summar|tldr|tl;dr)', 5);
-- LIST_OVERDUE patterns
INSERT IGNORE INTO ai_intent_patterns (intent_code, language, pattern_type, pattern_value, priority) VALUES
('LIST_OVERDUE', 'th', 'keyword', 'เกินกำหนด', 10),
('LIST_OVERDUE', 'th', 'keyword', 'ค้าง', 15),
('LIST_OVERDUE', 'th', 'keyword', 'overdue', 10),
('LIST_OVERDUE', 'en', 'keyword', 'overdue', 10),
('LIST_OVERDUE', 'en', 'keyword', 'late', 20),
('LIST_OVERDUE', 'any', 'regex', '(?i)(overdue|เกินกำหนด|ล่าช้า)', 5);
-- SUGGEST_METADATA patterns
INSERT IGNORE INTO ai_intent_patterns (intent_code, language, pattern_type, pattern_value, priority) VALUES
('SUGGEST_METADATA', 'th', 'keyword', 'แนะนำ metadata', 5),
('SUGGEST_METADATA', 'th', 'keyword', 'แท็ก', 15),
('SUGGEST_METADATA', 'en', 'keyword', 'suggest metadata', 5),
('SUGGEST_METADATA', 'en', 'keyword', 'tag', 15),
('SUGGEST_METADATA', 'any', 'regex', '(?i)(suggest|แนะนำ).*(tag|meta|ประเภท)', 5);
-- SUGGEST_ACTION patterns
INSERT IGNORE INTO ai_intent_patterns (intent_code, language, pattern_type, pattern_value, priority) VALUES
('SUGGEST_ACTION', 'th', 'keyword', 'ทำอะไรต่อ', 10),
('SUGGEST_ACTION', 'th', 'keyword', 'แนะนำ', 20),
('SUGGEST_ACTION', 'en', 'keyword', 'what should i do', 10),
('SUGGEST_ACTION', 'en', 'keyword', 'next step', 10),
('SUGGEST_ACTION', 'any', 'regex', '(?i)(next.?step|ทำอะไร|ควรทำ|what.*do)', 10);
-- FALLBACK: ไม่ต้อง seed pattern — ใช้เป็น default เมื่อไม่ match อะไรเลย
@@ -1,211 +0,0 @@
-- =============================================================================
-- LCBP3-DMS v1.9.0 — RFA Approval System Refactor Schema
-- Feature Branch: 204-rfa-approval-refactor
-- ADR-009: No TypeORM migrations — edit SQL schema directly
-- Created: 2026-05-13
-- =============================================================================
-- -----------------------------------------------------------------------------
-- 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),
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;
-- -----------------------------------------------------------------------------
-- 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),
PRIMARY KEY (`id`),
UNIQUE KEY `uq_review_team_members_uuid` (`uuid`),
UNIQUE KEY `uq_team_user_discipline` (`team_id`, `user_id`, `discipline_id`),
KEY `idx_rtm_team` (`team_id`),
KEY `idx_rtm_user` (`user_id`),
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;
-- -----------------------------------------------------------------------------
-- 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),
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;
-- -----------------------------------------------------------------------------
-- 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),
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`),
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;
-- -----------------------------------------------------------------------------
-- 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),
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`),
KEY `idx_review_tasks_rfa_revision` (`rfa_revision_id`),
KEY `idx_review_tasks_status` (`status`),
KEY `idx_review_tasks_assigned` (`assigned_to_user_id`, `status`),
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;
-- -----------------------------------------------------------------------------
-- 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),
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_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;
-- -----------------------------------------------------------------------------
-- 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),
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;
-- -----------------------------------------------------------------------------
-- 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),
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;
-- -----------------------------------------------------------------------------
-- 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),
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.';
@@ -872,15 +872,42 @@ CREATE TABLE attachments (
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',
rag_status ENUM('PENDING', 'PROCESSING', 'INDEXED', 'FAILED') NOT NULL DEFAULT 'PENDING' COMMENT 'สถานะ RAG ingestion ระดับ file (ADR-022)',
rag_last_error TEXT NULL COMMENT 'Error message ล่าสุดเมื่อ rag_status = FAILED',
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),
INDEX idx_attachments_rag_status (rag_status),
UNIQUE INDEX idx_attachments_uuid (uuid)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ตาราง "กลาง" เก็บไฟล์แนบทั้งหมดของระบบ';
-- =====================================================
-- 14. 📄 Document Chunks (ADR-022 RAG)
-- =====================================================
-- ตารางเก็บ vector metadata สำหรับ RAG ingestion
CREATE TABLE document_chunks (
id CHAR(36) NOT NULL PRIMARY KEY COMMENT 'UUID = Qdrant point ID',
document_id CHAR(36) NOT NULL COMMENT 'FK → attachments.public_id (UUIDv7)',
chunk_index INT NOT NULL COMMENT 'ลำดับ chunk ภายใน document',
content TEXT NOT NULL COMMENT 'เนื้อหา chunk หลัง PyThaiNLP normalize',
doc_type VARCHAR(20) NOT NULL COMMENT 'CORR, RFA, DRAWING, CONTRACT, RPT, TRANS',
doc_number VARCHAR(100) NULL COMMENT 'หมายเลขเอกสาร เช่น REF-2026-001',
revision VARCHAR(20) NULL COMMENT 'Revision เช่น Rev.A',
project_code VARCHAR(50) NOT NULL COMMENT 'รหัสโครงการ (ใช้ filter)',
project_public_id CHAR(36) NOT NULL COMMENT 'UUIDv7 ของโครงการ (Qdrant tenant key)',
version VARCHAR(20) NULL COMMENT 'เวอร์ชันเอกสาร เช่น 1.0, 2.1 (ถ้ามี)',
classification ENUM('PUBLIC', 'INTERNAL', 'CONFIDENTIAL') NOT NULL DEFAULT 'INTERNAL',
embedding_model VARCHAR(100) NOT NULL DEFAULT 'nomic-embed-text',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX idx_chunks_document_id (document_id),
INDEX idx_chunks_doc_number_rev (doc_number, revision),
INDEX idx_chunks_project (project_public_id),
FULLTEXT INDEX ft_chunks_content (content)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ตาราง Document Chunks สำหรับ RAG (ADR-022)';
-- ตารางเชื่อม correspondence_revisions กับ attachments (M:N)
-- [FIX] FK เปลี่ยนจาก correspondences.id → correspondence_revisions.id
-- เหตุผล: ไฟล์แนบผูกกับ revision ไม่ใช่ correspondence master (แต่ละ revision มีไฟล์ต่างกัน)
@@ -1365,9 +1392,6 @@ CREATE TABLE workflow_definitions (
UNIQUE KEY uq_workflow_version (workflow_code, version)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ตารางเก็บนิยามกฎการเดินเอกสาร (Workflow DSL)';
-- สร้าง Index สำหรับการค้นหา Workflow ที่ Active ล่าสุดได้เร็วขึ้น
CREATE INDEX idx_workflow_active ON workflow_definitions (workflow_code, is_active, version);
-- 2. ตารางเก็บ Workflow Instance (สถานะเอกสารจริง)
CREATE TABLE workflow_instances (
id CHAR(36) NOT NULL PRIMARY KEY COMMENT 'UUID ของ Instance',
@@ -1392,15 +1416,6 @@ CREATE TABLE workflow_instances (
SET NULL -- [delta-07]
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ตารางเก็บสถานะการเดินเรื่องของเอกสาร';
CREATE INDEX idx_wf_inst_entity ON workflow_instances (entity_type, entity_id);
CREATE INDEX idx_wf_inst_contract ON workflow_instances (contract_id, entity_type, STATUS);
CREATE INDEX idx_wf_inst_state ON workflow_instances (current_state);
-- Index เพื่อรองรับ CAS check: WHERE id = ? AND version_no = ?
CREATE INDEX idx_wf_inst_version ON workflow_instances (id, version_no);
-- 3. ตารางเก็บประวัติ (Audit Log / History)
CREATE TABLE workflow_histories (
id CHAR(36) NOT NULL PRIMARY KEY COMMENT 'UUID',
@@ -1416,10 +1431,6 @@ CREATE TABLE workflow_histories (
CONSTRAINT fk_wf_hist_inst FOREIGN KEY (instance_id) REFERENCES workflow_instances (id) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ตารางประวัติการเปลี่ยนสถานะ Workflow';
CREATE INDEX idx_wf_hist_instance ON workflow_histories (instance_id);
CREATE INDEX idx_wf_hist_user ON workflow_histories (action_by_user_id);
-- =====================================================
-- 11. 🤖 AI Gateway (ตาราง AI Integration - ADR-018, ADR-020)
-- =====================================================
@@ -1507,6 +1518,43 @@ CREATE TABLE ai_audit_logs (
SET NULL
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ADR-023 AI development feedback log';
-- =====================================================
-- 13. 🤖 Intent Classification (ADR-024)
-- =====================================================
-- Intent Definitions Table
CREATE TABLE IF NOT EXISTS ai_intent_definitions (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT 'Internal PK (ห้าม expose ใน API)',
public_id UUID NOT NULL DEFAULT UUID() COMMENT 'UUID Public Identifier (ADR-019)',
intent_code VARCHAR(50) NOT NULL COMMENT 'รหัส Intent เช่น RAG_QUERY, GET_RFA',
description_th VARCHAR(255) NOT NULL COMMENT 'คำอธิบายภาษาไทย',
description_en VARCHAR(255) NOT NULL COMMENT 'คำอธิบายภาษาอังกฤษ',
category ENUM('read', 'suggest', 'utility') NOT NULL COMMENT 'ประเภท Intent',
is_active BOOLEAN NOT NULL DEFAULT TRUE COMMENT 'สถานะการใช้งาน',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'วันที่แก้ไขล่าสุด',
UNIQUE KEY uk_intent_public_id (public_id),
UNIQUE KEY uk_intent_code (intent_code),
INDEX idx_intent_active (is_active, category)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ตาราง Intent Definitions สำหรับ Hybrid Intent Classifier (ADR-024)';
-- Intent Patterns Table
CREATE TABLE IF NOT EXISTS ai_intent_patterns (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT 'Internal PK (ห้าม expose ใน API)',
public_id UUID NOT NULL DEFAULT UUID() COMMENT 'UUID Public Identifier (ADR-019)',
intent_code VARCHAR(50) NOT NULL COMMENT 'รหัส Intent (FK to ai_intent_definitions)',
language ENUM('th', 'en', 'any') NOT NULL DEFAULT 'any' COMMENT 'ภาษาของ pattern',
pattern_type ENUM('keyword', 'regex') NOT NULL DEFAULT 'keyword' COMMENT 'ประเภท pattern',
pattern_value VARCHAR(255) NOT NULL COMMENT 'ค่า pattern (keyword หรือ regex)',
priority INT NOT NULL DEFAULT 100 COMMENT 'ลำดับความสำคัญ (ยิ่งน้อยยิ่งสำคัญ)',
is_active BOOLEAN NOT NULL DEFAULT TRUE COMMENT 'สถานะการใช้งาน',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'วันที่แก้ไขล่าสุด',
UNIQUE KEY uk_pattern_public_id (public_id),
INDEX idx_pattern_intent_code (intent_code),
INDEX idx_pattern_active_priority (is_active, priority ASC),
CONSTRAINT fk_intent_pattern_definition FOREIGN KEY (intent_code) REFERENCES ai_intent_definitions(intent_code) ON UPDATE CASCADE ON DELETE RESTRICT
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'ตาราง Intent Patterns สำหรับ Hybrid Intent Classifier (ADR-024)';
-- =============================================================================
-- 20. RFA Approval System (v1.9.0)
-- =============================================================================
@@ -93,6 +93,23 @@ CREATE INDEX idx_backup_logs_started_at ON backup_logs (started_at);
CREATE INDEX idx_backup_logs_completed_at ON backup_logs (completed_at);
-- Indexes for workflow_definitions (ADR-001 Unified Workflow Engine)
CREATE INDEX idx_workflow_active ON workflow_definitions (workflow_code, is_active, version);
-- Indexes for workflow_instances (ADR-001 Unified Workflow Engine)
CREATE INDEX idx_wf_inst_entity ON workflow_instances (entity_type, entity_id);
CREATE INDEX idx_wf_inst_contract ON workflow_instances (contract_id, entity_type, STATUS);
CREATE INDEX idx_wf_inst_state ON workflow_instances (current_state);
CREATE INDEX idx_wf_inst_version ON workflow_instances (id, version_no);
-- Indexes for workflow_histories (ADR-001 Unified Workflow Engine)
CREATE INDEX idx_wf_hist_instance ON workflow_histories (instance_id);
CREATE INDEX idx_wf_hist_user ON workflow_histories (action_by_user_id);
-- =====================================================
-- Additional Composite Indexes for Performance
-- =====================================================
@@ -2197,3 +2197,530 @@ VALUES (
'2025-12-16 09:34:10',
'2025-12-16 09:34:10'
);
-- =====================================================
-- Intent Classification Seed (ADR-024)
-- =====================================================
-- Intent Definitions (v1) — 12 รายการ
INSERT IGNORE INTO ai_intent_definitions (
intent_code,
description_th,
description_en,
category
)
VALUES -- Read Intents
(
'RAG_QUERY',
'ถามคำถามธรรมชาติ ตอบจาก vector + doc context',
'Natural language query from vector DB + document context',
'read'
),
(
'GET_RFA',
'ดึง RFA ตาม filter',
'Get RFA by filters',
'read'
),
(
'GET_DRAWING',
'ดึง Drawing revision',
'Get Drawing revision',
'read'
),
(
'GET_TRANSMITTAL',
'ดึง Transmittal',
'Get Transmittal',
'read'
),
(
'GET_CORRESPONDENCE',
'ดึง Correspondence ทั่วไป',
'Get Correspondence',
'read'
),
(
'GET_CIRCULATION',
'ดึง Circulation',
'Get Circulation',
'read'
),
(
'GET_RFA_DRAWINGS',
'ดึง Drawings ที่ผูกกับ RFA',
'Get Drawings linked to RFA',
'read'
),
(
'SUMMARIZE_DOCUMENT',
'สรุปเอกสารที่เปิดอยู่',
'Summarize current document',
'read'
),
(
'LIST_OVERDUE',
'รายการ cross-entity ที่เกินกำหนด',
'List overdue items across entities',
'read'
),
-- Suggest Intents
(
'SUGGEST_METADATA',
'แนะนำ metadata สำหรับเอกสารที่อัปโหลด',
'Suggest metadata for uploaded document',
'suggest'
),
(
'SUGGEST_ACTION',
'แจ้งเตือนว่าควรทำอะไรต่อ',
'Suggest next actions',
'suggest'
),
-- Utility Intents
(
'FALLBACK',
'ไม่เข้า intent ไหน / ไม่เกี่ยวกับระบบ',
'No matching intent / unrelated to system',
'utility'
);
-- Intent Patterns Seed (ADR-024)
-- =====================================================
-- RAG_QUERY patterns
INSERT IGNORE INTO ai_intent_patterns (
intent_code,
language,
pattern_type,
pattern_value,
priority
)
VALUES ('RAG_QUERY', 'th', 'keyword', 'ค้นหา', 10),
('RAG_QUERY', 'th', 'keyword', 'หาข้อมูล', 10),
('RAG_QUERY', 'en', 'keyword', 'search', 10),
('RAG_QUERY', 'en', 'keyword', 'find', 10),
(
'RAG_QUERY',
'any',
'regex',
'(?i)(what|where|who|when|how|why).*\\?',
50
);
-- GET_RFA patterns
INSERT IGNORE INTO ai_intent_patterns (
intent_code,
language,
pattern_type,
pattern_value,
priority
)
VALUES ('GET_RFA', 'th', 'keyword', 'rfa', 10),
('GET_RFA', 'th', 'keyword', 'อาร์เอฟเอ', 10),
(
'GET_RFA',
'en',
'keyword',
'request for approval',
15
),
('GET_RFA', 'any', 'regex', '(?i)rfa[- ]?\\d+', 5);
-- GET_DRAWING patterns
INSERT IGNORE INTO ai_intent_patterns (
intent_code,
language,
pattern_type,
pattern_value,
priority
)
VALUES ('GET_DRAWING', 'th', 'keyword', 'แบบ', 20),
('GET_DRAWING', 'th', 'keyword', 'drawing', 10),
('GET_DRAWING', 'en', 'keyword', 'drawing', 10),
('GET_DRAWING', 'en', 'keyword', 'revision', 20),
(
'GET_DRAWING',
'any',
'regex',
'(?i)(shop.?draw|dwg|rev\\.?\\s*\\d)',
5
);
-- GET_TRANSMITTAL patterns
INSERT IGNORE INTO ai_intent_patterns (
intent_code,
language,
pattern_type,
pattern_value,
priority
)
VALUES (
'GET_TRANSMITTAL',
'th',
'keyword',
'transmittal',
10
),
(
'GET_TRANSMITTAL',
'th',
'keyword',
'ทรานส์มิตทอล',
10
),
(
'GET_TRANSMITTAL',
'en',
'keyword',
'transmittal',
10
),
(
'GET_TRANSMITTAL',
'any',
'regex',
'(?i)tr[- ]?\\d+',
5
);
-- GET_CORRESPONDENCE patterns
INSERT IGNORE INTO ai_intent_patterns (
intent_code,
language,
pattern_type,
pattern_value,
priority
)
VALUES (
'GET_CORRESPONDENCE',
'th',
'keyword',
'จดหมาย',
10
),
(
'GET_CORRESPONDENCE',
'th',
'keyword',
'หนังสือ',
15
),
(
'GET_CORRESPONDENCE',
'en',
'keyword',
'correspondence',
10
),
(
'GET_CORRESPONDENCE',
'en',
'keyword',
'letter',
15
);
-- GET_CIRCULATION patterns
INSERT IGNORE INTO ai_intent_patterns (
intent_code,
language,
pattern_type,
pattern_value,
priority
)
VALUES ('GET_CIRCULATION', 'th', 'keyword', 'เวียน', 10),
(
'GET_CIRCULATION',
'th',
'keyword',
'circulation',
10
),
(
'GET_CIRCULATION',
'en',
'keyword',
'circulation',
10
),
(
'GET_CIRCULATION',
'en',
'keyword',
'distribute',
15
);
-- GET_RFA_DRAWINGS patterns
INSERT IGNORE INTO ai_intent_patterns (
intent_code,
language,
pattern_type,
pattern_value,
priority
)
VALUES (
'GET_RFA_DRAWINGS',
'th',
'keyword',
'แบบใน rfa',
5
),
(
'GET_RFA_DRAWINGS',
'en',
'keyword',
'drawings in rfa',
5
),
(
'GET_RFA_DRAWINGS',
'any',
'regex',
'(?i)(draw|แบบ).*(rfa|อาร์เอฟเอ)',
5
);
-- SUMMARIZE_DOCUMENT patterns
INSERT IGNORE INTO ai_intent_patterns (
intent_code,
language,
pattern_type,
pattern_value,
priority
)
VALUES (
'SUMMARIZE_DOCUMENT',
'th',
'keyword',
'สรุป',
10
),
(
'SUMMARIZE_DOCUMENT',
'th',
'keyword',
'สรุปเอกสาร',
5
),
(
'SUMMARIZE_DOCUMENT',
'en',
'keyword',
'summarize',
10
),
(
'SUMMARIZE_DOCUMENT',
'en',
'keyword',
'summary',
10
),
(
'SUMMARIZE_DOCUMENT',
'any',
'regex',
'(?i)(สรุป|summar|tldr|tl;dr)',
5
);
-- LIST_OVERDUE patterns
INSERT IGNORE INTO ai_intent_patterns (
intent_code,
language,
pattern_type,
pattern_value,
priority
)
VALUES ('LIST_OVERDUE', 'th', 'keyword', 'เกินกำหนด', 10),
('LIST_OVERDUE', 'th', 'keyword', 'ค้าง', 15),
('LIST_OVERDUE', 'th', 'keyword', 'overdue', 10),
('LIST_OVERDUE', 'en', 'keyword', 'overdue', 10),
('LIST_OVERDUE', 'en', 'keyword', 'late', 20),
(
'LIST_OVERDUE',
'any',
'regex',
'(?i)(overdue|เกินกำหนด|ล่าช้า)',
5
);
-- SUGGEST_METADATA patterns
INSERT IGNORE INTO ai_intent_patterns (
intent_code,
language,
pattern_type,
pattern_value,
priority
)
VALUES (
'SUGGEST_METADATA',
'th',
'keyword',
'แนะนำ metadata',
5
),
('SUGGEST_METADATA', 'th', 'keyword', 'แท็ก', 15),
(
'SUGGEST_METADATA',
'en',
'keyword',
'suggest metadata',
5
),
('SUGGEST_METADATA', 'en', 'keyword', 'tag', 15),
(
'SUGGEST_METADATA',
'any',
'regex',
'(?i)(suggest|แนะนำ).*(tag|meta|ประเภท)',
5
);
-- SUGGEST_ACTION patterns
INSERT IGNORE INTO ai_intent_patterns (
intent_code,
language,
pattern_type,
pattern_value,
priority
)
VALUES (
'SUGGEST_ACTION',
'th',
'keyword',
'ทำอะไรต่อ',
10
),
('SUGGEST_ACTION', 'th', 'keyword', 'แนะนำ', 20),
(
'SUGGEST_ACTION',
'en',
'keyword',
'what should i do',
10
),
(
'SUGGEST_ACTION',
'en',
'keyword',
'next step',
10
),
(
'SUGGEST_ACTION',
'any',
'regex',
'(?i)(next.?step|ทำอะไร|ควรทำ|what.*do)',
10
);
-- FALLBACK: ไม่ต้อง seed pattern — ใช้เป็น default เมื่อไม่ match อะไรเลย
-- =====================================================
-- Workflow Definitions Seed (ADR-001)
-- =====================================================
-- CIRCULATION_FLOW_V1 Workflow Definition
INSERT IGNORE INTO workflow_definitions (
id,
workflow_code,
version,
description,
dsl,
compiled,
is_active,
created_at,
updated_at
)
VALUES (
UUID(),
'CIRCULATION_FLOW_V1',
1,
'Circulation Workflow — DRAFT → ROUTING → COMPLETED | CANCELLED',
JSON_OBJECT(
'workflow',
'CIRCULATION_FLOW_V1',
'version',
1,
'states',
JSON_ARRAY(
JSON_OBJECT(
'name',
'DRAFT',
'initial',
TRUE,
'on',
JSON_OBJECT(
'START',
JSON_OBJECT('to', 'ROUTING')
)
),
JSON_OBJECT(
'name',
'ROUTING',
'on',
JSON_OBJECT(
'COMPLETE',
JSON_OBJECT('to', 'COMPLETED'),
'FORCE_CLOSE',
JSON_OBJECT('to', 'CANCELLED')
)
),
JSON_OBJECT('name', 'COMPLETED', 'terminal', TRUE),
JSON_OBJECT('name', 'CANCELLED', 'terminal', TRUE)
)
),
JSON_OBJECT(
'initialState',
'DRAFT',
'states',
JSON_OBJECT(
'DRAFT',
JSON_OBJECT(
'initial',
TRUE,
'terminal',
FALSE,
'transitions',
JSON_OBJECT(
'START',
JSON_OBJECT('to', 'ROUTING', 'events', JSON_ARRAY())
)
),
'ROUTING',
JSON_OBJECT(
'initial',
FALSE,
'terminal',
FALSE,
'transitions',
JSON_OBJECT(
'COMPLETE',
JSON_OBJECT('to', 'COMPLETED', 'events', JSON_ARRAY()),
'FORCE_CLOSE',
JSON_OBJECT('to', 'CANCELLED', 'events', JSON_ARRAY())
)
),
'COMPLETED',
JSON_OBJECT(
'initial',
FALSE,
'terminal',
TRUE,
'transitions',
JSON_OBJECT()
),
'CANCELLED',
JSON_OBJECT(
'initial',
FALSE,
'terminal',
TRUE,
'transitions',
JSON_OBJECT()
)
)
),
TRUE,
NOW(),
NOW()
);
@@ -1155,10 +1155,24 @@ VALUES (
'ลบ AiAuditLog เดี่ยวโดย publicId (Superadmin Only)',
'ai',
1
),
(
187,
'rag.query',
'ใช้งาน RAG Q&A เพื่อค้นหาคำตอบจากเอกสาร',
'rag',
1
),
(
188,
'rag.manage',
'จัดการ RAG ingestion, re-index, ลบ vectors',
'rag',
1
);
-- Role 1: Superadmin — ได้รับทุก permission โดยอัตโนมัติผ่าน SELECT-all pattern (บรรทัด 825-829)
-- Role 2: Org Admin — ai.suggest, ai.rag_query, ai.migration_manage, ai.read_analytics
-- Role 2: Org Admin — ai.suggest, ai.rag_query, ai.migration_manage, ai.read_analytics, rag.query
INSERT IGNORE INTO role_permissions (role_id, permission_id)
VALUES (2, 181),
-- ai.suggest
@@ -1166,10 +1180,12 @@ VALUES (2, 181),
-- ai.rag_query
(2, 183),
-- ai.migration_manage
(2, 185);
(2, 185),
-- ai.read_analytics
(2, 187);
-- ai.read_analytics
-- Role 3: Document Control — ai.suggest, ai.rag_query, ai.migration_manage, ai.read_analytics
-- rag.query
-- Role 3: Document Control — ai.suggest, ai.rag_query, ai.migration_manage, ai.read_analytics, rag.query
INSERT IGNORE INTO role_permissions (role_id, permission_id)
VALUES (3, 181),
-- ai.suggest
@@ -1177,8 +1193,22 @@ VALUES (3, 181),
-- ai.rag_query
(3, 183),
-- ai.migration_manage
(3, 185);
(3, 185),
-- ai.read_analytics
(3, 187);
-- ai.read_analytics
-- rag.query
-- rag.manage (188) — Superadmin เท่านั้น, ไม่ grant ให้ Role อื่น
-- ai.migration_manage
-- ai.audit_log_delete (184) — Superadmin เท่านั้น, ไม่ grant ให้ Role อื่น
-- ==========================================================
-- 19. RBAC Bulk Permission (Delta 02)
-- ==========================================================
-- Grant user.manage_assignments to ADMIN, Org Admin, DC, Document Control roles
INSERT IGNORE INTO role_permissions (role_id, permission_id)
SELECT r.role_id,
p.permission_id
FROM roles r,
permissions p
WHERE r.role_name IN ('ADMIN', 'Org Admin', 'DC', 'Document Control')
AND p.permission_name = 'user.manage_assignments';
+7 -10
View File
@@ -1,7 +1,7 @@
# Architecture Decision Records (ADRs)
**Version:** 1.9.1
**Last Updated:** 2026-05-14
**Version:** 1.9.5
**Last Updated:** 2026-05-18
**Project:** LCBP3-DMS (Laem Chabang Port Phase 3 - Document Management System)
---
@@ -95,6 +95,7 @@ Architecture Decision Records (ADRs) เป็นเอกสารที่บ
| [ADR-020](./ADR-020-ai-intelligence-integration.md) | AI Intelligence Integration Architecture | ❌ Superseded | 2026-04-03 | ถูกแทนที่โดย ADR-023: Unified AI Architecture |
| [ADR-022](./ADR-022-retrieval-augmented-generation.md) | Retrieval-Augmented Generation (RAG) | ❌ Superseded | 2026-04-20 | ถูกแทนที่โดย ADR-023: Unified AI Architecture |
| [ADR-023](./ADR-023-unified-ai-architecture.md) | Unified AI Architecture | ✅ Accepted | 2026-05-14 | สถาปัตยกรรม AI หลักแบบรวมศูนย์ (Boundary, RAG, Workflows และ Isolation) |
| [ADR-023A](./ADR-023A-unified-ai-architecture.md) | AI Model Revision | ✅ Accepted | 2026-05-15 | 2-Model Stack (gemma4:e4b Q8_0 + nomic-embed-text), BullMQ 2-Queue, RAG embed scope, OCR auto-detect |
---
@@ -146,16 +147,12 @@ Architecture Decision Records (ADRs) เป็นเอกสารที่บ
### 9. AI & Data Integration
- **ADR-017:** Ollama Data Migration - (Superseded by ADR-023)
- **ADR-017B:** Smart Document Digitization - (Superseded by ADR-023)
- **ADR-018:** AI Boundary Policy - (Superseded by ADR-023)
- **ADR-020:** AI Intelligence Integration - (Superseded by ADR-023)
- **ADR-022:** Retrieval-Augmented Generation - (Superseded by ADR-023)
- **ADR-023:** Unified AI Architecture - สถาปัตยกรรม AI หลักของระบบ ครอบคลุม Boundary, Workflows, RAG และ Hardware Isolation
- **ADR-023A:** AI Model Revision - 2-Model Stack (gemma4:e4b Q8_0 + nomic-embed-text), BullMQ 2-Queue, OCR auto-detect
---
## 📖 How to Read ADRs
## How to Read ADRs
### ADR Structure
@@ -379,8 +376,8 @@ graph TB
---
**Version:** 1.9.1 (Consolidated AI ADRs into ADR-023)
**Last Review:** 2026-05-14
**Version:** 1.9.5 (Added ADR-023A AI Model Revision)
**Last Review:** 2026-05-18
**Next Review:** 2026-10-10
---
+5
View File
@@ -16,7 +16,12 @@
## ตัวอย่างงานที่อยู่ในโฟลเดอร์นี้
- `201-transmittals-circulation` - Transmittals + Circulation Integration
- `202-adr-021-integrated-workflow-conte` - ADR-021 Integrated Workflow Context
- `203-unified-workflow-engine` - Unified Workflow Engine
- `204-rfa-approval-refactor` - RFA Approval Refactor
- `224-intent-classification` - AI Intent Classification
- `225-ai-tool-layer-architecture` - AI Tool Layer Architecture
- `226-document-chat-ui-pattern` - Document Chat UI Pattern
## การตั้งชื่อโฟลเดอร์
+6 -4
View File
@@ -1,7 +1,7 @@
# 📚 LCBP3-DMS Specifications Directory
**Version:** 1.9.0 (Global Standards & Agent Sync)
**Last Updated:** 2026-05-13
**Version:** 1.9.2 (AI Model Revision & Hybrid Staging)
**Last Updated:** 2026-05-18
**Project:** LCBP3-DMS (Laem Chabang Port Phase 3 - Document Management System)
**Status:** ✅ Production Ready — 10/10 Documentation Gaps Closed • Hybrid Specs Structure Applied
@@ -80,10 +80,12 @@ specs/
│ ├── 05-07-hybrid-uuid-implementation-plan.md # ADR-019 Implementation Guide
│ └── README.md # ภาพรวมเป้าหมายงาน Engineering
├── 06-Decision-Records/ # Architecture Decision Records (17 + Patch + ADR-019)
├── 06-Decision-Records/ # Architecture Decision Records (23 ADRs)
│ ├── ADR-001 to ADR-017... # ไฟล์อธิบายสถาปัตยกรรม (ADR)
│ ├── ADR-018-ai-boundary.md # ★ Patch 1.8.1: AI/Ollama Isolation Policy
│ ├── ADR-018-ai-boundary.md # ★ Patch 1.8.1: AI/Ollama Isolation Policy (Superseded by ADR-023)
│ ├── ADR-019-hybrid-identifier-strategy.md # ★ Hybrid ID: INT PK + UUIDv7 Public API
│ ├── ADR-023-unified-ai-architecture.md # ★ Unified AI Architecture (Consolidates ADR-017/017B/018/020/022)
│ ├── ADR-023A-unified-ai-architecture.md # ★ AI Model Revision: 2-Model Stack + BullMQ 2-Queue
│ └── README.md # รายชื่อ ADR ทั้งหมดพร้อมสถานะและวันที่
├── 100-Infrastructures/ # Feature Work: Infrastructure (Deployment, Monitoring, Docker Compose, Network)