diff --git a/.agents/rules/00-project-context.md b/.agents/rules/00-project-context.md index fce0cefd..a598b1ed 100644 --- a/.agents/rules/00-project-context.md +++ b/.agents/rules/00-project-context.md @@ -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 | --- diff --git a/.agents/rules/04-domain-terminology.md b/.agents/rules/04-domain-terminology.md index 14524d8f..54cf9e15 100644 --- a/.agents/rules/04-domain-terminology.md +++ b/.agents/rules/04-domain-terminology.md @@ -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 diff --git a/.agents/rules/05-forbidden-actions.md b/.agents/rules/05-forbidden-actions.md index d59a9f40..1f4f607a 100644 --- a/.agents/rules/05-forbidden-actions.md +++ b/.agents/rules/05-forbidden-actions.md @@ -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) diff --git a/.agents/rules/07-frontend-patterns.md b/.agents/rules/07-frontend-patterns.md index 9d590a9d..28bed1aa 100644 --- a/.agents/rules/07-frontend-patterns.md +++ b/.agents/rules/07-frontend-patterns.md @@ -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 })); diff --git a/.agents/rules/08-development-flow.md b/.agents/rules/08-development-flow.md index 7fe194f9..c1bef0bc 100644 --- a/.agents/rules/08-development-flow.md +++ b/.agents/rules/08-development-flow.md @@ -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 → วางแผนต่อโดยไม่ทำงานซ้ำ | diff --git a/.agents/rules/09-commit-checklist.md b/.agents/rules/09-commit-checklist.md index 1b81f5b2..0ebf27d6 100644 --- a/.agents/rules/09-commit-checklist.md +++ b/.agents/rules/09-commit-checklist.md @@ -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` diff --git a/.agents/rules/10-error-handling.md b/.agents/rules/10-error-handling.md index ec2a5d0e..76edf180 100644 --- a/.agents/rules/10-error-handling.md +++ b/.agents/rules/10-error-handling.md @@ -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); } } diff --git a/.agents/rules/11-ai-integration.md b/.agents/rules/11-ai-integration.md index 038b2170..864849ad 100644 --- a/.agents/rules/11-ai-integration.md +++ b/.agents/rules/11-ai-integration.md @@ -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 { // 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) diff --git a/.windsurf/rules/00-project-context.md b/.windsurf/rules/00-project-context.md index fa7c2b73..3e965e84 100644 --- a/.windsurf/rules/00-project-context.md +++ b/.windsurf/rules/00-project-context.md @@ -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 | --- diff --git a/.windsurf/rules/04-domain-terminology.md b/.windsurf/rules/04-domain-terminology.md index cf3005f8..4db3276d 100644 --- a/.windsurf/rules/04-domain-terminology.md +++ b/.windsurf/rules/04-domain-terminology.md @@ -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 diff --git a/.windsurf/rules/05-forbidden-actions.md b/.windsurf/rules/05-forbidden-actions.md index 9017c34d..4f024cb4 100644 --- a/.windsurf/rules/05-forbidden-actions.md +++ b/.windsurf/rules/05-forbidden-actions.md @@ -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) diff --git a/.windsurf/rules/08-development-flow.md b/.windsurf/rules/08-development-flow.md index 19c15cdc..832e8b87 100644 --- a/.windsurf/rules/08-development-flow.md +++ b/.windsurf/rules/08-development-flow.md @@ -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 → วางแผนต่อโดยไม่ทำงานซ้ำ | diff --git a/.windsurf/rules/11-ai-integration.md b/.windsurf/rules/11-ai-integration.md index 65476700..6147c599 100644 --- a/.windsurf/rules/11-ai-integration.md +++ b/.windsurf/rules/11-ai-integration.md @@ -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 { // 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) diff --git a/AGENTS.md b/AGENTS.md index f765dbbc..014f5204 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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 | diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index fe0846cb..0f833dfa 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -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 | diff --git a/CHANGELOG.md b/CHANGELOG.md index bc083d41..0a854c46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2c6c1321..191ed9c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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) diff --git a/README.md b/README.md index 33065788..4433407b 100644 --- a/README.md +++ b/README.md @@ -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 19–22. +> 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 diff --git a/memory/agent-memory.md b/memory/agent-memory.md index 1a8a883f..f76d741a 100644 --- a/memory/agent-memory.md +++ b/memory/agent-memory.md @@ -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 (งานหลักที่เหลือ)