Files
lcbp3/specs/88-logs/session-2026-06-14-correspondence-review-fixes.md
T
admin 67da186672
CI / CD Pipeline / build (push) Failing after 3m23s
CI / CD Pipeline / deploy (push) Has been skipped
feat(ai): implement unified prompt management UX/UI (ADR-037)
- Add context config endpoints (GET/PUT /api/ai/prompts/:type/:version/context-config)
- Add execution profile endpoints (CRUD /api/ai/execution-profiles)
- Add sandbox RAG Prep endpoint (POST /api/ai/admin/sandbox/rag-prep)
- Create Prompt Management UI with multi-type support
- Add ContextConfigEditor, PromptEditor, RuntimeParametersPanel components
- Add SandboxTabs for 3-step workflow (OCR, Extract, RAG Prep)
- Add database deltas for ai_execution_profiles and additional prompt types
- Update quickstart.md with production backend URLs
- Add comprehensive test coverage for new features
2026-06-14 19:55:43 +07:00

87 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Session — 2026-06-14 (Correspondence Module Review Fixes + RFA ADR-001/021 Refactor)
## Summary
สองงานหลักใน session นี้:
1. **Correspondence Module Code Review Fixes** — แก้ทุก item จาก `speckit-reviewer` report (HIGH + MEDIUM + Remaining)
2. **RFA Service ADR-001/021 Migration** — User refactor `rfa.service.ts` ตัด deprecated routing-template entities ออก และ rewire workflow ผ่าน Unified Workflow Engine
---
## Part 1: Correspondence Module Review Fixes
### ปัญหาที่พบ (Root Cause)
รายการจาก code review report ที่ต้องแก้ไข:
| # | Severity | ปัญหา |
|---|----------|-------|
| 1 | HIGH | `throw new Error` ใน `processAction` — ละเมิด ADR-007 |
| 2 | HIGH | CSV export capped ที่ 10 rows เพราะ `findAll` ใช้ default `limit: 10` |
| 3 | MEDIUM | `bulkCancel` empty `catch {}` — ไม่ log error |
| 4 | MEDIUM | `escapeCsv` ไม่กัน formula injection (OWASP) |
| 5 | MEDIUM | `update()` re-index search ด้วย hardcoded `status: 'DRAFT'` |
| 6 | LOW | `processAction` ไม่มี `@Audit` decorator |
| R1 | Remaining | `recipients` DTO ไม่มี nested validation |
| R2 | Remaining | `PUT /:uuid` ใช้ permission `correspondence.create` แทน `correspondence.edit` |
| R3 | Remaining | ไม่มี Idempotency protection บน mutation endpoints |
### การแก้ไข (Fix)
| ไฟล์ | การเปลี่ยนแปลง |
|------|---------------|
| `correspondence.controller.ts` | เพิ่ม `import { ValidationException }` + แทน `throw new Error` ด้วย `throw new ValidationException` |
| `correspondence.controller.ts` | เพิ่ม `@Audit('correspondence.workflow_action', 'correspondence')` บน `processAction` |
| `correspondence.controller.ts` | แก้ `PUT /:uuid``@RequirePermission('correspondence.edit')` (permission id=73 มีใน seed แล้ว) |
| `correspondence.controller.ts` | เพิ่ม `@UseInterceptors(IdempotencyInterceptor)` ทุก 7 mutation endpoints |
| `correspondence.service.ts` | `bulkCancel` catch block เพิ่ม `this.logger.warn(...)` |
| `correspondence.service.ts` | `exportCsv` force `limit: 10000` override |
| `correspondence.service.ts` | `escapeCsv` เพิ่ม prefix `'` สำหรับ values เริ่มต้นด้วย `=`, `+`, `-`, `@`, `\t`, `\r` |
| `correspondence.service.ts` | `update()` re-index ใช้ `currentRevisionStatus` จาก `revisions.find(r => r.isCurrent)` แทน `'DRAFT'` |
| `dto/create-correspondence.dto.ts` | เพิ่ม `RecipientDto` class + `@ValidateNested({ each: true })` + `@Type(() => RecipientDto)` |
### กฎที่ Lock แล้ว
- CSV export ต้อง override `limit` ก่อน call `findAll` เสมอ (ห้ามใช้ pagination default)
- `escapeCsv` ต้องกัน OWASP formula injection (prefix `'` สำหรับ `=+@\t\r`)
- Mutation endpoints ใน correspondence controller ต้องมี `@UseInterceptors(IdempotencyInterceptor)`
- `PUT /:uuid` ต้องใช้ `correspondence.edit` permission (ไม่ใช่ `correspondence.create`)
---
## Part 2: RFA Service ADR-001/021 Migration (User-driven)
### สิ่งที่ User เปลี่ยนแปลง
| ไฟล์ | การเปลี่ยนแปลง |
|------|---------------|
| `rfa.service.ts` | ลบ `CorrespondenceRouting`, `RoutingTemplate`, `RoutingTemplateStep` imports และ repos |
| `rfa.service.ts` | เพิ่ม `RfaMapped` interface fields: `workflowInstanceId`, `workflowState`, `availableActions` (ADR-021) |
| `rfa.service.ts` | เพิ่ม static constants: `WORKFLOW_CODE`, `STATE_TO_STATUS`, `DEFAULT_APPROVED_CODE` |
| `rfa.service.ts` | EC-RFA-001 check ย้ายเข้า transaction + `FOR UPDATE` lock (กัน TOCTOU race condition) |
| `rfa.service.ts` | `createInstance` ใช้ `RfaService.WORKFLOW_CODE` constant แทน hardcoded `'RFA_APPROVAL'` |
| `rfa.service.ts` | `findOneByUuid` ดึง workflow instance ผ่าน `getInstanceByEntity()` และ expose ADR-021 fields |
| `rfa.service.ts` | `submit()` ตัด `templateId` parameter ออก — rewire ผ่าน `workflowEngine.processTransition()` |
| `rfa.service.ts` | `processAction()` ตัด routing-template lookup ออก — ใช้ `workflowEngine.processTransition()` |
| `rfa.service.ts` | เพิ่ม `syncRevisionStatus()` helper: map workflow state → RFA status code + approve code |
| `rfa.service.ts` | เพิ่ม `notifyRecipients()` helper: ADR-008 async notify ผ่าน `notificationService.send()` |
| `rfa.module.ts` | ตัด deprecated routing-template entities ออกจาก `TypeOrmModule.forFeature([...])` |
### กฎที่ Lock แล้ว
- RFA ใช้ `workflowEngine.processTransition()` เป็น single entry point สำหรับ submit/approve/reject
- `syncRevisionStatus()` ต้องใช้ `STATE_TO_STATUS` map — ห้าม hardcode status code
- EC-RFA-001 ต้องทำใน transaction ด้วย `FOR UPDATE` lock (ไม่ใช่ก่อน transaction)
- Notification ต้องเรียกหลัง transaction commit แบบ `void ... .catch(...)` (ADR-008)
---
## Verification
- [ ] `pnpm --filter backend build` ผ่าน (ต้องตรวจสอบหลัง rfa.module.ts cleanup ครบ)
- [ ] `pnpm --filter backend exec tsc --noEmit` ไม่มี type error
- [ ] ทดสอบ `POST /correspondences` with `Idempotency-Key` header — duplicate request ต้องได้ cached response
- [ ] ทดสอบ CSV export มีมากกว่า 10 rows
- [ ] ทดสอบ `PUT /correspondences/:uuid` กับ user ที่มี `correspondence.edit` permission
- [ ] ทดสอบ `recipients` DTO validation กัน invalid `type` (ไม่ใช่ TO/CC)