Files
sys-analysis-design/ba-output/e-commerce/03-specification/SRS_US002-003_v1.0.md
Leonard-ThindPad-P50 2c7bcde741 improve BA skill
2026-09-09 06:34:57 +07:00

36 KiB
Raw Blame History

SRS — US-002, US-003 — Xem giỏ hàng nhóm theo seller · Sửa số lượng / xoá sản phẩm trong giỏ

Version 1.0
Date 2026-09-08
Author BA (qua skill ba-3-specification)
Status 🟡 Draft
Approved by PO: — · Tech Lead: — · QA: — · Designer: — (dự án không có Designer riêng — PO ký thay, DEC-01)
Source 02-analysis/BACKLOG_CartCheckout_v1.0.md (US-002, US-003) · 02-analysis/BR_CartCheckout_v1.0.md (§3 vòng đời CART, §4 ERD) · 02-analysis/RBAC_CartCheckout_v1.0.md (§1, §2, §6) · 02-analysis/IMPACT_CartCheckout_v1.0.md · 00-index/UICONV_e-commerce_v1.0.md v1.1 · e-commerce/docs/sections/07-giao-dien.md §7.1.1 SCR-04 (prototype tham chiếu dạng văn bản, chế độ 🎨, DEC-01) · e-commerce/docs/sections/04-api-design.md §4.1.1, §4.1.5, §4.1.13, §4.2 · e-commerce/docs/sections/05-thiet-ke-du-lieu.md §5.2.3 (tham chiếu entity cart/cart_item, không chép schema vật lý)
Scope US-002 (Xem giỏ hàng nhóm theo seller), US-003 (Sửa số lượng / xoá sản phẩm trong giỏ) — cùng màn hình SCR-04 Giỏ hàng
Profile screen · greenfield · standard (00-index/PROFILE_e-commerce.md)
Biến thể PART 2 srs-part2/screen.md (2.A Màn hình) + 2.B API (US-002/US-003 gọi trực tiếp API giỏ hàng để hiển thị/cập nhật)
Ngôn ngữ hiển thị VI + EN (đầy đủ ở §4.2) · ZH/KO/JA để trống — chờ OQ-023 (cần biên dịch chuyên nghiệp, không dịch máy — ghi chú người duyệt)

Change Log

Version Date Người sửa Thay đổi CR
1.0 2026-09-08 BA (qua skill ba-3-specification) Bản đầu — SRS chung US-002 + US-003, PART 2.A (màn hình SCR-04) + 2.B (API), 6 mã lỗi mới (E-CART-0002…0006), 6 OQ mới (OQ-028…OQ-033) —

⚠️ Ngoại lệ gate — tài liệu này được viết trong khi Gate G2 (Solution sign-off) của module Giỏ hàng & Checkout chưa được PO + Tech Lech ký chính thức (xem DEC-02, DEC-05, 00-index/DECISION_e-commerce.md). Ngoại lệ đã được người điều phối xác nhận rõ ràng — xem DEC-06. Nếu BACKLOG_CartCheckout/BR_CartCheckout đổi khi G2 ký thật, phần bị ảnh hưởng nhiều nhất ở đây là §1.3 (BR áp dụng — hiện chưa có BR-CART-nn nào áp dụng trực tiếp) và §1.4 (vòng đời CART).

Quy ước đọc tài liệu này (quy tắc W11). Bảng thành phần ở §2.A.3.1 quyết định một phần tử có tồn tại hay không và nó hành xử thế nào. WF_US002-003_v1.0.md + .html (và prototype SAD §7.1.1 nó tham chiếu) quyết định nó nằm ở đâu, to bằng nào, trông ra sao ở từng trạng thái. UICONV_e-commerce_v1.0.md quyết định quy ước chung — tài liệu này chỉ ghi phần khác. Khi mâu thuẫn: bảng thắng về sự tồn tại và hành vi, WF thắng về bố cục — mâu thuẫn đó có dòng ở WF §5.


PHẦN 1 — NGHIỆP VỤ

1.1 Tóm tắt cho người quyết định

US này giải quyết RQ-001: Giỏ hàng đa seller, một lần checkout. US-002 cho khách nhìn thấy rõ mình đang mua sản phẩm gì của những seller nào và tổng tiền từng seller/toàn giỏ trước khi quyết định đặt hàng; US-003 cho khách tự sửa số lượng hoặc bỏ bớt sản phẩm ngay tại màn hình này mà không phải rời trang
Người dùng được gì Nhìn một màn hình duy nhất biết chính xác đang mua của ai, số tiền mỗi seller và tổng cộng; tự điều chỉnh giỏ hàng (số lượng, xoá dòng) và thấy tổng tiền cập nhật ngay, không cần tải lại trang
Khác hiện tại chỗ nào N/A — dự án greenfield (xem PROFILE_e-commerce.md §Hệ quả đã áp dụng), không có màn hình giỏ hàng cũ để so sánh; đây là màn hình mới hoàn toàn của module Giỏ hàng & Checkout

1.2 Vai trò và quyền

Vai trò Được làm gì trong US này Không được làm gì RBAC
ROLE-01 Guest Xem giỏ hàng của chính mình (theo X-Guest-Session-Id); sửa số lượng / xoá CartItem của chính mình Xem/sửa giỏ hàng của người khác; không có sổ địa chỉ (không liên quan ở US này) RBAC_CartCheckout_v1.0.md §2
ROLE-02 Customer Xem giỏ hàng của chính mình (theo customer_id); sửa số lượng / xoá CartItem của chính mình Xem/sửa giỏ hàng của người khác RBAC_CartCheckout_v1.0.md §2

1.3 Business rule áp dụng

BR Phát biểu ngắn Áp dụng ở màn hình/field nào Khi vi phạm
(không có) Không có BR-CART-nn nào áp dụng trực tiếp cho US-002/US-003 — đúng theo BACKLOG_CartCheckout_v1.0.md (US-002: "BR áp dụng: chưa có — mục hiển thị thuần tuý"; US-003: "BR áp dụng: chưa có — ràng buộc số lượng tối thiểu/tối đa mỗi dòng chưa được chốt") — —
BR §3 CART Chỉ được sửa số lượng / xoá CartItem khi Cart.status = active (nguồn: BR_CartCheckout_v1.0.md §3, bảng "Chuyển trạng thái KHÔNG được phép") Toàn màn SCR-04 Chặn thao tác — xem §1.4

🔴 Không có BR nào định nghĩa giới hạn trên của số lượng (kiểm tra tồn kho) hay hành vi khi số lượng về 0 — đây là khoảng trống thật của BACKLOG/BR ở GĐ2, không phải BA quên chép. Xem OQ-028, OQ-030.

1.4 Vòng đời trạng thái (tham chiếu — không định nghĩa lại)

Vòng đời đầy đủ của CART ở BR_CartCheckout_v1.0.md §3. Ở đây chỉ nêu phần US-002/US-003 chạm tới.

Nguồn Sự kiện Điều kiện Đích Ai được làm BR
Active Sửa số lượng CartItem Cart.status = active Active (không đổi) Guest/Customer chủ giỏ BR §3 CART
Active Xoá CartItem (kể cả dòng cuối cùng của giỏ) Cart.status = active Active (không đổi — 🔴 giỏ hàng không tự chuyển abandoned khi rỗng, chỉ chuyển khi hết hạn phiên theo BR §3) Guest/Customer chủ giỏ BR §3 CART

Chuyển trạng thái KHÔNG được phép ở US-002/US-003: không có thao tác nào trong hai US này làm Cart.status chuyển sang converted/abandoned — hai chuyển đổi đó thuộc US-004 (checkout) và cơ chế hết hạn phiên tự động (ngoài phạm vi SRS này).

1.5 Ngoài phạm vi (quy tắc W12)

# Không làm gì Vì sao Xử lý ở đâu/khi nào
1 Kiểm tra tồn kho thời điểm thực khi xem/sửa giỏ hàng BACKLOG_CartCheckout_v1.0.md US-003 khoanh phạm vi: "cảnh báo hết hàng theo thời gian thực thuộc US-004 tại thời điểm checkout, không phải tại thời điểm xem/sửa giỏ — trừ khi PO quyết khác" US-004 (checkout); sẽ được cập nhật nếu PO trả lời OQ-030 theo hướng khác
2 Áp dụng khuyến mãi/mã giảm giá/điểm thưởng Điểm tích hợp với module Khuyến mãi & Loyalty (DEC-03) US-004/US-005 (module khác gọi vào)
3 Chọn/bỏ chọn từng dòng hoặc từng nhóm seller để checkout một phần giỏ hàng (checkbox) SAD §7.1.1 SCR-04 mô tả thành phần này nhưng không có US nào trong BACKLOG xác nhận tính năng "checkout một phần giỏ hàng" Chưa xác định — xem OQ-031, WF_US002-003 §5 dòng #1. Không tự thêm vào SRS này
4 Hiển thị badge "Sản phẩm đã hết hàng" / "Giá đã thay đổi" tại màn Giỏ hàng SAD §7.1.1 SCR-04 mô tả nhưng phụ thuộc mục 1, 2 ở trên (nguồn dữ liệu tồn kho/giá real-time chưa xác nhận thuộc scope US-002/US-003) Xem OQ-029, OQ-030, WF_US002-003 §5 dòng #2, #3
5 Tính phí vận chuyển Chỉ có ở bước checkout, cần địa chỉ trước US-005
6 Thanh toán Ngoài phạm vi màn hình Giỏ hàng US-007/US-008
7 Điều hướng từ dòng CartItem (ảnh/tên) về trang chi tiết sản phẩm Không được BACKLOG/BR xác nhận là hành vi bắt buộc của US-002/US-003 Bổ sung qua CR sau nếu PO yêu cầu

PHẦN 2 — ĐẶC TẢ SẢN PHẨM

2.A — Màn hình (srs-part2/screen.md)

2.A.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-04 Giỏ hàng Chi tiết (không phân trang) /cart (quy ước kỹ thuật, Dev FE xác nhận — không chặn G3) ROLE-01 Guest, ROLE-02 Customer Icon giỏ hàng ở header toàn site (SCR-01, theo SAD §7.1.1) SCR-05 Checkout (US-004, ngoài phạm vi SRS này) · SCR-01 (khi giỏ rỗng, nút "Tiếp tục mua sắm")

2.A.2 Sơ đồ điều hướng

flowchart LR
    SCR01(["SCR-01 Trang chủ — icon giỏ hàng"]) -->|"bấm icon giỏ hàng"| SCR04["SCR-04 Giỏ hàng"]
    SCR04 -->|"'Tiếp tục mua sắm' (giỏ rỗng, C10)"| SCR01
    SCR04 -->|"'Tiến hành Checkout' (C11) — US-004, ngoài phạm vi SRS này"| SCR05[["SCR-05 Checkout — ngoài phạm vi"]]
    SCR01 -.->|"vào URL /cart trực tiếp"| SCR04

ID node khớp cột ID của bảng §2.A.1.

Câu hỏi SCR-04
Hai đường quay lại (nút back + breadcrumb)? Quay lại có giữ trạng thái danh sách? Không áp dụng breadcrumb (SCR-04 không lồng trong danh mục); quay lại dùng logo/menu header (theo UICONV §2). Không có "trạng thái danh sách" (giỏ hàng không phân trang/lọc) để giữ
Vào bằng URL trực tiếp /cart khi chưa có CartItem nào / chưa có session Guest Hệ thống tự tạo Cart mới rỗng (Guest) hoặc lấy Cart rỗng của customer_id (Customer) — hiển thị trạng thái rỗng §2.A.3.6, không phải lỗi 404
Rời màn hình khi đang sửa dở N/A — không có "form đang dở": mỗi lần sửa số lượng/xoá gửi ngay lập tức (không có nút Lưu tổng, xem §2.A.3.5 và ngoại lệ UICONV §12)

2.A.3 SCR-04 — Giỏ hàng

Bố cục: WF_US002-003_v1.0.md §3.1 · WF_US002-003_v1.0.html#SCR-04 · prototype: 🎨 e-commerce/docs/sections/07-giao-dien.md §7.1.1 SCR-04. Hành vi xem bảng bên dưới, không suy từ hình (W11).

2.A.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 lbl_header_title Nhãn "Giỏ hàng của bạn ({n} sản phẩm)" — {n} = tổng số lượng (Σ quantity mọi CartItem), tĩnh, cập nhật khi Σ đổi — —
C02 grp_seller_header Nhãn nhóm "{Tên gian hàng}" — Lặp lại theo từng seller_id có ≥1 CartItem; nguồn tên: seller_id → tên gian hàng (module Seller Management, tham chiếu) ❌ ẩn nếu nhóm không còn CartItem nào (xem AC-US003-04) —
C03 img_cart_item Ảnh — Ảnh dạng ô xám khi lỗi tải Ảnh đại diện product_variant_id — —
C04 lbl_product_name Nhãn Tên sản phẩm — Hiển thị tĩnh, không điều hướng (xem §1.5 dòng 7) — —
C05 lbl_variant Nhãn "{Thuộc tính biến thể}" (VD "Size M, Đỏ") — Hiển thị tĩnh, nguồn product_variant_id (module Catalog, tham chiếu, không sở hữu) — —
C06 lbl_unit_price Nhãn "{đơn giá} ₫" — Hiển thị tĩnh — nguồn giá trị: 🔴 chưa chốt snapshot hay real-time, xem OQ-029 — —
F01 input_quantity Ô nhập số (bộ đếm +/-) — — Xem bảng field §2.A.3.3 🔒 disable trong lúc đang gửi cập nhật (spinner cục bộ, xem §2.A.3.6) —
C07 btn_delete_item Nút nguy hiểm "Xoá" — Bấm → mở modal xác nhận (theo UICONV §5 — mặc định áp dụng, không có ngoại lệ ghi ở UICONV §12 cho dòng này) → xác nhận thì gọi DELETE 🔒 disable trong lúc đang gửi —
C08 lbl_seller_subtotal Nhãn "Tạm tính: {tổng nhóm} ₫" — = Σ (quantity × giá hiển thị C06) của các CartItem cùng seller_id; cập nhật ngay khi F01/C07 thành công — —
C09 lbl_cart_total Nhãn "Tổng cộng: {tổng giỏ} ₫" — = Σ tất cả C08 — —
C10 btn_continue_shopping Nút phụ "Tiếp tục mua sắm" — Chỉ hiện ở trạng thái rỗng → điều hướng SCR-01 ❌ ẩn khi giỏ có ≥1 CartItem —
C11 btn_checkout Nút chính "Tiến hành Checkout" — Bấm → điều hướng SCR-05 (US-004, ngoài phạm vi SRS này) 🔒 disable khi giỏ có 0 CartItem. Điều kiện khác (yêu cầu chọn dòng) chưa xác nhận thuộc scope — xem OQ-031, không áp dụng ở SRS này —
C12 banner_error_load Banner — — Hiện khi GET /v1/cart lỗi/timeout, thay chỗ danh sách CartItem ❌ ẩn khi tải thành công —
C13 btn_retry_load Nút phụ "Thử lại" — Bấm → gọi lại GET /v1/cart Nằm trong C12 —

Cột Điều kiện ẩn/khoá — quy tắc W7 áp dụng đúng ba giá trị ❌ ẩn / 🔒 disable / 👁 read-only, không ghi "tuỳ trường hợp".

2.A.3.2 Bảng thuộc tính hiển thị mỗi dòng CartItem

Không phải danh sách phân trang/sắp xếp (giỏ hàng hiển thị toàn bộ, không giới hạn số dòng mỗi trang) — bảng dưới đây thay cho §2.3.2 chuẩn để ghi nguồn dữ liệu từng thuộc tính hiển thị.

# Thuộc tính Nguồn dữ liệu Định dạng Xử lý khi rỗng/thiếu Ghi chú
1 Ảnh product_variant_id → ảnh đại diện (module Catalog) Ảnh vuông Ô xám mặc định (theo UICONV) —
2 Tên sản phẩm product_variant_id → tên (module Catalog) Text, không giới hạn dòng xác nhận — 🔴 chưa chốt số dòng tối đa (không blocking G3, mức độ thấp, Dev FE tự quyết theo CSS) — —
3 Biến thể product_variant_id → thuộc tính Text — nếu sản phẩm không có biến thể —
4 Đơn giá cart_item.unit_price_snapshot hoặc giá hiện tại real-time — 🔴 OQ-029 #,##0 ₫ (UICONV §8) N/A —
5 Số lượng cart_item.quantity Số nguyên N/A (luôn ≥1 khi dòng còn tồn tại) Xem F01

Thứ tự hiển thị nhóm seller và CartItem trong mỗi nhóm: 🔴 chưa được BACKLOG/SAD xác nhận. BA đề xuất: theo thời điểm thêm vào giỏ tăng dần (added_at/tương đương cart_item không có cột này trong ERD GĐ2 hiện tại — cần Tech Lech xác nhận có cột thời gian thêm hay dùng thứ tự trả về mặc định của API). Mức độ thấp, không chặn G3 — ghi nhận ở WF_US002-003 §5 dòng #6.

2.A.3.3 Bảng field
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 Số lượng (quantity) Số nguyên (bộ đếm +/- và nhập trực tiếp) ✅ Tối thiểu 1 · tối đa 🔴 chưa chốt — xem OQ-030 (BA không tự đặt số, vì đây là ràng buộc tồn kho, quyết định nghiệp vụ) Giá trị quantity hiện có của CartItem khi mở màn hình cart_item.quantity (giá trị hiện tại) Số nguyên ≥ 1 "Số lượng phải là số nguyên từ 1 trở lên." (E-CART-0002) (không có BR — xem §1.3)

🔴 Hành vi khi giảm số lượng xuống 0 chưa chốt (bấm nút - khi quantity = 1, hoặc nhập trực tiếp 0): tự động mở modal xoá dòng, hay chặn không cho giảm dưới 1? — xem OQ-028. AC liên quan viết ở trạng thái mở, xem AC_US-003_v1.0.md §3 Nhóm 2.

2.A.3.4 Sơ đồ luồng — Sửa số lượng / Xoá CartItem
sequenceDiagram
    autonumber
    actor U as Customer/Guest
    participant FE as Giao diện SCR-04
    participant BE as Cart & Order Service

    U->>FE: Đổi số lượng (F01) hoặc bấm Xoá (C07, đã xác nhận modal)
    FE->>FE: Validate phía giao diện (số nguyên ≥ 1)
    FE->>BE: PATCH /v1/cart/items/{cartItemId} hoặc DELETE /v1/cart/items/{cartItemId} (khoá F01/C07 đang xử lý)
    alt Thành công
        BE-->>FE: 200 OK (dữ liệu giỏ hàng cập nhật)
        FE-->>U: Cập nhật C08/C09, mở lại F01/C07
    else CartItem không còn tồn tại trong giỏ (404/409 — bị xoá ở nơi khác)
        BE--xFE: 404 ERR_NOT_FOUND / 409 ERR_CONFLICT
        FE-->>U: Banner "Sản phẩm này đã được xoá khỏi giỏ hàng trước đó." (E-CART-0003), ẩn dòng, cập nhật C08/C09
    else Không đủ quyền sở hữu (403)
        BE--xFE: 403 ERR_FORBIDDEN_OWNERSHIP
        FE-->>U: Chuyển trang "Không có quyền" (E-CART-0005)
    else Timeout / lỗi hệ thống (5xx)
        BE--xFE: timeout / 5xx
        FE-->>U: Banner lỗi tại dòng CartItem "Không thể cập nhật giỏ hàng, thử lại." (E-CART-0006), GIỮ NGUYÊN giá trị trước đó, mở lại F01/C07
    end

🔴 Bắt buộc vẽ cả nhánh lỗi (alt/else) — đã vẽ đủ 4 nhánh (thành công, xung đột, phân quyền, hệ thống).

Bảng đi kèm:

Bước Mô tả Timeout Thất bại thì sao Mã lỗi AC
3 Gửi PATCH/DELETE cart item 🔴 chưa chốt — xem NFR_US002-003_v1.0.md §1, OQ-033 Giữ giá trị/dòng cũ, mở lại nút E-CART-0002/0003/0005/0006 (tuỳ nhánh) AC-US003-07…13
2.A.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
Xem giỏ hàng (tải trang) — Không Hiển thị đủ nhóm/dòng/C08/C09 Banner lỗi (C12) + Thử lại (C13) Guest, Customer AC-US002-01…04
Sửa số lượng (F01) Cart.status = active; giá trị mới là số nguyên ≥ 1 Không Cập nhật F01, C08, C09 ngay Hiện lỗi theo bảng mã lỗi §4.1, giữ giá trị trước đó Guest, Customer AC-US003-01, 02, 07…13
Xoá CartItem (C07) Cart.status = active ✅ Modal xác nhận (UICONV §5) Xoá dòng, cập nhật C08/C09; nhóm rỗng thì ẩn nhóm (C02); giỏ rỗng thì chuyển trạng thái rỗng Hiện lỗi theo bảng mã lỗi §4.1, giữ nguyên dòng Guest, Customer AC-US003-03…06, 10, 11
Bấm "Tiến hành Checkout" (C11) Giỏ có ≥1 CartItem Không Điều hướng SCR-05 (ngoài phạm vi SRS này) N/A Guest, Customer Ngoài phạm vi

🔴 Thất bại phải giữ nguyên dữ liệu người dùng đã nhập — áp dụng cho F01 (giữ số lượng cũ khi lỗi) và cho C07 (dòng không biến mất khi DELETE lỗi).

2.A.3.6 Trạng thái rỗng, đang tải, lỗi
Trạng thái Hiển thị gì Text nguyên văn Nút hành động
Đang tải lần đầu Skeleton theo UICONV §6 — —
Chưa có dữ liệu nào (giỏ trống) Minh hoạ + câu dẫn + nút chính. 🔴 Ngoại lệ so với mẫu chung UICONV §6 ("Chưa có <đối tượng> nào.") — dùng nguyên văn theo SAD, đã ghi ở UICONV §12 "Giỏ hàng trống" (khoá cart.empty.title) C10 "Tiếp tục mua sắm"
Bộ lọc không khớp N/A — giỏ hàng không có bộ lọc — —
Lỗi tải dữ liệu (GET /v1/cart) Banner C12 thay chỗ danh sách "Không tải được dữ liệu, thử lại." (error.load, theo UICONV §6 chung) C13 "Thử lại"
Đang xử lý sửa/xoá 1 dòng Spinner cục bộ tại dòng đó (F01/C07 disable), theo UICONV §6 "đang tải cục bộ" — —

2.B — API tiêu thụ (vì SCR-04 gọi trực tiếp API giỏ hàng)

Chi tiết đầy đủ ở API_US002-003_v1.0.md. Ở đây chỉ mô tả góc nhìn người tiêu thụ (FE), không lặp lại hợp đồng.

Endpoint Dùng để Gọi khi nào Nguồn contract
GET /v1/cart Tải dữ liệu SCR-04 khi vào màn hình Mở màn hình; bấm "Thử lại" (C13) ✅ method/path — SAD §4.1.5 · ⚠️ schema response — BA đề xuất
PATCH /v1/cart/items/{cartItemId} Cập nhật F01 Mỗi lần đổi số lượng (bấm +/-, hoặc rời field sau khi gõ tay) ✅ method/path — SAD §4.1.5 · ⚠️ schema request/response — BA đề xuất
DELETE /v1/cart/items/{cartItemId} Xoá C07 (sau khi xác nhận modal) Người dùng xác nhận trong modal ✅ method/path — SAD §4.1.5 · ⚠️ schema response — BA đề xuất

Guest dùng header X-Guest-Session-Id thay JWT cho cả ba endpoint (theo SAD §4.1.1, §4.1.5).


PHẦN 3 — TIÊU CHÍ NGHIỆM THU

Chi tiết đầy đủ, tách riêng theo US: AC_US-002_v1.0.md và AC_US-003_v1.0.md.

AC Nhóm Tóm tắt Field/Thành phần BR Test case (QA điền)
AC-US002-01 Thành công Xem giỏ hàng nhiều seller C01–C11 —
AC-US002-02 Thành công Xem giỏ hàng rỗng C10 BR §3
AC-US002-03 Lỗi hệ thống Lỗi tải giỏ hàng C12, C13 —
AC-US002-04 Lỗi hệ thống Phân biệt "chưa có dữ liệu" ↔ "không tải được" — —
AC-US002-05 Phân quyền Guest chỉ thấy giỏ của session mình — RBAC §2
AC-US002-06 Phân quyền Customer hết phiên bị chuyển đăng nhập — —
AC-US003-01…06 Thành công Tăng/giảm/xoá CartItem, xoá nhóm/giỏ, huỷ modal F01, C07, C08, C09 BR §3
AC-US003-07, 08 Validation Số lượng không hợp lệ; giảm về 0 (🔴 mở, OQ-028) F01 —
AC-US003-09…11 Lỗi hệ thống 5xx cập nhật, timeout xoá, item bị xoá đồng thời F01, C07 —
AC-US003-12, 13 Phân quyền Gọi API không đúng chủ sở hữu (Customer/Guest — Guest 🔴 mở, OQ-032) — RBAC §6

Mỗi US phải có đủ bốn nhóm — đã đủ cho cả hai US, trừ hai AC còn mở chờ trả lời OQ (ghi rõ thay vì bịa).


PHẦN 4 — MÃ LỖI VÀ TEXT HIỂN THỊ

4.1 Mã lỗi

Mã Khi nào xảy ra Thông điệp hiển thị (nguyên văn) Hiển thị ở đâu Người dùng làm gì tiếp BR/AC
E-CART-0002 Nhập số lượng không phải số nguyên ≥ 1 "Số lượng phải là số nguyên từ 1 trở lên." Inline dưới F01 Sửa lại giá trị AC-US003-07
E-CART-0003 CartItem không còn thuộc giỏ hàng (đã bị xoá ở nơi khác) khi cố sửa/xoá "Sản phẩm này đã được xoá khỏi giỏ hàng trước đó." Banner tại dòng (trước khi dòng biến mất) Không cần làm gì — hệ thống tự cập nhật lại danh sách AC-US003-11
E-CART-0004 GET /v1/cart lỗi/timeout "Không tải được dữ liệu, thử lại." Banner C12 thay chỗ danh sách Bấm "Thử lại" (C13) AC-US002-03
E-CART-0005 Gọi PATCH/DELETE cart item không thuộc quyền sở hữu (403) "Bạn không có quyền truy cập nội dung này." Trang trạng thái Về trang chủ AC-US003-12, 13
E-CART-0006 Lỗi hệ thống (5xx) hoặc timeout khi PATCH/DELETE "Không thể cập nhật giỏ hàng, thử lại." Banner tại dòng Bấm lại nút +/- hoặc Xoá AC-US003-09, 10

Dãy mã theo UICONV §10: E-CART- tiếp từ 0002 (0001 đã dùng cho BR-CART-02 ở US-004). Sau SRS này, số kế tiếp chưa dùng là 0007 — đã cập nhật UICONV §10.

4.2 Text màn hình

Khoá Ngữ cảnh VI EN KO/ZH/JA Giới hạn ký tự
cart.title Header C01 "Giỏ hàng của bạn" "Your Cart" 🔴 để trống — OQ-023 🔴 chưa chốt — OQ-023
cart.itemCount Header C01 phụ "({n} sản phẩm)" "({n} items)" 🔴 OQ-023 —
cart.empty.title Trạng thái rỗng "Giỏ hàng trống" "Your cart is empty" 🔴 OQ-023 —
cart.empty.cta Nút C10 "Tiếp tục mua sắm" "Continue shopping" 🔴 OQ-023 —
cart.error.load Banner C12 "Không tải được dữ liệu, thử lại." "Failed to load data. Please try again." 🔴 OQ-023 —
btn.retry Nút C13 "Thử lại" "Try again" 🔴 OQ-023 —
btn.delete Nút C07 "Xoá" "Remove" 🔴 OQ-023 —
cart.delete.confirm.title Modal xác nhận xoá "Xoá sản phẩm khỏi giỏ hàng?" "Remove item from cart?" 🔴 OQ-023 —
cart.delete.confirm.body Modal xác nhận xoá "Sản phẩm sẽ được xoá khỏi giỏ hàng của bạn." "This item will be removed from your cart." 🔴 OQ-023 —
btn.checkout Nút C11 "Tiến hành Checkout" "Proceed to Checkout" 🔴 OQ-023 —
E-CART-0002.msg Inline F01 "Số lượng phải là số nguyên từ 1 trở lên." "Quantity must be a whole number of 1 or more." 🔴 OQ-023 —
E-CART-0003.msg Banner dòng "Sản phẩm này đã được xoá khỏi giỏ hàng trước đó." "This item has already been removed from your cart." 🔴 OQ-023 —
E-CART-0005.msg Trang trạng thái "Bạn không có quyền truy cập nội dung này." "You don't have permission to access this content." 🔴 OQ-023 —
E-CART-0006.msg Banner dòng "Không thể cập nhật giỏ hàng, thử lại." "Couldn't update your cart. Please try again." 🔴 OQ-023 —

Bản dịch KO/ZH/JA để trống, ghi OQ-023 (đã mở từ UICONV) — không dịch máy, theo ghi chú người duyệt.

4.3 Định dạng hiển thị

Tham chiếu UICONV §8, không có ngoại lệ cho SCR-04.

Loại dữ liệu Định dạng Ví dụ Ghi chú
Số tiền #,##0 ₫ 1.234.567 ₫ Theo UICONV §8, không làm tròn thêm (VND)
Số lượng Số nguyên, không định dạng 3 —
Rỗng/null — Theo UICONV §8

PHẦN 5 — PHI CHỨC NĂNG

Chi tiết ở NFR_US002-003_v1.0.md. Ở đây chỉ nêu áp dụng cho US-002/US-003.

ID Nhóm Yêu cầu (có số đo) Điều kiện đo Cách verify
NFR-PERF-01 Hiệu năng 🔴 Ngưỡng thời gian tải/cập nhật giỏ hàng chưa chốt riêng — xem NFR §1, OQ-033 — —
NFR-SEC-01 Bảo mật Mọi PATCH/DELETE cart item kiểm tra quyền sở hữu (chống IDOR), trả 403 ERR_FORBIDDEN_OWNERSHIP khi không khớp Theo SAD §4.1.1 Test gọi thẳng API với token/session khác chủ

PHẦN 6 — DỮ LIỆU VÀ TÍCH HỢP

6.1 API sử dụng

Chi tiết ở API_US002-003_v1.0.md.

# Mục đích Method Endpoint Nguồn contract
1 Tải giỏ hàng GET /v1/cart ✅ method/path BE cung cấp · ⚠️ schema BA đề xuất
2 Sửa số lượng PATCH /v1/cart/items/{cartItemId} ✅ method/path BE cung cấp · ⚠️ schema BA đề xuất
3 Xoá sản phẩm DELETE /v1/cart/items/{cartItemId} ✅ method/path BE cung cấp · ⚠️ schema BA đề xuất

6.2 Tác động dữ liệu

Tham chiếu IMPACT_CartCheckout_v1.0.md. Không có tác động dữ liệu cũ (greenfield). Điểm chạm nội bộ duy nhất liên quan trực tiếp US-002/US-003: module Catalog & Inventory cung cấp tên/ảnh/biến thể sản phẩm (product_variant_id) hiển thị ở C03–C06 — độ trễ đồng bộ giá/tồn kho vẫn là ASM-06/OQ-009 (chưa xác minh), ảnh hưởng trực tiếp OQ-029/OQ-030 ở SRS này.


PHẦN 7 — BÀN GIAO CHO DEV

Trạng thái 🟡 Chưa sẵn sàng — còn 5 OQ chặn G3 (OQ-028…OQ-030, OQ-032, OQ-033)
Tài liệu cần đọc kèm UICONV_e-commerce_v1.0.md v1.1 → WF_US002-003_v1.0.md+.html → AC_US-002_v1.0.md → AC_US-003_v1.0.md → NFR_US002-003_v1.0.md → API_US002-003_v1.0.md
Quyết định đã chốt, không phải mặc định Modal xác nhận bắt buộc khi xoá CartItem (áp UICONV §5 mặc định, không có ngoại lệ) · Cart không tự chuyển abandoned khi rỗng · Checkout (C11) chỉ disable khi 0 CartItem, KHÔNG có điều kiện "phải chọn dòng" trong SRS này
Điểm còn mở OQ-028 (quantity=0) · OQ-029 (nguồn giá) · OQ-030 (giới hạn trên số lượng/tồn kho) · OQ-031 (checkout một phần giỏ — chủ yếu ảnh hưởng US-004) · OQ-032 (ownership Guest) · OQ-033 (ngưỡng hiệu năng)
Không được sao chép từ đâu Không có màn hình cũ (greenfield) — không áp dụng

PHẦN 8 — OPEN QUESTIONS

ID Câu hỏi Hỏi ai Từ ngày Chặn gì 🔴 chặn G3? Phương án BA đề xuất
OQ-028 Sửa số lượng CartItem về 0 (nhập tay hoặc bấm - khi đang ở 1) → hệ thống tự mở modal xoá dòng, hay chặn không cho giảm dưới 1? PO 2026-09-08 F01, AC-US003-08 🔴 Chặn không cho - giảm dưới 1 (nút - disable ở quantity=1); xoá dòng chỉ qua nút "Xoá" (C07) riêng — tách rõ hai hành động, tránh xoá nhầm khi bấm liên tiếp nút -
OQ-029 Giá hiển thị ở SCR-04 (C06) là giá snapshot lúc thêm giỏ (cart_item.unit_price_snapshot) hay giá hiện tại real-time từ Catalog? PO, Tech Lead 2026-09-08 C06, WF_US002-003 §5 #2/#3 🔴 Dùng unit_price_snapshot để hiển thị nhất quán với số tiền đã "chốt" khi thêm giỏ, đối chiếu lại giá thật ở bước checkout (US-004) — tránh giỏ hàng nhảy số liên tục do giá đổi ngoài ý muốn khách
OQ-030 Sửa số lượng ở SCR-04 (US-003) có kiểm tra giới hạn trên theo tồn kho hiện tại ngay lúc sửa không, hay chỉ kiểm tra ở checkout (US-004) như BACKLOG đã khoanh phạm vi? PO, Tech Lead 2026-09-08 F01, C06 (badge hết hàng/giá đổi), WF_US002-003 §5 #2/#4 🔴 Giữ đúng khoanh vùng của BACKLOG: không kiểm tra tồn kho ở màn Giỏ hàng, chỉ kiểm tra ở US-004 — đơn giản hoá US-002/US-003, tránh phụ thuộc real-time vào Catalog ở màn hình tần suất truy cập cao
OQ-031 Nút "Tiến hành Checkout" áp dụng cho toàn bộ giỏ hàng, hay chỉ cho các dòng được tick chọn (theo checkbox mà SAD SCR-04 mô tả nhưng không US nào trong BACKLOG định nghĩa)? PO 2026-09-08 C11, WF_US002-003 §5 #1, ảnh hưởng US-004 🔴 Áp dụng cho toàn bộ giỏ hàng ở MVP (không có tính năng chọn từng phần) — khớp đúng phạm vi BACKLOG hiện tại, tính năng chọn từng phần đưa vào backlog cho phiên bản sau nếu PO thấy cần
OQ-032 Với Guest, cơ chế kiểm tra quyền sở hữu CartItem khi gọi PATCH/DELETE /v1/cart/items/{cartItemId} có tương đương cơ chế ownership theo JWT (403 ERR_FORBIDDEN_OWNERSHIP) không? SAD §4.1.1/§4.2 chỉ mô tả rõ cho customerId/sellerId trong JWT Tech Lead 2026-09-08 AC-US003-13, E-CART-0005 🔴 Áp dụng cùng cơ chế: đối chiếu cart_id của cartItemId với session_id trong X-Guest-Session-Id, không khớp → 403 ERR_FORBIDDEN_OWNERSHIP
OQ-033 Ngưỡng thời gian phản hồi (p95) cho GET /v1/cart và cho PATCH/DELETE /v1/cart/items là bao nhiêu giây? SAD NFR-01 chỉ có ngưỡng cho danh mục/tìm kiếm (<2s) và checkout (<3s) PO, Tech Lead 2026-09-08 NFR_US002-003 §1 🔴 Áp dụng cùng ngưỡng với danh mục/tìm kiếm (≤2s p95) cho GET /v1/cart vì cùng là thao tác đọc; ≤1s p95 cho PATCH/DELETE (thao tác ghi đơn giản, 1 dòng)

Tự chấm

Gate G3

# Tiêu chí ☐/✅ Ghi chú
1 Đủ mọi mục bắt buộc (mục N/A có ghi lý do) ✅ Mọi mục N/A (§2.A.3.2 phân trang, §4.2/4.3 phần không áp dụng) đều ghi lý do
2 Tiêu chí riêng của biến thể PART 2 đã nạp ☐ Bảng field F01 còn 1 ô để trống có lý do rõ (giới hạn trên — OQ-030); bảng thành phần đủ 8 cột; hai trạng thái rỗng khác nhau (đã có)
3 Mỗi US có AC đủ 4 nhóm, có luồng lỗi ✅ (có 2 AC còn mở chờ OQ) Xem AC_US-002, AC_US-003
4 Bảng mã lỗi đầy đủ, mỗi mã có thông điệp ✅ 5 mã, đủ thông điệp VI+EN
5 NFR có số đo + cách verify ☐ Ngưỡng hiệu năng chưa chốt — OQ-033
6 API contract có, ghi rõ nguồn ✅ Đánh dấu rõ ✅/⚠️ theo từng phần
7 QA xác nhận mọi AC test được ☐ Chờ QA — chưa có QA thật tham gia lần chạy này
8 Không còn OQ mở ảnh hưởng hành vi ☐ 5/6 OQ mới đánh dấu 🔴 chặn G3
9 Không còn TBD trong bảng đặc tả PART 2 và bảng mã lỗi ✅ Không dùng chữ "TBD" — mọi chỗ thiếu dùng 🔴 + OQ-nnn cụ thể
10 Đã áp đúng bảng "Bớt ở light"/"Thêm ở strict" theo RIGOR ✅ RIGOR = standard — áp đúng checklist §2, không bớt/thêm
11 (screen) WF có cho mọi SCR, tập C-id khớp hai chiều, §5 không còn lệch Tồn tại/Hành vi chưa quyết ☐ Xem WF_US002-003_v1.0.md §5 — còn 4 dòng chưa quyết
12 (screen) Quy ước chung tham chiếu UICONV; chỗ khác có dòng ở UICONV §12 ✅ 2 dòng ngoại lệ đã thêm vào UICONV §12 (text rỗng SCR-04, auto-save không có nút Lưu)

Quét bắt buộc trước khi nộp:

grep -niE "nhanh|mượt|thân thiện|v\.v|phù hợp|tương ứng|nên |có thể " SRS_US002-003_v1.0.md
→ chạy thật: 5 dòng khớp ban đầu (§1.5 dòng 1 và 7, §2.A.3.5 hai dòng "tương ứng", §8 OQ-028
  "bấm nhanh") — đã sửa lại câu chữ cho cả 5 dòng, chạy lại lần hai: 0 dòng khớp
grep -n "TBD\|TODO\|???" SRS_US002-003_v1.0.md
→ 0 dòng khớp (dùng 🔴 + OQ-nnn thay vì TBD)

Quy tắc viết W1–W13

W1 W2 W3 W4 W5 W6 W7 W8 W9 W10 W11 W12 W13
✅ ✅ ✅ (con số thiếu ⇒ OQ, không bịa) ✅ (sequence đủ 4 nhánh) ✅ (§4.2) ✅ (§1.4 tham chiếu BR §3) ✅ (§2.A.3.1 cột riêng) ✅ (mọi OQ ghi rõ đề xuất, không quyết thay) ✅ (mọi AC/field ghi US/BR) ✅ (§1.1 cho PO) ✅ (có câu quy ước đầu tài liệu) ✅ (§1.5) ✅ (2 sơ đồ mermaid, đủ bảng đi kèm)