Files
lcbp3/specs/06-Decision-Records/ADR-017-ollama-data-migration.md
admin 276d06e950
All checks were successful
Build and Deploy / deploy (push) Successful in 2m49s
260228:1412 20260228: setup n8n
2026-02-28 14:12:48 +07:00

347 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-017: Ollama Data Migration Architecture
**Status:** Accepted
**Date:** 2026-02-26
**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).
---
## Context and Problem Statement
โครงการ LCBP3-DMS มีความจำเป็นต้องนำเข้าเอกสาร PDF เก่าจำนวนกว่า 20,000 ฉบับ พร้อม Metadata ใน Excel เข้าสู่ระบบใหม่
ความท้าทายหลักคือ **Data Integrity และความถูกต้องของ Metadata** เนื่องจากข้อมูลเก่ามีโอกาสเกิด Human Error เราจึงต้องการ AI ช่วย Validate ก่อนนำเข้า
การส่งข้อมูลขึ้น Cloud AI Provider มีปัญหา 2 ประการ:
1. **Data Privacy:** เอกสารก่อสร้างท่าเรือเป็นความลับ ห้ามออกนอกเครือข่าย
2. **Cost:** ~$0.010.03 ต่อ Record = อาจสูงถึง $600 สำหรับ 20,000 records
---
## Decision Drivers
- **Security & Privacy:** ประมวลผลภายในเครือข่ายองค์กร (On-Premise) เท่านั้น
- **Cost Effectiveness:** ไม่เสียค่า Pay-per-use
- **Performance:** ประมวลผลได้ในระยะเวลาที่จำกัด (~34 คืน)
- **Maintainability:** แยก Migration ออกจาก Core Application
- **Recoverability:** Rollback ได้สมบูรณ์
- **Resilience:** รองรับ Checkpoint/Resume และ Hardware Failure
- **Data Integrity:** Idempotency, Revision Drift Protection, Enum Enforcement
- **Storage Governance:** ทุก File Move ต้องผ่าน StorageService
---
## Considered Options
### Option 1: NestJS Custom Script + Public AI API
**Pros:** ไม่ต้องจัดหา Hardware เพิ่ม, AI ฉลาดสูง
**Cons:**
- ❌ ผิดนโยบาย Data Privacy
- ❌ ค่าใช้จ่ายสูง (~$600)
- ❌ Code สกปรก ปะปนกับ Source Code หลัก
### Option 2: Pure Scripting (No AI)
**Pros:** เร็ว ไม่มีค่าใช้จ่าย
**Cons:**
- ❌ ความแม่นยำต่ำ ตรวจได้แค่ Format
- ❌ ต้องใช้ Manual Review จำนวนมาก
### Option 3: Local AI Model (Ollama) + n8n ⭐ (Selected)
**Pros:**
- ✅ Privacy Guaranteed
- ✅ Zero Cost
- ✅ Clean Architecture
- ✅ Visual & Debuggable
- ✅ Resilient (Checkpoint/Resume)
- ✅ Structured Output ด้วย JSON Schema
**Cons:**
- ❌ ต้องเปิด Desktop ทิ้งไว้ดูแล GPU Temperature
- ❌ Model เล็กอาจแม่นน้อยกว่า Cloud AI → ต้องมี Human Review Queue
---
## Decision Outcome
**Chosen Option:** Option 3 — Local AI Model (Ollama) + n8n
**Rationale:** ประยุกต์ใช้ Hardware ที่มีอยู่ โดยไม่ขัดหลัก Privacy และ Security ของโครงการ n8n ช่วยลด Risk ที่จะกระทบ Core Backend และรองรับ Checkpoint/Resume ได้ดีกว่าการเขียน Script เอง
---
## Implementation Summary
| Component | รายละเอียด |
| ---------------------- | ------------------------------------------------------------------------------- |
| Migration Orchestrator | n8n (Docker บน QNAP NAS) |
| AI Model Primary | Ollama `llama3.2:3b` |
| AI Model Fallback | Ollama `mistral:7b-instruct-q4_K_M` |
| Hardware | QNAP NAS (Orchestrator) + Desktop Desk-5439 (AI Processing, RTX 2060 SUPER 8GB) |
| Data Ingestion | RESTful API + Migration Token (7 วัน) + Idempotency-Key Header |
| Concurrency | Sequential — 1 Request/ครั้ง, Delay 2 วินาที |
| Checkpoint | MariaDB `migration_progress` |
| Fallback | Auto-switch Model เมื่อ Error ≥ Threshold |
| Storage | Backend StorageService เท่านั้น — ห้าม move file โดยตรง |
| Expected Runtime | ~16.6 ชั่วโมง (~34 คืน) สำหรับ 20,000 records |
---
## AI Output Contract (JSON Schema)
```json
{
"is_valid": true,
"confidence": 0.92,
"suggested_category": "Correspondence",
"detected_issues": [],
"suggested_title": null
}
```
| Field | Type | คำอธิบาย |
| -------------------- | ------------------------- | --------------------------- |
| `is_valid` | boolean | เอกสารผ่านการตรวจสอบหรือไม่ |
| `confidence` | float (0.01.0) | ความมั่นใจของ AI |
| `suggested_category` | string (enum จาก Backend) | หมวดหมู่ที่ AI แนะนำ |
| `detected_issues` | string[] | รายการปัญหา (array ว่างถ้าไม่มี) |
| `suggested_title` | string \| null | Title ที่แก้ไขแล้ว หรือ null |
> ⚠️ **Patch:** `suggested_category` ต้องตรงกับ System Enum จาก `GET /api/meta/categories` เท่านั้น — ห้าม hardcode Category List ใน Prompt
---
## Confidence Threshold Policy
| ระดับ Confidence | การดำเนินการ |
| ------------------------------- | --------------------------------------- |
| `>= 0.85` และ `is_valid = true` | Auto Ingest เข้าระบบ |
| `0.600.84` | ส่งไป Human Review Queue |
| `< 0.60` หรือ `is_valid = false` | ส่งไป Reject Log รอ Manual Fix |
| AI Parse Error | ส่งไป Error Log + Trigger Fallback Logic |
| Revision Drift | ส่งไป Review Queue พร้อม reason |
---
## 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
```
ป้องกัน Revision ซ้ำกรณี n8n Retry หรือ Network Error
---
## Duplicate Handling Clarification
Bypass Duplicate **Validation Error**
Hard Rules:
- ❌ Migration Token ไม่สามารถ Overwrite Revision ที่มีอยู่
- ❌ Migration Token ไม่สามารถ Delete Revision ก่อนหน้า
- ✅ Migration Token trigger Revision increment logic ตามปกติเท่านั้น
---
## Storage Governance (Patch)
**ข้อห้าม:**
```
❌ mv /data/dms/staging_ai/TCC-COR-0001.pdf /final/path/...
```
**ข้อบังคับ:**
```
✅ POST /api/correspondences/import
body: { source_file_path: "/data/dms/staging_ai/TCC-COR-0001.pdf", ... }
```
Backend จะ:
1. Generate UUID
2. Enforce path strategy: `/data/dms/uploads/YYYY/MM/{uuid}.pdf`
3. Move file atomically ผ่าน StorageService
4. Create revision folder ถ้าจำเป็น
---
## Review Queue Contract
- `migration_review_queue` เป็น **Temporary Table เท่านั้น** — ไม่ใช่ Business Schema
- ห้ามสร้าง Correspondence record จนกว่า Admin จะ Approve
- Approval Flow: `Review → Admin Approve → POST /api/correspondences/import`
---
## Revision Drift Protection
ถ้า Excel มี revision column:
```
IF excel_revision != current_db_revision + 1
→ ROUTE ไป Review Queue พร้อม reason: "Revision drift"
```
---
## Execution Time Estimate
| Parameter | ค่า |
| -------------------- | ---------------------------- |
| Delay ระหว่าง Request | 2 วินาที |
| Inference Time (avg) | ~1 วินาที |
| เวลาต่อ Record | ~3 วินาที |
| จำนวน Record | 20,000 |
| เวลารวม | ~60,000 วินาที (~16.6 ชั่วโมง) |
| **จำนวนคืนที่ต้องใช้** | **~34 คืน** (รัน 22:0006:00) |
---
## Encoding Normalization
ก่อน Ingestion ทุกครั้ง:
- Excel data → Convert เป็น **UTF-8**
- Filename → Normalize เป็น **NFC UTF-8** ป้องกันปัญหาภาษาไทยเพี้ยนข้าม OS
---
## Security Constraints
1. Migration Token อายุ **≤ 7 วัน** — Revoke ทันทีหลัง Migration
2. Token Bypass ได้เฉพาะ: Virus Scan, Duplicate Validation Error, Created-by
3. Token **ไม่มีสิทธิ์** ลบหรือ Overwrite Record เดิม
4. ทุก Request บันทึก Audit Log: `action=IMPORT, source=MIGRATION, created_by=SYSTEM_IMPORT`
5. **IP Whitelist:** ใช้ได้เฉพาะจาก `<NAS_IP>`
6. **Nginx Rate Limit:** `limit_req zone=migration burst=5 nodelay`
7. **Docker Hardening:** `mem_limit: 2g`, log rotation `max-size: 10m, max-file: 3`
---
## Rollback Strategy
1. Disable Migration Token ใน DB ทันที
2. ลบ Records ทั้งหมด `created_by = 'SYSTEM_IMPORT'` ผ่าน Transaction SQL (รวม `import_transactions`)
3. ย้ายไฟล์ PDF กลับ `migration_temp/`
4. Reset `migration_progress` และ `migration_fallback_state`
5. วิเคราะห์ Root Cause ก่อนรันใหม่
รายละเอียดดูที่ `03-04-legacy-data-migration.md` หัวข้อ 4
---
## Architecture Validation Checklist (GO-LIVE GATE)
### 🟢 A. Infrastructure Validation
| Check | Expected | ✅ |
| ---------------------------- | ------------- | --- |
| Ollama `/api/tags` reachable | HTTP 200 | |
| Backend `/health` OK | HTTP 200 | |
| MariaDB reachable | SELECT 1 | |
| `staging_ai` mounted RO | ls works | |
| `migration_logs` mounted RW | write test OK | |
| GPU VRAM < 70% idle | safe margin | |
| Disk space > 30% free | safe | |
### 🟢 B. Security Validation
| Check | Expected | ✅ |
| -------------------------------------- | -------- | --- |
| Migration Token expiry ≤ 7 days | Verified | |
| Token IP Whitelist = NAS IP only | Verified | |
| Token cannot DELETE records | Verified | |
| Token cannot UPDATE non-import records | Verified | |
| Audit Log records `source=MIGRATION` | Verified | |
| Nginx rate limit configured | Verified | |
| Docker mem_limit = 2g | Verified | |
### 🟢 C. Data Integrity Validation
| Check | Expected | ✅ |
| ---------------------------------------------- | -------------- | --- |
| Enum fetched from `/api/meta/categories` | Not hardcoded | |
| `Idempotency-Key` header enforced | Verified | |
| Duplicate revision test (run same batch twice) | No overwrite | |
| Revision drift test | Sent to Review | |
| Storage path matches Core Storage Spec v1.8.0 | Verified | |
| Encoding normalization NFC UTF-8 | Verified | |
### 🟢 D. Workflow Validation (Dry Run 20 Records)
| Check | Expected | ✅ |
| ---------------------------------------- | ------------ | --- |
| JSON parse success rate | > 95% | |
| Confidence distribution reasonable | Mean 0.70.9 | |
| Checkpoint updates every 10 records | Verified | |
| Fallback model not prematurely triggered | Verified | |
| Reject log written to `migration_logs/` | Verified | |
| Error log written to `migration_logs/` | Verified | |
| Review queue inserts to DB | Verified | |
### 🟢 E. Performance Validation
| Check | Expected | ✅ |
| ------------------------------- | -------- | --- |
| 10 records processed < 1 minute | Verified | |
| GPU temp < 80°C | Verified | |
| No memory leak after 1 hour | Verified | |
| No duplicate revision created | Verified | |
### 🟢 F. Rollback Test (Mandatory)
| Check | Expected | ✅ |
| ------------------------------------ | ----------------- | --- |
| Disable token works | is_active = false | |
| Delete `SYSTEM_IMPORT` records works | COUNT = 0 | |
| `import_transactions` cleared | COUNT = 0 | |
| Checkpoint reset to 0 | Verified | |
| Fallback state reset | Verified | |
---
## 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 โดยตรง)
- Audit log ไม่ครบ
---
## Final Architectural Assessment
| Area | Status |
| ------------------ | ------------------------------------------------ |
| ADR Compliance | ✅ Fully aligned |
| Security | ✅ Hardened (IP Whitelist, Rate Limit, Docker) |
| Data Integrity | ✅ Controlled (Idempotency, Revision Drift, Enum) |
| Storage Governance | ✅ Enforced (StorageService only) |
| Operational Safety | ✅ Production Grade |
---
*สำหรับขั้นตอนปฏิบัติงานแบบละเอียด ดูที่ `03-04-legacy-data-migration.md` และ `03-05-n8n-migration-setup-guide.md`*