Files
lcbp3/specs/200-fullstacks/229-dynamic-prompt-management/quickstart.md
T
admin 1139e54086
CI / CD Pipeline / build (push) Successful in 4m29s
CI / CD Pipeline / deploy (push) Successful in 1m50s
690525:1720 ADR-028-228-migration-OCR #06 dynamic prompt
2026-05-25 17:20:48 +07:00

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_all permission)

Prerequisites: User seed (pnpm --filter backend seed or ts-node run-seed.ts) MUST run before applying this delta. The seed INSERT for ai_prompts references users.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-batch queue 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.

  1. Navigate to /admin → AI Admin Console → OCR Sandbox tab
  2. Verify: Prompt Editor shows active version template in textarea
  3. Verify: Version History panel shows v1 (inactive), v2 (active )
  4. Click "Load" on v1 → template should appear in textarea (v2 still active)
  5. Upload a PDF → Click "เริ่มทำ OCR Sandbox" → wait for result (up to 120s — cold start allowed)
  6. Verify: Result JSON appears with 8 fields; test_result_json and last_tested_at updated 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