260322:1648 Correct Coresspondence / Doing RFA / Correct CI
This commit is contained in:
@@ -5,11 +5,13 @@
|
||||
**Version:** 1.8.0
|
||||
**Decision Makers:** Development Team, DevOps Engineer
|
||||
**Related Documents:**
|
||||
|
||||
- [Legacy Data Migration Plan](../03-Data-and-Storage/03-04-legacy-data-migration.md)
|
||||
- [n8n Migration Setup Guide](../03-Data-and-Storage/03-05-n8n-migration-setup-guide.md)
|
||||
- [Software Architecture](../02-Architecture/02-02-software-architecture.md)
|
||||
- [Data Dictionary](../03-Data-and-Storage/03-01-data-dictionary.md)
|
||||
> **Note:** ADR-017 is clarified and hardened by ADR-018 regarding AI physical isolation. Category Enum system-driven, Idempotency Contract, Duplicate Handling Clarification, Storage Enforcement, Audit Log Enhancement, Review Queue Integration, Revision Drift Protection, Execution Time, Encoding Normalization, Security Hardening, Orchestrator on QNAP, AI Physical Isolation (Desktop Desk-5439).
|
||||
> **Note:** ADR-017 is clarified and hardened by ADR-018 regarding AI physical isolation. Category Enum system-driven, Idempotency Contract, Duplicate Handling Clarification, Storage Enforcement, Audit Log Enhancement, Review Queue Integration, Revision Drift Protection, Execution Time, Encoding Normalization, Security Hardening, Orchestrator on QNAP, AI Physical Isolation (Desktop Desk-5439).
|
||||
|
||||
---
|
||||
|
||||
## Context and Problem Statement
|
||||
@@ -19,6 +21,7 @@
|
||||
ความท้าทายหลักคือ **Data Integrity และความถูกต้องของ Metadata** เนื่องจากข้อมูลเก่ามีโอกาสเกิด Human Error เราจึงต้องการ AI ช่วย Validate ก่อนนำเข้า
|
||||
|
||||
การส่งข้อมูลขึ้น Cloud AI Provider มีปัญหา 2 ประการ:
|
||||
|
||||
1. **Data Privacy:** เอกสารก่อสร้างท่าเรือเป็นความลับ ห้ามออกนอกเครือข่าย
|
||||
2. **Cost:** ~$0.01–0.03 ต่อ Record = อาจสูงถึง $600 สำหรับ 20,000 records
|
||||
|
||||
@@ -44,6 +47,7 @@
|
||||
**Pros:** ไม่ต้องจัดหา Hardware เพิ่ม, AI ฉลาดสูง
|
||||
|
||||
**Cons:**
|
||||
|
||||
- ❌ ผิดนโยบาย Data Privacy
|
||||
- ❌ ค่าใช้จ่ายสูง (~$600)
|
||||
- ❌ Code สกปรก ปะปนกับ Source Code หลัก
|
||||
@@ -53,12 +57,14 @@
|
||||
**Pros:** เร็ว ไม่มีค่าใช้จ่าย
|
||||
|
||||
**Cons:**
|
||||
|
||||
- ❌ ความแม่นยำต่ำ ตรวจได้แค่ Format
|
||||
- ❌ ต้องใช้ Manual Review จำนวนมาก
|
||||
|
||||
### Option 3: Local AI Model (Ollama) + n8n ⭐ (Selected)
|
||||
|
||||
**Pros:**
|
||||
|
||||
- ✅ Privacy Guaranteed
|
||||
- ✅ Zero Cost
|
||||
- ✅ Clean Architecture
|
||||
@@ -67,6 +73,7 @@
|
||||
- ✅ Structured Output ด้วย JSON Schema
|
||||
|
||||
**Cons:**
|
||||
|
||||
- ❌ ต้องเปิด Desktop ทิ้งไว้ดูแล GPU Temperature
|
||||
- ❌ Model เล็กอาจแม่นน้อยกว่า Cloud AI → ต้องมี Human Review Queue
|
||||
|
||||
@@ -82,19 +89,19 @@
|
||||
|
||||
## Implementation Summary
|
||||
|
||||
| Component | รายละเอียด |
|
||||
| ---------------------- | ------------------------------------------------------------------------------- |
|
||||
| Migration Orchestrator | n8n (Docker บน QNAP NAS) |
|
||||
| AI Model Primary | Ollama `llama3.2:3b` (Validation, Summarization, Tagging) |
|
||||
| AI Model Fallback | Ollama `mistral:7b-instruct-q4_K_M` |
|
||||
| Hardware | QNAP NAS (Orchestrator) + Desktop Desk-5439 (AI Processing, RTX 2060 SUPER 8GB) |
|
||||
| DB Lookup (n8n) | n8n ทำการ Query `project_id`, `organization_id` และดึง `Tags` จาก DB ให้ AI |
|
||||
| Component | รายละเอียด |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| Migration Orchestrator | n8n (Docker บน QNAP NAS) |
|
||||
| AI Model Primary | Ollama `llama3.2:3b` (Validation, Summarization, Tagging) |
|
||||
| AI Model Fallback | Ollama `mistral:7b-instruct-q4_K_M` |
|
||||
| Hardware | QNAP NAS (Orchestrator) + Desktop Desk-5439 (AI Processing, RTX 2060 SUPER 8GB) |
|
||||
| DB Lookup (n8n) | n8n ทำการ Query `project_id`, `organization_id` และดึง `Tags` จาก DB ให้ AI |
|
||||
| Data Ingestion | 1. Staging ลง `migration_review_queue` -> 2. กดยืนยันผ่าน Frontend Management UI -> 3. Final Commit ผ่าน API |
|
||||
| Concurrency (n8n) | Sequential — Batch Size 50-100 ป้องกัน DB Connection Overload |
|
||||
| Checkpoint | MariaDB `migration_progress` และการใช้ `ON DUPLICATE KEY UPDATE` ใน Staging |
|
||||
| Fallback | Auto-switch Model เมื่อ Error ≥ Threshold |
|
||||
| Storage | Two-Phase Storage: 1. `POST /api/storage/upload` (Temp) -> 2. Commit ภายหลัง |
|
||||
| Expected Runtime | ~16.6 ชั่วโมง (~3–4 คืน) สำหรับ 20,000 records |
|
||||
| Concurrency (n8n) | Sequential — Batch Size 50-100 ป้องกัน DB Connection Overload |
|
||||
| Checkpoint | MariaDB `migration_progress` และการใช้ `ON DUPLICATE KEY UPDATE` ใน Staging |
|
||||
| Fallback | Auto-switch Model เมื่อ Error ≥ Threshold |
|
||||
| Storage | Two-Phase Storage: 1. `POST /api/storage/upload` (Temp) -> 2. Commit ภายหลัง |
|
||||
| Expected Runtime | ~16.6 ชั่วโมง (~3–4 คืน) สำหรับ 20,000 records |
|
||||
|
||||
---
|
||||
|
||||
@@ -115,14 +122,14 @@
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | คำอธิบาย |
|
||||
| -------------------- | ------------------------- | --------------------------- |
|
||||
| `is_valid` | boolean | เอกสารผ่านการตรวจสอบหรือไม่ (เปรียบเทียบ subject vs pdf) |
|
||||
| `confidence` | float (0.0–1.0) | ความมั่นใจของ AI |
|
||||
| `suggested_category` | string (enum จาก Backend) | หมวดหมู่ที่ AI แนะนำ |
|
||||
| `detected_issues` | string[] | รายการปัญหา (array ว่างถ้าไม่มี) |
|
||||
| `suggested_title` | string \| null | Title ที่แก้ไขแล้ว หรือ null |
|
||||
| `summary` | string | สรุปเนื้อหา 4-5 ประโยค สำหรับใส่ใน `body` |
|
||||
| Field | Type | คำอธิบาย |
|
||||
| -------------------- | ------------------------- | ---------------------------------------------------------------- |
|
||||
| `is_valid` | boolean | เอกสารผ่านการตรวจสอบหรือไม่ (เปรียบเทียบ subject vs pdf) |
|
||||
| `confidence` | float (0.0–1.0) | ความมั่นใจของ AI |
|
||||
| `suggested_category` | string (enum จาก Backend) | หมวดหมู่ที่ AI แนะนำ |
|
||||
| `detected_issues` | string[] | รายการปัญหา (array ว่างถ้าไม่มี) |
|
||||
| `suggested_title` | string \| null | Title ที่แก้ไขแล้ว หรือ null |
|
||||
| `summary` | string | สรุปเนื้อหา 4-5 ประโยค สำหรับใส่ใน `body` |
|
||||
| `suggested_tags` | array of objects | รายการ Tags ที่จับคู่ได้ หรือ แนะนำให้สร้างใหม่ (`is_new: true`) |
|
||||
|
||||
> ⚠️ **Patch:** `suggested_category` ต้องตรงกับ System Enum จาก `GET /api/meta/categories` เท่านั้น — ห้าม hardcode Category List ใน Prompt
|
||||
@@ -133,13 +140,13 @@
|
||||
|
||||
**ข้อมูลทุกชุดจาก n8n จะต้องถูกส่งเข้าตาราง `migration_review_queue` เสมอ** โดยจัดสถานะเบื้องต้นตาม Confidence:
|
||||
|
||||
| ระดับ Confidence | สถานะใน Review Queue |
|
||||
| ------------------------------- | --------------------------------------- |
|
||||
| `>= 0.85` และ `is_valid = true` | `PENDING` (พร้อมให้ Admin เลือก Batch Import) |
|
||||
| `0.60–0.84` | `PENDING` (ไฮไลต์แจ้งให้ Admin ตรวจสอบข้อมูลก่อน) |
|
||||
| `< 0.60` หรือ `is_valid = false` | `REJECTED` (รอให้ Admin แก้ไขข้อมูล Manual) |
|
||||
| AI Parse Error | ส่งไป Error Log + Trigger Fallback Logic |
|
||||
| Revision Drift | `PENDING` พร้อมระบุ reason: "Revision drift" |
|
||||
| ระดับ Confidence | สถานะใน Review Queue |
|
||||
| -------------------------------- | ------------------------------------------------- |
|
||||
| `>= 0.85` และ `is_valid = true` | `PENDING` (พร้อมให้ Admin เลือก Batch Import) |
|
||||
| `0.60–0.84` | `PENDING` (ไฮไลต์แจ้งให้ Admin ตรวจสอบข้อมูลก่อน) |
|
||||
| `< 0.60` หรือ `is_valid = false` | `REJECTED` (รอให้ Admin แก้ไขข้อมูล Manual) |
|
||||
| AI Parse Error | ส่งไป Error Log + Trigger Fallback Logic |
|
||||
| Revision Drift | `PENDING` พร้อมระบุ reason: "Revision drift" |
|
||||
|
||||
> ⚠️ **Tag Review:** ข้อมูลใดที่มี `is_new: true` ใน `suggested_tags` จะถูกบังคับให้ Admin ตรวจสอบบน Frontend UI ก่อน เพื่อป้องกัน AI สร้าง Tags ขยะซ้ำซ้อน
|
||||
|
||||
@@ -148,11 +155,13 @@
|
||||
## Idempotency Contract
|
||||
|
||||
**HTTP Header ที่ต้องส่งทุก Request:**
|
||||
|
||||
```
|
||||
Idempotency-Key: <document_number>:<batch_id>
|
||||
```
|
||||
|
||||
**Backend Logic:**
|
||||
|
||||
```
|
||||
IF idempotency_key EXISTS in import_transactions → RETURN HTTP 200 (no action)
|
||||
ELSE → Process normally → INSERT import_transactions → RETURN HTTP 201
|
||||
@@ -167,6 +176,7 @@ ELSE → Process normally → INSERT import_transactions → RETURN HTTP 201
|
||||
Bypass Duplicate **Validation Error**
|
||||
|
||||
Hard Rules:
|
||||
|
||||
- ❌ Migration Token ไม่สามารถ Overwrite Revision ที่มีอยู่
|
||||
- ❌ Migration Token ไม่สามารถ Delete Revision ก่อนหน้า
|
||||
- ✅ Migration Token trigger Revision increment logic ตามปกติเท่านั้น
|
||||
@@ -176,6 +186,7 @@ Hard Rules:
|
||||
## Storage Governance (Two-Phase Storage)
|
||||
|
||||
**ข้อห้าม:**
|
||||
|
||||
```
|
||||
❌ mv /data/dms/staging_ai/TCC-COR-0001.pdf /final/path/...
|
||||
```
|
||||
@@ -183,6 +194,7 @@ Hard Rules:
|
||||
**ข้อบังคับ (Two-Phase Strategy):**
|
||||
|
||||
**Phase 1: Temp Upload (โดย n8n)**
|
||||
|
||||
```
|
||||
✅ POST /api/storage/upload
|
||||
(Upload ไฟล์ PDF ได้ผลลัพธ์เป็น attachment_id เช่น 1024)
|
||||
@@ -190,12 +202,14 @@ Hard Rules:
|
||||
```
|
||||
|
||||
**Phase 2: Final Commit (โดย Frontend UI -> Backend API)**
|
||||
|
||||
```
|
||||
✅ POST /api/migration/commit_batch
|
||||
body: { queue_ids: [1, 2, 3] }
|
||||
```
|
||||
|
||||
Backend จะทำหน้าที่:
|
||||
|
||||
1. อ่านข้อมูลจาก `migration_review_queue` ซึ่งมี `temp_attachment_id` อยู่
|
||||
2. นำ `temp_attachment_id` ไปเชื่อมกับเอกสาร (Link to `correspondence_attachments`)
|
||||
3. เปลี่ยนสถานะอัพเดต `is_temporary = FALSE`
|
||||
@@ -206,8 +220,8 @@ Backend จะทำหน้าที่:
|
||||
## Review Queue Contract & Frontend UI
|
||||
|
||||
- `migration_review_queue` เป็น **Staging Table หลัก** (ไม่ auto-ingest ข้ามขั้นตอนนี้)
|
||||
- ห้ามสร้าง Correspondence record จนกว่า Admin จะสั่ง Execute การ Import จากหน้าจอ
|
||||
- **Approval Flow:**
|
||||
- ห้ามสร้าง Correspondence record จนกว่า Admin จะสั่ง Execute การ Import จากหน้าจอ
|
||||
- **Approval Flow:**
|
||||
1. N8N Insert เข้า `migration_review_queue` (พร้อม `temp_attachment_id`)
|
||||
2. Admin Review บน Frontend UI (ให้ความสำคัญกับการเช็ค `is_new: true` Tags)
|
||||
3. Admin เลือก Rows แล้วกด **"Execute Import"**
|
||||
@@ -218,6 +232,7 @@ Backend จะทำหน้าที่:
|
||||
## Revision Drift Protection
|
||||
|
||||
ถ้า Excel มี revision column:
|
||||
|
||||
```
|
||||
IF excel_revision != current_db_revision + 1
|
||||
→ ROUTE ไป Review Queue พร้อม reason: "Revision drift"
|
||||
@@ -227,20 +242,21 @@ IF excel_revision != current_db_revision + 1
|
||||
|
||||
## Execution Time Estimate
|
||||
|
||||
| Parameter | ค่า |
|
||||
| -------------------- | ---------------------------- |
|
||||
| Delay ระหว่าง Request | 2 วินาที |
|
||||
| Inference Time (avg) | ~1 วินาที |
|
||||
| เวลาต่อ Record | ~3 วินาที |
|
||||
| จำนวน Record | 20,000 |
|
||||
| เวลารวม | ~60,000 วินาที (~16.6 ชั่วโมง) |
|
||||
| **จำนวนคืนที่ต้องใช้** | **~3–4 คืน** (รัน 22:00–06:00) |
|
||||
| Parameter | ค่า |
|
||||
| ---------------------- | ------------------------------ |
|
||||
| Delay ระหว่าง Request | 2 วินาที |
|
||||
| Inference Time (avg) | ~1 วินาที |
|
||||
| เวลาต่อ Record | ~3 วินาที |
|
||||
| จำนวน Record | 20,000 |
|
||||
| เวลารวม | ~60,000 วินาที (~16.6 ชั่วโมง) |
|
||||
| **จำนวนคืนที่ต้องใช้** | **~3–4 คืน** (รัน 22:00–06:00) |
|
||||
|
||||
---
|
||||
|
||||
## Encoding Normalization
|
||||
|
||||
ก่อน Ingestion ทุกครั้ง:
|
||||
|
||||
- Excel data → Convert เป็น **UTF-8**
|
||||
- Filename → Normalize เป็น **NFC UTF-8** ป้องกันปัญหาภาษาไทยเพี้ยนข้าม OS
|
||||
|
||||
@@ -274,7 +290,7 @@ IF excel_revision != current_db_revision + 1
|
||||
|
||||
### 🟢 A. Infrastructure Validation
|
||||
|
||||
| Check | Expected | ✅ |
|
||||
| Check | Expected | ✅ |
|
||||
| ---------------------------- | ------------- | --- |
|
||||
| Ollama `/api/tags` reachable | HTTP 200 | |
|
||||
| Backend `/health` OK | HTTP 200 | |
|
||||
@@ -286,7 +302,7 @@ IF excel_revision != current_db_revision + 1
|
||||
|
||||
### 🟢 B. Security Validation
|
||||
|
||||
| Check | Expected | ✅ |
|
||||
| Check | Expected | ✅ |
|
||||
| -------------------------------------- | -------- | --- |
|
||||
| Migration Token expiry ≤ 7 days | Verified | |
|
||||
| Token IP Whitelist = NAS IP only | Verified | |
|
||||
@@ -298,7 +314,7 @@ IF excel_revision != current_db_revision + 1
|
||||
|
||||
### 🟢 C. Data Integrity Validation
|
||||
|
||||
| Check | Expected | ✅ |
|
||||
| Check | Expected | ✅ |
|
||||
| ---------------------------------------------- | -------------- | --- |
|
||||
| Enum fetched from `/api/meta/categories` | Not hardcoded | |
|
||||
| `Idempotency-Key` header enforced | Verified | |
|
||||
@@ -309,7 +325,7 @@ IF excel_revision != current_db_revision + 1
|
||||
|
||||
### 🟢 D. Workflow Validation (Dry Run 20 Records)
|
||||
|
||||
| Check | Expected | ✅ |
|
||||
| Check | Expected | ✅ |
|
||||
| ---------------------------------------- | ------------ | --- |
|
||||
| JSON parse success rate | > 95% | |
|
||||
| Confidence distribution reasonable | Mean 0.7–0.9 | |
|
||||
@@ -321,7 +337,7 @@ IF excel_revision != current_db_revision + 1
|
||||
|
||||
### 🟢 E. Performance Validation
|
||||
|
||||
| Check | Expected | ✅ |
|
||||
| Check | Expected | ✅ |
|
||||
| ------------------------------- | -------- | --- |
|
||||
| 10 records processed < 1 minute | Verified | |
|
||||
| GPU temp < 80°C | Verified | |
|
||||
@@ -330,7 +346,7 @@ IF excel_revision != current_db_revision + 1
|
||||
|
||||
### 🟢 F. Rollback Test (Mandatory)
|
||||
|
||||
| Check | Expected | ✅ |
|
||||
| Check | Expected | ✅ |
|
||||
| ------------------------------------ | ----------------- | --- |
|
||||
| Disable token works | is_active = false | |
|
||||
| Delete `SYSTEM_IMPORT` records works | COUNT = 0 | |
|
||||
@@ -343,12 +359,14 @@ IF excel_revision != current_db_revision + 1
|
||||
## GO / NO-GO Criteria
|
||||
|
||||
**GO ถ้า:**
|
||||
|
||||
- A, B, C ทุก Check = PASS
|
||||
- Dry run error rate < 10%
|
||||
- JSON parse failure < 5%
|
||||
- Revision conflict < 3%
|
||||
|
||||
**NO-GO ถ้า:**
|
||||
|
||||
- Enum mismatch (Category hardcoded)
|
||||
- Idempotency ไม่ได้ implement
|
||||
- Storage bypass (move file โดยตรง)
|
||||
@@ -358,8 +376,8 @@ IF excel_revision != current_db_revision + 1
|
||||
|
||||
## Final Architectural Assessment
|
||||
|
||||
| Area | Status |
|
||||
| ------------------ | ------------------------------------------------ |
|
||||
| Area | Status |
|
||||
| ------------------ | ------------------------------------------------- |
|
||||
| ADR Compliance | ✅ Fully aligned |
|
||||
| Security | ✅ Hardened (IP Whitelist, Rate Limit, Docker) |
|
||||
| Data Integrity | ✅ Controlled (Idempotency, Revision Drift, Enum) |
|
||||
@@ -368,4 +386,4 @@ IF excel_revision != current_db_revision + 1
|
||||
|
||||
---
|
||||
|
||||
*สำหรับขั้นตอนปฏิบัติงานแบบละเอียด ดูที่ `03-04-legacy-data-migration.md` และ `03-05-n8n-migration-setup-guide.md`*
|
||||
_สำหรับขั้นตอนปฏิบัติงานแบบละเอียด ดูที่ `03-04-legacy-data-migration.md` และ `03-05-n8n-migration-setup-guide.md`_
|
||||
|
||||
Reference in New Issue
Block a user