Giao diện
US-S06: Kiểm tra các trạng thái chặn xóa học viên (luồng 3B) ​
Thuộc FS: 00-overview.md — SAPP-26297 Chuyển nhượng học viên (tool
sapp.011) Phần chung (tổng quan, roles, flow tổng, related features, NFR, Open Questions, References) xem ở Overview. File này chỉ chứa nội dung riêng của US.Cơ chế chạy bước, tự chấm, xác nhận GHI → US-S01. Câu SQL → US-S02 §4. Danh sách trạng thái bị chặn là kỳ vọng theo guide QA (nghiệp vụ Ops), không phải rule mind_keep cài.
| Field | Value |
|---|---|
| US ID | US-S06 |
| Role thực hiện | R1 - Người dùng tool — Assumption (OQ về G-01 → OQ-S-01) |
| Phase | As-built (đã triển khai @ e77c47a) |
| Priority | N/A — as-built |
| Status | Draft |
| NFR liên quan | NFR-S-01, NFR-S-02 — xem Overview §5 |
| OQ liên quan | OQ-S-01, OQ-S-04, OQ-S-12, OQ-S-14 — xem Overview §6 |
1. US Statement ​
text
As a Người dùng tool [Assumption — OQ-S-01]
I want dựng từng trạng thái học viên trong lớp rồi gọi xoá học viên khỏi lớp (đơn lẻ và hàng loạt)
để xác nhận Ops chặn đúng 8 trạng thái và vẫn xoá phần hợp lệ
So that [Assumption — OQ-S-18] kiểm được hành vi chặn xoá trên nhánh sapp-sprint-49 (SAPP-28419 chạy trước)2. Dependencies & Definition Of Ready ​
N/A — đã triển khai. Dependency runtime:
| # | Cần sẵn sàng | Ai cung cấp | Trạng thái |
|---|---|---|---|
| D1 | Fixture nhóm 3B: class_id, user_x, user_y — tài khoản test riêng vì bị xoá mềm thật | Tester | — |
3. Business Rules ​
| ID | Rule | Áp dụng ở | Đã cover bởi (AC) | Nguồn code (Mode B/C) |
|---|---|---|---|---|
| BR-01 | Bước xoá gửi danh sách học viên (ô user, id cách nhau dấu phẩy, tách thành mảng), lớp (classId) và lý do mặc định "test SAPP-26297"; đây là thao tác GHI – xoá mềm thật trên Ops | M1 - bước xoá | AC-M1.1 → AC-M1.5 | fe/src/ui/components/works/sapp/sapp-26297-flows.ts:452-472 · fe/src/ui/components/works/sapp/sapp-26297-step-call.tsx:118-129 |
| BR-02 | Tool dựng trạng thái cho user_x bằng panel SQL nhóm B: câu 1 đọc trạng thái user_x / user_y, câu 2 đặt type = target_type (tester nhập), câu 3 khôi phục học viên bị xoá mềm | M1 - panel grpb | AC-M1.1 → AC-M1.3 | sapp-26297-flows.ts:504-535 · be/libs/constants/src/lib/sapp/sapp-26297-sql.constants.ts:211-228 |
| BR-03 | Xoá một học viên ở trạng thái bị chặn (3.8 TRANSFERED_TO, 3.9 BE_TRANSFERRED, 3.12 RESERVED, 3.13 RETAKING, 3.14 REASSIGNED) đạt khi "Từ chối đúng" 400|490037 · exceptions.class_user_cannot_be_removed; 3.13, 3.14 ghi chú "ĐỔI so với production" | M1 - case 3.8, 3.9, 3.12 → 3.14 | AC-M1.1 | sapp-26297-flows.ts:1166-1188,1226-1228 |
| BR-04 | Xoá hàng loạt 1 học viên chuyển nhượng + 1 NORMAL (3.10) đạt khi HTTP 200, user_x có trong danh sách bị bỏ qua, user_y không có trong đó | M1 - case 3.10 | AC-M1.2 | sapp-26297-flows.ts:1190-1214 |
| BR-05 | Xoá hàng loạt khi tất cả bị chặn (3.11) đạt khi 400|490037 | M1 - case 3.11 | AC-M1.3 | sapp-26297-flows.ts:1216-1225 |
| BR-06 | Xoá một học viên NORMAL (3.15) đạt khi HTTP 200, user_x có trong danh sách đã xoá, danh sách bị bỏ qua rỗng | M1 - case 3.15 | AC-M1.4 | sapp-26297-flows.ts:1230-1242 |
| BR-07 | Xoá học viên đã ở lớp Lesson khác (3.16) đạt khi HTTP 200 và danh sách học viên không hợp lệ không rỗng (cơ chế cũ, định danh bằng họ tên) | M1 - case 3.16 | AC-M1.5 | sapp-26297-flows.ts:1244-1255 |
| BR-08 | Case "UI" (checkbox trên màn Ops bị disable) chỉ là hướng dẫn kiểm tay — API không trả cờ được-xoá | M1 - case UI | AC-M1.6 | sapp-26297-flows.ts:1257-1269 |
| BR-09 | Một phần tử danh sách được coi là "học viên X" khi là chuỗi = id, hoặc object có user_id / id / user.id = id (shape skipped / removed chưa đo — đoán theo handover 0045) | M1 - check danh sách | AC-M1.2, AC-M1.4 | sapp-26297-step-call.tsx:217-224 · shared/integration/0045-be-sapp-26297-transfer-tool.md:52-54 |
4. Design ​
a. Mối liên hệ giữa các màn & User Flow ​
text
[Tab "3B · Chặn xóa học viên"]
↓ mỗi case
[SQL grpb: đọc → dựng target_type cho user_x (GHI)] → [xoá học viên (GHI – xoá mềm Ops)] → [hướng dẫn verify / khôi phục bằng grpb câu 3]b. Chi tiết từng màn ​
Màn M1 - Tab "3B · Chặn xóa học viên" ​
| Field | Value |
|---|---|
| Figma frame | N/A |
| Trigger vào màn | Bấm tab "3B · Chặn xóa học viên" |
| Mô tả ngắn | Tóm tắt: "Test trên sapp-sprint-49 (SAPP-28419 chạy trước): lọc người bị chặn ra rồi xóa tiếp phần hợp lệ. 400|100334 KHÔNG còn fire qua UI. 8 trạng thái bị chặn: RESERVED · RETOOK · RETAKING · MOVED_OUT · REASSIGNED · TRANSFERED_TO · BE_TRANSFERRED · WITHDRAWN. Xóa được: NORMAL · CANCELED · MOVED_IN. ⚠ Xóa MỀM thật — dùng tài khoản test riêng." 10 case |
UI States ​
| State | Khi nào | Hiển thị | Figma frame |
|---|---|---|---|
| Default | Vào tab | Tóm tắt + 10 case đóng; fixture hiện class_id, user_x, user_y | N/A |
| Loading | Bước đang chạy | Theo US-S01 | N/A |
| Has data | Bước chạy xong | ✓/✗ + "x/y đạt"; 3.10 có khung "Case quan trọng nhất của luồng 3…" | N/A |
| Empty | N/A | — | N/A |
| Error | Không gọi được Ops | Hộp đỏ 13042 | N/A |
| Disabled | Fixture thiếu class_id / user_x | Nút khoá "Chưa điền: …" | N/A |
Fields ​
| Field | Required | Type | Default | Format | Validation | Error Message | Visibility | Depends On |
|---|---|---|---|---|---|---|---|---|
user | Yes | Text | {user_x} (3.10, 3.11: {user_x},{user_y}) | id cách nhau dấu phẩy | Phần tử rỗng bị bỏ | "Chưa điền: …" | Bước xoá | Fixture |
classId | No | Text | {class_id} | id Ops | Trống ⇒ không gửi | — | Bước xoá | Fixture |
reason | No | Text | "test SAPP-26297" | — | Trống ⇒ không gửi | — | Bước xoá | — |
target_type (param SQL câu 2) | Yes khi chạy câu 2 | Text | Gợi ý 8 trạng thái | chuỗi lưu thật (TRANSFERED_TO một R) | Theo US-P09 | Theo US-P09 | Panel grpb | — |
Actions ​
A1 - Chạy các bước của một case ​
| Item | Description |
|---|---|
| Trigger | Mở case, chạy từng bước (US-S01) |
| Behavior | Thao tác dùng: xoá học viên khỏi lớp (GHI – xoá mềm); SQL grpb (1 đọc, 2 GHI). Ghi vào: Ops dev/staging (xoá mềm học viên thật), DB Ops dev/staging (dựng type, khôi phục). Không có đường PROD |
| Success Result | Các check đạt theo bảng case |
Error cases:
| Case | Expected Handling |
|---|---|
| Ops trả mã khác kỳ vọng | Check ✗ + giá trị thực |
| Không gọi được Ops | Hộp đỏ 13042 |
Bảng case (10 case):
| Mã case | Tên | Bước | Kỳ vọng tool chấm |
|---|---|---|---|
| 3.8 | Xoá 1 học viên TRANSFERED_TO | SQL grpb (dựng type) · xoá | 400|490037 class_user_cannot_be_removed · không xoá ai |
| 3.9 | Xoá 1 học viên BE_TRANSFERRED | SQL grpb · xoá | 400|490037 |
| 3.10 | Bulk: 1 chuyển nhượng + 1 NORMAL | SQL grpb (user_x = TRANSFERED_TO, user_y = NORMAL) · xoá cả hai · hướng dẫn verify DB | HTTP 200 · user_x trong skipped · user_y không trong skipped |
| 3.11 | Bulk: tất cả đều bị chặn | SQL grpb · xoá | 400|490037 · skipped liệt kê đủ (văn bản) |
| 3.12 | Xoá 1 học viên RESERVED | SQL grpb · xoá | 400|490037 |
| 3.13 | Xoá 1 học viên RETAKING | SQL grpb · xoá | 400|490037 · "ĐỔI so với production (trước xóa được)" |
| 3.14 | Xoá 1 học viên REASSIGNED | SQL grpb · xoá | 400|490037 · "ĐỔI so với production" |
| 3.15 | Xoá 1 học viên NORMAL | SQL grpb · xoá · hướng dẫn khôi phục | HTTP 200 · removed có user_x · skipped rỗng |
| 3.16 | Học viên đã ở lớp Lesson khác | hướng dẫn · xoá | HTTP 200 · invalid_student không rỗng (định danh họ tên) |
| UI | Checkbox trên UI Ops bị disable | hướng dẫn | Kiểm tay; API không trả can_delete |
Acceptance Criteria của màn M1 ​
AC-M1.1 - Xoá một học viên ở trạng thái bị chặn ​
gherkin
Scenario Outline: 490037
Given đã chạy SQL grpb câu 2 với target_type = <type> cho user_x
When người dùng chạy bước xoá với user = user_x và xác nhận GHI
Then HTTP 400, error.code = "400|490037", error.message = "exceptions.class_user_cannot_be_removed"
Examples:
| case | type |
| 3.8 | TRANSFERED_TO |
| 3.9 | BE_TRANSFERRED |
| 3.12 | RESERVED |
| 3.13 | RETAKING |
| 3.14 | REASSIGNED |Maps to:
- Business Rule: BR-01, BR-02, BR-03
AC-M1.2 - Bulk: xoá phần hợp lệ, bỏ qua phần bị chặn ​
gherkin
Given user_x = TRANSFERED_TO, user_y = NORMAL (hai id khác nhau)
When người dùng chạy "Xóa cả hai" với user = "user_x,user_y"
Then HTTP 200
And data.skipped chứa user_x
And data.skipped KHÔNG chứa user_y
And SQL grpb câu 1 cho thấy user_y có deleted_at, user_x không (tester đọc)Maps to:
- Business Rule: BR-01, BR-04, BR-09
AC-M1.3 - Bulk: tất cả bị chặn ​
gherkin
Given cả user_x và user_y ở trạng thái bị chặn
When người dùng chạy bước xoá cả hai
Then HTTP 400, error.code = "400|490037"Maps to:
- Business Rule: BR-05
AC-M1.4 - Xoá học viên NORMAL ​
gherkin
Given user_x NORMAL
When người dùng chạy "Xóa user_x"
Then HTTP 200, data.removed chứa user_x, data.skipped rỗng
And tester khôi phục bằng SQL grpb câu 3Maps to:
- Business Rule: BR-06, BR-09
AC-M1.5 - Học viên đã ở lớp Lesson khác ​
gherkin
Given user_x đã có mặt ở một lớp Lesson khác
When người dùng chạy "Xóa user_x"
Then HTTP 200 và data.invalid_student KHÔNG rỗngMaps to:
- Business Rule: BR-07
AC-M1.6 - Kiểm checkbox trên UI Ops ​
gherkin
When người dùng mở case "UI"
Then chỉ hiện hướng dẫn kiểm tay màn List Student của Ops và không có request nàoMaps to:
- Business Rule: BR-08
Negative AC / Edge Cases của màn M1 ​
| ID | Tình huống | Hành vi mong đợi |
|---|---|---|
| EC-M1.1 | ⚠️ Observed — user_y để trống ở 3.10 | Hành vi hiện tại: user_y tự lấy user_x ⇒ request gửi user_x,user_x; tool vừa đòi skipped chứa user_x vừa đòi không chứa user_y (= user_x) ⇒ luôn có 1 check fail, dễ hiểu nhầm là Ops lỗi (sapp-26297-tool.tsx:69 · sapp-26297-flows.ts:1197-1207) — OQ-S-04 |
| EC-M1.2 | Học viên bị xoá mềm thật sau 3.10 / 3.15 | Không tự khôi phục — tester chạy SQL grpb câu 3 (case 0.2 cũng nhắc) |
| EC-M1.3 | Shape phần tử skipped / removed khác giả định | Check có thể fail dù Ops đúng — BR-09 là đoán, chưa đo |
| EC-M1.4 | target_type gõ theo tên hằng Ops (vd TRANSFERRED_TO hai R) | Không khớp dữ liệu lưu thật — dùng đúng TRANSFERED_TO (US-S01 BR-22) |
5. Cross-feature AC ​
Không có.