Skip to content

Kế hoạch kiểm thử — Insight Ghi Âm cho BOD

Phiên bản: 1.0 Ngày: 15/05/2026 Mục đích: Test oracle — kỳ vọng hành vi cần verify. KHÔNG copy nguyên FR; chỉ map AC cần test cụ thể.


D1) Coverage

D1.1) Test pyramid

Loại testPhạm viTỷ lệ
Unit testChart data transform, date bucketing, WoW delta calc40%
Component testFilter dropdown behavior, KPI card render states, modal pagination30%
Integration testPermission check + query flow, URL params parsing20%
E2E test (Cypress)BOD login → access → drill-down; Staff blocked10%

D1.2) Browser & device

  • Browser support: Chrome (latest 3), Safari (latest 2), Firefox (latest 2), Edge (latest 2)
  • Resolution: 1280×800 minimum (desktop only, không mobile P0)
  • Network: test với 3G simulated cho slow query scenarios

D2) Requirements Matrix (FR → AC → Test ID)

FR-001: Dashboard 5 KPI cards

Test IDMô tả testAC refLoại
TC-001-1Page load lần đầu < 2s với data có sẵn (staging seed 24k records 7 ngày × 70 CN)AC-001-1Integration + Performance
TC-001-2Skeleton loading hiển thị TRƯỚC khi data loadAC-001-1Component
TC-001-3Filter change → KPI re-fetch với loading state intermediateAC-001-2Integration
TC-001-4Delta indicator: positive → ▲green, negative → ▼red, no change → ─grayAC-001-3Component
TC-001-5Hover ⓘ icon → tooltip hiển thị sau 300ms với content đúng theo B9 dictionaryAC-001-4Component
TC-001-6KPI #4 "Tuân thủ" mẫu số = 0 → hiển thị "—" không "0%"/"NaN%"AC-001-5Component edge case
TC-001-7KPI #2 "Thời lượng TB" warning "X cuộc không có metadata" khi reference_file.duration IS NULL ở vài recordsAC-001-6Integration

FR-002: Trend Chart

Test IDMô tả testAC refLoại
TC-002-1Hover 1 điểm → tooltip "Thứ X, DD/MM/YYYY: N cuộc"AC-002-2Component
TC-002-2Click 1 điểm ngày 12/05 → navigate URL /e/record?dateExact=2026-05-12&branchId=<scope>AC-002-3E2E
TC-002-3Period < 2 ngày data → empty state "Chưa đủ dữ liệu để vẽ xu hướng"AC-002-4Component
TC-002-4Time range = 365 ngày → chart vẫn render với pagination/sampling phù hợpAC-002-5Performance
TC-002-5Time range > 365 → input picker disable ApplyAC-002-5 + EdgeCase G4Component

FR-003: Top Staff

Test IDMô tả testAC refLoại
TC-003-1Hiển thị top 10 NV theo số cuộc, sorted descAC-003-1Integration
TC-003-2Click bar NV Lam → navigate /e/record?staffId=<lam_uuid>&from=&to=&branchId=AC-003-2E2E
TC-003-3Empty state khi không có dataAC-003-3Component
TC-003-4Tên NV display dùng account.display_name (KHÔNG full_name)(Pitfalls Map)Integration

FR-004: Heatmap

Test IDMô tả testAC refLoại
TC-004-1Cell color theo amber scale chuẩn (0/1-3/4-7/8+)AC-004-1Component
TC-004-2Hover cell → tooltip "Thứ X lúc Hh: N cuộc, TB Y phút"AC-004-2Component
TC-004-3Click cell T5 10h → navigate /e/record?dateExact=<recent_T5>AC-004-3E2E
TC-004-4Auto-hide giờ 22h-7h không có hoạt độngAC-004-4Component
TC-004-5Legend "Ít / Nhiều" hiển thị với color scaleAC-004-5Component

FR-005: Branch Top + "Khác"

Test IDMô tả testAC refLoại
TC-005-1Top 10 branches hiển thị với % tổngAC-005-1Integration
TC-005-2Row "Khác (N CN)" gộp các CN ngoài top 10AC-005-2Component
TC-005-3Click bar Long Khánh → navigate /e/record?branchId=<lk_uuid>AC-005-3E2E
TC-005-4CTA "[Xem tất cả 70 CN →]" hiển thị (defer P2 — visual only)AC-005-4Component

FR-006: Missing Records Modal

Test IDMô tả testAC refLoại
TC-006-1Title dynamic "N lịch hẹn..." với N = count thực tếAC-006-1Integration
TC-006-2Click CTA → modal mở với pagination 10 rows/pageAC-006-2E2E
TC-006-3Search box filter realtime → reset page 1AC-006-3 + DEC-013Component
TC-006-4Sort dropdown thay đổi order → re-fetch + reset page 1AC-006-3Component
TC-006-5Empty state khi count = 0AC-006-4Component
TC-006-6Click row [Mở] → tab mới /appointment/<id>AC-006-2E2E
TC-006-7Page size selector 10/20/50 → re-fetch với limit phù hợpDEC-013Component
TC-006-8Server-side pagination — không load tất cả records cùng lúcDEC-013Integration + Performance
TC-006-9Modal P0 KHÔNG hiển thị Export Excel button (defer P2 theo DEC-014)AC-006-3 + DEC-014Component

FR-007: KH chờ TV Modal

Tương tự FR-006 nhưng với additional:

Test IDMô tả testAC ref
TC-007-1 đến TC-007-7Tương tự TC-006-1 đến TC-006-7 nhưng cho AnomalyMissingTVModalAC-007-1 đến 4
TC-007-8Filter "Lọc lý do" với 3 options (no-show / compliance gap / pending)AC-007-3
TC-007-9Row có 2 action: [Mở appt] + [KH] (tab mới khác nhau)AC-007-4

FR-008: Filter Bar (70 CN + 700 NV)

Test IDMô tả testAC refLoại
TC-008-1Branch dropdown — search "Long" → filter 1 results realtimeAC-008-1Component
TC-008-2Branch dropdown — "Chọn tất cả" → 70/70 selectedAC-008-1Component
TC-008-3Branch dropdown — group by region (nếu BE có) HOẶC flat list với searchAC-008-1 + PD-001Component
TC-008-4Date range picker — preset "7 ngày qua" → calc đúng (today - 6 days đến today)AC-008-2Unit
TC-008-5Date range picker — custom range > 365 ngày → disable ApplyAC-008-2 + EdgeCaseComponent
TC-008-6Staff dropdown — empty state mặc định (KHÔNG render 700 NV)AC-008-3Component
TC-008-7Staff dropdown — type "lam" → debounce 300ms → fetch 10 resultsAC-008-3Integration
TC-008-8Filter change → reset pagination về page 1 ở tất cả widget có paginationAC-008-5Integration
TC-008-9BOD login với view_all → default 70 CN; BranchManager → branches của họAC-008-6Integration + Permission

FR-009: Audio drill-down

Test IDMô tả testAC refLoại
TC-009-1Click chart segment → navigate /e/record?<params> với params correctAC-009-1E2E
TC-009-2/e/record parse query params và apply vào filterAC-009-2Integration
TC-009-3Player HTML5 hoạt động không thay đổi (regression)AC-009-3Regression
TC-009-4Browser back → quay lại dashboard với filter state giữ nguyênAC-009-4E2E
TC-009-5File audio 404 → toast "File audio không khả dụng" (EdgeCase G7)EdgeCase G7Integration

FR-010: Permission v2

Test IDMô tả testAC refLoại
TC-010-1BOD login → sidebar "Insight Ghi Âm" + button trên /e/record hiển thịAC-010-1, 2E2E
TC-010-2Staff login → sidebar + button KHÔNG hiển thịAC-010-1, 2E2E
TC-010-3Staff truy cập URL trực tiếp /e/record/insights → redirect /forbiddenAC-010-3E2E
TC-010-4ITLeader bypass branch filter (view_all) → thấy data 70 CNAC-010-1Integration
TC-010-5Migration seed correct: row mới trong module_permission_action (module_id='voice_recording_management', action='view_insight'); BOD + ITLeader có 'view_insight' = ANY(role_module.actions)AC-010-4Integration (DB query)
TC-010-6Admin (ROLE_MODERATOR) bypass tất cả checksAC-010-5E2E
TC-010-7User mất quyền giữa session → next API 403 → toast + redirectEdgeCase G3Integration
TC-010-8 (NEW PD-011)JWT claim x-hasura-allowed-branches middleware — Decode JWT 3 role: BOD/ITLeader chứa list 70 branch UUIDs; BranchManager chứa own branch IDs; Staff (no view_insight) chứa [] empty arrayPD-011 + G-PERM-6Integration (JWT decode test)
TC-010-9 (NEW PD-011)Direct Hasura GraphQL query 3 materialized views: Staff token (claim []) → record_daily_summary query → trả 0 rows. BOD token (claim 70 IDs) → trả full rowsPD-011 + G-PERM-6Integration (Hasura security boundary)
TC-010-10 (NEW PD-011)Hasura filter _in: [] empty branches behavior — verify PostgreSQL returns empty set (secure default)PD-011Unit (Hasura/SQL)

FR-011: /e/record extend

Test IDMô tả testAC refLoại
TC-011-1URL /e/record?staffId=X&from=Y&to=Z → filter pre-appliedAC-011-1E2E
TC-011-2URL ?dateExact=12/05/2026 → from = to = 12/05/2026AC-011-2E2E
TC-011-3URL ?durationGt=3600 → table filter records duration > 1hAC-011-3Integration
TC-011-4URL không có params → RecordTable hoạt động như cũ (regression)AC-011-4Regression

D3) Dữ liệu mẫu (Seed Data) cho staging benchmark

D3.1) Required data

EntityCountNote
Branch70Realistic distribution (28 TP HCM, 24 HN, 12 ĐN, 3 HP, 3 CT)
NV (account)~70010 NV/branch trung bình
Customer~10,000Spread across branches
Appointment~50,00030 ngày qua, mix status
Record~105,00030 ngày × 3,500/day; mix duration (short < 1m, normal 5-15m, long > 60m)
Reference_file~105,0001:1 với records (mostly); some NULL duration để test edge case

D3.2) Permission seed

  • 5 BOD users với role BOD + action view_insight
  • 3 ITLeader users
  • 1 Admin (ROLE_MODERATOR)
  • 10 Branch Manager
  • 50 Staff (test access deny)

D4) Ca kiểm thử (Test Cases) — Hành trình quan trọng (Critical Path E2E)

TC-CRITICAL-001: BOD happy path

  1. Login as BOD user bod@diva.vn
  2. Click sidebar "Insight Ghi Âm" → navigate /e/record/insights
  3. Verify dashboard load < 2s với data 7 ngày × 70 CN
  4. Verify 5 KPI cards hiển thị với số liệu + delta
  5. Verify 4 chart render
  6. Verify 2 anomaly cards với count
  7. Change filter: chọn "30 ngày qua" → loading state → re-fetch → render < 3s
  8. Change filter: chọn 3 chi nhánh cụ thể → loading → render
  9. Click Top Staff bar Nguyễn T. Lam → navigate /e/record?staffId=<lam_uuid>&from=&to=&branchId= (open same tab)
  10. Trên /e/record, verify filter pre-applied + records hiển thị
  11. Click play 1 record → audio modal mở → playback OK
  12. Browser back → quay lại dashboard với filter state intact
  13. Click anomaly 🔴 Missing → modal mở với pagination
  14. Search "Trần V. Hùng" trong modal → filter realtime → reset page 1
  15. Navigate page 2 → fetch + render
  16. Click [Mở] row → tab mới /appointment/<id>
  17. Close modal → quay về dashboard

TC-CRITICAL-002: Staff access deny

  1. Login as Staff user
  2. Verify sidebar KHÔNG có "Insight Ghi Âm"
  3. Verify /e/record KHÔNG có button [📊 Insight →]
  4. Type URL /e/record/insights trong browser → redirect /forbidden
  5. Verify error message phù hợp

TC-CRITICAL-003: Performance benchmark (DEC-012 P0 gate)

  1. Seed staging với 105k records × 70 CN × 30 ngày
  2. BOD login → mở dashboard với default filter (7 ngày)
  3. Verify TTFMP < 2s (Sentry transaction tracking)
  4. Change filter to 30 ngày → Verify TTFMP < 3s
  5. Run EXPLAIN ANALYZE cho 7 GraphQL queries trong dev-spec C5
  6. Verify KHÔNG có Seq Scan trên record / appointment (must use indexes)
  7. Check Hasura cache hit rate qua admin console
  8. Verify URQL cache-and-network: lần 2 load < 200ms (cached)

D5) Entry / Exit Criteria

D5.1) Entry criteria (đủ điều kiện bắt đầu QA)

  • ☐ All 11 FR implemented và unit tested (FE Dev report)
  • ☐ Migrations chạy thành công trên staging (4 indexes + permission seed + 3 materialized views + Hasura YAML + scheduler)
  • ☐ Seed data có sẵn (D3.1)
  • 6 PD critical RESOLVED bởi BE TL + PO (đây là PREREQUISITE — KHÔNG được mark ✅ cho đến khi PD-status trong SOURCE_OF_TRUTH chuyển sang "Resolved"):
    • PD-001 (region grouping schema)
    • PD-003 (appointment baseline status/type/service_type/consultant_behavior)
    • PD-005 (action name view_insight confirm)
    • PD-007 (reference_file.url presigned hay raw)
    • PD-008 (performance benchmark plan trên staging)
    • PD-011 (JWT claim x-hasura-allowed-branches BE middleware implemented + tested) — Block ship P0 BE security
  • ☐ Cypress E2E setup hoạt động

D5.2) Exit criteria (đủ điều kiện ship P0)

  • ✅ 100% TC-001 đến TC-011 PASS
  • ✅ 100% TC-CRITICAL-001 đến TC-CRITICAL-003 PASS
  • ✅ Performance gate: TTFMP < 2s/7d, < 3s/30d (TC-CRITICAL-003)
  • ✅ Permission gate: 0 unauthorized access (TC-010, TC-CRITICAL-002)
  • ✅ Regression: existing /e/record không break (TC-011-4 + manual smoke test)
  • ✅ Zero critical bugs (P0/P1 severity)
  • ✅ Documentation review: BOD demo session OK

D5.3) Defect severity

SeverityĐịnh nghĩaBlock ship?
P0 CriticalCrash, data loss, security breachYES
P1 HighCore flow broken, BOD không thể dùngYES
P2 MediumEdge case fail, UX issueNO (ship + fix patch)
P3 LowMinor visual, typoNO

D6) Performance Test Plan

D6.1) Load test scenarios

ScenarioConcurrent usersDurationExpected
Normal load10 BOD users30 minTTFMP < 3s, no errors
Peak load30 users15 minTTFMP < 5s, < 1% error rate
Stress test50 users (max)10 minIdentify bottleneck (DB CPU, Hasura, FE)

D6.2) Tools

  • Sentry transactions cho TTFMP tracking
  • pg_stat_statements cho top slow queries
  • Hasura admin cache hit metrics
  • Lighthouse CI cho FE performance score

D7) Regression Suite (chạy mỗi release)

  • TC-009-3: /e/record player HTML5 hoạt động
  • TC-011-4: /e/record không có URL params → behavior cũ
  • /e/record download ZIP + delete file flow (existing functionality)
  • Permission v2 không break các module khác đã dùng hasPermission API

Cross-ref:

  • PRD: ./prd.md A5 FR/AC
  • UI Spec: ./ui-spec.md
  • Dev Spec: ./dev-spec.md C5 queries + C12 traceability
  • Go-Live: ./go-live-checklist.md