Appearance
v1.2 — 21/04/2026
| Thay đổi | Section | Ảnh hưởng |
|---|---|---|
| Khóa test coverage cho confidence rubric, hybrid refresh và role seed mặc định | D2, D3, TC-FR-004, TC-FR-008 | QA, BE, FE |
| Bổ sung test cho lifecycle mapping/backfill và cập nhật trace theo PRD v1.1 | D2, TC-FR-003, TC-FR-004 | QA, BE, FE |
| Khởi tạo QA test plan cho LTV Phase 1 | Toàn file | QA, BE, FE |
QA Test Plan — LTV Phase 1
Ref: PRD v1.2 | Date: 21/04/2026
QA plan này dùng để khóa regression ở các phần dễ vỡ nhất của LTV Phase 1: formula canonical, snapshot source, lifecycle mapping version và backfill job.
Nên đọc D2 Requirements Matrix trước, sau đó chạy lần lượt TC-FR-003, TC-FR-004, rồi mới mở rộng sang các test report / UI semantics.
D1) Coverage Scope
| FR | Mô tả | Priority |
|---|---|---|
| FR-001 | Tính đúng LTV chuẩn ở cấp customer | Must |
| FR-002 | Snapshot Nguồn gốc LTV chuẩn đúng 1 customer | Must |
| FR-003 | Mapping version hoạt động đúng | Must |
| FR-004 | Backfill tối đa + confidence đúng | Must |
| FR-005 | Bảng khách hàng LTV | Must |
| FR-006 | Bảng tổng hợp quản trị | Must |
| FR-007 | Bảng kiểm soát chất lượng dữ liệu | Must |
| FR-008 | Chỉnh tay nguồn gốc LTV có audit | Should |
| FR-009 | Semantics time/branch/service đúng wording + logic | Must |
| FR-010 | Scope guard phase 1 | Must |
D2) Requirements Matrix
| Area | What to verify | Risk |
|---|---|---|
| Revenue correctness | Payment/reverse events vào đúng formula | Sai CAC/LTV |
| Source correctness | Không rewrite lịch sử theo raw source động | Sai attribution |
| Versioning | Mapping version mới không tự remap snapshot cũ | Méo lịch sử |
| Lifecycle safety | draft/published/archived và queued/running/done/failed đi đúng rule | User publish/rerun sai thời điểm |
| Confidence rubric | high / medium / unknown đúng với từng loại evidence | Business hiểu sai độ tin cậy |
| Hybrid refresh | Event-driven + cron reconcile không đè sai snapshot lịch sử | Drift dữ liệu hoặc missed update |
| UI semantics | Label/filter không gây hiểu sai | Business đọc sai số |
| Admin actions | Chỉ Admin/IT làm được config/backfill/override | Sai RBAC |
D3) Seed Data
Dataset DS-001 — Customer revenue canonical
sql
-- Khách A:
-- 05/03/2025 thanh toán 5.000.000
-- 19/03/2025 thanh toán 3.000.000
-- 04/04/2025 thanh toán 10.000.000
-- 08/04/2025 refund 2.000.000
-- Expected LTV = 16.000.000Dataset DS-002 — Wallet / prepaid edge cases
sql
-- Khách B:
-- top-up ví chính 5.000.000 (không tính tại thời điểm nạp)
-- dùng 2.000.000 ví chính thanh toán invoice hợp lệ (được tính)
-- dùng 500.000 ví khuyến mãi (không tính)
-- Expected LTV = 2.000.000Dataset DS-003 — Source attribution / unknown
sql
-- Khách C:
-- customer_source hiện tại = ['facebook']
-- first_paid có evidence rõ -> map Quảng cáo trả phí / Facebook Ads
--
-- Khách D:
-- raw source hiện tại trống, không có evidence lịch sử
-- Expected source_group = 'Chưa xác định'Dataset DS-004 — Mapping version
sql
-- Version v1: raw_source 'facebook' -> Quảng cáo trả phí / Facebook Ads
-- Version v2: raw_source 'facebook' -> Quảng cáo trả phí / Meta Ads
-- Snapshot cũ trên khách dùng v1 phải giữ nguyên sau khi publish v2Dataset DS-005 — Manual override
sql
-- Khách E auto-map = Quảng cáo trả phí / Facebook Ads
-- Admin override -> Khách giới thiệu / CTV / Đối tác
-- reason = 'Đã xác minh lại từ case gốc'Dataset DS-006 — Confidence medium / conflicting signals
sql
-- Khách F:
-- customer_source hiện tại = ['tiktok']
-- không có historical evidence gần first_paid, không có manual override
-- Expected confidence = 'medium'
--
-- Khách G:
-- customer_source hiện tại = ['facebook', 'referral']
-- evidence mâu thuẫn / nhiều raw source
-- Expected confidence = 'unknown'D4) Test Cases
TC-FR-001: Base LTV
| TC | Mô tả | Input | Expected | Priority |
|---|---|---|---|---|
| TC-001-01 | Tính nhiều lần thanh toán | DS-001 | LTV = tổng payment hợp lệ | P0 |
| TC-001-02 | Trừ refund toàn phần / một phần | DS-001 | LTV giảm đúng số refund | P0 |
| TC-001-03 | Không tính top-up lúc nạp | DS-002 | top-up không làm tăng LTV | P0 |
| TC-001-04 | Ví chính được tính khi dùng thanh toán | DS-002 | chỉ phần tiêu vào invoice hợp lệ được cộng | P0 |
| TC-001-05 | Ví khuyến mãi không được tính | DS-002 | phần promo wallet = 0 impact | P0 |
| TC-001-06 | Timezone first paid | payment gần nửa đêm UTC | first_paid_at đúng theo Asia/Ho_Chi_Minh | P1 |
TC-FR-002: Source snapshot
| TC | Mô tả | Input | Expected | Priority |
|---|---|---|---|---|
| TC-002-01 | Mỗi khách chỉ có 1 source snapshot | customer bất kỳ | 1 row duy nhất trong snapshot | P0 |
| TC-002-02 | Raw source thay đổi sau này không rewrite snapshot | đổi customer_source của khách C | snapshot cũ giữ nguyên | P0 |
| TC-002-03 | Unknown là output hợp lệ | khách D | source_group = Chưa xác định | P0 |
TC-FR-003: Mapping version
| TC | Mô tả | Input | Expected | Priority |
|---|---|---|---|---|
| TC-003-01 | Publish version mới | v1 -> v2 | v2 active, v1 không bị overwrite | P0 |
| TC-003-02 | Snapshot lưu đúng version | khách C | mapping_version_id = v1 | P0 |
| TC-003-03 | Version mới không tự remap snapshot cũ | publish v2 | khách C vẫn giữ mapping v1 | P0 |
| TC-003-04 | Version published là read-only | mở version đã publish | không cho edit inline, chỉ cho clone/archive | P0 |
| TC-003-05 | Clone version published tạo draft mới | click Clone thành draft | có draft mới, version nguồn vẫn published | P1 |
| TC-003-06 | Publish bị chặn khi draft chưa đủ điều kiện | thiếu effective_from hoặc còn raw source chưa map | validation fail, giữ drawer mở và focus lỗi đầu tiên | P0 |
TC-FR-004: Backfill
| TC | Mô tả | Input | Expected | Priority |
|---|---|---|---|---|
| TC-004-01 | Full backfill tạo đủ snapshot | DS-001..003 | customer trong scope có snapshot | P0 |
| TC-004-02 | Confidence high khi có evidence rõ | khách C | confidence = high | P1 |
| TC-004-03 | Confidence unknown khi thiếu evidence | khách D | confidence = unknown | P0 |
| TC-004-04 | Job summary ghi unknown count | chạy backfill | summary_payload.unknown_count đúng | P1 |
| TC-004-05 | Publish version mới không auto chạy backfill | publish v2 | không tự tạo ltv_backfill_job mới | P0 |
| TC-004-06 | Job đi đúng state queued -> running -> done | chạy backfill thành công | badge/status và timestamps đúng | P0 |
| TC-004-07 | Rerun sau fail tạo job mới | 1 job failed rồi click Chạy lại | có row job mới queued, job failed cũ giữ nguyên audit | P1 |
| TC-004-08 | Incremental refresh chạy khi có payment/refund mới | phát sinh payment hoặc refund mới | customer bị ảnh hưởng được refresh mà không cần full backfill | P0 |
| TC-004-09 | Scheduled reconcile không rewrite snapshot lịch sử sang version mới | publish v2 rồi chạy reconcile định kỳ | snapshot cũ giữ mapping version trước, chỉ case active drift hợp lệ được sửa | P1 |
TC-FR-005: Customer table
| TC | Mô tả | Input | Expected | Priority |
|---|---|---|---|---|
| TC-005-01 | Hiển thị đủ cột chính | mở SCR-01 | có LTV, first paid, source, status | P0 |
| TC-005-02 | Filter cohort first paid | chọn kỳ 03/2025 | chỉ khách có first_paid_at trong kỳ | P0 |
| TC-005-03 | Filter chi nhánh first paid | chọn branch A | chỉ khách first_paid_branch_id = A | P0 |
| TC-005-04 | Filter nhóm dịch vụ khởi đầu | chọn Phun xăm | chỉ khách initial service group = Phun xăm | P0 |
| TC-005-05 | Export đúng dataset hiện tại | apply filter rồi export | file export khớp table | P1 |
TC-FR-006: Aggregate summary
| TC | Mô tả | Input | Expected | Priority |
|---|---|---|---|---|
| TC-006-01 | Bảng theo nguồn | default | nhóm nguồn + avg LTV đúng | P0 |
| TC-006-02 | Bảng theo chi nhánh dùng semantics first paid | default | label và dữ liệu theo first_paid_branch | P0 |
| TC-006-03 | Bảng theo nhóm dịch vụ dùng semantics khởi đầu | default | không phân bổ đa nhóm | P0 |
| TC-006-04 | Cohort filter không cắt revenue all-time | filter 03/2025 | khách A vẫn hiển thị full LTV all-time | P0 |
TC-FR-007: Data quality
| TC | Mô tả | Input | Expected | Priority |
|---|---|---|---|---|
| TC-007-01 | Hiển thị tỷ lệ unknown | có khách D | ratio đúng | P0 |
| TC-007-02 | Hiển thị case chỉnh tay | có khách E override | manual count tăng 1 | P1 |
| TC-007-03 | Hiển thị top raw source chưa map | tạo raw source lạ | panel hiển thị source chưa map | P1 |
TC-FR-008: Manual override
| TC | Mô tả | Input | Expected | Priority |
|---|---|---|---|---|
| TC-008-01 | Chỉ Admin/IT mới thấy action override | login user thường | không thấy action | P0 |
| TC-008-02 | Override bắt buộc lý do | submit rỗng reason | validation fail | P0 |
| TC-008-03 | Override thành công tạo audit | khách E | có row trong audit table | P0 |
| TC-008-04 | Sau override row hiển thị badge Chỉnh tay | khách E | status đúng | P1 |
| TC-008-05 | Override hợp lệ đẩy confidence lên high | khách E sau khi save override | confidence_level = high | P1 |
TC-FR-009: Semantics lock
| TC | Mô tả | Input | Expected | Priority |
|---|---|---|---|---|
| TC-009-01 | Filter label Cohort first paid | mở SCR-01 | wording đúng | P0 |
| TC-009-02 | Aggregate label Chi nhánh first paid | tab theo chi nhánh | wording đúng | P0 |
| TC-009-03 | Aggregate label Nhóm dịch vụ khởi đầu | tab theo dịch vụ | wording đúng | P0 |
| TC-009-04 | Tooltip LTV rõ nghĩa all-time | hover icon | không hiểu sai thành LTV trong kỳ | P1 |
TC-FR-010: Scope guard
| TC | Mô tả | Input | Expected | Priority |
|---|---|---|---|---|
| TC-010-01 | Không có multi-touch fields | inspect UI/API | không có field multi-touch | P1 |
| TC-010-02 | Không có forecast score | inspect UI/API | không có predictive fields | P1 |
D5) Entry / Exit Criteria
Entry
- PRD, UI Spec, Dev Spec đã lock.
- Mapping taxonomy nhóm nguồn chuẩn đã seed trên staging.
- Có seed data tối thiểu cho revenue / source / unknown / override.
Exit
- Tất cả test P0 pass.
- Không còn bug P0/P1 mở liên quan formula, source snapshot, versioning, semantics.
- Business sanity check pass:
- top 10 khách LTV cao nhìn hợp lý
- unknown ratio được giải thích được
- source group đọc đúng theo business expectation phase 1
D6) Traceability
| FR | TC-ID | Status |
|---|---|---|
| FR-001 | TC-001-* | ✅ |
| FR-002 | TC-002-* | ✅ |
| FR-003 | TC-003-* | ✅ |
| FR-004 | TC-004-* | ✅ |
| FR-005 | TC-005-* | ✅ |
| FR-006 | TC-006-* | ✅ |
| FR-007 | TC-007-* | ✅ |
| FR-008 | TC-008-* | ✅ |
| FR-009 | TC-009-* | ✅ |
| FR-010 | TC-010-* | ✅ |