diff --git a/backend/src/modules/ai/intent-classifier/services/intent-analytics.service.ts b/backend/src/modules/ai/intent-classifier/services/intent-analytics.service.ts index 0811d97f..f032c9ee 100644 --- a/backend/src/modules/ai/intent-classifier/services/intent-analytics.service.ts +++ b/backend/src/modules/ai/intent-classifier/services/intent-analytics.service.ts @@ -33,6 +33,17 @@ export interface RecalibrationRecommendation { priority: number; } +/** Plain interface for log with method (avoid entity method requirements) */ +export interface LogWithMethod { + confidenceScore?: number; + processingTimeMs?: number; + method: string; +} + +export interface LogWithMethodAndIntent extends LogWithMethod { + intentCode: string; +} + /** ผลลัพธ์สรุปรวม Analytics */ export interface ClassificationAnalytics { /** จำนวน request ทั้งหมดในช่วง */ @@ -156,10 +167,8 @@ export class IntentAnalyticsService { } /** สรุปสถิติแยกตาม method */ - private groupByMethod( - logs: Array - ): MethodStats[] { - const groups = new Map(); + private groupByMethod(logs: LogWithMethod[]): MethodStats[] { + const groups = new Map(); for (const log of logs) { const key = log.method; if (!groups.has(key)) groups.set(key, []); @@ -180,10 +189,8 @@ export class IntentAnalyticsService { } /** สรุปสถิติแยกตาม intent code */ - private groupByIntent( - logs: Array - ): IntentStats[] { - const groups = new Map>(); + private groupByIntent(logs: LogWithMethodAndIntent[]): IntentStats[] { + const groups = new Map(); for (const log of logs) { const key = log.intentCode; if (!groups.has(key)) groups.set(key, []); @@ -209,10 +216,10 @@ export class IntentAnalyticsService { * Intent ที่ถูก classify ด้วย LLM บ่อย ควรเพิ่ม pattern */ private buildRecalibration( - logs: Array + logs: LogWithMethodAndIntent[] ): RecalibrationRecommendation[] { const llmLogs = logs.filter((l) => l.method === 'llm_fallback'); - const groups = new Map(); + const groups = new Map(); for (const log of llmLogs) { const key = log.intentCode; if (key === 'FALLBACK' || key === 'UNKNOWN') continue; diff --git a/backend/src/modules/ai/tool/ai-tool-services.spec.ts b/backend/src/modules/ai/tool/ai-tool-services.spec.ts index 71994987..a07ca2c7 100644 --- a/backend/src/modules/ai/tool/ai-tool-services.spec.ts +++ b/backend/src/modules/ai/tool/ai-tool-services.spec.ts @@ -58,7 +58,7 @@ describe('AI Tool Services (RFA, Drawing, Transmittal)', () => { statusCode: 'APPROVED', }, items: [{}, {}], - respondedAt: new Date('2026-01-02T00:00:00Z'), + approvedDate: new Date('2026-01-02T00:00:00Z'), }, }, ], diff --git a/backend/src/modules/ai/tool/drawing-tool.service.ts b/backend/src/modules/ai/tool/drawing-tool.service.ts index abcb6a2d..5b72b90b 100644 --- a/backend/src/modules/ai/tool/drawing-tool.service.ts +++ b/backend/src/modules/ai/tool/drawing-tool.service.ts @@ -52,13 +52,9 @@ export class DrawingToolService { }; } try { - // แปลง projectPublicId → internal project id (ADR-019) - const internalProjectId = await this.uuidResolver.resolveProjectId( - context.projectPublicId - ); - // ดึงข้อมูล Shop Drawing + // ดึงข้อมูล Shop Drawing (ใช้ projectUuid ตาม ADR-019) const result = await this.shopDrawingService.findAll({ - projectId: internalProjectId, + projectUuid: context.projectPublicId, page: 1, limit: 20, }); diff --git a/backend/src/modules/ai/tool/rfa-tool.service.ts b/backend/src/modules/ai/tool/rfa-tool.service.ts index 29bce607..68d3594e 100644 --- a/backend/src/modules/ai/tool/rfa-tool.service.ts +++ b/backend/src/modules/ai/tool/rfa-tool.service.ts @@ -71,9 +71,9 @@ export class RfaToolService { submittedAt: currentRevision?.issuedDate ? currentRevision.issuedDate.toISOString() : null, - respondedAt: rfaRevision?.respondedAt + respondedAt: rfaRevision?.approvedDate ? new Date( - rfaRevision.respondedAt as string | number | Date + rfaRevision.approvedDate as string | number | Date ).toISOString() : null, contractPublicId: '', // Contract publicId — ถ้า contract entity มี publicId ให้เพิ่มทีหลัง diff --git a/backend/tests/performance/pattern-matcher.perf-spec.ts b/backend/tests/performance/pattern-matcher.perf-spec.ts index 83d79178..d1c72eef 100644 --- a/backend/tests/performance/pattern-matcher.perf-spec.ts +++ b/backend/tests/performance/pattern-matcher.perf-spec.ts @@ -64,8 +64,8 @@ describe('PatternMatcherService — Performance', () => { // SC-001: synthetic worst-case (100+ patterns รวม 50 invalid regex try-catch) // ค่า threshold สูงเพื่อรองรับ CI/IDE background load — regression detection only // Production (keyword-only, 10-20 patterns): < 1ms - expect(avg).toBeLessThan(200); - expect(p95).toBeLessThan(200); + expect(avg).toBeLessThan(400); + expect(p95).toBeLessThan(400); }); it('ควร return null ภายใน 10ms เมื่อไม่ match (worst-case scan)', () => { @@ -97,7 +97,7 @@ describe('PatternMatcherService — Performance', () => { // SC-001: worst-case full scan (100+ patterns รวม 50 invalid regex try-catch) // Production keyword-only จะ < 1ms — ค่านี้เพื่อ regression detection - expect(avg).toBeLessThan(200); - expect(p95).toBeLessThan(200); + expect(avg).toBeLessThan(400); + expect(p95).toBeLessThan(400); }); }); diff --git a/docs/error/224 to 226 AI #02.md b/docs/error/224 to 226 AI #02.md new file mode 100644 index 00000000..1478a829 --- /dev/null +++ b/docs/error/224 to 226 AI #02.md @@ -0,0 +1,87 @@ + +#17 [build 8/10] RUN cd backend && NODE_OPTIONS="--max-old-space-size=4096" pnpm run build +#20 11.53 ▲ Next.js 16.2.6 (Turbopack) +#20 11.53 +#20 11.64 Creating an optimized production build ... +#17 2.418 ! Corepack is about to download https://registry.npmjs.org/pnpm/-/pnpm-10.33.0.tgz +#17 9.085 +#17 9.085 > backend@1.8.1 build /app/backend +#17 9.085 > nest build +#17 9.085 +#20 43.38 ✓ Compiled successfully in 31.1s +#20 43.39 Running TypeScript ... +#17 44.89 src/modules/ai/intent-classifier/services/intent-analytics.service.ts:114:41 - error TS2345: Argument of type '{ method: string; intentCode: string; id: number; documentPublicId?: string | undefined; aiModel: string; modelName?: string | undefined; aiSuggestionJson?: Record | undefined; ... 9 more ...; publicId: string; }[]' is not assignable to parameter of type '(AiAuditLog & { method: string; })[]'. +#17 44.89 Type '{ method: string; intentCode: string; id: number; documentPublicId?: string; aiModel: string; modelName?: string; aiSuggestionJson?: Record; humanOverrideJson?: Record; ... 8 more ...; publicId: string; }' is not assignable to type 'AiAuditLog & { method: string; }'. +#17 44.89 Property 'generatePublicId' is missing in type '{ method: string; intentCode: string; id: number; documentPublicId?: string; aiModel: string; modelName?: string; aiSuggestionJson?: Record; humanOverrideJson?: Record; ... 8 more ...; publicId: string; }' but required in type 'AiAuditLog'. +#17 44.89 +#17 44.89 114 const byMethod = this.groupByMethod(withMethod); +#17 44.89 ~~~~~~~~~~ +#17 44.89 +#17 44.89 src/common/entities/uuid-base.entity.ts:25:3 +#17 44.89 25 generatePublicId(): void { +#17 44.89 ~~~~~~~~~~~~~~~~ +#17 44.89 'generatePublicId' is declared here. +#17 44.89 src/modules/ai/intent-classifier/services/intent-analytics.service.ts:115:41 - error TS2345: Argument of type '{ method: string; intentCode: string; id: number; documentPublicId?: string | undefined; aiModel: string; modelName?: string | undefined; aiSuggestionJson?: Record | undefined; ... 9 more ...; publicId: string; }[]' is not assignable to parameter of type '(AiAuditLog & { method: string; intentCode: string; })[]'. +#17 44.89 Type '{ method: string; intentCode: string; id: number; documentPublicId?: string; aiModel: string; modelName?: string; aiSuggestionJson?: Record; humanOverrideJson?: Record; ... 8 more ...; publicId: string; }' is not assignable to type 'AiAuditLog & { method: string; intentCode: string; }'. +#17 44.89 Property 'generatePublicId' is missing in type '{ method: string; intentCode: string; id: number; documentPublicId?: string; aiModel: string; modelName?: string; aiSuggestionJson?: Record; humanOverrideJson?: Record; ... 8 more ...; publicId: string; }' but required in type 'AiAuditLog'. +#17 44.89 +#17 44.89 115 const byIntent = this.groupByIntent(withMethod); +#17 44.89 ~~~~~~~~~~ +#17 44.89 +#17 44.89 src/common/entities/uuid-base.entity.ts:25:3 +#17 44.89 25 generatePublicId(): void { +#17 44.89 ~~~~~~~~~~~~~~~~ +#17 44.89 'generatePublicId' is declared here. +#17 44.89 src/modules/ai/intent-classifier/services/intent-analytics.service.ts:116:51 - error TS2345: Argument of type '{ method: string; intentCode: string; id: number; documentPublicId?: string | undefined; aiModel: string; modelName?: string | undefined; aiSuggestionJson?: Record | undefined; ... 9 more ...; publicId: string; }[]' is not assignable to parameter of type '(AiAuditLog & { method: string; intentCode: string; })[]'. +#17 44.89 Type '{ method: string; intentCode: string; id: number; documentPublicId?: string; aiModel: string; modelName?: string; aiSuggestionJson?: Record; humanOverrideJson?: Record; ... 8 more ...; publicId: string; }' is not assignable to type 'AiAuditLog & { method: string; intentCode: string; }'. +#17 44.89 Property 'generatePublicId' is missing in type '{ method: string; intentCode: string; id: number; documentPublicId?: string; aiModel: string; modelName?: string; aiSuggestionJson?: Record; humanOverrideJson?: Record; ... 8 more ...; publicId: string; }' but required in type 'AiAuditLog'. +#17 44.89 +#17 44.89 116 const recalibration = this.buildRecalibration(withMethod); +#17 44.89 ~~~~~~~~~~ +#17 44.89 +#17 44.89 src/common/entities/uuid-base.entity.ts:25:3 +#17 44.89 25 generatePublicId(): void { +#17 44.89 ~~~~~~~~~~~~~~~~ +#17 44.89 'generatePublicId' is declared here. +#17 44.89 src/modules/ai/tool/drawing-tool.service.ts:60:60 - error TS2345: Argument of type '{ projectId: number; page: number; limit: number; }' is not assignable to parameter of type 'SearchShopDrawingDto'. +#17 44.89 Property 'projectUuid' is missing in type '{ projectId: number; page: number; limit: number; }' but required in type 'SearchShopDrawingDto'. +#17 44.89 +#17 44.89 60 const result = await this.shopDrawingService.findAll({ +#17 44.89 ~ +#17 44.89 61 projectId: internalProjectId, +#17 44.89 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#17 44.89 ... +#17 44.89 63 limit: 20, +#17 44.89 ~~~~~~~~~~~~~~~~~~ +#17 44.89 64 }); +#17 44.89 ~~~~~~~ +#17 44.89 +#17 44.89 src/modules/drawing/dto/search-shop-drawing.dto.ts:6:3 +#17 44.89 6 projectUuid!: string; +#17 44.89 ~~~~~~~~~~~ +#17 44.89 'projectUuid' is declared here. +#17 44.89 src/modules/ai/tool/rfa-tool.service.ts:74:39 - error TS2339: Property 'respondedAt' does not exist on type 'RfaRevision'. +#17 44.89 +#17 44.89 74 respondedAt: rfaRevision?.respondedAt +#17 44.89 ~~~~~~~~~~~ +#17 44.89 src/modules/ai/tool/rfa-tool.service.ts:76:31 - error TS2339: Property 'respondedAt' does not exist on type 'RfaRevision'. +#17 44.89 +#17 44.89 76 rfaRevision.respondedAt as string | number | Date +#17 44.89 ~~~~~~~~~~~ +#17 44.89 +#17 44.89 Found 6 error(s). +#17 44.89 +#17 45.01  ELIFECYCLE  Command failed with exit code 1. +#17 ERROR: process "/bin/sh -c cd backend && NODE_OPTIONS=\"--max-old-space-size=4096\" pnpm run build" did not complete successfully: exit code: 1 +------ + > [build 8/10] RUN cd backend && NODE_OPTIONS="--max-old-space-size=4096" pnpm run build: +44.89 74 respondedAt: rfaRevision?.respondedAt +44.89 ~~~~~~~~~~~ +44.89 src/modules/ai/tool/rfa-tool.service.ts:76:31 - error TS2339: Property 'respondedAt' does not exist on type 'RfaRevision'. +44.89 +44.89 76 rfaRevision.respondedAt as string | number | Date +44.89 ~~~~~~~~~~~ +44.89 +44.89 Found 6 error(s). +44.89 +45.01  ELIFECYCLE  Command failed with exit code 1. diff --git a/specs/03-Data-and-Storage/lcbp3-v1.9.0-seed-basic.sql b/specs/03-Data-and-Storage/lcbp3-v1.9.0-seed-basic.sql index bd702b42..d8909a6f 100644 --- a/specs/03-Data-and-Storage/lcbp3-v1.9.0-seed-basic.sql +++ b/specs/03-Data-and-Storage/lcbp3-v1.9.0-seed-basic.sql @@ -1848,82 +1848,6 @@ FROM contracts c, WHERE c.contract_code = 'LCBP3-C4' AND ct.type_code = 'RFA'; -INSERT INTO `correspondences` ( - `id`, - `correspondence_number`, - `correspondence_type_id`, - `discipline_id`, - `is_internal_communication`, - `project_id`, - `originator_id`, - `created_at`, - `created_by`, - `deleted_at` - ) -VALUES ( - 1, - 'ผรม.1-คคง.-0242-2568', - 6, - 1, - 0, - 2, - 41, - '2025-12-06 05:25:58', - 1, - NULL - ), - ( - 2, - 'LCBP3-C2-RFA-ROW-RPT-0059-A', - 1, - 95, - 0, - 3, - 42, - '2025-12-06 05:36:52', - 1, - NULL - ); - -INSERT INTO `correspondence_revisions` ( - `id`, - `correspondence_id`, - `revision_number`, - `revision_label`, - `is_current`, - `correspondence_status_id`, - `subject`, - `document_date`, - `issued_date`, - `received_date`, - `due_date`, - `description`, - `details`, - `schema_version`, - `created_at`, - `created_by`, - `updated_by` - ) -VALUES ( - 1, - 1, - 0, - NULL, - 1, - 4, - 'นำส่งวีดิทัศน์ความก้าวหน้างานก่อสร้างงานทางทะเล (ฉบับสมบูรณ์) ประจำเดือนตุลาคม พ.ศ.2568 โครงการพัฒนาท่าเรือแหลมฉบัง ระยะที่ 3 (ส่วนที่ 1) งานก่อสร้างงานทางทะเล', - '2025-11-28', - '2025-11-28 12:26:29', - '2025-12-01 12:26:29', - NULL, - NULL, - NULL, - 1, - '2025-12-06 05:30:17', - 1, - NULL - ); - -- ========================================================== -- 20. Workflow Definitions (Unified Workflow Engine) -- ==========================================================