Appearance
QA Test Plan: Cải thiện UX cài đặt Mã Công Việc / Tiền Tour
Feature slug: settings-ux-subtask-tagVersion: 1.0 Ngày: 2026-03-26
D1) Coverage
| Loại | Số lượng | Chi tiết |
|---|---|---|
| FR | 8 | FR-001 → FR-008 |
| NFR | 2 | NFR-001, NFR-003 |
| Edge Cases | 10 | EC-01 → EC-10 |
| Test Cases | 30 | TC-FR-001 → TC-FR-008, TC-BR-001 → TC-BR-003, TC-NFR-001 → TC-NFR-002, TC-EC-001 → TC-EC-010, TC-CP-001 → TC-CP-003 |
D2) Requirements Matrix
| FR/NFR | Test Cases | Priority |
|---|---|---|
| FR-001 Trang TourFeeConfig | TC-FR-001a (accordion), TC-FR-001b (CRUD group), TC-FR-001c (CRUD tag) | Critical |
| FR-002 Range + Chi tiết | TC-FR-002a (flat), TC-FR-002b (multi), TC-FR-002c (empty) | High |
| FR-003 "Đang dùng bởi" | TC-FR-003a (count), TC-FR-003b (expand list) | High |
| FR-004 Tag chip enriched | TC-FR-004a (settings), TC-FR-004b (projects), TC-FR-004c (ecommerce) | Critical |
| FR-005 Tooltip | TC-FR-005 | High |
| FR-006 Dropdown enriched | TC-FR-006 | High |
| FR-007 SubTaskTable | TC-FR-007a (cột), TC-FR-007b (filter), TC-FR-007c (fix label) | High |
| FR-008 Rename + redirects | TC-FR-008a (sidebar), TC-FR-008b (redirects), TC-FR-008c (route name) | Critical |
| Blast radius | TC-BR-001 (TaskForm), TC-BR-002 (OrderTaskLimitForm), TC-BR-003 (ServiceSubtaskItem) | Critical |
| NFR-001 Page load | TC-NFR-001 | High |
| NFR-003 SubTaskTable | TC-NFR-002 | High |
D3) Seed Data
Dataset SD-01: Nhóm + Tags + Tour Moneys
Precondition: Dùng data sẵn có trên test env. Verify:
sql
-- Verify có ít nhất 2 nhóm tiền tour
SELECT id, code, name FROM project_task_group_tag WHERE disabled = false LIMIT 5;
-- Verify có tags với tour_moneys
SELECT t.id, t.code, t.name, t.group_tag_id,
array_agg(tm.tour_money ORDER BY tm.seniority) as tour_moneys
FROM project_task_tag t
LEFT JOIN tag_tour_money tm ON tm.tag_id = t.id
WHERE t.disabled = false
GROUP BY t.id
LIMIT 10;
-- Verify có subtask dùng tags
SELECT s.code, s.name, array_agg(st.tag_id) as tag_ids
FROM subtask s
JOIN subtask_tag st ON st.subtask_id = s.id
GROUP BY s.id
LIMIT 10;Dataset SD-02: Tag flat-rate + multi-rate
sql
-- Tìm 1 tag flat-rate (tất cả cấp bậc = nhau)
SELECT tag_id, array_agg(DISTINCT tour_money) as unique_amounts
FROM tag_tour_money
GROUP BY tag_id
HAVING count(DISTINCT tour_money) = 1
LIMIT 1;
-- Tìm 1 tag multi-rate (cấp bậc khác nhau)
SELECT tag_id, array_agg(DISTINCT tour_money) as unique_amounts
FROM tag_tour_money
GROUP BY tag_id
HAVING count(DISTINCT tour_money) > 1
LIMIT 1;Dataset SD-03: Tag chưa cấu hình tour money
sql
-- Tìm tag không có tour_moneys
SELECT t.id, t.code, t.name
FROM project_task_tag t
LEFT JOIN tag_tour_money tm ON tm.tag_id = t.id
WHERE tm.id IS NULL
LIMIT 1;D4) Test Cases
Critical Path Tests
| TC-ID | Tên | Steps | Expected | Priority |
|---|---|---|---|---|
| TC-CP-001 | E2E: Tạo nhóm → tạo tag → gán vào subtask | 1. Mở Cấu Hình Tiền Tour 2. [+ Nhóm] → tạo "Test Group" 3. Expand → [+ Thêm tag] → tạo tag T-TEST 4. Mở Mã Công Việc → edit SUB280 5. Search T-TEST → chọn 6. Lưu | Nhóm + tag tạo thành công. SUB280 có chip [T-TEST — {range}] | Critical |
| TC-CP-002 | E2E: Verify blast radius — KTV chọn tag enriched | 1. Mở chi tiết khách hàng → Tab Công Việc 2. Tạo subtask → field "Loại tiền tour" 3. Mở dropdown | Dropdown hiện: Mã + Tên + Range + Nhóm (enriched format) | Critical |
| TC-CP-003 | E2E: Route redirect + link ecommerce | 1. Mở URL cũ /s/internal-settings/task-tag 2. Mở URL cũ /task-tag/{id} 3. Trong form đơn hàng, click link tag | Tất cả redirect đúng sang /tour-fee-config. Link ecommerce vẫn mở đúng. | Critical |
FR Test Cases
| TC-ID | FR | Tên | Steps | Expected | Priority |
|---|---|---|---|---|---|
| TC-FR-001a | FR-001 | Accordion expand/collapse | Mở Cấu Hình Tiền Tour → click ▼ nhóm | Expand hiện bảng tags. Click ▶ collapse. | Critical |
| TC-FR-001b | FR-001 | CRUD nhóm | [+ Nhóm] → nhập code + name → Lưu. [Sửa nhóm] → đổi name → Enter | Nhóm tạo/sửa thành công | High |
| TC-FR-001c | FR-001 | CRUD tag trong nhóm | [+ Thêm tag] → form side dialog → nhập → Lưu. [Sửa] → đổi → Lưu | Tag tạo/sửa trong nhóm | High |
| TC-FR-002a | FR-002 | Range flat-rate | Mở nhóm có tag T26 (tất cả CĐ = 100k) | Range = "100,000đ", Chi tiết = "CĐ1-5: đều 100k" | High |
| TC-FR-002b | FR-002 | Range multi-rate | Mở nhóm có tag T15 (CĐ khác nhau) | Range = "50k~120k", Chi tiết = "CĐ1:50k ... CĐ5:120k" | High |
| TC-FR-002c | FR-002 | Range empty | Mở nhóm có tag chưa config tour money | Range = "—", Chi tiết = "Chưa có tiền tour" | Medium |
| TC-FR-003a | FR-003 | Usage count | Mở nhóm có tags đang dùng | Footer hiện "Đang dùng bởi: N mã công việc" (N > 0) | High |
| TC-FR-003b | FR-003 | Usage expand | Click [Xem ↗] | Expand danh sách: Mã, Tên công việc, Tags | High |
| TC-FR-004a | FR-004 | Chip enriched (settings) | Mở edit subtask có tag T26 | Chip hiện "[T26 — 100,000đ ×]" (không phải "[100k ×]") | Critical |
| TC-FR-004b | FR-004 | Chip enriched (projects) | Mở TaskForm tạo subtask → chọn tag | Selected hiện "T26 — 100k — 100,000đ (Tiền tour 2024)" | Critical |
| TC-FR-004c | FR-004 | Display enriched (ecommerce) | Mở OrderTaskLimitForm có tag | Tag hiện "T08 (80,000đ)" thay vì "Ok" | Critical |
| TC-FR-005 | FR-005 | Tooltip tiền tour | Hover chip tag trong SubTaskForm | Tooltip hiện: tên, nhóm, bảng 5 CĐ + tiền, link "Xem chi tiết ↗" | High |
| TC-FR-006 | FR-006 | Dropdown enriched | Mở SubTaskForm → search tag | Dropdown option hiện: Mã + Tên + Range + Nhóm | High |
| TC-FR-007a | FR-007 | Cột tag trong SubTaskTable | Mở Mã Công Việc | Cột "Tag tiền tour" hiện data (VD: "T08: 80,000đ") | High |
| TC-FR-007b | FR-007 | Filter nhóm/tag | Chọn filter [Nhóm tiền tour: Tiền tour 2024] | List filter đúng subtask có tags thuộc nhóm đó | High |
| TC-FR-007c | FR-007 | Fix label swap | Xem bảng SubTaskTable | Cột 3 = Loại (Dịch vụ/Thủ công), Cột 4 = Tên công việc. Đúng label. | Medium |
| TC-FR-008a | FR-008 | Sidebar rename | Mở sidebar "Quản Lý Công Việc" | Hiện "Mã Công Việc" (không phải "Công Việc"), "Cấu Hình Tiền Tour" (gộp 2 cũ) | High |
| TC-FR-008b | FR-008 | Path redirect | Navigate /s/internal-settings/task-tag | Redirect sang /s/internal-settings/tour-fee-config | Critical |
| TC-FR-008c | FR-008 | Route name redirect | Trong OrderTaskLimitForm, click tag link | Mở /tour-fee-config?tag={id} (không 404) | Critical |
Blast Radius Tests
| TC-ID | Nơi | Steps | Expected | Priority |
|---|---|---|---|---|
| TC-BR-001 | TaskForm (projects) | Tạo subtask → field "Loại tiền tour" → chọn tag → verify tiền tour auto-fill | Dropdown enriched + tiền tour fill đúng theo cấp bậc KTV | Critical |
| TC-BR-002 | OrderTaskLimitForm | Mở form đơn hàng có subtask với tag → xem hiển thị tag | Tag hiện "T08 (80,000đ)" + link xanh cho IT | Critical |
| TC-BR-003 | ServiceSubtaskItem | Mở cài đặt dịch vụ có subtask với tag | Tag hiện "T08 (80,000đ)" + link xanh cho IT | Critical |
NFR Test Cases
| TC-ID | NFR | Steps | Expected | Priority |
|---|---|---|---|---|
| TC-NFR-001 | NFR-001 | Mở trang Cấu Hình Tiền Tour (cold load) | First meaningful paint < 1s | High |
| TC-NFR-002 | NFR-003 | Mở Mã Công Việc (275+ rows + cột tag) | Table render < 500ms | High |
Edge Case Test Cases
| TC-ID | EC | Steps | Expected | Priority |
|---|---|---|---|---|
| TC-EC-001 | EC-01 | Tạo nhóm mới (0 tags) → expand | Hiện "Chưa có tag. Bấm [+ Thêm tag tiền tour]" | Medium |
| TC-EC-002 | EC-02 | Xem tag chưa config tour money | Range = "—", Chi tiết = "Chưa có tiền tour" | Medium |
| TC-EC-003 | EC-03 | Edit subtask type = Thủ công | Field "Tag tiền tour" readonly, list hiện "—" | Medium |
| TC-EC-004 | EC-04 | Subtask có 4+ tags | Chips wrap, SubTaskTable hiện 2 tags + "+N more" | Medium |
| TC-EC-005 | EC-05 | Search tag không tìm thấy | Dropdown trống + "Không tìm thấy" | Low |
| TC-EC-006 | EC-06 | Xóa nhóm đang có tags | Block + toast "Nhóm đang có N tag..." | High |
| TC-EC-007 | EC-07 | Navigate URL cũ /task-tag/abc123 | Redirect → /tour-fee-config?tag=abc123 | High |
| TC-EC-008 | EC-08 | Tag disabled đã gán vào subtask | Chip hiện bình thường, dropdown filter ra | Medium |
| TC-EC-009 | EC-09 | Tất cả tiền tour = 0 | Range = "0đ" | Low |
| TC-EC-010 | EC-10 | Group có 50+ tags | Bảng tags trong accordion phân trang | Medium |
D5) Entry / Exit Criteria
Entry Criteria
- [ ]
pnpm codegenpass (GraphQL fragments mở rộng thành công) - [ ] TourFeeConfig page render (không error)
- [ ] TaskTagSelect enriched chip hiển thị đúng
- [ ] Test accounts: IT Leader, IT Staff, Admin, Manager, Staff (KTV)
- [ ] Test data: ít nhất 2 nhóm, 5+ tags, subtasks có tags
Exit Criteria
- [ ] 3/3 Critical Path tests pass (TC-CP-001 → TC-CP-003)
- [ ] 18/18 FR tests pass
- [ ] 3/3 Blast Radius tests pass
- [ ] 2/2 NFR tests pass
- [ ] 10/10 Edge Case tests pass
- [ ] Route redirects hoạt động cho tất cả route cũ
- [ ] Tiền tour auto-fill trong TaskForm KHÔNG bị ảnh hưởng
- [ ] No P1/P2 bugs open