690526:0905 ADR-023-229 dynamic prompt #02
CI / CD Pipeline / build (pull_request) Successful in 4m37s
CI / CD Pipeline / deploy (pull_request) Has been skipped

This commit is contained in:
2026-05-26 09:05:34 +07:00
parent fd3bee394c
commit b3d3f6db95
19 changed files with 499 additions and 244 deletions
+19 -19
View File
@@ -126,25 +126,25 @@ Best practice — follow when possible:
## 🚫 Forbidden Actions
| ❌ Forbidden | ✅ Correct Approach |
| ----------------------------------------------- | ------------------------------------------------------- |
| SQL Triggers for business logic | NestJS Service methods |
| `.env` files in production | `docker-compose.yml` environment section |
| TypeORM migration files | Edit schema SQL directly (ADR-009) |
| Inventing table/column names | Verify against `lcbp3-v1.9.0-schema-02-tables.sql` |
| `any` TypeScript type | Proper types / generics |
| `console.log` in committed code | NestJS Logger (backend) / remove (frontend) |
| `req: any` in controllers | `RequestWithUser` typed interface |
| `parseInt()` on UUID values | Use UUID string directly (ADR-019) |
| Exposing INT PK in API responses | UUIDv7 (ADR-019) |
| AI accessing DB/storage directly | AI → DMS API → DB (ADR-023) |
| Direct file operations bypassing StorageService | `StorageService` for all file moves |
| Inline email/notification sending | BullMQ queue job |
| Deploying without Release Gates | Complete `04-08-release-management-policy.md` |
| AI direct cloud API calls | On-premises Ollama only (ADR-023) |
| AI outputs without human validation | Human-in-the-loop validation required (ADR-023) |
| n8n calling Ollama/Qdrant directly | n8n → DMS API → BullMQ → Ollama/Qdrant (ADR-023A) |
| Qdrant query without `projectPublicId` filter | `QdrantService.search(projectPublicId, ...)` (ADR-023A) |
| ❌ Forbidden | ✅ Correct Approach | ⚠️ Why |
| ----------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------- |
| SQL Triggers for business logic | NestJS Service methods | Untestable; bypasses audit log |
| `.env` files in production | `docker-compose.yml` environment section | Secrets exposed in version control |
| TypeORM migration files | Edit schema SQL directly (ADR-009) | Migration drift risk; schema managed via SQL delta |
| Inventing table/column names | Verify against `schema-02-tables.sql` | Schema mismatch causes silent runtime errors |
| `any` TypeScript type | Proper types / generics | Defeats strict mode; hides runtime type errors |
| `console.log` in committed code | NestJS Logger (backend) / remove (frontend) | Log flooding in production; risk of data leakage |
| `req: any` in controllers | `RequestWithUser` typed interface | Type safety lost; auth context unreachable |
| `parseInt()` on UUID values | Use UUID string directly (ADR-019) | `"0195…"` parsed to integer `19` — silently wrong |
| Exposing INT PK in API responses | UUIDv7 `publicId` (ADR-019) | Leaks row count; enables DB enumeration attacks |
| AI accessing DB/storage directly | AI → DMS API → DB (ADR-023/023A) | Bypasses RBAC, audit trail, and validation layer |
| Direct file operations bypassing StorageService | `StorageService` for all file moves | Orphaned files; broken ClamAV scan; no audit trail |
| Inline email/notification sending | BullMQ queue job (ADR-008) | Blocks request thread; no retry on transient failure |
| Deploying without Release Gates | Complete `04-08-release-management-policy.md` | Unverified deploy risks data loss in production |
| AI direct cloud API calls | On-premises Ollama only (ADR-023/023A) | Data privacy violation; no audit control |
| AI outputs without human validation | Human-in-the-loop validation required (ADR-023/023A) | Unvalidated AI metadata corrupts document records |
| n8n calling Ollama/Qdrant directly | n8n → DMS API → BullMQ → Ollama (ADR-023A) | Bypasses audit log, RBAC, and error handling layer |
| Qdrant query without `projectPublicId` filter | `QdrantService.search(projectPublicId, ...)` (ADR-023A) | Cross-project data leak via vector search |
---
+11 -11
View File
@@ -2,17 +2,17 @@
## DMS Glossary
| ✅ Use | ❌ Don't Use |
| ------------------ | ------------------------------------- |
| Correspondence | Letter, Communication, Document |
| RFA | Approval Request, Submit for Approval |
| Transmittal | Delivery Note, Cover Letter |
| Circulation | Distribution, Routing |
| Shop Drawing | Construction Drawing |
| Contract Drawing | Design Drawing, Blueprint |
| Workflow Engine | Approval Flow, Process Engine |
| Document Numbering | Document ID, Auto Number |
| RBAC | Permission System (generic) |
| ✅ Use | ❌ Don't Use | คำอธิบายเพิ่มเติม |
| ------------------ | ------------------------------------- | ------------------------------------------------ |
| Correspondence | Letter, Communication, Document | ครอบคลุมทุกประเภท: Letter, RFA, Memo, ฯลฯ |
| RFA | Approval Request, Submit for Approval | เอกสารขออนุมัติ (ชนิดหนึ่งของ Correspondence) |
| Transmittal | Delivery Note, Cover Letter | เอกสารนำส่ง (ชนิดหนึ่งของ Correspondence) |
| Circulation | Distribution, Routing | ใบเวียนเอกสารภายใน (ชนิดหนึ่งของ Correspondence) |
| Shop Drawing | Construction Drawing | แบบก่อสร้าง |
| Contract Drawing | Design Drawing, Blueprint | แบบคู่สัญญา |
| Workflow Engine | Approval Flow, Process Engine | เครื่องมือจัดการลำดับงาน |
| Document Numbering | Document ID, Auto Number | ระบบจัดการเลขที่เอกสาร |
| RBAC | Permission System (generic) | การควบคุมสิทธิ์ตามบทบาท |
## Full Glossary
+19 -19
View File
@@ -2,25 +2,25 @@
## ❌ Never Do This
| ❌ Forbidden | ✅ Correct Approach |
| ----------------------------------------------- | ----------------------------------------------------------------- |
| SQL Triggers for business logic | NestJS Service methods |
| `.env` files in production | `docker-compose.yml` environment section |
| TypeORM migration files | Edit schema SQL directly (ADR-009) |
| Inventing table/column names | Verify against `lcbp3-v1.9.0-schema-02-tables.sql` |
| `any` TypeScript type | Proper types / generics |
| `console.log` in committed code | NestJS Logger (backend) / remove (frontend) |
| `req: any` in controllers | `RequestWithUser` typed interface |
| `parseInt()` on UUID values | Use UUID string directly (ADR-019) |
| Exposing INT PK in API responses | UUIDv7 (ADR-019) |
| AI accessing DB/storage directly | AI → DMS API → DB (ADR-023) |
| Direct file operations bypassing StorageService | `StorageService` for all file moves |
| Inline email/notification sending | BullMQ queue job |
| Deploying without Release Gates | Complete `04-08-release-management-policy.md` |
| AI direct cloud API calls | On-premises Ollama only (ADR-023) |
| AI outputs without human validation | Human-in-the-loop validation required (ADR-023) |
| n8n calling Ollama/Qdrant directly | n8n → DMS API → BullMQ → Ollama/Qdrant (ADR-023A) |
| Qdrant query without projectPublicId filter | QdrantService.search(projectPublicId: string) required (ADR-023A) |
| ❌ Forbidden | ✅ Correct Approach | ⚠️ Why |
| ----------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------- |
| SQL Triggers for business logic | NestJS Service methods | Untestable; bypasses audit log |
| `.env` files in production | `docker-compose.yml` environment section | Secrets exposed in version control |
| TypeORM migration files | Edit schema SQL directly (ADR-009) | Migration drift risk; schema managed via SQL delta |
| Inventing table/column names | Verify against `schema-02-tables.sql` | Schema mismatch causes silent runtime errors |
| `any` TypeScript type | Proper types / generics | Defeats strict mode; hides runtime type errors |
| `console.log` in committed code | NestJS Logger (backend) / remove (frontend) | Log flooding in production; risk of data leakage |
| `req: any` in controllers | `RequestWithUser` typed interface | Type safety lost; auth context unreachable |
| `parseInt()` on UUID values | Use UUID string directly (ADR-019) | `"0195…"` parsed to integer `19` — silently wrong |
| Exposing INT PK in API responses | UUIDv7 `publicId` (ADR-019) | Leaks row count; enables DB enumeration attacks |
| AI accessing DB/storage directly | AI → DMS API → DB (ADR-023/023A) | Bypasses RBAC, audit trail, and validation layer |
| Direct file operations bypassing StorageService | `StorageService` for all file moves | Orphaned files; broken ClamAV scan; no audit trail |
| Inline email/notification sending | BullMQ queue job (ADR-008) | Blocks request thread; no retry on transient failure |
| Deploying without Release Gates | Complete `04-08-release-management-policy.md` | Unverified deploy risks data loss in production |
| AI direct cloud API calls | On-premises Ollama only (ADR-023/023A) | Data privacy violation; no audit control |
| AI outputs without human validation | Human-in-the-loop validation required (ADR-023/023A) | Unvalidated AI metadata corrupts document records |
| n8n calling Ollama/Qdrant directly | n8n → DMS API → BullMQ → Ollama (ADR-023A) | Bypasses audit log, RBAC, and error handling layer |
| Qdrant query without `projectPublicId` filter | `QdrantService.search(projectPublicId, ...)` (ADR-023A) | Cross-project data leak via vector search |
## Schema Changes (ADR-009)
+1 -2
View File
@@ -1,4 +1,3 @@
# Frontend Patterns (Next.js)
## Form Handling
@@ -17,7 +16,7 @@ interface ProjectOption {
}
// Select options
const options = contracts.map(c => ({
const options = contracts.map((c) => ({
label: `${c.contractName} (${c.contractCode})`,
value: c.publicId!, // Use publicId, no fallback to id
}));
+33 -28
View File
@@ -9,7 +9,7 @@
3. **Check schema** — verify table/column in `lcbp3-v1.9.0-schema-02-tables.sql`
4. **Check data dictionary** — confirm field meanings + business rules
5. **Scan edge cases**`01-06-edge-cases-and-rules.md`
6. **Check ADRs** — verify decisions align (ADR-009, ADR-018, ADR-019)
6. **Check ADRs** — verify decisions align (ADR-009, ADR-019, ADR-023)
7. **Write code** — TypeScript strict, no `any`, no `console.log`
## 🟡 Normal Work — UI / Feature / Integration
@@ -80,30 +80,35 @@
## Context-Aware Triggers
| Request | Files to Check | Expected Response |
| ----------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| "สร้าง API ใหม่" | `05-02-backend-guidelines.md`, `lcbp3-v1.9.0-schema-02-tables.sql` | NestJS Controller + Service + DTO + CASL Guard |
| "แก้ฟอร์ม frontend" | `05-03-frontend-guidelines.md`, `01-06-edge-cases.md` | RHF+Zod + TanStack Query + Thai comments |
| "เพิ่ม field ใหม่" | `ADR-009`, `data-dictionary.md`, `lcbp3-v1.9.0-schema-02-tables.sql` | Edit SQL directly + update Data Dictionary + Entity |
| "ตรวจสอบ UUID" | `ADR-019`, `05-07-hybrid-uuid-implementation-plan.md` | UUIDv7 MariaDB native UUID + TransformInterceptor |
| "สร้าง migration" | `ADR-009`, `03-06-migration-business-scope.md` | Edit SQL schema directly + n8n workflow |
| "ตรวจสอบ permission" | `seed-permissions.sql`, `ADR-016` | CASL 4-Level RBAC matrix |
| "deploy production" | `04-08-release-management-policy.md`, `ADR-015` | Release Gates + Blue-Green strategy |
| "เพิ่ม test" | `05-04-testing-strategy.md` | Coverage goals + test patterns |
| "AI integration" | ✅ | `ADR-023`, `ADR-023A`, `ADR-024`, `ADR-025` | AI boundary + 2-model stack + BullMQ queue policy + Intent/Tool Layer |
| "Error handling" | ✅ | `ADR-007` | Layered error classification + recovery |
| "File upload" | ✅ | `ADR-016`, `05-02-backend-guidelines.md`, `03-Data-and-Storage/03-03-file-storage.md` | Two-phase upload → temp → commit; ClamAV + whitelist |
| "Notifications / Queue" | ✅ | `ADR-008`, `05-02-backend-guidelines.md` | BullMQ job — never inline; check retry + dead-letter |
| "Add i18n / translate" | ✅ | `05-08-i18n-guidelines.md` | i18n keys only — no hardcoded text |
| "Workflow / DSL" | ✅ | `ADR-001`, `01-03-modules/01-03-06-unified-workflow.md` | DSL state machine + WorkflowEngineService |
| "Document numbering" | ✅ | `ADR-002`, `01-02-business-rules/01-02-02-doc-numbering-rules.md` | Redis Redlock + DB optimistic lock (double-lock) |
| "ตรวจสอบ Workflow" | ✅ | `01-06-edge-cases-and-rules.md`, `05-02-backend-guidelines.md`, `ADR-001`, `ADR-002` | เช็คการเปลี่ยน State, คิว BullMQ และการล็อกเลขที่เอกสาร |
| "Transmittal submit" | 📋 | `ADR-021`, `specs/200-fullstacks/201-transmittals-circulation/` | submit() with EC-RFA-004 validation |
| "Circulation reassign" | 📋 | `ADR-021`, `specs/200-fullstacks/201-transmittals-circulation/` | reassignRouting() with EC-CIRC-001 |
| "สร้าง workflow ใหม่" | 📋 | `ADR-001`, `ADR-021`, `specs/200-fullstacks/203-unified-workflow-engine/` | DSL workflow definition + WorkflowEngineService setup |
| "ตรวจสอบ AI boundary" | ✅ | `ADR-023`, `ADR-023A` | Verify Ollama isolation + BullMQ queues + Qdrant projectPublicId filter |
| "Intent classification" | ✅ | `ADR-024`, `specs/200-fullstacks/224-intent-classification/` | Pattern Layer → LLM Fallback; ai_intent_patterns; Redis cache 5 min |
| "AI Tool Layer" | ✅ | `ADR-025`, `specs/200-fullstacks/225-ai-tool-layer-architecture/` | Tool Registry; CASL-guarded dispatch; ToolResult publicId only |
| "Document Chat UI" | ✅ | `ADR-026`, `specs/200-fullstacks/226-document-chat-ui-pattern/` | Side-panel; useAiChat() hook; streaming SSE; TanStack Query cache |
| "AI Admin Console" | ✅ | `ADR-027`, `specs/200-fullstacks/227-ai-admin-console/` | Dynamic model/prompt/intent control; admin-only CASL endpoints |
| "Migration refactor" | ✅ | `ADR-028`, `specs/200-fullstacks/228-migration-arch-refactor/` | Staging Queue; post-migration cleanup; validation gates |
| Request | Files to Check | Expected Response |
| --------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| "สร้าง API ใหม่" | `05-02-backend-guidelines.md`, `lcbp3-v1.9.0-schema-02-tables.sql` | NestJS Controller + Service + DTO + CASL Guard |
| "แก้ฟอร์ม frontend" | `05-03-frontend-guidelines.md`, `01-06-edge-cases-and-rules.md` | RHF+Zod + TanStack Query + Thai comments |
| "เพิ่ม field ใหม่" | `ADR-009`, `03-01-data-dictionary.md`, `lcbp3-v1.9.0-schema-02-tables.sql` | Edit SQL directly + update Data Dictionary + Entity |
| "ตรวจสอบ UUID" | `ADR-019`, `05-07-hybrid-uuid-implementation-plan.md` | UUIDv7 MariaDB native UUID + TransformInterceptor |
| "สร้าง migration" | `ADR-009`, `03-06-migration-business-scope.md` | Edit SQL schema directly + n8n workflow |
| "ตรวจสอบ permission" | `lcbp3-v1.9.0-seed-permissions.sql`, `ADR-016` | CASL 4-Level RBAC matrix |
| "deploy production" | `04-08-release-management-policy.md`, `ADR-015` | Release Gates + Blue-Green strategy |
| "เพิ่ม test" | `05-04-testing-strategy.md` | Coverage goals + test patterns |
| "AI integration" | `ADR-023`, `ADR-023A`, `ADR-024`, `ADR-025` | AI boundary + 2-model stack + BullMQ queue policy + Intent/Tool Layer |
| "Error handling" | `ADR-007` | Layered error classification + recovery |
| "File upload" | `ADR-016`, `05-02-backend-guidelines.md`, `03-Data-and-Storage/03-03-file-storage.md` | Two-phase upload → temp → commit; ClamAV + whitelist |
| "Notifications / Queue" | `ADR-008`, `05-02-backend-guidelines.md` | BullMQ job — never inline; check retry + dead-letter |
| "Add i18n / translate" | `05-08-i18n-guidelines.md` | i18n keys only — no hardcoded text |
| "Workflow / DSL" | `ADR-001`, `01-03-modules/01-03-06-unified-workflow.md` | DSL state machine + WorkflowEngineService |
| "Document numbering" | `ADR-002`, `01-02-business-rules/01-02-02-doc-numbering-rules.md` | Redis Redlock + DB optimistic lock (double-lock) |
| "ตรวจสอบ Workflow" | `01-06-edge-cases-and-rules.md`, `05-02-backend-guidelines.md`, `ADR-001`, `ADR-002` | เช็คการเปลี่ยน State, คิว BullMQ และการล็อกเลขที่เอกสาร |
| "Transmittal submit" | `ADR-021`, `specs/200-fullstacks/201-transmittals-circulation/` | submit() with EC-RFA-004 validation |
| "Circulation reassign" | `ADR-021`, `specs/200-fullstacks/201-transmittals-circulation/` | reassignRouting() with EC-CIRC-001 |
| "สร้าง workflow ใหม่" | `ADR-001`, `ADR-021`, `specs/200-fullstacks/203-unified-workflow-engine/` | DSL workflow definition + WorkflowEngineService setup |
| "ตรวจสอบ AI boundary" | `ADR-023`, `ADR-023A` | Verify Ollama isolation + BullMQ queues + Qdrant projectPublicId filter |
| "Intent classification" | `ADR-024`, `specs/200-fullstacks/224-intent-classification/` | Pattern Layer → LLM Fallback; ai_intent_patterns; Redis cache 5 min |
| "AI Tool Layer" | `ADR-025`, `specs/200-fullstacks/225-ai-tool-layer-architecture/` | Tool Registry; CASL-guarded dispatch; ToolResult publicId only |
| "Document Chat UI" | `ADR-026`, `specs/200-fullstacks/226-document-chat-ui-pattern/` | Side-panel; useAiChat() hook; streaming SSE; TanStack Query cache |
| "AI Admin Console" | `ADR-027`, `specs/200-fullstacks/227-ai-admin-console/` | Dynamic model/prompt/intent control; admin-only CASL endpoints |
| "Migration refactor" | `ADR-028`, `specs/200-fullstacks/228-migration-arch-refactor/` | Staging Queue; post-migration cleanup; validation gates |
| "จัดการ document numbering" | `ADR-002`, `specs/03-Data-and-Storage/03-04-document-numbering.md` | Redis Redlock + template system + preview/override workflows |
| "Audit ความปลอดภัย" | `ADR-016`, `ADR-019`, `ADR-023`, `ADR-023A` | ตรวจสอบ UUID pattern, CASL Guard, AI Boundary และ Qdrant multi-tenancy |
| "แก้ bug / bugfix" | `.agents/workflows/bugfix.md`, `error-catalog.md` | ใช้ bugfix workflow สำหรับเคสที่สาเหตุชัดเจน |
| "ตรวจแอปจริง" | `.windsurf/workflows/check-real-app.md` | ตรวจ endpoint/UI/console หลัง build pass — No Fake Evidence |
| "งานค้าง / resume" | `.windsurf/workflows/resume-pending-work.md` | อ่าน checkpoint เดิม → ตรวจ build → วางแผนต่อโดยไม่ทำงานซ้ำ |
+1 -1
View File
@@ -1,4 +1,3 @@
# Commit Checklist
## Pre-Commit Verification
@@ -28,6 +27,7 @@ type(scope): description
Types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`
Examples:
- `feat(correspondence): add originator organization validation`
- `fix(uuid): correct parseInt usage to string comparison`
- `spec(agents): bump to v1.8.5 - refactor structure`
+6 -12
View File
@@ -1,4 +1,3 @@
# ADR-007 Error Handling Strategy
## CRITICAL RULES
@@ -11,23 +10,18 @@
## Error Classification
| Error Type | Description | User Message | Technical Log |
|------------|-------------|--------------|---------------|
| **Validation** | Input validation failures | Clear field-level errors | Full validation details |
| **Business** | Business rule violations | Actionable guidance | Business context + user ID |
| **System** | Infrastructure failures | Generic "try again" | Full stack trace + metrics |
| Error Type | Description | User Message | Technical Log |
| -------------- | ------------------------- | ------------------------ | -------------------------- |
| **Validation** | Input validation failures | Clear field-level errors | Full validation details |
| **Business** | Business rule violations | Actionable guidance | Business context + user ID |
| **System** | Infrastructure failures | Generic "try again" | Full stack trace + metrics |
## Backend Pattern (NestJS)
```typescript
// Custom Exception Hierarchy
export class BusinessException extends HttpException {
constructor(
message: string,
userMessage: string,
recoveryAction?: string,
errorCode?: string
) {
constructor(message: string, userMessage: string, recoveryAction?: string, errorCode?: string) {
super({ message, userMessage, recoveryAction, errorCode }, 400);
}
}
+10 -5
View File
@@ -3,7 +3,7 @@
## CRITICAL RULES
- **ALWAYS** follow ADR-023 AI boundary policy (isolation on Admin Desktop)
- **ALWAYS** use ADR-023A 2-model stack (gemma4:e4b Q8_0 + nomic-embed-text)
- **ALWAYS** use ADR-023A 2-model stack (gemma4:e2b + nomic-embed-text)
- **ALWAYS** use BullMQ 2-queue (ai-realtime + ai-batch) for GPU overload prevention
- **NEVER** allow AI direct database/storage access
- **ALWAYS** implement human-in-the-loop validation
@@ -26,7 +26,7 @@ n8n (Migration) → DMS API → BullMQ → Admin Desktop (Ollama) → Backend Va
| ----------------- | ------------------------- | ------------------------------------------------------------------------ |
| **AI Gateway** | Backend (NestJS) | API endpoints, validation, audit logging |
| **BullMQ Queues** | Backend (NestJS) | ai-realtime (RAG/Suggest), ai-batch (OCR/Extract/Embed) |
| **Ollama Engine** | Admin Desktop (Desk-5439) | gemma4:e4b Q8_0 (LLM) + nomic-embed-text (Embedding) |
| **Ollama Engine** | Admin Desktop (Desk-5439) | gemma4:e2b (LLM) + nomic-embed-text (Embedding) |
| **OCR Engine** | Admin Desktop (Desk-5439) | PaddleOCR + PyThaiNLP (Thai/English text extraction) |
| **Orchestrator** | QNAP NAS (n8n) | Migration Phase orchestrator only (calls DMS API, never Ollama directly) |
@@ -76,7 +76,7 @@ export class AiService {
async extractMetadata(documentId: string): Promise<AIMetadata> {
// 1. Validate permissions
// 2. Queue job to BullMQ (ai-batch or ai-realtime)
// 3. Worker sends to Admin Desktop AI (gemma4:e4b Q8_0)
// 3. Worker sends to Admin Desktop AI (gemma4:e2b)
// 4. Validate AI response
// 5. Log audit trail to ai_audit_logs
// 6. Return validated results
@@ -115,7 +115,7 @@ const DocumentReviewForm = ({ document, aiSuggestions }) => {
## ADR-023A Specific Rules
- **2-Model Stack:** gemma4:e4b Q8_0 (~4.0GB) + nomic-embed-text (~0.3GB) = ~4.3GB VRAM peak
- **2-Model Stack:** gemma4:e2b + nomic-embed-text
- **PDF 3-Page Limit:** Classification/Tagging uses first 3 pages only (NOT RAG embedding)
- **RAG Embedding:** Full document chunked at 512 tokens/64 tokens overlap
- **OCR Auto-Detect:** PyMuPDF chars > 100 → Fast path, else PaddleOCR
@@ -129,7 +129,7 @@ const DocumentReviewForm = ({ document, aiSuggestions }) => {
- [ ] BullMQ 2-queue setup (ai-realtime + ai-batch)
- [ ] QdrantService with projectPublicId enforcement
- [ ] DocumentReviewForm reusable component
- [ ] Admin Desktop Ollama (gemma4:e4b Q8_0 + nomic-embed-text) + PaddleOCR setup
- [ ] Admin Desktop Ollama (gemma4:e2b + nomic-embed-text) + PaddleOCR setup
- [ ] n8n workflow orchestration (Migration Phase only)
- [ ] AI audit logging and monitoring (ai_audit_logs)
- [ ] Human-in-the-loop validation workflows
@@ -138,3 +138,8 @@ const DocumentReviewForm = ({ document, aiSuggestions }) => {
- `specs/06-Decision-Records/ADR-023-unified-ai-architecture.md` (Base architecture)
- `specs/06-Decision-Records/ADR-023A-unified-ai-architecture.md` (Model revision - current)
- `specs/06-Decision-Records/ADR-024-intent-classification-strategy.md` (Pattern→LLM Fallback)
- `specs/06-Decision-Records/ADR-025-ai-tool-layer-architecture.md` (Tool Registry)
- `specs/06-Decision-Records/ADR-026-document-chat-ui-pattern.md` (Chat UI)
- `specs/06-Decision-Records/ADR-027-ai-admin-console-and-dynamic-control.md` (Admin Console)
- `specs/06-Decision-Records/ADR-028-migration-architecture-refactor.md` (Migration Pipeline)
+19 -19
View File
@@ -130,25 +130,25 @@ Best practice — follow when possible:
## 🚫 Forbidden Actions
| ❌ Forbidden | ✅ Correct Approach |
| ----------------------------------------------- | ------------------------------------------------------- |
| SQL Triggers for business logic | NestJS Service methods |
| `.env` files in production | `docker-compose.yml` environment section |
| TypeORM migration files | Edit schema SQL directly (ADR-009) |
| Inventing table/column names | Verify against `lcbp3-v1.9.0-schema-02-tables.sql` |
| `any` TypeScript type | Proper types / generics |
| `console.log` in committed code | NestJS Logger (backend) / remove (frontend) |
| `req: any` in controllers | `RequestWithUser` typed interface |
| `parseInt()` on UUID values | Use UUID string directly (ADR-019) |
| Exposing INT PK in API responses | UUIDv7 (ADR-019) |
| AI accessing DB/storage directly | AI → DMS API → DB (ADR-023) |
| Direct file operations bypassing StorageService | `StorageService` for all file moves |
| Inline email/notification sending | BullMQ queue job |
| Deploying without Release Gates | Complete `04-08-release-management-policy.md` |
| AI direct cloud API calls | On-premises Ollama only (ADR-023) |
| AI outputs without human validation | Human-in-the-loop validation required (ADR-023) |
| n8n calling Ollama/Qdrant directly | n8n → DMS API → BullMQ → Ollama/Qdrant (ADR-023A) |
| Qdrant query without `projectPublicId` filter | `QdrantService.search(projectPublicId, ...)` (ADR-023A) |
| ❌ Forbidden | ✅ Correct Approach | ⚠️ Why |
| ----------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------- |
| SQL Triggers for business logic | NestJS Service methods | Untestable; bypasses audit log |
| `.env` files in production | `docker-compose.yml` environment section | Secrets exposed in version control |
| TypeORM migration files | Edit schema SQL directly (ADR-009) | Migration drift risk; schema managed via SQL delta |
| Inventing table/column names | Verify against `schema-02-tables.sql` | Schema mismatch causes silent runtime errors |
| `any` TypeScript type | Proper types / generics | Defeats strict mode; hides runtime type errors |
| `console.log` in committed code | NestJS Logger (backend) / remove (frontend) | Log flooding in production; risk of data leakage |
| `req: any` in controllers | `RequestWithUser` typed interface | Type safety lost; auth context unreachable |
| `parseInt()` on UUID values | Use UUID string directly (ADR-019) | `"0195…"` parsed to integer `19` — silently wrong |
| Exposing INT PK in API responses | UUIDv7 `publicId` (ADR-019) | Leaks row count; enables DB enumeration attacks |
| AI accessing DB/storage directly | AI → DMS API → DB (ADR-023/023A) | Bypasses RBAC, audit trail, and validation layer |
| Direct file operations bypassing StorageService | `StorageService` for all file moves | Orphaned files; broken ClamAV scan; no audit trail |
| Inline email/notification sending | BullMQ queue job (ADR-008) | Blocks request thread; no retry on transient failure |
| Deploying without Release Gates | Complete `04-08-release-management-policy.md` | Unverified deploy risks data loss in production |
| AI direct cloud API calls | On-premises Ollama only (ADR-023/023A) | Data privacy violation; no audit control |
| AI outputs without human validation | Human-in-the-loop validation required (ADR-023/023A) | Unvalidated AI metadata corrupts document records |
| n8n calling Ollama/Qdrant directly | n8n → DMS API → BullMQ → Ollama (ADR-023A) | Bypasses audit log, RBAC, and error handling layer |
| Qdrant query without `projectPublicId` filter | `QdrantService.search(projectPublicId, ...)` (ADR-023A) | Cross-project data leak via vector search |
---
+11 -11
View File
@@ -6,17 +6,17 @@ trigger: always_on
## DMS Glossary
| ✅ Use | ❌ Don't Use |
| ------------------ | ------------------------------------- |
| Correspondence | Letter, Communication, Document |
| RFA | Approval Request, Submit for Approval |
| Transmittal | Delivery Note, Cover Letter |
| Circulation | Distribution, Routing |
| Shop Drawing | Construction Drawing |
| Contract Drawing | Design Drawing, Blueprint |
| Workflow Engine | Approval Flow, Process Engine |
| Document Numbering | Document ID, Auto Number |
| RBAC | Permission System (generic) |
| ✅ Use | ❌ Don't Use | คำอธิบายเพิ่มเติม |
| ------------------ | ------------------------------------- | ------------------------------------------------ |
| Correspondence | Letter, Communication, Document | ครอบคลุมทุกประเภท: Letter, RFA, Memo, ฯลฯ |
| RFA | Approval Request, Submit for Approval | เอกสารขออนุมัติ (ชนิดหนึ่งของ Correspondence) |
| Transmittal | Delivery Note, Cover Letter | เอกสารนำส่ง (ชนิดหนึ่งของ Correspondence) |
| Circulation | Distribution, Routing | ใบเวียนเอกสารภายใน (ชนิดหนึ่งของ Correspondence) |
| Shop Drawing | Construction Drawing | แบบก่อสร้าง |
| Contract Drawing | Design Drawing, Blueprint | แบบคู่สัญญา |
| Workflow Engine | Approval Flow, Process Engine | เครื่องมือจัดการลำดับงาน |
| Document Numbering | Document ID, Auto Number | ระบบจัดการเลขที่เอกสาร |
| RBAC | Permission System (generic) | การควบคุมสิทธิ์ตามบทบาท |
## Full Glossary
+19 -19
View File
@@ -6,25 +6,25 @@ trigger: always_on
## ❌ Never Do This
| ❌ Forbidden | ✅ Correct Approach |
| ----------------------------------------------- | ----------------------------------------------------------------- |
| SQL Triggers for business logic | NestJS Service methods |
| `.env` files in production | `docker-compose.yml` environment section |
| TypeORM migration files | Edit schema SQL directly (ADR-009) |
| Inventing table/column names | Verify against `lcbp3-v1.9.0-schema-02-tables.sql` |
| `any` TypeScript type | Proper types / generics |
| `console.log` in committed code | NestJS Logger (backend) / remove (frontend) |
| `req: any` in controllers | `RequestWithUser` typed interface |
| `parseInt()` on UUID values | Use UUID string directly (ADR-019) |
| Exposing INT PK in API responses | UUIDv7 (ADR-019) |
| AI accessing DB/storage directly | AI → DMS API → DB (ADR-023) |
| Direct file operations bypassing StorageService | `StorageService` for all file moves |
| Inline email/notification sending | BullMQ queue job |
| Deploying without Release Gates | Complete `04-08-release-management-policy.md` |
| AI direct cloud API calls | On-premises Ollama only (ADR-023) |
| AI outputs without human validation | Human-in-the-loop validation required (ADR-023) |
| n8n calling Ollama/Qdrant directly | n8n → DMS API → BullMQ → Ollama/Qdrant (ADR-023A) |
| Qdrant query without projectPublicId filter | QdrantService.search(projectPublicId: string) required (ADR-023A) |
| ❌ Forbidden | ✅ Correct Approach | ⚠️ Why |
| ----------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------- |
| SQL Triggers for business logic | NestJS Service methods | Untestable; bypasses audit log |
| `.env` files in production | `docker-compose.yml` environment section | Secrets exposed in version control |
| TypeORM migration files | Edit schema SQL directly (ADR-009) | Migration drift risk; schema managed via SQL delta |
| Inventing table/column names | Verify against `schema-02-tables.sql` | Schema mismatch causes silent runtime errors |
| `any` TypeScript type | Proper types / generics | Defeats strict mode; hides runtime type errors |
| `console.log` in committed code | NestJS Logger (backend) / remove (frontend) | Log flooding in production; risk of data leakage |
| `req: any` in controllers | `RequestWithUser` typed interface | Type safety lost; auth context unreachable |
| `parseInt()` on UUID values | Use UUID string directly (ADR-019) | `"0195…"` parsed to integer `19` — silently wrong |
| Exposing INT PK in API responses | UUIDv7 `publicId` (ADR-019) | Leaks row count; enables DB enumeration attacks |
| AI accessing DB/storage directly | AI → DMS API → DB (ADR-023/023A) | Bypasses RBAC, audit trail, and validation layer |
| Direct file operations bypassing StorageService | `StorageService` for all file moves | Orphaned files; broken ClamAV scan; no audit trail |
| Inline email/notification sending | BullMQ queue job (ADR-008) | Blocks request thread; no retry on transient failure |
| Deploying without Release Gates | Complete `04-08-release-management-policy.md` | Unverified deploy risks data loss in production |
| AI direct cloud API calls | On-premises Ollama only (ADR-023/023A) | Data privacy violation; no audit control |
| AI outputs without human validation | Human-in-the-loop validation required (ADR-023/023A) | Unvalidated AI metadata corrupts document records |
| n8n calling Ollama/Qdrant directly | n8n → DMS API → BullMQ → Ollama (ADR-023A) | Bypasses audit log, RBAC, and error handling layer |
| Qdrant query without `projectPublicId` filter | `QdrantService.search(projectPublicId, ...)` (ADR-023A) | Cross-project data leak via vector search |
## Schema Changes (ADR-009)
+33 -28
View File
@@ -13,7 +13,7 @@ trigger: always_on
3. **Check schema** — verify table/column in `lcbp3-v1.9.0-schema-02-tables.sql`
4. **Check data dictionary** — confirm field meanings + business rules
5. **Scan edge cases**`01-06-edge-cases-and-rules.md`
6. **Check ADRs** — verify decisions align (ADR-009, ADR-018, ADR-019)
6. **Check ADRs** — verify decisions align (ADR-009, ADR-019, ADR-023)
7. **Write code** — TypeScript strict, no `any`, no `console.log`
## 🟡 Normal Work — UI / Feature / Integration
@@ -84,30 +84,35 @@ trigger: always_on
## Context-Aware Triggers
| Request | Files to Check | Expected Response |
| ----------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| "สร้าง API ใหม่" | `05-02-backend-guidelines.md`, `lcbp3-v1.9.0-schema-02-tables.sql` | NestJS Controller + Service + DTO + CASL Guard |
| "แก้ฟอร์ม frontend" | `05-03-frontend-guidelines.md`, `01-06-edge-cases.md` | RHF+Zod + TanStack Query + Thai comments |
| "เพิ่ม field ใหม่" | `ADR-009`, `data-dictionary.md`, `lcbp3-v1.9.0-schema-02-tables.sql` | Edit SQL directly + update Data Dictionary + Entity |
| "ตรวจสอบ UUID" | `ADR-019`, `05-07-hybrid-uuid-implementation-plan.md` | UUIDv7 MariaDB native UUID + TransformInterceptor |
| "สร้าง migration" | `ADR-009`, `03-06-migration-business-scope.md` | Edit SQL schema directly + n8n workflow |
| "ตรวจสอบ permission" | `seed-permissions.sql`, `ADR-016` | CASL 4-Level RBAC matrix |
| "deploy production" | `04-08-release-management-policy.md`, `ADR-015` | Release Gates + Blue-Green strategy |
| "เพิ่ม test" | `05-04-testing-strategy.md` | Coverage goals + test patterns |
| "AI integration" | ✅ | `ADR-023`, `ADR-023A`, `ADR-024`, `ADR-025` | AI boundary + 2-model stack + BullMQ queue policy + Intent/Tool Layer |
| "Error handling" | ✅ | `ADR-007` | Layered error classification + recovery |
| "File upload" | ✅ | `ADR-016`, `05-02-backend-guidelines.md`, `03-Data-and-Storage/03-03-file-storage.md` | Two-phase upload → temp → commit; ClamAV + whitelist |
| "Notifications / Queue" | ✅ | `ADR-008`, `05-02-backend-guidelines.md` | BullMQ job — never inline; check retry + dead-letter |
| "Add i18n / translate" | ✅ | `05-08-i18n-guidelines.md` | i18n keys only — no hardcoded text |
| "Workflow / DSL" | ✅ | `ADR-001`, `01-03-modules/01-03-06-unified-workflow.md` | DSL state machine + WorkflowEngineService |
| "Document numbering" | ✅ | `ADR-002`, `01-02-business-rules/01-02-02-doc-numbering-rules.md` | Redis Redlock + DB optimistic lock (double-lock) |
| "ตรวจสอบ Workflow" | ✅ | `01-06-edge-cases-and-rules.md`, `05-02-backend-guidelines.md`, `ADR-001`, `ADR-002` | เช็คการเปลี่ยน State, คิว BullMQ และการล็อกเลขที่เอกสาร |
| "Transmittal submit" | 📋 | `ADR-021`, `specs/200-fullstacks/201-transmittals-circulation/` | submit() with EC-RFA-004 validation |
| "Circulation reassign" | 📋 | `ADR-021`, `specs/200-fullstacks/201-transmittals-circulation/` | reassignRouting() with EC-CIRC-001 |
| "สร้าง workflow ใหม่" | 📋 | `ADR-001`, `ADR-021`, `specs/200-fullstacks/203-unified-workflow-engine/` | DSL workflow definition + WorkflowEngineService setup |
| "ตรวจสอบ AI boundary" | ✅ | `ADR-023`, `ADR-023A` | Verify Ollama isolation + BullMQ queues + Qdrant projectPublicId filter |
| "Intent classification" | ✅ | `ADR-024`, `specs/200-fullstacks/224-intent-classification/` | Pattern Layer → LLM Fallback; ai_intent_patterns; Redis cache 5 min |
| "AI Tool Layer" | ✅ | `ADR-025`, `specs/200-fullstacks/225-ai-tool-layer-architecture/` | Tool Registry; CASL-guarded dispatch; ToolResult publicId only |
| "Document Chat UI" | ✅ | `ADR-026`, `specs/200-fullstacks/226-document-chat-ui-pattern/` | Side-panel; useAiChat() hook; streaming SSE; TanStack Query cache |
| "AI Admin Console" | ✅ | `ADR-027`, `specs/200-fullstacks/227-ai-admin-console/` | Dynamic model/prompt/intent control; admin-only CASL endpoints |
| "Migration refactor" | ✅ | `ADR-028`, `specs/200-fullstacks/228-migration-arch-refactor/` | Staging Queue; post-migration cleanup; validation gates |
| Request | Files to Check | Expected Response |
| --------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| "สร้าง API ใหม่" | `05-02-backend-guidelines.md`, `lcbp3-v1.9.0-schema-02-tables.sql` | NestJS Controller + Service + DTO + CASL Guard |
| "แก้ฟอร์ม frontend" | `05-03-frontend-guidelines.md`, `01-06-edge-cases-and-rules.md` | RHF+Zod + TanStack Query + Thai comments |
| "เพิ่ม field ใหม่" | `ADR-009`, `03-01-data-dictionary.md`, `lcbp3-v1.9.0-schema-02-tables.sql` | Edit SQL directly + update Data Dictionary + Entity |
| "ตรวจสอบ UUID" | `ADR-019`, `05-07-hybrid-uuid-implementation-plan.md` | UUIDv7 MariaDB native UUID + TransformInterceptor |
| "สร้าง migration" | `ADR-009`, `03-06-migration-business-scope.md` | Edit SQL schema directly + n8n workflow |
| "ตรวจสอบ permission" | `lcbp3-v1.9.0-seed-permissions.sql`, `ADR-016` | CASL 4-Level RBAC matrix |
| "deploy production" | `04-08-release-management-policy.md`, `ADR-015` | Release Gates + Blue-Green strategy |
| "เพิ่ม test" | `05-04-testing-strategy.md` | Coverage goals + test patterns |
| "AI integration" | `ADR-023`, `ADR-023A`, `ADR-024`, `ADR-025` | AI boundary + 2-model stack + BullMQ queue policy + Intent/Tool Layer |
| "Error handling" | `ADR-007` | Layered error classification + recovery |
| "File upload" | `ADR-016`, `05-02-backend-guidelines.md`, `03-Data-and-Storage/03-03-file-storage.md` | Two-phase upload → temp → commit; ClamAV + whitelist |
| "Notifications / Queue" | `ADR-008`, `05-02-backend-guidelines.md` | BullMQ job — never inline; check retry + dead-letter |
| "Add i18n / translate" | `05-08-i18n-guidelines.md` | i18n keys only — no hardcoded text |
| "Workflow / DSL" | `ADR-001`, `01-03-modules/01-03-06-unified-workflow.md` | DSL state machine + WorkflowEngineService |
| "Document numbering" | `ADR-002`, `01-02-business-rules/01-02-02-doc-numbering-rules.md` | Redis Redlock + DB optimistic lock (double-lock) |
| "ตรวจสอบ Workflow" | `01-06-edge-cases-and-rules.md`, `05-02-backend-guidelines.md`, `ADR-001`, `ADR-002` | เช็คการเปลี่ยน State, คิว BullMQ และการล็อกเลขที่เอกสาร |
| "Transmittal submit" | `ADR-021`, `specs/200-fullstacks/201-transmittals-circulation/` | submit() with EC-RFA-004 validation |
| "Circulation reassign" | `ADR-021`, `specs/200-fullstacks/201-transmittals-circulation/` | reassignRouting() with EC-CIRC-001 |
| "สร้าง workflow ใหม่" | `ADR-001`, `ADR-021`, `specs/200-fullstacks/203-unified-workflow-engine/` | DSL workflow definition + WorkflowEngineService setup |
| "ตรวจสอบ AI boundary" | `ADR-023`, `ADR-023A` | Verify Ollama isolation + BullMQ queues + Qdrant projectPublicId filter |
| "Intent classification" | `ADR-024`, `specs/200-fullstacks/224-intent-classification/` | Pattern Layer → LLM Fallback; ai_intent_patterns; Redis cache 5 min |
| "AI Tool Layer" | `ADR-025`, `specs/200-fullstacks/225-ai-tool-layer-architecture/` | Tool Registry; CASL-guarded dispatch; ToolResult publicId only |
| "Document Chat UI" | `ADR-026`, `specs/200-fullstacks/226-document-chat-ui-pattern/` | Side-panel; useAiChat() hook; streaming SSE; TanStack Query cache |
| "AI Admin Console" | `ADR-027`, `specs/200-fullstacks/227-ai-admin-console/` | Dynamic model/prompt/intent control; admin-only CASL endpoints |
| "Migration refactor" | `ADR-028`, `specs/200-fullstacks/228-migration-arch-refactor/` | Staging Queue; post-migration cleanup; validation gates |
| "จัดการ document numbering" | `ADR-002`, `specs/03-Data-and-Storage/03-04-document-numbering.md` | Redis Redlock + template system + preview/override workflows |
| "Audit ความปลอดภัย" | `ADR-016`, `ADR-019`, `ADR-023`, `ADR-023A` | ตรวจสอบ UUID pattern, CASL Guard, AI Boundary และ Qdrant multi-tenancy |
| "แก้ bug / bugfix" | `.agents/workflows/bugfix.md`, `error-catalog.md` | ใช้ bugfix workflow สำหรับเคสที่สาเหตุชัดเจน |
| "ตรวจแอปจริง" | `.windsurf/workflows/check-real-app.md` | ตรวจ endpoint/UI/console หลัง build pass — No Fake Evidence |
| "งานค้าง / resume" | `.windsurf/workflows/resume-pending-work.md` | อ่าน checkpoint เดิม → ตรวจ build → วางแผนต่อโดยไม่ทำงานซ้ำ |
+10 -5
View File
@@ -7,7 +7,7 @@ trigger: always_on
## CRITICAL RULES
- **ALWAYS** follow ADR-023 AI boundary policy (isolation on Admin Desktop)
- **ALWAYS** use ADR-023A 2-model stack (gemma4:e4b Q8_0 + nomic-embed-text)
- **ALWAYS** use ADR-023A 2-model stack (gemma4:e2b + nomic-embed-text)
- **ALWAYS** use BullMQ 2-queue (ai-realtime + ai-batch) for GPU overload prevention
- **NEVER** allow AI direct database/storage access
- **ALWAYS** implement human-in-the-loop validation
@@ -30,7 +30,7 @@ n8n (Migration) → DMS API → BullMQ → Admin Desktop (Ollama) → Backend Va
| ----------------- | ------------------------- | ------------------------------------------------------------------------ |
| **AI Gateway** | Backend (NestJS) | API endpoints, validation, audit logging |
| **BullMQ Queues** | Backend (NestJS) | ai-realtime (RAG/Suggest), ai-batch (OCR/Extract/Embed) |
| **Ollama Engine** | Admin Desktop (Desk-5439) | gemma4:e4b Q8_0 (LLM) + nomic-embed-text (Embedding) |
| **Ollama Engine** | Admin Desktop (Desk-5439) | gemma4:e2b (LLM) + nomic-embed-text (Embedding) |
| **OCR Engine** | Admin Desktop (Desk-5439) | PaddleOCR + PyThaiNLP (Thai/English text extraction) |
| **Orchestrator** | QNAP NAS (n8n) | Migration Phase orchestrator only (calls DMS API, never Ollama directly) |
@@ -80,7 +80,7 @@ export class AiService {
async extractMetadata(documentId: string): Promise<AIMetadata> {
// 1. Validate permissions
// 2. Queue job to BullMQ (ai-batch or ai-realtime)
// 3. Worker sends to Admin Desktop AI (gemma4:e4b Q8_0)
// 3. Worker sends to Admin Desktop AI (gemma4:e2b)
// 4. Validate AI response
// 5. Log audit trail to ai_audit_logs
// 6. Return validated results
@@ -119,7 +119,7 @@ const DocumentReviewForm = ({ document, aiSuggestions }) => {
## ADR-023A Specific Rules
- **2-Model Stack:** gemma4:e4b Q8_0 (~4.0GB) + nomic-embed-text (~0.3GB) = ~4.3GB VRAM peak
- **2-Model Stack:** gemma4:e2b + nomic-embed-text
- **PDF 3-Page Limit:** Classification/Tagging uses first 3 pages only (NOT RAG embedding)
- **RAG Embedding:** Full document chunked at 512 tokens/64 tokens overlap
- **OCR Auto-Detect:** PyMuPDF chars > 100 → Fast path, else PaddleOCR
@@ -133,7 +133,7 @@ const DocumentReviewForm = ({ document, aiSuggestions }) => {
- [ ] BullMQ 2-queue setup (ai-realtime + ai-batch)
- [ ] QdrantService with projectPublicId enforcement
- [ ] DocumentReviewForm reusable component
- [ ] Admin Desktop Ollama (gemma4:e4b Q8_0 + nomic-embed-text) + PaddleOCR setup
- [ ] Admin Desktop Ollama (gemma4:e2b + nomic-embed-text) + PaddleOCR setup
- [ ] n8n workflow orchestration (Migration Phase only)
- [ ] AI audit logging and monitoring (ai_audit_logs)
- [ ] Human-in-the-loop validation workflows
@@ -142,3 +142,8 @@ const DocumentReviewForm = ({ document, aiSuggestions }) => {
- `specs/06-Decision-Records/ADR-023-unified-ai-architecture.md` (Base architecture)
- `specs/06-Decision-Records/ADR-023A-unified-ai-architecture.md` (Model revision - current)
- `specs/06-Decision-Records/ADR-024-intent-classification-strategy.md` (Pattern→LLM Fallback)
- `specs/06-Decision-Records/ADR-025-ai-tool-layer-architecture.md` (Tool Registry)
- `specs/06-Decision-Records/ADR-026-document-chat-ui-pattern.md` (Chat UI)
- `specs/06-Decision-Records/ADR-027-ai-admin-console-and-dynamic-control.md` (Admin Console)
- `specs/06-Decision-Records/ADR-028-migration-architecture-refactor.md` (Migration Pipeline)
+39 -35
View File
@@ -1,7 +1,7 @@
# NAP-DMS Project Context & Rules
- For: Windsurf Cascade (and compatible: Codex CLI, opencode, Amp, Antigravity, AGENTS.md tools)
- Version: 1.9.6 | Last synced from repo: 2026-05-22
- Version: 1.9.7 | Last synced from repo: 2026-05-25
- Repo: [https://git.np-dms.work/np-dms/lcbp3](https://git.np-dms.work/np-dms/lcbp3)
- Skill pack: `.agents/skills/` (v1.9.0, 21 skills) — see [`skills/README.md`](./.agents/skills/README.md) + [`skills/_LCBP3-CONTEXT.md`](./.agents/skills/_LCBP3-CONTEXT.md)
@@ -120,37 +120,38 @@ Best practice — follow when possible:
Spec priority: **`06-Decision-Records`** > **`05-Engineering-Guidelines`** > others
| Document | Path | Status | Use When |
| ------------------------------ | --------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- |
| **Glossary** | `specs/00-overview/00-02-glossary.md` | — | Verify domain terminology |
| **Schema Tables** | `specs/03-Data-and-Storage/lcbp3-v1.9.0-schema-02-tables.sql` | — | Before writing any query |
| **Data Dictionary** | `specs/03-Data-and-Storage/03-01-data-dictionary.md` | — | Field meanings + business rules |
| **RBAC Matrix** | `specs/01-requirements/01-02-business-rules/01-02-01-rbac-matrix.md` | — | Permission levels + roles |
| **Edge Cases** | `specs/01-Requirements/01-06-edge-cases-and-rules.md` | — | Prevent bugs in flows |
| **ADR-001 Workflow Engine** | `specs/06-Decision-Records/ADR-001-unified-workflow-engine.md` | ✅ Active | DSL-based workflow implementation |
| **ADR-002 Doc Numbering** | `specs/06-Decision-Records/ADR-002-document-numbering-strategy.md` | ✅ Active | Document number generation + locking |
| **ADR-007 Error Handling** | `specs/06-Decision-Records/ADR-007-error-handling-strategy.md` | ✅ Active | Error patterns & recovery |
| **ADR-008 Notifications** | `specs/06-Decision-Records/ADR-008-email-notification-strategy.md` | ✅ Active | BullMQ + multi-channel notification |
| **ADR-009 DB Migration** | `specs/06-Decision-Records/ADR-009-database-migration-strategy.md` | ✅ Active | Schema changes — edit SQL directly |
| **ADR-016 Security** | `specs/06-Decision-Records/ADR-016-security-authentication.md` | ✅ Active | Auth, RBAC, file upload security |
| **ADR-015 Release Strategy** | `specs/06-Decision-Records/ADR-015-deployment-infrastructure.md` | ✅ Active | Blue-Green deployment + release gates |
| **ADR-019 UUID** | `specs/06-Decision-Records/ADR-019-hybrid-identifier-strategy.md` | ✅ Active | UUID-related work |
| **ADR-021 Workflow Context** | `specs/06-Decision-Records/ADR-021-workflow-context.md` | ✅ Active | Integrated workflow & step attachments |
| **ADR-023 AI Architecture** | `specs/06-Decision-Records/ADR-023-unified-ai-architecture.md` | ✅ Active | Unified AI boundaries and pipeline (base architecture) |
| **ADR-023A AI Model Rev.** | `specs/06-Decision-Records/ADR-023A-unified-ai-architecture.md` | ✅ Active | 2-Model stack (gemma4:e2b), BullMQ 2-queue, RAG embed scope, OCR auto-detect |
| **ADR-024 Intent Class.** | `specs/06-Decision-Records/ADR-024-intent-classification-strategy.md` | ✅ Active | Hybrid Pattern→LLM Fallback; ai_intent_patterns DB; Redis cache 5 min |
| **ADR-025 AI Tool Layer** | `specs/06-Decision-Records/ADR-025-ai-tool-layer-architecture.md` | ✅ Active | Server-side Tool dispatch; CASL-guarded bridge; ToolResult uses publicId only |
| **ADR-026 Chat UI** | `specs/06-Decision-Records/ADR-026-document-chat-ui-pattern.md` | ✅ Active | Side-panel Document Chat UI; useAiChat() hook; streaming response support |
| **ADR-027 AI Admin Console** | `specs/06-Decision-Records/ADR-027-ai-admin-console-and-dynamic-control.md` | ✅ Active | Admin Panel + dynamic model/prompt/intent control without redeploy |
| **ADR-028 Migration Refactor** | `specs/06-Decision-Records/ADR-028-migration-architecture-refactor.md` | ✅ Active | Staging Queue & post-migration cleanup |
| **Backend Guidelines** | `specs/05-Engineering-Guidelines/05-02-backend-guidelines.md` | — | NestJS patterns |
| **Frontend Guidelines** | `specs/05-Engineering-Guidelines/05-03-frontend-guidelines.md` | — | Next.js patterns |
| **Testing Strategy** | `specs/05-Engineering-Guidelines/05-04-testing-strategy.md` | — | Coverage goals |
| **Git Conventions** | `specs/05-Engineering-Guidelines/05-05-git-conventions.md` | — | Commit/branch naming |
| **Code Snippets** | `specs/05-Engineering-Guidelines/05-06-code-snippets.md` | — | Reusable patterns |
| **i18n Guidelines** | `specs/05-Engineering-Guidelines/05-08-i18n-guidelines.md` | — | Localization rules |
| **Release Policy** | `specs/04-Infrastructure-OPS/04-08-release-management-policy.md` | — | Before deploy/hotfix |
| **UAT Criteria** | `specs/01-Requirements/01-05-acceptance-criteria.md` | — | Feature completeness |
| Document | Path | Status | Use When |
| ------------------------------ | --------------------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------- |
| **Glossary** | `specs/00-overview/00-02-glossary.md` | — | Verify domain terminology |
| **Schema Tables** | `specs/03-Data-and-Storage/lcbp3-v1.9.0-schema-02-tables.sql` | — | Before writing any query |
| **Data Dictionary** | `specs/03-Data-and-Storage/03-01-data-dictionary.md` | — | Field meanings + business rules |
| **RBAC Matrix** | `specs/01-requirements/01-02-business-rules/01-02-01-rbac-matrix.md` | — | Permission levels + roles |
| **Edge Cases** | `specs/01-Requirements/01-06-edge-cases-and-rules.md` | — | Prevent bugs in flows |
| **ADR-001 Workflow Engine** | `specs/06-Decision-Records/ADR-001-unified-workflow-engine.md` | ✅ Active | DSL-based workflow implementation |
| **ADR-002 Doc Numbering** | `specs/06-Decision-Records/ADR-002-document-numbering-strategy.md` | ✅ Active | Document number generation + locking |
| **ADR-007 Error Handling** | `specs/06-Decision-Records/ADR-007-error-handling-strategy.md` | ✅ Active | Error patterns & recovery |
| **ADR-008 Notifications** | `specs/06-Decision-Records/ADR-008-email-notification-strategy.md` | ✅ Active | BullMQ + multi-channel notification |
| **ADR-009 DB Migration** | `specs/06-Decision-Records/ADR-009-database-migration-strategy.md` | ✅ Active | Schema changes — edit SQL directly |
| **ADR-016 Security** | `specs/06-Decision-Records/ADR-016-security-authentication.md` | ✅ Active | Auth, RBAC, file upload security |
| **ADR-015 Release Strategy** | `specs/06-Decision-Records/ADR-015-deployment-infrastructure.md` | ✅ Active | Blue-Green deployment + release gates |
| **ADR-019 UUID** | `specs/06-Decision-Records/ADR-019-hybrid-identifier-strategy.md` | ✅ Active | UUID-related work |
| **ADR-021 Workflow Context** | `specs/06-Decision-Records/ADR-021-workflow-context.md` | ✅ Active | Integrated workflow & step attachments |
| **ADR-023 AI Architecture** | `specs/06-Decision-Records/ADR-023-unified-ai-architecture.md` | ✅ Active | Unified AI boundaries and pipeline (base architecture) |
| **ADR-023A AI Model Rev.** | `specs/06-Decision-Records/ADR-023A-unified-ai-architecture.md` | ✅ Active | 2-Model stack (gemma4:e4b Q8_0), BullMQ 2-queue, RAG embed scope, OCR auto-detect |
| **ADR-024 Intent Class.** | `specs/06-Decision-Records/ADR-024-intent-classification-strategy.md` | ✅ Active | Hybrid Pattern→LLM Fallback; ai_intent_patterns DB; Redis cache 5 min |
| **ADR-025 AI Tool Layer** | `specs/06-Decision-Records/ADR-025-ai-tool-layer-architecture.md` | ✅ Active | Server-side Tool dispatch; CASL-guarded bridge; ToolResult uses publicId only |
| **ADR-026 Chat UI** | `specs/06-Decision-Records/ADR-026-document-chat-ui-pattern.md` | ✅ Active | Side-panel Document Chat UI; useAiChat() hook; streaming response support |
| **ADR-027 AI Admin Console** | `specs/06-Decision-Records/ADR-027-ai-admin-console-and-dynamic-control.md` | ✅ Active | Admin Panel + dynamic model/prompt/intent control without redeploy |
| **ADR-028 Migration Refactor** | `specs/06-Decision-Records/ADR-028-migration-architecture-refactor.md` | ✅ Active | Staging Queue & post-migration cleanup |
| **ADR-029 Dynamic Prompts** | `specs/06-Decision-Records/ADR-029-dynamic-prompt-management.md` | ✅ Active | Prompt templates in DB (`ai_prompts`); Redis cache TTL 60s; versioned |
| **Backend Guidelines** | `specs/05-Engineering-Guidelines/05-02-backend-guidelines.md` | — | NestJS patterns |
| **Frontend Guidelines** | `specs/05-Engineering-Guidelines/05-03-frontend-guidelines.md` | — | Next.js patterns |
| **Testing Strategy** | `specs/05-Engineering-Guidelines/05-04-testing-strategy.md` | — | Coverage goals |
| **Git Conventions** | `specs/05-Engineering-Guidelines/05-05-git-conventions.md` | — | Commit/branch naming |
| **Code Snippets** | `specs/05-Engineering-Guidelines/05-06-code-snippets.md` | — | Reusable patterns |
| **i18n Guidelines** | `specs/05-Engineering-Guidelines/05-08-i18n-guidelines.md` | — | Localization rules |
| **Release Policy** | `specs/04-Infrastructure-OPS/04-08-release-management-policy.md` | — | Before deploy/hotfix |
| **UAT Criteria** | `specs/01-Requirements/01-05-acceptance-criteria.md` | — | Feature completeness |
---
@@ -265,7 +266,7 @@ Read `specs/05-Engineering-Guidelines/05-07-hybrid-uuid-implementation-plan.md`
5. **Password:** bcrypt 12 salt rounds, min 8 chars, rotate every 90 days
6. **Rate Limiting:** `ThrottlerGuard` on all auth endpoints
7. **File Upload:** Whitelist PDF/DWG/DOCX/XLSX/ZIP, max 50MB, ClamAV scan
8. **AI Isolation (ADR-023/023A):** Ollama on Admin Desktop ONLY — NO direct DB/storage access; 2-model stack `gemma4:e2b` + `nomic-embed-text`; all inference via BullMQ (`ai-realtime` / `ai-batch`)
8. **AI Isolation (ADR-023/023A):** Ollama on Admin Desktop ONLY — NO direct DB/storage access; 2-model stack `gemma4:e4b Q8_0` + `nomic-embed-text`; all inference via BullMQ (`ai-realtime` / `ai-batch`)
9. **Error Handling (ADR-007):** Use layered error classification with user-friendly messages
10. **AI Integration (ADR-023/023A):** RFA-First approach; n8n orchestrates Migration Phase only via DMS API — never calls Ollama directly; `QdrantService.search()` requires `projectPublicId` as mandatory param
@@ -427,7 +428,7 @@ Full glossary: `specs/00-overview/00-02-glossary.md`
**For AI Runtime Layer (ADR-024/025/026/027):**
- ADR-024: Pattern Layer first (ai_intent_patterns DB + Redis cache 5 min) → LLM Fallback (gemma4:e2b, semaphore max=3)
- ADR-024: Pattern Layer first (ai_intent_patterns DB + Redis cache 5 min) → LLM Fallback (gemma4:e4b Q8_0, semaphore max=3)
- ADR-025: Tool Registry dispatch — AI Gateway → Tool → Business Service; ToolResult DTO must use publicId only
- ADR-026: useAiChat() hook + side-panel UI; streaming response via SSE; TanStack Query cache
- ADR-027: Admin Console — dynamic model/prompt/intent control; CASL-guarded admin-only endpoints
@@ -479,6 +480,7 @@ When user asks about... check these files:
| "Document Chat UI" | ✅ | `ADR-026`, `specs/200-fullstacks/226-document-chat-ui-pattern/` | Side-panel; useAiChat() hook; streaming SSE; TanStack Query cache |
| "AI Admin Console" | ✅ | `ADR-027`, `specs/200-fullstacks/227-ai-admin-console/` | Dynamic model/prompt/intent control; admin-only CASL endpoints |
| "Migration refactor" | ✅ | `ADR-028`, `specs/200-fullstacks/228-migration-arch-refactor/` | Staging Queue; post-migration cleanup; validation gates |
| "Dynamic Prompt / Prompt" | ✅ | `ADR-029`, `specs/06-Decision-Records/ADR-029-dynamic-prompt-management.md` | ai_prompts table; Redis cache `ai:prompt:active:{type}` TTL 60s |
| "จัดการ document numbering" | ✅ | `ADR-002`, `specs/03-Data-and-Storage/03-04-document-numbering.md` | Redis Redlock + template system + preview/override workflows |
| "Audit ความปลอดภัย" | ✅ | `ADR-016`, `ADR-019`, `ADR-023`, `ADR-023A` | ตรวจสอบ UUID pattern, CASL Guard, AI Boundary และ Qdrant multi-tenancy |
| "แก้ bug / bugfix" | ✅ | `.agents/workflows/bugfix.md`, `error-catalog.md` | ใช้ bugfix workflow สำหรับเคสที่สาเหตุชัดเจน |
@@ -549,7 +551,8 @@ When user asks about... check these files:
- [ ] **Qdrant Multi-tenancy:** `projectPublicId` filter enforced
- [ ] **Human-in-the-loop:** AI outputs validated before use
- [ ] **Audit Logging:** All AI interactions logged to `ai_audit_logs`
- [ ] **2-Model Stack:** gemma4:e2b + nomic-embed-text verified
- [ ] **2-Model Stack:** gemma4:e4b Q8_0 + nomic-embed-text verified
- [ ] **Dynamic Prompts (ADR-029):** Prompt templates loaded from `ai_prompts` DB, not hardcoded
**Performance & Complex Logic:**
@@ -603,6 +606,7 @@ This file is a **quick reference**. For detailed information:
| Version | Date | Changes | Updated By |
| ------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------- |
| 1.9.7 | 2026-05-25 | Added ADR-029 Dynamic Prompt Management to Key Spec Files table; fixed gemma4 model name e2b→e4b Q8_0; added Dynamic Prompt context trigger; added ADR-029 to Tier 3 AI checklist; bumped last synced date | Windsurf AI |
| 1.9.6 | 2026-05-22 | Added ADR-024/025/026/027/028 to Key Spec Files table; Tier 3 expanded with AI Runtime Layer + Migration Pipeline tiers; Specialized Work section updated with ADR-024~028 patterns; 6 new Context-Aware Triggers; bumped Last synced date | Windsurf AI |
| 1.9.5 | 2026-05-18 | **Grill-with-Docs Session:** Domain terminology clarified (Correspondence = all doc types), Tier 3: SPECIALIZED WORK added, Context-Aware Triggers with Status column, Tier-specific Final Checklists | Windsurf AI |
| 1.9.4 | 2026-05-16 | Added ADR-015 Release Strategy to Key Spec Files table (Blue-Green deployment + release gates) | Human Dev |
+21 -19
View File
@@ -3,10 +3,10 @@
---
**title:** 'LCBP3-DMS Architecture Documentation'
**version:** 1.9.5
**version:** 1.9.7
**status:** active
**owner:** Nattanin Peancharoen
**last_updated:** 2026-05-22
**last_updated:** 2026-05-25
**related:**
- specs/02-Architecture/02-01-system-context.md
@@ -519,23 +519,24 @@ graph TB
### 6.1 Key ADRs Implemented
| ADR | Title | Status | Description |
| ------------ | ------------------------------- | --------- | ---------------------------------------------- |
| **ADR-001** | Unified Workflow Engine | ✅ Active | DSL-based workflow implementation |
| **ADR-002** | Document Numbering Strategy | ✅ Active | Document number generation + locking |
| **ADR-007** | Error Handling Strategy | ✅ Active | Layered error classification |
| **ADR-008** | Email Notification Strategy | ✅ Active | BullMQ + multi-channel notification |
| **ADR-009** | Database Migration Strategy | ✅ Active | Schema changes — edit SQL directly |
| **ADR-016** | Security Authentication | ✅ Active | Auth, RBAC, file upload security |
| **ADR-019** | Hybrid Identifier Strategy | ✅ Active | INT PK + UUIDv7 Public API |
| **ADR-021** | Workflow Context | ✅ Active | Integrated workflow & step attachments |
| **ADR-023** | Unified AI Architecture | ✅ Active | AI boundaries and pipeline |
| **ADR-023A** | AI Model Revision | ✅ Active | 2-Model stack with BullMQ queues |
| **ADR-024** | Intent Classification Strategy | ✅ Active | Hybrid Pattern → LLM Fallback intent routing |
| **ADR-025** | AI Tool Layer Architecture | ✅ Active | Server-side Tool dispatch, CASL-guarded bridge |
| **ADR-026** | Document Chat UI Pattern | ✅ Active | Side-panel document chat UI |
| **ADR-027** | AI Admin Console & Dynamic Ctrl | ✅ Active | AI Admin Panel + dynamic model/prompt control |
| **ADR-028** | Migration Architecture Refactor | ✅ Active | Staging Queue & post-migration cleanup |
| ADR | Title | Status | Description |
| ------------ | ------------------------------- | --------- | --------------------------------------------------------------------- |
| **ADR-001** | Unified Workflow Engine | ✅ Active | DSL-based workflow implementation |
| **ADR-002** | Document Numbering Strategy | ✅ Active | Document number generation + locking |
| **ADR-007** | Error Handling Strategy | ✅ Active | Layered error classification |
| **ADR-008** | Email Notification Strategy | ✅ Active | BullMQ + multi-channel notification |
| **ADR-009** | Database Migration Strategy | ✅ Active | Schema changes — edit SQL directly |
| **ADR-016** | Security Authentication | ✅ Active | Auth, RBAC, file upload security |
| **ADR-019** | Hybrid Identifier Strategy | ✅ Active | INT PK + UUIDv7 Public API |
| **ADR-021** | Workflow Context | ✅ Active | Integrated workflow & step attachments |
| **ADR-023** | Unified AI Architecture | ✅ Active | AI boundaries and pipeline |
| **ADR-023A** | AI Model Revision | ✅ Active | 2-Model stack with BullMQ queues |
| **ADR-024** | Intent Classification Strategy | ✅ Active | Hybrid Pattern → LLM Fallback intent routing |
| **ADR-025** | AI Tool Layer Architecture | ✅ Active | Server-side Tool dispatch, CASL-guarded bridge |
| **ADR-026** | Document Chat UI Pattern | ✅ Active | Side-panel document chat UI |
| **ADR-027** | AI Admin Console & Dynamic Ctrl | ✅ Active | AI Admin Panel + dynamic model/prompt control |
| **ADR-028** | Migration Architecture Refactor | ✅ Active | Staging Queue & post-migration cleanup |
| **ADR-029** | Dynamic Prompt Management | ✅ Active | Prompt templates in DB (`ai_prompts`), Redis cache TTL 60s, versioned |
### 6.2 ADR References
@@ -562,6 +563,7 @@ For detailed architectural decisions, please refer to:
| Version | Date | Changes |
| --------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| **1.9.7** | 2026-05-25 | Added ADR-029 Dynamic Prompt Management to ADR table; bumped version/date |
| **1.9.5** | 2026-05-22 | Added ADR-024/025/026/027/028 to ADR reference table; updated AI Architecture section heading; schema reference corrected to v1.9.0 |
| **1.9.2** | 2026-05-18 | Complete restructure following specs/02-Architecture format, added comprehensive diagrams, updated AI Architecture (ADR-023/023A) |
| **1.9.0** | 2026-05-13 | AI Architecture consolidation, Agent Infrastructure standardization |
+38
View File
@@ -1,5 +1,43 @@
# Version History
## 1.9.7 (2026-05-25)
### docs(ai): ADR-029 Dynamic Prompt Management + PaddleOCR Sidecar + Bug Fixes
#### Summary
เพิ่ม ADR-029 (Dynamic Prompt Management) สำหรับจัดการ Prompt Templates ใน DB และ Deploy PaddleOCR Sidecar บน Desk-5439 พร้อมแก้ไข Bug สำคัญในระบบ n8n, Correspondence และ Tags/Contracts
#### Changes
- **ADR-029**: สร้างเอกสาร `ADR-029-dynamic-prompt-management.md` — Prompt templates เก็บใน `ai_prompts` table, Redis cache `ai:prompt:active:{type}` TTL 60s; `activate()` รันใน DB transaction + Redis DEL; CASL guard `system.manage_all` บน mutations
- **PaddleOCR Sidecar (Desk-5439)**: สร้าง Docker Compose stack สำหรับ OCR sidecar — FastAPI (`app.py`) endpoints `/ocr` + `/normalize` + `/health`; CIFS volume เชื่อมต่อ QNAP (`//192.168.10.8/np-dms-as/data/uploads`); model download ตอน runtime (ไม่ pre-download ใน Dockerfile เพื่อหลีกเลี่ยง segfault)
- **n8n Workflow Fixes**: แก้ไข Migration Queue attachment UUID mismatch, normalize migration errors, debug n8n Submit AI Job pipeline
- **TransformInterceptor Bug Fix**: ลบ duplicate registration ออกจาก `main.ts` (เก็บเฉพาะ `APP_INTERCEPTOR` ใน `CommonModule`) — แก้ปัญหา double-wrapped response `{ data: { data: ... } }`
- **Correspondence Module Fixes**: `findOneByUuid()` ใช้ explicit JOIN + revision ordering (DESC) เพื่อให้ deterministic; normalize `recipient_type` whitespace variants ใน frontend detail component
- **Tags/Contracts UUID Fixes**: แก้ TypeORM Tag entity column-name mismatch; แก้ `handleEdit` ใน contracts page อ่าน `contract.project?.id` แทน `project?.publicId`
- **Playwright E2E**: ติดตั้ง MCP Playwright server, สร้าง E2E spec `frontend/e2e/workflow-adr021.spec.ts`
- **Root Docs**: อัปเดต `AGENTS.md` v1.9.7 (ADR-029, gemma4:e4b Q8_0 fix), `README.md`, `ARCHITECTURE.md`, `CHANGELOG.md`, `CONTRIBUTING.md` ทั้งหมดสะท้อน 29 ADRs
---
## 1.9.6 (2026-05-22)
### spec(agents): AGENTS.md v1.9.6 — AI Runtime Layer + Migration Pipeline Tiers
#### Summary
อัปเดต `AGENTS.md` ให้ครอบคลุม AI Runtime Layer (ADR-024~028) อย่างครบถ้วน พร้อมขยาย Tier 3 SPECIALIZED WORK และเพิ่ม Context-Aware Triggers ใหม่
#### Changes
- **Key Spec Files**: เพิ่ม ADR-024/025/026/027/028 ในตาราง Key Spec Files
- **Tier 3 Expanded**: เพิ่ม AI Runtime Layer (ADR-024/025/026/027) และ Migration Pipeline (ADR-028) ใน Specialized Work tiers
- **Context-Aware Triggers**: เพิ่ม 6 triggers ใหม่ (Intent classification, AI Tool Layer, Document Chat UI, AI Admin Console, Migration refactor, งานค้าง/resume)
- **Specialized Work Flow**: เพิ่ม subsection "For AI Runtime Layer" และ "For Migration Pipeline" ใน Development Flow
---
## 1.9.5 (2026-05-22)
### docs(adr): ADR-028 Migration Architecture Refactor + Root Docs Update
+6 -4
View File
@@ -1,6 +1,6 @@
# 📝 Contributing to LCBP3-DMS Specifications
> แนวทางการมีส่วนร่วมในการพัฒนาเอกสาร Specifications ของโครงการ LCBP3-DMS (v1.9.5)
> แนวทางการมีส่วนร่วมในการพัฒนาเอกสาร Specifications ของโครงการ LCBP3-DMS (v1.9.7)
ยินดีต้อนรับสู่คู่มือการมีส่วนร่วมในการพัฒนาเอกสาร Specifications! เอกสารนี้จะช่วยให้คุณเข้าใจวิธีการสร้าง แก้ไข และปรับปรุงเอกสารข้อกำหนดของโครงการได้อย่างมีประสิทธิภาพ
@@ -561,13 +561,15 @@ graph LR
| 1.9.3 | 2026-05-19 | Tech Lead | ADR-024 Intent Classification + ADR-025 AI Tool Layer + ADR-026 Chat UI (26 ADRs) |
| 1.9.4 | 2026-05-21 | Tech Lead | ADR-027 AI Admin Console & Dynamic Control (27 ADRs) |
| 1.9.5 | 2026-05-22 | Tech Lead | ADR-028 Migration Architecture Refactor + Root Docs Update (28 ADRs) |
| 1.9.6 | 2026-05-22 | Tech Lead | AGENTS.md v1.9.6 — AI Runtime Layer + Migration Pipeline Tiers expanded |
| 1.9.7 | 2026-05-25 | Tech Lead | ADR-029 Dynamic Prompt Management + PaddleOCR Sidecar infra + bug fixes (29 ADRs) |
**Current Version**: 1.9.5
**Current Version**: 1.9.7
**Status**: Approved
**Last Updated**: 2026-05-22
**Last Updated**: 2026-05-25
**Security**: 0 vulnerabilities (backend) + Compose stack hardened (27 findings → 0)
**Workflow Engine**: ADR-021 Integrated Context complete + RFA v1.9.0 finalized
**AI Runtime Layer**: ADR-024/025/026/027 Accepted — Intent Classification, Tool Layer, Chat UI, Admin Console
**AI Runtime Layer**: ADR-024/025/026/027/028/029 Active — Intent Classification, Tool Layer, Chat UI, Admin Console, Dynamic Prompts
```
### 5. UUID Conventions (ADR-019)
+8 -7
View File
@@ -3,26 +3,26 @@
> **Laem Chabang Port Phase 3 - Document Management System**
> ระบบบริหารจัดการเอกสารโครงการแบบครบวงจร สำหรับโครงการก่อสร้างท่าเรือแหลมฉบังระยะที่ 3
[![Version](https://img.shields.io/badge/version-1.9.5-blue.svg)](./CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-1.9.7-blue.svg)](./CHANGELOG.md)
[![License](https://img.shields.io/badge/license-Internal-red.svg)]()
[![Status](https://img.shields.io/badge/status-Production%20Ready-brightgreen.svg)]()
[![Docs](https://img.shields.io/badge/docs-10%2F10%20Gaps%20Closed-success.svg)](./specs/00-Overview/README.md)
---
## 📈 Current Status (As of 2026-05-22)
## 📈 Current Status (As of 2026-05-25)
**Version 1.9.5 — AI Intent/Tool Layer/Chat/Admin Console ADRs + Migration Arch Refactor (ADR-024~028)**
**Version 1.9.7 — ADR-029 Dynamic Prompt Management + PaddleOCR Sidecar + n8n Workflow Fixes**
> v1.9.0 shipped May 13; v1.9.2 (ADR-023A) May 15; v1.9.3~1.9.5 (ADR-024~028) May 1922.
> v1.9.5 (ADR-028) May 22; v1.9.6 (AGENTS update) May 22; v1.9.7 (ADR-029 + sidecar infra) May 25.
| Area | Status | หมายเหตุ |
| ---------------------- | ------------------------ | ------------------------------------------------------------------ |
| 🔧 **Backend** | ✅ Production Ready | NestJS 11, Express v5, 0 Vulnerabilities |
| 🎨 **Frontend** | ✅ 100% Complete | Next.js 16.2.0, React 19.2.4, ESLint 9 |
| 💾 **Database** | ✅ Schema v1.9.0 Stable | MariaDB 11.8, No-migration Policy |
| 📘 **Documentation** | ✅ **10/10 Gaps Closed** | Product Vision → Release Policy (28 ADRs — v1.9.5) |
| 🤖 **AI Architecture** | ✅ 28 ADRs Accepted | ADR-023A infra + ADR-024/025/026/027/028 runtime layer |
| 📘 **Documentation** | ✅ **10/10 Gaps Closed** | Product Vision → Release Policy (29 ADRs — v1.9.7) |
| 🤖 **AI Architecture** | ✅ 29 ADRs Accepted | ADR-023A infra + ADR-024~029 runtime + dynamic prompts |
| 🔄 **Workflow Engine** | ✅ ADR-021 Integrated | Transmittals & Circulation with Integrated Context |
| 🧪 **Testing** | ✅ UAT Ready | E2E + Acceptance Criteria ready |
| 🚀 **Deployment** | ✅ Production Ready | Blue-Green on QNAP Container Station |
@@ -52,6 +52,8 @@ LCBP3-DMS เป็นระบบบริหารจัดการเอก
- 🤖 **AI-Assisted Migration** - Ollama + n8n นำเข้าเอกสารเก่า ~20,000 ไฟล์ (ADR-023/028)
- 💬 **AI Document Assistant** - Intent Classification + Tool Layer + Document Chat UI (ADR-024/025/026)
- ⚙️ **AI Admin Console** - Dynamic model/prompt/intent control (ADR-027)
- 📝 **Dynamic Prompt Management** - Prompt templates in DB `ai_prompts`, Redis cache TTL 60s (ADR-029)
- 🔬 **PaddleOCR Sidecar** - FastAPI OCR service on Desk-5439 with CIFS mount to QNAP
---
@@ -548,6 +550,5 @@ lcbp3-dms/
**Built with ❤️ for LCBP3 Project**
[Documentation](./docs) • [Issues](https://git.np-dms.work/lcbp3/lcbp3-dms/issues) • [Changelog](./CHANGELOG.md)
เพิ่มชั่วคราวเพื่อ push
</div>
+195
View File
@@ -8,6 +8,7 @@
- 2026-05-25 (Session 5): N8N Workflow Debug — แก้ Submit AI Job (jsonBody serialization + RBAC permission gap) และเพิ่ม checksum-based dedup ใน FileStorageService.upload().
- 2026-05-25 (Session 6): AI Model Management (ADR-027) — เพิ่มระบบเลือกโมเดล AI แบบไดนามิกผ่าน AI Admin Console: สร้าง `ai_available_models` table + entity, extend `AiSettingsService` ด้วย methods CRUD โมเดล, add REST endpoints, update frontend UI ด้วย Select dropdown และ model list management, update `OllamaService` ใช้ DB-configured model แทน ENV เท่านั้น.
- 2026-05-25 (Session 7): PaddleOCR Sidecar setup บน Desk-5439 — สร้าง FastAPI sidecar (port 8765) รองรับ `/ocr` + `/normalize`, แก้ AggregateError ใน ocr.service.ts, เพิ่ม path remapping (`OCR_SIDECAR_UPLOAD_BASE`), CIFS volume mount จาก QNAP.
- 2026-05-26: เพิ่ม system memories ที่หายไป — QNAP SSH Key Authentication, TransformInterceptor double registration, ADR-021 Transmittals/Circulation integration, Correspondence detail fixes, Playwright E2E setup, Tag/Contract UUID fixes.
-->
# 🧠 Agent Long-term Project Memory
@@ -447,6 +448,200 @@ OCR_SIDECAR_UPLOAD_BASE=/mnt/uploads (env var)
---
### Session 8 — 2026-05-26 (System Memories Consolidation)
#### QNAP SSH Key Authentication & CI/CD Deployment
**Infrastructure:**
- QNAP `192.168.10.8` — target deploy server (runs Gitea + app containers)
- ASUSTOR `192.168.10.9` — Gitea runner
**SSH Key Setup (Persistent):**
- Private key: `/etc/config/ssh/gitea-runner`
- Public key: `/etc/config/ssh/gitea-runner.pub`
- Fingerprint: `SHA256:OhPbRe9vi4aWTyzBqCQ6T3MLl+JK9lFtH5bPrx+ICPw`
- Authorized keys: `/etc/config/ssh/authorized_keys` (symlinked from `/root/.ssh/`)
- QNAP SSH config: `/etc/config/ssh/sshd_config` (persistent — ใช้อันนี้เท่านั้น ไม่ใช้ `/etc/ssh/sshd_config`)
**Critical Fix: AuthorizedKeysFile**
```
AuthorizedKeysFile /etc/config/ssh/authorized_keys
```
ต้องใช้ **absolute path** — ถ้าใช้ `.ssh/authorized_keys` จะ resolve ไปที่ `/share/homes/admin/.ssh/` ซึ่งผิด (admin home = `/share/homes/admin` แต่ symlink อยู่ที่ `/root/.ssh`)
**Reload QNAP SSH daemon**
```bash
kill -HUP $(ps | grep "/usr/sbin/sshd -f /etc/config" | grep -v grep | awk '{print $1}')
```
ไม่มี `pgrep` และไม่มี `systemctl` บน QNAP
**Gitea Secrets:**
| Secret | Value |
|--------|-------|
| HOST | `192.168.10.8` |
| PORT | `22` |
| USERNAME | `admin` |
| SSH_KEY | private key content from `/etc/config/ssh/gitea-runner` |
**deploy.sh Fix:**
```bash
# scripts/deploy.sh line 10 — correct path:
COMPOSE_FILE="$SOURCE_DIR/specs/04-Infrastructure-OPS/04-00-docker-compose/QNAP/app/docker-compose-app.yml"
```
ไม่ใช่ `...04-00-docker-compose/docker-compose-app.yml` (ขาด `QNAP/app/`)
**Root Causes (ทั้งหมด):**
1. `authorized_keys` เสียหาย — 2 keys บรรทัดเดียว
2. SSH key pair หายหลัง reboot — QNAP `/` เป็น RAM, ต้องเก็บใน `/etc/config/`
3. `AuthorizedKeysFile` ใช้ relative path — resolve ผิด directory
4. HOST secret ชี้ไปผิด server (Go SSH) — แก้เป็น `192.168.10.8:22`
5. `deploy.sh` COMPOSE_FILE path ผิด — ขาด `QNAP/app/` subdirectory
#### Backend TransformInterceptor Double Registration Bug
**Issue:** API responses were double-wrapped `{ data: { data: actualData } }` causing frontend detail pages to fail loading data.
**Root Cause:** TransformInterceptor registered in TWO places:
1. `backend/src/main.ts`: `app.useGlobalInterceptors(new TransformInterceptor())`
2. `backend/src/common/common.module.ts`: `{ provide: APP_INTERCEPTOR, useClass: TransformInterceptor }`
**Fix:** Removed duplicate registration from `main.ts` (keep only APP_INTERCEPTOR in CommonModule).
**Why list page still worked:** Paginated responses were re-detected as paginated by second interceptor, preventing double-nesting. Non-paginated (detail) endpoints were affected.
**Verification:** `curl http://localhost:3001/api/correspondences/{uuid}` now returns single-wrapped `{ data: {...} }` instead of double-wrapped.
**Pattern to Avoid:** Never register global interceptors/filters in both `main.ts` AND via `APP_INTERCEPTOR`/`APP_FILTER` providers.
#### ADR-021 Integration: Transmittals & Circulation
**Summary:** Successfully integrated ADR-021 (Integrated Workflow Context & Step-specific Attachments) into Transmittals and Circulation modules. All backend services, frontend pages, and tests are wired to the Unified Workflow Engine.
**Backend Changes (B1-B9):**
- **WorkflowEngineService**: Added `getInstanceByEntity(entityType, entityId)` for polymorphic workflow instance lookup
- **TransmittalService**:
- Expose `workflowInstanceId`, `workflowState`, `availableActions` in `findOneByUuid()`
- Added purpose filter to `findAll()`
- Added `submit()` with EC-RFA-004 validation (prevents submission if any item correspondence is DRAFT)
- Starts workflow instance `TRANSMITTAL_FLOW_V1` and updates CorrespondenceRevision status
- **TransmittalController**: Added `POST /:uuid/submit` endpoint with RBAC and Audit
- **TransmittalModule**: Imported `WorkflowEngineModule` and `CorrespondenceRevision`
- **CirculationService**:
- Expose workflow fields in `findOneByUuid()`
- Added `reassignRouting()` (EC-CIRC-001) for PENDING routing reassignment
- Added `forceClose()` (EC-CIRC-002) with transactional rollback and reason validation
- **CirculationController**: Added `PATCH /:uuid/routing/:routingId/reassign` and `POST /:uuid/force-close`
- **Circulation Entity**: Added `deadlineDate` column for EC-CIRC-003 Overdue badge
- **Schema Delta**: `05-add-circulation-deadline.sql` per ADR-009 (no migrations)
**Frontend Changes (F1-F7):**
- **Types**: Extended `Transmittal` and `Circulation` interfaces with workflow fields; added `deadlineDate` to Circulation
- **Hooks**: Created `useTransmittal()` and extended `useCirculation()` hooks with TanStack Query
- **Detail Pages**:
- Both wired with `IntegratedBanner` and `WorkflowLifecycle` using live workflow data
- Circulation page includes EC-CIRC-003 Overdue badge logic (`isOverdue()`)
- **List Page**: Added purpose filter dropdown to `transmittals/page.tsx`
**Tests (T1-T2): 19/19 Passing**
- **TransmittalService**: 7 tests covering EC-RFA-004 validation, workflow instance creation, and error cases
- **CirculationService**: 12 tests covering EC-CIRC-001 (reassign), EC-CIRC-002 (forceClose), EC-CIRC-003 (deadlineDate exposure)
**Key Technical Decisions:**
- Followed ADR-019 UUID handling (no parseInt, use string UUIDs)
- Used ADR-009 direct schema edits (no TypeORM migrations)
- Enforced RBAC with CASL guards and Audit decorators
- Implemented transactional force-close with proper rollback
- Maintained existing patterns for error handling and service architecture
**Remaining Work:**
- I1: i18n keys for new workflow actions (low priority)
#### Correspondence Detail Display Fixes
**Issue:** `/correspondences/[uuid]` detail display inconsistency
**Fix:** Made backend `findOneByUuid` query deterministic with explicit relation joins and revision ordering (rev.revisionNumber DESC, rev.createdAt DESC), and normalized recipient_type values in frontend detail page before TO/CC filtering to handle whitespace variants per schema (e.g., 'CC ').
**Files Modified:**
- `backend/src/modules/correspondence/correspondence.service.ts`
- `frontend/components/correspondences/detail.tsx`
#### Correspondence Create Permission Bypass
**Issue:** Users without primaryOrganizationId could not create documents even with system.manage_all permission
**Fix:** In backend CorrespondenceService.create flow, users without primaryOrganizationId can still create when they have system.manage_all and provide originatorId. Validation now resolves originator organization under that permission instead of immediately throwing 'User must belong to an organization to create documents'. Added regression test in correspondence.service.spec.ts.
**Extension:** Applied same pattern to RFA, Transmittal, and Circulation create endpoints — they now accept optional originatorId and allow creation for users with system.manage_all even when primaryOrganizationId is null. Added permission-gated impersonation checks in their services to prevent unauthorized cross-organization creation.
#### Playwright E2E Testing Setup
**Test Stack:**
- **Backend**: Jest (Unit + Integration + E2E)
- **Frontend**: Vitest (Unit) + Playwright (E2E)
**MCP Server Setup (Windsurf):**
```json
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["-y", "@playwright/mcp@latest"]
}
}
}
```
**Windsurf Cascade Tools:**
- `browser_navigate` - เปิด URL
- `browser_click` - คลิก element
- `browser_type` - พิมพ์ข้อความ
- `browser_take_screenshot` - ถ่าย screenshot
- `browser_evaluate` - รัน JavaScript
**Run E2E Tests:**
```bash
cd frontend
npx playwright test # Run all
npx playwright test --ui # Debug mode
npx playwright test --headed # See browser
npx playwright show-report # Generate report
```
**E2E Script Location:** `frontend/e2e/workflow-adr021.spec.ts`
#### Tag Creation and Contract UUID Fixes
**Issue 1:** `/admin/doc-control/reference/tags` needed a list-level Project dropdown filter and Tag creation could fail due to TypeORM Tag entity column-name mismatches.
**Fix:** Added selectedProjectId filter in frontend tags page and mapped backend Tag entity fields to schema names (project_id, tag_name, color_code, created_by, created_at, updated_at, deleted_at).
**Issue 2:** Frontend contract detail page typecheck failure — `contract.project?.id` vs `contract.project?.publicId`
**Fix:** In `frontend/app/(admin)/admin/doc-control/contracts/page.tsx`, handleEdit must read nested project UUID from contract.project?.id (not project?.publicId) because Contract.project is typed and returned as { id: string; projectCode; projectName }.
---
## 🎯 10. แผนงานขั้นต่อไป (Next Session Focus)
### N8N Migration (งานหลักที่เหลือ)