5.1 KiB
5.1 KiB
Quickstart: Dynamic Prompt Management for OCR Extraction
Feature: 229-dynamic-prompt-management
Date: 2026-05-25
Pre-requisites
- Backend running:
pnpm --filter backend dev(port 3001) - Frontend running:
pnpm --filter frontend dev(port 3000) - MariaDB running with SQL delta applied
- Redis running (for cache testing)
- Logged in as Superadmin (user with
system.manage_allpermission)
Prerequisites: User seed (
pnpm --filter backend seedorts-node run-seed.ts) MUST run before applying this delta. The seed INSERT forai_promptsreferencesusers.username = 'superadmin'— if the user table is empty, the INSERT will fail with a FK constraint error.
Step 1: Apply SQL Delta
-- Run in MariaDB:
SOURCE specs/03-Data-and-Storage/deltas/2026-05-25-create-ai-prompts.sql;
-- Verify:
SELECT id, prompt_type, version_number, is_active, LEFT(template, 50) AS template_preview
FROM ai_prompts;
-- Expected: 1 row, version_number=1, is_active=1
Step 2: Verify API Endpoint (List Versions)
# List all versions for ocr_extraction:
curl -X GET http://localhost:3001/api/ai/prompts/ocr_extraction \
-H "Authorization: Bearer <superadmin_token>"
# Expected: { data: [{ promptType: 'ocr_extraction', versionNumber: 1, isActive: true, ... }] }
Step 3: Create a New Prompt Version
curl -X POST http://localhost:3001/api/ai/prompts/ocr_extraction \
-H "Authorization: Bearer <superadmin_token>" \
-H "Content-Type: application/json" \
-d '{
"template": "Improved prompt for OCR extraction:\n{{ocr_text}}\nReturn JSON with documentNumber, subject, discipline, date, confidence, category, tags, summary."
}'
# Expected: { data: { versionNumber: 2, isActive: false, ... } }
Step 4: Activate New Version
curl -X POST http://localhost:3001/api/ai/prompts/ocr_extraction/2/activate \
-H "Authorization: Bearer <superadmin_token>"
# Expected: { data: { versionNumber: 2, isActive: true, activatedAt: "...", ... } }
# Verify old version is now inactive:
curl -X GET http://localhost:3001/api/ai/prompts/ocr_extraction \
-H "Authorization: Bearer <superadmin_token>"
# Expected: v1 isActive=false, v2 isActive=true
Step 5: Test Validation (Missing Placeholder)
curl -X POST http://localhost:3001/api/ai/prompts/ocr_extraction \
-H "Authorization: Bearer <superadmin_token>" \
-H "Content-Type: application/json" \
-d '{ "template": "This prompt has no placeholder" }'
# Expected: 400 Bad Request
# { message: "template ต้องมี {{ocr_text}} placeholder", userMessage: "กรุณาเพิ่ม {{ocr_text}} ใน template ก่อนบันทึก" }
Step 6: Verify Redis Cache
# After GET or activate, check Redis:
redis-cli GET "ai:prompt:active:ocr_extraction"
# Expected: JSON string of active prompt
# After activate:
redis-cli TTL "ai:prompt:active:ocr_extraction"
# Expected: number between 1-60 (seconds remaining)
Step 7: UI Verification
Sandbox polling mechanism: "เริ่มทำ OCR Sandbox" enqueues a BullMQ job to the
ai-batchqueue via the existing sandbox trigger endpoint. The frontend polls the existing job-status endpoint (GET /api/ai/jobs/:jobId/status) until the job completes or fails — this is the existing pattern, no new polling endpoint is introduced by this feature.
- Navigate to
/admin→ AI Admin Console → OCR Sandbox tab - Verify: Prompt Editor shows active version template in textarea
- Verify: Version History panel shows v1 (inactive), v2 (active ✅)
- Click "Load" on v1 → template should appear in textarea (v2 still active)
- Upload a PDF → Click "เริ่มทำ OCR Sandbox" → wait for result (up to 120s — cold start allowed)
- Verify: Result JSON appears with 8 fields;
test_result_jsonandlast_tested_atupdated on v2
Step 8: Delete Inactive Version
# Try to delete active version (should fail):
curl -X DELETE http://localhost:3001/api/ai/prompts/ocr_extraction/2 \
-H "Authorization: Bearer <superadmin_token>"
# Expected: 400 Bad Request
# Delete inactive version (should succeed):
curl -X DELETE http://localhost:3001/api/ai/prompts/ocr_extraction/1 \
-H "Authorization: Bearer <superadmin_token>"
# Expected: 204 No Content
Acceptance Checklist
- SQL delta applied; seed data present (v1, is_active=1)
- GET returns all versions for prompt_type
- POST validates {{ocr_text}} placeholder
- POST creates new inactive version with auto-incremented version_number
- Activate deactivates old + activates new + invalidates Redis cache (single transaction)
- Cannot delete active version
- Can delete inactive version
- PATCH saves manual_note
- processSandboxExtract uses 120s timeout (no timeout on cold start)
- processMigrateDocument uses same resolvePrompt() — no hardcoded prompt
- UI: Prompt Editor + Version History rendered correctly
- UI: OCR Sandbox run shows result + auto-saves test_result_json
- audit_logs records: create, activate, delete events