690530:1239 ADR-030-231-ocr-sandbox-two-step-flow #04
CI / CD Pipeline / build (push) Successful in 5m11s
CI / CD Pipeline / deploy (push) Successful in 4m23s

This commit is contained in:
2026-05-30 12:39:17 +07:00
parent 33c62993d5
commit c88354347b
3 changed files with 125 additions and 0 deletions
+2
View File
@@ -8,6 +8,7 @@
// - 2026-05-21: เพิ่ม POST /ai/admin/sandbox/extract endpoint สำหรับ Superadmin OCR sandbox (T041 & T042)
// - 2026-05-21: แก้ไขข้อห้ามใช้ parseInt โดยการใช้ Number แทนตามกฎ Tier 1
// - 2026-05-23: เพิ่ม Migration Checkpoint API endpoints แทน MySQL direct access (ADR-023A)
// - 2026-05-30: เพิ่ม @UseInterceptors(FileInterceptor('file')) ใน submitSandboxOcr เพื่อแก้ไขปัญหา BadRequestException (File is required)
// Controller สำหรับ AI Gateway Endpoints (ADR-023)
import {
@@ -515,6 +516,7 @@ export class AiController {
@Post('admin/sandbox/ocr')
@UseGuards(JwtAuthGuard, RbacGuard)
@RequirePermission('system.manage_all')
@UseInterceptors(FileInterceptor('file'))
@ApiOperation({
summary: 'Step 1: Run OCR Only — สำหรับตรวจคุณภาพ OCR ก่อนทดสอบ AI',
description:
+102
View File
@@ -0,0 +1,102 @@
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/migration/queue/:id, GET} route +2ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/migration/errors, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/migration/errors, GET} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/migration/queue/:id/approve, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/migration/queue/:id/reject, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/migration/staging-file, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RoutesResolver] MigrationReviewController {/api/ai/migration}: +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/migration/review, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RoutesResolver] AiController {/api/ai}: +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/intent, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/suggest, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/jobs/:jobId/status, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/jobs, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/jobs/:jobId, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/extract, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/status, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/settings, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/toggle, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/models, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/models/active, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/models/active, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/models, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/models/:modelName/toggle, PATCH} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/models/:modelName, DELETE} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/health, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/sandbox/rag, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/sandbox/job/:id, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/sandbox/extract, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/sandbox/ocr, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/admin/sandbox/ai-extract, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/callback, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/migration, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/migration/:publicId, PATCH} route +2ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/audit-logs, DELETE} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/analytics/summary, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/audit-logs/:publicId, DELETE} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/rag/query, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/rag/jobs/:requestPublicId, GET} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/rag/jobs/:requestPublicId, DELETE} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/legacy-migration/ingest, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/legacy-migration/queue, GET} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/legacy-migration/queue/:publicId/approve, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/migration/checkpoint/:batchId, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/migration/checkpoint, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/migration/queue/record, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/migration/errors, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RoutesResolver] TagsController {/api/tags}: +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/tags, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/tags, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RoutesResolver] IntentAdminController {/api/admin/ai/intent-definitions}: +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/admin/ai/intent-definitions, GET} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/admin/ai/intent-definitions/:intentCode, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/admin/ai/intent-definitions, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/admin/ai/intent-definitions/:intentCode, PATCH} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/admin/ai/intent-definitions/:intentCode/patterns, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/admin/ai/intent-definitions/:intentCode/patterns, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RoutesResolver] IntentPatternAdminController {/api/admin/ai/intent-patterns}: +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/admin/ai/intent-patterns/:publicId, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/admin/ai/intent-patterns/:publicId, PATCH} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/admin/ai/intent-patterns/:publicId, DELETE} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RoutesResolver] IntentClassifyController {/api/ai/intent}: +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/intent/classify, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RoutesResolver] IntentAnalyticsController {/api/admin/ai/intent-analytics}: +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/admin/ai/intent-analytics, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RoutesResolver] AiPromptsController {/api/ai/prompts}: +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/prompts/:promptType, GET} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/prompts/:promptType, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/prompts/:promptType/:versionNumber, DELETE} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/prompts/:promptType/:versionNumber/activate, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/ai/prompts/:promptType/:versionNumber/note, PATCH} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RoutesResolver] RagController {/api/rag}: +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/rag/query, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/rag/status/:attachmentId, GET} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/rag/ingest/:attachmentId, POST} route +1ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/rag/vectors/:attachmentId, DELETE} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [RouterExplorer] Mapped {/api/rag/admin/init-collection, POST} route +0ms
[Nest] 1 - 05/30/2026, 12:20:17 PM LOG [SearchService] Elasticsearch connection successful
[Nest] 1 - 05/30/2026, 12:20:18 PM LOG [QdrantService] Qdrant collection 'lcbp3_vectors' ready
[Nest] 1 - 05/30/2026, 12:20:18 PM LOG [NestApplication] Nest application successfully started +84ms
[Nest] 1 - 05/30/2026, 12:20:18 PM LOG [Bootstrap] Application is running on: http://127.0.0.1:3000/api
[Nest] 1 - 05/30/2026, 12:20:18 PM LOG [Bootstrap] Swagger UI is available at: http://127.0.0.1:3000/docs
[Nest] 1 - 05/30/2026, 12:24:10 PM ERROR [GlobalExceptionFilter] Critical error occurred
path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 exception={"name":"QueryFailedError","message":"Unknown column 'AiPrompt.publicId' in 'SELECT'","stack":"QueryFailedError: Unknown column 'AiPrompt.publicId' in 'SELECT'\n at Query.onResult (/app/node_modules/.pnpm/typeorm@0.3.27_ioredis@5.8.2_mysql2@3.15.3_redis@4.7.1_reflect-metadata@0.2.2_ts-node@1_a2dc5b77c713fab455f1a297d51ed595/node_modules/typeorm/driver/mysql/MysqlQueryRunner.js:168:37)\n at Query.execute (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/commands/command.js:36:14)\n at PoolConnection.handlePacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:477:34)\n at PacketParser.onPacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:93:12)\n at PacketParser.executeStart (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packet_parser.js:75:16)\n at Socket.<anonymous> (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:100:25)\n at Socket.emit (node:events:509:28)\n at addChunk (node:internal/streams/readable:563:12)\n at readableAddChunkPushByteMode (node:internal/streams/readable:514:3)\n at Readable.push (node:internal/streams/readable:394:5)"}
[Nest] 1 - 05/30/2026, 12:24:11 PM ERROR [GlobalExceptionFilter] Critical error occurred
path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 exception={"name":"QueryFailedError","message":"Unknown column 'AiPrompt.publicId' in 'SELECT'","stack":"QueryFailedError: Unknown column 'AiPrompt.publicId' in 'SELECT'\n at Query.onResult (/app/node_modules/.pnpm/typeorm@0.3.27_ioredis@5.8.2_mysql2@3.15.3_redis@4.7.1_reflect-metadata@0.2.2_ts-node@1_a2dc5b77c713fab455f1a297d51ed595/node_modules/typeorm/driver/mysql/MysqlQueryRunner.js:168:37)\n at Query.execute (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/commands/command.js:36:14)\n at PoolConnection.handlePacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:477:34)\n at PacketParser.onPacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:93:12)\n at PacketParser.executeStart (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packet_parser.js:75:16)\n at Socket.<anonymous> (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:100:25)\n at Socket.emit (node:events:509:28)\n at addChunk (node:internal/streams/readable:563:12)\n at readableAddChunkPushByteMode (node:internal/streams/readable:514:3)\n at Readable.push (node:internal/streams/readable:394:5)"}
[Nest] 1 - 05/30/2026, 12:24:28 PM ERROR [GlobalExceptionFilter] Critical error occurred
path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 exception={"name":"QueryFailedError","message":"Unknown column 'AiPrompt.publicId' in 'SELECT'","stack":"QueryFailedError: Unknown column 'AiPrompt.publicId' in 'SELECT'\n at Query.onResult (/app/node_modules/.pnpm/typeorm@0.3.27_ioredis@5.8.2_mysql2@3.15.3_redis@4.7.1_reflect-metadata@0.2.2_ts-node@1_a2dc5b77c713fab455f1a297d51ed595/node_modules/typeorm/driver/mysql/MysqlQueryRunner.js:168:37)\n at Query.execute (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/commands/command.js:36:14)\n at PoolConnection.handlePacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:477:34)\n at PacketParser.onPacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:93:12)\n at PacketParser.executeStart (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packet_parser.js:75:16)\n at Socket.<anonymous> (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:100:25)\n at Socket.emit (node:events:509:28)\n at addChunk (node:internal/streams/readable:563:12)\n at readableAddChunkPushByteMode (node:internal/streams/readable:514:3)\n at Readable.push (node:internal/streams/readable:394:5)"}
[Nest] 1 - 05/30/2026, 12:24:29 PM ERROR [GlobalExceptionFilter] Critical error occurred
path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 exception={"name":"QueryFailedError","message":"Unknown column 'AiPrompt.publicId' in 'SELECT'","stack":"QueryFailedError: Unknown column 'AiPrompt.publicId' in 'SELECT'\n at Query.onResult (/app/node_modules/.pnpm/typeorm@0.3.27_ioredis@5.8.2_mysql2@3.15.3_redis@4.7.1_reflect-metadata@0.2.2_ts-node@1_a2dc5b77c713fab455f1a297d51ed595/node_modules/typeorm/driver/mysql/MysqlQueryRunner.js:168:37)\n at Query.execute (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/commands/command.js:36:14)\n at PoolConnection.handlePacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:477:34)\n at PacketParser.onPacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:93:12)\n at PacketParser.executeStart (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packet_parser.js:75:16)\n at Socket.<anonymous> (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:100:25)\n at Socket.emit (node:events:509:28)\n at addChunk (node:internal/streams/readable:563:12)\n at readableAddChunkPushByteMode (node:internal/streams/readable:514:3)\n at Readable.push (node:internal/streams/readable:394:5)"}
[Nest] 1 - 05/30/2026, 12:24:49 PM DEBUG [DashboardService] Getting pending tasks for user 1, project: Global
[Nest] 1 - 05/30/2026, 12:24:58 PM DEBUG [DashboardService] Getting recent activity for user 1, project: Global
[Nest] 1 - 05/30/2026, 12:24:58 PM DEBUG [DashboardService] Getting dashboard stats for user 1, project: Global
[Nest] 1 - 05/30/2026, 12:25:04 PM ERROR [GlobalExceptionFilter] Critical error occurred
path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 exception={"name":"QueryFailedError","message":"Unknown column 'AiPrompt.publicId' in 'SELECT'","stack":"QueryFailedError: Unknown column 'AiPrompt.publicId' in 'SELECT'\n at Query.onResult (/app/node_modules/.pnpm/typeorm@0.3.27_ioredis@5.8.2_mysql2@3.15.3_redis@4.7.1_reflect-metadata@0.2.2_ts-node@1_a2dc5b77c713fab455f1a297d51ed595/node_modules/typeorm/driver/mysql/MysqlQueryRunner.js:168:37)\n at Query.execute (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/commands/command.js:36:14)\n at PoolConnection.handlePacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:477:34)\n at PacketParser.onPacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:93:12)\n at PacketParser.executeStart (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packet_parser.js:75:16)\n at Socket.<anonymous> (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:100:25)\n at Socket.emit (node:events:509:28)\n at addChunk (node:internal/streams/readable:563:12)\n at readableAddChunkPushByteMode (node:internal/streams/readable:514:3)\n at Readable.push (node:internal/streams/readable:394:5)"}
[Nest] 1 - 05/30/2026, 12:25:05 PM ERROR [GlobalExceptionFilter] Critical error occurred
path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET path=/api/ai/prompts/ocr_extraction path=/api/ai/prompts/ocr_extraction method=GET userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 exception={"name":"QueryFailedError","message":"Unknown column 'AiPrompt.publicId' in 'SELECT'","stack":"QueryFailedError: Unknown column 'AiPrompt.publicId' in 'SELECT'\n at Query.onResult (/app/node_modules/.pnpm/typeorm@0.3.27_ioredis@5.8.2_mysql2@3.15.3_redis@4.7.1_reflect-metadata@0.2.2_ts-node@1_a2dc5b77c713fab455f1a297d51ed595/node_modules/typeorm/driver/mysql/MysqlQueryRunner.js:168:37)\n at Query.execute (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/commands/command.js:36:14)\n at PoolConnection.handlePacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:477:34)\n at PacketParser.onPacket (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:93:12)\n at PacketParser.executeStart (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/packet_parser.js:75:16)\n at Socket.<anonymous> (/app/node_modules/.pnpm/mysql2@3.15.3/node_modules/mysql2/lib/base/connection.js:100:25)\n at Socket.emit (node:events:509:28)\n at addChunk (node:internal/streams/readable:563:12)\n at readableAddChunkPushByteMode (node:internal/streams/readable:514:3)\n at Readable.push (node:internal/streams/readable:394:5)"}
[Nest] 1 - 05/30/2026, 12:25:57 PM WARN [GlobalExceptionFilter] Error occurred
path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 ip=172.29.0.19 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 ip=172.29.0.19 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 exception={"name":"BadRequestException","message":"File is required","stack":"BadRequestException: File is required\n at ParseFilePipe.exceptionFactory (/app/node_modules/.pnpm/@nestjs+common@11.1.19_class-transformer@0.5.1_class-validator@0.14.3_reflect-metadata@0.2.2_rxjs@7.8.2/node_modules/@nestjs/common/pipes/file/parse-file.pipe.js:24:27)\n at ParseFilePipe.transform (/app/node_modules/.pnpm/@nestjs+common@11.1.19_class-transformer@0.5.1_class-validator@0.14.3_reflect-metadata@0.2.2_rxjs@7.8.2/node_modules/@nestjs/common/pipes/file/parse-file.pipe.js:31:24)\n at /app/node_modules/.pnpm/@nestjs+core@11.1.19_@nestjs+common@11.1.19_class-transformer@0.5.1_class-validator@0.1_cbe1fb75cf716ace88130e83fa30d064/node_modules/@nestjs/core/pipes/pipes-consumer.js:16:33\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n at async resolveParamValue (/app/node_modules/.pnpm/@nestjs+core@11.1.19_@nestjs+common@11.1.19_class-transformer@0.5.1_class-validator@0.1_cbe1fb75cf716ace88130e83fa30d064/node_modules/@nestjs/core/router/router-execution-context.js:148:23)\n at async Promise.all (index 1)\n at async pipesFn (/app/node_modules/.pnpm/@nestjs+core@11.1.19_@nestjs+common@11.1.19_class-transformer@0.5.1_class-validator@0.1_cbe1fb75cf716ace88130e83fa30d064/node_modules/@nestjs/core/router/router-execution-context.js:151:13)\n at async /app/node_modules/.pnpm/@nestjs+core@11.1.19_@nestjs+common@11.1.19_class-transformer@0.5.1_class-validator@0.1_cbe1fb75cf716ace88130e83fa30d064/node_modules/@nestjs/core/router/router-execution-context.js:37:30"}
[Nest] 1 - 05/30/2026, 12:25:57 PM WARN [GlobalExceptionFilter]
[Nest] 1 - 05/30/2026, 12:26:04 PM WARN [GlobalExceptionFilter] Error occurred
path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 ip=172.29.0.19 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 ip=172.29.0.19 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST path=/api/ai/admin/sandbox/ocr path=/api/ai/admin/sandbox/ocr method=POST userId=1 ip=172.29.0.19 userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0 exception={"name":"BadRequestException","message":"File is required","stack":"BadRequestException: File is required\n at ParseFilePipe.exceptionFactory (/app/node_modules/.pnpm/@nestjs+common@11.1.19_class-transformer@0.5.1_class-validator@0.14.3_reflect-metadata@0.2.2_rxjs@7.8.2/node_modules/@nestjs/common/pipes/file/parse-file.pipe.js:24:27)\n at ParseFilePipe.transform (/app/node_modules/.pnpm/@nestjs+common@11.1.19_class-transformer@0.5.1_class-validator@0.14.3_reflect-metadata@0.2.2_rxjs@7.8.2/node_modules/@nestjs/common/pipes/file/parse-file.pipe.js:31:24)\n at /app/node_modules/.pnpm/@nestjs+core@11.1.19_@nestjs+common@11.1.19_class-transformer@0.5.1_class-validator@0.1_cbe1fb75cf716ace88130e83fa30d064/node_modules/@nestjs/core/pipes/pipes-consumer.js:16:33\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n at async resolveParamValue (/app/node_modules/.pnpm/@nestjs+core@11.1.19_@nestjs+common@11.1.19_class-transformer@0.5.1_class-validator@0.1_cbe1fb75cf716ace88130e83fa30d064/node_modules/@nestjs/core/router/router-execution-context.js:148:23)\n at async Promise.all (index 1)\n at async pipesFn (/app/node_modules/.pnpm/@nestjs+core@11.1.19_@nestjs+common@11.1.19_class-transformer@0.5.1_class-validator@0.1_cbe1fb75cf716ace88130e83fa30d064/node_modules/@nestjs/core/router/router-execution-context.js:151:13)\n at async /app/node_modules/.pnpm/@nestjs+core@11.1.19_@nestjs+common@11.1.19_class-transformer@0.5.1_class-validator@0.1_cbe1fb75cf716ace88130e83fa30d064/node_modules/@nestjs/core/router/router-execution-context.js:37:30"}
[Nest] 1 - 05/30/2026, 12:26:04 PM WARN [GlobalExceptionFilter]
@@ -0,0 +1,21 @@
-- Delta: เพิ่ม publicId column ให้ ai_prompts table เพื่อ ADR-019 compliance
-- Date: 2026-05-30
-- Related ADR: ADR-019 (Hybrid UUID Strategy)
-- Applied in: v1.9.6 -> v1.9.7
-- ------------------------------------------------------------
-- การเปลี่ยนแปลงโครงสร้างฐานข้อมูล (Schema changes)
-- ------------------------------------------------------------
-- เพิ่ม publicId column (MariaDB native UUID type ตาม ADR-019)
ALTER TABLE ai_prompts
ADD COLUMN publicId CHAR(36) UNIQUE COMMENT 'UUIDv7 public identifier (ADR-019)';
-- Generate UUIDv7 for existing records
-- ใช้ MariaDB UUID() function สำหรับสร้าง UUID v4 (fallback)
-- หมายเหตุ: UUIDv7 จริงๆ ต้องใช้ timestamp แต่ MariaDB ยังไม่รองรับ UUIDv7 native
-- ใช้ UUID() เป็น workaround และจะถูก replace ด้วย UUIDv7 จริงเมื่อ migrate document
UPDATE ai_prompts
SET publicId = UUID()
WHERE publicId IS NULL;
-- Add index for publicId (optional but recommended for performance)
CREATE INDEX idx_ai_prompts_publicId ON ai_prompts(publicId);