Giao diện
US-S08: Kiểm tra khoá học của học viên trên LMS (luồng 4) ​
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 → US-S01. Câu SQL
lms,f2v→ US-S02 §4. Cấu hình URL LMS → US-P04. Quy tắc ẩn/hiện lớp là kỳ vọng theo guide QA (SAPP-28974, nghiệp vụ LMS), không phải rule mind_keep cài.
| Field | Value |
|---|---|
| US ID | US-S08 |
| 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 | Đã triển khai — chưa chạy được end-to-end (lỗi 13058 tới khi có URL LMS; token học viên, shape /courses chờ SAPP — OQ-S-10) · Draft |
| NFR liên quan | NFR-S-01, NFR-S-02, NFR-S-03 — xem Overview §5 |
| OQ liên quan | OQ-S-01, OQ-S-05, OQ-S-10, OQ-S-14, OQ-S-17 — xem Overview §6 |
1. US Statement ​
text
As a Người dùng tool [Assumption — OQ-S-01]
I want gọi danh sách "Khóa học của tôi" trên LMS bằng token của học viên trước / sau chuyển nhượng, sau hủy,
và với từng trạng thái học viên trong lớp, rồi xem tool chấm lớp nào hiện / ẩn
So that kiểm SAPP-28974: "Người CHO (TRANSFERED_TO) mất lớp khỏi 'Khóa học của tôi', người NHẬN (BE_TRANSFERRED)
vẫn thấy và học được" (tóm tắt luồng trên màn; mục đích nghiệp vụ rộng hơn là [Assumption] — OQ-S-18)2. Dependencies & Definition Of Ready ​
N/A — đã triển khai. Dependency runtime (đang thiếu → chưa chạy được end-to-end):
| # | Cần sẵn sàng | Ai cung cấp | Trạng thái |
|---|---|---|---|
| D1 | Khoá SAPP_LMS_API_URL_DEV / SAPP_LMS_API_URL_STAGING trong env_systems (URL đầy đủ kèm prefix LMS) (US-P04) | SAPP → Admin CMS | ⏸ Chờ SAPP câu 1 — OQ-S-10 |
| D2 | Cách lấy token học viên test | SAPP | ⏸ Chờ SAPP câu 2 — OQ-S-10 |
| D3 | Shape response /courses (field định danh lớp) | SAPP | ⏸ Chờ SAPP câu 3 — OQ-S-05 |
| D4 | Luồng 1 bước 2 (4.B, 4.C) và luồng 2 bước 2 (4.D) đã chạy | Tester | — |
3. Business Rules ​
| ID | Rule | Áp dụng ở | Đã cover bởi (AC) | Nguồn code (Mode B/C) |
|---|---|---|---|---|
| BR-01 | Thiếu URL LMS của môi trường đang chọn ⇒ lỗi 13058 "No LMS API URL is configured for this environment…"; URL có dấu / cuối bị cắt | M1 - mọi bước LMS | AC-M1.1 | be/libs/modules/src/lib/sapp/sapp-26297.common.service.ts:180-201 · be/libs/constants/src/lib/error-codes/error-codes.constants.ts:834-839 · be/libs/constants/src/lib/env-system/env-system.constants.ts:39-40 |
| BR-02 | Thiếu token (sau khi bỏ tiền tố Bearer ) ⇒ lỗi 13059 "A learner LMS token is required…" | M1 - mọi bước LMS | AC-M1.2 | sapp-26297.common.service.ts:203-209 · error-codes.constants.ts:840-845 |
| BR-03 | Token là token học viên, gửi qua header riêng, chỉ dùng cho lần gọi đó, không lưu (NFR-S-03); ô token dạng password, điền từ lms_token_a / lms_token_b / lms_token | M1 - field token | AC-M1.3 | fe/src/data/services/sapp/sapp-26297.service.ts:100-115 · fe/src/ui/components/works/sapp/sapp-26297-flows.ts:1334-1357 |
| BR-04 | Mỗi bước LMS luôn chấm HTTP LMS = 200, mặc định trang 1 / 50 dòng; câu trả lời LMS (kể cả 4xx) được trả nguyên văn như Ops (US-S01 BR-14) | M1 - bước LMS | AC-M1.4 → AC-M1.6 | sapp-26297-flows.ts:1352-1356 · sapp-26297.common.service.ts:210-229 |
| BR-05 | "Lớp hiện" / "lớp ẩn" được chấm bằng việc chuỗi id lớp có / không xuất hiện nguyên chuỗi ở bất kỳ đâu trong body — vì chưa biết field định danh lớp | M1 - check | AC-M1.4 → AC-M1.6 | fe/src/ui/components/works/sapp/sapp-26297-step-call.tsx:233-241,371-380 · sapp-26297-flows.ts:1359-1367 |
| BR-06 | Case mốc / sau chuyển nhượng / sau hủy: 4.A A thấy L1; 4.B A không thấy L1 và F1; 4.C B thấy L2; 4.D A thấy lại L1, B vẫn thấy L2 (+ SQL f2v) | M1 - case 4.A → 4.D | AC-M1.4 | sapp-26297-flows.ts:1409-1465 |
| BR-07 | Hồi quy theo type (4.1–4.8): dựng type cho học viên test tại lớp test bằng SQL lms, gọi bằng lms_token; RESERVED, RETOOK, MOVED_OUT ⇒ lớp ẩn; CANCELED, REASSIGNED, RETAKING, MOVED_IN, WITHDRAWN ⇒ lớp hiện; 4.4 "BẮT BUỘC chạy"; 4.8 "Chưa rõ đúng ý nghiệp vụ" | M1 - case 4.1 → 4.8 | AC-M1.5 | sapp-26297-flows.ts:1369-1400,1466-1483 |
| BR-08 | Case 4.F (filter cũ): tester điền name / type / status rồi chạy; không có check ngoài HTTP 200; ghi chú "vào thẳng nội dung bằng URL" là ngoài phạm vi | M1 - case 4.F | AC-M1.6 | sapp-26297-flows.ts:1485-1506 |
4. Design ​
a. Mối liên hệ giữa các màn & User Flow ​
text
[Tab "4 · LMS"]
4.A (TRƯỚC luồng 1) → [LMS courses token A] : chứa L1
[luồng 1 bước 2] → 4.B [LMS token A] : không chứa L1, F1 · 4.C [LMS token B] : chứa L2
[luồng 2 bước 2] → 4.D [LMS token A] : chứa L1 · [LMS token B] : chứa L2 · SQL f2v
4.1–4.8: [SQL lms: đọc → đổi type (GHI) → (sau kiểm) trả NORMAL (GHI)] → [LMS token hồi quy] : lms_class_id ẩn/hiện
4.F: [LMS + name/type/status] → đọc tay
Hiện tại: mọi bước LMS dừng ở lỗi 13058 cho tới khi có khoá URL LMS (BR-01)b. Chi tiết từng màn ​
Màn M1 - Tab "4 · LMS" ​
| Field | Value |
|---|---|
| Figma frame | N/A |
| Trigger vào màn | Bấm tab "4 · LMS" |
| Mô tả ngắn | Tóm tắt: "SAPP-28974. Người CHO (TRANSFERED_TO) mất lớp khỏi 'Khóa học của tôi', người NHẬN (BE_TRANSFERRED) vẫn thấy và học được. Cần token HỌC VIÊN (không phải staff). ⚠ Chưa có URL LMS: route trả 13058 cho tới khi có key SAPP_LMS_API_URL_* trong env_systems (đang hỏi SAPP, câu 1–2)." 13 case |
UI States ​
| State | Khi nào | Hiển thị | Figma frame |
|---|---|---|---|
| Default | Vào tab | Tóm tắt + 13 case đóng; fixture hiện token A / B / hồi quy (password), lms_user_id, lms_class_id và các ô lớp / học viên | N/A |
| Loading | Bước đang chạy | Theo US-S01 | N/A |
| Has data | LMS trả kết quả | ✓/✗ + "x/y đạt"; 4.C, 4.4, 4.8 có khung cảnh báo | N/A |
| Empty | 4.F không có check | Chỉ response thô | N/A |
| Error | Thiếu URL LMS / thiếu token / không gọi được | Hộp đỏ "Không gọi được Ops qua API: 400 13058 …" / "… 13059 …" / "… 13042 …" | N/A |
| Disabled | Ô token hoặc lớp còn {…} chưa điền | Nút khoá "Chưa điền: …" | N/A |
Fields ​
| Field | Required | Type | Default | Format | Validation | Error Message | Visibility | Depends On |
|---|---|---|---|---|---|---|---|---|
Token LMS (header X-Lms-Token) | Yes | Password | {lms_token_a} / {lms_token_b} / {lms_token} theo bước | token học viên, có hoặc không tiền tố Bearer | BR-02; US-S01 BR-10 | 13059 | Mọi bước LMS | Fixture (không lưu) |
page_index, page_size | No | Text | 1, 50 | — | Trống ⇒ không gửi | — | Mọi bước LMS | — |
name, type, status | No | Text | Trống | status vd IN_PROGRESS | Trống ⇒ không gửi | — | Chỉ 4.F | — |
target_type (param SQL lms câu 2) | Yes | Text | Gợi ý type của case | chuỗi lưu thật | Theo US-P09 | Theo US-P09 | 4.1–4.8 | — |
Fixture lms_class_id | Yes cho 4.1–4.8 | Text | — | id lớp | — | — | Tab 4 | — |
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: khoá học của tôi (đọc LMS); SQL lms (1 đọc, 2 GHI), f2v (đọc). Ghi vào: chỉ DB Ops dev/staging qua SQL lms (đổi type / trả NORMAL); gọi LMS không ghi. Không có đường PROD (khoá URL chỉ có dev/staging) |
| Success Result | Các check đạt theo bảng case |
Error cases:
| Case | Expected Handling |
|---|---|
| Chưa cấu hình URL LMS | Hộp đỏ 13058 (BR-01) |
| Thiếu token | Hộp đỏ 13059 (BR-02) |
| LMS không phản hồi | Hộp đỏ 13042 (US-S01 BR-15) |
Bảng case (13 case):
| Mã case | Tên | Bước | Kỳ vọng tool chấm |
|---|---|---|---|
| 4.A | Trước chuyển nhượng — mốc so sánh | hướng dẫn · LMS (token A) | HTTP 200 · body chứa L1 |
| 4.B | Sau chuyển nhượng — người CHO (A) | hướng dẫn tiền đề · LMS (token A) · hướng dẫn kiểm UI | HTTP 200 · body không chứa L1 · không chứa F1 |
| 4.C | Sau chuyển nhượng — người NHẬN (B) | LMS (token B) · hướng dẫn kiểm UI | HTTP 200 · body chứa L2 |
| 4.D | Sau hủy chuyển nhượng | hướng dẫn tiền đề · LMS (A) · LMS (B) · SQL f2v | A: chứa L1 · B: chứa L2 |
| 4.1 | type = RESERVED | SQL lms · LMS (token hồi quy) | lms_class_id ẩn |
| 4.2 | type = RETOOK | SQL lms · LMS | ẩn |
| 4.3 | type = MOVED_OUT | SQL lms · LMS | ẩn |
| 4.4 | type = CANCELED | SQL lms · LMS | hiện ("BẮT BUỘC chạy") |
| 4.5 | type = REASSIGNED | SQL lms · LMS | hiện |
| 4.6 | type = RETAKING | SQL lms · LMS | hiện |
| 4.7 | type = MOVED_IN | SQL lms · LMS | hiện |
| 4.8 | type = WITHDRAWN | SQL lms · LMS | hiện ("Chưa rõ đúng ý nghiệp vụ" — OQ-S-17) |
| 4.F | Filter cũ vẫn chạy | LMS (+ name / type / status) · hướng dẫn | Chỉ HTTP 200; còn lại đọc tay |
Acceptance Criteria của màn M1 ​
AC-M1.1 - Chưa cấu hình URL LMS (hiện trạng) ​
gherkin
Given env_systems chưa có SAPP_LMS_API_URL_DEV
And môi trường "dev" được chọn
When người dùng chạy bất kỳ bước LMS nào
Then hộp đỏ hiện "Không gọi được Ops qua API: 400 13058 No LMS API URL is configured for this environment..."
And không có dòng check nàoMaps to:
- Business Rule: BR-01
AC-M1.2 - Thiếu token ​
gherkin
Given đã cấu hình URL LMS
And người dùng xoá trống ô token của bước (hoặc chỉ để "Bearer ")
When người dùng chạy bước
Then hộp đỏ hiện mã 13059 "A learner LMS token is required (header X-Lms-Token)..."Maps to:
- Business Rule: BR-02
AC-M1.3 - Token không bị lưu ​
gherkin
Given người dùng nhập lms_token_a vào fixture
When người dùng tải lại trang
Then ô lms_token_a trống
And request tới mind_keep mang token trong header X-Lms-Token, không nằm trong queryMaps to:
- Business Rule: BR-03
AC-M1.4 - Trước / sau chuyển nhượng / sau hủy ​
gherkin
Scenario Outline: lớp hiện hoặc ẩn theo mốc
Given <tiền đề>
When người dùng chạy bước LMS với token <học viên>
Then HTTP 200
And body <kỳ vọng>
Examples:
| case | tiền đề | học viên | kỳ vọng |
| 4.A | chưa chạy luồng 1 | A | chứa L1 |
| 4.B | luồng 1 bước 2 đã chạy | A | KHÔNG chứa L1 và KHÔNG chứa F1 |
| 4.C | luồng 1 bước 2 đã chạy | B | chứa L2 |
| 4.D | luồng 2 bước 2 đã chạy | A | chứa L1 |
| 4.D | luồng 2 bước 2 đã chạy | B | chứa L2 |Maps to:
- Business Rule: BR-04, BR-05, BR-06
AC-M1.5 - Hồi quy theo type ​
gherkin
Scenario Outline: type của học viên test
Given đã chạy SQL lms câu 2 với target_type = <type>
When người dùng chạy "Danh sách khóa học của học viên test"
Then HTTP 200 và body <kỳ vọng> lms_class_id
And tester trả type về NORMAL bằng SQL lms câu 3
Examples:
| case | type | kỳ vọng |
| 4.1 | RESERVED | KHÔNG chứa |
| 4.2 | RETOOK | KHÔNG chứa |
| 4.3 | MOVED_OUT | KHÔNG chứa |
| 4.4 | CANCELED | chứa |
| 4.5 | REASSIGNED | chứa |
| 4.6 | RETAKING | chứa |
| 4.7 | MOVED_IN | chứa |
| 4.8 | WITHDRAWN | chứa |Maps to:
- Business Rule: BR-04, BR-05, BR-07
AC-M1.6 - Filter cũ ​
gherkin
Given case 4.F đang mở
When người dùng điền status = "IN_PROGRESS" rồi chạy
Then query gửi đi có status=IN_PROGRESS
And chỉ có check HTTP 200; tester tự đọc bodyMaps to:
- Business Rule: BR-04, 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 — check "lớp biến mất" | Hành vi hiện tại: check phủ định (4.B, 4.1–4.3) đạt giả nếu LMS chỉ trả mã lớp (không trả id lớp) hoặc trả body lỗi 4xx không chứa id (sapp-26297-step-call.tsx:233-241,371-380 · sapp-26297-flows.ts:1413-1416); bước có check HTTP 200 nên body lỗi vẫn bị bắt ở check đó, nhưng trường hợp "chỉ trả mã lớp" thì không — OQ-S-05 |
| EC-M1.2 | Id lớp xuất hiện ở field khác trong body (vd lớp khác có liên kết tới L1) | Check "hiện" đạt dù card lớp không hiện — hệ quả của BR-05 |
| EC-M1.3 | Dùng token staff thay token học viên | LMS trả gì tool hiển thị nguyên văn; thông điệp 13059 nhắc token staff không đọc được danh sách của học viên |
| EC-M1.4 | Quên trả type về NORMAL sau 4.1–4.8 | Học viên test giữ type đã dựng — tester chạy SQL lms câu 3 |
5. Cross-feature AC ​
AC-X.1 - Phụ thuộc cấu hình env_systems ​
gherkin
Given Admin CMS thêm khoá SAPP_LMS_API_URL_STAGING (có "/" ở cuối) trong env_systems
When người dùng chọn "staging" và chạy bước LMS
Then mind_keep gọi LMS tại URL đó đã bỏ "/" cuối, không còn lỗi 13058Maps to:
- REL-02 (Affects - Cấu hình env_systems)
AC-X.2 - Phụ thuộc luồng 1 và 2 ​
gherkin
Given luồng 1 bước 2 (US-S03) chưa chạy
When người dùng chạy case 4.B
Then kết quả không phản ánh trạng thái sau chuyển nhượng (tiền đề trong case yêu cầu chạy trước)Maps to:
- REL-07 (Affects - Hệ thống SAPP)