# PART 2 — biến thể `screen` > **Dùng khi** `PRODUCT = screen` — sản phẩm có giao diện người dùng (web admin, web app, > app di động). Cắm khối này vào chỗ PART 2 của [`../srs.md`](../srs.md). > > **Tiêu chí G3 riêng của biến thể này** *(thay cho dòng "bảng field" và "wireframe" ở > [workflow.md §2](../../../ba-lifecycle/references/workflow.md))*: > mỗi màn hình có bảng thành phần đủ 8 cột · mỗi field có bảng field đủ 10 cột · hai trạng > thái rỗng khác nhau · mọi thành phần có điều kiện ẩn/khoá/read-only rõ ràng · **có `WF_` > (md + html) phủ mọi `SCR`, tập `C-id` khớp hai chiều, bảng lệch prototype ↔ SRS không còn > dòng Tồn tại/Hành vi chưa quyết** · quy ước chung tham chiếu `UICONV_`. --- ## 2.1 Danh sách màn hình | ID | Tên màn hình | Loại | Đường dẫn | Vai trò truy cập | Vào từ đâu | Ra đi đâu | |---|---|---|---|---|---|---| | SCR-01 | | Danh sách / Chi tiết / Form / Modal | | | | | Liệt kê **từng màn hình riêng**, kể cả modal và trang lỗi. ## 2.2 Sơ đồ điều hướng ```mermaid flowchart LR MENU(["Menu"]) --> SCR01["SCR-01 Danh sách"] SCR01 -->|chọn dòng| SCR02["SCR-02 Chi tiết"] SCR01 -->|nút Tạo mới| SCR03["SCR-03 Form"] SCR03 -->|lưu thành công| SCR01 SCR03 -->|huỷ / back| SCR01 SCR02 -->|back / breadcrumb| SCR01 ``` *ID node khớp cột `ID` của bảng §2.1. Nhãn cạnh là **hành động gây điều hướng**.* 🔴 **Vẽ cả cạnh quay lại.** Sơ đồ chỉ có chiều đi là sơ đồ bỏ sót đúng phần hay lỗi nhất — quay lại có giữ trạng thái danh sách không, huỷ giữa chừng thì đi đâu. **Ba câu bắt buộc trả lời cho mỗi màn hình chi tiết/form:** | Câu hỏi | SCR-02 | SCR-03 | |---|---|---| | Hai đường quay lại (nút back + breadcrumb)? Quay lại có giữ trạng thái danh sách (trang, bộ lọc)? | | | | Vào bằng URL trực tiếp với id không tồn tại / không có quyền ⇒ hiện gì? | | | | Rời màn hình khi form đang dở ⇒ có cảnh báo mất dữ liệu không? | | | --- ## 2.3 SCR-01 — **Bố cục:** `WF__v1.0.md` §3.x · `WF__v1.0.html#SCR-01` · prototype: *(frame/trang, hoặc "✏️ BA tự dựng")*. Hành vi xem bảng bên dưới, không suy từ hình (W11). ### 2.3.1 Bảng thành phần | ID | Tên thành phần | Loại | Nhãn (nguyên văn) | Placeholder / Hint | Hành vi & sự kiện | Điều kiện ẩn/khoá | BR | |---|---|---|---|---|---|---|---| | C01 | btn_create | Nút | Tạo mới | — | Mở SCR-03 | ❌ ẩn với ROLE-03 | | | C02 | txt_search | Ô nhập | — | Nhập mã hoặc tên | Enter hoặc bấm Tìm mới gọi API | — | | **Cột `Điều kiện ẩn/khoá` — chọn rõ một trong ba (quy tắc W7):** | Ký hiệu | Nghĩa | Người dùng thấy gì | |---|---|---| | `❌ ẩn` | Không render | Không biết chức năng tồn tại | | `🔒 disable` | Render, không bấm được, **có tooltip nêu lý do** | Biết có, biết vì sao chưa dùng được | | `👁 read-only` | Hiện giá trị, không sửa được | Tra cứu được | Ghi "tuỳ quyền" là **chưa đặc tả xong**. ### 2.3.2 Bảng dữ liệu hiển thị *(màn hình danh sách)* | # | Cột | Nguồn dữ liệu | Định dạng | Sắp xếp được | Mặc định | Xử lý khi rỗng | Độ rộng | |---|---|---|---|---|---|---|---| | 1 | Mã | `code` | Chữ hoa | ✅ | Sắp tăng | `—` | 120px | | | | |---|---| | **Sắp xếp mặc định** | | | **Số dòng mỗi trang** | mặc định … · tuỳ chọn … | | **Kiểu phân trang** | Offset / Cursor | | **Bấm vào dòng** | Mở chi tiết / Không | ### 2.3.3 Bảng field *(màn hình có nhập liệu)* | ID | Tên field | Kiểu | Bắt buộc | Độ dài / Khoảng | Default | Nguồn giá trị | Validation | Message khi sai | BR | |---|---|---|---|---|---|---|---|---|---| | F01 | | Text | ✅ | 3–20 ký tự (code point UTF-8) | — | Người dùng nhập | | `E-XXX-0001` | BR-0nn | | F02 | | Chọn 1 | ✅ | — | | API `/…`, lọc `active=true`, sắp theo `order` | phải thuộc danh sách | `E-XXX-0002` | | 🔴 **Bốn cột không được để trống:** | Cột | Nếu bỏ trống | |---|---| | **Độ dài/Khoảng** | DB nhận 255, UI không chặn ⇒ lỗi 500 khi dán đoạn dài. Ghi kèm **đơn vị** (ký tự? byte?) | | **Default** | Mỗi màn hình một kiểu, báo cáo lệch vì bản ghi cũ null | | **Nguồn giá trị** | Dropdown lấy từ đâu, **lọc theo gì**, **sắp xếp thế nào** | | **Message khi sai** | Dev tự viết ⇒ mỗi màn hình một giọng, không dịch được | ### 2.3.4 Sơ đồ luồng *(bắt buộc khi hành động chạm ≥ 3 bên)* *Chỉ vẽ khi luồng đi qua người dùng → giao diện → hệ thống → bên thứ ba, hoặc có bước bất đồng bộ. Luồng đơn giản (bấm Lưu, gọi 1 API) thì bảng §2.3.5 là đủ.* ```mermaid sequenceDiagram autonumber actor U as Người dùng participant FE as Giao diện participant BE as Hệ thống participant EXT as Hệ thống ngoài U->>FE: Bấm Lưu FE->>FE: Validate phía giao diện FE->>BE: POST /… (khoá nút Lưu) BE->>EXT: Kiểm tra … (timeout 3s) alt Phản hồi kịp EXT-->>BE: 200 OK BE-->>FE: 200 + id FE-->>U: Toast "Đã lưu", về danh sách else Timeout / lỗi EXT--xBE: timeout BE-->>FE: 503 · E-XXX-0503 FE-->>U: Báo lỗi, GIỮ NGUYÊN dữ liệu đã nhập, mở lại nút Lưu end ``` 🔴 **Bắt buộc vẽ cả nhánh lỗi** (`alt`/`else`). Sequence chỉ có luồng thành công là vi phạm quy tắc W4, và đó chính là nhánh dev hay tự bịa. **Bảng đi kèm** *(quy tắc W13 — sơ đồ không nói được mã lỗi và ngưỡng)*: | Bước | Mô tả | Timeout | Thất bại thì sao | Mã lỗi | AC | |---|---|---|---|---|---| | 3 | Gửi form lên hệ thống | 30s | Giữ dữ liệu, mở lại nút | `E-XXX-0503` | AC-09 | | 4 | Kiểm tra với hệ thống ngoài | 3s | Cho lưu và đồng bộ sau / chặn? | | | *Số ở cột **Bước** là số `autonumber` trong sơ đồ.* ### 2.3.5 Hành động trên màn hình | Hành động | Điều kiện được phép | Xác nhận trước khi làm | Kết quả thành công | Kết quả thất bại | Vai trò | AC | |---|---|---|---|---|---|---| | Lưu | Form hợp lệ | Không | Toast + về danh sách | Giữ nguyên dữ liệu đã nhập, hiện lỗi | | AC-01 | | Xoá | Trạng thái = Nháp | ✅ Modal + **nhập lý do** | Toast + xoá khỏi danh sách | Hiện lỗi, không xoá | | AC-07 | 🔴 **Thất bại phải giữ nguyên dữ liệu người dùng đã nhập.** Xoá trắng form sau lỗi mạng là lỗi trải nghiệm nghiêm trọng và rất hay xảy ra khi spec không nói. ### 2.3.6 Trạng thái rỗng, đang tải, lỗi *Cách trình bày (skeleton/spinner/banner) theo `UICONV` §6 — ở đây chỉ ghi **text riêng** cho đối tượng của màn hình này và nút hành động. Trông thế nào, ở vùng nào: `WF` §3.x.3.* | Trạng thái | Hiển thị gì | Text nguyên văn | Nút hành động | |---|---|---|---| | Đang tải | theo UICONV §6 | | | | **Chưa có dữ liệu nào** | | "Chưa có bản ghi nào. Tạo bản ghi đầu tiên?" | ✅ Tạo mới | | **Bộ lọc không khớp** | | "Không tìm thấy kết quả phù hợp với bộ lọc." | ✅ Xoá lọc | | Lỗi tải dữ liệu | | | ✅ Thử lại | 🔴 Hai trạng thái rỗng **phải khác nhau**. Dùng chung một câu khiến người dùng tưởng mất dữ liệu. --- ## Lưu ý cho `PRODUCT = screen` + app di động B2C Biến thể này viết cho phần mềm nghiệp vụ có vai trò. Với app tiêu dùng B2C, ba chỗ lệch: | Chỗ | Điều chỉnh | |---|---| | `RBAC` ở GĐ2 | Thường chỉ 1–2 vai trò ⇒ ma trận gần như rỗng. Ghi rõ thay vì bỏ, và chuyển trọng tâm sang **phạm vi dữ liệu của chính người dùng** | | Elicitation ở GĐ1 | Không phỏng vấn được hàng vạn người ⇒ dựa vào analytics + phỏng vấn sâu vài người + khảo sát | | UAT ở GĐ4 | "Đúng người dùng thật" không scale ⇒ thay bằng **usability test 5–8 người + beta có giám sát**, tiêu chí pass đổi thành tỷ lệ hoàn thành tác vụ |