# WF — Wireframe & bố cục — US-002, US-003 (SCR-04 Giỏ hàng) | | | |---|---| | **Version** | 1.0 | | **Date** | 2026-09-08 | | **Author** | BA (qua skill ba-3-specification, activity `wf`) | | **Status** | 🟡 Draft | | **Approved by** | Designer: — · PO: — *(dự án không có Designer riêng — PO ký thay, `DEC-01`)* | | **Source** | `SRS_US002-003_v1.0.md` v1.0 · `UICONV_e-commerce_v1.0.md` v1.1 · prototype: `e-commerce/docs/sections/07-giao-dien.md` §7.1.1 SCR-04 (status: approved, version 1) | | **Scope** | US-002, US-003 · `SCR-04` | | **Nguồn bố cục** | 🎨 **Prototype tham chiếu** — `e-commerce/docs/sections/07-giao-dien.md` §7.1.1 SCR-04, coi là nguồn sự thật về bố cục dạng văn bản (`DEC-01` v1.2) | | **Tệp kèm** | `WF_US002-003_v1.0.html` | ## Change Log | Version | Date | Người sửa | Thay đổi | CR | |---|---|---|---|---| | 1.0 | 2026-09-08 | BA (qua skill ba-3-specification, activity `wf`) | Bản đầu — bố cục `SCR-04` chế độ 🎨, 6 dòng lệch ở §5 (4 chưa quyết, 1 đã xử lý theo `UICONV` mặc định, 1 mức thấp không chặn) | — | > **Quy ước đọc** *(quy tắc W11)*. Bảng thành phần trong `SRS` §2.A.3.1 quyết định **một phần tử > có tồn tại không** và **hành xử thế nào**. Tài liệu này và tệp HTML kèm theo quyết định **nó > nằm ở đâu, thứ tự nào, to bằng nào, trông ra sao ở từng trạng thái**. Mâu thuẫn ⇒ SRS thắng về > tồn tại/hành vi, WF thắng về bố cục — mâu thuẫn đó được ghi ở §5, không im lặng. --- ## 0. Nguồn bố cục và độ tin cậy | | | |---|---| | **Prototype tham chiếu** | `e-commerce/docs/sections/07-giao-dien.md` §7.1.1 SCR-04 — mô tả văn bản có cấu trúc (mục đích, persona, FR phục vụ, bố cục, 3 trạng thái, validation), `status: approved`, `version: 1` | | **Định dạng** | Mô tả văn bản có cấu trúc (không phải Figma/ảnh) — SAD §7.0 xác nhận "không có brand guideline cố định" | | **Mức phủ** | 1/1 màn hình của US-002/US-003 (`SCR-04`) có mô tả trong prototype | | **Design system** | Chưa chọn — `OQ-022` (đã mở ở `UICONV`) | | **Độ tin cậy** | 🎨 SAD §7 đã `approved` ở cấp SA/dự án ⇒ WF là **bản ghi lại** bố cục của SCR-04 và đối chiếu với `SRS` | ## 1. Bản đồ prototype ↔ màn hình | SCR | Tên màn hình | Có trong prototype | Frame / trang / mục trong prototype | Mức khớp với SRS | Ghi chú | |---|---|---|---|---|---| | SCR-04 | Giỏ hàng | ✅ | SAD §7.1.1 "SCR-04 — Giỏ hàng" | 🔴 khác tồn tại/hành vi | 4 điểm lệch — xem §5 (#1–#4) | ## 2. Khung bố cục chung *Lấy từ `UICONV` §1. Chỉ ghi phần khác/bổ sung cho SCR-04.* | | | |---|---| | **Grid** | 🔴 Chưa chốt — `UICONV` §1, `OQ-018` (áp dụng chung, không riêng SCR-04) | | **Vùng cố định** | Header toàn site kế thừa `SCR-01` (logo, tìm kiếm, `LanguageSwitcher`, `CurrencyToggle`, icon giỏ hàng, icon tài khoản) — theo `UICONV` §1. SCR-04 không có sidebar/menu cố định riêng | | Breakpoint | Khoảng (px) | Bố cục | Nguồn | |---|---|---|---| | Desktop | ≥ 1024 *(ngưỡng chính xác — `OQ-018`)* | Danh sách nhóm seller full-width, sidebar tổng kết bên phải | `UICONV` §1 + SAD §7.1.1 (mô tả "Sidebar/footer tổng kết") | | Tablet | 768–1023 | 🔴 Chưa mô tả riêng trong SAD — BA đề xuất giữ như desktop nhưng tổng kết chuyển xuống dưới danh sách (footer thay vì sidebar) | BA đề xuất, chưa xác nhận — mức thấp, không chặn G3 | | Mobile | < 768 | Danh sách nhóm seller full-width, tổng kết chuyển thành **footer cố định đáy màn hình** ("Sidebar/footer tổng kết" — SAD dùng cả hai từ, BA diễn giải: sidebar ở desktop, footer ở mobile) | SAD §7.1.1 + BA diễn giải | --- ## 3. Bố cục từng màn hình ### 3.1 SCR-04 — Giỏ hàng | | | |---|---| | **Loại** | Chi tiết (không phân trang) | | **Prototype** | SAD §7.1.1 SCR-04 | | **HTML** | `WF_US002-003_v1.0.html#SCR-04` | | **Thành phần (SRS §2.A.3.1)** | C01–C13, F01 — khớp đủ (xem tự kiểm §"Tự chấm") | #### 3.1.1 Bảng vùng | Vùng | Tên | Vị trí desktop | Vị trí mobile | Chứa thành phần | Chiều rộng | Ưu tiên hiển thị | |---|---|---|---|---|---|---| | Z1 | Header màn hình | Hàng 1, full | Hàng 1, full | C01 | 100% | 1 | | Z2 | Danh sách nhóm seller | Hàng 2, cột trái (2/3) | Hàng 2, full (trên footer tổng kết) | C02, C03, C04, C05, C06, F01, C07 (lặp theo nhóm/dòng) | 66% desktop / 100% mobile | 1 | | Z3 | Tổng kết (sidebar desktop / footer mobile) | Hàng 2, cột phải (1/3), sticky | Cố định đáy màn hình | C09, C11 (C08 nằm trong từng nhóm ở Z2, không lặp lại ở Z3) | 33% desktop / 100% mobile | 1 | | Z4 | Trạng thái đặc biệt (rỗng/lỗi) | Thay chỗ Z2 khi kích hoạt | Thay chỗ Z2 khi kích hoạt | C10, C12, C13 | Bằng Z2 | 1 | *Ưu tiên hiển thị: 1 = luôn hiện.* **Ghi chú vị trí C08 (tạm tính nhóm):** theo mô tả SAD "mỗi nhóm = 1 seller... tạm tính theo VND" nằm cuối mỗi khối nhóm trong Z2 (không phải trong Z3) — khác với cách trình bày "tổng kết ở sidebar" chỉ áp dụng cho **tổng toàn giỏ** (C09), không áp dụng cho tạm tính từng nhóm (C08). #### 3.1.2 Vị trí thành phần *Tập `C-id`/`F-id` phải khớp hai chiều với `SRS` §2.A.3.1 — xem "Tự chấm" cuối tài liệu.* | C-id | Tên thành phần | Vùng | Thứ tự trong vùng | Kích thước / độ rộng | Kiểu trình bày | Phần tử trong prototype | Khớp | |---|---|---|---|---|---|---|---| | C01 | lbl_header_title | Z1 | 1 | auto | Tiêu đề cấp 1 | "Header: tiêu đề 'Giỏ hàng của bạn' + số lượng sản phẩm" | ✅ | | C02 | grp_seller_header | Z2 | 1 (đầu mỗi nhóm, lặp) | 100% | Nhãn | "danh sách nhóm theo seller (mỗi nhóm = 1 seller, hiển thị tên gian hàng)" | ✅ | | C03 | img_cart_item | Z2 | 1 (trong mỗi dòng) | 64px (đề xuất, chưa xác nhận — mức thấp) | Ảnh | "CartItem (ảnh...)" | ✅ | | C04 | lbl_product_name | Z2 | 2 | auto | Nhãn | "CartItem (...tên...)" | ✅ | | C05 | lbl_variant | Z2 | 3 | auto | Nhãn | "CartItem (...biến thể...)" | ✅ | | C06 | lbl_unit_price | Z2 | 4 | auto | Nhãn | "CartItem (...đơn giá...)" | 🟠 *(nguồn giá — `OQ-029` — bố cục khớp, nội dung/nguồn dữ liệu chưa chốt)* | | F01 | input_quantity | Z2 | 5 | 96px (đề xuất) | Ô nhập số (bộ đếm +/-) | "CartItem (...bộ đếm số lượng...)" | ✅ | | C07 | btn_delete_item | Z2 | 6 | auto | Nút nguy hiểm | "CartItem (...nút xoá)" | ✅ | | C08 | lbl_seller_subtotal | Z2 | 7 (cuối mỗi nhóm) | auto | Nhãn | "mỗi nhóm... hiển thị tên gian hàng" *(SAD không tách riêng "tạm tính theo nhóm" — BA suy ra từ "danh sách nhóm theo seller" + "tạm tính" ở footer; xem §5 #6)* | 🟠 | | C09 | lbl_cart_total | Z3 | 1 | auto | Nhãn | "Sidebar/footer tổng kết: tổng số lượng đã chọn, tạm tính (subtotal theo VND)" | ✅ | | C10 | btn_continue_shopping | Z4 | 2 (trong khối rỗng) | auto | Nút phụ | "empty = 'Giỏ hàng trống' + nút 'Tiếp tục mua sắm'" | ✅ | | C11 | btn_checkout | Z3 | 2 | 100% (nút chính, nổi bật) | Nút chính | "nút 'Tiến hành Checkout'" | ✅ *(bố cục khớp; điều kiện bật/tắt theo checkbox — xem §5 #1, KHÔNG áp dụng ở SRS này)* | | C12 | banner_error_load | Z4 | 1 | 100% | Banner | "error = cảnh báo dòng sản phẩm hết hàng/giá thay đổi (badge...)" *(SAD mô tả lỗi ở mức dòng, BA áp dụng mẫu banner lỗi tải chung của `UICONV` §6 cho lỗi `GET /v1/cart` — không phải cùng ý nghĩa với badge SAD, xem §5 #2/#3)* | 🟠 | | C13 | btn_retry_load | Z4 | 1 (trong C12) | auto | Nút phụ | Suy ra từ mẫu "lỗi tải + retry" chung toàn site (`UICONV` §6), SAD không viết riêng cho SCR-04 | 🟠 | **Thành phần chỉ có ở prototype, chưa có trong SRS này** *(không gán C-id — theo quy tắc "không tự thêm vào SRS")*: | Mô tả trong prototype (SAD §7.1.1) | Vì sao chưa vào SRS | Xem §5 | |---|---|---| | Checkbox chọn/bỏ chọn từng dòng `CartItem` hoặc cả nhóm | Không có `US` nào trong `BACKLOG` định nghĩa tính năng chọn từng phần giỏ hàng | #1 | | Badge "Sản phẩm đã hết hàng" chặn tick chọn | Phụ thuộc mục trên (checkbox) + kiểm tra tồn kho real-time ngoài scope US-002/US-003 theo `BACKLOG` | #2 | | Badge "Giá đã thay đổi" | Nguồn giá hiển thị (snapshot/real-time) chưa xác nhận thuộc scope US-002 | #3 | **Kiểu trình bày** dùng đúng từ vựng `UICONV` §11 (Nhãn, Nút chính, Nút phụ, Nút nguy hiểm, Ô nhập số, Card, Modal, Banner...). #### 3.1.3 Trạng thái hiển thị | Trạng thái | Vùng thay đổi | Hiển thị gì | Khoá text (SRS §4.2) | Nút hành động | |---|---|---|---|---| | Đang tải lần đầu | Z2 | Skeleton 3 dòng (theo `UICONV` §6) | — | — | | **Chưa có dữ liệu nào (rỗng)** | Z2→Z4 | Minh hoạ + câu dẫn + nút | `cart.empty.title` | C10 | | Lỗi tải dữ liệu | Z2→Z4 | Banner C12 thay chỗ danh sách | `cart.error.load` | C13 | | Đang gửi (sửa số lượng/xoá 1 dòng) | Đúng dòng `CartItem` đang xử lý trong Z2 | Spinner cục bộ tại dòng, F01/C07 disable | — | — | 🔴 Hai trạng thái rỗng: SCR-04 chỉ có MỘT loại rỗng (chưa có dữ liệu), không có "bộ lọc không khớp" (giỏ hàng không có bộ lọc) — khác với mẫu chung `UICONV` §6 vốn có hai loại rỗng. Đây không phải lệch, mà là **không áp dụng** loại rỗng thứ hai. #### 3.1.4 Responsive | Breakpoint | Thay đổi so với desktop | Thành phần ẩn / gộp / đổi kiểu | |---|---|---| | Tablet | 🔴 Chưa mô tả riêng trong SAD — BA đề xuất giữ layout 1 cột, Z3 chuyển xuống footer | Mức thấp, không chặn G3 | | Mobile | Z3 (C09, C11) chuyển thành footer cố định đáy màn hình; Z2 giữ danh sách dạng dọc | Không ẩn thành phần nào, chỉ đổi vị trí Z3 | #### 3.1.5 Tương tác trình bày | Thành phần | Sự kiện | Phản hồi trình bày | Ngưỡng / thời lượng | Nguồn | |---|---|---|---|---| | F01 | Bấm +/- hoặc rời field sau khi gõ tay | Gọi `PATCH` ngay, dòng chuyển spinner cục bộ | 🔴 chưa có ngưỡng debounce khi gõ tay — `OQ` mới nếu cần, mức thấp không chặn G3 | BA đề xuất | | C07 | Bấm "Xoá" | Mở modal xác nhận giữa màn (theo `UICONV` §5) | — | `UICONV` §5 | | Toàn màn | Sửa/xoá thành công | Cập nhật C08/C09 tại chỗ, không toast (🔴 `UICONV` §5 chưa chốt vị trí/thời lượng toast — `OQ-020`, đã mở) | — | `UICONV` §5 (chưa chốt) | #### 3.1.6 Thứ tự focus | Thứ tự | ID | Ghi chú | |---|---|---| | 1 | F01 (dòng đầu tiên) | Focus mặc định khi vào màn hình — 🔴 chưa xác nhận với PO/Dev FE, mức thấp không chặn G3 | --- ## 4. Luồng màn hình theo prototype | Từ | Hành động | Đến | Có trong SRS §2.A.2 | Có trong prototype | |---|---|---|---|---| | SCR-01 | Bấm icon giỏ hàng | SCR-04 | ✅ | ✅ (SAD §7.2.1 bước D "Thêm vào giỏ hàng (SCR-04)") | | SCR-04 | Bấm "Tiến hành Checkout" (C11) | SCR-05 | ✅ (ngoài phạm vi hành vi) | ✅ (SAD §7.2.1 bước E→H) | | SCR-04 | Bấm "Tiếp tục mua sắm" (C10, giỏ rỗng) | SCR-01 | ✅ | 🟠 SAD không vẽ rõ cạnh này trong `7.2.1` (chỉ mô tả trong bố cục SCR-04, không có trong flowchart) — không mâu thuẫn, chỉ là chưa vẽ | --- ## 5. Lệch giữa prototype và SRS | # | Màn hình | Prototype có | SRS nói | Loại lệch | Bên thắng theo W11 | Xử lý | Ai quyết | Trạng thái | |---|---|---|---|---|---|---|---|---| | 1 | SCR-04 | Checkbox chọn/bỏ chọn từng dòng hoặc cả nhóm seller; nút Checkout ngụ ý chỉ áp dụng cho phần đã chọn | `SRS` §1.5 dòng 3: không có tính năng chọn từng phần; C11 chỉ disable khi giỏ có 0 `CartItem` | Tồn tại | Chưa quyết — đây là khoảng trống scope, không phải "SRS đã nói khác" | PO xác nhận có bổ sung tính năng chọn từng phần vào phạm vi US-002/US-003 (hoặc US mới) hay giữ nguyên "Checkout toàn giỏ" | PO | ☐ (`OQ-031`) | | 2 | SCR-04 | Badge "Sản phẩm đã hết hàng" chặn tick chọn | `SRS` §1.5 dòng 4: không kiểm tra tồn kho tại màn Giỏ hàng (khoanh vùng theo `BACKLOG`, thuộc US-004) | Tồn tại/Hành vi | Chưa quyết | PO + Tech Lead xác nhận có đưa kiểm tra tồn kho real-time vào US-002/US-003 hay giữ ở US-004 | PO, Tech Lead | ☐ (`OQ-030`) | | 3 | SCR-04 | Badge "Giá đã thay đổi"; đơn giá hiển thị ngụ ý là giá real-time (để so sánh phát hiện thay đổi) | `SRS` C06: nguồn giá chưa chốt (snapshot hay real-time) | Tồn tại/Hành vi | Chưa quyết | PO + Tech Lead xác nhận nguồn giá trước, sau đó mới quyết có badge này không | PO, Tech Lead | ☐ (`OQ-029`) | | 4 | SCR-04 | "số lượng ≥ 1 và ≤ tồn kho hiện tại" (validation chính của SAD SCR-04) | `SRS` F01: chỉ xác nhận ràng buộc dưới (≥1); ràng buộc trên chưa chốt | Hành vi | Chưa quyết | PO + Tech Lead xác nhận có kiểm tra tồn kho khi sửa số lượng ở màn Giỏ hàng không (cùng nguồn với #2) | PO, Tech Lead | ☐ (`OQ-030`, gộp cùng #2) | | 5 | SCR-04 | Chỉ liệt kê "nút xoá" trong `CartItem`, không nhắc xác nhận trước khi xoá | `SRS`/`WF` áp dụng modal xác nhận mặc định theo `UICONV` §5 (quy ước chung cho "xoá") | Hành vi | **SRS** (áp dụng đúng quy ước dự án, không phải SRS tự ý khác `UICONV`) | Đã xử lý — không cần PO quyết thêm, ghi nhận ở đây để không ai tưởng là bỏ sót | — | ✅ Đã xử lý | | 6 | SCR-04 | Không nêu rõ tiêu chí sắp xếp nhóm seller/dòng `CartItem` trong mỗi nhóm | `SRS` §2.A.3.2: BA đề xuất theo thời điểm thêm vào giỏ, mức thấp không chặn G3 | Bố cục nhỏ | **Prototype** (không có, để BA/Dev FE quyết định tự do) | Giữ đề xuất của BA, PO xác nhận không bắt buộc trước G3 | PO *(không chặn)* | ☐ *(không chặn G3 — mức thấp)* | **Tổng kết:** đã đối chiếu 1 màn hình (`SCR-04`); **6 dòng lệch** — 4 dòng loại Tồn tại/Hành vi **chưa quyết** (🔴 chặn G3: #1, #2, #3, #4 — thực chất #2 và #4 cùng một nguồn `OQ-030`, đếm là 2 câu hỏi độc lập `OQ-029`/`OQ-030`/`OQ-031`), 1 dòng Hành vi đã xử lý bằng cách áp dụng mặc định `UICONV` (#5, không chặn), 1 dòng Bố cục mức thấp không chặn (#6). ## 6. Bàn giao | | | |---|---| | **Designer còn phải làm** | Không có Designer riêng ở dự án này (`DEC-01`) — việc còn lại (màu, typography, icon, minh hoạ trạng thái rỗng, motion, khoảng cách chính xác) chuyển cho **Dev FE**, dùng `UICONV` §11 làm ràng buộc tối thiểu và tự chọn design system theo `OQ-022` khi được Tech Lead xác nhận | | **Dev FE dùng WF để** | Dựng layout Z1–Z4 và chọn component theo §3.1.2; **không** suy ra hành vi từ WF — hành vi ở `SRS` | | **Không được suy ra từ WF** | Khoảng cách/kích thước chính xác (chưa có design system); màu; font; ngưỡng debounce F01 (chưa chốt) | | **Khi prototype thay đổi** | Cập nhật `07-giao-dien.md` SCR-04 (SA/BE) → BA cập nhật §1, §5 và version WF; `SRS` chỉ đổi nếu lệch loại Tồn tại/Hành vi được PO chấp nhận qua `CR` (vì `SRS` chưa `✅ Baselined`, chưa cần `CR` chính thức, chỉ cần sửa trực tiếp + Change Log) | ## 7. Open Questions | ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | 🔴 chặn G3? | |---|---|---|---|---|---| | OQ-031 | Checkout áp dụng toàn giỏ hay theo dòng được chọn? | PO | 2026-09-08 | §5 #1, C11 | 🔴 | | OQ-030 | Kiểm tra tồn kho khi sửa số lượng tại màn Giỏ hàng — có hay không? | PO, Tech Lead | 2026-09-08 | §5 #2, #4, F01 | 🔴 | | OQ-029 | Nguồn giá hiển thị C06 — snapshot hay real-time? | PO, Tech Lead | 2026-09-08 | §5 #3, C06 | 🔴 | --- ## Tự chấm | # | Tiêu chí | ☐/✅ | Ghi chú | |---|---|---|---| | 1 | Mọi `SCR` trong `SRS` §2.A.1 có một mục §3 | ✅ | Chỉ 1 SCR (SCR-04), có §3.1 | | 2 | Mọi `C-id`/`F-id` khớp hai chiều giữa `SRS` §2.A.3.1 và WF §3.1.2 | ✅ | Xem kết quả chạy thật ngay dưới bảng này | | 3 | Mỗi màn hình có §3.x.3 với trạng thái rỗng | ✅ (có 1 loại rỗng, ghi rõ lý do không có loại thứ 2) | — | | 4 | Mỗi màn hình web có responsive ≥ 2 breakpoint | ✅ | Desktop/Tablet/Mobile — Tablet mức đề xuất thấp | | 5 | Mọi con số ở §3.x.5 có nguồn (UICONV/prototype/OQ) | ✅ | Debounce F01 chưa có ngưỡng, ghi rõ mức thấp không chặn | | 6 | §5 đã điền, mọi lệch Tồn tại/Hành vi có người quyết | ☐ | Đã điền đủ, nhưng 4 dòng còn ☐ chờ PO/Tech Lead — đây là kết quả thật của lần chạy này, không phải thiếu sót của WF | | 7 | Tệp HTML mở được, mỗi `SCR` một `
`, mỗi thành phần có `data-c` khớp C-id | ✅ | Xem `WF_US002-003_v1.0.html` | | 8 | Kiểu trình bày chỉ dùng từ vựng `UICONV` §11 | ✅ | — | | 9 | Có chữ ký Designer *(hoặc PO thay, `DEC-01`)* | ☐ | Chưa ký — chờ PO xác nhận thật ở G3 | **Kết quả chạy thật tự kiểm C-id/F-id hai chiều** *(trích `[CF][0-9]{2}` từ `SRS` §2.A.3.1 và từ `WF` .md §3.1.2 + `data-c` trong `.html`)*: - Tập trong `SRS`: `C01, C02, C03, C04, C05, C06, F01, C07, C08, C09, C10, C11, C12, C13` (13 `C` + 1 `F` = 14) - Tập trong `WF` .md §3.1.2: `C01, C02, C03, C04, C05, C06, F01, C07, C08, C09, C10, C11, C12, C13` (khớp) - Tập `data-c` trong `.html`: `C01, C02, C03, C04, C05, C06, F01, C07, C08, C09, C10, C11, C12, C13` (khớp) - **Kết luận: 0 lệch hai chiều.** Ba thành phần chỉ có ở prototype (checkbox chọn dòng, badge hết hàng, badge giá đổi) **không** được gán `C-id` và **không** xuất hiện trong `data-c` của HTML — đúng quy tắc "không tự thêm vào SRS", được mô tả riêng ở khối chú thích trực quan trong HTML (không có `data-c`).