---
title: "แผนการทดสอบหลัก (Master Test Plan)"
titleEn: "Master Test Plan"
clauses: ["4.7.1", "7.1.4"]
phase: 1
category: "ทดสอบ"
generated: false
---

# แผนการทดสอบหลัก (Master Test Plan)

**อ้างอิง TOR:** ข้อ 4.7.1 (Master Test Plan + Test Case + Traceability กับ SRS) และข้อ 7.1.4 (เอกสารส่งมอบงวดที่ 1)
**ฉบับ:** 1.0 — วันที่ 3 ตุลาคม พ.ศ. 2569
**เอกสารที่เกี่ยวข้อง:** `/documents/srs` (รหัส FR/NFR), `/documents/test-checklist` (Checklist ประสิทธิภาพ/ความปลอดภัย), `/documents/test-reports-index` (ดัชนีรายงานผลทดสอบ)

> ตารางกรณีทดสอบในเอกสารนี้จัดทำจาก **ไฟล์ทดสอบที่มีอยู่จริงใน repository** (`tests/unit`, `tests/api`, `tests/e2e`) จำนวนกรณีนับจากบรรทัด `it(...)` / `test(...)` ในแต่ละไฟล์ (`it.each` นับเป็น 1 แม้จะขยายเป็นหลายกรณีตอนรัน) ผลการรันจริงให้ดูจากรายงานที่สร้างจากการรันแต่ละครั้ง (หัวข้อ 9) — เอกสารนี้ไม่ได้อ้างผลผ่าน/ไม่ผ่าน

---

## 1. วัตถุประสงค์

1. กำหนดกลยุทธ์ ระดับ สภาพแวดล้อม เกณฑ์เริ่ม/สิ้นสุด และวิธีบริหารข้อบกพร่องของการทดสอบตลอดโครงการ
2. ระบุกรณีทดสอบ (Test Case) และความเชื่อมโยงกับความต้องการใน SRS (FR-xxx) และข้อ TOR (Traceability)
3. เป็นฐานของการทดสอบถดถอย (Regression) อัตโนมัติทุก API และทุก CTA หลัก (TOR 4.7.5)

## 2. ขอบเขต

| อยู่ในขอบเขต | นอกขอบเขตของรอบนี้ |
|---|---|
| Domain logic (retrieval, guardrail, citation, token budget, chunking, scorers, SLA, PII) | การทดสอบเจาะระบบโดยผู้ทดสอบภายนอก — **ไม่ได้ดำเนินการในรอบนี้ตามคำสั่งของผู้ว่าจ้าง** |
| API ทุก endpoint ใน OpenAPI registry (107 operation) + middleware | การทดสอบโหลด 500 concurrent บนคลาวด์จริง (ทำระดับเครื่องเดียว) |
| RAG pipeline 8 โหนด (LangGraph) ด้วย Mock LLM | Firefox / Safari / Edge (sandbox มี Chromium เท่านั้น) |
| UI E2E 3 viewport (390/768/1280) | UAT กับผู้ใช้จริงของมหาวิทยาลัย (มีแม่แบบและ Defect Log รองรับ) |
| ไฟล์ส่งมอบ IaC (YAML parse), สคริปต์สำรอง/กู้คืน | การรัน CI/CD บน GitHub Actions จริง |
| การประเมินคุณภาพ AI 7 ชุด (Benchmark) | |

## 3. กลยุทธ์การทดสอบ

- **Test pyramid:** เน้น unit test ที่ `src/domain` (pure TypeScript) มากที่สุด ตามด้วย API test ที่เรียก route handler ตรง (ไม่ต้องเปิดเซิร์ฟเวอร์) และ E2E ครอบคลุมเส้นทางผู้ใช้หลัก
- **ข้อมูลทดสอบแยก:** vitest สร้างฐานข้อมูล template หนึ่งครั้งต่อการรัน (`prisma migrate deploy` + `prisma/seed.ts`, `tests/helpers/global-setup.ts`) แล้วแต่ละไฟล์ทดสอบคัดลอกเป็นฐานข้อมูลของตนเอง — ไม่แตะ `prisma/dev.db`
- **LLM แบบ deterministic:** ชุด vitest ตั้ง `LLM_FORCE_MOCK=1` จึงใช้ `MockLlmAdapter` เสมอ ผลจึงทำซ้ำได้และไม่เสียค่า API ส่วนคุณภาพของ LLM จริง (Typhoon) วัดแยกด้วยระบบประเมินผล (หัวข้อ 4.5)
- **Regression ทุก API:** 2 ชั้น — (1) `tests/api/openapi-coverage.test.ts` ตรวจว่าทุก path+method ใน registry ของ `/api/openapi.json` มีไฟล์ทดสอบที่ import handler นั้น (2) เมื่อรัน `npm test` (`OPENAPI_COVERAGE=1`) teardown ใน `tests/helpers/global-setup.ts` ตรวจการเรียกจริงที่บันทึกโดย `withApi` และเขียน `coverage/openapi-coverage.json` — endpoint ใหม่ที่ไม่มีการทดสอบจะทำให้ชุดทดสอบล้มเหลว (รายละเอียดใน `/documents/test-reports-index` หัวข้อ 4)
- **สิทธิ์:** ทุกกลุ่ม endpoint มีกรณีสำเร็จและกรณีสิทธิ์ไม่พอ (401/403) อย่างน้อยกลุ่มละ 1
- **Coverage gate:** `src/domain/**` + `src/application/**` lines/functions/statements ≥80%, branches ≥75% (`vitest.config.ts`) — ต่ำกว่าเกณฑ์ vitest ออกด้วยรหัสผิดพลาด (TOR 4.7.3)

## 4. ระดับการทดสอบ

| ระดับ | เครื่องมือ | ตำแหน่ง | ไฟล์ | กรณี (นับจากซอร์ส) | คำสั่ง |
|---|---|---|---:|---:|---|
| Unit (รวม component) | vitest + Testing Library (jsdom) | `tests/unit/**` | 29 | 391 | `npx vitest run tests/unit` |
| API / SIT | vitest (เรียก route handler ตรง) | `tests/api/*.test.ts` | 24 | 172 | `npm run test:sit` |
| ทั้งชุด + regression ทุก API | vitest + `OPENAPI_COVERAGE=1` | unit + api | 53 | 563 | `npm test` / `npm run test:coverage` |
| E2E / Functional UI | Playwright (Chromium) × 3 viewport | `tests/e2e/*.spec.ts` | 3 | 26 (× 3 viewport = 78 การรัน) | `npm run test:e2e` |
| ประสิทธิภาพ | `scripts/perf/load-test.ts`, `seed-perf-users.ts` | `scripts/perf/` | — | — | `npm run report:perf` |
| ความปลอดภัย | npm audit | `scripts/security/npm-audit-report.ts` | — | — | `npm run report:security` |
| กู้คืนข้อมูล | bash + sqlite3 | `scripts/restore-test.sh` | — | — | `npm run report:restore-test` |
| คุณภาพ AI | Evaluation runner | `src/application/evaluation/runner.ts`, `scripts/eval/run-acceptance.ts` | 7 ชุด | 650 ข้อ (+ Injection 20) | `npm run eval:acceptance` |
| UAT | ผู้ใช้ของมหาวิทยาลัย | Defect Log (`/admin/defect-log`) | — | — | ดำเนินการในงวดที่ 2–3 |

### 4.1 การทดสอบ Functional และ SIT บนสภาพแวดล้อมทดสอบ (TOR 4.7.4)

- ระบบสาธิต: API test รันกับฐานข้อมูลทดสอบแยกต่อไฟล์ (เทียบเท่า Test Environment) ผ่าน `npm run test:sit`
- Production: SIT/UAT ดำเนินการบน namespace `mbu-test` (deploy อัตโนมัติจาก branch `release/*` ตาม `.github/workflows/ci-cd.yml`) — ยังไม่ได้ติดตั้งจริงในรอบนี้

### 4.2 การประเมินคุณภาพ AI (Benchmark)

| ชุด | จำนวนข้อ | Workflow | เกณฑ์ขั้นต่ำ (TOR ก.5.3) |
|---|---:|---|---|
| DS-1 ธรรมศึกษา ปรนัย | 100 | Accuracy (exact match ตัวเลือก) | ≥80% |
| NT-2 นักธรรม ตอบสั้น | 50 | LLM-as-Judge 0–3 | ≥2.00 |
| RET-1 พระวินัยปิฎก | 100 | Recall@5 | ≥80% |
| RET-2 พระสุตตันตปิฎก | 100 | Recall@5 | ≥80% |
| RET-3 พระอภิธรรมปิฎก | 100 | Recall@5 | ≥80% |
| GR-1 นอกขอบเขต | 100 | Refusal | ≥80% |
| GR-2 หัวข้อสุ่มเสี่ยง | 50 | Refusal | ≥80% |
| INJ Prompt injection (รายงานความปลอดภัย) | 20 | Refusal | ≥80% |

ต้องรันอย่างน้อย 2 ครั้ง (Baseline และ Acceptance — TOR 4.7.7) ผลดูที่ `/admin/evaluation` และ `/documents/baseline-evaluation-report`

## 5. สภาพแวดล้อมการทดสอบ

| สภาพแวดล้อม | รายละเอียด |
|---|---|
| เครื่องพัฒนา/sandbox | Node.js ≥22, SQLite, macOS หรือ Debian; dev server ที่ `http://localhost:3210` (E2E ใช้ `E2E_PORT`, ค่าเริ่มต้น 3210) |
| ฐานข้อมูลทดสอบ | `prisma/test-template-<pid>.db` (สร้างอัตโนมัติ) แล้วคัดลอกต่อไฟล์ทดสอบ |
| LLM | Mock (vitest) / Typhoon `typhoon-v2.5-30b-a3b-instruct` (การประเมินผลและการใช้งานจริงเมื่อตั้ง `TYPHOON_API_KEY`) |
| เบราว์เซอร์ | Chromium ของระบบ (`CHROMIUM_PATH` หรือ `/usr/bin/chromium`) viewport 390×844 (มือถือ, touch), 768×1024, 1280×800; locale `th-TH` |
| CI | GitHub Actions `ubuntu-latest` (ไฟล์ส่งมอบ ยังไม่ได้รันจริง) |
| Production | Kubernetes 3 namespace `mbu-dev` / `mbu-test` / `mbu-prod` (Helm) — ยังไม่ได้ติดตั้ง |

## 6. เกณฑ์เริ่มต้นและเกณฑ์สิ้นสุด

**Entry criteria**
1. ความต้องการใน SRS ได้รับการทบทวนและมีรหัส FR/NFR
2. ฐานข้อมูล migrate + seed สำเร็จ (ผู้ใช้สาธิต 6 บัญชี, config, prompt, guardrail, คลังความรู้, ชุดทดสอบ)
3. `npx tsc --noEmit` และ `npm run lint` ผ่าน
4. สำหรับ E2E: dev server ตอบ `GET /api/health` = 200

**Exit criteria**
1. `npm test` ผ่านทั้งหมด รวม `openapi-coverage` (ทุก endpoint ถูกทดสอบ)
2. Coverage `src/domain` + `src/application` ผ่าน gate (≥80% / branches ≥75%) — ดู `/documents/coverage-report`
3. `npm run test:e2e` ผ่านทั้ง 3 viewport
4. npm audit ไม่มีช่องโหว่ระดับ High/Critical (`/documents/vulnerability-scan-report`)
5. Benchmark 7 ชุดผ่านเกณฑ์ขั้นต่ำ TOR ก.5.3 (ไม่ผ่าน = ไม่ตรวจรับตาม ก.5.3.1)
6. Defect Log ไม่มีรายการ High/Critical ค้าง (TOR 4.7.8)
7. Restore test ผ่าน (`/documents/restore-test-report`)

**Suspension / Resumption:** หยุดการทดสอบระดับถัดไปเมื่อระดับก่อนหน้าล้มเหลว (ลำดับเดียวกับ pipeline: lint → test → security → build → e2e) และเริ่มใหม่เมื่อแก้ไขและผ่านการทดสอบซ้ำ

## 7. ตารางกรณีทดสอบ (Test Cases) และ Traceability

### 7.1 Unit tests (`tests/unit`)

| รหัส | ไฟล์ | ขอบเขต | กรณี | FR/NFR | TOR |
|---|---|---|---:|---|---|
| UT-01 | `tests/unit/audit-hash-chain.test.ts` | GENESIS_HASH, computeAuditHash, verifyChain (ตรวจการแก้ไขแถว) | 13 | FR-111 | ก.6.5.3 |
| UT-02 | `tests/unit/bm25.test.ts` | Bm25Index: เพิ่ม/ลบ/ค้นหา incremental | 14 | FR-031 | ก.4.6.1 |
| UT-03 | `tests/unit/chunking-policy.test.ts` | estimateTokens, โหมด marker (ไม่ตัดข้อเดียวกัน, oversized, หน้าเริ่ม–จบ), โหมด semantic (ไม่ตัดตามโทเคนล้วน) | 28 | FR-071 | ก.4.8.2, ก.4.6.2 |
| UT-04 | `tests/unit/citation-vo.test.ts` | formatCitationLabel, resolveCitations (ตัด cite ปลอม, ป้ายไม่มีอ้างอิง) | 14 | FR-012, FR-043 | ก.3.6.3, ก.4.6.3 |
| UT-05 | `tests/unit/config-snapshot.test.ts` | AI_CONFIG_DEFAULTS, CONFIG_GROUPS, aiConfigSchema (partial update), merge/diff | 14 | FR-080, FR-051 | ก.6.2.1, ก.6.2.6, ก.4.2.1 |
| UT-06 | `tests/unit/contrast.test.ts` | WCAG contrast ทุกคู่สีใน `contrastPairs` (light/dark) | 3 | NFR-008 | ก.3.1.1 |
| UT-07 | `tests/unit/documents.test.ts` | ศูนย์เอกสาร: ครบ 36 ฉบับ, frontmatter, กัน path traversal | 3 | FR-153 | 7.5 |
| UT-08 | `tests/unit/embedding.test.ts` | fnv1a, embed (512 มิติ, L2), cosine | 13 | FR-031 | ก.4.6.1 |
| UT-09 | `tests/unit/graph.test.ts` | LangGraph 8 โหนดตามลำดับ, refusal หยุด graph, stopAfter, mcq, fitContext ≤ maxPerPromptQa | 7 | FR-030, FR-040, FR-051 | ก.4.1.2, ก.4.2.1 |
| UT-10 | `tests/unit/guardrail-policy.test.ts` | หัวข้อเริ่มต้น, evaluateInput (injection/sensitive/yes-no/scope), evaluateOutput | 23 | FR-040–FR-043, FR-035 | ก.4.3.1, ก.4.4.1, ก.4.4.3, ก.4.5.3 |
| UT-11 | `tests/unit/i18n.test.ts` | key ของ `messages/th` และ `messages/en` ตรงกันทุก namespace | 3 | FR-150 | ก.3.2.1 |
| UT-12 | `tests/unit/infra-yaml.test.ts` | ci-cd.yml (ลำดับ job, trigger, Node 22, deploy-prod ตรวจ tag), Helm (Chart/values parse, 8 services, HPA 70%, ingress TLS, 3 namespaces), สคริปต์ backup/restore/HTTPS | 17 | NFR-005, NFR-014 | 4.6.2, 4.6.3, ก.1.3.2, ก.1.6.3, ก.2.1.2 |
| UT-13 | `tests/unit/llm-adapters.test.ts` | Typhoon/OpenAI-compatible, Gemini, Claude, Mock (fetch mock) และการสลับ provider | 7 | FR-030, NFR-012 | ก.4.1.2, 4.4.6 |
| UT-14 | `tests/unit/oauth-providers.test.ts` | Google/Facebook: authorize URL, state/PKCE, parse profile | 6 | FR-003 | ก.3.3.2 |
| UT-15 | `tests/unit/parsers.test.ts` | parsers 4 ชนิด, pipeline helpers (unwrapLines, chunkText), kb-admin helpers | 16 | FR-070, FR-073 | ก.4.8.1 |
| UT-16 | `tests/unit/password-lockout-rbac.test.ts` | นโยบายรหัสผ่าน (ผู้ใช้/ผู้ดูแล), lockout 5/20 ครั้ง 15 นาที, RBAC | 18 | FR-004, FR-006, FR-007 | ก.2.1.4, ก.6.1.1, ก.6.1.4 |
| UT-17 | `tests/unit/pii-masking.test.ts` | เลขบัตรประชาชน (checksum), เบอร์โทร, อีเมล, ชื่อ | 9 | FR-063 | 14.3 |
| UT-18 | `tests/unit/relevance-scoring.test.ts` | DEFAULT_PRECEDENCE, applyPrecedence (≤10) | 8 | FR-034, FR-011 | ก.4.8.3, ก.3.6.2 |
| UT-19 | `tests/unit/report-scripts.test.ts` | ฟังก์ชันช่วยของสคริปต์รายงาน: percentile/summarize, mdTable, replaceSection/extractSection | 43 | NFR-001, FR-141 | 4.7.9, 12.2 |
| UT-20 | `tests/unit/reranker.test.ts` | HeuristicReranker (0.6/0.3/0.1), phraseCandidates | 15 | FR-033 | ก.4.7.1 |
| UT-21 | `tests/unit/rrf.test.ts` | rrfFuse | 6 | FR-031 | ก.4.6.1 |
| UT-22 | `tests/unit/sanitize.test.ts` | INJECTION_LINE_PATTERNS (ไม่ตัดเนื้อหาธรรม), sanitizeText | 12 | FR-075, FR-041 | ก.4.4.1 |
| UT-23 | `tests/unit/scorers.test.ts` | normalizeAnswer, extractChoiceLabel, exactMatch, recallAtK, mockJudge, refusal, aggregate | 24 | FR-092, FR-095 | ก.5.2.2, ก.5.3 |
| UT-24 | `tests/unit/sla-policy.test.ts` | slaHoursFor, slaDeadline (ชั่วโมงทำการ), overdue, ค่าปรับ | 15 | FR-140 | 12.3, 12.4, 10.2 |
| UT-25 | `tests/unit/synonyms.test.ts` | SYNONYM_GROUPS ไทย–บาลี–อังกฤษ, expandQuery | 16 | FR-031, FR-032 | ก.4.6.1, ก.4.7.2 |
| UT-26 | `tests/unit/token-budget-policy.test.ts` | estimateTokens, checkDailyBudget (cap, margin, alert), checkInputLength, fitContext | 13 | FR-050–FR-053 | ก.3.4.1, ก.3.4.4, ก.4.4.2, ก.7.3.5 |
| UT-27 | `tests/unit/tokenizer.test.ts` | normalizeText, segmentWords (Intl.Segmenter), tokenize, charNgrams | 17 | FR-031 | ก.4.6.1 |
| UT-28 | `tests/unit/tor-map.test.ts` | ตาราง TOR 200 ข้อ, clauseId ครบ/ไม่ซ้ำ, route มีจริง, เอกสาร `/documents/<slug>` มีไฟล์, todo มี note | 7 | FR-153 | 4.4, 7.5 |
| UT-29 | `tests/unit/components/chat-components.test.tsx` | ReferenceList (แสดง 3 + Expand All), AnswerSummary + CitationChip, FeedbackButtons | 7 | FR-011, FR-012, FR-014 | ก.3.6.2, ก.3.6.3, ก.3.8.1 |

### 7.2 API / SIT tests (`tests/api`)

| รหัส | ไฟล์ | ขอบเขต | กรณี | FR | TOR |
|---|---|---|---:|---|---|
| AT-01 | `tests/api/admin-users.test.ts` | ค้นหา/ดู/แก้/ระงับ/ลบผู้ใช้, สิทธิ์ Dhamma Talk, เปลี่ยน role เฉพาะ SUPER_ADMIN, conversation_accessed | 10 | FR-100–FR-102, FR-021 | ก.6.1.1–ก.6.1.3 |
| AT-02 | `tests/api/ai-config.test.ts` | อ่าน/แก้ config มีผลทันที, snapshot, revert, models, test-llm | 7 | FR-080, FR-081 | ก.6.2.1–ก.6.2.6 |
| AT-03 | `tests/api/alerts.test.ts` | รายการ AlertEmailLog, ส่งแจ้งเตือนทดสอบ | 3 | FR-130 | ก.4.10.2, ก.7.3.5 |
| AT-04 | `tests/api/audit-log.test.ts` | ค้นหา/กรอง, export CSV, verify hash chain, UPDATE/DELETE ถูกปฏิเสธ | 6 | FR-110–FR-112 | ก.6.5.1–ก.6.5.4 |
| AT-05 | `tests/api/auth.test.ts` | register (consent), login, logout, บัญชีระงับ, lockout, /api/me | 6 | FR-001, FR-002, FR-004, FR-008 | ก.3.3.1, ก.2.1.4, 14.2 |
| AT-06 | `tests/api/backup.test.ts` | สร้าง/รายการไฟล์สำรอง (SUPER_ADMIN เท่านั้น) | 4 | FR-142 | ก.1.6.3 |
| AT-07 | `tests/api/chat-qa.test.ts` | SSE references≤10 → delta → done (citation, usage, trace 8 โหนด), ถามต่อ + retention 90 วัน, INPUT_TOO_LONG, เพดาน 24 ชม. → 503 + auto unavailable + alert, Unavailable mode, IDOR, chunks, feedback, ลบบทสนทนา | 10 | FR-010–FR-017, FR-050–FR-054 | ก.3.4, ก.3.5.1, ก.3.6.2, ก.3.6.3, ก.3.8.1, ก.4.4.2 |
| AT-08 | `tests/api/dashboard.test.ts` | usage/tokens/feedback ตามช่วงเวลา + เทียบช่วงก่อน, สิทธิ์ | 8 | FR-120–FR-122 | ก.7.1–ก.7.3 |
| AT-09 | `tests/api/data-destruction.test.ts` | ทำลายข้อมูลตาม scope + ข้อความยืนยัน + หนังสือรับรอง, AuditLog ไม่ถูกลบ | 6 | FR-143 | 4.11.3 |
| AT-10 | `tests/api/defect-log.test.ts` | CRUD, deadline ตามความรุนแรง, resolutionNote บังคับ, confirm → overdue/ค่าปรับ, export | 6 | FR-140 | 12.3, 12.4, 10.2, 4.7.8 |
| AT-11 | `tests/api/dhamma-talk.test.ts` | สิทธิ์ (403 เมื่อปิด), SSE artifact, ใช้ฉบับที่ผู้ใช้แก้เป็นบริบท | 3 | FR-020, FR-021 | ก.3.7.1–ก.3.7.4, ก.3.3.3 |
| AT-12 | `tests/api/evaluation.test.ts` | สิทธิ์, CRUD ชุด/ข้อ, CSV import + template, version bump, runs, compare, thresholds, security-report, export | 18 | FR-090–FR-097 | ก.5.1–ก.5.3, ก.6.4.1–ก.6.4.3, 7.2.7 |
| AT-13 | `tests/api/guardrails.test.ts` | CRUD หัวข้อ, ทดสอบข้อความ, snapshot | 5 | FR-044 | ก.6.2.5 |
| AT-14 | `tests/api/health-status-openapi.test.ts` | /api/health, /api/status (ไม่เปิดเผยความลับ), /api/openapi.json, /api/csrf, /api/documents | 5 | FR-144, FR-005, FR-153 | ก.4.1.1 |
| AT-15 | `tests/api/knowledge-base.test.ts` | อัปโหลด TXT/TEI/DOCX/PDF → job → chunks → ค้นเจอ, oversized, ตัด injection, PDF สแกน, PATCH metadata/precedence + audit, reindex selected/all (คง id), retry, delete, coverage 91 เล่ม/เป้า 20% | 28 | FR-070–FR-075, FR-034 | ก.4.8.1–ก.4.8.3, ก.6.3.1–ก.6.3.3, 4.5.3, ข.1 |
| AT-16 | `tests/api/oauth.test.ts` | Authorization Code flow ครบด้วย Mock Provider (start → authorize → callback → token → userinfo), state ไม่ตรงถูกปฏิเสธ | 4 | FR-003 | ก.3.3.2 |
| AT-17 | `tests/api/openapi-coverage.test.ts` | ทุก path+method ใน registry มีไฟล์ทดสอบที่ import handler (ชั้น static) — ชั้น runtime ตรวจใน teardown เมื่อ `OPENAPI_COVERAGE=1` | 1 | ทุก FR ที่มี API | 4.7.5 |
| AT-18 | `tests/api/pricing.test.ts` | CRUD อัตราค่าโทเคน | 4 | FR-084 | ก.7.3.3 |
| AT-19 | `tests/api/privacy-requests.test.ts` | ผู้ดูแลดำเนินการ access_copy / erase (anonymize) / withdraw_consent (ระงับบัญชี), สร้างแทนผู้ใช้ | 7 | FR-062 | 14.4, ก.6.1.2 |
| AT-20 | `tests/api/privacy.test.ts` | export JSON ข้อมูลตนเอง, ยื่น/ดูคำขอ | 5 | FR-061 | 14.4 |
| AT-21 | `tests/api/prompts.test.ts` | เวอร์ชันใหม่, diff, activate/rollback, audit prompt_changed | 6 | FR-082 | ก.4.9.1, ก.6.2.4 |
| AT-22 | `tests/api/rbac-ip-allowlist.test.ts` | CSRF 403, rate limit login 10/นาที และเขียน 60/อ่าน 600, admin IP allowlist 403 (API+หน้าเว็บ) + audit, locale | 7 | FR-004–FR-007 | ก.2.1.4, ก.2.1.5, ก.6.1.4, ก.2.2.1 |
| AT-23 | `tests/api/sla-report.test.ts` | availability, p95 latency, TTFT p95, error rate, defect เกิน SLA, export Markdown | 7 | FR-141 | 12.1, 12.2, 12.5 |
| AT-24 | `tests/api/unavailable.test.ts` | เปิด/ปิด Unavailable + ข้อความ th/en, /api/status, snapshot | 6 | FR-054 | ก.3.4.3, ก.6.6.1 |

### 7.3 E2E tests (`tests/e2e`, Playwright × 3 viewport)

| รหัส | ไฟล์ | สถานการณ์ | FR | TOR |
|---|---|---|---|---|
| E2E-01 | `tests/e2e/public.spec.ts` | หน้าแรก: โลโก้ มมร. + สลับภาษา + สลับธีม (คงค่าหลังโหลดใหม่) + ไม่มี horizontal scroll | FR-150–FR-152 | ก.3.1.3, ก.3.2.1, 4.3.3 |
| E2E-02 | `tests/e2e/public.spec.ts` | `/tor` แสดง 200 ข้อ + กรองสถานะ + ค้นหา | FR-153 | 4.4 |
| E2E-03 | `tests/e2e/public.spec.ts` | `/documents` เปิดเอกสาร 1 ฉบับ + ดาวน์โหลด .md | FR-153 | 7.5 |
| E2E-04 | `tests/e2e/public.spec.ts` | หน้า help / privacy-policy / unavailable / 404 แสดงผลได้ | FR-154, FR-064 | 11.2, ก.1.1.3 |
| E2E-05 | `tests/e2e/public.spec.ts` | หน้าที่ต้องเข้าสู่ระบบ redirect ไป /login | FR-006 | ก.6.1.1 |
| E2E-06 | `tests/e2e/public.spec.ts` | FCP ของหน้าแรก < 5 วินาที | NFR-001 | 12.2 |
| E2E-07 | `tests/e2e/chat.spec.ts` | register → consent → login → เข้าหน้าแชต | FR-001, FR-002 | ก.3.3.1 |
| E2E-08 | `tests/e2e/chat.spec.ts` | รหัสผ่านผิดแสดงข้อผิดพลาด | FR-002 | ก.3.3.1 |
| E2E-09 | `tests/e2e/chat.spec.ts` | Mock OAuth: Gmail (โหมดสาธิต) → เลือกบัญชี → เข้าสู่ระบบ | FR-003 | ก.3.3.2 |
| E2E-10 | `tests/e2e/chat.spec.ts` | ถาม → อ้างอิง 3 รายการ + Expand All → บทสรุปมี citation → modal → 👍 → RAG Trace → ประวัติ | FR-010–FR-016 | ก.3.6.1–ก.3.6.3, ก.3.8.1, ก.3.5.1 |
| E2E-11 | `tests/e2e/chat.spec.ts` | คำถามต้องห้ามถูกปฏิเสธพร้อมเหตุผล (การเมือง / ใช่-ไม่ใช่) | FR-042, FR-035 | ก.4.4.3, ก.4.5.3 |
| E2E-12 | `tests/e2e/chat.spec.ts` | FCP ของหน้าแชต < 5 วินาที | NFR-001 | 12.2 |
| E2E-13 | `tests/e2e/chat.spec.ts` | Dhamma Talk: สร้าง artifact → แก้ไขใน modal → บันทึก → คำสั่งถัดไปคงข้อความที่แก้ | FR-020 | ก.3.7.1–ก.3.7.4 |
| E2E-14 | `tests/e2e/admin.spec.ts` | ทุกหน้าใน Admin เปิดได้ ไม่มี horizontal scroll | FR-152 | ก.6, 4.3.3 |
| E2E-15 | `tests/e2e/admin.spec.ts` | Dashboard: KPI มีค่า + เลือกช่วงเวลา + เทียบช่วงก่อนหน้า | FR-120 | ก.7.1 |
| E2E-16 | `tests/e2e/admin.spec.ts` | ตั้งค่า AI: เปลี่ยนค่า → มีผลทันที → ย้อนกลับด้วย snapshot | FR-080 | ก.6.2.6 |
| E2E-17 | `tests/e2e/admin.spec.ts` | Prompt: หลายเวอร์ชัน + diff + rollback แล้วคืนค่าเดิม | FR-082 | ก.6.2.4 |
| E2E-18 | `tests/e2e/admin.spec.ts` | Guardrails: ทดสอบข้อความที่หน้า admin | FR-044 | ก.6.2.5 |
| E2E-19 | `tests/e2e/admin.spec.ts` | Unavailable: เปิดโหมด → banner แสดงทุกหน้า → ปิดโหมด | FR-054 | ก.3.4.3, ก.6.6.1 |
| E2E-20 | `tests/e2e/admin.spec.ts` | Audit Log: ตรวจ hash chain = valid + export CSV | FR-111, FR-112 | ก.6.5 |
| E2E-21 | `tests/e2e/admin.spec.ts` | ผู้ใช้: ค้นหา + เปิดรายละเอียด | FR-100 | ก.6.1.2 |
| E2E-22 | `tests/e2e/admin.spec.ts` | ฐานองค์ความรู้: อัปโหลด TXT → job เสร็จ → ค้นเจอ → ลบ | FR-070, FR-073 | ก.6.3 |
| E2E-23 | `tests/e2e/admin.spec.ts` | Defect Log: ความรุนแรงสูง → deadline 24 ชม. → ปิดต้องมีหมายเหตุ | FR-140 | 12.3, 4.7.8 |
| E2E-24 | `tests/e2e/admin.spec.ts` | SLA report: ตัวเลขไม่ว่าง | FR-141 | 12.1–12.5 |
| E2E-25 | `tests/e2e/admin.spec.ts` | ผู้ใช้ทั่วไปเข้า /admin ไม่ได้ และ API ตอบ 403 | FR-006 | ก.6.1.1, ก.7.1.3 |
| E2E-26 | `tests/e2e/admin.spec.ts` | หน้า Backup / Data destruction แสดงสำหรับ SUPER_ADMIN | FR-142, FR-143 | ก.1.6.3, 4.11.3 |

ไฟล์สนับสนุน (ไม่ใช่กรณีทดสอบ): `tests/e2e/global-setup.ts`, `tests/e2e/helpers.ts`, `tests/helpers/{api,setup,global-setup,empty}.ts`, `tests/fixtures/kb/*` (ไฟล์ตัวอย่าง PDF/DOCX/TEI/TXT และ PDF ไม่มีชั้นข้อความ), `tests/unit/expected-clause-ids.json`

### 7.4 สรุป Traceability: FR ที่ยังไม่มีกรณีทดสอบอัตโนมัติโดยตรง

| FR | สถานะ | วิธีตรวจทดแทน |
|---|---|---|
| FR-060 (purge อัตโนมัติ) | endpoint `purge-conversations` ถูกเรียกใน regression (openapi-coverage) แต่ไม่มีกรณีที่รอ scheduler | ตรวจด้วย `npm run purge:conversations` และ audit `system` |
| FR-064 (GA หลังยินยอม) | ไม่มี E2E เฉพาะการโหลด GA | ตรวจด้วยตนเองตาม checklist (`/documents/test-checklist`) |
| FR-083 (`prompts:publish`) | ไม่มีกรณีทดสอบอัตโนมัติ | รันสคริปต์แล้วตรวจเวอร์ชันที่ `/admin/prompts` |
| FR-145 (logging) | ตรวจทางอ้อมผ่าน SLA report (ApiRequestLog) | ตรวจ `logs/app.log` |
| NFR-002/003/004 | วัดด้วยสคริปต์ ไม่ใช่ unit test | `/documents/performance-report`, `/documents/sla-monthly-report` |

## 8. การบริหารข้อบกพร่อง (Defect Management)

| หัวข้อ | แนวปฏิบัติ |
|---|---|
| เครื่องมือ | `/admin/defect-log` (ตาราง `DefectLog`) — ส่งออก CSV ได้ |
| ข้อมูลที่บันทึก | โมดูล, รายละเอียด, ความรุนแรง, ผู้แจ้ง, เวลาที่มหาวิทยาลัยแจ้ง (เริ่มนับ SLA), ผู้รับผิดชอบ, ระยะที่พบ (SIT/UAT), สถานะ, วิธีแก้และมาตรการป้องกันซ้ำ |
| ระดับความรุนแรงและ SLA (TOR 12.3) | critical/high 24 ชม., medium 48 ชม., low 10 วันทำการ (80 ชม.) นับเป็นชั่วโมงทำการ (`src/domain/report/sla-policy.ts`) |
| วงจรสถานะ | `open → in_progress → resolved → closed`; ปิด high/critical ต้องมี `resolutionNote`; การยืนยันของมหาวิทยาลัย (`confirmedAt`) สิ้นสุดการนับ (TOR 12.4) และคำนวณชั่วโมงเกิน + ค่าปรับโดยประมาณ 0.025%/ชม. ของมูลค่าสัญญา (TOR 10.2) |
| การทดสอบซ้ำ | ทุกการแก้ไขต้องเพิ่ม/ปรับกรณีทดสอบอัตโนมัติที่ครอบคลุมข้อบกพร่อง แล้วรัน `npm test` ทั้งชุด (regression) |
| ช่องโหว่ความปลอดภัย | npm audit High/Critical ถือเป็นข้อบกพร่องระดับ high ต้องแก้ก่อนใช้งานจริง (ก.2.2.2) |
| เกณฑ์ตรวจรับ | ไม่มี High/Critical ค้าง (การ์ดสรุปในหน้า Defect Log) |
| การรายงาน | สรุปใน Progress Report ทุก 30 วัน และรายงาน SLA รายเดือน |

## 9. รายงานผลการทดสอบ

ผลการรันจริงอยู่ในรายงานที่สร้างจากเครื่องมือ (ดูดัชนีที่ `/documents/test-reports-index`): `coverage-report`, `performance-report`, `vulnerability-scan-report`, `pentest-report` (บันทึกว่าไม่ได้ดำเนินการรอบนี้), `restore-test-report`, `baseline-evaluation-report`, `guardrail-security-report`, `ingestion-report`, `sla-monthly-report` และผล E2E ที่ `test-results/e2e-results.json`

## 10. บทบาทและความรับผิดชอบ

| บทบาท | หน้าที่ |
|---|---|
| QA Lead | จัดทำ/ปรับแผน ทบทวน Traceability ติดตาม Defect |
| Developer | เขียน unit/API test คู่กับฟีเจอร์ แก้ข้อบกพร่อง |
| AI Engineer | ดูแลชุด Benchmark และการประเมินคุณภาพ AI |
| คณะกรรมการ/ผู้ใช้ของมหาวิทยาลัย | UAT และยืนยันการแก้ไขข้อบกพร่อง |
