From 2c7bcde74126878f2b194e056ec8cefb318771fc Mon Sep 17 00:00:00 2001 From: Leonard-ThindPad-P50 Date: Wed, 9 Sep 2026 06:34:57 +0700 Subject: [PATCH] improve BA skill --- .claude/agents/ba-gate-auditor.md | 3 +- .claude/agents/ba-stage-runner.md | 7 +- .claude/skills/{README.md => README-BA.md} | 26 +- .claude/skills/REAME-SAD.md | 230 ++++++++ .claude/skills/ba-3-specification/GUIDE.md | 44 +- .claude/skills/ba-3-specification/SKILL.md | 97 +++- .../templates/srs-part2/screen.md | 12 +- .../ba-3-specification/templates/srs.md | 12 +- .../templates/ui-convention.md | 211 +++++++ .../templates/wireframe.html | 206 +++++++ .../ba-3-specification/templates/wireframe.md | 204 +++++++ .claude/skills/ba-lifecycle/SKILL.md | 8 +- .../ba-lifecycle/references/artifact-map.md | 15 +- .../ba-lifecycle/references/diagram-rules.md | 2 +- .../references/domain-profiles.md | 2 +- .../ba-lifecycle/references/workflow.md | 29 +- .../ba-lifecycle/references/writing-rules.md | 11 +- .claude/skills/ba-pipeline/SKILL.md | 9 +- .claude/skills/ba-traceability/SKILL.md | 15 +- .../skills/ba-traceability/templates/rtm.md | 8 + .claude/workflows/ba-pipeline.js | 7 +- .../00-index/DECISION_e-commerce.md | 31 + .../e-commerce/00-index/INDEX_e-commerce.md | 24 + .../e-commerce/00-index/OQ_e-commerce.md | 66 +++ .../e-commerce/00-index/PROFILE_e-commerce.md | 30 + .../00-index/UICONV_e-commerce_v1.0.md | 265 +++++++++ .../01-discovery/BRIEF_CartCheckout_v1.0.md | 278 +++++++++ .../ELICITATION_CartCheckout_2026-09-08.md | 123 ++++ .../01-discovery/RISK_CartCheckout_v1.0.md | 100 ++++ .../STAKEHOLDER_CartCheckout_v1.0.md | 148 +++++ .../02-analysis/BACKLOG_CartCheckout_v1.0.md | 534 +++++++++++++++++ .../02-analysis/BR_CartCheckout_v1.0.md | 535 ++++++++++++++++++ .../02-analysis/IMPACT_CartCheckout_v1.0.md | 188 ++++++ .../02-analysis/PROCESS_CartCheckout_v1.0.md | 186 ++++++ .../02-analysis/RBAC_CartCheckout_v1.0.md | 141 +++++ .../03-specification/AC_US-002_v1.0.md | 215 +++++++ .../03-specification/AC_US-003_v1.0.md | 267 +++++++++ .../03-specification/API_US002-003_v1.0.md | 235 ++++++++ .../03-specification/NFR_US002-003_v1.0.md | 124 ++++ .../03-specification/SRS_US002-003_v1.0.md | 379 +++++++++++++ .../03-specification/WF_US002-003_v1.0.html | 239 ++++++++ .../03-specification/WF_US002-003_v1.0.md | 217 +++++++ 42 files changed, 5429 insertions(+), 54 deletions(-) rename .claude/skills/{README.md => README-BA.md} (88%) create mode 100644 .claude/skills/REAME-SAD.md create mode 100644 .claude/skills/ba-3-specification/templates/ui-convention.md create mode 100644 .claude/skills/ba-3-specification/templates/wireframe.html create mode 100644 .claude/skills/ba-3-specification/templates/wireframe.md create mode 100644 ba-output/e-commerce/00-index/DECISION_e-commerce.md create mode 100644 ba-output/e-commerce/00-index/INDEX_e-commerce.md create mode 100644 ba-output/e-commerce/00-index/OQ_e-commerce.md create mode 100644 ba-output/e-commerce/00-index/PROFILE_e-commerce.md create mode 100644 ba-output/e-commerce/00-index/UICONV_e-commerce_v1.0.md create mode 100644 ba-output/e-commerce/01-discovery/BRIEF_CartCheckout_v1.0.md create mode 100644 ba-output/e-commerce/01-discovery/ELICITATION_CartCheckout_2026-09-08.md create mode 100644 ba-output/e-commerce/01-discovery/RISK_CartCheckout_v1.0.md create mode 100644 ba-output/e-commerce/01-discovery/STAKEHOLDER_CartCheckout_v1.0.md create mode 100644 ba-output/e-commerce/02-analysis/BACKLOG_CartCheckout_v1.0.md create mode 100644 ba-output/e-commerce/02-analysis/BR_CartCheckout_v1.0.md create mode 100644 ba-output/e-commerce/02-analysis/IMPACT_CartCheckout_v1.0.md create mode 100644 ba-output/e-commerce/02-analysis/PROCESS_CartCheckout_v1.0.md create mode 100644 ba-output/e-commerce/02-analysis/RBAC_CartCheckout_v1.0.md create mode 100644 ba-output/e-commerce/03-specification/AC_US-002_v1.0.md create mode 100644 ba-output/e-commerce/03-specification/AC_US-003_v1.0.md create mode 100644 ba-output/e-commerce/03-specification/API_US002-003_v1.0.md create mode 100644 ba-output/e-commerce/03-specification/NFR_US002-003_v1.0.md create mode 100644 ba-output/e-commerce/03-specification/SRS_US002-003_v1.0.md create mode 100644 ba-output/e-commerce/03-specification/WF_US002-003_v1.0.html create mode 100644 ba-output/e-commerce/03-specification/WF_US002-003_v1.0.md diff --git a/.claude/agents/ba-gate-auditor.md b/.claude/agents/ba-gate-auditor.md index 5373c06..098e9e5 100644 --- a/.claude/agents/ba-gate-auditor.md +++ b/.claude/agents/ba-gate-auditor.md @@ -20,7 +20,8 @@ Bạn là **kiểm toán viên độc lập** của quy trình BA. Bạn **khôn - ☐ chưa bắt đầu. **Đừng suy ra trạng thái từ tên file** — mở file, đọc `Status` và kiểm mục bắt buộc có nội dung thật. 3. **Blocker:** gate thấp nhất chưa ✅ là vị trí hiện tại. Blocker cứng (artifact thiếu/chưa ký), blocker mềm (`OQ` chưa trả lời, `CR` chưa quyết, `RISK` cao chưa có phương án). Grep `OQ-[0-9]|TBD|TODO|❓`; `OQ` quá 5 ngày làm việc (so với ngày trong prompt) ⇒ quá hạn, nêu người phải trả lời. -4. **Traceability (ba-traceability):** trích ID từ mọi artifact; chạy 6 phép kiểm coverage (RQ→US, US→AC, AC→test case, BR→AC/test, US không có nguồn = scope creep, RQ không có US) và 4 phép kiểm nhất quán (tham chiếu gãy, ID trùng, version lệch giữa tài liệu tham chiếu nhau, artifact khai profile khác PROFILE). Báo **con số** (VD "RQ→US 18/20 = 90%") và danh sách ID lệch. Theo skill, coverage thiếu có quyền **chặn G2, G3, G4** — ghi rõ kết luận chặn. +4. **Traceability (ba-traceability):** trích ID từ mọi artifact; chạy 6 phép kiểm coverage (RQ→US, US→AC, AC→test case, BR→AC/test, US không có nguồn = scope creep, RQ không có US) và 6 phép kiểm nhất quán (tham chiếu gãy/version lệch, ràng buộc SRS↔API, mã lỗi SRS↔API, trạng thái BR↔SRS/RBAC, **thành phần SRS↔WF hai chiều** và **quy ước SRS↔UICONV** — hai phép cuối chỉ khi `PRODUCT = screen`). Báo **con số** (VD "RQ→US 18/20 = 90%", "C-id lệch: C07 chỉ có trong WF") và danh sách ID lệch. Theo skill, coverage thiếu có quyền **chặn G2, G3, G4** — ghi rõ kết luận chặn. + Với `screen` ở G3 còn phải mở `00-index/UICONV_*.md` (tồn tại? còn ô "chọn một" chưa chọn? có chữ ký Designer hoặc DEC "không có Designer"?) và `03-specification/WF_*.md` (phủ mọi SCR của SRS? §5 có điền không? còn dòng Tồn tại/Hành vi ☐ không? chế độ 🎨 hay ✏️, ✏️ đã có Designer ký chưa?). WF thiếu §5 ⇒ báo "chưa đối chiếu prototype", **không** báo "không lệch". 5. **Cảnh báo bắt buộc:** `RIGOR = light` nhưng đã có người dùng thật ⇒ đề xuất nâng `standard` và chạy bù G1–G3. US có trong BACKLOG nhưng chưa có SRS. SRS tham chiếu `BR` không tồn tại. ## Không được làm diff --git a/.claude/agents/ba-stage-runner.md b/.claude/agents/ba-stage-runner.md index f59705e..895037d 100644 --- a/.claude/agents/ba-stage-runner.md +++ b/.claude/agents/ba-stage-runner.md @@ -23,6 +23,11 @@ Bạn là **người thực thi một bước của quy trình BA** theo đúng - Không hỏi người dùng. Điều skill định hỏi ở Bước 0 mà prompt chưa trả lời ⇒ ghi vào `humanInputNeeded` {topic, question, suggestedDefault}; nếu ảnh hưởng nội dung ⇒ thêm `OQ-nnn` trong artifact và trong sổ `00-index/OQ_.md` (tạo nếu chưa có). - **Preflight gate:** đọc INDEX + header artifact của gate trước. Gate trước chưa `✅ Baselined` và prompt **không** có mục "Ngoại lệ gate" ⇒ **không ghi file**, trả `blocked=true` + `gateWarning` nêu rõ thiếu gì. Có ngoại lệ ⇒ làm tiếp và ghi ngoại lệ vào Open Questions của artifact + `DEC-nn`. - Phạm vi: chỉ làm đúng giai đoạn/hoạt động được giao (`activity`). `ba-3` quá 3 US ⇒ chỉ làm 3 US đầu, báo phần còn lại trong `summary`. +- **`ba-3` với `PRODUCT = screen`** — hai activity thêm, theo `SKILL.md` Bước 8–9: + - `uiconv`: chưa có `00-index/UICONV__v*.md` ⇒ tạo từ `templates/ui-convention.md`; đã có ⇒ chỉ bổ sung §10–§12, version +0.1. Điền từ prototype/design system trong prompt; ô "chọn một" không có nguồn ⇒ **để nguyên các phương án và ghi `OQ`**, không tự chọn. + - `wf`: chạy sau `part2` + `errors` của cùng US. Ghi **hai file** `03-specification/WF__v1.0.md` (từ `templates/wireframe.md`) và `WF__v1.0.html` (từ `templates/wireframe.html` — giữ nguyên ` + + + +
+

WF — ·

+ + + Nhãn đen = C-id trong SRS §2.3.1 · khung đứt xám = vùng Zn trong WF §3.x.1 · khung đứt đỏ = chỉ có ở prototype, chưa có trong SRS (WF §5) · hành vi xem SRS, không suy từ hình +
+ +
+ + +
+

SCR-01 · Danh sách · vào từ Menu · vai trò: ROLE-01, ROLE-02

+
+ +
+
+ Tiêu đề màn hình + Tạo mới +
+
+ +
+
+ Nhập mã hoặc tên… + Trạng thái: Tất cả + Lọc +
+
+ +
+
+ + + + + + +
MãTênTrạng tháiNgày tạo
STR-001Cửa hàng ANháp30/08/2026Chi tiết
STR-002Cửa hàng BĐã duyệt29/08/2026Chi tiết
+
+
STR-001Nháp
Cửa hàng A
30/08/2026
+
STR-002Đã duyệt
Cửa hàng B
29/08/2026
+
+
+
+
minh hoạ
Chưa có bản ghi nào. Tạo bản ghi đầu tiên?Tạo mới
+
Không tìm thấy kết quả phù hợp với bộ lọc.Xoá lọc
+
Không tải được dữ liệu.Thử lại
+
+ +
+
+ Nút "Xuất Excel" — prototype có, BACKLOG không có US ⇒ PO quyết + ‹1 / 7›20 dòng +
+
+ +
+
+ + +
+

SCR-03 · Modal · mở từ C02 · vai trò: ROLE-01, ROLE-02

+
+ +

Field F01–F03 tham chiếu bảng field SRS §2.3.3. Thất bại ⇒ giữ nguyên dữ liệu đã nhập (AC-09), lỗi hiện dưới field theo UICONV §4.

+
+
+ +
+ +
Wireframe low-fi · bố cục và trạng thái · không phải thiết kế visual · nguồn hành vi: SRS_ · nguồn quy ước: UICONV_
+ + + + diff --git a/.claude/skills/ba-3-specification/templates/wireframe.md b/.claude/skills/ba-3-specification/templates/wireframe.md new file mode 100644 index 0000000..19b0b90 --- /dev/null +++ b/.claude/skills/ba-3-specification/templates/wireframe.md @@ -0,0 +1,204 @@ +# WF — Wireframe & bố cục — + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | YYYY-MM-DD | +| **Author** | (skill ba-3-specification, activity `wf`) | +| **Status** | 🟡 Draft | +| **Approved by** | Designer: — · PO: — | +| **Source** | SRS_… v1.0 · UICONV_ v1.0 · | +| **Scope** | US-0nn · SCR-01, SCR-02, … | +| **Nguồn bố cục** | 🎨 **Prototype tham chiếu** `` / ✏️ **BA tự dựng — chờ Designer duyệt** | +| **Tệp kèm** | `WF__v1.0.html` *(low-fi render, mở bằng trình duyệt)* | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | CR | +|---|---|---|---|---| +| 1.0 | | | Bản đầu | — | + +> **Quy ước đọc** *(quy tắc W11)*. Bảng thành phần trong `SRS` §2.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 — và mâu thuẫn đó **phải được ghi ở §5**, không im lặng. + +--- + +## 0. Nguồn bố cục và độ tin cậy + +| | | +|---|---| +| **Prototype tham chiếu** | *(đường dẫn / URL Figma / thư mục ảnh / mục SAD §7 · phiên bản · ngày · ai cung cấp)* | +| **Định dạng** | Figma / HTML tương tác / ảnh tĩnh / mô tả văn bản / **không có** | +| **Mức phủ** | n / m màn hình của US này có trong prototype | +| **Design system** | *(tên + version, hoặc "chưa có — dùng `UICONV` §11")* | +| **Độ tin cậy** | 🎨 Prototype đã được PO/Design duyệt ⇒ WF là **bản ghi lại** · ✏️ Không có prototype ⇒ WF là **đề xuất của BA**, Designer phải duyệt trước G3 | + +🔴 **Có prototype thì prototype là nguồn sự thật về bố cục**, WF chỉ ghi lại và đối chiếu với +SRS. Không có prototype thì WF là đề xuất, và dòng `Approved by: Designer` là **bắt buộc** khi +`PRODUCT = screen` ở mức `standard` trở lên. + +## 1. Bản đồ prototype ↔ màn hình + +*Một dòng cho mỗi `SCR` trong `SRS` §2.1. Màn hình không có trong prototype ⇒ ghi rõ, và mục +§3 tương ứng do BA tự dựng.* + +| 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-01 | | ✅ / ❌ | *(vd: Figma frame "Cart / Desktop", hoặc SAD §7.1.1 SCR-04)* | ✅ khớp · 🟠 khác bố cục · 🔴 khác tồn tại/hành vi | → §5 nếu 🟠/🔴 | + +## 2. Khung bố cục chung + +*Lấy từ `UICONV` §1 nếu đã có. Chỉ ghi lại phần **khác** hoặc **bổ sung** cho US này.* + +| | | +|---|---| +| **Grid** | *(số cột · gutter · max-width, đơn vị px — nguồn: UICONV / prototype)* | +| **Vùng cố định** | Header · Sidebar · Footer — *(có / không, nội dung, tham chiếu UICONV §1)* | + +| Breakpoint | Khoảng (px) | Bố cục | Nguồn | +|---|---|---|---| +| Desktop | ≥ 1024 | | UICONV §1 | +| Tablet | 768–1023 | | | +| Mobile | < 768 | | | + +--- + +## 3. Bố cục từng màn hình + +*Lặp mục này cho **mọi** `SCR` của US, kể cả modal và trang lỗi.* + +### 3.1 SCR-01 — + +| | | +|---|---| +| **Loại** | Danh sách / Chi tiết / Form / Modal / Trang trạng thái | +| **Prototype** | *(frame/trang cụ thể, hoặc "✏️ BA tự dựng")* | +| **HTML** | `WF__v1.0.html#SCR-01` | +| **Thành phần (SRS §2.3.1)** | C01 … C0n — *(số lượng phải khớp bảng thành phần)* | + +#### 3.1.1 Bảng vùng + +*Bảng này thay cho hình vẽ: mỗi vùng là một khối trên màn hình. Tệp HTML render đúng theo bảng này.* + +| 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 | C01 (tiêu đề), C02 (nút Tạo mới) | 100% | 1 | +| Z2 | Thanh lọc | Hàng 2, full | Hàng 2, thu gọn thành nút "Lọc" | C03, C04 | 100% | 2 | +| Z3 | Bảng dữ liệu | Hàng 3, full | Hàng 3, dạng card | C05 | 100% | 1 | +| Z4 | Phân trang | Hàng 4, phải | Hàng 4, giữa | C06 | auto | 3 | + +*Ưu tiên hiển thị: 1 = luôn hiện · 2 = có thể gộp/thu gọn ở mobile · 3 = có thể ẩn sau nút.* + +#### 3.1.2 Vị trí thành phần + +*Mọi `C-id` trong `SRS` §2.3.1 phải có ở đây. `C-id` có ở đây mà không có trong SRS ⇒ lỗi +(thành phần chưa được đặc tả hành vi).* + +| 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_title | Z1 | 1 | auto | Tiêu đề cấp 1 | | ✅ | +| C02 | btn_create | Z1 | 2 (phải) | auto | **Nút chính** | | ✅ | +| C03 | txt_search | Z2 | 1 | 320px | Ô nhập có icon tìm | | 🟠 | + +**Kiểu trình bày** dùng từ vựng của `UICONV` §11 (nút chính / nút phụ / nút nguy hiểm / liên +kết / ô nhập / chọn 1 / chọn nhiều / bảng / card / badge trạng thái …). Không tự đặt tên mới. + +#### 3.1.3 Trạng thái hiển thị + +*Hành vi và text lấy từ `SRS` §2.3.6 và §4.2. Ở đây chỉ nói **trông thế nào và ở vùng nào**.* + +| 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 | Z3 | Skeleton n dòng *(theo UICONV §6)* | — | — | +| **Chưa có dữ liệu nào** | Z3 | Minh hoạ + câu dẫn + nút chính | `empty.none` | C02 Tạo mới | +| **Bộ lọc không khớp** | Z3 | Câu dẫn + nút phụ | `empty.filter` | Xoá lọc | +| Lỗi tải dữ liệu | Z3 | Banner lỗi trong vùng + nút thử lại | `error.load` | Thử lại | +| Đang gửi (form) | Nút gửi | Spinner trong nút, khoá form | — | — | + +🔴 Hai trạng thái rỗng **phải trông khác nhau**, không chỉ khác câu chữ. + +#### 3.1.4 Responsive + +| Breakpoint | Thay đổi so với desktop | Thành phần ẩn / gộp / đổi kiểu | +|---|---|---| +| Tablet | Z2 xuống 2 hàng | — | +| Mobile | Z3 đổi bảng → card; Z2 thu vào nút "Lọc" mở bottom-sheet | C04 gộp vào bottom-sheet | + +#### 3.1.5 Tương tác trình bày + +*Chỉ phần **trình bày** (hành vi nghiệp vụ đã ở SRS). Mọi con số phải có nguồn — không có ⇒ `OQ`.* + +| Thành phần | Sự kiện | Phản hồi trình bày | Ngưỡng / thời lượng | Nguồn | +|---|---|---|---|---| +| C03 txt_search | Gõ | Gợi ý sau khi ngừng gõ | 300 ms | UICONV §4 | +| Toàn màn | Lưu thành công | Toast góc trên phải | 3 s, tự đóng | UICONV §5 | +| C05 bảng | Hover dòng | Đổi nền dòng | — | UICONV §11 | + +#### 3.1.6 Thứ tự focus *(màn hình có nhập liệu)* + +| Thứ tự | C-id | Ghi chú | +|---|---|---| +| 1 | C03 | Focus mặc định khi vào màn hình | + +--- + +### 3.2 SCR-02 — + +*(lặp cấu trúc 3.1)* + +--- + +## 4. Luồng màn hình theo prototype + +*Chỉ khi prototype có tương tác. Đối chiếu với sơ đồ điều hướng `SRS` §2.2 — cạnh có trong +prototype mà SRS không có, hoặc ngược lại, ghi vào §5.* + +| Từ | Hành động | Đến | Có trong SRS §2.2 | Có trong prototype | +|---|---|---|---|---| +| SCR-01 | Bấm dòng | SCR-02 | ✅ | ✅ | +| SCR-03 | Huỷ giữa chừng | SCR-01 | ✅ | ❌ *(prototype không vẽ nút Huỷ)* → §5 | + +## 5. Lệch giữa prototype và SRS + +*Bảng bắt buộc, kể cả khi rỗng (ghi "Không phát hiện lệch, đã đối chiếu n màn hình").* + +| # | 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-03 | Không có nút Huỷ | C07 btn_cancel tồn tại | Tồn tại | **SRS** | Thêm vào WF, báo Design cập nhật prototype | Designer | ☐ | +| 2 | SCR-01 | Bộ lọc ở sidebar trái | Bảng vùng ghi hàng 2 | Bố cục | **Prototype** | Sửa WF theo prototype | — | ✅ | +| 3 | SCR-01 | Nút "Tạo" | Nhãn "Tạo mới" | Text | **SRS** (BA sở hữu text, W5) | Design đổi nhãn | Designer | ☐ | + +Loại lệch: **Tồn tại** · **Hành vi** · **Bố cục** · **Text** · **Trạng thái thiếu**. +Lệch loại *Tồn tại* hoặc *Hành vi* chưa được quyết ⇒ 🔴 **chặn G3**. + +## 6. Bàn giao + +| | | +|---|---| +| **Designer còn phải làm** | *(visual: màu, typography, icon, minh hoạ trạng thái rỗng, motion… — hoặc "Không: prototype đã phủ toàn bộ")* | +| **Dev dùng WF để** | Dựng layout và chọn component theo §3.x.2; **không** suy ra hành vi từ WF | +| **Không được suy ra từ WF** | Khoảng cách/kích thước chính xác nếu chưa có design system; màu; font | +| **Khi prototype thay đổi** | Design báo 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 | + +## 7. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | 🔴 chặn G3? | +|---|---|---|---|---|---| + +--- + +## Tự chấm + +| # | Tiêu chí | ☐/✅ | Ghi chú | +|---|---|---|---| +| 1 | Mọi `SCR` trong `SRS` §2.1 có một mục §3 | | | +| 2 | Mọi `C-id` khớp **hai chiều** giữa `SRS` §2.3.1 và WF §3.x.2 | | *chạy: grep -o "C[0-9][0-9]" cả hai file, so tập* | +| 3 | Mỗi màn hình có §3.x.3 với **hai trạng thái rỗng trông khác nhau** | | | +| 4 | Mỗi màn hình web có responsive ≥ 2 breakpoint | | | +| 5 | Mọi con số ở §3.x.5 có nguồn (UICONV / prototype / OQ) | | | +| 6 | §5 đã điền, mọi lệch Tồn tại/Hành vi có người quyết | | | +| 7 | Tệp HTML mở được, mỗi `SCR` một `
`, mỗi thành phần có `data-c` khớp C-id | | | +| 8 | Kiểu trình bày chỉ dùng từ vựng `UICONV` §11 | | | +| 9 | Có chữ ký Designer *(bắt buộc ở `standard`+ khi WF do BA tự dựng)* | | | diff --git a/.claude/skills/ba-lifecycle/SKILL.md b/.claude/skills/ba-lifecycle/SKILL.md index e5bd65b..bcd038e 100644 --- a/.claude/skills/ba-lifecycle/SKILL.md +++ b/.claude/skills/ba-lifecycle/SKILL.md @@ -68,9 +68,11 @@ bảng "Thêm ở strict". Ghi mức đang chấm ngay đầu bảng pipeline. Chấm **thật**: mở artifact và kiểm tra mục bắt buộc có nội dung hay chỉ là khung rỗng. Một file tồn tại nhưng các mục còn `TBD` ⇒ **chưa đạt**, không được đánh ✅. -**Tiêu chí phụ thuộc `PRODUCT`**: dòng "bảng field" và "wireframe" của G3 chỉ áp cho -`PRODUCT = screen`. Loại khác dùng tiêu chí ghi ở đầu file -`ba-3-specification/templates/srs-part2/.md`. +**Tiêu chí phụ thuộc `PRODUCT`**: dòng "bảng field" và bốn dòng *(screen)* của G3 (`UICONV` +tồn tại và có chữ ký Designer · `WF` phủ mọi SCR, `C-id` khớp hai chiều · `WF` §5 không còn lệch +Tồn tại/Hành vi chưa quyết · WF ✏️ có Designer ký) chỉ áp cho `PRODUCT = screen`. Loại khác +dùng tiêu chí ghi ở đầu file `ba-3-specification/templates/srs-part2/.md`. +Khi chấm G3 cho `screen`, mở cả `00-index/UICONV_*.md` và `03-specification/WF_*.md`. Ba trạng thái, không có trạng thái thứ tư: diff --git a/.claude/skills/ba-lifecycle/references/artifact-map.md b/.claude/skills/ba-lifecycle/references/artifact-map.md index 2d28bdd..92cbbc7 100644 --- a/.claude/skills/ba-lifecycle/references/artifact-map.md +++ b/.claude/skills/ba-lifecycle/references/artifact-map.md @@ -17,7 +17,8 @@ | `AC` | Acceptance Criteria (nếu tách khỏi SRS) | `03-specification/` | ba-3 | QA | | `API` | API contract đề xuất | `03-specification/` | ba-3 | Dev BE/FE | | `NFR` | Yêu cầu phi chức năng | `03-specification/` | ba-3 | Dev, Ops, QA | -| `WF` | Wireframe / Prototype | `03-specification/` | ba-3 | Dev, PO | +| `WF` | Wireframe & bố cục (`.md` bảng vùng/thành phần/lệch + `.html` low-fi) — chỉ `PRODUCT = screen` | `03-specification/` | ba-3 (activity `wf`) | Dev FE, Designer, PO | +| `UICONV` | Quy ước giao diện cấp project — chỉ `PRODUCT = screen`, sinh một lần | `00-index/` | ba-3 (activity `uiconv`) | Dev FE, Designer, mọi SRS/WF | | `QLOG` | Clarification log | `04-delivery/` | ba-4 | Dev, QA | | `CR` | Change Request | `04-delivery/` | ba-4 | PO, PM, Dev | | `TCREVIEW` | Biên bản review test case | `04-delivery/` | ba-4 | QA | @@ -128,14 +129,22 @@ flowchart LR SRS --> AC["AC"] SRS --> API["API"] SRS --> NFR["NFR"] - SRS --> WF["WF"] + UICONV["UICONV"] --> SRS + UICONV --> WF["WF"] + SRS --> WF + PROTO[["Prototype / design system (ngoài bộ BA)"]] -.-> UICONV + PROTO -.-> WF AC --> UAT["UAT"] UAT --> BENEFIT["BENEFIT"] UAT --> RELNOTE["RELNOTE"] UAT --> MANUAL["MANUAL"] ``` -**RTM đọc:** `BRIEF`(RQ) · `BACKLOG`(US) · `SRS`+`AC`(AC, field, mã lỗi) · `UAT`(test case) · `CR` +**RTM đọc:** `BRIEF`(RQ) · `BACKLOG`(US) · `SRS`+`AC`(AC, field, mã lỗi) · `WF`(C-id, SCR) · `UAT`(test case) · `CR` + +`WF` và `UICONV` chỉ tồn tại khi `PRODUCT = screen`. `WF` **không** là nguồn sự thật về hành +vi — nó tham chiếu ngược về `SRS`; đổi prototype ⇒ đổi `WF`, `SRS` chỉ đổi khi lệch loại +Tồn tại/Hành vi được PO chấp nhận (qua `CR` nếu SRS đã Baselined). Đọc xuôi mũi tên để biết **sửa cái này thì phải sửa tiếp cái nào**. Ví dụ sửa một `BR` ⇒ phải rà lại `SRS`, `AC`, test case, và cập nhật `RTM`. diff --git a/.claude/skills/ba-lifecycle/references/diagram-rules.md b/.claude/skills/ba-lifecycle/references/diagram-rules.md index 31c3e41..ec3062a 100644 --- a/.claude/skills/ba-lifecycle/references/diagram-rules.md +++ b/.claude/skills/ba-lifecycle/references/diagram-rules.md @@ -267,7 +267,7 @@ Ba trường hợp, và cách xử lý: | Trường hợp | Làm gì | |---|---| -| Bố cục màn hình | Wireframe ảnh — mermaid không phải công cụ vẽ UI | +| Bố cục màn hình | `WF_.md` (bảng vùng + bảng vị trí thành phần) **và** `WF_.html` low-fi sinh từ `ba-3-specification/templates/wireframe.html` — mermaid không phải công cụ vẽ UI, ASCII art càng không. Có prototype thì WF ghi lại và đối chiếu; không có thì WF là đề xuất của BA | | Ma trận ≥ 3×3, bảng số liệu | Bảng markdown | | Sơ đồ > 20 node | Tách thành nhiều sơ đồ theo phân vùng, mỗi cái một mục con | diff --git a/.claude/skills/ba-lifecycle/references/domain-profiles.md b/.claude/skills/ba-lifecycle/references/domain-profiles.md index 858d846..5dad9bc 100644 --- a/.claude/skills/ba-lifecycle/references/domain-profiles.md +++ b/.claude/skills/ba-lifecycle/references/domain-profiles.md @@ -116,7 +116,7 @@ Quyết định **gate chặt tới đâu và ai phải ký**. `standard` là ba | Giá trị | Dùng khi | Ký gate | |---|---|---| | `light` | POC, thử nghiệm, công cụ nội bộ ≤ 2 tuần, không đụng tiền/dữ liệu cá nhân | Chỉ PO | -| `standard` | Mặc định — sản phẩm thật, có người dùng thật | PO + Tech Lead + QA (theo từng gate) | +| `standard` | Mặc định — sản phẩm thật, có người dùng thật | PO + Tech Lead + QA (theo từng gate); `PRODUCT = screen` thêm **Designer ở G3** (`UICONV`, `WF`) | | `strict` | Có tiền, dữ liệu cá nhân, yêu cầu pháp lý, chịu kiểm toán (tài chính, y tế, bảo hiểm) | Như standard **+ Bảo mật/Pháp chế ở G2 và G3** | Chi tiết tiêu chí bớt/thêm theo từng gate: [workflow.md §2.0](workflow.md). diff --git a/.claude/skills/ba-lifecycle/references/workflow.md b/.claude/skills/ba-lifecycle/references/workflow.md index 6dba4c2..28ac206 100644 --- a/.claude/skills/ba-lifecycle/references/workflow.md +++ b/.claude/skills/ba-lifecycle/references/workflow.md @@ -15,7 +15,7 @@ flowchart TD START --> GD1 GD1 -->|"G1 — PO ký: bài toán & phạm vi đã đúng"| GD2 GD2 -->|"G2 — PO + Tech Lead ký: khả thi, backlog đủ"| GD3 - GD3 -->|"G3 — PO + Tech Lead + QA ký: Ready for Dev"| GD4 + GD3 -->|"G3 — PO + Tech Lead + QA (+ Designer nếu screen) ký: Ready for Dev"| GD4 GD4 -->|"G4 — PO ký UAT pass: Go-live"| GD5 GD5 -->|"G5 — Benefit review"| END @@ -91,7 +91,7 @@ giải quyết được pain point đã ghi ở G1. | `IMPACT` rút gọn: chỉ trục dữ liệu và tích hợp | Mọi `ASM` phải chuyển sang **đã xác minh** trước khi qua G2 (thay vì trước G3) | | Ký: chỉ PO | Ký: PO + Tech Lead + Bảo mật | -### G3 — Ready for Dev · duyệt bởi **PO + Tech Lead + QA** +### G3 — Ready for Dev · duyệt bởi **PO + Tech Lead + QA** (+ **Designer** khi `PRODUCT = screen`) - [ ] `SRS` đủ mọi mục bắt buộc (xem `ba-3-specification/templates/srs.md`) - [ ] Mỗi màn hình có bảng field: kiểu, bắt buộc, độ dài, default, validation, message lỗi @@ -99,16 +99,20 @@ giải quyết được pain point đã ghi ở G1. - [ ] Bảng mã lỗi `E--nnnn` đầy đủ, mỗi mã có thông điệp hiển thị - [ ] `NFR` đã chốt cho các nhóm áp dụng, mỗi cái có cách verify - [ ] `API` contract có, hoặc ghi rõ là **giả định của BA** chờ BE xác nhận -- [ ] Wireframe/prototype khớp với bảng component +- [ ] *(screen)* `UICONV_` tồn tại, không còn ô "chọn một" chưa chọn, có chữ ký Designer (hoặc PO + `DEC-nn` khi dự án không có Designer) +- [ ] *(screen)* `WF_` (md + html) phủ **mọi** `SCR` của SRS; tập `C-id` khớp **hai chiều** với bảng thành phần +- [ ] *(screen)* `WF` §5 (lệch prototype ↔ SRS) đã điền; không còn lệch **Tồn tại/Hành vi** chưa có người quyết +- [ ] *(screen)* `WF` chế độ ✏️ (BA tự dựng) có chữ ký Designer; chế độ 🎨 (prototype tham chiếu) có PO xác nhận §1 và §5 - [ ] QA xác nhận **mọi AC đều test được** — AC không test được là AC chưa viết xong - [ ] Không còn `OQ` mở nào ảnh hưởng tới hành vi hệ thống -- [ ] `ba-traceability` báo coverage US→AC và AC→test case ≥ 100% +- [ ] `ba-traceability` báo coverage US→AC và AC→test case ≥ 100%, và *(screen)* SRS↔WF `C-id` lệch = 0 **Chặn:** còn bất kỳ `TBD` nào trong bảng field hoặc bảng mã lỗi. Còn `OQ` mở về hành vi. +*(screen)* Còn lệch Tồn tại/Hành vi giữa prototype và SRS chưa quyết. **Đây là gate nghiêm nhất** — một chỗ mơ hồ lọt qua G3 sẽ thành một bug hoặc một CR. -> Checklist trên viết theo `PRODUCT = screen`. Loại khác thì dòng "bảng field" và "wireframe" -> được thay bằng tiêu chí tương ứng của biến thể PART 2 — xem đầu file +> Checklist trên viết theo `PRODUCT = screen`. Loại khác thì dòng "bảng field" và bốn dòng +> *(screen)* được thay bằng tiêu chí tương ứng của biến thể PART 2 — xem đầu file > `ba-3-specification/templates/srs-part2/.md`. | Bớt ở `light` | Thêm ở `strict` | @@ -116,7 +120,8 @@ giải quyết được pain point đã ghi ở G1. | `AC` chỉ bắt buộc nhóm 1 (thành công) và 2 (validation). Nhóm 3–4 bắt buộc **nếu** có ghi/xoá dữ liệu hoặc có >1 vai trò | Bảng lưu vết (`NFR-AUD`) bắt buộc cho mọi hành động ghi | | `NFR` chỉ bắt buộc nhóm áp dụng rõ ràng; các nhóm khác ghi "N/A — POC" | Mọi mã lỗi phải có bản dịch đủ mọi ngôn ngữ hỗ trợ, không được để sau | | `API` được phép là phác thảo, không cần bảng đối chiếu mã lỗi | `API` phải do BE xác nhận, **không chấp nhận contract BA tự đề xuất** | -| Không cần chữ ký QA | Ký: PO + Tech Lead + QA + Bảo mật/Pháp chế | +| *(screen)* `WF` chỉ cần bảng vùng + bảng lệch, không cần HTML; `UICONV` chỉ cần §3–§6, §8 | *(screen)* `WF` phải có responsive đủ mọi breakpoint của `UICONV` §1 và thứ tự focus cho mọi form | +| Không cần chữ ký QA; Designer không bắt buộc (PO ký `WF`) | Ký: PO + Tech Lead + QA + Designer + Bảo mật/Pháp chế | ### G4 — UAT pass · duyệt bởi **PO** @@ -162,11 +167,17 @@ cách một POC mang theo mọi thiếu sót của nó vào sản phẩm thật. | **PO / Khách hàng** | Quyết ưu tiên và scope. Ký G1, G4, G5. Trả lời `OQ` nghiệp vụ | | **Tech Lead** | Ký G2, G3 về mặt khả thi. Quyết kiến trúc. Trả lời `OQ` kỹ thuật | | **QA** | Ký G3 về tính test được. Viết test case từ AC. Chủ trì thực thi UAT | -| **Dev** | Tiêu thụ SRS. Đặt `OQ` qua `QLOG` | +| **Designer** *(khi `PRODUCT = screen`)* | Sở hữu prototype, design system, visual. Ký `UICONV` và `WF` ở G3. Trả lời lệch loại *Bố cục* ở `WF` §5. Nhận từ BA: kho thành phần, text nguyên văn, trạng thái, phân quyền hiển thị — **không phải đi hỏi lại nghiệp vụ** | +| **Dev** | Tiêu thụ SRS + WF + UICONV. Đặt `OQ` qua `QLOG` | | **PM** | Tiến độ, nguồn lực. Không ký gate nội dung | BA **không** thay PO quyết ưu tiên, **không** thay Tech Lead chọn kiến trúc, **không** thay -PM quản tiến độ — nhưng phải cung cấp đủ thông tin để cả ba ra quyết định. +PM quản tiến độ, **không** thay Designer quyết visual — nhưng phải cung cấp đủ thông tin để +cả bốn ra quyết định. Riêng phần **bố cục và trạng thái**, BA làm được khi có prototype tham +chiếu (chế độ 🎨 của `WF`); không có thì BA đề xuất, Designer quyết (chế độ ✏️). + +**Dự án không có Designer:** ghi `DEC-nn`, PO ký thay `UICONV`/`WF`, và mục §6 của `WF` +("Designer còn phải làm") chuyển thành việc của dev FE — nêu đích danh. ## 4. Khi nào được bỏ giai đoạn diff --git a/.claude/skills/ba-lifecycle/references/writing-rules.md b/.claude/skills/ba-lifecycle/references/writing-rules.md index d381315..ded2519 100644 --- a/.claude/skills/ba-lifecycle/references/writing-rules.md +++ b/.claude/skills/ba-lifecycle/references/writing-rules.md @@ -83,9 +83,12 @@ Một tài liệu, ba mục tiêu. Đừng viết SRS chỉ cho dev đọc. ## W11 — Ảnh không thay lời -Wireframe minh hoạ bố cục. Hành vi luôn nằm ở bảng component và AC. Khi ảnh và bảng mâu -thuẫn: **bảng thắng về việc "có tồn tại không"**, ảnh thắng về "nằm ở đâu, to bằng nào". -Ghi rõ quy tắc này trong mỗi tài liệu có ảnh. +Wireframe (`WF`) và prototype minh hoạ bố cục. Hành vi luôn nằm ở bảng component và AC. Khi +hình và bảng mâu thuẫn: **bảng thắng về "có tồn tại không" và "hành xử thế nào"**, hình thắng +về "nằm ở đâu, to bằng nào". Ghi rõ quy tắc này trong mỗi tài liệu có hình, và **ghi từng +mâu thuẫn vào `WF` §5** kèm người quyết — mâu thuẫn không ghi là mâu thuẫn dev sẽ tự xử. +Hệ quả: prototype có thành phần mà SRS không có ⇒ không tự thêm vào SRS; đó là scope creep +bằng hình ảnh, PO quyết. ## W12 — Ghi cả cái tài liệu KHÔNG nói @@ -130,7 +133,7 @@ Sơ đồ mâu thuẫn bảng ⇒ **bảng thắng** (hệ quả của W11). [ ] W8 Mọi chỗ chưa rõ là OQ, không phải quyết định ngầm [ ] W9 Mọi AC/BR/field có tham chiếu ngược [ ] W10 Có tóm tắt nghiệp vụ cho PO ở đầu -[ ] W11 Có câu quy định ảnh vs bảng +[ ] W11 Có câu quy định ảnh vs bảng; (screen) mọi lệch prototype ↔ SRS nằm ở WF §5 [ ] W12 Có mục "Ngoài phạm vi" [ ] W13 Sơ đồ dùng mermaid (không ASCII), và mỗi sơ đồ có bảng đi kèm ``` diff --git a/.claude/skills/ba-pipeline/SKILL.md b/.claude/skills/ba-pipeline/SKILL.md index 1622f2e..d365c56 100644 --- a/.claude/skills/ba-pipeline/SKILL.md +++ b/.claude/skills/ba-pipeline/SKILL.md @@ -14,9 +14,10 @@ Engine: `Workflow({ scriptPath: "/.claude/workflows/ba-pipeline.js", args } |---|---|---| | `project`, `date` | luôn | tên project (1 project/lần), ngày hôm nay `YYYY-MM-DD` (header) | | `stage` | luôn | `init` · `audit` · `discovery` · `analysis` · `specification` · `delivery` · `post-release` · `sign` · `sync` | -| `activity` | nên dùng | 1 hoạt động của stage (mặc định cả stage): discovery `stakeholder|elicitation|requirements|goals-scope|risks` · analysis `process|backlog|rules|rbac|impact` · specification `srs|part2|ac|errors|nfr|api` · delivery `clarification|cr|testcase-review|uat` · post-release `release-note|manual|feedback|benefit` | +| `activity` | nên dùng | 1 hoạt động của stage (mặc định cả stage): discovery `stakeholder|elicitation|requirements|goals-scope|risks` · analysis `process|backlog|rules|rbac|impact` · specification `uiconv|srs|part2|ac|errors|nfr|api|wf` (`uiconv`/`wf` chỉ khi `PRODUCT = screen`; `uiconv` chạy một lần đầu project) · delivery `clarification|cr|testcase-review|uat` · post-release `release-note|manual|feedback|benefit` | | `scope` | specification/delivery | `US-012,US-013` (≤3 US) · `CR-004` · câu hỏi cụ thể | | `profile` | init | `{product, lifecycle, rigor}` đã được người dùng xác nhận | +| `proto` | specification (screen) | Prototype tham chiếu: đường dẫn thư mục/file/URL hoặc mục SAD (`docs/sections/07-giao-dien.md`). Không có ⇒ runner tự tìm; vẫn không có ⇒ WF chạy chế độ ✏️ (đề xuất BA, cần Designer ký) | | `inputs[]`, `answers`, `notes`, `override` | tuỳ | file người dùng đưa · trả lời OQ · ghi chú sửa · khẳng định chạy dù gate trước chưa qua | | `approvals[]`, `gate`, `decisions[]` | sign | `{artifact, decision: approve|baseline|revise, approver, role, note}` · gate được ký · DEC-nn | @@ -25,7 +26,7 @@ Hỏi bằng `AskUserQuestion` (≤4 câu/lượt), không hỏi lại điều 1. Project & phạm vi lần này (cả module hay US nào). 2. Profile: `PRODUCT` (screen | api-service | data-pipeline | ml-model | batch-job | process-only) · `LIFECYCLE` (greenfield | brownfield | enhancement) · `RIGOR` (light | standard | strict). Chưa có PROFILE ⇒ suy đoán từ tài liệu, nêu rõ là suy đoán, hỏi xác nhận. 3. Thư mục output: mặc định `ba-output//`; nếu repo đã có thư mục BA khác ⇒ hỏi dùng cái nào, **không tạo cấu trúc song song**. -4. Input đã tìm thấy (Glob `docs/`, `ba-output/`, `sa-output/`, file người dùng đưa) — trình bảng `File | Vai trò | Giai đoạn`. +4. Input đã tìm thấy (Glob `docs/`, `ba-output/`, `sa-output/`, `design/`, `prototype/`, file người dùng đưa) — trình bảng `File | Vai trò | Giai đoạn`. Với `screen` trước stage `specification`: hỏi **prototype/design system tham chiếu** là gì (→ `proto`) và **dự án có Designer không** (không có ⇒ PO ký thay `UICONV`/`WF`, ghi DEC). Lấy ngày hôm nay từ ngữ cảnh → `date`. ## Vòng lặp chuẩn cho mỗi bước @@ -35,11 +36,11 @@ Lấy ngày hôm nay từ ngữ cảnh → `date`. - Duyệt ⇒ hỏi **tên + vai trò người duyệt** ⇒ `sign` với `decision: approve` cho từng artifact. Không có tên người ⇒ không sign. - Sửa ⇒ `notes` → chạy lại đúng activity. Trả lời ⇒ gom `answers` (`OQ-012: …`) → chạy lại. - `blocked` ⇒ trình `gateWarning`; hỏi có **khẳng định chạy ngoại lệ** không; có ⇒ chạy lại với `override: true` và ghi `decisions: ["DEC: chạy khi chưa qua vì …"]` ở lần `sign` kế. -4. **Ký gate** khi mọi artifact của stage đã 🔵 Approved: `audit` ⇒ gate 🟠 chỉ còn thiếu chữ ký và coverage đạt ⇒ hỏi **ai ký** đúng vai trò (G1 PO · G2 PO + Tech Lead · G3 PO + Tech Lead + QA · G4 PO · G5 PO + BA Lead; `strict` thêm Bảo mật/Pháp chế) ⇒ `sign` với `gate` + `decision: baseline` ⇒ `sync` ⇒ `audit` xác nhận ✅. Coverage fail / còn TBD / `refused[]` không rỗng ⇒ **không ký**, quay lại bước 2. +4. **Ký gate** khi mọi artifact của stage đã 🔵 Approved: `audit` ⇒ gate 🟠 chỉ còn thiếu chữ ký và coverage đạt ⇒ hỏi **ai ký** đúng vai trò (G1 PO · G2 PO + Tech Lead · G3 PO + Tech Lead + QA, `screen` thêm Designer cho `UICONV`/`WF` · G4 PO · G5 PO + BA Lead; `strict` thêm Bảo mật/Pháp chế) ⇒ `sign` với `gate` + `decision: baseline` ⇒ `sync` ⇒ `audit` xác nhận ✅. Coverage fail / còn TBD / `refused[]` không rỗng ⇒ **không ký**, quay lại bước 2. 5. Kết thúc mỗi lượt: tóm tắt gate ✅/🟠/☐, OQ mở (ai, quá hạn?), việc kế tiếp. ## Đặc thù -- `specification`: ≤3 US mỗi lần; QA phải xác nhận "mọi AC test được" trước G3 (`standard`+). +- `specification`: ≤3 US mỗi lần; QA phải xác nhận "mọi AC test được" trước G3 (`standard`+). Với `screen`: lần đầu của project chạy `uiconv` trước; `wf` chạy sau `part2` + `errors` của cùng US, truyền `proto`; trình riêng **bảng lệch WF §5** (Tồn tại/Hành vi chưa quyết = blocker) và chế độ 🎨/✏️ để người dùng biết cần Designer ký hay không. - `delivery`: chạy theo từng câu hỏi/CR; CR phải qua 6 bước của ba-4, không sửa artifact Baselined trực tiếp. - `post-release`: `benefit` cần KPI baseline từ G1 — không có ⇒ ghi bài học, không lấp liếm. - **Liên kết SA:** G2 cần `AG1` của `sa-pipeline` (Tech Lead ký "khả thi" dựa trên OPT/ARISK). SA báo lệch `NFR↔QAS`, `API↔ICD`, `RBAC↔SEC` ⇒ chạy lại `specification` activity liên quan với `notes` (QAS/ICD thắng). diff --git a/.claude/skills/ba-traceability/SKILL.md b/.claude/skills/ba-traceability/SKILL.md index 5dd384d..9e12ac1 100644 --- a/.claude/skills/ba-traceability/SKILL.md +++ b/.claude/skills/ba-traceability/SKILL.md @@ -95,7 +95,7 @@ một phần". 🔴 **Phép kiểm bị bỏ vì profile phải được ghi ra trong báo cáo**, kèm lý do — đừng lặng lẽ tính coverage trên tập nhỏ hơn rồi báo 100%. -### Bước 3 — Bốn phép kiểm nhất quán +### Bước 3 — Sáu phép kiểm nhất quán Ngoài coverage, kiểm tra tài liệu có mâu thuẫn nhau không: @@ -105,8 +105,21 @@ Ngoài coverage, kiểm tra tài liệu có mâu thuẫn nhau không: | 2 | **Ràng buộc lệch** | Bảng field trong `SRS` vs. bảng ràng buộc trong `API` | UI chặn 20 ký tự, API chặn 50 | | 3 | **Mã lỗi lệch** | Mã trong `SRS` §4.1 vs. mã trong `API` §4 | Mã lỗi không endpoint nào sinh ra | | 4 | **Trạng thái lệch** | Trạng thái trong `BR` vs. trạng thái dùng trong `SRS`/`RBAC` | RBAC phân quyền cho trạng thái không tồn tại | +| 5 | **Thành phần lệch** *(screen)* | Tập `C-id`/`F-id` trong `SRS` §2.3.1/§2.3.3 vs. `WF` §3.x.2 và `data-c` trong `WF.html` — **hai chiều** | Nút có trong WF (từ prototype) mà SRS không đặc tả hành vi; hoặc SRS có nút mà WF không đặt chỗ | +| 6 | **Quy ước lệch** *(screen)* | `SRS` §2.3.2/§2.3.6/§4.3 định nghĩa phân trang, trạng thái, định dạng khác `UICONV` mà `UICONV` §12 không có dòng | Hai SRS hai kiểu phân trang; múi giờ hiển thị khác nhau | Phép 1 chạy được bằng máy: so `Source:` trong header với version thật của file được trích dẫn. +Phép 5 cũng vậy: + +```bash +grep -oE "\b[CF][0-9]{2}\b" SRS_*.md | sort -u > /tmp/srs_ids +grep -oE "\b[CF][0-9]{2}\b|data-c=\"[CF][0-9]{2}\"" WF_*.md WF_*.html | grep -oE "[CF][0-9]{2}" | sort -u > /tmp/wf_ids +comm -3 /tmp/srs_ids /tmp/wf_ids # phải rỗng +``` + +Ngoài ra với `screen`: đọc `WF` §5 — mỗi dòng loại **Tồn tại/Hành vi** có trạng thái ☐ là một +blocker G3, liệt kê đích danh. `WF` không có §5 hoặc §5 trống không ghi "đã đối chiếu" ⇒ báo +"chưa đối chiếu prototype", không phải "không lệch". ### Bước 4 — `OQ` và `CR` tồn đọng diff --git a/.claude/skills/ba-traceability/templates/rtm.md b/.claude/skills/ba-traceability/templates/rtm.md index 21b2422..ff6b767 100644 --- a/.claude/skills/ba-traceability/templates/rtm.md +++ b/.claude/skills/ba-traceability/templates/rtm.md @@ -93,6 +93,14 @@ quyết**. Đó là cách một business rule bốc hơi khỏi sản phẩm. | 2 | **Ràng buộc lệch** — field vs. API | F01 max 20 ký tự (SRS) vs. 50 (API) | 🔴 | | | 3 | **Mã lỗi lệch** — SRS vs. API | `E-STL-0007` không endpoint nào sinh ra | 🟠 | | | 4 | **Trạng thái lệch** — BR vs. SRS/RBAC | RBAC phân quyền cho trạng thái `LOCKED` không có trong BR | 🔴 | | +| 5 | **Thành phần lệch** *(screen)* — SRS §2.3.1 vs. WF §3.x.2 / `data-c` | `C07` có trong WF (prototype vẽ nút Xuất) nhưng SRS không đặc tả | 🔴 G3 | PO quyết ở WF §5 | +| 6 | **Quy ước lệch** *(screen)* — SRS vs. UICONV không có dòng §12 | SRS_US011 phân trang cursor, UICONV §3 offset | 🟠 | Sửa SRS hoặc thêm UICONV §12 | + +**Lệch prototype ↔ SRS còn mở** *(screen — đọc từ `WF` §5, chỉ loại Tồn tại/Hành vi)* + +| WF | # | Màn hình | Nội dung lệch | Ai quyết | Từ ngày | Chặn | +|---|---|---|---|---|---|---| +| `WF_US011` | 1 | SCR-03 | Prototype không có nút Huỷ, SRS có C07 | Designer | | 🔴 G3 | --- diff --git a/.claude/workflows/ba-pipeline.js b/.claude/workflows/ba-pipeline.js index 4caeb02..e7001c9 100644 --- a/.claude/workflows/ba-pipeline.js +++ b/.claude/workflows/ba-pipeline.js @@ -29,14 +29,14 @@ const TRACK = { analysis: { phase: 'Analysis', skill: 'ba-2-analysis', dir: '02-analysis', gate: 'G2', prevGate: 'G1', activities: ['process', 'backlog', 'rules', 'rbac', 'impact'] }, specification: { phase: 'Specification', skill: 'ba-3-specification', dir: '03-specification', gate: 'G3', prevGate: 'G2', - activities: ['srs', 'part2', 'ac', 'errors', 'nfr', 'api'], scopeHint: 'danh sách US (tối đa 3)' }, + activities: ['uiconv', 'srs', 'part2', 'ac', 'errors', 'nfr', 'api', 'wf'], scopeHint: 'danh sách US (tối đa 3); uiconv/wf chỉ khi PRODUCT=screen, kèm args.proto nếu có prototype' }, delivery: { phase: 'Delivery', skill: 'ba-4-delivery-support', dir: '04-delivery', gate: 'G4', prevGate: 'G3', activities: ['clarification', 'cr', 'testcase-review', 'uat'], scopeHint: 'US / câu hỏi / CR-nnn cụ thể' }, 'post-release': { phase: 'Post-release', skill: 'ba-5-post-release', dir: '05-post-release', gate: 'G5', prevGate: 'G4', activities: ['release-note', 'manual', 'feedback', 'benefit'] }, }, gates: { - G1: 'PO', G2: 'PO + Tech Lead', G3: 'PO + Tech Lead + QA', G4: 'PO', G5: 'PO + BA Lead', + G1: 'PO', G2: 'PO + Tech Lead', G3: 'PO + Tech Lead + QA (+ Designer khi PRODUCT=screen: UICONV, WF)', G4: 'PO', G5: 'PO + BA Lead', }, profileFields: ['product', 'lifecycle', 'rigor'], } @@ -47,6 +47,7 @@ const TRACK = { // activity : một hoạt động trong stage (mặc định: cả stage, theo thứ tự) // scope : phạm vi (VD US-012,US-013 · CR-004 · --focus) // inputs[] : file/nguồn người dùng cung cấp (ưu tiên cao nhất) +// proto : (specification, PRODUCT=screen) prototype/design system tham chiếu cho uiconv/wf — đường dẫn, URL, hoặc mục SAD // answers : trả lời của người dùng cho OQ / humanInputNeeded // notes : ghi chú người duyệt (Revise) // override : true = người dùng khẳng định chạy dù gate trước chưa qua @@ -132,6 +133,8 @@ lines.push(`Skill điều phối: ${skillsDir}/${TRACK.lifecycleSkill}/ (referen if (a.profile) lines.push(`Profile đã được người dùng xác nhận: ${Object.keys(a.profile).map((k) => `${k}=${a.profile[k]}`).join(' · ')}.`) else if (TRACK.profileFields.length) lines.push(`Profile: đọc ${root}/${TRACK.indexDir}/PROFILE_${project}.md; chưa có ⇒ dùng mặc định standard và NÓI RÕ điều đó.`) if (Array.isArray(a.inputs) && a.inputs.length) lines.push(`Input bổ sung do người dùng cung cấp (ưu tiên cao nhất):\n${a.inputs.map((i) => `- ${i}`).join('\n')}`) +if (a.proto) lines.push(`## Prototype / design system tham chiếu (cho UICONV và WF, PRODUCT=screen)\n${a.proto}\nĐây là nguồn sự thật về BỐ CỤC: WF chạy chế độ 🎨 (ghi lại + đối chiếu với SRS, ghi mọi lệch vào WF §5). Thành phần có trong prototype mà SRS không có ⇒ KHÔNG tự thêm vào SRS, ghi lệch loại Tồn tại cho PO quyết.`) +else lines.push(`Prototype tham chiếu: không được cung cấp. Với PRODUCT=screen, tự tìm theo thứ tự design/, prototype/, docs/sections/07-*.md, docs/SAD.md §7; vẫn không có ⇒ WF chạy chế độ ✏️ (đề xuất của BA, cần Designer ký) và nói rõ trong summary.`) if (a.answers) lines.push(`## Câu trả lời của người dùng cho OQ / humanInputNeeded vòng trước\n${a.answers}`) if (a.notes) lines.push(`## Ghi chú từ người duyệt (bắt buộc xử lý trước, version +0.1 và Change Log)\n${a.notes}`) if (a.override) lines.push(`## Ngoại lệ gate\nNgười dùng đã được cảnh báo gate trước chưa ✅ Baselined và KHẲNG ĐỊNH LẠI muốn tiếp tục. Làm tiếp, ghi ngoại lệ vào Open Questions + DEC-nn của artifact.`) diff --git a/ba-output/e-commerce/00-index/DECISION_e-commerce.md b/ba-output/e-commerce/00-index/DECISION_e-commerce.md new file mode 100644 index 0000000..d4c3e0d --- /dev/null +++ b/ba-output/e-commerce/00-index/DECISION_e-commerce.md @@ -0,0 +1,31 @@ +# DECISION — e-commerce + +| | | +|---|---| +| **Version** | 1.3 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-lifecycle / ba-2-analysis / ba-3-specification) | +| **Status** | 🟡 Draft | +| **Approved by** | — *(sổ quyết định, cập nhật liên tục, không cần baseline riêng)* | +| **Source** | Ghi chú từ người duyệt trong prompt khởi tạo dự án; `references/workflow.md` §3 "Dự án không có Designer"; prompt điều phối GĐ2 (ngoại lệ gate, trả lời `OQ-004`/`OQ-008`); ghi chú từ người duyệt trong prompt điều phối GĐ3 (sửa DEC-01, chốt chế độ WF); prompt điều phối GĐ3 (ngoại lệ gate G2); prompt điều phối GĐ3 lần chạy US-002/US-003 (ngoại lệ gate G2 nối tiếp) | +| **Scope** | Toàn dự án e-commerce | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | CR | +|---|---|---|---|---| +| 1.0 | 2026-09-08 | BA (qua skill ba-lifecycle) | Khởi tạo sổ quyết định, ghi DEC-01 | — | +| 1.1 | 2026-09-08 | BA (qua skill ba-2-analysis) | Thêm DEC-02 (ngoại lệ gate G1 khi chạy GĐ2), DEC-03 (xác nhận điểm tích hợp Khuyến mãi/Loyalty — trả lời `OQ-004`), DEC-04 (thứ tự ưu tiên khi cắt phạm vi — trả lời `OQ-008`) | — | +| 1.2 | 2026-09-08 | BA (qua skill ba-3-specification, activity `uiconv`) | Sửa nội dung `DEC-01` theo ghi chú người duyệt: dự án **CÓ** prototype tham chiếu dạng văn bản (`e-commerce/docs/sections/07-giao-dien.md`, SAD §7, status approved) — `WF` sẽ chạy chế độ 🎨 (mức phủ khác nhau theo từng màn hình) thay vì ✏️ hoàn toàn như ghi trước đây; phần PO ký thay Designer giữ nguyên. Thêm `DEC-05` (ngoại lệ gate G2 khi chạy GĐ3 `uiconv`) | — | +| 1.3 | 2026-09-08 | BA (qua skill ba-3-specification, activity `srs`/`ac`/`nfr`/`api`/`wf`) | Thêm `DEC-06` (ngoại lệ gate G2 nối tiếp khi viết `SRS`/`AC`/`NFR`/`API`/`WF` của US-002/US-003) | — | + +## Danh sách quyết định + +| ID | Quyết định | Người quyết | Ngày | Ảnh hưởng | Nguồn | +|---|---|---|---|---|---| +| DEC-01 | Dự án e-commerce chưa có Designer riêng trong giai đoạn thử nghiệm bộ skill BA. **PO sẽ ký thay Designer** cho `UICONV_e-commerce` và mọi `WF_` ở gate G3. **[Sửa 2026-09-08, v1.2]** Dự án **CÓ** prototype tham chiếu dạng văn bản: `e-commerce/docs/sections/07-giao-dien.md` (SAD §7 "Thiết kế giao diện", `status: approved`, `version: 1`) mô tả bố cục có cấu trúc (mục đích, persona, bố cục, trạng thái loading/empty/error, validation) cho `SCR-01`…`SCR-32`. Theo `artifact-map.md` §5 (`PROTO -.-> UICONV`, `PROTO -.-> WF`), tài liệu này được coi là **nguồn sự thật về bố cục dạng văn bản**. Do đó `WF` sẽ chạy ở **chế độ 🎨 (prototype tham chiếu)**, với **mức độ phủ khác nhau theo từng màn hình** (nhóm Guest/Customer `SCR-01`…`SCR-15` được mô tả khá đầy đủ 3 trạng thái + bố cục; các nhóm Seller/Admin/Ops/CSR cũng có mô tả nhưng chưa được đối chiếu ở lần chạy `uiconv` này) — **không phải** chế độ ✏️ hoàn toàn như ghi trước đây. Phần "PO ký thay Designer" và mục "Designer còn phải làm" ở `WF` §6 chuyển thành việc của **Dev FE** vẫn **giữ nguyên**. | Điều phối, thay mặt PO (chạy chế độ `go` — cần PO xác nhận lại bằng chữ ký thật khi ký G3) | 2026-09-08 (sửa nội dung ngày 2026-09-08, v1.2) | Ở G3: `UICONV`/`WF` không có chữ ký Designer, thay bằng chữ ký PO + tham chiếu `DEC-01`; `WF` chạy chế độ 🎨 nên PO chỉ cần xác nhận bản đồ §1 và §5 không còn lệch mở (không cần Designer duyệt lại prototype vì đây là văn bản SAD đã approved); rủi ro: mô tả text có thể thiếu chi tiết thị giác thật (không có ảnh/Figma) | `references/workflow.md` §3, §2 (checklist G3 dòng *(screen)*); ghi chú người duyệt trong prompt điều phối GĐ3 | +| DEC-05 | Chạy `ba-3-specification` activity `uiconv` (sinh `UICONV_e-commerce_v1.0.md`) **trong khi Gate G2 (Solution sign-off) chưa được PO + Tech Lead ký chính thức** cho module Giỏ hàng & Checkout — xem `DEC-02` (ngoại lệ gate G1→G2). Đây là **ngoại lệ gate nối tiếp**, chấp nhận cho mục đích đánh giá bộ skill BA, không phải G2 đã coi là đạt. `UICONV` là tài liệu cấp **project** (không riêng module), nên rủi ro thấp hơn so với việc viết SRS/AC dựa trực tiếp trên `BACKLOG`/`BR` chưa chốt — nhưng nếu `BACKLOG_CartCheckout`/`BR_CartCheckout` đổi khi G2 ký thật (đặc biệt các trường đang có `OQ` mở như số field Guest checkout — `BR-CART-07`), phải rà lại `UICONV` §11 (từ vựng thành phần liên quan Guest checkout) và mọi `WF` đã tham chiếu. | Người điều phối, xác nhận rõ ràng và khẳng định lại sau khi được cảnh báo rủi ro | 2026-09-08 | `UICONV_e-commerce_v1.0.md` giữ `Status: 🟡 Draft`, không thể `✅ Baselined` cho tới khi G2 module liên quan được ký thật và G3 tự nó được ký; ghi thêm `OQ-027` trong `UICONV` §13 và `OQ_e-commerce.md` | Prompt điều phối GĐ3 "Ngoại lệ gate"; `references/workflow.md` §1 (sơ đồ gate tuần tự), §2 (G3 phụ thuộc G2) | +| DEC-02 | Chạy GĐ2 (`ba-2-analysis`) cho module Giỏ hàng & Checkout **trong khi Gate G1 chưa được ký chính thức** — `BRIEF_CartCheckout_v1.0.md` tự chấm chưa đủ điều kiện G1 (3/6 tiêu chí còn ☐: thiếu tên thật stakeholder, thiếu buổi làm việc trực tiếp, KPI chưa có baseline số). Đây là **ngoại lệ gate**, chấp nhận cho mục đích đánh giá bộ skill BA, **không phải G1 đã được coi là đạt**. Toàn bộ artifact GĐ2 (`PROCESS`, `BACKLOG`, `BR`, `RBAC`, `IMPACT`) phải được rà lại khi PO ký G1 thật — đặc biệt các phần dựa trên `RISK`/`ASM` chưa xác nhận (AS-IS Phần A3–A5, `BR-CART-01/03/06`). | Người điều phối, xác nhận rõ ràng và khẳng định lại sau khi được cảnh báo rủi ro | 2026-09-08 | Mọi artifact GĐ2 của module Giỏ hàng & Checkout mang trạng thái 🟡 Draft, cần rà lại toàn bộ khi G1 ký thật; G2 (gate của chính GĐ2 này) cũng chưa thể ký chính thức vì phụ thuộc G1 | Prompt điều phối "Ngoại lệ gate"; `references/workflow.md` §1 (sơ đồ gate tuần tự) | +| DEC-03 | Xác nhận điểm nối với module Khuyến mãi & Loyalty (trả lời `OQ-004`, mở từ GĐ1): áp dụng mã coupon (FR-13) và điểm thưởng (FR-14) là **điểm tích hợp**, không thuộc phạm vi module Giỏ hàng & Checkout. Module Khuyến mãi/Loyalty **sở hữu logic tính toán**; module Giỏ hàng & Checkout **chỉ hiển thị kết quả đã tính và gọi API áp dụng**. | PO sàn (trả lời qua người điều phối) | 2026-09-08 | Phạm vi §5.2 của `BRIEF` được xác nhận đúng như đề xuất ban đầu của BA; `BACKLOG_CartCheckout_v1.0.md` không có US riêng cho coupon/loyalty; `IMPACT_CartCheckout_v1.0.md` §1.5 ghi nhận đây là một điểm tích hợp cần API contract trước GĐ3 (`OQ-017` mới phát sinh: xử lý khi API này lỗi/chậm) | `BRIEF_CartCheckout_v1.0.md` §5.2, `OQ-004`; trả lời của người dùng trong prompt điều phối GĐ2 | +| DEC-06 | Chạy `ba-3-specification` các activity `srs`/`part2`/`ac`/`errors`/`nfr`/`api`/`wf` để đặc tả US-002 (Xem giỏ hàng nhóm theo seller) và US-003 (Sửa số lượng / xoá sản phẩm trong giỏ) — sinh `SRS_US002-003_v1.0.md`, `AC_US-002_v1.0.md`, `AC_US-003_v1.0.md`, `NFR_US002-003_v1.0.md`, `API_US002-003_v1.0.md`, `WF_US002-003_v1.0.md`+`.html` — **trong khi Gate G2 của module Giỏ hàng & Checkout vẫn chưa được PO + Tech Lead ký chính thức** (nối tiếp `DEC-02`, `DEC-05`). Đây là ngoại lệ gate nối tiếp, chấp nhận cho mục đích đánh giá bộ skill BA. Rủi ro cao hơn `DEC-05` (UICONV cấp project) vì `SRS`/`AC` lần này bám trực tiếp vào `BACKLOG`/`BR` của module — nếu `BACKLOG_CartCheckout`/`BR_CartCheckout` đổi khi G2 ký thật, phần bị ảnh hưởng nhiều nhất là §1.3 (hiện chưa có `BR-CART-nn` áp dụng trực tiếp cho US-002/US-003) và mọi AC nhóm 1 dựa trên "không có BR ràng buộc". | Người điều phối, xác nhận rõ ràng và khẳng định lại sau khi được cảnh báo rủi ro | 2026-09-08 | `SRS_US002-003_v1.0.md` và các artifact phụ thuộc giữ `Status: 🟡 Draft`, không thể `✅ Baselined` cho tới khi G2 module được ký thật; đã ghi 7 `OQ` mới (`OQ-028`…`OQ-034`) vào `OQ_e-commerce.md` | Prompt điều phối GĐ3 (lần chạy US-002/US-003) "Ngoại lệ gate"; `DEC-02`, `DEC-05` | +| DEC-04 | Xác nhận thứ tự ưu tiên khi phải cắt phạm vi (trả lời `OQ-008`, mở từ GĐ1): giữ **RQ-001 (giỏ hàng đa seller) và RQ-002 (tách đơn theo seller)** làm ưu tiên trước; **RQ-003 phần thanh toán ví điện tử (VNPay/Momo) có thể lùi triển khai sau COD** nếu thiếu thời gian. | PO sàn (trả lời qua người điều phối) | 2026-09-08 | `BACKLOG_CartCheckout_v1.0.md` §8 (đề xuất thứ tự thực hiện): US-001…US-006 (giỏ hàng + checkout + Guest) và US-007 (COD) ưu tiên đợt 1–3; US-008 (VNPay/Momo) xếp đợt 4, có thể lùi tiếp nếu `ASM-01` chưa xác minh kịp | `BRIEF_CartCheckout_v1.0.md` §6, `OQ-008`; trả lời của người dùng trong prompt điều phối GĐ2 | diff --git a/ba-output/e-commerce/00-index/INDEX_e-commerce.md b/ba-output/e-commerce/00-index/INDEX_e-commerce.md new file mode 100644 index 0000000..4aa67cf --- /dev/null +++ b/ba-output/e-commerce/00-index/INDEX_e-commerce.md @@ -0,0 +1,24 @@ +# INDEX — e-commerce + +| | | +|---|---| +| **Cập nhật** | 2026-09-08 | +| **Giai đoạn hiện tại** | GĐ1 · Discovery (chưa bắt đầu) | +| **Gate gần nhất đã qua** | Chưa có (project mới khởi tạo) | + +## Artifact + +| Loại | File mới nhất | Version | Status | Cập nhật | +|---|---|---|---|---| +| PROFILE | `00-index/PROFILE_e-commerce.md` | 1.0 | 🟡 Draft | 2026-09-08 | + +## Open Question đang mở + +| ID | Nội dung | Hỏi ai | Từ ngày | Chặn gì | +|---|---|---|---|---| + +## Quyết định đã chốt + +| ID | Quyết định | Người quyết | Ngày | Ảnh hưởng | +|---|---|---|---|---| +| DEC-01 | Dự án chưa có Designer riêng — PO ký thay `UICONV`/`WF` ở G3; `WF` chạy chế độ ✏️ (không có prototype tham chiếu, dùng `docs/sections/07-giao-dien.md` làm đầu vào đề xuất) | Điều phối (thay mặt PO, chạy chế độ `go`) | 2026-09-08 | G3 — chữ ký `UICONV`/`WF` là PO thay vì Designer; mục "Designer còn phải làm" ở `WF` §6 chuyển cho Dev FE | diff --git a/ba-output/e-commerce/00-index/OQ_e-commerce.md b/ba-output/e-commerce/00-index/OQ_e-commerce.md new file mode 100644 index 0000000..9bc85b3 --- /dev/null +++ b/ba-output/e-commerce/00-index/OQ_e-commerce.md @@ -0,0 +1,66 @@ +# OQ — Sổ Open Question — e-commerce + +| | | +|---|---| +| **Version** | 1.3 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-1-discovery / ba-2-analysis / ba-3-specification) | +| **Status** | 🟡 Draft — cập nhật liên tục qua các giai đoạn | +| **Approved by** | — *(sổ theo dõi, không cần baseline riêng)* | +| **Source** | `01-discovery/BRIEF_CartCheckout_v1.0.md` · `01-discovery/STAKEHOLDER_CartCheckout_v1.0.md` · `01-discovery/ELICITATION_CartCheckout_2026-09-08.md` · `01-discovery/RISK_CartCheckout_v1.0.md` · `02-analysis/PROCESS_CartCheckout_v1.0.md` · `02-analysis/BACKLOG_CartCheckout_v1.0.md` · `02-analysis/BR_CartCheckout_v1.0.md` · `02-analysis/RBAC_CartCheckout_v1.0.md` · `02-analysis/IMPACT_CartCheckout_v1.0.md` · `00-index/UICONV_e-commerce_v1.0.md` · `03-specification/SRS_US002-003_v1.0.md` · `03-specification/API_US002-003_v1.0.md` · `03-specification/NFR_US002-003_v1.0.md` · `03-specification/WF_US002-003_v1.0.md` | +| **Scope** | Toàn dự án e-commerce — module Giỏ hàng & Checkout (GĐ1 + GĐ2) + quy ước giao diện cấp project (GĐ3 `uiconv`) + đặc tả US-002/US-003 (GĐ3 `srs`/`ac`/`nfr`/`api`/`wf`) | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | CR | +|---|---|---|---|---| +| 1.0 | 2026-09-08 | BA (qua skill ba-1-discovery) | Khởi tạo sổ OQ, nhập 8 câu hỏi từ GĐ1 module Giỏ hàng & Checkout | — | +| 1.1 | 2026-09-08 | BA (qua skill ba-2-analysis) | Đóng `OQ-004`, `OQ-008` (đã có trả lời của PO, xem `DEC-03`/`DEC-04`); thêm 9 câu hỏi mới phát sinh từ GĐ2 (`OQ-009`…`OQ-017`) | — | +| 1.2 | 2026-09-08 | BA (qua skill ba-3-specification, activity `uiconv`) | Thêm 10 câu hỏi phát sinh từ `UICONV_e-commerce_v1.0.md` (`OQ-018`…`OQ-027`) — chủ yếu các ô "chọn một" mà SAD §7 không nói, cộng ngoại lệ gate G2 (`OQ-027`, xem `DEC-05`) | — | +| 1.3 | 2026-09-08 | BA (qua skill ba-3-specification, activity `srs`/`ac`/`nfr`/`api`/`wf`) | Thêm 7 câu hỏi phát sinh từ đặc tả US-002/US-003 (`OQ-028`…`OQ-034`) — số lượng về 0, nguồn giá hiển thị, giới hạn tồn kho tại màn Giỏ hàng, checkout một phần giỏ, ownership Guest, ngưỡng hiệu năng, schema `GET /v1/cart` | — | + +--- + +## Open Question đang mở + +| ID | Nội dung | Hỏi ai | Từ ngày | Chặn gì | Nguồn | +|---|---|---|---|---|---| +| OQ-001 | Tên thật + đầu mối liên lạc của STK-01…STK-06 (PO sàn, Khách hàng đại diện, Seller đại diện, Kế toán đối soát, Trưởng vận hành, Tech Lead) là gì? | Điều phối dự án / PO | 2026-09-08 | Ký G1 module Giỏ hàng & Checkout một cách hợp lệ | `STAKEHOLDER_CartCheckout_v1.0.md` §7 | +| OQ-002 | Mức Quan tâm × Ảnh hưởng của từng stakeholder (đánh giá sơ bộ của BA) có đúng không? | STK-01…STK-06 | 2026-09-08 | Chiến lược tiếp cận stakeholder | `STAKEHOLDER_CartCheckout_v1.0.md` §2, §7 | +| OQ-003 | Ai là đại diện Pháp chế/Bảo mật cho dự án e-commerce? Cần rà soát phạm vi lưu/chia sẻ PII (địa chỉ, SĐT) khi tách đơn theo seller. | PO sàn | 2026-09-08 | RISK-03, RQ-003, RACI mục tuân thủ PII | `STAKEHOLDER_CartCheckout_v1.0.md` §3, §7; `BRIEF_CartCheckout_v1.0.md` §10; `RISK_CartCheckout_v1.0.md` §2 | +| OQ-005 | Cần tổ chức phỏng vấn thật với Khách hàng đại diện (STK-02) và Seller đại diện (STK-03) cho module này — ai làm đầu mối sắp xếp? | Điều phối dự án / PO sàn | 2026-09-08 | Chất lượng RQ, phát hiện ngoại lệ thực tế trước GĐ2 | `ELICITATION_CartCheckout_2026-09-08.md` §5; `BRIEF_CartCheckout_v1.0.md` §10 | +| OQ-006 | Chính sách giới hạn giá trị đơn COD (nếu có) là gì, để giảm rủi ro bùng hàng khi giỏ đa seller bị tách thành nhiều đơn COD độc lập? | PO sàn, Kế toán đối soát | 2026-09-08 | `ASM-05`, `RISK-01`, `BR-CART-03` (GĐ2) | `RISK_CartCheckout_v1.0.md` §1, §2; `BR_CartCheckout_v1.0.md` | +| OQ-007 | Baseline thật cho GOAL-01 (tỷ lệ bỏ giỏ hàng ở checkout đa seller) và GOAL-02 (tỷ lệ thanh toán thành công theo kênh) là bao nhiêu? | PO sàn | 2026-09-08 | Đo lường hiệu quả ở GĐ5, xác nhận mục tiêu ở GĐ1 | `BRIEF_CartCheckout_v1.0.md` §4, §10 | +| OQ-009 | Khi giá/tồn kho thay đổi giữa lúc thêm giỏ và lúc checkout (`ASM-06`), hệ thống tự động cập nhật giá mới và thông báo, hay chặn checkout yêu cầu khách xác nhận lại? | PO + Tech Lead | 2026-09-08 | US-003, US-004, `PROCESS` bước B3/B5 | `PROCESS_CartCheckout_v1.0.md` A5 (E2); `BACKLOG_CartCheckout_v1.0.md` | +| OQ-010 | Xác nhận khả thi kỹ thuật `ASM-01` (webhook VNPay/Momo gần thời gian thực) | Tech Lead | 2026-09-08 | `BR-CART-06`, US-008 | `PROCESS_CartCheckout_v1.0.md` A3 (P2); `RISK_CartCheckout_v1.0.md` ASM-01 | +| OQ-011 | Xác nhận `ASM-03` — giỏ hàng N seller luôn tách thành đúng N đơn con, không có trường hợp gộp 2 seller vào 1 đơn con | PO | 2026-09-08 | `BR-CART-01`, US-004 | `RISK_CartCheckout_v1.0.md` ASM-03; `BR_CartCheckout_v1.0.md` | +| OQ-012 | Guest (chưa xác thực) có cần giới hạn giá trị đơn hoặc xác thực OTP cho đơn giá trị cao không (liên quan `RISK-01` phương án (b))? | PO, Bảo mật *(chưa có người — `OQ-003`)* | 2026-09-08 | `RBAC_CartCheckout_v1.0.md` §2, `BR-CART-03` | `RBAC_CartCheckout_v1.0.md` | +| OQ-013 | Với thanh toán COD, `Payment.status` được ghi nhận "success" ngay khi đơn được xác nhận, hay giữ "pending" cho tới khi thực thu tiền lúc giao hàng? | Kế toán đối soát, PO | 2026-09-08 | US-007, `BR_CartCheckout_v1.0.md` §3 (vòng đời `PAYMENT`) | `BR_CartCheckout_v1.0.md` | +| OQ-014 | `Order.total_amount`/`OrderSeller.subtotal_amount` có gồm phí vận chuyển ước tính (US-005) không? Coupon/điểm thưởng áp giảm giá ở cấp `Order` hay từng `OrderSeller`? | PO, Tech Lead | 2026-09-08 | `BR-CART-08`/`09`, US-005, `AC` ở GĐ3 | `BR_CartCheckout_v1.0.md` §5 | +| OQ-015 | Có cần cơ chế chống lạm dụng (rate limit/CAPTCHA) cho Guest checkout để tránh spam tạo đơn giả không? | Tech Lead, Bảo mật | 2026-09-08 | `RBAC_CartCheckout_v1.0.md` §5, thiết kế kỹ thuật GĐ3 | `RBAC_CartCheckout_v1.0.md` | +| OQ-016 | Mức che dữ liệu PII (địa chỉ/SĐT) khi truyền cho seller lúc tách đơn là gì? | Pháp chế/Bảo mật *(chưa có người — `OQ-003`)*, PO | 2026-09-08 | `RBAC_CartCheckout_v1.0.md` §4, `RISK-03` | `RBAC_CartCheckout_v1.0.md` | +| OQ-017 | Nếu API "áp dụng mã/điểm" của module Khuyến mãi & Loyalty lỗi/chậm lúc checkout, hệ thống bỏ qua và cho tiếp tục hay chặn checkout hoàn toàn? | PO, Tech Lead | 2026-09-08 | `IMPACT_CartCheckout_v1.0.md` §1.5 dòng Khuyến mãi & Loyalty | `IMPACT_CartCheckout_v1.0.md` | +| OQ-018 | Ngưỡng breakpoint theo px cho desktop/tablet/mobile-web, và grid layout (số cột, gutter px, max-width px) toàn site — SAD §7.0 chỉ nêu 3 tier tên gọi, không cho ngưỡng cụ thể | Dev FE / Tech Lead | 2026-09-08 | `UICONV` §1 (Khung layout) | `UICONV_e-commerce_v1.0.md` §1 | +| OQ-019 | Kiểu phân trang (offset/cursor/cuộn vô hạn), số dòng-sản phẩm mỗi trang, và tiêu chí sắp xếp mặc định cho danh sách sản phẩm (SCR-02) và lịch sử đơn hàng (SCR-10) — SCR-02 chỉ nêu "phân trang hoặc infinite-scroll", chưa chọn 1 | PO, Dev FE | 2026-09-08 | `UICONV` §3 (Danh sách) | `UICONV_e-commerce_v1.0.md` §3 | +| OQ-020 | Vị trí và thời lượng hiển thị toast thông báo — SAD §7 không mô tả cơ chế toast (chỉ có banner trong vùng, inline dưới field, trang trạng thái) | PO, Dev FE | 2026-09-08 | `UICONV` §5 (Phản hồi hệ thống) | `UICONV_e-commerce_v1.0.md` §5 | +| OQ-021 | Nút CTA chính khi form chưa hợp lệ: bấm được rồi hiện lỗi, hay khoá (disable) tới khi hợp lệ? — SAD chỉ nói rõ hành vi này ở cấp wizard (SCR-16, chặn "Next"), không nói cho form thường | PO, Dev FE | 2026-09-08 | `UICONV` §4 (Form) | `UICONV_e-commerce_v1.0.md` §4 | +| OQ-022 | Chọn design system cụ thể — Material Design hay Ant Design? NFR-07 ghi "dev chọn", chưa có quyết định chính thức | Tech Lead | 2026-09-08 | `UICONV` §0, §11 (Từ vựng thành phần) | `UICONV_e-commerce_v1.0.md` §0, §11 | +| OQ-023 | Ngôn ngữ hiển thị khi thiếu bản dịch (EN/ZH/KO/JA): hiện khoá i18n hay fallback VI? Độ dài nhãn tối đa (ký tự) để không vỡ layout ở ZH/KO/JA? SAD §7.0 chỉ cảnh báo định tính "cần co giãn được, không fix-width" | PO, Dev FE | 2026-09-08 | `UICONV` §9 (Ngôn ngữ và giọng văn) | `UICONV_e-commerce_v1.0.md` §9 | +| OQ-024 | Độ trễ debounce (ms) cho gợi ý autocomplete ở ô tìm kiếm (SCR-01) — SAD chỉ chốt ngưỡng tối thiểu 1 ký tự trước khi gợi ý, không chốt độ trễ | Dev FE | 2026-09-08 | `UICONV` §3 (Danh sách — Tìm kiếm) | `UICONV_e-commerce_v1.0.md` §3 | +| OQ-025 | Quy tắc quy đổi tiền tệ tham khảo (`CurrencyToggle`/`PriceDisplay`, FR-16/NFR-06): nguồn tỷ giá, tần suất cập nhật, quy tắc làm tròn — SAD chỉ xác nhận VND là tiền giao dịch chính, giá quy đổi chỉ tham khảo | PO, Tech Lead | 2026-09-08 | `UICONV` §8 (Định dạng hiển thị) | `UICONV_e-commerce_v1.0.md` §8 | +| OQ-026 | Xưng hô trong toàn bộ text hệ thống ("bạn" hay không xưng hô) — SAD §7 không đề cập giọng văn | PO | 2026-09-08 | `UICONV` §9 (Ngôn ngữ và giọng văn) | `UICONV_e-commerce_v1.0.md` §9 | +| OQ-027 | 🔴 Ngoại lệ gate: `UICONV_e-commerce_v1.0.md` được sinh trong khi Gate G2 module Giỏ hàng & Checkout chưa được PO + Tech Lead ký chính thức (xem `DEC-02`). Nếu `BACKLOG_CartCheckout`/`BR_CartCheckout` đổi khi G2 ký thật, `UICONV` (đặc biệt §11 phần liên quan Guest checkout, `BR-CART-07`) có cần rà lại không? | PO, Tech Lead | 2026-09-08 | Baseline `UICONV` và mọi `WF` phụ thuộc | `DECISION_e-commerce.md` DEC-05 | +| OQ-028 | Sửa số lượng `CartItem` về 0 (nhập tay hoặc bấm `-` khi đang ở 1, màn Giỏ hàng US-003) → hệ thống tự mở modal xoá dòng, hay chặn không cho giảm dưới 1? | PO | 2026-09-08 | `SRS_US002-003` F01, `AC-US003-08` | `SRS_US002-003_v1.0.md` §8 | +| OQ-029 | Giá hiển thị ở màn Giỏ hàng (US-002, C06) là giá snapshot lúc thêm giỏ (`cart_item.unit_price_snapshot`) hay giá hiện tại real-time từ Catalog? Ảnh hưởng badge "Giá đã thay đổi" mà SAD SCR-04 mô tả nhưng `BACKLOG` không xác nhận thuộc scope US-002 | PO, Tech Lead | 2026-09-08 | `SRS_US002-003` C06, `WF_US002-003` §5 #3 | `SRS_US002-003_v1.0.md` §8 | +| OQ-030 | Sửa số lượng tại màn Giỏ hàng (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? SAD SCR-04 mô tả "≤ tồn kho hiện tại" nhưng `BACKLOG` loại trừ việc này khỏi US-002/US-003 | PO, Tech Lead | 2026-09-08 | `SRS_US002-003` F01, `WF_US002-003` §5 #2/#4 | `SRS_US002-003_v1.0.md` §8 | +| OQ-031 | Nút "Tiến hành Checkout" (SCR-04) áp dụng cho toàn bộ giỏ hàng, hay chỉ cho các dòng được tick chọn (checkbox mà SAD SCR-04 mô tả nhưng không `US` nào trong `BACKLOG` định nghĩa)? Ảnh hưởng cả phạm vi US-004 | PO | 2026-09-08 | `SRS_US002-003` C11, `WF_US002-003` §5 #1 | `SRS_US002-003_v1.0.md` §8 | +| 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` | `SRS_US002-003_v1.0.md` §8, `API_US002-003_v1.0.md` §5 | +| 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 | `NFR_US002-003_v1.0.md` §9 | +| OQ-034 | `GET /v1/cart` trả về cấu trúc đã nhóm theo seller sẵn (`sellers[].items[]`) hay danh sách phẳng cart items kèm `sellerId` để FE tự nhóm? SAD §4.1.5 không có ví dụ JSON cho endpoint này | BE Lead, Tech Lead | 2026-09-08 | `API_US002-003` §1 endpoint 3.1, C02 nguồn dữ liệu (không chặn G3 — đã đánh dấu ⚠️ BA đề xuất) | `API_US002-003_v1.0.md` §5 | + +## Open Question đã đóng + +| ID | Nội dung | Trả lời | Ngày đóng | Người trả lời | +|---|---|---|---|---| +| OQ-004 | Áp coupon (FR-13) và dùng điểm thưởng (FR-14) ngay trong màn hình checkout có thuộc phạm vi module Giỏ hàng & Checkout không, hay là điểm tích hợp với module Khuyến mãi/Loyalty? | Là điểm tích hợp: module Khuyến mãi/Loyalty sở hữu logic tính, module Giỏ hàng & Checkout chỉ hiển thị kết quả đã tính và gọi API áp dụng — xem `DEC-03` | 2026-09-08 | PO sàn (qua người điều phối) | +| OQ-008 | Xác nhận lại: cả 4 RQ của module này (RQ-001…RQ-004) đều Must — nếu chỉ kịp một nửa thời gian, PO sẽ cắt cái nào? | Giữ RQ-001 (giỏ hàng đa seller) và RQ-002 (tách đơn) trước; RQ-003 phần ví điện tử (VNPay/Momo) có thể lùi sau COD — xem `DEC-04` | 2026-09-08 | PO sàn (qua người điều phối) | diff --git a/ba-output/e-commerce/00-index/PROFILE_e-commerce.md b/ba-output/e-commerce/00-index/PROFILE_e-commerce.md new file mode 100644 index 0000000..ec9be00 --- /dev/null +++ b/ba-output/e-commerce/00-index/PROFILE_e-commerce.md @@ -0,0 +1,30 @@ +# PROFILE — e-commerce + +| | | +|---|---| +| **PRODUCT** | screen | +| **LIFECYCLE** | greenfield | +| **RIGOR** | standard | +| **Ngành** | Thương mại điện tử — marketplace đa seller | +| **Người chốt profile** | PO, 2026-09-08 (xác nhận qua điều phối, chạy chế độ `go`) | +| **Lý do chọn** | `screen`: sản phẩm có giao diện người dùng (web/app cho buyer, seller, admin) — xem `e-commerce/docs/sections/07-giao-dien.md` (SCR-01…). `greenfield`: dự án marketplace mới, không thay thế hệ thống đang chạy nào — xem `e-commerce/docs/00-project-brief.md`. `standard`: đây là lần chạy thử nghiệm để đánh giá bộ skill BA nhưng mô hình hoá theo sản phẩm thật (marketplace đa seller, có tiền, có nhiều actor) — không phải POC nội bộ ≤ 2 tuần nên không dùng `light`. | + +## Hệ quả đã áp dụng + +| Quyết định | Vì trục nào | +|---|---| +| GĐ3 dùng biến thể SRS PART 2 = `screen`; GĐ3 nạp thêm `UICONV` (00-index) + `WF` (03-specification) | PRODUCT | +| GĐ1 mô tả cách làm thủ công hiện tại (nếu có) thay vì AS-IS đầy đủ; không có "dữ liệu cũ cần migrate" | LIFECYCLE | +| GĐ2 `PROCESS` PHẦN A rút gọn còn A3 (điểm đau) + A4 (đường tắt) + A5 (ngoại lệ); bỏ A1/A2/A6 với lý do "không có hệ thống cũ để mô tả" | LIFECYCLE | +| GĐ2 `IMPACT` rút gọn: chỉ trục tích hợp (không có module/dữ liệu cũ bị ảnh hưởng) | LIFECYCLE | +| Gate ký bởi PO + Tech Lead + QA theo từng gate | RIGOR | +| G3 (screen) cần thêm chữ ký Designer cho `UICONV`/`WF` — dự án **chưa có Designer riêng** ⇒ **PO ký thay**, ghi `DEC-01` (xem `00-index/DECISION_e-commerce.md`); mục "Designer còn phải làm" ở `WF` §6 chuyển thành việc của Dev FE | RIGOR + PRODUCT | +| Không có prototype tham chiếu (design/, prototype/ không tồn tại) ⇒ `WF` chạy chế độ ✏️ (BA tự đề xuất bố cục dựa trên `e-commerce/docs/sections/07-giao-dien.md` — SCR-01…), cần Designer/PO ký; không dùng chế độ 🎨 | PRODUCT | + +## Input đã phát hiện (background, ngoài `ba-output/`) + +| File | Vai trò | Dùng ở giai đoạn | +|---|---|---| +| `e-commerce/docs/00-project-brief.md` | Brief đã chốt qua 3 vòng — mô hình marketplace đa seller, actor, MVP, NFR | Input cho `ba-1-discovery` | +| `e-commerce/docs/sections/02-phan-tich-yeu-cau.md` | FR-01…FR-24, NFR-01…08 của SAD | Input cho `ba-2-analysis` / `ba-3-specification` | +| `e-commerce/docs/sections/07-giao-dien.md` | Mô tả UI dạng văn bản SCR-01… | Input tham chiếu cho `UICONV`/`WF` ở `ba-3-specification` (chế độ ✏️, không phải prototype thật) | diff --git a/ba-output/e-commerce/00-index/UICONV_e-commerce_v1.0.md b/ba-output/e-commerce/00-index/UICONV_e-commerce_v1.0.md new file mode 100644 index 0000000..14849dd --- /dev/null +++ b/ba-output/e-commerce/00-index/UICONV_e-commerce_v1.0.md @@ -0,0 +1,265 @@ +# UICONV — Quy ước giao diện — e-commerce + +| | | +|---|---| +| **Version** | 1.1 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-3-specification, activity `uiconv`) | +| **Status** | 🟡 Draft | +| **Approved by** | Designer: — · PO: — *(dự án chưa có Designer riêng — PO ký thay, xem `DEC-01`)* | +| **Source** | `e-commerce/docs/sections/07-giao-dien.md` (SAD §7 "Thiết kế giao diện", `status: approved`, `version: 1` — coi là **prototype tham chiếu dạng văn bản**, xem `DEC-01` đã sửa) · `e-commerce/docs/sections/02-phan-tich-yeu-cau.md` (NFR-01, NFR-06, NFR-07, FR-15, FR-16) · `02-analysis/BR_CartCheckout_v1.0.md` §3 (vòng đời trạng thái `CART`/`ORDER_SELLER`/`PAYMENT` — nguồn cho Badge trạng thái §11) · `00-index/DECISION_e-commerce.md` (`DEC-01`, `DEC-05`) · `00-index/PROFILE_e-commerce.md` | +| **Scope** | Toàn project — mọi `SRS` và `WF` có `PRODUCT = screen`. Lần chạy này **ưu tiên điền quy ước phục vụ nhóm màn hình Guest/Customer** (`SCR-01`…`SCR-10`, SAD §7.1.1); nhóm Seller/Admin/Ops/CSR (`SCR-16`…`SCR-32`) dùng chung khung §1–§10 nhưng phần điều hướng/menu riêng của họ **chưa được đối chiếu chi tiết** ở lần chạy này — xem ghi chú ở §1 và §12. | +| **Profile** | `screen · greenfield · standard` (xem `00-index/PROFILE_e-commerce.md`) | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | CR | +|---|---|---|---|---| +| 1.0 | 2026-09-08 | BA (qua skill ba-3-specification, activity `uiconv`) | Bản đầu — sinh từ SAD §7 (prototype dạng văn bản, `SCR-01`…`SCR-32`), NFR-01/06/07, `BR_CartCheckout_v1.0.md` §3. 10 open question mới (`OQ-018`…`OQ-027`) cho các ô "chọn một" mà SAD §7 không nói | — | +| 1.1 | 2026-09-08 | BA (qua skill ba-3-specification, activity `srs`/`wf` — bổ sung §10/§12 theo `SRS_US002-003_v1.0.md`/`WF_US002-003_v1.0.md`) | §10: cập nhật số kế tiếp chưa dùng của dãy `E-CART-` từ `0002` lên `0007` (đã dùng `0002`…`0006` cho US-002/US-003). §12: thêm 2 dòng ngoại lệ đã duyệt — (1) `SCR-04` dùng text riêng "Giỏ hàng trống"/"Tiếp tục mua sắm" thay mẫu chung §6 (đã ghi chú trước, nay chính thức hoá); (2) `SCR-04` sửa số lượng theo mẫu inline auto-save (không có nút Lưu riêng), khác quy ước §4 mặc định | — | + +> ⚠️ **Ngoại lệ gate G2** — tài liệu này được sinh trong khi Gate G2 (Solution sign-off) của +> module Giỏ hàng & Checkout **chưa được PO + Tech Lead 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. Nếu +> `BACKLOG_CartCheckout`/`BR_CartCheckout` đổi khi G2 ký thật, phải rà lại §11 (từ vựng thành +> phần liên quan Guest checkout) — xem `OQ-027`. + +> **Vai trò của tài liệu này.** Một project có nhiều `SRS`, mỗi lần chạy tối đa 3 US. Không có +> tài liệu này thì mỗi `SRS` tự đặt một kiểu phân trang, một vị trí toast, một định dạng ngày. +> `SRS` và `WF` **tham chiếu** mục ở đây thay vì định nghĩa lại; muốn lệch phải ghi vào §12. +> +> **Thứ tự ưu tiên khi lệch:** Design system của dự án (nếu có) > Prototype đã duyệt > `UICONV` +> > `SRS` từng US. `SRS` chỉ được ghi khác `UICONV` khi có dòng ở §12. + +--- + +## 0. Nguồn + +| | | +|---|---| +| **Design system** | Chưa có lựa chọn cụ thể. NFR-07 (SAD §2.2) ghi "sử dụng design system chuẩn (VD. Material Design hoặc Ant Design) làm nền tảng giao diện" — **dev chọn, chưa chốt** → `OQ-022`. Quy ước ở tài liệu này là **ràng buộc tối thiểu** (bố cục, trạng thái, text), không phụ thuộc design system cụ thể nào. | +| **Prototype tham chiếu** | `e-commerce/docs/sections/07-giao-dien.md` — SAD §7 "Thiết kế giao diện" (`status: approved`, `version: 1`, ngày duyệt không ghi rõ trong front-matter). Mô tả bố cục dạng 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) cho `SCR-01`…`SCR-32`. **Không phải** Figma/ảnh — không có màu sắc/typography/khoảng cách chính xác (SAD §7.0 xác nhận rõ: "không có brand guideline cố định"). | +| **Guideline sẵn có của dự án** | Không có `GLOBAL_UI_CONVENTION.md` trước đó — đây là bản đầu tiên. | +| **Ai sở hữu quy ước** | BA đề xuất · **Designer duyệt** (dự án không có Designer ⇒ **PO ký thay**, `DEC-01`) · PO duyệt phần text/giọng văn | +| **Nền tảng** | Web responsive (desktop, tablet, mobile-web) — theo SAD §7.0. **Không** có app di động native trong MVP (out-of-scope, xem SAD §1.1). | + +## 1. Khung layout + +| | | +|---|---| +| **Grid** | 🔴 Chưa chốt — SAD §7 không cho số cột/gutter/max-width cụ thể → `OQ-018` | +| **Header cố định** | **Có** — chứa: logo sàn, thanh tìm kiếm (autocomplete), `LanguageSwitcher` (FR-15), `CurrencyToggle` (FR-16, giá tham khảo), icon giỏ hàng (badge số lượng), icon tài khoản/đăng nhập. *(Nguồn: SCR-01)* | +| **Sidebar / menu** | Nhóm **Guest/Customer**: **Không có** sidebar/menu cố định toàn cục — điều hướng chính qua header (tìm kiếm, tài khoản, giỏ hàng) + mega-menu ngành hàng (SCR-01 Section 2 "điều hướng ngành hàng"). Sidebar/bottom-sheet chỉ xuất hiện **cục bộ** ở màn hình có bộ lọc (SCR-02 — xem §3), không phải điều hướng toàn cục. *(Nhóm Seller có header menu điều hướng riêng — SCR-17: "Sản phẩm, Đơn hàng, Báo cáo, Thông báo"; nhóm Admin tương tự SCR-22 — hai nhóm này **ngoài phạm vi ưu tiên** lần chạy này, chưa được điền chi tiết ở §1–§9, xem §12 khi có lần chạy `uiconv` bổ sung.)* | +| **Footer** | **Có** — chứa: thông tin sàn, chính sách đổi trả, liên kết ngôn ngữ, thông tin tuân thủ (thông báo Bộ Công Thương theo NĐ 52/2013, 85/2021 — NFR-05). *(Nguồn: SCR-01)* | + +| Breakpoint | Khoảng (px) | Sidebar | Bảng dữ liệu | Form | +|---|---|---|---|---| +| Desktop | 🔴 `OQ-018` | Bộ lọc hiện cố định trái *(SCR-02)* | N/A cho Guest/Customer — luôn dùng lưới `ProductCard`/`CartItem`, không phải bảng dữ liệu kiểu bảng-hành-chính *(SCR-01, SCR-04)* | 🔴 Số cột form — `OQ-018` | +| Tablet | 🔴 `OQ-018` | 🔴 Chưa chốt — SAD chỉ nói "desktop, tablet, mobile-web" không mô tả riêng hành vi tablet cho bộ lọc → `OQ-018` | Như trên | 🔴 `OQ-018` | +| Mobile | 🔴 `OQ-018` | Bottom-sheet *(SCR-02, nguyên văn: "Sidebar trái (desktop) / bottom-sheet (mobile)")* | Như trên | 🔴 `OQ-018` | + +*Ghi chú:* bảng `Bảng → Card` chuyển đổi theo breakpoint (mô tả ở template gốc) áp dụng cho các +màn hình **quản trị** (Seller/Admin, VD SCR-18, SCR-19, SCR-23) dùng bảng dữ liệu thật — +ngoài phạm vi ưu tiên Guest/Customer của lần chạy này. + +## 2. Điều hướng + +| Câu hỏi | Quy ước | +|---|---| +| Quay lại từ màn hình chi tiết/form | Nút Back **và** breadcrumb — cả hai. *(Nguồn một phần: SCR-02 có breadcrumb "Trang chủ > Ngành hàng > Từ khoá"; nút Back không nói rõ trong SAD — BA đề xuất theo thực hành chung, PO/Dev FE xác nhận ở G3)* | +| Quay lại có giữ trạng thái danh sách (trang, bộ lọc, sắp xếp)? | ✅ Giữ, qua query string — BA đề xuất (SAD không nói), không mâu thuẫn gì đã có | +| Vào bằng URL trực tiếp với id không tồn tại | Trang trạng thái "Không tìm thấy" + nút về danh sách. *(Nguồn: SCR-03 error = "Sản phẩm không tồn tại/đã bị gỡ" + link quay lại danh mục)* | +| Vào bằng URL trực tiếp không có quyền | Trang "Không có quyền" + nút về trang chủ; **không** lộ tên bản ghi — BA đề xuất theo W7, chưa có ví dụ cụ thể trong SAD §7.1.1–7.1.2 nhưng nhất quán với RBAC §4 (`RBAC_CartCheckout_v1.0.md`, che PII) | +| Rời màn hình khi form đang dở | Modal xác nhận "Rời trang? Thay đổi chưa lưu sẽ mất." — BA đề xuất (SAD không nói) | +| Menu với chức năng không có quyền | ❌ Ẩn (W7) | +| Mở chi tiết | Cùng tab, đổi URL. *(Nguồn: luồng 7.2.1 "Tìm kiếm/duyệt danh mục (SCR-02, SCR-03)" mô tả điều hướng tuần tự trong cùng phiên, không có nhắc mở tab mới)* | + +## 3. Danh sách + +| | | +|---|---| +| **Kiểu phân trang** | 🔴 Chưa chốt — SCR-02 nêu cả "phân trang **hoặc** infinite-scroll", chưa chọn 1 → `OQ-019` | +| **Số dòng mỗi trang** | 🔴 Chưa chốt → `OQ-019` | +| **Sắp xếp mặc định** | 🔴 Chưa chốt — SCR-02 liệt kê tuỳ chọn "giá tăng/giảm, mới nhất, bán chạy" nhưng không nói mặc định là gì → `OQ-019` | +| **Bấm vào dòng** | Bấm vào `ProductCard` → mở chi tiết sản phẩm (SCR-03). *(Nguồn: luồng 7.2.1)*. Không áp dụng khái niệm "dòng bảng" cho Guest/Customer — xem §1 | +| **Cột hành động** | N/A cho lưới `ProductCard` (Guest/Customer). Áp dụng cho bảng quản trị Seller/Admin (SCR-18, SCR-19, SCR-23…) — ngoài phạm vi ưu tiên lần này | +| **Chọn nhiều dòng** | Riêng SCR-04 (Giỏ hàng): checkbox chọn/bỏ chọn **từng `CartItem` hoặc cả nhóm seller** để tính tạm tính — đây là chọn-để-tính-tổng, **không phải** thanh hành động hàng loạt kiểu xoá/duyệt. *(Nguồn: SCR-04)* | +| **Tìm kiếm** | Autocomplete, tối thiểu 1 ký tự trước khi gợi ý; không cho submit tìm kiếm rỗng. *(Nguồn: SCR-01 validation)*. Độ trễ debounce (ms) 🔴 chưa chốt → `OQ-024` | +| **Bộ lọc** | Thanh ngang trên bảng (desktop) · nút "Lọc" mở bottom-sheet (mobile) — tổng hợp từ SCR-02: "Sidebar trái (desktop) / bottom-sheet (mobile): bộ lọc — ngành hàng, khoảng giá, seller, rating, tình trạng còn hàng" *(SAD gọi là sidebar chứ không phải "thanh ngang", đã điều chỉnh nhãn cho khớp — nội dung bộ lọc giữ nguyên theo SAD)* | +| **Cột trên mobile** | N/A — Guest/Customer dùng `ProductCard`/`CartItem` xuyên suốt mọi breakpoint, không có khái niệm "cột bảng → card" (đã là card từ đầu) | + +## 4. Form + +| | | +|---|---| +| **Vị trí nút** | Lưu/CTA chính (nút chính) **bên phải**, Huỷ (nút phụ) bên trái nút chính — BA đề xuất, SAD không mô tả vị trí nút cụ thể, không mâu thuẫn với các CTA đã liệt kê (VD SCR-05 "Tiếp tục đến thanh toán", SCR-06 "Xác nhận thanh toán") | +| **Đánh dấu bắt buộc** | Dấu `*` màu cảnh báo sau nhãn — BA đề xuất (SAD không mô tả) | +| **Thời điểm validate** | Khi rời field (blur) **và** khi bấm nút chính — BA đề xuất, nhất quán với các validation liệt kê theo từng SCR (VD SCR-08 email đúng định dạng, SCR-09 SĐT đúng định dạng VN) | +| **Vị trí message lỗi** | Ngay dưới field, thay chỗ hint; field viền cảnh báo — BA đề xuất, khớp với mô tả "thông báo inline" xuất hiện nhiều nơi (SCR-05 coupon không hợp lệ, SCR-18 xung đột SKU) | +| **Lỗi nhiều field** | Focus vào field lỗi đầu tiên, cuộn tới nó — BA đề xuất (SAD không mô tả cơ chế UI chi tiết) | +| **Lỗi từ server không gắn field** | Banner đầu form — BA đề xuất, khớp mẫu "banner lỗi" đã dùng ở SCR-01 | +| **Sau lỗi mạng/5xx** | 🔴 **Giữ nguyên dữ liệu đã nhập**, mở lại nút chính — quy tắc bắt buộc theo `writing-rules.md`, áp dụng toàn hệ thống trừ khi SRS ghi khác ở §12 | +| **Đang gửi** | Khoá toàn form, spinner trong nút chính, nhãn đổi "Đang xử lý…". *(Nguồn gần nhất: SCR-06 "Đang xử lý thanh toán..." — không cho thao tác khác, tránh double-submit; SCR-16 "spinner khi upload file (progress bar)")* | +| **Huỷ khi có thay đổi** | Modal xác nhận — BA đề xuất | +| **Nhãn field** | Trên field (không đặt cạnh trái) — BA đề xuất | +| **Nút CTA chính khi form chưa hợp lệ** | 🔴 Chưa chốt — SAD chỉ nói rõ ở cấp **wizard** (SCR-16: "wizard chặn 'Next' nếu bước hiện tại chưa hợp lệ"), không nói cho form thường (VD SCR-08 đăng ký, SCR-09 hồ sơ) → `OQ-021` | + +## 5. Phản hồi hệ thống + +| Loại | Dùng khi | Vị trí | Thời lượng | Có nút đóng | +|---|---|---|---|---| +| **Toast thành công** | Lưu/xoá thành công | 🔴 Chưa chốt — SAD §7 không dùng khái niệm "toast" ở bất kỳ SCR nào → `OQ-020` | 🔴 `OQ-020` | 🔴 `OQ-020` | +| **Toast lỗi** | Lỗi không gắn field, có thể thử lại | 🔴 `OQ-020` | 🔴 `OQ-020` | 🔴 `OQ-020` | +| **Modal xác nhận** | Hành động không hoàn tác được (huỷ đơn, xoá) | Giữa màn. *(Nguồn: SCR-10 "xác nhận (dialog) trước khi huỷ đơn")* | — | Nút chính bên **phải**; hành động nguy hiểm dùng nút nguy hiểm — BA đề xuất vị trí, hành vi "cần xác nhận" đã có nguồn | +| **Inline dưới field** | Lỗi validation | Dưới field | Tới khi sửa | — | +| **Banner trong vùng** | Lỗi tải một vùng dữ liệu | Trong vùng đó. *(Nguồn: SCR-01 "banner lỗi 'Không tải được dữ liệu, thử lại' + nút retry"; SCR-02, SCR-03, SCR-09, SCR-10, SCR-14, SCR-15 dùng mẫu "lỗi tải + retry" tương tự)* | Tới khi thử lại | Nút Thử lại | +| **Trang trạng thái** | 404 / 403 / lỗi toàn trang | Toàn trang. *(Nguồn: SCR-03 "Sản phẩm không tồn tại/đã bị gỡ" + link quay lại danh mục)* | — | Nút về danh sách/trang chủ | + +## 6. Trạng thái chuẩn + +| Trạng thái | Hiển thị | Text mặc định (VI) | Text (EN) | Nút | +|---|---|---|---|---| +| Đang tải danh sách | Skeleton lưới/bảng. *(Nguồn: dùng ở hầu hết SCR-01…SCR-15, VD "loading = skeleton lưới sản phẩm/banner")* | — | — | — | +| Đang tải chi tiết/form | Skeleton theo bố cục. *(Nguồn: SCR-03 "loading = skeleton toàn trang")* | — | — | — | +| Đang tải cục bộ (tính lại phí ship/khuyến mãi) | Spinner nhỏ tại chỗ. *(Nguồn: SCR-05 "loading = tính lại phí vận chuyển/khuyến mãi khi thay đổi địa chỉ (spinner cục bộ)")* | — | — | — | +| **Rỗng — chưa có dữ liệu nào** | Minh hoạ + câu dẫn + nút chính | "Chưa có \<đối tượng\> nào." — mẫu quan sát được lặp lại nhiều nơi trong SAD (SCR-03 "Chưa có đánh giá nào", SCR-09 "Chưa có địa chỉ nào", SCR-14 "Chưa có giao dịch điểm thưởng nào", SCR-15 "Không có thông báo nào"). **Hai ngoại lệ đã có text riêng trong SAD, không theo mẫu chung** — giữ nguyên khi viết SRS cho đúng US: SCR-04 "Giỏ hàng trống", SCR-10 "Bạn chưa có đơn hàng nào" | 🔴 Chưa dịch chính thức — BA có thể đề xuất bản dịch EN khi viết SRS, ZH/KO/JA cần biên dịch chuyên nghiệp, không tự dịch → `OQ-023` | Tạo mới / CTA tương ứng (VD "Tiếp tục mua sắm" — SCR-04; "Tạo mới" — SCR-09) | +| **Rỗng — bộ lọc không khớp** | Câu dẫn + nút phụ | "Không tìm thấy \<đối tượng\> phù hợp với bộ lọc." — dựa trên SCR-02 "Không tìm thấy sản phẩm phù hợp" + gợi ý bỏ bớt bộ lọc | 🔴 `OQ-023` | Xoá lọc | +| Lỗi tải | Banner trong vùng | "Không tải được dữ liệu, thử lại." — nguyên văn SCR-01 | 🔴 `OQ-023` | Thử lại | +| Không có quyền | Trang trạng thái | "Bạn không có quyền truy cập nội dung này." — BA đề xuất (SAD không có ví dụ SCR cụ thể cho Guest/Customer, RBAC xử lý ở tầng khác) | 🔴 `OQ-023` | Về trang chủ | +| Không tìm thấy | Trang trạng thái | "Sản phẩm không tồn tại hoặc đã bị gỡ." (mẫu chung: "Không tìm thấy nội dung yêu cầu.") — nguồn SCR-03 | 🔴 `OQ-023` | Về danh sách | + +`SRS` §2.3.6 chỉ ghi **phần khác** với bảng này (vd: câu dẫn riêng cho đối tượng), còn lại tham chiếu. + +## 7. Ẩn · khoá · read-only *(quy tắc W7)* + +| Trạng thái | Trình bày | Bắt buộc kèm | +|---|---|---| +| `❌ ẩn` | Không render | — | +| `🔒 disable` | Mờ 45%, con trỏ mặc định | **Tooltip nêu lý do** khi hover/focus. *(Nguồn hành vi tương tự: SCR-03 "nút chuyển trạng thái 'Hết hàng', disabled" khi SKU hết hàng — SAD xác nhận có dùng disable, không cho chi tiết % mờ/tooltip, phần trình bày cụ thể là đề xuất BA)* | +| `👁 read-only` | Giá trị dạng text, không viền ô nhập, nhãn giữ nguyên. *(Nguồn: SCR-06 "tóm tắt đơn hàng (read-only, tham chiếu từ SCR-05)"; SCR-09 "email (read-only hoặc yêu cầu xác thực lại khi đổi)")* | — | + +## 8. Định dạng hiển thị + +*`SRS` §4.3 tham chiếu bảng này; chỉ ghi khác khi có dòng ở §12.* + +| Loại | Định dạng | Ví dụ | Ghi chú | +|---|---|---|---| +| Ngày | `dd/MM/yyyy` | 30/08/2026 | BA đề xuất theo chuẩn VN, SAD không cho ví dụ cụ thể | +| Ngày giờ | `dd/MM/yyyy HH:mm` | 30/08/2026 14:05 | **Múi giờ hiển thị:** đề xuất UTC+7 cố định (thị trường Việt Nam, giao dịch VND, tuân thủ NĐ 52/2013 — SAD §7.0) — 🔴 **chưa được Tech Lead/PO xác nhận chính thức là không cần hiển thị theo múi giờ địa phương của người dùng nước ngoài dùng EN/ZH/KO/JA**; coi là giả định của lần chạy này, cần xác nhận trước khi SRS dùng | +| Lưu trữ thời gian | ISO-8601 UTC | | Khớp `API` §1 (khi viết) | +| Số | `#,##0` | 1.234.567 | Dấu phân cách: theo chuẩn VN (dấu chấm phân nghìn) — BA đề xuất, SAD không cho ví dụ | +| Tiền (VND — giao dịch chính) | `#,##0 ₫` | 1.234.567 ₫ | Làm tròn: không làm tròn thêm ở cấp hiển thị (VND không có phần thập phân) — theo `BR-CART-09` (`BR_CartCheckout_v1.0.md`) | +| Giá quy đổi tham khảo (đa tiền tệ) | 🔴 Chưa chốt | | Nguồn tỷ giá, tần suất cập nhật, quy tắc làm tròn cho `CurrencyToggle`/`PriceDisplay` (FR-16/NFR-06) — SAD chỉ xác nhận đây là "giá quy đổi tham khảo", không phải giá giao dịch → `OQ-025` | +| Phần trăm | `0,0 %` | 12,5 % | BA đề xuất — dùng cho % hoa hồng (SCR-25), ngoài phạm vi ưu tiên Guest/Customer nhưng dùng chung định dạng | +| Rỗng / null | `—` | | Thống nhất toàn hệ thống — BA đề xuất | +| Số lớn (id, mã đơn) | Hiển thị nguyên văn chuỗi | `order_number`/`sub_order_number` — theo `BR_CartCheckout_v1.0.md` §4.1, đây là khoá nghiệp vụ dạng chuỗi, không phải số kỹ thuật để tính toán | Không format | + +## 9. Ngôn ngữ và giọng văn + +| | | +|---|---| +| **Ngôn ngữ hỗ trợ** | VI (mặc định) · EN · ZH · KO · JA — theo FR-15/NFR-06 (SAD §2.2, §7.0). Thiếu bản dịch ⇒ hiện **khoá** hay **VI**? 🔴 Chưa chốt → `OQ-023` | +| **Xưng hô** | 🔴 Chưa chốt — SAD §7 không đề cập giọng văn → `OQ-026` | +| **Thông điệp lỗi** | Nói **vì sao** và **làm gì tiếp**; không mã kỹ thuật; kết thúc bằng dấu chấm. *(Nguồn nhất quán với các ví dụ SAD: SCR-01 "Không tải được dữ liệu, thử lại", SCR-06 "thông báo lý do + nút 'Thử lại' hoặc 'Chọn phương thức khác'")* | +| **Nhãn nút** | Động từ, viết hoa chữ đầu — khớp các CTA đã liệt kê trong SAD: "Thêm vào giỏ", "Tiến hành Checkout", "Xác nhận thanh toán", "Tiếp tục mua sắm" | +| **Tiêu đề màn hình** | Danh từ — khớp SCR-04 "Giỏ hàng của bạn" (có xưng "bạn" — mâu thuẫn tiềm ẩn với `OQ-026` chưa chốt, cần thống nhất khi trả lời) | +| **Độ dài nhãn tối đa** | 🔴 Chưa chốt (ký tự) — SAD chỉ cảnh báo định tính "ZH/KO/JA cần rà soát độ dài chuỗi dịch có thể dài hơn, layout co giãn được" → `OQ-023` | +| **Khoá i18n** | `..` — vd `scr01.search.ph` — quy ước kỹ thuật do BA đề xuất, Dev FE áp dụng, không cần PO duyệt | + +## 10. Dãy mã lỗi + +| Dãy | Module / phạm vi | Số kế tiếp chưa dùng | Ai cấp | +|---|---|---|---| +| `E-CART-` | Giỏ hàng & Checkout (RQ-001…RQ-004) | `0007` — `E-CART-0001` đã dùng cho `BR-CART-02` (giữ tồn kho khi checkout, `BR_CartCheckout_v1.0.md` §2); `E-CART-0002`…`0006` đã dùng cho US-002/US-003 (`SRS_US002-003_v1.0.md` §4.1) | BA | + +*Các module khác (Catalog, Seller, Admin, Payout, Khuyến mãi/Loyalty…) chưa có `SRS`/`BR` viết +tới ở GĐ3 — sẽ đăng ký dãy mã khi module đó chạy `ba-3-specification`.* + +## 11. Từ vựng thành phần + +*`WF` §3.x.2 cột "Kiểu trình bày" chỉ dùng từ ở cột đầu. Cột thứ hai map sang design system khi có (🔴 `OQ-022` — design system chưa chọn, để trống).* + +| Kiểu trình bày | Component trong design system | Dùng khi | +|---|---|---| +| Nút chính | 🔴 `OQ-022` | Một hành động chính mỗi màn hình (VD "Tiến hành Checkout" — SCR-04) | +| Nút phụ | 🔴 `OQ-022` | Huỷ, hành động thứ cấp | +| Nút nguy hiểm | 🔴 `OQ-022` | Xoá, huỷ đơn — luôn kèm modal xác nhận (SCR-10) | +| Liên kết | 🔴 `OQ-022` | Điều hướng trong text (VD "Theo dõi đơn hàng" — SCR-07) | +| Ô nhập | 🔴 `OQ-022` | | +| Ô nhập số | 🔴 `OQ-022` | Số lượng sản phẩm (SCR-03, SCR-04) | +| Chọn 1 | 🔴 `OQ-022` | Phương thức thanh toán (SCR-06: "radio group") — ≤ 7 lựa chọn | +| Chọn nhiều | 🔴 `OQ-022` | Checkbox chọn `CartItem` (SCR-04) | +| Chọn ngày / khoảng ngày | 🔴 `OQ-022` | | +| Công tắc | 🔴 `OQ-022` | | +| Bảng | 🔴 `OQ-022` | Desktop — chủ yếu dùng ở màn hình quản trị Seller/Admin, ngoài ưu tiên lần này | +| Card | 🔴 `OQ-022` | `ProductCard` (SCR-01, SCR-02, SCR-03, SCR-12), `CartItem` (SCR-04) — dùng xuyên suốt mọi breakpoint cho Guest/Customer, không chỉ trên mobile | +| Badge trạng thái | 🔴 `OQ-022` | Trạng thái vòng đời — xem bảng ánh xạ chi tiết bên dưới | +| Tab | 🔴 `OQ-022` | Đăng nhập/Đăng ký (SCR-08); Thông tin cá nhân/Sổ địa chỉ (SCR-09) | +| Modal | 🔴 `OQ-022` | Xác nhận huỷ đơn (SCR-10) | +| Drawer | 🔴 `OQ-022` | | +| Bottom-sheet | 🔴 `OQ-022` | Bộ lọc trên mobile (SCR-02) | +| Toast | 🔴 `OQ-022` + `OQ-020` (vị trí/thời lượng chưa chốt) | §5 | +| Skeleton | 🔴 `OQ-022` | §6 | +| `LanguageSwitcher` | 🔴 `OQ-022` | Component riêng của dự án (FR-15) — cố định ở header, mọi màn hình | +| `CurrencyToggle` / `PriceDisplay` | 🔴 `OQ-022` | Component riêng của dự án (FR-16) — hiển thị giá VND + giá quy đổi tham khảo, mọi nơi có giá | + +### 11.1 Badge trạng thái — ánh xạ theo vòng đời (nguồn: `BR_CartCheckout_v1.0.md` §3) + +*Chỉ mô tả **nhãn hiển thị** và **nhóm ý nghĩa màu** (không có hex cụ thể — SAD §7.0 xác nhận +dự án không có brand guideline; hex/màu chính xác thuộc `OQ-022` khi chọn design system).* + +| Thực thể | Trạng thái kỹ thuật | Nhãn hiển thị (VI, đề xuất) | Nhóm ý nghĩa màu | Nguồn | +|---|---|---|---|---| +| `CART` | `active` | "Đang hoạt động" | Trung tính | `BR_CartCheckout_v1.0.md` §3 | +| `CART` | `converted` | "Đã chuyển thành đơn" | Thành công | nt | +| `CART` | `abandoned` | "Bỏ quên" | Trung tính/cảnh báo nhẹ | nt | +| `ORDER_SELLER` *(đoạn khởi tạo)* | `pending` | "Chờ thanh toán" | Cảnh báo | nt | +| `ORDER_SELLER` *(đoạn khởi tạo)* | `confirmed` | "Đã xác nhận" | Thành công | nt | +| `ORDER_SELLER` *(đoạn khởi tạo)* | `cancelled` | "Đã huỷ" | Lỗi/trung tính | nt | +| `PAYMENT` | `pending` | "Chờ xử lý" | Cảnh báo | nt | +| `PAYMENT` | `success` | "Thành công" | Thành công | nt | +| `PAYMENT` | `failed` | "Thất bại" | Lỗi | nt | + +🔴 **Chưa đầy đủ để SRS dùng trực tiếp:** vòng đời đầy đủ của `ORDER_SELLER` sau `confirmed` +(packed/shipped/delivered/returned…) thuộc module Quản lý đơn hàng (FR-08/FR-19), **ngoài +phạm vi** module Giỏ hàng & Checkout — SRS của module đó phải bổ sung nhãn cho các trạng thái +còn lại (khớp danh sách filter đã có ở SCR-10: "Chờ xác nhận, Đang xử lý, Đang giao, Đã giao, +Đã huỷ, Yêu cầu đổi trả" — **các nhãn này chưa được đối chiếu 1-1 với state machine `BR` ở GĐ2**, +cần rà khi viết SRS US-004 trở đi). `Payment.status` khi COD (ghi `success` ngay hay giữ +`pending`) **chưa chốt** — xem `OQ-013` (đã mở từ GĐ2, chưa đóng). + +## 12. Ngoại lệ đã duyệt + +*`SRS`/`WF` lệch quy ước ⇒ phải có dòng ở đây. Không có dòng ⇒ lệch là lỗi, không phải quyết định.* + +| # | Tài liệu | Mục lệch | Quy ước | Thực tế | Vì sao | Ai duyệt | Ngày | +|---|---|---|---|---|---|---|---| +| 1 | `SRS_US002-003_v1.0.md` §2.A.3.6, `WF_US002-003_v1.0.md` §3.1.3 | §6 Trạng thái chuẩn — "Rỗng, chưa có dữ liệu nào" | "Chưa có \<đối tượng\> nào." | "Giỏ hàng trống" + nút "Tiếp tục mua sắm" | Text nguyên văn đã có sẵn trong SAD §7.1.1 SCR-04 (nguồn duyệt sẵn), giữ nguyên để không tạo hai phiên bản câu chữ cho cùng một khái niệm | PO (thay Designer, `DEC-01`) | 2026-09-08 | +| 2 | `SRS_US002-003_v1.0.md` §2.A.3.1 (F01), `UICONV` §4 | §4 Form — "Vị trí nút Lưu... Thời điểm validate: khi rời field và khi bấm Lưu" | Không có nút "Lưu" riêng — mỗi lần đổi số lượng (F01) gửi `PATCH` ngay lập tức (auto-save) | Số lượng trong giỏ hàng là thao tác tần suất cao, chỉ một field; mẫu "inline edit" tránh người dùng phải nhớ bấm Lưu cho từng dòng trong danh sách nhiều dòng | PO (thay Designer, `DEC-01`) | 2026-09-08 | + +## 13. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | +|---|---|---|---|---| +| OQ-018 | Ngưỡng breakpoint theo px cho desktop/tablet/mobile-web, và grid layout (số cột, gutter px, max-width px) toàn site | Dev FE / Tech Lead | 2026-09-08 | §1 | +| OQ-019 | Kiểu phân trang, số dòng/trang, tiêu chí sắp xếp mặc định cho danh sách sản phẩm (SCR-02) và lịch sử đơn hàng (SCR-10) | PO, Dev FE | 2026-09-08 | §3 | +| OQ-020 | Vị trí và thời lượng hiển thị toast thông báo | PO, Dev FE | 2026-09-08 | §5, §11 | +| OQ-021 | Nút CTA chính khi form chưa hợp lệ: bấm được rồi hiện lỗi, hay khoá (disable)? | PO, Dev FE | 2026-09-08 | §4 | +| OQ-022 | Chọn design system cụ thể (Material Design hay Ant Design) | Tech Lead | 2026-09-08 | §0, §11 | +| OQ-023 | Ngôn ngữ thiếu bản dịch: khoá hay fallback VI? Độ dài nhãn tối đa (ký tự)? Bản dịch EN/ZH/KO/JA cho các text mặc định ở §6 | PO, Dev FE (và cần đơn vị biên dịch cho ZH/KO/JA) | 2026-09-08 | §6, §9 | +| OQ-024 | Độ trễ debounce (ms) cho gợi ý autocomplete tìm kiếm | Dev FE | 2026-09-08 | §3 | +| OQ-025 | Quy tắc quy đổi tiền tệ tham khảo: nguồn tỷ giá, tần suất cập nhật, làm tròn | PO, Tech Lead | 2026-09-08 | §8 | +| OQ-026 | Xưng hô trong toàn bộ text hệ thống ("bạn" hay không xưng hô) | PO | 2026-09-08 | §9 | +| OQ-027 | 🔴 Ngoại lệ gate G2 chưa ký — ảnh hưởng tới §11 (Guest checkout) nếu `BACKLOG`/`BR` đổi khi ký G2 thật | PO, Tech Lead | 2026-09-08 | Baseline `UICONV` | + +--- + +## Tự chấm + +| # | Tiêu chí | ☐/✅ | +|---|---|---| +| 1 | Mọi ô "chọn một" đã chọn, không còn dấu `/` giữa các phương án | ☐ — 10 ô còn mở, mỗi ô có `OQ` tương ứng (§1, §3, §4, §5, §9), **không tự chọn** theo đúng chỉ đạo | +| 2 | §6 có hai trạng thái rỗng **trông khác nhau** | ✅ — "Rỗng — chưa có dữ liệu nào" (minh hoạ + nút chính, VD "Tạo mới"/"Tiếp tục mua sắm") khác "Rỗng — bộ lọc không khớp" (không minh hoạ, nút phụ "Xoá lọc"), theo đúng mẫu SCR-02 | +| 3 | §8 có múi giờ hiển thị và quy tắc làm tròn tiền | 🟡 — múi giờ đề xuất UTC+7 nhưng **chưa xác nhận chính thức** (đánh dấu 🔴 trong bảng); làm tròn VND đã có (không làm tròn thêm); làm tròn tiền quy đổi tham khảo **chưa chốt** (`OQ-025`) | +| 4 | §11 mọi kiểu trình bày dùng trong `WF` hiện có đều có dòng | ✅ — `WF_US002-003_v1.0.md` (SCR-04) chỉ dùng: Nhãn, Nút chính, Nút phụ, Nút nguy hiểm, Ô nhập số, Card, Modal, Badge trạng thái — cả 8 kiểu đều đã có dòng ở §11 | +| 5 | Có chữ ký Designer (hoặc ghi rõ dự án không có Designer ⇒ PO ký thay, `DEC-nn`) | ✅ — dự án không có Designer, PO ký thay theo `DEC-01` (đã sửa nội dung ở v1.2, giữ nguyên phần này); **chữ ký thật chưa có** — `Approved by` vẫn để trống, chờ PO ký ở G3 | diff --git a/ba-output/e-commerce/01-discovery/BRIEF_CartCheckout_v1.0.md b/ba-output/e-commerce/01-discovery/BRIEF_CartCheckout_v1.0.md new file mode 100644 index 0000000..87f6e60 --- /dev/null +++ b/ba-output/e-commerce/01-discovery/BRIEF_CartCheckout_v1.0.md @@ -0,0 +1,278 @@ +# BRIEF — Module Giỏ hàng & Checkout (e-commerce) + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-1-discovery) | +| **Status** | 🟡 Draft | +| **Approved by** | — | +| **Profile** | screen · greenfield · standard (xem `00-index/PROFILE_e-commerce.md`) | +| **Source** | `e-commerce/docs/00-project-brief.md` · `e-commerce/docs/sections/01-tong-quan.md` · `e-commerce/docs/sections/02-phan-tich-yeu-cau.md` (FR-05, FR-06, FR-07, NFR-01, NFR-03, NFR-05) · `e-commerce/docs/sections/07-giao-dien.md` (SCR-04…SCR-07, chỉ dùng làm bối cảnh) · `STAKEHOLDER_CartCheckout_v1.0.md` · `ELICITATION_CartCheckout_2026-09-08.md` · `RISK_CartCheckout_v1.0.md` | +| **Scope** | Module Giỏ hàng & Checkout — FR-05 (Giỏ hàng đa seller), FR-06 (Checkout & tách đơn theo seller), FR-07 (Thanh toán VNPay/Momo/COD) — dự án e-commerce (marketplace). **Không** bao gồm toàn sàn. | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | CR | +|---|---|---|---|---| +| 1.0 | 2026-09-08 | BA (qua skill ba-1-discovery) | Bản đầu | — | + +--- + +## 1. Tóm tắt cho người quyết định + +Sàn marketplace đa seller sắp xây (dự án e-commerce) cần một luồng giỏ hàng–checkout–thanh +toán xử lý đúng đặc thù đa người bán: một khách mua từ nhiều seller trong một lần thanh toán, +hệ thống tự tách thành các đơn con theo seller, thanh toán qua VNPay/Momo/COD. Đây là luồng +giao dịch lõi — không có nó, sàn không ghi nhận được doanh thu và seller không nhận được đơn. +Tài liệu này chốt phạm vi, mục tiêu đo được và bốn yêu cầu mức nghiệp vụ (`RQ-001`…`RQ-004`) +cho module này; còn nhiều `OQ` cần PO/Tech Lead trả lời trước khi ký G1 chính thức (tên thật +stakeholder, KPI baseline, chính sách giới hạn COD). + +--- + +## 2. Bối cảnh + +Dự án e-commerce là **greenfield** — chưa có hệ thống nào đang chạy để thay thế (xem +`00-index/PROFILE_e-commerce.md`). Vì vậy không có "cách làm thủ công hiện tại" của chính sàn +này để mô tả; bối cảnh dưới đây là **quyết định mô hình kinh doanh đã chốt**, không phải số đo +vận hành thật. + +| Thông tin hiện trạng | Giá trị | Nguồn | +|---|---|---| +| Số giao dịch/ngày (dự kiến khi vận hành) | Chưa vận hành — quy mô mục tiêu "lớn": hàng trăm nghìn SKU, hàng trăm nghìn–hàng triệu user đăng ký, cao điểm hàng nghìn–chục nghìn concurrent user mùa flash sale | `00-project-brief.md` mục 3 | +| Số người thao tác checkout đồng thời | N/A — chưa vận hành | — | +| Thời gian xử lý trung bình | N/A — chưa vận hành; mục tiêu latency đề xuất ở NFR-01 (< 2s catalog/search, < 3s checkout) là **giả định mặc định đã chốt trong brief**, chưa phải SLA hợp đồng thật | `sections/02-phan-tich-yeu-cau.md` NFR-01, ghi chú cuối §2.2 | +| Tỷ lệ sai sót hiện tại | N/A — chưa vận hành, không có hệ thống cũ | — | + +## 3. Phát biểu bài toán + +> **Vấn đề:** Sàn marketplace đa seller đã cam kết mô hình "khách mua từ nhiều seller trong một +> trải nghiệm thống nhất" (mục tiêu dự án, `sections/01-tong-quan.md` §1.1) nhưng **chưa có** +> luồng giỏ hàng–checkout–thanh toán nào xử lý được việc: (1) gộp sản phẩm nhiều seller vào một +> giỏ, (2) tách thành đơn con đúng theo từng seller khi khách xác nhận mua, (3) thu tiền qua +> nhiều kênh thanh toán phổ biến tại Việt Nam (VNPay, Momo, COD) mà không lưu thông tin thẻ. +> Thiếu luồng này, sàn không thể ra mắt MVP, seller không có cách nào nhận đơn hàng, và không +> có dữ liệu giao dịch để tính hoa hồng/payout ở các module khác. + +❌ Không viết giải pháp ở đây — mục này giữ đúng quy tắc, không nêu tên màn hình/nút cụ thể. + +**Bằng chứng của vấn đề:** + +| # | Bằng chứng | Nguồn | Loại | +|---|---|---|---| +| 1 | Mô hình kinh doanh đã xác nhận là marketplace đa seller (không phải single-vendor) — kéo theo yêu cầu bắt buộc về giỏ hàng/checkout đa seller | `00-project-brief.md` vòng 1, câu hỏi 1 | Sự thật (quyết định đã chốt) | +| 2 | FR-05 (Giỏ hàng đa người bán), FR-06 (Checkout & tách đơn theo seller), FR-07 (Thanh toán) đều được xếp **Must** trong bảng yêu cầu đã duyệt | `sections/02-phan-tich-yeu-cau.md` §2.1 | Sự thật | +| 3 | Guest (khách vãng lai) được xác nhận cho phép checkout không cần tài khoản | `sections/01-tong-quan.md` §1.2 | Sự thật | + +**Điều gì xảy ra nếu không làm gì cả?** Sàn không ra mắt được MVP marketplace — toàn bộ các +module phụ thuộc (quản lý đơn hàng, hoa hồng, payout, đánh giá sau mua) đều cần dữ liệu đơn +hàng sinh ra từ checkout. Đây là điều kiện tiên quyết (blocker), không phải một cải tiến. + +## 4. Mục tiêu kinh doanh & KPI + +🔴 **Cả hai GOAL dưới đây chưa có baseline số thật** vì dự án greenfield (chưa vận hành). Theo +quy tắc, không bỏ trống — ghi `OQ` kèm đề xuất cách đo baseline. + +| ID | Mục tiêu | Baseline hiện tại | Mục tiêu | Cách đo | Ai đo | Tần suất | +|---|---|---|---|---|---|---| +| GOAL-01 | Giảm tỷ lệ bỏ giỏ hàng ở bước checkout đối với giỏ hàng có ≥2 seller (rủi ro cao hơn giỏ 1 seller do phí ship gộp — xem `RISK-04`) | ❓ Chưa có — dự án chưa vận hành (`OQ-007`). Đề xuất cách đo: theo dõi tỷ lệ hoàn tất checkout trong 4–6 tuần đầu soft-launch, tách riêng theo số seller trong giỏ | PO xác nhận sau khi có số đo soft-launch, đề xuất ban đầu ≤ tỷ lệ bỏ giỏ của giỏ 1 seller + 10 điểm phần trăm | (số phiên checkout hoàn tất) / (số phiên bắt đầu checkout), theo nhóm số seller trong giỏ | BA + PO, hàng tuần trong 6 tuần đầu | Hàng tuần (giai đoạn đầu) | +| GOAL-02 | Tỷ lệ thanh toán thành công trên tổng số phiên checkout đã chọn phương thức thanh toán | ❓ Chưa có — chưa vận hành (`OQ-007`). Đề xuất đo baseline bằng dữ liệu 4 tuần đầu sau go-live, tách riêng theo kênh VNPay/Momo/COD | PO xác nhận; đề xuất tham khảo ngành ≥ 90% cho ví điện tử, COD không tính "thất bại" theo nghĩa kỹ thuật mà theo tỷ lệ hoàn/từ chối nhận hàng (liên quan `RISK-01`) | (số giao dịch thanh toán thành công) / (số giao dịch đã khởi tạo), theo kênh | BA + Kế toán đối soát (STK-04), hàng tuần | Hàng tuần (giai đoạn đầu), sau đó hàng tháng | + +## 5. Phạm vi + +### 5.1 Trong phạm vi + +| # | Hạng mục | Vì sao cần | RQ liên quan | +|---|---|---|---| +| 1 | Giỏ hàng chứa sản phẩm từ nhiều seller khác nhau, nhóm hiển thị theo seller | Điều kiện tiên quyết của mô hình marketplace đa seller | RQ-001 | +| 2 | Checkout: thu thập địa chỉ giao hàng, tự động tách giỏ hàng thành các đơn con theo từng seller | Mỗi seller cần xử lý đơn độc lập, không lẫn với seller khác | RQ-002 | +| 3 | Thanh toán qua VNPay, Momo hoặc COD, không lưu thông tin thẻ trên hệ thống sàn | Đối tác thanh toán đã xác nhận; giảm phạm vi PCI-DSS (NFR-05) | RQ-003 | +| 4 | Guest checkout — mua hàng không cần tạo tài khoản trước | Đã xác nhận trong `sections/01-tong-quan.md` §1.2 | RQ-004 | + +### 5.2 Ngoài phạm vi *(quan trọng hơn mục 5.1)* + +| # | Hạng mục | Lý do loại | Xử lý ở đâu / khi nào | +|---|---|---|---| +| 1 | Áp mã khuyến mãi/coupon (FR-13) | Được giao ở một module khác (Khuyến mãi), dù xuất hiện trên cùng màn hình checkout theo bối cảnh UI ở `sections/07-giao-dien.md` SCR-05 | Module Khuyến mãi & Loyalty — cần PO xác nhận điểm nối, xem `OQ-004` | +| 2 | Dùng điểm thưởng loyalty khi checkout (FR-14) | Tương tự trên | Module Loyalty — `OQ-004` | +| 3 | Theo dõi/xử lý đơn hàng sau khi đã tạo (huỷ, đổi trả, khiếu nại — FR-08, FR-09, FR-25) | Là vòng đời đơn hàng sau checkout, không phải hành vi tạo đơn | GĐ1/GĐ2 của module Quản lý đơn hàng, chạy riêng | +| 4 | Xử lý tồn kho, đóng gói, cập nhật vận chuyển sau khi đơn được tạo (FR-26) | Thuộc vận hành kho, không phải luồng giỏ hàng/checkout | Module Vận hành đơn hàng, chạy riêng | +| 5 | KYC, cấu hình hoa hồng, payout cho seller (FR-17, FR-21, FR-22) | Không liên quan trực tiếp tới hành vi giỏ hàng/checkout của khách mua | Module Quản trị Seller & Tài chính, chạy riêng | +| 6 | Danh mục & tìm kiếm sản phẩm (FR-04) | Là bước trước giỏ hàng, đã có màn hình riêng (SCR-01…SCR-03) | Module Catalog & Tìm kiếm, chạy riêng | +| 7 | Nội dung/mẫu thông báo email/SMS xác nhận đơn hàng (FR-12) | Module này chỉ **kích hoạt** sự kiện gửi thông báo, không thiết kế nội dung/kênh gửi | Module Thông báo, chạy riêng — GĐ3 chỉ ghi rõ sự kiện trigger | + +### 5.3 Ranh giới hệ thống + +```mermaid +flowchart LR + GUEST(["👤 Guest"]) + CUS(["👤 Customer"]) + + subgraph PHAMVI["Trong phạm vi — Module Giỏ hàng & Checkout"] + CART["Giỏ hàng đa seller (FR-05)"] + CHK["Checkout & tách đơn theo seller (FR-06)"] + PAY["Thanh toán VNPay/Momo/COD (FR-07)"] + end + + CATALOG[["Catalog & Tìm kiếm (FR-04) — ngoài phạm vi"]] + PROMO[["Khuyến mãi & Loyalty (FR-13/14) — ngoài phạm vi"]] + ORDER[["Quản lý đơn hàng sau checkout (FR-08/09) — ngoài phạm vi"]] + SELLERBIZ[["KYC / Hoa hồng / Payout seller (FR-17/21/22) — ngoài phạm vi"]] + NOTI[["Thông báo email/SMS (FR-12) — ngoài phạm vi"]] + VNPAY[["VNPay"]] + MOMO[["Momo"]] + GHN[["GHN"]] + GHTK[["GHTK"]] + + GUEST --> CART + CUS --> CART + CATALOG --> CART + CART --> CHK + PROMO -.-> CHK + CHK --> GHN + CHK --> GHTK + CHK --> PAY + PAY <--> VNPAY + PAY <--> MOMO + CHK --> ORDER + CHK --> SELLERBIZ + CHK --> NOTI +``` + +*Khung đôi `[[ ]]` = ngoài phạm vi module này (có thể trong phạm vi dự án e-commerce nói +chung, chạy ở module khác). Mũi tên hai chiều = trao đổi dữ liệu hai chiều với hệ thống ngoài.* + +| Hệ thống | Trong/Ngoài phạm vi | Dữ liệu trao đổi | Chiều | Đầu mối | +|---|---|---|---|---| +| VNPay | Ngoài — tích hợp | Yêu cầu thanh toán, xác nhận kết quả (webhook — `ASM-01` chưa xác minh) | Hai chiều | Chưa xác định | +| Momo | Ngoài — tích hợp | Tương tự VNPay | Hai chiều | Chưa xác định | +| GHN | Ngoài — tích hợp | Địa chỉ giao hàng → phí ship/thời gian giao ước tính (`ASM-02` chưa xác minh) | Hai chiều | Chưa xác định | +| GHTK | Ngoài — tích hợp | Tương tự GHN | Hai chiều | Chưa xác định | +| Catalog & Tìm kiếm | Ngoài phạm vi module, trong phạm vi dự án | Sản phẩm, giá, tồn kho → giỏ hàng | Một chiều vào giỏ hàng | STK-06 (Tech Lead) | +| Khuyến mãi & Loyalty | Ngoài phạm vi module — điểm nối cần xác nhận (`OQ-004`) | Mã coupon/điểm thưởng → giảm giá áp vào checkout | Một chiều vào checkout | STK-01 (PO sàn) | +| Quản lý đơn hàng sau checkout | Ngoài phạm vi module, trong phạm vi dự án | Đơn con đã tạo → module quản lý đơn hàng | Một chiều ra khỏi module | STK-05 (Trưởng vận hành) | +| KYC/Hoa hồng/Payout seller | Ngoài phạm vi module | Dữ liệu giao dịch đã thanh toán → tính hoa hồng/payout | Một chiều ra khỏi module | STK-04 (Kế toán đối soát) | +| Thông báo email/SMS | Ngoài phạm vi module | Sự kiện "đơn đã tạo/thanh toán thành công" → trigger gửi | Một chiều ra khỏi module | Chưa xác định | + +## 6. Yêu cầu mức nghiệp vụ + +| ID | Phát biểu yêu cầu | Nguồn (STK + ngày) | MoSCoW | GOAL | Giải pháp khách gợi ý | +|---|---|---|---|---|---| +| RQ-001 | Customer/Guest phải mua được sản phẩm từ nhiều seller khác nhau trong một giỏ hàng và hoàn tất bằng một lần checkout, thay vì phải đặt hàng riêng lẻ với từng seller trên các trang/luồng khác nhau. | STK-01 (PO sàn), qua `00-project-brief.md` vòng 1 (2026, vòng 1 không ghi ngày cụ thể) | Must | GOAL-01 | "Giỏ hàng đa seller" | +| RQ-002 | Hệ thống phải tự động tách một giỏ hàng đa seller thành các đơn con riêng theo từng seller ngay khi Customer/Guest xác nhận đặt hàng, để mỗi seller xử lý đơn của mình độc lập mà không thấy dữ liệu của seller khác. | STK-01 (PO sàn), STK-03 (Seller đại diện — chưa phỏng vấn trực tiếp), qua `00-project-brief.md` mục 2 & `sections/02-phan-tich-yeu-cau.md` FR-06 | Must | GOAL-01 | "tách đơn theo seller" | +| RQ-003 | Customer/Guest phải thanh toán được bằng VNPay, Momo hoặc COD mà hệ thống sàn không lưu trữ thông tin thẻ thanh toán, để giảm phạm vi tuân thủ PCI-DSS. | STK-01 (PO sàn), STK-06 (Tech Lead — chưa xác nhận khả thi), qua `00-project-brief.md` vòng 1 & `sections/02-phan-tich-yeu-cau.md` NFR-05 | Must | GOAL-02 | "Thanh toán (VNPay/Momo + COD)" | +| RQ-004 | Guest (khách vãng lai) phải checkout hoàn tất được mà không cần tạo tài khoản trước, để không mất khách hàng tiềm năng ở bước bắt buộc đăng ký. | STK-01 (PO sàn), qua `sections/01-tong-quan.md` §1.2 | Must | GOAL-01 | "guest checkout" | + +🔴 **Kiểm tra phân bổ MoSCoW:** cả 4/4 RQ đều Must = 100% > ngưỡng 60%. Theo quy tắc, đây là +dấu hiệu "chưa phân loại thật" và cần hỏi PO câu "nếu chỉ kịp một nửa module này thì cắt cái +nào". Trong trường hợp này, mức Must khớp với xếp hạng đã có sẵn ở `FR-05/06/07` trong tài +liệu phân tích yêu cầu đã duyệt (`sections/02-phan-tich-yeu-cau.md`), với lý do hợp lý là cả 4 +RQ đều thuộc luồng giao dịch lõi không thể MVP thiếu. Tuy vậy, **BA chưa tự ý coi đây là đã +chốt** — ghi `OQ-008` để PO xác nhận lại đúng theo quy trình BA-1, không suy diễn thay PO. + +| MoSCoW | Nghĩa chính xác | +|---|---| +| **Must** | Không có thì bản phát hành này vô nghĩa | +| **Should** | Quan trọng, nhưng thiếu vẫn dùng được, có cách làm thủ công tạm | +| **Could** | Có thì tốt, cắt đầu tiên khi thiếu thời gian | +| **Won't (this time)** | Đã bàn và thống nhất **không** làm lần này | + +## 7. Ràng buộc + +| Loại | Nội dung | Nguồn | Ảnh hưởng | +|---|---|---|---| +| Thời gian | Ngân sách/thời gian dự án chưa xác định chính thức; giả định lộ trình MVP tiêu chuẩn ~9–12 tháng cho toàn sàn | `00-project-brief.md` mục 5, giả định #7 | Có thể cần cắt phạm vi module nếu timeline thực tế ngắn hơn | +| Ngân sách / nguồn lực | Chưa xác định | `00-project-brief.md` mục 6 | — | +| Công nghệ | Triển khai trên AWS; không ràng buộc tech stack cụ thể cho module này | `sections/01-tong-quan.md` §1.5 | Kiến trúc chi tiết thuộc GĐ2/Tech Lead | +| Pháp lý / tuân thủ | NĐ52/85 (thông báo website TMĐT), NĐ13/2023 (bảo vệ dữ liệu cá nhân — địa chỉ/SĐT trong đơn hàng), PCI-DSS phạm vi giảm (không lưu thẻ) | `sections/01-tong-quan.md` §1.5, NFR-05 | Cần đại diện Pháp chế xác nhận (chưa có — `OQ-003`); ảnh hưởng RQ-003, RISK-03 | +| Tổ chức / quy trình | Không có hệ thống cũ, không có seller/khách hàng thật để tham chiếu quy trình — mọi giả định phải xác minh trước GĐ2/GĐ3 | `00-project-brief.md` mục 3, mục 6 | Số lượng `ASM` cao hơn bình thường cho một dự án brownfield | + +## 8. Giả định và rủi ro + +*Chi tiết đầy đủ ở `RISK_CartCheckout_v1.0.md`. Tóm tắt các mục ảnh hưởng trực tiếp tới phạm +vi module này:* + +| ID | Nội dung | Nếu sai thì sao | +|---|---|---| +| ASM-01 | VNPay/Momo hỗ trợ webhook xác nhận thanh toán gần thời gian thực | Phải đổi cơ chế xác nhận đơn hàng ở GĐ3, ảnh hưởng NFR-01 | +| ASM-02 | GHN/GHTK cung cấp API tính phí ship/kiểm tra vùng phục vụ tại checkout | Không hiển thị được phí/thời gian giao theo seller lúc checkout | +| ASM-05 | COD không giới hạn giá trị đơn ở MVP | Thiếu một business rule quan trọng, có thể lộ ở UAT dưới dạng rủi ro tài chính | +| RISK-01 | Bùng đơn COD một phần khi giỏ đa seller bị tách nhiều đơn con | Tổn thất phí vận chuyển hoàn hàng cho seller, tranh chấp seller–sàn | +| RISK-02 | Webhook thanh toán trễ/lỗi khiến đơn kẹt "Chờ thanh toán" dù đã thu tiền | Khiếu nại CSKH, sai lệch đối soát | +| RISK-03 | Chưa có đại diện Pháp chế/Bảo mật rà soát việc chia sẻ PII cho seller | Rủi ro vi phạm NĐ13/2023 khi go-live | + +## 9. Tiêu chí thành công của giai đoạn + +- [ ] PO sàn xác nhận đúng phát biểu bài toán ở mục 3 (không phải giải pháp) +- [ ] PO sàn chốt lại KPI/baseline ở mục 4 (dù chỉ là cam kết đo baseline trong X tuần đầu, không cần số thật ngay) +- [ ] PO sàn xác nhận điểm nối với module Khuyến mãi/Loyalty (`OQ-004`) và ranh giới ngoài phạm vi ở mục 5.2 +- [ ] Tech Lead xác nhận sơ bộ tính khả thi của ASM-01, ASM-02 (không cần xác minh đầy đủ ở G1, nhưng phải biết là rủi ro) +- [ ] RISK-01 (bùng COD) có người chịu trách nhiệm thật và hướng xử lý (chọn 1 trong 2 phương án BA đề xuất, hoặc phương án khác) +- [ ] Có người đại diện Pháp chế/Bảo mật được chỉ định (`OQ-003`), dù việc rà soát chi tiết có thể làm ở GĐ2 + +## 10. Open Questions + +*Tổng hợp từ mọi artifact của lần chạy này. Sổ toàn dự án: `00-index/OQ_e-commerce.md`.* + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Phương án BA đề xuất | +|---|---|---|---|---|---| +| OQ-001 | Tên thật + đầu mối liên lạc của STK-01…STK-06 là gì? | Điều phối dự án / PO | 2026-09-08 | Ký G1 thật | Dùng vai trò tạm để chạy tiếp; phải có tên thật trước khi coi G1 là ký hợp lệ | +| OQ-002 | Mức Quan tâm × Ảnh hưởng ở `STAKEHOLDER` mục 2 là đánh giá của BA — từng STK có đồng ý không? | STK-01…STK-06 | 2026-09-08 | Chiến lược tiếp cận | Giữ nguyên đánh giá ban đầu, điều chỉnh khi có phản hồi | +| OQ-003 | Ai là đại diện Pháp chế/Bảo mật cho dự án? Cần xác nhận phạm vi lưu/chia sẻ PII khi tách đơn theo seller. | PO sàn | 2026-09-08 | RISK-03, RQ-003 | Đề nghị PO chỉ định trước khi kết thúc GĐ2 | +| OQ-004 | Áp coupon (FR-13) và dùng điểm thưởng (FR-14) trong màn hình checkout có thuộc phạm vi module này không, hay là điểm tích hợp với module khác? | PO sàn | 2026-09-08 | Phạm vi mục 5.1/5.2, thiết kế màn hình checkout ở GĐ3 | Đề xuất: coi là điểm tích hợp (module Khuyến mãi/Loyalty sở hữu logic, module này chỉ hiển thị kết quả) — PO quyết | +| OQ-005 | Cần tổ chức phỏng vấn thật với Khách hàng đại diện (STK-02) và Seller đại diện (STK-03) — ai làm đầu mối sắp xếp? | Điều phối dự án / PO sàn | 2026-09-08 | Chất lượng RQ, phát hiện ngoại lệ thực tế | Đề nghị lên lịch trong tuần đầu GĐ2 | +| OQ-006 | Chính sách giới hạn giá trị đơn COD (nếu có) là gì? | PO sàn, Kế toán đối soát | 2026-09-08 | ASM-05, RISK-01, `BR` ở GĐ2 | BA đề xuất 2 phương án ở RISK-01, PO chọn | +| OQ-007 | Baseline thật cho GOAL-01 (tỷ lệ bỏ giỏ hàng) và GOAL-02 (tỷ lệ thanh toán thành công) là bao nhiêu? | PO sàn | 2026-09-08 | Đo lường hiệu quả ở GĐ5 | Đo trong 4–6 tuần đầu soft-launch theo cách đề xuất ở mục 4 | +| OQ-008 | Xác nhận lại: cả 4 RQ của module này đều Must — nếu chỉ kịp một nửa thời gian, PO sẽ cắt cái nào? | PO sàn | 2026-09-08 | Ưu tiên hoá ở GĐ2 (`BACKLOG`) | Đề xuất giữ nguyên cả 4 vì đều thuộc luồng giao dịch lõi, nhưng đây là đề xuất — PO quyết | + +## 11. Ngoài phạm vi tài liệu này + +- Thiết kế màn hình chi tiết (field, validation, message lỗi) → GĐ3, `SRS` +- Quy trình AS-IS/TO-BE chi tiết từng bước, business rule đầy đủ (VD công thức tính phí ship gộp) → GĐ2, `PROCESS`/`BR` +- Ước lượng công sức, lịch trình → PM +- Thiết kế API/kiến trúc tích hợp VNPay/Momo/GHN/GHTK → GĐ2/GĐ3, Tech Lead +- Nội dung/mẫu email/SMS thông báo đơn hàng → module Thông báo (FR-12), ngoài phạm vi module này + +--- + +## Tự chấm + +**Gate G1** *(chấm ở mức RIGOR = standard — áp đúng checklist §2 của `workflow.md`, không bớt/thêm)* + +| # | Tiêu chí | ☐/✅ | Ghi chú | +|---|---|---|---| +| 1 | BRIEF có bối cảnh, phát biểu bài toán, phạm vi in/out, GOAL kèm KPI | ✅ | Có đủ; GOAL chưa có baseline số thật (greenfield) nhưng đã ghi `OQ-007` + đề xuất cách đo, đúng quy tắc "không bỏ trống" | +| 2 | STAKEHOLDER đủ 4 nhóm, có tên thật | ☐ | Đủ 4 nhóm (Quyết định/Sử dụng/Bị ảnh hưởng/Cung cấp thông tin) nhưng **chưa có tên thật** cho bất kỳ ai — chỉ có vai trò, chờ `OQ-001`. Thiếu hẳn đại diện Pháp chế/Bảo mật (`OQ-003`) | +| 3 | ELICITATION có ≥1 buổi với nhóm quyết định và nhóm sử dụng | ☐ | Có bản tổng hợp có nguồn (từ brief 3 vòng), nhưng **không phải buổi làm việc trực tiếp** với STK-02 (Sử dụng) riêng cho module này — xem `ELICITATION` mục 0 và `OQ-005` | +| 4 | RQ có MoSCoW, truy về được stakeholder cụ thể | ✅ (có lưu ý) | 4/4 RQ có MoSCoW + nguồn, nhưng nguồn là brief cấp dự án (qua STK-01) chứ chưa phải phỏng vấn riêng module; 100% Must đã ghi nhận và tạo `OQ-008` theo đúng quy tắc thay vì tự quyết | +| 5 | RISK/ASM đã ghi, rủi ro mức cao có người chịu trách nhiệm | ☐ | Đã ghi đủ 6 ASM + 4 RISK (3 mức 🔴); nhưng người chịu trách nhiệm mới là **vai trò**, chưa có tên thật (`OQ-001`), và RISK-03 chưa có người chịu trách nhiệm nào (chưa có đại diện Pháp chế) | +| 6 | KPI có baseline | ☐ | Cả 2 GOAL đều baseline = ❓ (đúng vì greenfield), đã đề xuất cách đo — chưa phải "có" baseline thật | + +**Kết luận tự chấm:** G1 **chưa đủ điều kiện ký chính thức** theo đúng nghĩa checklist — +3/6 tiêu chí còn ☐ do thiếu tên thật stakeholder, thiếu buổi làm việc trực tiếp, và KPI chưa +có baseline số. Đây là kết quả **đúng như thiết kế của GĐ1 chạy chế độ `go` không phỏng vấn +thật**: sản phẩm là một bộ khung đầy đủ cấu trúc + danh sách việc cụ thể cần làm trước khi PO +ký thật. Không tự đánh ✅ cho có. + +**Quy tắc viết W1–W13** + +| W1 | W2 | W3 | W4 | W5 | W6 | W7 | W8 | W9 | W10 | W11 | W12 | W13 | +|---|---|---|---|---|---|---|---|---|---|---|---|---| +| ✅ | ✅ | ✅ | N/A (GĐ1 chưa có luồng lỗi màn hình) | N/A (GĐ1 chưa có text hiển thị) | N/A (GĐ1 chưa có trạng thái thực thể) | N/A (GĐ1 chưa có field/nút) | ✅ | ✅ | ✅ | ✅ | N/A (GĐ1 không có hình wireframe) | ✅ | ✅ | + +Ghi chú W2: đã quét cụm từ mơ hồ (`nhanh|mượt|thân thiện|v\.v|phù hợp|tương ứng|nên |có thể `) +trên toàn bộ 4 file GĐ1 — **~15 dòng khớp**, không phải 0. Đã soát lại từng dòng: +- Phần lớn nằm trong **mô tả rủi ro** (`RISK_CartCheckout_v1.0.md` RISK-01…04), dùng đúng công + thức bắt buộc của template rủi ro *"có thể xảy ra , dẫn tới "* — + đây là cú pháp chuẩn của `risk-register.md`, không phải một phát biểu yêu cầu/NFR mơ hồ. +- Một số nằm trong **giả định `ASM`** đang chờ xác minh (VD "đồng bộ đủ nhanh" ở `ASM-06`) — + đây là hạn chế thật, chưa xác minh xong nên chưa thể quy về con số cụ thể; đã gắn `ASM-06` + và lịch xác minh trước GĐ3, không để trôi thành spec chính thức còn mơ hồ. +- Một số nằm trong **trích dẫn/diễn giải nguồn** (F1 ở `ELICITATION`, ghi chú phạm vi ở + `BRIEF` §5.3, §9) — mô tả khả năng/phạm vi bằng ngôn ngữ tự nhiên, không phải NFR/AC cần đo + được ở GĐ1. +Không có dòng nào trong 4 file dùng các từ này để **né việc quyết định** trong một phát biểu +`RQ`/`GOAL` chính thức (mọi `RQ`/`GOAL` đều dùng "phải" và có phép đo). Đã quét +`TBD|TODO|\?\?\?` — 0 kết quả là placeholder chưa xử lý thật (chỉ có 1 dòng tự nhắc tới chuỗi +`TBD|TODO` trong chính câu giải thích quy tắc này); mọi chỗ chưa rõ đều dùng `OQ-nnn`. diff --git a/ba-output/e-commerce/01-discovery/ELICITATION_CartCheckout_2026-09-08.md b/ba-output/e-commerce/01-discovery/ELICITATION_CartCheckout_2026-09-08.md new file mode 100644 index 0000000..e26c573 --- /dev/null +++ b/ba-output/e-commerce/01-discovery/ELICITATION_CartCheckout_2026-09-08.md @@ -0,0 +1,123 @@ +# ELICITATION — Module Giỏ hàng & Checkout — 2026-09-08 + +| | | +|---|---| +| **Buổi** | Tổng hợp — không phải phỏng vấn trực tiếp (xem mục 0) | +| **Ngày giờ** | Không ghi trong nguồn theo mốc ngày/giờ cụ thể — nguồn ghi theo "vòng 1" và "vòng 3" của `docs/00-project-brief.md`; ngày tổng hợp lại: 2026-09-08 | +| **Hình thức** | Phân tích tài liệu đã chốt (không phải phỏng vấn 1-1/workshop/quan sát trực tiếp) | +| **Người tham gia** | Không có — nguồn là biên bản Q&A giữa điều phối dự án và "người dùng" (đóng vai PO) đã chốt qua 3 vòng, ghi trong `docs/00-project-brief.md` §4 | +| **Người ghi** | BA (qua skill ba-1-discovery) | +| **Đã gửi xác nhận** | ☐ Chưa — chưa có đầu mối thật để gửi (xem `OQ-001` ở `STAKEHOLDER_CartCheckout_v1.0.md`) | + +--- + +## 0. Ghi chú bắt buộc đọc trước + +Theo chỉ đạo của người duyệt: *"Không cần chạy phỏng vấn thật: ELICITATION ghi lại 3 vòng Q&A +trong brief như biên bản có nguồn."* File này **không phải** biên bản một buổi phỏng vấn/khảo +sát/workshop thật với STK-01…STK-06 của module Giỏ hàng & Checkout. Nó là bản trích lọc và +diễn giải lại các câu hỏi/trả lời **liên quan tới FR-05, FR-06, FR-07** đã có sẵn trong +`e-commerce/docs/00-project-brief.md` (văn bản đã qua 3 vòng Q&A ở cấp toàn dự án, không phải +riêng module này). + +Hệ quả: + +- **Năm câu hỏi bắt buộc** của `ba-1-discovery` (Bước 3) — *"cho tôi xem một ca thật"*, *"chỗ + nào hay sai nhất"*, *"trường hợp ngoại lệ nào"*, *"nếu chỉ làm được một thứ"*, *"làm sao biết + thành công"* — **chưa được hỏi nguyên văn** cho module này, vì nguồn là văn bản tổng hợp, không + phải hội thoại trực tiếp. Đây là khoảng trống thật, không che giấu — xem mục 5 (Open Questions). +- **Không có bước "đọc lại tóm tắt cho người tham gia xác nhận tại chỗ"** vì không có buổi họp + thật diễn ra. +- Mọi phát biểu dưới đây **vẫn có nguồn truy vết được** (trích dẫn tới `00-project-brief.md`), + đáp ứng nguyên tắc "không bịa yêu cầu", nhưng **độ tin cậy thấp hơn** một buổi phỏng vấn thật + với đúng vai trò sử dụng/bị ảnh hưởng của module (STK-02…STK-05) — vì brief được chốt ở tầm + toàn dự án, chưa đào sâu riêng luồng giỏ hàng/checkout/thanh toán. + +## 1. Mục tiêu + +- Trích ra các Q&A trong `docs/00-project-brief.md` liên quan tới: giỏ hàng đa seller (FR-05), + checkout & tách đơn theo seller (FR-06), thanh toán VNPay/Momo/COD (FR-07). + +## 2. Nội dung + +### 2.1 Sự thật thu được *(đã chốt qua Q&A, coi là quyết định của PO)* + +| # | Nội dung | Nguồn xác minh | +|---|---|---| +| F1 | Mô hình là marketplace đa người bán (multi-vendor B2C/B2B2C); Guest có thể checkout không cần tài khoản | `00-project-brief.md` vòng 1, câu hỏi 1; `sections/01-tong-quan.md` §1.2 | +| F2 | MVP xác nhận có "Giỏ hàng & checkout (hỗ trợ giỏ hàng đa seller trong 1 đơn)" và "Thanh toán (VNPay/Momo + COD)" | `00-project-brief.md` vòng 1, câu hỏi 2 | +| F3 | Quản lý đơn hàng bao gồm "tách đơn theo seller" — một giỏ hàng đa seller được tách thành các đơn con | `00-project-brief.md` mục 2 "Bộ tính năng MVP chuẩn"; `sections/02-phan-tich-yeu-cau.md` FR-06 | +| F4 | Nền tảng client MVP là web responsive (không phải app di động) | `00-project-brief.md` vòng 1, câu hỏi 4 | +| F5 | Đối tác thanh toán/vận chuyển mặc định: VNPay, Momo, COD / GHN, GHTK | `00-project-brief.md` vòng 1, câu hỏi 4 | +| F6 | FR-05, FR-06, FR-07 đều được xếp **Must** trong bảng yêu cầu chức năng đã duyệt | `sections/02-phan-tich-yeu-cau.md` §2.1 | +| F7 | Không có hệ thống cũ (ERP/kho/CRM) cần tích hợp hoặc migrate cho luồng giỏ hàng/checkout — dự án hoàn toàn mới | `00-project-brief.md` vòng 3, câu hỏi 4; mục 3 | + +### 2.2 Ý kiến / mong muốn *(chưa phải yêu cầu đã chốt ở mức chi tiết module)* + +| # | Nội dung | Người nêu | Mức thiết tha | +|---|---|---|---| +| O1 | Mã khuyến mãi/coupon và điểm thưởng loyalty có thể áp dụng ngay trong bước checkout (không phải một bước tách riêng) | Suy ra từ mô tả UI ở `sections/07-giao-dien.md` SCR-05 — **chỉ là bối cảnh UI, chưa phải yêu cầu đã chốt cho module này** (FR-13/FR-14 nằm ngoài phạm vi FR-05/06/07 được giao) | Trung bình — cần PO xác nhận có thuộc phạm vi module Giỏ hàng & Checkout hay là điểm nối với module Khuyến mãi/Loyalty | +| O2 | Kỳ vọng phí vận chuyển/thời gian giao hiển thị riêng theo từng đơn con seller trước khi thanh toán | Suy ra từ `sections/07-giao-dien.md` SCR-05 (bối cảnh UI) | Trung bình — chưa có RQ chính thức, xem `OQ-004` | + +### 2.3 Giả định phát hiện *(người nói tin là đúng nhưng chưa ai xác nhận riêng cho module này)* + +| # | Giả định | Cách xác minh | → ASM | +|---|---|---|---| +| A1 | VNPay/Momo hỗ trợ webhook xác nhận thanh toán gần thời gian thực | Đọc tài liệu tích hợp VNPay/Momo, gọi thử sandbox | ASM-01 | +| A2 | GHN/GHTK cung cấp API tính phí vận chuyển & kiểm tra vùng phục vụ theo địa chỉ ngay tại bước checkout | Đọc tài liệu API GHN/GHTK, xác nhận với Trưởng vận hành (STK-05) | ASM-02 | +| A3 | COD không có giới hạn giá trị đơn hàng tối đa ở MVP | Hỏi PO sàn (STK-01) và Kế toán đối soát (STK-04) | ASM-05 | +| A4 | Giá/tồn kho hiển thị trong giỏ hàng được đồng bộ đủ nhanh với catalog để phát hiện thay đổi giữa lúc thêm giỏ và lúc checkout | Xác nhận kiến trúc dữ liệu catalog ở GĐ2 với Tech Lead (STK-06) | ASM-06 | + +### 2.4 Trích nguyên văn + +> "Giữ toàn bộ MVP đề xuất VÀ bổ sung ngay từ MVP: (1) loyalty/điểm thưởng; (2) đa ngôn ngữ và +> đa tiền tệ." — trả lời vòng 1, câu hỏi 2, `00-project-brief.md` + +> "Payout hàng tuần qua chuyển khoản ngân hàng, có kỳ giữ tiền (hold) sau giao hàng thành công +> (dùng mặc định 3-7 ngày)." — trả lời vòng 3, câu hỏi 1, `00-project-brief.md` *(không thuộc +> phạm vi module này nhưng cho biết chính sách đổi trả có thể ảnh hưởng tới thời điểm "giao hàng +> thành công" mà module Order/Payment cần ghi nhận — liên quan gián tiếp tới FR-07)* + +## 3. Mâu thuẫn với thông tin trước đó + +Không phát hiện mâu thuẫn giữa các vòng Q&A trong brief liên quan tới FR-05/06/07 — cả 3 vòng +đều nhất quán về việc giữ nguyên các tính năng này ở mức Must, không có vòng nào đề xuất bỏ hoặc +thay đổi. + +| # | Buổi này nói | Buổi/nguồn trước nói | Trạng thái | +|---|---|---|---| +| — | *(không có)* | | — | + +## 4. Yêu cầu chưng cất được + +Chi tiết đầy đủ (nguồn, MoSCoW, liên kết GOAL) nằm ở `BRIEF_CartCheckout_v1.0.md` §6. Tóm tắt +liên kết: + +| → RQ | Phát biểu | MoSCoW đề xuất | Giải pháp khách gợi ý | +|---|---|---|---| +| RQ-001 | Customer/Guest mua được từ nhiều seller trong một giỏ hàng | Must | "Giỏ hàng đa seller" (F2) | +| RQ-002 | Hệ thống tự tách đơn theo seller khi checkout | Must | "tách đơn theo seller" (F3) | +| RQ-003 | Thanh toán qua nhiều kênh (VNPay/Momo/COD), không lưu thẻ trên hệ thống sàn | Must | "Thanh toán (VNPay/Momo + COD)" (F2) | +| RQ-004 | Guest checkout không cần tạo tài khoản trước | Must | "checkout không cần đăng nhập" (F1) | + +## 5. Open Questions phát sinh + +| ID | Câu hỏi | Hỏi ai | Hạn đề xuất | +|---|---|---|---| +| OQ-004 | Việc áp coupon (FR-13) và dùng điểm thưởng (FR-14) ngay trong màn hình checkout có thuộc phạm vi module Giỏ hàng & Checkout hay là điểm tích hợp với module Khuyến mãi/Loyalty (xử lý ở GĐ2 module khác)? | PO sàn (STK-01) | Trước khi bắt đầu GĐ2 của module này | +| OQ-005 | Cần tổ chức tối thiểu 1 buổi phỏng vấn/workshop thật với STK-02 (Khách hàng đại diện) và STK-03 (Seller đại diện) để hỏi 5 câu bắt buộc của Bước 3 (ca thật, điểm hay sai, ngoại lệ, ưu tiên số 1, định nghĩa thành công) — hiện chưa có buổi nào. Ai sẽ làm đầu mối sắp xếp? | Điều phối dự án / PO sàn | Trước khi ký G1 chính thức (khuyến nghị, xem mục 0) | +| OQ-006 | Chính sách giới hạn giá trị đơn COD (nếu có) là gì, để giảm rủi ro bùng hàng khi một giỏ hàng đa seller bị tách thành nhiều đơn COD độc lập? | PO sàn (STK-01), Kế toán đối soát (STK-04) | Trước GĐ2 (ảnh hưởng BR) | + +## 6. Việc cần làm tiếp + +| # | Việc | Ai | Hạn | +|---|---|---|---| +| 1 | Xác nhận tên thật + đầu mối liên lạc của STK-01…STK-06 | Điều phối dự án | Trước ký G1 | +| 2 | Tổ chức phỏng vấn thật với Khách hàng đại diện và Seller đại diện cho module này | BA | Trước GĐ2 | +| 3 | Xác nhận với Tech Lead về ASM-01, ASM-02, ASM-06 | BA | Trước GĐ2 | + +## 7. Tóm tắt đã đọc lại cho người tham gia xác nhận tại chỗ + +- [ ] Đã đọc lại tóm tắt cuối buổi — **N/A, không có buổi họp trực tiếp (xem mục 0)** +- [ ] Đã gửi biên bản trong vòng 24h — **N/A** +- [ ] Đã nhận phản hồi xác nhận — **N/A, chờ đầu mối thật (`OQ-001`)** diff --git a/ba-output/e-commerce/01-discovery/RISK_CartCheckout_v1.0.md b/ba-output/e-commerce/01-discovery/RISK_CartCheckout_v1.0.md new file mode 100644 index 0000000..80ccfb8 --- /dev/null +++ b/ba-output/e-commerce/01-discovery/RISK_CartCheckout_v1.0.md @@ -0,0 +1,100 @@ +# RISK — Sổ rủi ro & giả định — Module Giỏ hàng & Checkout (e-commerce) + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-1-discovery) | +| **Status** | 🟡 Draft | +| **Approved by** | — | +| **Profile** | screen · greenfield · standard | +| **Source** | `e-commerce/docs/00-project-brief.md` · `e-commerce/docs/sections/01-tong-quan.md` · `e-commerce/docs/sections/02-phan-tich-yeu-cau.md` · `e-commerce/docs/sections/07-giao-dien.md` (bối cảnh UI SCR-04…07) · `ELICITATION_CartCheckout_2026-09-08.md` | +| **Scope** | Module Giỏ hàng & Checkout (FR-05, FR-06, FR-07) — dự án e-commerce | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | CR | +|---|---|---|---|---| +| 1.0 | 2026-09-08 | BA (qua skill ba-1-discovery) | Bản đầu | — | + +--- + +## 1. Giả định (`ASM-nn`) + +| ID | Giả định | Ai/cái gì làm nó đúng | Cách xác minh | Hạn xác minh | Hệ quả nếu sai | Trạng thái | +|---|---|---|---|---|---|---| +| ASM-01 | VNPay/Momo hỗ trợ webhook xác nhận thanh toán gần thời gian thực (không phải chỉ polling chậm) | Cổng thanh toán bên thứ ba | Đọc tài liệu tích hợp VNPay/Momo, gọi thử sandbox | Trước GĐ2 kết thúc (trước khi chốt `PROCESS`/`BR` thanh toán) | SCR-07 (xác nhận đơn) phải đổi từ "chờ webhook" sang polling định kỳ, tăng độ trễ cảm nhận, ảnh hưởng NFR-01 | ☐ Chưa xác minh | +| ASM-02 | GHN/GHTK cung cấp API tính phí vận chuyển & kiểm tra vùng phục vụ theo địa chỉ tại thời điểm checkout | Đơn vị vận chuyển bên thứ ba | Đọc tài liệu API GHN/GHTK; xác nhận với Trưởng vận hành (STK-05) | Trước GĐ2 kết thúc | Không hiển thị được phí/thời gian giao theo từng seller lúc checkout → phải chuyển sang ước tính tĩnh hoặc tính sau, ảnh hưởng trải nghiệm và RQ liên quan tách đơn | ☐ Chưa xác minh | +| ASM-03 | Giỏ hàng có N seller sẽ luôn tách thành đúng N đơn con — không có trường hợp gộp 2 seller vào 1 đơn con | FR-06 đã mô tả rõ cơ chế này ở mức khái niệm | Xác nhận lại với PO sàn (STK-01) khi làm `BR` ở GĐ2 — chưa có ngoại lệ nào được nêu | Trước khi chốt `BR` ở GĐ2 | Nếu có ngoại lệ (VD gộp đơn cùng kho vận), toàn bộ luồng tách đơn và tính phí ship phải thiết kế lại | ☐ Chưa xác minh | +| ASM-04 | Seller (STK-03) sẽ nhận được thông báo về đơn con mới ngay sau khi checkout thành công, dù việc gửi thông báo thuộc FR-12/FR-19 (ngoài phạm vi module này) | Phụ thuộc module Quản lý đơn hàng (seller) và Thông báo — chưa xác nhận SLA bàn giao dữ liệu giữa hai module | Xác nhận điểm nối dữ liệu (event/queue) với Tech Lead (STK-06) ở GĐ2 | Trước khi chốt `IMPACT` ở GĐ2 | Seller không biết có đơn mới kịp thời → chậm xử lý, ảnh hưởng SLA giao hàng | ☐ Chưa xác minh | +| ASM-05 | COD không có giới hạn giá trị đơn hàng tối đa ở MVP (không có business rule chặn) | Suy ra từ việc brief không đề cập giới hạn COD | Hỏi PO sàn (STK-01) và Kế toán đối soát (STK-04) — xem `OQ-006` | Trước khi chốt `BR` thanh toán ở GĐ2 | Nếu sai (cần giới hạn) → thiếu một business rule quan trọng, phát hiện muộn có thể lộ ở UAT hoặc sau go-live dưới dạng rủi ro tài chính thật (RISK-01) | ☐ Chưa xác minh | +| ASM-06 | Giá/tồn kho hiển thị trong giỏ hàng đủ đồng bộ với catalog để phát hiện thay đổi giữa lúc thêm giỏ và lúc checkout (không có cache trễ đáng kể) | Kiến trúc dữ liệu catalog (chưa thiết kế — thuộc GĐ2/GĐ3) | Xác nhận với Tech Lead (STK-06) khi có kiến trúc sơ bộ | Trước GĐ3 (SRS) | Nếu cache trễ, khách có thể thanh toán với giá/tồn kho sai → tranh chấp, phải bổ sung cơ chế khoá giá/tồn kho tạm thời (reservation) | ☐ Chưa xác minh | + +**Bốn chỗ giả định hay ẩn nấp — đã rà theo checklist chuẩn:** + +| Chỗ | Giả định điển hình trong module này | Trạng thái rà soát | +|---|---|---| +| **Dữ liệu** | ASM-06 (đồng bộ giá/tồn kho) | Đã ghi, chưa xác minh | +| **Tích hợp** | ASM-01 (webhook VNPay/Momo), ASM-02 (API GHN/GHTK) | Đã ghi, chưa xác minh | +| **Con người** | ASM-04 (seller được thông báo kịp thời) | Đã ghi, chưa xác minh | +| **Pháp lý** | Không có ASM riêng cho PII ở đây — xem `RISK-03` (chưa có đại diện Pháp chế để hỏi, `OQ-003` ở `STAKEHOLDER_CartCheckout_v1.0.md`) | Chưa có người trả lời được | + +🔴 ASM-05 có hệ quả nếu sai ở mức **Cao** (rủi ro tài chính thật) → đã nâng thành `RISK-01` +bên dưới và cần xác minh **ngay trong GĐ1/đầu GĐ2**, không để tới UAT. + +## 2. Rủi ro (`RISK-nn`) + +| ID | Mô tả rủi ro | Loại | Khả năng | Tác động | Mức | Người chịu trách nhiệm | Phương án ứng phó | Dấu hiệu sớm | Trạng thái | +|---|---|---|---|---|---|---|---|---|---| +| RISK-01 | Vì một giỏ hàng đa seller được tách thành nhiều đơn con COD độc lập (FR-06) và MVP theo giả định (`ASM-05`) chưa có giới hạn giá trị/số lượng đơn COD, có thể xảy ra tình trạng khách nhận một phần đơn (VD chỉ nhận đơn của seller A, từ chối đơn seller B), dẫn tới seller B chịu phí vận chuyển hoàn hàng và phát sinh tranh chấp seller–sàn hàng loạt khi quy mô giao dịch lớn (brief xác nhận quy mô "lớn", hàng trăm nghìn user). | Nghiệp vụ / Tài chính | Cao | Cao | 🔴 | STK-01 (PO sàn) — *chưa có tên thật, `OQ-001`* | BA đề xuất 2 phương án cho PO chọn: (a) giới hạn giá trị tối đa cho đơn COD đa seller; (b) yêu cầu xác thực OTP/đặt cọc cho đơn giá trị cao. **Đây là đề xuất, PO phải chọn (W8)** | Tỷ lệ đơn con bị từ chối một phần tăng bất thường theo dữ liệu vận hành sau go-live | Mở | +| RISK-02 | Vì VNPay/Momo là bên thứ ba và cơ chế xác nhận qua webhook chưa được xác minh (`ASM-01`), có thể xảy ra tình trạng khách đã bị trừ tiền nhưng hệ thống không nhận được xác nhận trong thời gian chờ ở màn hình xác nhận đơn hàng (SCR-07, bối cảnh UI), dẫn tới đơn hàng kẹt ở trạng thái "Chờ thanh toán" dù tiền đã được cổng thanh toán ghi nhận, gây khiếu nại CSKH và tranh chấp đối soát với STK-04. | Tích hợp | Trung bình | Cao | 🔴 | STK-06 (Tech Lead) + STK-01 (PO sàn) | BA đề xuất: có cơ chế đối soát bù (reconciliation job) định kỳ đối chiếu trạng thái giao dịch với cổng thanh toán, không chỉ dựa vào webhook một lần. **Cần Tech Lead xác nhận khả thi** | Số lượng đơn "Chờ thanh toán" quá 15 phút tăng bất thường | Mở | +| RISK-03 | Vì dự án chưa có đại diện Pháp chế/Bảo mật được chỉ định (xem `STAKEHOLDER_CartCheckout_v1.0.md` mục 3), có thể xảy ra việc module Giỏ hàng & Checkout thu thập/chia sẻ dữ liệu địa chỉ giao hàng và số điện thoại người nhận cho từng seller (khi tách đơn) mà chưa được rà soát theo Nghị định 13/2023 về bảo vệ dữ liệu cá nhân, dẫn tới rủi ro vi phạm quy định khi go-live. | Tuân thủ | Trung bình | Cao | 🔴 | *(Chưa có người — `OQ-003`)* | BA đề xuất: PO chỉ định người phụ trách pháp chế/bảo mật trước khi kết thúc GĐ2; BA chuẩn bị danh sách trường dữ liệu PII được chia sẻ cho seller để người đó rà soát | Chưa có ai được hỏi về việc này tính tới thời điểm chốt G1 | Mở | +| RISK-04 | Vì checkout phải tính phí vận chuyển riêng cho từng đơn con theo seller (FR-06, tích hợp GHN/GHTK — `ASM-02`), tổng phí vận chuyển của một giỏ hàng nhiều seller có thể cao hơn đáng kể so với mua từ một seller duy nhất, dẫn tới khách bỏ giỏ hàng ở bước checkout (ảnh hưởng trực tiếp tới GOAL-01/GOAL-02 ở `BRIEF`). | Nghiệp vụ | Trung bình | Trung bình | 🟠 | STK-01 (PO sàn) | BA đề xuất PO cân nhắc chính sách trợ giá/miễn phí ship theo ngưỡng đơn hàng — **đề xuất, PO quyết, chưa phải chốt** | Tỷ lệ bỏ giỏ hàng ở bước checkout cao hơn ở bước giỏ hàng, đặc biệt với giỏ có ≥2 seller | Mở | + +**Ma trận mức:** + +| Tác động ↓ · Khả năng → | Thấp | Trung bình | Cao | +|---|---|---|---| +| **Cao** | 🟠 | 🔴 RISK-02, RISK-03 | 🔴 RISK-01 | +| **Trung bình** | 🟢 | 🟠 RISK-04 | 🔴 | +| **Thấp** | 🟢 | 🟢 | 🟠 | + +🔴 RISK-01, RISK-02, RISK-03 phải có phương án ứng phó và người chịu trách nhiệm **thật** (không +phải placeholder vai trò) trước khi qua G2 — báo PM. + +**Loại rủi ro — đã rà đủ 6 loại:** + +| Loại | Rà cho module này | +|---|---| +| Nghiệp vụ | RISK-01, RISK-04 | +| Dữ liệu | Chưa phát hiện rủi ro riêng — theo dõi qua `ASM-06` | +| Tích hợp | RISK-02 | +| Con người | Chưa phát hiện rủi ro riêng cho module này — theo dõi qua `ASM-04` | +| Tuân thủ | RISK-03 | +| Tổ chức | Chưa phát hiện — vì chưa có buổi làm việc thật để lộ mâu thuẫn (xem `STAKEHOLDER` mục 6) | + +## 3. Phụ thuộc bên ngoài + +| # | Phụ thuộc vào | Bên nào | Cần trước ngày | Nếu trễ thì sao | Đầu mối | Trạng thái | +|---|---|---|---|---|---|---| +| 1 | Tài liệu API + tài khoản sandbox VNPay | VNPay | Trước khi bắt đầu GĐ3 (SRS thanh toán) | Không xác minh được ASM-01, chặn thiết kế luồng xác nhận thanh toán | Chưa xác định | Mở | +| 2 | Tài liệu API + tài khoản sandbox Momo | Momo | Trước khi bắt đầu GĐ3 | Tương tự trên | Chưa xác định | Mở | +| 3 | Tài liệu API + tài khoản tích hợp GHN | GHN | Trước khi bắt đầu GĐ3 (SRS checkout, tính phí ship) | Không xác minh được ASM-02, phải dùng ước tính tĩnh tạm thời | Chưa xác định | Mở | +| 4 | Tài liệu API + tài khoản tích hợp GHTK | GHTK | Trước khi bắt đầu GĐ3 | Tương tự trên | Chưa xác định | Mở | + +## 4. Rủi ro đã đóng + +*Chưa có — dự án mới bắt đầu GĐ1.* + +| ID | Rủi ro | Ngày đóng | Kết cục | Bài học | +|---|---|---|---|---| + +## 5. Lịch rà soát + +| Mốc | Việc | +|---|---| +| Trước khi ký G1 | Rà lại RISK-01, RISK-02, RISK-03 với người chịu trách nhiệm thật (không phải vai trò placeholder) | +| GĐ2 bắt đầu | ASM-03, ASM-04, ASM-05 phải chuyển sang "đã xác minh" trước khi chốt `BR` | +| GĐ3 bắt đầu | ASM-01, ASM-02, ASM-06 phải chuyển sang "đã xác minh" hoặc thành `RISK` chính thức | +| GĐ4 UAT | Rà lại RISK-01 (COD) và RISK-02 (webhook) — đây là lúc chúng dễ hiện hình nhất | +| GĐ5 | Chuyển bài học vào `BENEFIT` | diff --git a/ba-output/e-commerce/01-discovery/STAKEHOLDER_CartCheckout_v1.0.md b/ba-output/e-commerce/01-discovery/STAKEHOLDER_CartCheckout_v1.0.md new file mode 100644 index 0000000..7e8377e --- /dev/null +++ b/ba-output/e-commerce/01-discovery/STAKEHOLDER_CartCheckout_v1.0.md @@ -0,0 +1,148 @@ +# STAKEHOLDER — Module Giỏ hàng & Checkout (e-commerce) + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-1-discovery) | +| **Status** | 🟡 Draft | +| **Approved by** | — | +| **Profile** | screen · greenfield · standard (xem `00-index/PROFILE_e-commerce.md`) | +| **Source** | `e-commerce/docs/00-project-brief.md` · `e-commerce/docs/sections/01-tong-quan.md` §1.2 · `e-commerce/docs/sections/02-phan-tich-yeu-cau.md` · Ghi chú vai trò từ người duyệt (prompt khởi tạo, 2026-09-08) | +| **Scope** | Module Giỏ hàng & Checkout (FR-05, FR-06, FR-07) — dự án e-commerce | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | CR | +|---|---|---|---|---| +| 1.0 | 2026-09-08 | BA (qua skill ba-1-discovery) | Bản đầu | — | + +--- + +## 0. Ghi chú về nguồn — đọc trước khi dùng + +🔴 Stakeholder thật **chưa có tên**. Theo ghi chú từ người duyệt, dùng **vai trò** thay tên +thật: PO sàn, Trưởng vận hành, Kế toán đối soát, Seller đại diện, Khách hàng đại diện, Tech +Lead. Mọi ô "Tên" dưới đây ghi placeholder theo vai trò và có `OQ` đòi tên thật + đầu mối +liên lạc — **chưa liên hệ được thì chưa nên coi G1 là đã ký thật**, kể cả khi PO ký thay bằng +vai trò. + +Mức quan tâm/ảnh hưởng ở bảng dưới là **đánh giá ban đầu của BA** dựa trên vai trò nghiệp vụ +mô tả trong brief, **chưa được chính chủ tự chấm** — xem `OQ-002`. + +--- + +## 1. Danh sách stakeholder + +| ID | Tên | Vai trò / Bộ phận | Nhóm | Quan tâm | Ảnh hưởng | Chiến lược | Kênh | Người thay thế | +|---|---|---|---|---|---|---|---|---| +| STK-01 | *(chưa có tên thật — OQ-001)* | PO sàn (Product Owner marketplace) | Quyết định | Cao | Cao | Quản lý sát | Chưa xác định | Chưa xác định | +| STK-02 | *(chưa có tên thật — OQ-001)* | Khách hàng đại diện (đại diện Guest + Customer, người thao tác giỏ hàng/checkout/thanh toán) | Sử dụng | Cao | Thấp | Giữ thông tin | Chưa xác định | Chưa xác định | +| STK-03 | *(chưa có tên thật — OQ-001)* | Seller đại diện (Vendor — đơn con của họ được tạo ra từ checkout) | Bị ảnh hưởng | Cao | Trung bình | Giữ thông tin | Chưa xác định | Chưa xác định | +| STK-04 | *(chưa có tên thật — OQ-001)* | Kế toán đối soát (đối soát doanh thu theo VNPay/Momo/COD, theo seller) | Bị ảnh hưởng | Thấp | Cao | Giữ hài lòng | Chưa xác định | Chưa xác định | +| STK-05 | *(chưa có tên thật — OQ-001)* | Trưởng vận hành (Ops/Warehouse — nhận đơn con sau checkout, phối hợp GHN/GHTK) | Cung cấp thông tin | Trung bình | Trung bình | Giữ thông tin | Chưa xác định | Chưa xác định | +| STK-06 | *(chưa có tên thật — OQ-001)* | Tech Lead (khả thi tích hợp VNPay/Momo/GHN/GHTK, ràng buộc kiến trúc) | Cung cấp thông tin | Cao | Cao | Quản lý sát | Chưa xác định | Chưa xác định | + +**Nhóm** — bốn nhóm, thiếu nhóm nào cũng là lỗ hổng: + +| Nhóm | Câu hỏi nhận diện | Rủi ro nếu bỏ sót | +|---|---|---| +| Quyết định | Ai ký duyệt? Ai cắt được scope? | Làm xong bị bác | +| Sử dụng | Ai ngồi trước màn hình mỗi ngày? | Đúng spec nhưng không ai dùng | +| Bị ảnh hưởng | Quy trình của ai thay đổi? Ai mất/được việc? | Kháng cự lúc go-live | +| Cung cấp thông tin | Ai biết nghiệp vụ hiện tại? Ai giữ dữ liệu? | Hiểu sai AS-IS | + +🔴 **Nhóm còn thiếu — Pháp chế/Bảo mật.** Module này xử lý PII (địa chỉ giao hàng, số điện +thoại) và dữ liệu thanh toán (dù không lưu số thẻ). Danh sách vai trò do người duyệt cung cấp +**không có** đại diện Pháp chế/Bảo mật. Đây đúng là một trong ba nhóm SKILL cảnh báo hay bị bỏ +sót nhất → `OQ-003`. Chưa có người này ký thì rủi ro tuân thủ (RISK-03) chưa ai chịu trách +nhiệm chính thức. + +## 2. Ma trận Quan tâm × Ảnh hưởng + +```mermaid +quadrantChart + title Stakeholder — Quan tâm × Ảnh hưởng (module Giỏ hàng & Checkout) + x-axis "Quan tâm thấp" --> "Quan tâm cao" + y-axis "Ảnh hưởng thấp" --> "Ảnh hưởng cao" + quadrant-1 "QUẢN LÝ SÁT" + quadrant-2 "GIỮ HÀI LÒNG" + quadrant-3 "THEO DÕI" + quadrant-4 "GIỮ THÔNG TIN" + "STK-01 PO sàn": [0.90, 0.90] + "STK-02 KH đại diện": [0.80, 0.25] + "STK-03 Seller đại diện": [0.75, 0.50] + "STK-04 Kế toán đối soát": [0.20, 0.85] + "STK-05 Trưởng vận hành": [0.50, 0.45] + "STK-06 Tech Lead": [0.75, 0.85] +``` + +*Toạ độ 0–1, đánh giá sơ bộ của BA — cần từng người tự xác nhận lại, xem `OQ-002`.* + +| Ô | Chiến lược | STK trong ô | +|---|---|---| +| **Quản lý sát** *(quan tâm cao, ảnh hưởng cao)* | Đồng hành, duyệt từng gate | STK-01, STK-06 | +| **Giữ hài lòng** *(quan tâm thấp, ảnh hưởng cao)* | Hỏi từng điểm một, không chấp nhận im lặng | STK-04 | +| **Giữ thông tin** *(quan tâm cao, ảnh hưởng thấp/TB)* | Hỏi ý kiến, demo sớm | STK-02, STK-03, STK-05 | +| **Theo dõi** *(cả hai thấp)* | Thông báo khi cần | — | + +🔴 **STK-04 (Kế toán đối soát) nằm ở ô nguy hiểm nhất** — ảnh hưởng cao (họ phát hiện lỗi số +liệu payout/đối soát muộn nhất, và phủ quyết muộn nhất) nhưng quan tâm thấp (hiếm khi được +mời họp sản phẩm). Không được coi im lặng là đồng ý. + +## 3. Ba nhóm hay bị bỏ sót — rà đích danh + +| Nhóm | Có mặt trong danh sách vai trò của người duyệt? | Câu phải hỏi | +|---|---|---| +| Vận hành / CS | ✅ STK-05 Trưởng vận hành | "Khi Customer khiếu nại một đơn con bị chậm ngay sau checkout, ai nhận đầu tiên?" | +| Kế toán / đối soát | ✅ STK-04 Kế toán đối soát | "Số liệu doanh thu theo VNPay/Momo/COD, theo seller, ai đối chiếu và đối chiếu với cái gì?" | +| Pháp chế / bảo mật | ❌ **Không có trong danh sách** — `OQ-003` | "Dữ liệu địa chỉ + số điện thoại người nhận trong Order có phải PII cần xin phép lưu trữ/chia sẻ cho seller không?" | + +## 4. RACI theo hạng mục quyết định (thu hẹp cho module này) + +| Hạng mục | R (làm) | A (chịu trách nhiệm cuối) | C (hỏi ý kiến) | I (thông báo) | +|---|---|---|---|---| +| Chốt phạm vi module Giỏ hàng & Checkout | BA | STK-01 (PO sàn) | STK-06 (Tech Lead) | Team | +| Chốt quy tắc tách đơn theo seller (FR-06) | BA | STK-01 | STK-03, STK-05 | STK-04 | +| Chốt danh sách phương thức thanh toán & xử lý lỗi thanh toán (FR-07) | BA | STK-01 | STK-06, STK-04 | STK-02 | +| Chốt giới hạn/điều kiện áp dụng COD (RISK-01) | BA | STK-01 | STK-04, STK-05 | STK-03 | +| Xác nhận yêu cầu tuân thủ PII/thanh toán | BA | *(chưa xác định — `OQ-003`)* | STK-01, STK-06 | Team | +| Duyệt UAT module | QA | STK-01 | BA | Team | + +**Mỗi hàng chỉ có đúng một chữ A.** Hàng "Xác nhận yêu cầu tuân thủ PII/thanh toán" chưa có A +vì chưa có đại diện Pháp chế — đây chính là lỗ hổng nêu ở mục 3. + +## 5. Kế hoạch tiếp cận + +🔴 Toàn bộ nội dung trong `BRIEF`/`ELICITATION` của lần chạy này lấy từ `docs/00-project-brief.md` +(biên bản 3 vòng Q&A đã chốt ở cấp toàn dự án, không riêng module Giỏ hàng & Checkout) — **chưa +có buổi làm việc trực tiếp nào với 6 vai trò dưới đây riêng cho module này.** Bảng dưới là kế +hoạch đề xuất, chưa thực hiện. + +| STK | Cần lấy thông tin gì | Kỹ thuật | Dự kiến | Trạng thái | +|---|---|---|---|---| +| STK-01 (PO sàn) | Xác nhận tên thật, KPI/baseline conversion & tỷ lệ thanh toán thành công, ngưỡng Must/Should thật của module | Phỏng vấn 1-1 | Trước khi ký G1 | ☐ Chưa thực hiện | +| STK-02 (KH đại diện) | Kỳ vọng thực tế khi mua từ nhiều seller (mức chấp nhận phí ship gộp, thời gian chờ) | Phỏng vấn/khảo sát | Trước GĐ2 | ☐ Chưa thực hiện | +| STK-03 (Seller đại diện) | Kỳ vọng về tốc độ nhận đơn con, rủi ro bùng COD ảnh hưởng seller thế nào | Phỏng vấn 1-1 | Trước GĐ2 | ☐ Chưa thực hiện | +| STK-04 (Kế toán đối soát) | Cách đối soát hiện tại (nếu công ty đã có luồng thu khác), yêu cầu dữ liệu tối thiểu từ Order/Payment | Phỏng vấn 1-1 | Trước GĐ2 (BR) | ☐ Chưa thực hiện | +| STK-05 (Trưởng vận hành) | Ràng buộc thực tế của GHN/GHTK (vùng phục vụ, SLA báo phí), quy trình nhận đơn con | Phỏng vấn 1-1 hoặc workshop | Trước GĐ2 | ☐ Chưa thực hiện | +| STK-06 (Tech Lead) | Khả thi webhook VNPay/Momo, ràng buộc kiến trúc tách đơn | Phỏng vấn 1-1 | Trước G2 | ☐ Chưa thực hiện | +| *(Pháp chế/Bảo mật — chưa có người)* | Phạm vi PII được phép lưu/chia sẻ cho seller, thời hạn lưu | Chưa xác định người | Trước G2/G3 | ☐ Chưa xác định | + +## 6. Mâu thuẫn giữa các bên + +Chưa phát hiện mâu thuẫn trực tiếp nào giữa các vai trò cho module này, **vì chưa có buổi làm +việc riêng với từng vai trò** (xem mục 5). Đây không phải "không có mâu thuẫn" mà là "chưa đủ +dữ liệu để phát hiện mâu thuẫn" — ghi nhận như một giới hạn của lần chạy này, không tự suy diễn. + +| # | Bên A muốn | Bên B muốn | Vì sao mâu thuẫn | Trạng thái | +|---|---|---|---|---| +| — | *(chưa phát hiện — xem ghi chú trên)* | | | — | + +## 7. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | +|---|---|---|---|---| +| OQ-001 | Tên thật + đầu mối liên lạc của 6 vai trò STK-01…STK-06 là gì? | Điều phối dự án / PO | 2026-09-08 | Ký G1 thật (hiện chỉ có vai trò, chưa có người ký thật) | +| OQ-002 | Mức Quan tâm × Ảnh hưởng ở mục 2 là đánh giá của BA — từng STK có đồng ý không? | STK-01…STK-06 | 2026-09-08 | Chiến lược tiếp cận ở mục 5 | +| OQ-003 | Ai là đại diện Pháp chế/Bảo mật cho dự án e-commerce? Module Giỏ hàng & Checkout cần họ xác nhận phạm vi lưu/chia sẻ PII (địa chỉ, SĐT) cho seller khi tách đơn. | PO sàn (STK-01) | 2026-09-08 | RACI mục 4 (hàng tuân thủ PII), RISK-03 | diff --git a/ba-output/e-commerce/02-analysis/BACKLOG_CartCheckout_v1.0.md b/ba-output/e-commerce/02-analysis/BACKLOG_CartCheckout_v1.0.md new file mode 100644 index 0000000..960e6a3 --- /dev/null +++ b/ba-output/e-commerce/02-analysis/BACKLOG_CartCheckout_v1.0.md @@ -0,0 +1,534 @@ +# BACKLOG — Giỏ hàng & Checkout (e-commerce) + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-2-analysis) | +| **Status** | 🟡 Draft | +| **Approved by** | — | +| **Profile** | screen · greenfield · standard (xem `00-index/PROFILE_e-commerce.md`) | +| **Source** | `01-discovery/BRIEF_CartCheckout_v1.0.md` (RQ-001…RQ-004) · `PROCESS_CartCheckout_v1.0.md` v1.0 · Trả lời của người dùng cho `OQ-004` và `OQ-008` (xem `DEC-03`, `DEC-04` ở `00-index/DECISION_e-commerce.md`) | +| **Scope** | Module Giỏ hàng & Checkout — RQ-001…RQ-004. Ưu tiên phân rã US cho màn hình Giỏ hàng (FR-05) và Checkout & tách đơn (FR-06), theo đúng chỉ định phạm vi lần chạy này. Tối đa 8 US (giới hạn theo chỉ đạo "tối đa 6–8 US"). | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | CR | +|---|---|---|---|---| +| 1.0 | 2026-09-08 | BA (qua skill ba-2-analysis) | Bản đầu — 8 US, 2 Epic, 3 Feature | — | + +--- + +> ⚠️ **Ngoại lệ gate G1** — xem cảnh báo đầy đủ ở đầu `PROCESS_CartCheckout_v1.0.md`. Tài liệu +> này được viết tiếp trong khi `BRIEF` module chưa qua G1 chính thức, theo xác nhận của người +> điều phối — xem `DEC-02` ở `00-index/DECISION_e-commerce.md`. Backlog dưới đây **phải rà lại +> phạm vi và ưu tiên** khi PO ký G1 thật. + +## 0. Sơ đồ Use Case — toàn cảnh cho PO + +```mermaid +flowchart LR + GUEST(["👤 Guest"]) + CUS(["👤 Customer"]) + + subgraph HT["Phạm vi RQ-001…RQ-004 — Giỏ hàng & Checkout"] + UC1(["US-001 Thêm sản phẩm đa seller vào giỏ"]) + UC2(["US-002 Xem giỏ hàng nhóm theo seller"]) + UC3(["US-003 Sửa/xoá sản phẩm trong giỏ"]) + UC4(["US-004 Checkout & tách đơn theo seller"]) + UC5(["US-005 Nhập địa chỉ & xem phí ship theo seller"]) + UC6(["US-006 Checkout không cần tài khoản (Guest)"]) + UC7(["US-007 Thanh toán COD"]) + UC8(["US-008 Thanh toán VNPay/Momo"]) + end + + NGOAI1[["Catalog & Tìm kiếm — ngoài phạm vi"]] + NGOAI2[["VNPay/Momo — ngoài phạm vi (bên thứ 3)"]] + NGOAI3[["GHN/GHTK — ngoài phạm vi (bên thứ 3)"]] + NGOAI4[["Khuyến mãi & Loyalty — ngoài phạm vi (điểm tích hợp, OQ-004 đã đóng)"]] + + GUEST --- UC1 + GUEST --- UC2 + GUEST --- UC3 + GUEST --- UC4 + GUEST --- UC5 + GUEST --- UC6 + GUEST --- UC7 + GUEST --- UC8 + CUS --- UC1 + CUS --- UC2 + CUS --- UC3 + CUS --- UC4 + CUS --- UC5 + CUS --- UC7 + CUS --- UC8 + + UC1 --- NGOAI1 + UC5 --- NGOAI3 + UC8 --- NGOAI2 + UC4 -.-> NGOAI4 +``` + +*`Customer` không có US-006 riêng (Guest checkout không áp dụng cho tài khoản đã có). Liên +kết nét đứt `UC4 -.-> NGOAI4` = điểm tích hợp hiển thị kết quả coupon/điểm thưởng do module +khác tính (đã đóng `OQ-004`, xem `DEC-03`), module này chỉ gọi API áp dụng và hiển thị.* + +| Actor trong sơ đồ | Vai trò trong `RBAC` | Số US | +|---|---|---| +| Guest | ROLE-01 | 8 | +| Customer | ROLE-02 | 7 (không gồm US-006) | + +*Actor khớp `RBAC_CartCheckout_v1.0.md` §1.* + +## 1. Cây phân rã + +```mermaid +flowchart LR + RQ001["RQ-001 Giỏ hàng đa seller"] + RQ002["RQ-002 Tách đơn theo seller"] + RQ003["RQ-003 Thanh toán VNPay/Momo/COD"] + RQ004["RQ-004 Guest checkout"] + + E01["EPIC-01 Giỏ hàng & Checkout đa seller"] + E02["EPIC-02 Thanh toán đa kênh"] + + F01["FEAT-01 Quản lý giỏ hàng đa seller"] + F02["FEAT-02 Checkout & tách đơn theo seller"] + F03["FEAT-03 Thanh toán"] + + U01(["US-001"]) + U02(["US-002"]) + U03(["US-003"]) + U04(["US-004"]) + U05(["US-005"]) + U06(["US-006"]) + U07(["US-007"]) + U08(["US-008"]) + + RQ001 --> E01 + RQ002 --> E01 + RQ004 --> E01 + RQ003 --> E02 + + E01 --> F01 + E01 --> F02 + E02 --> F03 + + F01 --> U01 + F01 --> U02 + F01 --> U03 + F02 --> U04 + F02 --> U05 + F02 --> U06 + F03 --> U07 + F03 --> U08 +``` + +## 2. Epic + +| ID | Tên | Giá trị nghiệp vụ | RQ phủ | Feature | Ưu tiên | +|---|---|---|---|---|---| +| EPIC-01 | Giỏ hàng & Checkout đa seller | Cho phép khách mua từ nhiều seller trong một trải nghiệm thống nhất — điều kiện tiên quyết của mô hình marketplace | RQ-001, RQ-002, RQ-004 | FEAT-01, FEAT-02 | Must — ưu tiên hàng đầu theo `OQ-008` (đã đóng, xem `DEC-04`) | +| EPIC-02 | Thanh toán đa kênh | Thu tiền qua kênh phổ biến VN mà không lưu thẻ, giảm phạm vi PCI-DSS | RQ-003 | FEAT-03 | Must, nhưng nội bộ Feature có thứ tự con: COD trước, ví điện tử có thể lùi (xem `OQ-008`/`DEC-04` và §8) | + +## 3. Feature + +| ID | Tên | Epic | Mô tả một câu | US | MoSCoW | +|---|---|---|---|---|---| +| FEAT-01 | Quản lý giỏ hàng đa seller | EPIC-01 | Customer/Guest thêm, xem, sửa, xoá sản phẩm từ nhiều seller trong một giỏ hàng | US-001, US-002, US-003 | Must | +| FEAT-02 | Checkout & tách đơn theo seller | EPIC-01 | Customer/Guest xác nhận đặt hàng; hệ thống thu địa chỉ, tính phí ship, tách đơn theo seller, hỗ trợ cả Guest | US-004, US-005, US-006 | Must | +| FEAT-03 | Thanh toán | EPIC-02 | Customer/Guest thanh toán qua COD hoặc VNPay/Momo | US-007, US-008 | Must (US-007) — US-008 Must nhưng có thể triển khai sau theo `DEC-04` | + +## 4. User Story + +> Mẫu — **cả ba vế bắt buộc**: *Là ``, tôi muốn ``, để ` nghiệp vụ>`.* + +### US-001 — Thêm sản phẩm từ nhiều seller vào giỏ hàng + +| | | +|---|---| +| **Feature** | FEAT-01 | +| **RQ** | RQ-001 | +| **MoSCoW** | Must | +| **Vai trò** | Customer, Guest | +| **Phụ thuộc** | Không — US nền tảng đầu tiên | +| **BR áp dụng** | *(chưa có BR ràng buộc số lượng seller/sản phẩm tối đa trong giỏ — xem `OQ` mới nếu phát sinh ở GĐ3)* | +| **Ước lượng sơ bộ** | M | + +**Story:** +> Là Customer hoặc Guest, tôi muốn thêm sản phẩm từ nhiều seller khác nhau vào cùng một giỏ +> hàng, để tôi có thể mua sắm từ nhiều gian hàng mà không phải đặt hàng riêng lẻ với từng +> seller. + +**Phạm vi:** +- Trong: thêm `CartItem` từ bất kỳ seller nào vào `Cart` hiện có của khách (theo `customer_id` + hoặc `session_id` nếu Guest) +- Ngoài: kiểm tra tồn kho thời điểm checkout (thuộc US-004), tính giá sau khuyến mãi (thuộc + module Khuyến mãi/Loyalty theo `OQ-004`/`DEC-03`) + +**Điều kiện nghiệm thu mức thô:** +- Thêm được sản phẩm của seller A rồi seller B vào cùng một giỏ mà không bị lỗi/mất dữ liệu + của seller A +- Giỏ hàng của Guest được giữ lại theo phiên (thời hạn cụ thể — GĐ3 xác nhận, tham khảo SAD + §5.3.1 đề xuất 7 ngày cho Guest, cần Tech Lead xác nhận có áp dụng đúng con số này không) + +**INVEST:** + +| I | N | V | E | S | T | Ghi chú nếu không đạt | +|---|---|---|---|---|---|---| +| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | + +### US-002 — Xem giỏ hàng nhóm theo seller + +| | | +|---|---| +| **Feature** | FEAT-01 | +| **RQ** | RQ-001 | +| **MoSCoW** | Must | +| **Vai trò** | Customer, Guest | +| **Phụ thuộc** | US-001 (phải có sản phẩm trong giỏ trước) | +| **BR áp dụng** | *(chưa có — mục hiển thị thuần tuý)* | +| **Ước lượng sơ bộ** | M | + +**Story:** +> Là Customer hoặc Guest, tôi muốn xem giỏ hàng của mình được **nhóm hiển thị theo từng +> seller** kèm tổng tiền từng nhóm, để tôi biết rõ mình đang mua gì của ai trước khi quyết định +> đặt hàng. + +**Phạm vi:** +- Trong: hiển thị màn hình Giỏ hàng (FR-05, ưu tiên của lần chạy này) nhóm `CartItem` theo + `seller_id`, tổng tiền từng nhóm, tổng tiền toàn giỏ +- Ngoài: phí vận chuyển (chưa biết tới lúc checkout — thuộc US-005), áp dụng coupon/điểm + thưởng (module khác, `OQ-004`/`DEC-03`) + +**Điều kiện nghiệm thu mức thô:** +- Giỏ hàng có sản phẩm của 3 seller hiển thị đúng 3 nhóm, mỗi nhóm đúng tổng tiền của nhóm đó +- Giỏ hàng rỗng hiển thị trạng thái rỗng rõ ràng (text cụ thể — GĐ3, W5) + +**INVEST:** + +| I | N | V | E | S | T | Ghi chú nếu không đạt | +|---|---|---|---|---|---|---| +| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | + +### US-003 — Sửa số lượng / xoá sản phẩm trong giỏ hàng + +| | | +|---|---| +| **Feature** | FEAT-01 | +| **RQ** | RQ-001 | +| **MoSCoW** | Must | +| **Vai trò** | Customer, Guest | +| **Phụ thuộc** | US-001 | +| **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, xem GĐ3)* | +| **Ước lượng sơ bộ** | S | + +**Story:** +> Là Customer hoặc Guest, tôi muốn cập nhật số lượng hoặc xoá sản phẩm khỏi giỏ hàng, để tôi +> kiểm soát đúng những gì mình sẽ mua trước khi checkout. + +**Phạm vi:** +- Trong: sửa `quantity`, xoá `CartItem` khỏi `Cart` +- Ngoài: 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, xem `OQ-009`) + +**Điều kiện nghiệm thu mức thô:** +- Sửa số lượng thành 0 ⇒ hành vi (xoá luôn hay chặn) — **chưa chốt, cần OQ ở GĐ3** +- Xoá hết sản phẩm của một seller ⇒ nhóm hiển thị theo seller đó biến mất (US-002) + +**INVEST:** + +| I | N | V | E | S | T | Ghi chú nếu không đạt | +|---|---|---|---|---|---|---| +| ✅ | ✅ | ✅ | ⚠️ | ✅ | ✅ | E: hành vi khi sửa số lượng về 0 chưa rõ — cần làm rõ ở GĐ3 (AC) | + +### US-004 — Checkout & tự động tách đơn theo seller + +| | | +|---|---| +| **Feature** | FEAT-02 | +| **RQ** | RQ-002 | +| **MoSCoW** | Must | +| **Vai trò** | Customer, Guest | +| **Phụ thuộc** | US-001, US-002, US-005 (cần địa chỉ + phí ship trước khi xác nhận cuối) | +| **BR áp dụng** | BR-CART-01 (tách đơn theo seller), BR-CART-02 (giữ tồn kho — chống oversell) | +| **Ước lượng sơ bộ** | L | + +**Story:** +> Là Customer hoặc Guest, tôi muốn xác nhận đặt hàng và để hệ thống **tự động tách giỏ hàng đa +> seller thành các đơn con riêng theo từng seller**, để mỗi seller nhận và xử lý đúng phần đơn +> của mình mà không thấy dữ liệu của seller khác. + +**Phạm vi:** +- Trong: kiểm tra tồn kho, tạo `Order` (cha) + nhiều `OrderSeller` (con) + `OrderItem` +- Ngoài: xử lý đơn sau khi tạo (đóng gói, giao hàng — FR-19/FR-26, ngoài phạm vi module) + +**Điều kiện nghiệm thu mức thô:** +- Giỏ hàng có N seller ⇒ tạo đúng N `OrderSeller` con **(giả định `ASM-03` chưa xác minh — + `OQ-011`, phải xác nhận trước khi coi AC này là chốt ở GĐ3)** +- Không đủ tồn kho một sản phẩm bất kỳ ⇒ chặn tạo đơn, báo lỗi, giữ nguyên giỏ hàng + (BR-CART-02) + +**INVEST:** + +| I | N | V | E | S | T | Ghi chú nếu không đạt | +|---|---|---|---|---|---|---| +| ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ⚠️ | E: phụ thuộc `OQ-009` (giá/tồn kho thay đổi) và `OQ-011` (ASM-03 tách N seller); S: đây là US lõi phức tạp nhất, có thể cần tách thêm ở GĐ3 theo luồng thành công/luồng lỗi (W4); T: điều kiện biên "đủ tồn kho" cần dữ liệu test cụ thể ở GĐ3 | + +### US-005 — Nhập địa chỉ & xem phí vận chuyển ước tính theo từng seller + +| | | +|---|---| +| **Feature** | FEAT-02 | +| **RQ** | RQ-002, RQ-001 (đóng góp làm rõ chi phí giỏ đa seller — `RISK-04`) | +| **MoSCoW** | Must | +| **Vai trò** | Customer, Guest | +| **Phụ thuộc** | US-002 | +| **BR áp dụng** | *(chưa có BR tính phí ship cụ thể — thuộc tích hợp GHN/GHTK, `ASM-02` chưa xác minh)* | +| **Ước lượng sơ bộ** | L | + +**Story:** +> Là Customer hoặc Guest, tôi muốn nhập/chọn địa chỉ giao hàng và xem phí vận chuyển ước tính +> theo từng đơn con seller **trước khi** xác nhận đặt hàng, để tôi biết chính xác tổng số tiền +> phải trả và không bị bất ngờ ở bước cuối (giải quyết điểm đau `P3`/`RISK-04` ở `PROCESS` B3). + +**Phạm vi:** +- Trong: thu thập địa chỉ giao hàng, gọi tích hợp GHN/GHTK để ước tính phí/thời gian giao theo + từng seller +- Ngoài: tạo vận đơn thật (chỉ xảy ra sau khi đơn đã `confirmed`, thuộc FR-26) + +**Điều kiện nghiệm thu mức thô:** +- Địa chỉ ngoài vùng phục vụ của GHN/GHTK cho một seller cụ thể ⇒ hành vi hiển thị — **chưa + chốt, cần OQ ở GĐ3** +- Nếu `ASM-02` sai (API không khả dụng thời gian thực) ⇒ phương án dự phòng (ước tính tĩnh) + — **chưa chốt, chặn bởi xác minh ASM-02 ở GĐ1/RISK** + +**INVEST:** + +| I | N | V | E | S | T | Ghi chú nếu không đạt | +|---|---|---|---|---|---|---| +| ✅ | ✅ | ✅ | ⚠️ | ✅ | ⚠️ | E/T: phụ thuộc kết quả xác minh `ASM-02` (GHN/GHTK) — chưa có, ảnh hưởng trực tiếp cách viết AC ở GĐ3 | + +### US-006 — Checkout không cần tạo tài khoản (Guest) + +| | | +|---|---| +| **Feature** | FEAT-02 | +| **RQ** | RQ-004 | +| **MoSCoW** | Must | +| **Vai trò** | Guest | +| **Phụ thuộc** | US-004, US-005 | +| **BR áp dụng** | BR-CART-07 (điều kiện tối thiểu cho Guest checkout) | +| **Ước lượng sơ bộ** | M | + +**Story:** +> Là Guest (khách vãng lai), tôi muốn hoàn tất checkout mà không cần tạo tài khoản trước, để +> tôi không phải dừng lại đăng ký tài khoản khi chỉ muốn mua một lần. + +**Phạm vi:** +- Trong: cho phép hoàn tất toàn bộ luồng US-001…US-005, US-007/US-008 mà không yêu cầu đăng + nhập/đăng ký +- Ngoài: chuyển đổi giỏ hàng Guest thành tài khoản Customer sau khi mua (nếu có — thuộc FR-01, + ngoài phạm vi module này) + +**Điều kiện nghiệm thu mức thô:** +- Guest hoàn tất được toàn bộ luồng checkout mà không bị chặn bởi bước "đăng nhập bắt buộc" +- Guest phải cung cấp tối thiểu thông tin liên hệ nào (họ tên, SĐT, email?) — **chưa chốt, xem + `BR-CART-07`, cần GĐ3 xác nhận danh sách field bắt buộc** + +**INVEST:** + +| I | N | V | E | S | T | Ghi chú nếu không đạt | +|---|---|---|---|---|---|---| +| ✅ | ✅ | ✅ | ⚠️ | ✅ | ✅ | E: danh sách field bắt buộc tối thiểu cho Guest chưa chốt — xem `BR-CART-07`, để GĐ3 làm bảng field | + +### US-007 — Thanh toán khi nhận hàng (COD) + +| | | +|---|---| +| **Feature** | FEAT-03 | +| **RQ** | RQ-003 | +| **MoSCoW** | Must | +| **Vai trò** | Customer, Guest | +| **Phụ thuộc** | US-004 | +| **BR áp dụng** | BR-CART-03 (giới hạn giá trị đơn COD — **chưa chốt, `OQ-006`**), BR-CART-04 | +| **Ước lượng sơ bộ** | M | + +**Story:** +> Là Customer hoặc Guest, tôi muốn thanh toán đơn hàng bằng hình thức thanh toán khi nhận hàng +> (COD), để tôi hoàn tất mua sắm mà không cần thanh toán trước qua kênh điện tử. + +*Ưu tiên triển khai trước US-008 theo xác nhận của PO ở `OQ-008` — xem `DEC-04` và §8.* + +**Phạm vi:** +- Trong: chọn COD làm phương thức thanh toán, tạo `Payment` gắn với `Order` +- Ngoài: thu tiền thật lúc giao hàng (thuộc vận hành giao nhận, FR-26) + +**Điều kiện nghiệm thu mức thô:** +- Chọn COD ⇒ đơn được tạo mà không cần chuyển hướng ra ngoài hệ thống +- Đơn giá trị vượt ngưỡng (nếu PO chốt `BR-CART-03`) ⇒ hành vi chặn/cảnh báo — **chưa chốt, + `OQ-006`** + +**INVEST:** + +| I | N | V | E | S | T | Ghi chú nếu không đạt | +|---|---|---|---|---|---|---| +| ✅ | ✅ | ✅ | ⚠️ | ✅ | ⚠️ | E/T: phụ thuộc `OQ-006` (giới hạn COD) và `OQ-013` (Payment.status COD ghi nhận thế nào) — chưa có câu trả lời, AC ở GĐ3 chưa viết được đầy đủ nếu hai OQ này còn mở | + +### US-008 — Thanh toán qua VNPay/Momo + +| | | +|---|---| +| **Feature** | FEAT-03 | +| **RQ** | RQ-003 | +| **MoSCoW** | Must (theo `BRIEF`), nhưng **có thể lùi triển khai sau US-007** theo `OQ-008`/`DEC-04` | +| **Vai trò** | Customer, Guest | +| **Phụ thuộc** | US-004 | +| **BR áp dụng** | BR-CART-04, BR-CART-05 (không lưu thẻ), BR-CART-06 (xác thực webhook — phụ thuộc `ASM-01`) | +| **Ước lượng sơ bộ** | XL | + +**Story:** +> Là Customer hoặc Guest, tôi muốn thanh toán đơn hàng qua VNPay hoặc Momo mà không phải +> nhập/lưu thông tin thẻ trên hệ thống sàn, để tôi dùng đúng ví điện tử quen thuộc mà không lộ +> thông tin thẻ cho sàn. + +**Phạm vi:** +- Trong: khởi tạo giao dịch, chuyển hướng cổng thanh toán, nhận xác nhận qua webhook +- Ngoài: hoàn tiền qua VNPay/Momo (thuộc FR-25 đổi trả/tranh chấp, ngoài phạm vi module này), + cơ chế đối soát bù đầy đủ (thuộc thiết kế chi tiết Payment Service ở GĐ3) + +**Điều kiện nghiệm thu mức thô:** +- Thanh toán thành công ⇒ webhook cập nhật `Payment.status = success`, `OrderSeller.status` + chuyển sang `confirmed` +- Webhook không tới đúng hạn ⇒ hành vi hiển thị cho khách — **chưa chốt, phụ thuộc `ASM-01`/ + `OQ-010` và cơ chế đối soát bù (ngoài phạm vi US module này, xem `PROCESS` B9)** + +**INVEST:** + +| I | N | V | E | S | T | Ghi chú nếu không đạt | +|---|---|---|---|---|---|---| +| ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ⚠️ | E/S/T: đây là US phụ thuộc nhiều nhất vào xác nhận bên ngoài (`ASM-01`, sandbox VNPay/Momo) — nếu tới GĐ3 vẫn chưa xác minh được, đề xuất tách nhỏ US-008 theo từng cổng thanh toán (VNPay riêng, Momo riêng) để không chặn nhau | + +--- + +## 5. Bảng tổng hợp US + +| ID | Tên | Feature | RQ | MoSCoW | Ước lượng | Phụ thuộc | INVEST | Trạng thái | +|---|---|---|---|---|---|---|---|---| +| US-001 | Thêm sản phẩm đa seller vào giỏ | FEAT-01 | RQ-001 | Must | M | — | ✅ | Draft | +| US-002 | Xem giỏ hàng nhóm theo seller | FEAT-01 | RQ-001 | Must | M | US-001 | ✅ | Draft | +| US-003 | Sửa/xoá sản phẩm trong giỏ | FEAT-01 | RQ-001 | Must | S | US-001 | ⚠️ | Draft | +| US-004 | Checkout & tách đơn theo seller | FEAT-02 | RQ-002 | Must | L | US-001, US-002, US-005 | ⚠️ | Draft | +| US-005 | Địa chỉ & phí ship theo seller | FEAT-02 | RQ-002, RQ-001 | Must | L | US-002 | ⚠️ | Draft | +| US-006 | Checkout không cần tài khoản (Guest) | FEAT-02 | RQ-004 | Must | M | US-004, US-005 | ⚠️ | Draft | +| US-007 | Thanh toán COD | FEAT-03 | RQ-003 | Must | M | US-004 | ⚠️ | Draft | +| US-008 | Thanh toán VNPay/Momo | FEAT-03 | RQ-003 | Must | XL | US-004 | ⚠️ | Draft | + +## 6. Đối chiếu ngược RQ → US *(bảng bắt buộc)* + +| RQ | Phát biểu ngắn | MoSCoW | US phủ | Trạng thái | +|---|---|---|---|---| +| RQ-001 | Giỏ hàng đa seller, một lần checkout | Must | US-001, US-002, US-003, US-005 | ✅ Đã phủ | +| RQ-002 | Tự động tách đơn theo seller | Must | US-004, US-005 | ✅ Đã phủ | +| RQ-003 | Thanh toán VNPay/Momo/COD, không lưu thẻ | Must | US-007, US-008 | ✅ Đã phủ | +| RQ-004 | Guest checkout không cần tài khoản | Must | US-006 | ✅ Đã phủ | + +**Kết luận:** 4/4 `RQ` của module này đã được phủ bởi ≥1 `US` — không có `RQ` bị bỏ quên. + +## 7. US không truy về RQ nào *(nghi ngờ scope creep)* + +| US | Từ đâu ra | Đề xuất | PO quyết | +|---|---|---|---| +| *(không có)* | — | — | — | + +**Kết luận:** cả 8 US đều truy về được một `RQ` cụ thể — không phát hiện scope creep trong +lần phân rã này. + +## 8. Đề xuất thứ tự thực hiện + +*BA đề xuất theo trả lời của PO ở `OQ-008` (xem `DEC-04`): giữ RQ-001/RQ-002 (giỏ hàng đa +seller, tách đơn) trước; RQ-003 phần ví điện tử (VNPay/Momo) có thể lùi sau COD nếu thiếu +thời gian. **PO chốt thứ tự cuối cùng.*** + +| Đợt | US | Lý do xếp trước | Kết quả demo được | +|---|---|---|---| +| 1 | US-001, US-002, US-003 | Nền tảng giỏ hàng — mọi US sau đều phụ thuộc | Thêm/xem/sửa giỏ hàng đa seller | +| 2 | US-004, US-005, US-006 | Lõi giao dịch — tách đơn theo seller (RQ-002, ưu tiên theo `OQ-008`), gồm cả luồng Guest | Checkout hoàn tất, tạo được `Order`/`OrderSeller`, hỗ trợ cả Guest và Customer | +| 3 | US-007 | COD không phụ thuộc tích hợp bên thứ ba phức tạp (VNPay/Momo) — làm trước theo `DEC-04` | Đặt hàng thanh toán COD đầu-cuối | +| 4 | US-008 | Phụ thuộc xác minh `ASM-01` + sandbox VNPay/Momo (`RISK` §3 phụ thuộc bên ngoài) — có thể lùi theo `DEC-04` nếu ASM-01 chưa xác minh kịp | Đặt hàng thanh toán qua ví điện tử đầu-cuối | + +## 9. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn US nào | +|---|---|---|---|---| +| OQ-006 | *(đã mở từ GĐ1)* Giới hạn giá trị đơn COD là gì? | PO, Kế toán đối soát | 2026-09-08 | US-007 | +| OQ-009 | Giá/tồn kho thay đổi giữa lúc thêm giỏ và checkout — tự động cập nhật hay chặn xác nhận lại? | PO + Tech Lead | 2026-09-08 | US-003, US-004 | +| OQ-010 | Xác nhận khả thi `ASM-01` (webhook VNPay/Momo) | Tech Lead | 2026-09-08 | US-008 | +| OQ-011 | Xác nhận `ASM-03` — giỏ N seller luôn tách đúng N đơn, không gộp | PO | 2026-09-08 | US-004 | +| OQ-013 | Với COD, `Payment.status` ghi "success" ngay khi xác nhận đơn hay giữ "pending" tới khi thực thu tiền? | Kế toán đối soát, PO | 2026-09-08 | US-007 | + +## 10. Ngoài phạm vi + +- Ước lượng story point chính thức → team dev ở buổi grooming +- Thiết kế màn hình, field spec chi tiết → GĐ3 `SRS` +- Áp dụng coupon/điểm thưởng (FR-13/FR-14) → module Khuyến mãi & Loyalty (điểm tích hợp đã + xác nhận qua `OQ-004`/`DEC-03`) +- Xử lý đơn sau khi tạo (đóng gói, giao hàng, đổi trả, khiếu nại) → module Quản lý đơn hàng +- Cơ chế đối soát bù thanh toán → thiết kế chi tiết Payment Service ở GĐ3, không phải US của + module này + +--- + +## 11. Tự chấm Gate G2 *(chấm ở mức RIGOR = standard — áp đúng checklist `workflow.md` §2, không bớt/thêm)* + +| # | Tiêu chí | ☐/✅ | Ghi chú | +|---|---|---|---| +| 1 | `PROCESS` có AS-IS và TO-BE, mỗi bước ghi ai làm, input/output, điều kiện rẽ nhánh | ✅ (có lưu ý) | AS-IS rút gọn đúng theo `greenfield` (A3–A5 thay vì A1/A2/A6, giải thích rõ lý do ở `PROCESS` §0); TO-BE (B1–B6) đầy đủ | +| 2 | `BACKLOG` phân rã tới `US-nnn`, mỗi US có value statement và ước lượng sơ bộ | ✅ | 8 US, đủ ba vế Là/muốn/để, có ước lượng S/M/L/XL | +| 3 | Mỗi `RQ-nnn` của G1 map được về ≥1 `US-nnn` | ✅ | 4/4 RQ đã phủ — xem §6 | +| 4 | `BR-nnn` đã chốt, không mâu thuẫn nhau | ☐ | `BR_CartCheckout_v1.0.md` đã liệt kê đủ rule nhưng **3 rule quan trọng chưa chốt được giá trị** (BR-CART-03 giới hạn COD, BR-CART-01 phụ thuộc xác minh ASM-03, BR-CART-06 phụ thuộc xác minh ASM-01) — đây là khoảng trống thật, đã ghi `OQ`, không tự chốt thay PO/Tech Lead | +| 5 | `RBAC` có ma trận vai trò × hành động; hành động phê duyệt/chốt sổ có bảng SoD | ✅ (có lưu ý) | Ma trận Guest/Customer đầy đủ; **không có hành động phê duyệt nội bộ nào trong phạm vi RQ-001…004** (tách đơn/thanh toán do hệ thống tự động, không có bước người duyệt) — đã ghi rõ lý do thay vì bỏ trống bảng SoD, xem `RBAC` §3 | +| 6 | `IMPACT` nêu module/dữ liệu/tích hợp bị ảnh hưởng và cách xử lý dữ liệu cũ | ✅ (rút gọn theo greenfield) | Theo `PROFILE` §"Hệ quả đã áp dụng": `IMPACT` rút gọn chỉ trọng tâm trục tích hợp (1.5); các trục khác ghi N/A kèm lý do (greenfield, module đầu tiên, không dữ liệu cũ) | +| 7 | Tech Lead xác nhận khả thi kỹ thuật và nêu ràng buộc | ☐ | **Chưa có** — không có Tech Lead thật tham gia lần chạy này (đúng như cảnh báo G1 chưa ký); các giả định kỹ thuật (`ASM-01`, `ASM-02`, `ASM-06`) vẫn ở trạng thái "chưa xác minh" | +| 8 | `ba-traceability` báo coverage RQ→US ≥ 100% | ☐ | Chưa chạy `ba-traceability` trong lần này — khuyến nghị chạy trước khi trình G2, theo đúng nhắc nhở cuối `SKILL.md` | + +**Kết luận tự chấm:** G2 **chưa đủ điều kiện ký chính thức** — 4/8 tiêu chí còn ☐, chủ yếu vì +thiếu xác nhận thật từ Tech Lead (đúng hệ quả của việc G1 cũng chưa ký thật, xem ngoại lệ gate +ở đầu tài liệu) và chưa chạy `ba-traceability`. Đây là kết quả *tự chấm*, không phải kết luận +gate — PO + Tech Lead phải xem lại trước khi ký. + +## 12. Quy tắc viết W1–W13 + +| W1 | W2 | W3 | W4 | W5 | W6 | W7 | W8 | W9 | W10 | W11 | W12 | W13 | +|---|---|---|---|---|---|---|---|---|---|---|---|---| +| ✅ | ✅ (có lưu ý) | N/A (chưa có field/con số cụ thể — thuộc GĐ3) | N/A (GĐ2 chưa viết AC Given/When/Then chi tiết) | N/A (chưa có text hiển thị — GĐ3) | ✅ (xem `BR` §3) | N/A (chưa có bảng field — GĐ3) | ✅ | ✅ | ✅ | N/A (chưa có wireframe ở GĐ2) | ✅ | ✅ | + +Ghi chú W2: quét `nhanh|mượt|thân thiện|v\.v|phù hợp|tương ứng|nên |có thể ` trên 5 file GĐ2 +(`PROCESS`, `BACKLOG`, `BR`, `RBAC`, `IMPACT`) — 27 dòng khớp trước khi soát, đã rà từng dòng: +- Hai dòng ban đầu dùng "nhanh" trong vế **để** của US-006/US-008 đã được **sửa lại** (không + còn "mua nhanh"/"thanh toán nhanh") để không mô tả giá trị bằng tính từ mơ hồ — thay bằng mô + tả hành vi cụ thể hơn (không phải dừng lại đăng ký; dùng đúng ví điện tử quen thuộc mà không + lộ thông tin thẻ). Grep lại sau khi sửa: 0 kết quả cho riêng từ khoá `nhanh` trong toàn bộ + 5 file. +- Các dòng còn lại (25 dòng) đều thuộc hai nhóm: (a) trích dẫn/diễn giải rủi ro theo đúng công + thức chuẩn của `RISK` GĐ1 ("có thể xảy ra…"), hoặc (b) mô tả điều mà PO **có thể** cân nhắc + như một tuỳ chọn thương mại/kỹ thuật chưa chốt (VD trợ giá phí ship ở `PROCESS` B3, thứ tự + triển khai US-008 "có thể lùi" theo `DEC-04`) — đây là ngôn ngữ mô tả **tuỳ chọn có nguồn** + (`RISK`, `DEC-04`), không phải một phát biểu `RQ`/`AC` né tránh quyết định bằng từ mơ hồ. +- Không có dòng nào dùng các từ này để thay thế cho một con số/quyết định còn thiếu — mọi chỗ + thiếu số đều có `OQ` riêng (xem §9, §13). Đã quét `TBD|TODO|\?\?\?` — 0 kết quả ngoài chính + dòng giải thích quy tắc này. + +## 13. OQ mở tổng hợp của lần chạy GĐ2 này + +| ID | Câu hỏi | Hỏi ai | Chặn gì | Nguồn | +|---|---|---|---|---| +| OQ-006 | *(GĐ1, nhắc lại)* Giới hạn giá trị đơn COD | PO, Kế toán đối soát | BR-CART-03, US-007 | `RISK_CartCheckout_v1.0.md` | +| OQ-009 | Giá/tồn kho đổi giữa thêm giỏ và checkout — tự động cập nhật hay chặn? | PO + Tech Lead | US-003, US-004 | `PROCESS` A5 (E2) | +| OQ-010 | Xác nhận khả thi `ASM-01` (webhook VNPay/Momo) | Tech Lead | BR-CART-06, US-008 | `PROCESS` A3 (P2) | +| OQ-011 | Xác nhận `ASM-03` — luôn tách đúng N đơn theo N seller | PO | BR-CART-01, US-004 | `RISK_CartCheckout_v1.0.md` ASM-03 | +| OQ-012 | Guest có giới hạn giá trị đơn hoặc cần OTP xác thực cho đơn giá trị cao? | PO, Bảo mật | RBAC §4, RISK-01 phương án (b) | `RBAC_CartCheckout_v1.0.md` | +| OQ-013 | Payment.status của COD ghi "success" ngay hay giữ "pending" tới khi thực thu? | Kế toán đối soát, PO | US-007, `BR_CartCheckout` §3 | `BR_CartCheckout_v1.0.md` | + +*Đã đồng bộ vào `00-index/OQ_e-commerce.md` — xem sổ toàn dự án để theo dõi trạng thái đóng/mở.* diff --git a/ba-output/e-commerce/02-analysis/BR_CartCheckout_v1.0.md b/ba-output/e-commerce/02-analysis/BR_CartCheckout_v1.0.md new file mode 100644 index 0000000..e047f41 --- /dev/null +++ b/ba-output/e-commerce/02-analysis/BR_CartCheckout_v1.0.md @@ -0,0 +1,535 @@ +# BR — Business Rules — Giỏ hàng & Checkout (e-commerce) + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-2-analysis) | +| **Status** | 🟡 Draft | +| **Approved by** | — | +| **Profile** | screen · greenfield · standard | +| **Source** | `01-discovery/BRIEF_CartCheckout_v1.0.md` · `01-discovery/RISK_CartCheckout_v1.0.md` · `PROCESS_CartCheckout_v1.0.md` · `BACKLOG_CartCheckout_v1.0.md` · `e-commerce/docs/sections/06-luong-xu-ly.md` §6.4 (BR-01, BR-02, tham chiếu kỹ thuật, không phải nguồn quyết định BA) · `e-commerce/docs/sections/05-thiet-ke-du-lieu.md` §5.2.3–5.2.4 (tham chiếu entity, không chép schema vật lý) | +| **Scope** | Module Giỏ hàng & Checkout — RQ-001…RQ-004 | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | CR | +|---|---|---|---|---| +| 1.0 | 2026-09-08 | BA (qua skill ba-2-analysis) | Bản đầu — 8 business rule, ERD, 2 vòng đời trạng thái | — | + +--- + +> ⚠️ **Ngoại lệ gate G1** — xem cảnh báo đầy đủ ở đầu `PROCESS_CartCheckout_v1.0.md` và `DEC-02` +> ở `00-index/DECISION_e-commerce.md`. Ba quy tắc dưới đây (`BR-CART-01`, `BR-CART-03`, +> `BR-CART-06`) phụ thuộc giả định **chưa được PO/Tech Lead xác nhận** — không được coi là đã +> chốt cho tới khi `OQ` liên quan được trả lời. + +## 1. Danh sách quy tắc + +### BR-CART-01 — Tách đơn hàng theo seller khi checkout + +| | | +|---|---| +| **Loại** | Quy trình / Tính toán | +| **Nguồn** | 🟠 Quyết định mô hình kinh doanh đã chốt (marketplace đa seller) — `00-project-brief.md` vòng 1; **cơ chế tách chi tiết ("luôn đúng N đơn cho N seller, không gộp") chưa được PO xác nhận riêng cho module này** (`ASM-03`, chưa xác minh) | +| **Người chốt** | STK-01 (PO sàn) — *ở mức mô hình kinh doanh*; cơ chế tách chi tiết **chưa chốt**, xem `OQ-011` | +| **RQ** | RQ-002 | +| **US áp dụng** | US-004 | +| **Khi vi phạm** | Chặn — không tạo được `Order` nếu không nhóm được `CartItem` theo `seller_id` hợp lệ | +| **Có ngoại lệ** | Chưa xác định — nếu PO xác nhận có ngoại lệ gộp seller (VD cùng kho vận), rule này phải viết lại hoàn toàn (xem `ASM-03`) | +| **Có thể đổi trong 1 năm** | Có — đây là quyết định thiết kế nghiệp vụ, không phải quy định pháp luật | + +**Phát biểu:** +> Khi Customer/Guest xác nhận đặt hàng (checkout), hệ thống nhóm `CartItem` theo `seller_id` +> và tạo một `OrderSeller` (đơn con) riêng cho mỗi nhóm; `Order` (đơn cha) là tập hợp các +> `OrderSeller` con, mỗi `OrderSeller` có vòng đời trạng thái độc lập (xem §3). + +**Điều kiện áp dụng:** Áp dụng cho mọi giỏ hàng có ≥1 sản phẩm hợp lệ (đủ tồn kho theo +`BR-CART-02`) tại thời điểm checkout, không phân biệt Customer hay Guest. + +**Ví dụ đúng / sai:** + +| Trường hợp | Dữ liệu | Kết quả mong đợi | +|---|---|---| +| Hợp lệ | Giỏ có 2 sản phẩm của seller A, 1 sản phẩm của seller B | Tạo 1 `Order` + 2 `OrderSeller` (A, B) | +| Biên | Giỏ có sản phẩm của 1 seller duy nhất | Tạo 1 `Order` + 1 `OrderSeller` — vẫn đúng cấu trúc cha-con dù chỉ 1 con | +| Chưa xác định | Hai seller cùng thuộc một kho vận trung tâm (nếu có mô hình này trong tương lai) | **Chưa có quy tắc — `OQ-011`, không tự giả định là gộp hay không gộp** | + +--- + +### BR-CART-02 — Giữ tồn kho khi checkout (chống oversell) + +| | | +|---|---| +| **Loại** | Điều kiện hành động | +| **Nguồn** | 🟠 Chính sách vận hành (bảo vệ trải nghiệm khách + quyền lợi seller khỏi bán vượt tồn kho); cơ chế kỹ thuật tham khảo SAD §6.4 BR-02, cần Tech Lead xác nhận khả thi | +| **Người chốt** | *(chưa có Tech Lead thật xác nhận — xem ngoại lệ gate)* | +| **RQ** | RQ-001, RQ-002 | +| **US áp dụng** | US-004 | +| **Khi vi phạm** | Chặn — trả lỗi, không tạo `Order`, giữ nguyên giỏ hàng để khách điều chỉnh | +| **Có ngoại lệ** | Không | +| **Có thể đổi trong 1 năm** | Có — là quyết định vận hành, có thể tinh chỉnh ngưỡng/cơ chế khi có dữ liệu tải thật | + +**Phát biểu:** +> Tại thời điểm checkout, hệ thống phải kiểm tra tồn kho khả dụng cho từng sản phẩm trong +> giỏ hàng; nếu bất kỳ sản phẩm nào không đủ số lượng yêu cầu, hệ thống chặn việc tạo đơn và +> báo lỗi thay vì tạo đơn với số lượng vượt tồn kho thực có. + +**Điều kiện áp dụng:** Áp dụng cho mọi lần `POST /checkout` (theo tên gọi tham chiếu SAD), +không phân biệt Customer/Guest, không phân biệt phương thức thanh toán. + +**Ví dụ đúng / sai:** + +| Trường hợp | Dữ liệu | Kết quả mong đợi | +|---|---|---| +| Hợp lệ | Tồn kho khả dụng 10, khách mua 3 | Cho qua, tạo đơn | +| Vi phạm | Tồn kho khả dụng 2, khách mua 3 | Chặn, báo lỗi mã `E-CART-0001` *(mã cụ thể — GĐ3 xác nhận)* | +| Biên | Tồn kho khả dụng đúng bằng số lượng yêu cầu | Cho qua (biên `>=`, không phải `>`) | + +--- + +### BR-CART-03 — Giới hạn giá trị đơn hàng thanh toán COD + +| | | +|---|---| +| **Loại** | Điều kiện hành động | +| **Nguồn** | 🟠 Chính sách rủi ro tài chính (đề xuất, chưa có chính sách chính thức) | +| **Người chốt** | ☐ **Chưa chốt** — xem `OQ-006` | +| **RQ** | RQ-003 | +| **US áp dụng** | US-007 | +| **Khi vi phạm** | *(Chưa xác định — phụ thuộc phương án PO chọn)* | +| **Có ngoại lệ** | *(Chưa xác định)* | +| **Có thể đổi trong 1 năm** | Có | + +**Phát biểu:** +> 🔴 **Chưa có phát biểu chính thức.** `ASM-05` (GĐ1) giả định "COD không có giới hạn giá trị +> đơn ở MVP", nhưng `RISK-01` (🔴 mức cao) cảnh báo hệ quả nếu giả định này sai: seller chịu +> phí hoàn hàng khi khách từ chối một phần đơn COD đa seller. BA **không tự đặt một con số** +> (VD "giới hạn 5.000.000đ") vì đây là quyết định tài chính/rủi ro, phải do PO quyết — xem +> `OQ-006`. + +**Điều kiện áp dụng:** *(Chưa xác định — chờ PO chọn 1 trong 2 phương án dưới)* + +**Hai phương án BA đề xuất cho PO chọn (theo `RISK-01`):** + +| Phương án | Mô tả | Ưu điểm | Nhược điểm | +|---|---|---|---| +| (a) Giới hạn giá trị | Đặt ngưỡng tối đa cho tổng giá trị đơn COD đa seller — vượt ngưỡng phải chọn thanh toán trước | Đơn giản, dễ thực hiện | Cần chốt con số cụ thể, có thể chặn nhầm khách hàng hợp lệ giá trị cao | +| (b) Xác thực bổ sung | Yêu cầu OTP/đặt cọc cho đơn COD giá trị cao | Không chặn hoàn toàn, chỉ tăng ma sát ở đơn rủi ro | Phức tạp hơn kỹ thuật, cần tích hợp OTP | + +**Ví dụ đúng / sai:** *(chưa viết được — phụ thuộc phương án PO chọn)* + +--- + +### BR-CART-04 — Điều kiện chọn phương thức thanh toán + +| | | +|---|---| +| **Loại** | Điều kiện hành động | +| **Nguồn** | 🟠 Quyết định sản phẩm đã chốt (đối tác thanh toán mặc định VNPay/Momo/COD) | +| **Người chốt** | STK-01 (PO sàn), qua `00-project-brief.md` vòng 1 | +| **RQ** | RQ-003 | +| **US áp dụng** | US-007, US-008 | +| **Khi vi phạm** | Chặn — không cho tiếp tục checkout nếu chưa chọn phương thức | +| **Có ngoại lệ** | Không | +| **Có thể đổi trong 1 năm** | Có | + +**Phát biểu:** +> Customer và Guest đều được chọn một trong ba phương thức thanh toán: VNPay, Momo, hoặc COD, +> cho mọi đơn hàng trong phạm vi module này — không có ràng buộc phân biệt theo vai trò ở mức +> GĐ2 (GĐ3 xác nhận lại nếu phát sinh ràng buộc theo khu vực địa lý/giá trị đơn). + +**Điều kiện áp dụng:** Áp dụng tại bước B6 (`PROCESS_CartCheckout_v1.0.md`), sau khi `Order`/ +`OrderSeller` đã được tạo (BR-CART-01). + +**Ví dụ đúng / sai:** + +| Trường hợp | Dữ liệu | Kết quả mong đợi | +|---|---|---| +| Hợp lệ | Guest chọn COD | Cho qua | +| Hợp lệ | Customer chọn VNPay | Cho qua | +| Vi phạm | Không chọn phương thức nào, bấm tiếp tục | Chặn, báo lỗi bắt buộc chọn | + +--- + +### BR-CART-05 — Không lưu trữ thông tin thẻ thanh toán + +| | | +|---|---| +| **Loại** | Ràng buộc dữ liệu | +| **Nguồn** | 🔴 Tuân thủ pháp lý — phạm vi PCI-DSS thu hẹp, `NFR-05` (`e-commerce/docs/sections/02-phan-tich-yeu-cau.md`) | +| **Người chốt** | STK-01 (PO sàn) + yêu cầu kỹ thuật/pháp lý đã chốt ở cấp dự án | +| **RQ** | RQ-003 | +| **US áp dụng** | US-008 | +| **Khi vi phạm** | Chặn — về mặt thiết kế, hệ thống sàn không được có trường lưu số thẻ/CVV ở bất kỳ đâu trong phạm vi module này | +| **Có ngoại lệ** | Không | +| **Có thể đổi trong 1 năm** | Không — đây là ràng buộc pháp lý/hợp đồng với đối tác thanh toán, không tự ý thay đổi | + +**Phát biểu:** +> Hệ thống sàn không được lưu trữ số thẻ thanh toán, mã CVV, hoặc bất kỳ dữ liệu thẻ nhạy cảm +> nào; mọi xử lý thẻ do VNPay/Momo thực hiện, hệ thống sàn chỉ lưu tham chiếu giao dịch +> (`gateway_transaction_ref`) và kết quả (thành công/thất bại). + +**Điều kiện áp dụng:** Áp dụng cho toàn bộ luồng thanh toán VNPay/Momo (US-008). Không áp dụng +cho COD (không có dữ liệu thẻ). + +**Ví dụ đúng / sai:** + +| Trường hợp | Dữ liệu | Kết quả mong đợi | +|---|---|---| +| Hợp lệ | Hệ thống chỉ lưu `gateway_transaction_ref`, `status`, `amount` | Đúng thiết kế | +| Vi phạm | Bất kỳ trường nào lưu số thẻ/CVV | Vi phạm nghiêm trọng — chặn ở review thiết kế GĐ3, không chờ tới UAT | + +--- + +### BR-CART-06 — Xác thực webhook xác nhận thanh toán + +| | | +|---|---| +| **Loại** | Điều kiện hành động (kỹ thuật, ảnh hưởng nghiệp vụ) | +| **Nguồn** | 🟢 Đề xuất kỹ thuật, cần Tech Lead xác nhận khả thi (`ASM-01` chưa xác minh) | +| **Người chốt** | ☐ **Chưa chốt** — xem `OQ-010` | +| **RQ** | RQ-003 | +| **US áp dụng** | US-008 | +| **Khi vi phạm** | Chặn — webhook không hợp lệ (chữ ký sai/quá hạn) thì không được cập nhật `Payment.status` | +| **Có ngoại lệ** | Không | +| **Có thể đổi trong 1 năm** | Có — là cơ chế kỹ thuật, có thể đổi nếu VNPay/Momo đổi API | + +**Phát biểu:** +> Hệ thống chỉ chấp nhận cập nhật `Payment.status = success` khi nhận được webhook có chữ ký +> hợp lệ từ VNPay/Momo **và** trong khoảng thời gian hợp lệ kể từ khi giao dịch được khởi tạo +> — 🔴 **con số cụ thể (bao nhiêu phút) chưa được PO/Tech Lead chốt cho module này**, chỉ có +> giả định kỹ thuật tham khảo (không phải quyết định BA) ở tài liệu SAD. + +**Điều kiện áp dụng:** Áp dụng cho US-008 (VNPay/Momo). Không áp dụng cho COD (US-007, không +có webhook). + +**Ví dụ đúng / sai:** + +| Trường hợp | Dữ liệu | Kết quả mong đợi | +|---|---|---| +| Hợp lệ | Webhook có chữ ký đúng, trong hạn | Cập nhật `Payment.status = success` | +| Vi phạm | Chữ ký sai | Từ chối, không cập nhật, ghi log | +| Chưa xác định | Webhook không tới trong thời gian chờ | Xem `PROCESS` B9 — cần cơ chế đối soát bù, ngoài phạm vi US module này | + +--- + +### BR-CART-07 — Điều kiện tối thiểu cho Guest checkout + +| | | +|---|---| +| **Loại** | Điều kiện hành động | +| **Nguồn** | 🟠 Quyết định sản phẩm đã chốt (Guest checkout được xác nhận ở cấp dự án) | +| **Người chốt** | STK-01 (PO sàn), qua `sections/01-tong-quan.md` §1.2 | +| **RQ** | RQ-004 | +| **US áp dụng** | US-006 | +| **Khi vi phạm** | Chặn — thiếu thông tin liên hệ tối thiểu thì không cho xác nhận đặt hàng | +| **Có ngoại lệ** | Không | +| **Có thể đổi trong 1 năm** | Có | + +**Phát biểu:** +> Guest phải cung cấp tối thiểu thông tin liên hệ và địa chỉ giao hàng để hoàn tất checkout mà +> không cần tạo tài khoản (không cần mật khẩu) — 🔴 **danh sách field bắt buộc cụ thể (họ tên, +> số điện thoại, email có bắt buộc không) chưa được chốt ở mức GĐ2**, để GĐ3 làm bảng field +> đầy đủ khi có thiết kế màn hình. + +**Điều kiện áp dụng:** Áp dụng cho toàn bộ luồng checkout khi `customer_id = null` (Guest). + +**Ví dụ đúng / sai:** + +| Trường hợp | Dữ liệu | Kết quả mong đợi | +|---|---|---| +| Hợp lệ | Guest điền đủ trường bắt buộc (danh sách — GĐ3 xác nhận) | Cho qua | +| Vi phạm | Thiếu trường bắt buộc | Chặn, báo lỗi field cụ thể (GĐ3) | + +## 2. Bảng tổng hợp + +| ID | Tên | Loại | Nguồn | US áp dụng | Khi vi phạm | Mã lỗi (GĐ3) | +|---|---|---|---|---|---|---| +| BR-CART-01 | Tách đơn theo seller | Quy trình/Tính toán | 🟠 (cơ chế chi tiết chưa chốt — `OQ-011`) | US-004 | Chặn | E-CART-00nn | +| BR-CART-02 | Giữ tồn kho khi checkout | Điều kiện hành động | 🟠 | US-004 | Chặn | E-CART-0001 | +| BR-CART-03 | Giới hạn giá trị đơn COD | Điều kiện hành động | ☐ Chưa chốt — `OQ-006` | US-007 | *(chưa xác định)* | *(chưa xác định)* | +| BR-CART-04 | Điều kiện chọn phương thức thanh toán | Điều kiện hành động | 🟠 | US-007, US-008 | Chặn | E-CART-00nn | +| BR-CART-05 | Không lưu thông tin thẻ | Ràng buộc dữ liệu | 🔴 | US-008 | Chặn (thiết kế) | N/A — chặn ở review thiết kế | +| BR-CART-06 | Xác thực webhook thanh toán | Điều kiện hành động | 🟢 (chưa chốt — `OQ-010`) | US-008 | Chặn | E-CART-00nn | +| BR-CART-07 | Điều kiện tối thiểu Guest checkout | Điều kiện hành động | 🟠 (field cụ thể — GĐ3) | US-006 | Chặn | E-CART-00nn | + +## 3. Vòng đời trạng thái + +*Bắt buộc với mọi thực thể có trạng thái (quy tắc W6). Ba thực thể có trạng thái trong phạm vi +module này: `CART`, `ORDER_SELLER` (chỉ đoạn khởi tạo — phần sau thuộc module khác), `PAYMENT`.* + +### Thực thể: `CART` + +**Bốn câu phải trả lời:** + +| Câu hỏi | Trả lời | +|---|---| +| Trạng thái khởi tạo | `active` (Đang hoạt động) | +| Trạng thái cuối (không đi tiếp được) | `converted` (Đã chuyển thành đơn) hoặc `abandoned` (Bỏ quên) | +| Từ trạng thái cuối quay lại được không | Không — giỏ hàng mới phải được tạo lại | +| Trạng thái nào cho phép xoá | Chỉ `active` — Customer/Guest được xoá từng `CartItem`, không "xoá" bản ghi `Cart` (chỉ chuyển trạng thái) | + +**Sơ đồ:** + +```mermaid +stateDiagram-v2 + state "Đang hoạt động" as Active + state "Đã chuyển thành đơn" as Converted + state "Bỏ quên" as Abandoned + + [*] --> Active + Active --> Converted: Checkout thành công (BR-CART-01, BR-CART-02) + Active --> Abandoned: Hết hạn phiên (tự động, hệ thống) + Converted --> [*] + Abandoned --> [*] +``` + +**Bảng chuyển trạng thái:** + +| # | Nguồn | Sự kiện | Điều kiện | Đích | Ai được làm | BR | Ghi vết | +|---|---|---|---|---|---|---|---| +| 1 | Active | Checkout | Đủ tồn kho tất cả item (BR-CART-02) | Converted | Customer/Guest | BR-CART-01, BR-CART-02 | ✅ (thông qua `Order` được tạo) | +| 2 | Active | Hết hạn phiên | Thời hạn cụ thể — **chưa chốt ở GĐ2, tham khảo kỹ thuật SAD §5.3.1 (Guest 7 ngày/Customer 30 ngày), cần Tech Lead xác nhận áp dụng đúng con số này** | Abandoned | Hệ thống (tự động) | — | ➖ Không ghi vết chi tiết (chấp nhận mất theo thiết kế kỹ thuật tham khảo) | + +**Chuyển trạng thái KHÔNG được phép:** + +| Từ | Sang | Vì sao cấm | +|---|---|---| +| Converted | Active | Mất dấu vết đơn đã tạo — giỏ đã chuyển thành đơn không thể "mở lại" để sửa tiếp | +| Abandoned | Converted | Giỏ đã hết hạn — khách phải thêm lại sản phẩm vào giỏ mới, không checkout trực tiếp từ giỏ bỏ quên | + +### Thực thể: `ORDER_SELLER` *(chỉ đoạn khởi tạo trong phạm vi module này)* + +🔴 Vòng đời đầy đủ của `OrderSeller` (packed/shipped/delivered/returned…) thuộc module Quản lý +đơn hàng (FR-08/FR-19, ngoài phạm vi RQ-001…004). Phần dưới đây **chỉ mô tả đoạn khởi tạo** mà +module Giỏ hàng & Checkout chịu trách nhiệm, để BA GĐ3 của module kế tiếp kế thừa đúng điểm nối. + +**Bốn câu phải trả lời (trong phạm vi module này):** + +| Câu hỏi | Trả lời | +|---|---| +| Trạng thái khởi tạo | `pending` (Chờ thanh toán) | +| Trạng thái cuối (trong phạm vi module này) | `confirmed` (Đã xác nhận — bàn giao module khác) hoặc `cancelled` (Đã huỷ) | +| Từ trạng thái cuối quay lại được không | Không, trong phạm vi module này (huỷ sau `confirmed` là nghiệp vụ FR-08, ngoài phạm vi) | +| Trạng thái nào cho phép xoá | Không — không cho phép xoá `OrderSeller`, chỉ chuyển trạng thái (bắt buộc giữ dấu vết tài chính/đối soát) | + +**Sơ đồ:** + +```mermaid +stateDiagram-v2 + state "Chờ thanh toán" as Pending + state "Đã xác nhận" as Confirmed + state "Đã huỷ" as Cancelled + + [*] --> Pending: Checkout tạo đơn con (BR-CART-01) + Pending --> Confirmed: Thanh toán thành công (COD hoặc webhook VNPay/Momo — BR-CART-06) + Pending --> Cancelled: Thanh toán thất bại/hết hạn chờ, hoặc khách huỷ trước khi thanh toán + Confirmed --> [*]: Bàn giao module Quản lý đơn hàng seller (FR-19, ngoài phạm vi) + Cancelled --> [*] +``` + +**Bảng chuyển trạng thái:** + +| # | Nguồn | Sự kiện | Điều kiện | Đích | Ai được làm | BR | Ghi vết | +|---|---|---|---|---|---|---|---| +| 1 | Pending | Thanh toán COD | Đơn không vượt giới hạn COD (nếu `BR-CART-03` được chốt) | Confirmed | Hệ thống (tự động khi US-007 xác nhận) | BR-CART-03 (chưa chốt), BR-CART-04 | ✅ | +| 2 | Pending | Webhook thanh toán thành công | Webhook hợp lệ (BR-CART-06) | Confirmed | Hệ thống (tự động) | BR-CART-06 | ✅ | +| 3 | Pending | Thanh toán thất bại / hết hạn chờ | *(Thời hạn chờ cụ thể — chưa chốt, ngoài phạm vi US module này, xem `PROCESS` B9)* | Cancelled | Hệ thống (tự động) | — | ✅ | + +**Chuyển trạng thái KHÔNG được phép:** + +| Từ | Sang | Vì sao cấm | +|---|---|---| +| Confirmed | Pending | Mất dấu vết đơn đã xác nhận thanh toán — ảnh hưởng đối soát tài chính | +| Cancelled | Confirmed | Đơn đã huỷ không thể tự khôi phục — khách phải đặt lại từ đầu | + +### Thực thể: `PAYMENT` + +**Bốn câu phải trả lời:** + +| Câu hỏi | Trả lời | +|---|---| +| Trạng thái khởi tạo | `pending` | +| Trạng thái cuối | `success` hoặc `failed` *(trong phạm vi module này — `refunded` thuộc FR-25, ngoài phạm vi)* | +| Từ trạng thái cuối quay lại được không | Không, trong phạm vi module này | +| Trạng thái nào cho phép xoá | Không — bản ghi thanh toán không bao giờ bị xoá (bắt buộc giữ cho đối soát/kiểm toán) | + +**Sơ đồ:** + +```mermaid +stateDiagram-v2 + state "Chờ xử lý" as Pending + state "Thành công" as Success + state "Thất bại" as Failed + + [*] --> Pending: Khởi tạo thanh toán (US-007/US-008) + Pending --> Success: COD xác nhận / webhook VNPay-Momo hợp lệ (BR-CART-06) + Pending --> Failed: Webhook báo lỗi / hết hạn chờ (cơ chế cụ thể ngoài phạm vi US module này) + Success --> [*] + Failed --> [*] +``` + +**Bảng chuyển trạng thái:** + +| # | Nguồn | Sự kiện | Điều kiện | Đích | Ai được làm | BR | Ghi vết | +|---|---|---|---|---|---|---|---| +| 1 | Pending | Xác nhận COD | 🔴 **Chưa chốt — `Payment.status` của COD ghi `success` ngay hay giữ `pending` tới khi thực thu? Xem `OQ-013`** | Success (giả định, chưa chốt) | Hệ thống | *(chưa xác định)* | ✅ | +| 2 | Pending | Webhook VNPay/Momo thành công | Chữ ký hợp lệ, trong hạn (BR-CART-06) | Success | Hệ thống | BR-CART-06 | ✅ | +| 3 | Pending | Webhook báo lỗi/hết hạn | *(cơ chế cụ thể — ngoài phạm vi US module này)* | Failed | Hệ thống | — | ✅ | + +**Chuyển trạng thái KHÔNG được phép:** + +| Từ | Sang | Vì sao cấm | +|---|---|---| +| Success | Pending | Mất dấu vết giao dịch đã ghi nhận thành công — sai lệch đối soát | +| Failed | Success | Không tự động — nếu cần xử lý lại phải tạo bản ghi `Payment` mới, không sửa bản ghi cũ | + +## 4. Mô hình dữ liệu khái niệm (ERD) + +🔴 **Mục bắt buộc vì US-004 chạm ≥2 thực thể.** Mô hình khái niệm — không kiểu dữ liệu vật lý, +không index, không bảng trung gian (đó là việc của Solution Architect/dev; tham chiếu +`e-commerce/docs/sections/05-thiet-ke-du-lieu.md` §5.2.3–5.2.4 chỉ để đối chiếu tên thực thể, +không chép nguyên cấu trúc bảng). + +```mermaid +erDiagram + CUSTOMER ||--o{ CART : "sở hữu (nếu đăng nhập)" + CART ||--o{ CART_ITEM : "chứa" + CART_ITEM }o--|| PRODUCT_VARIANT : "tham chiếu" + CART_ITEM }o--|| SELLER : "thuộc về" + CUSTOMER ||--o{ ORDER : "đặt (nếu đăng nhập)" + ORDER ||--o{ ORDER_SELLER : "tách thành" + ORDER ||--o| PAYMENT : "thanh toán bởi" + ORDER_SELLER ||--o{ ORDER_ITEM : "chứa" + ORDER_SELLER }o--|| SELLER : "thuộc về" + ORDER_ITEM }o--|| PRODUCT_VARIANT : "tham chiếu" + + CART { + string id PK "khoá kỹ thuật" + string customer_id FK "nullable — null nếu Guest" + string session_id "định danh phiên — dùng khi Guest" + enum status "active/converted/abandoned — xem BR §3" + } + CART_ITEM { + string id PK + string cart_id FK + string product_variant_id FK + string seller_id FK + int quantity "> 0" + } + ORDER { + string id PK + string customer_id FK "nullable — Guest checkout (RQ-004)" + string order_number "khoá nghiệp vụ, duy nhất, dễ đọc" + decimal total_amount "VND — tổng các OrderSeller con" + enum status "pending_payment/… — dẫn xuất từ trạng thái các OrderSeller con, chi tiết ở module khác" + } + ORDER_SELLER { + string id PK + string order_id FK + string seller_id FK + string sub_order_number "khoá nghiệp vụ, duy nhất" + decimal subtotal_amount "VND" + enum status "pending/confirmed/cancelled — xem BR §3 (đoạn khởi tạo)" + } + ORDER_ITEM { + string id PK + string order_seller_id FK + string product_variant_id FK + int quantity + decimal unit_price "VND, snapshot tại thời điểm đặt hàng" + } + PAYMENT { + string id PK + string order_id FK + enum method "vnpay/momo/cod — BR-CART-04" + decimal amount "VND" + enum status "pending/success/failed — xem BR §3" + } +``` + +*Ký hiệu lực lượng: `||--o{` một-nhiều · `||--o|` một-không hoặc một · `}o--||` nhiều-một.* + +### 4.1 Bảng thực thể + +| Thực thể | Tên nghiệp vụ | Khoá nghiệp vụ | Số bản ghi hiện có | Ai tạo | Vòng đời | BR | +|---|---|---|---|---|---|---| +| `CART` | Giỏ hàng | *(id kỹ thuật — chưa có khoá nghiệp vụ do khách hàng nhận biết; `customer_id`/`session_id` là khoá truy vấn, không phải khoá nghiệp vụ theo nghĩa người dùng gõ ra)* | 0 — greenfield | Customer/Guest (US-001) | §3 `CART` | BR-CART-01, BR-CART-02 | +| `CART_ITEM` | Dòng sản phẩm trong giỏ | `(cart_id, product_variant_id)` | 0 | Customer/Guest | Theo `CART` cha | — | +| `ORDER` | Đơn hàng (cha) | `order_number` | 0 | Hệ thống, khi checkout (US-004) | Dẫn xuất từ `ORDER_SELLER` con | BR-CART-01 | +| `ORDER_SELLER` | Đơn hàng con theo seller | `sub_order_number` | 0 | Hệ thống, khi checkout (US-004) | §3 `ORDER_SELLER` (đoạn khởi tạo) | BR-CART-01, BR-CART-02 | +| `ORDER_ITEM` | Dòng sản phẩm trong đơn con | *(id kỹ thuật, không có khoá nghiệp vụ riêng — thuộc về `ORDER_SELLER`)* | 0 | Hệ thống, khi checkout | Theo `ORDER_SELLER` cha | — | +| `PAYMENT` | Giao dịch thanh toán | `gateway_transaction_ref` *(chỉ có với VNPay/Momo — COD chưa rõ khoá nghiệp vụ tương đương, xem `OQ-013`)* | 0 | Hệ thống, khi US-007/US-008 | §3 `PAYMENT` | BR-CART-03…06 | + +**Khoá nghiệp vụ** là thứ người dùng dùng để nhận biết — `order_number`/`sub_order_number` là +mã đơn hàng khách/seller nhìn thấy và trao đổi (VD tra cứu, khiếu nại), khác với `id` kỹ thuật. + +### 4.2 Quan hệ cần làm rõ + +| Quan hệ | Xoá bên "một" thì bên "nhiều" ra sao | Bắt buộc có quan hệ? | Đổi được sang bên khác? | BR | +|---|---|---|---|---| +| `CART` → `CART_ITEM` | Không áp dụng "xoá" `CART` — chỉ chuyển trạng thái (§3); xoá `CART_ITEM` riêng lẻ là hành vi hợp lệ (US-003) | ✅ mỗi `CART_ITEM` luôn thuộc đúng 1 `CART` | ❌ | — | +| `ORDER` → `ORDER_SELLER` | Không áp dụng "xoá" `ORDER` (bắt buộc giữ dấu vết tài chính) | ✅ mỗi `ORDER_SELLER` luôn thuộc đúng 1 `ORDER` cha | ❌ | BR-CART-01 | +| `ORDER_SELLER` → `ORDER_ITEM` | Không áp dụng "xoá" | ✅ | ❌ | BR-CART-01 | +| `ORDER` → `PAYMENT` | Không áp dụng "xoá" | 🔶 một `ORDER` có 0 hoặc 1 `PAYMENT` tại một thời điểm — **trường hợp đổi phương thức thanh toán giữa chừng (huỷ Payment cũ, tạo Payment mới) chưa được chốt, xem `OQ` mới nếu phát sinh ở GĐ3** | 🔶 xem trên | BR-CART-04 | + +### 4.3 Thực thể ngoài phạm vi + +*Thực thể có nhắc tới nhưng do module/service khác sở hữu — nêu rõ để không ai định tạo bảng +cho nó trong phạm vi module Giỏ hàng & Checkout.* + +| Thực thể | Ai sở hữu | Lấy về bằng cách nào | Cache không | +|---|---|---|---| +| `CUSTOMER` | Module Tài khoản (FR-01/FR-03, Identity & Access) | Tham chiếu qua `customer_id` (FK logic) | Không cache PII ngoài những trường cần thiết cho hiển thị checkout (địa chỉ, tên người nhận) — chi tiết mã hoá/cache thuộc Tech Lead/GĐ3 | +| `SELLER` | Module Quản trị Seller (FR-17/FR-23) | Tham chiếu qua `seller_id` (FK logic) | Cache tên hiển thị seller cho màn hình giỏ hàng — không cache dữ liệu KYC/tài chính của seller | +| `PRODUCT_VARIANT` | Module Catalog & Tìm kiếm (FR-04/FR-18) | Tham chiếu qua `product_variant_id`; giá được snapshot vào `CART_ITEM`/`ORDER_ITEM` tại thời điểm thêm giỏ/đặt hàng (xem `ASM-06`, `OQ-009`) | Có — snapshot giá tại thời điểm thêm giỏ, cần đối chiếu lại khi checkout (US-004) | + +## 5. Công thức tính toán + +| ID | Đại lượng | Công thức | Đơn vị | Làm tròn | Nguồn dữ liệu | Ví dụ | +|---|---|---|---|---|---|---| +| BR-CART-08 | Tổng tiền một `OrderSeller` | Σ (`ORDER_ITEM.quantity × ORDER_ITEM.unit_price`) — **chưa chốt có gồm phí vận chuyển ước tính (US-005) hay không** | VND | Chưa chốt — **cần OQ mới ở GĐ3 nếu phát sinh** | `ORDER_ITEM` | *(chưa có ví dụ số cụ thể — chờ chốt có gồm phí ship không)* | +| BR-CART-09 | Tổng tiền `Order` (cha) | Σ (`ORDER_SELLER.subtotal_amount`) | VND | Không làm tròn thêm (đã làm tròn ở từng `OrderSeller`) | `ORDER_SELLER` | Đơn A: 250.000đ + Đơn B: 180.000đ = 430.000đ | + +🔴 BR-CART-08 **chưa chốt được** vì phụ thuộc: (a) phí vận chuyển có tính vào `subtotal_amount` +hay tách riêng một trường phí ship, và (b) coupon/điểm thưởng (module khác, `OQ-004`/`DEC-03`) +áp giảm giá ở cấp `Order` hay từng `OrderSeller`. Đây là khoảng trống thật cần Tech Lead + PO +xác nhận trước khi viết `AC` ở GĐ3 — không tự chọn cách tính. + +## 6. Kiểm tra mâu thuẫn giữa các rule + +*Đối chiếu từng cặp rule cùng tác động lên một thực thể (`ORDER_SELLER`, `PAYMENT`).* + +| # | Rule A | Rule B | Mâu thuẫn ở đâu | Trạng thái | +|---|---|---|---|---| +| 1 | BR-CART-02 (giữ tồn kho, chặn nếu thiếu) | BR-CART-01 (tách đơn theo seller) | Không mâu thuẫn trực tiếp — BR-CART-02 chạy **trước** BR-CART-01 trong luồng (xem `PROCESS` B1 sơ đồ: kiểm tra tồn kho ở D1 trước khi tách đơn ở B5) | ✅ Không mâu thuẫn — đã xác nhận thứ tự | +| 2 | BR-CART-03 (giới hạn COD, chưa chốt) | BR-CART-04 (mọi phương thức đều được chọn tự do) | Nếu PO chốt BR-CART-03 theo phương án (a) giới hạn giá trị, nó sẽ **thu hẹp** BR-CART-04 (không còn "tự do chọn mọi phương thức" cho đơn giá trị cao) — cần cập nhật BR-CART-04 khi BR-CART-03 chốt | 🔴 Chờ PO quyết — `OQ-006` | +| 3 | BR-CART-06 (chặn khi webhook không hợp lệ/quá hạn) | Nhu cầu trải nghiệm khách "biết ngay kết quả thanh toán" (`RISK-02`) | Nếu thời gian chờ webhook quá dài, khách không biết đơn có được xác nhận hay không — không phải mâu thuẫn giữa hai rule mà là **khoảng trống thiết kế** (cơ chế đối soát bù) chưa có rule nào lấp — xem `PROCESS` B9, ngoài phạm vi US module này | 🟠 Ghi nhận là khoảng trống, không phải mâu thuẫn rule-rule | + +**Kết luận:** không phát hiện mâu thuẫn rule-rule nghiêm trọng trong phạm vi các rule **đã chốt +được nội dung**. Mâu thuẫn tiềm ẩn ở dòng #2 phụ thuộc hoàn toàn vào việc PO trả lời `OQ-006`. + +## 7. Rule của hệ thống hiện tại bị thay đổi + +*Không áp dụng — `LIFECYCLE = greenfield`, không có hệ thống/rule cũ nào bị thay đổi bởi module +này (xác nhận F7, `ELICITATION_CartCheckout_2026-09-08.md`).* + +## 8. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | +|---|---|---|---|---| +| OQ-006 | *(GĐ1, nhắc lại)* Giới hạn giá trị đơn COD là gì? | PO, Kế toán đối soát | 2026-09-08 | `BR-CART-03` | +| OQ-010 | Xác nhận khả thi `ASM-01` (webhook VNPay/Momo) | Tech Lead | 2026-09-08 | `BR-CART-06` | +| OQ-011 | Xác nhận `ASM-03` — giỏ N seller luôn tách đúng N đơn, không gộp | PO | 2026-09-08 | `BR-CART-01` | +| OQ-013 | `Payment.status` của COD ghi "success" ngay hay giữ "pending" tới khi thực thu? | Kế toán đối soát, PO | 2026-09-08 | `PAYMENT` §3 bảng chuyển #1 | +| *(mới)* OQ-014 | `Order.total_amount`/`OrderSeller.subtotal_amount` có gồm phí vận chuyển ước tính (US-005) không? Coupon/điểm thưởng áp giảm giá ở cấp `Order` hay từng `OrderSeller`? | PO, Tech Lead | 2026-09-08 | BR-CART-08/09, US-005, `AC` ở GĐ3 | + +## 9. Ngoài phạm vi + +- Thông điệp lỗi hiển thị nguyên văn (VD nội dung `E-CART-0001`) → GĐ3 `SRS` §bảng mã lỗi +- Ai được thực hiện hành động → `RBAC_CartCheckout_v1.0.md` +- Công thức tính hoa hồng, payout, điểm loyalty (BR-03…BR-08 ở SAD) → module Commission & + Payout / Promotion & Loyalty, ngoài phạm vi module này +- Cơ chế đối soát bù thanh toán chi tiết (reconciliation job) → thiết kế kỹ thuật GĐ3 của + module Thanh toán diff --git a/ba-output/e-commerce/02-analysis/IMPACT_CartCheckout_v1.0.md b/ba-output/e-commerce/02-analysis/IMPACT_CartCheckout_v1.0.md new file mode 100644 index 0000000..884d230 --- /dev/null +++ b/ba-output/e-commerce/02-analysis/IMPACT_CartCheckout_v1.0.md @@ -0,0 +1,188 @@ +# IMPACT — Phân tích tác động — Giỏ hàng & Checkout (e-commerce) + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-2-analysis) | +| **Status** | 🟡 Draft | +| **Approved by** | — *(cần Tech Lead xác nhận — chưa có Tech Lead thật tham gia lần chạy này)* | +| **Profile** | screen · greenfield · standard | +| **Source** | `01-discovery/BRIEF_CartCheckout_v1.0.md` §5.3 (ranh giới hệ thống) · `01-discovery/RISK_CartCheckout_v1.0.md` §3 (phụ thuộc bên ngoài) · `PROCESS_CartCheckout_v1.0.md` · `e-commerce/docs/sections/06-luong-xu-ly.md` §6.1.1 (tham chiếu tích hợp, không chép thiết kế) | +| **Scope** | Module Giỏ hàng & Checkout — RQ-001…RQ-004 | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | CR | +|---|---|---|---|---| +| 1.0 | 2026-09-08 | BA (qua skill ba-2-analysis) | Bản đầu — rút gọn theo `LIFECYCLE = greenfield`, trọng tâm trục tích hợp | — | + +--- + +> ⚠️ **Ngoại lệ gate G1** — xem cảnh báo đầy đủ ở đầu `PROCESS_CartCheckout_v1.0.md` và `DEC-02` +> ở `00-index/DECISION_e-commerce.md`. +> +> **Vì sao tài liệu này rút gọn:** theo `00-index/PROFILE_e-commerce.md` mục "Hệ quả đã áp +> dụng" (`LIFECYCLE = greenfield`): *"GĐ2 `IMPACT` rút gọn: chỉ trục tích hợp (không có +> module/dữ liệu cũ bị ảnh hưởng)"*. Tài liệu dưới đây vẫn rà đủ **sáu trục** theo template +> (không bỏ giai đoạn im lặng) — năm trục còn lại ghi rõ *"đã rà, không phát hiện"* kèm lý do +> greenfield; trục 1.5 (Tích hợp) là trọng tâm thật sự của tài liệu này. + +--- + +## 0. Kết luận + +| | | +|---|---| +| **Mức tác động tổng thể** | 🟠 Trung bình — không có gì để đụng ở màn hình/dữ liệu/BR/RBAC cũ (greenfield), nhưng **tích hợp với 4 bên thứ ba (VNPay, Momo, GHN, GHTK) + 3 module nội bộ song song (Catalog, Commission & Payout, Promotion & Loyalty, Notification) đều chưa được xác minh khả thi** | +| **Số hạng mục 🔴** | 2 (VNPay, Momo — xem §1.5) | +| **Cần migrate dữ liệu** | Không — `LIFECYCLE = greenfield`, không có dữ liệu cũ (xác nhận F7, `ELICITATION_CartCheckout_2026-09-08.md`) | +| **Cần phối hợp bên thứ ba** | Có — VNPay, Momo, GHN, GHTK (xem §1.5) | +| **Rủi ro lớn nhất** | `RISK-02` (webhook thanh toán trễ/lỗi khiến đơn kẹt "chờ thanh toán") và `RISK-01` (COD bùng đơn một phần) — cả hai đã ghi ở GĐ1, ảnh hưởng trực tiếp tới khả năng chốt `BR-CART-03`/`BR-CART-06` ở GĐ2 này | + +--- + +## 1. Sáu trục rà soát + +### 1.1 Màn hình / chức năng hiện có + +| Màn hình/chức năng | Đường dẫn | Tác động | Mức | Phương án | Ai xác nhận | +|---|---|---|---|---|---| +| *(không có)* | — | — | — | — | — | + +**Đã rà:** đã kiểm tra `ba-output/e-commerce/` (chỉ có artifact GĐ1 của chính module này) và +`e-commerce/docs/sections/07-giao-dien.md` (mô tả UI dạng văn bản SCR-01…, chưa phải màn hình +đã build). **Kết luận: không có màn hình nào đang chạy để module này tác động** — đây là module +đầu tiên chạy GĐ2 của dự án e-commerce (greenfield, chưa có bản build sản phẩm nào trước đó). + +### 1.2 Dữ liệu + +| Bảng/thực thể | Thay đổi | Số bản ghi hiện có | Dữ liệu cũ xử lý thế nào | Mức | Ai xác nhận | +|---|---|---|---|---|---| +| *(không có)* | — | 0 | N/A | — | — | + +**Đã rà:** đối chiếu `e-commerce/docs/sections/05-thiet-ke-du-lieu.md` §5.3.5 *"Migration dữ +liệu cũ: Không áp dụng — dự án greenfield… không có hệ thống cũ cần tích hợp/migrate"*. **Kết +luận: không có dữ liệu cũ.** Toàn bộ thực thể mới (`Cart`, `CartItem`, `Order`, `OrderSeller`, +`OrderItem`, `Payment` — xem `BR_CartCheckout_v1.0.md` §4) được tạo mới hoàn toàn; không thuộc +ba lựa chọn "giữ nguyên/migrate/song song" vì không có dữ liệu cũ để chọn. + +### 1.3 Business rule + +| BR hiện hành | Bị ảnh hưởng thế nào | Mâu thuẫn với rule mới? | Xử lý | Mức | +|---|---|---|---|---| +| *(không có)* | — | — | — | — | + +**Đã rà:** không có `BR` nào đã chốt (`✅ Baselined`) trước module này trong toàn dự án +e-commerce — đây là bộ `BR` đầu tiên (`BR_CartCheckout_v1.0.md`). Mâu thuẫn **nội bộ** giữa các +rule mới của chính module này đã được rà ở `BR_CartCheckout_v1.0.md` §6, không lặp lại ở đây. + +### 1.4 Phân quyền + +| Vai trò | Thay đổi quyền | Ai bị mất quyền | Đã thông báo | Mức | +|---|---|---|---|---| +| *(không có)* | — | — | — | — | + +**Đã rà:** không có `RBAC` nào đã chốt trước module này. `RBAC_CartCheckout_v1.0.md` tạo mới +2 vai trò (Guest, Customer) — chưa ảnh hưởng vai trò nào đã tồn tại vì đây là module đầu tiên. + +### 1.5 Tích hợp / hệ thống ngoài — TRỌNG TÂM + +| Hệ thống | Điểm chạm | Thay đổi | Đầu mối bên kia | Cần bên kia làm gì | Hạn | Mức | +|---|---|---|---|---|---|---| +| VNPay | Payment Service khởi tạo giao dịch (US-008) + nhận webhook xác nhận (BR-CART-06) | Tích hợp mới hoàn toàn | Chưa xác định (`RISK` §3 phụ thuộc #1) | Cung cấp tài liệu API + tài khoản sandbox; xác nhận cơ chế/độ trễ webhook (`ASM-01`/`OQ-010`) | Trước khi bắt đầu GĐ3 (SRS thanh toán) | 🔴 | +| Momo | Tương tự VNPay | Tích hợp mới hoàn toàn | Chưa xác định (`RISK` §3 phụ thuộc #2) | Tương tự VNPay | Trước GĐ3 | 🔴 | +| GHN | Ước tính phí ship/kiểm tra vùng phục vụ theo địa chỉ lúc checkout (US-005) | Tích hợp mới | Chưa xác định (`RISK` §3 phụ thuộc #3) | Cung cấp API tính phí + vùng phục vụ (`ASM-02`/`OQ` GĐ1) | Trước GĐ3 (SRS checkout) | 🟠 | +| GHTK | Tương tự GHN | Tích hợp mới | Chưa xác định (`RISK` §3 phụ thuộc #4) | Tương tự GHN | Trước GĐ3 | 🟠 | +| Catalog & Inventory (module nội bộ, cùng dự án, ngoài phạm vi RQ-001…004) | Cart đọc giá/tồn kho khi thêm giỏ (US-001) và giữ tồn kho khi checkout (US-004, BR-CART-02) | Tích hợp nội bộ mới (một chiều vào Cart) | STK-06 (Tech Lead) | Xác nhận kiến trúc đồng bộ giá/tồn kho, độ trễ cache (`ASM-06`/`OQ-009`) | Trước GĐ3 | 🟠 | +| Commission & Payout (module nội bộ, ngoài phạm vi) | Nhận sự kiện thanh toán thành công để tạo bản ghi hoa hồng | Tích hợp nội bộ mới (một chiều ra khỏi module này) | STK-06 (Tech Lead) | Xác nhận cấu trúc sự kiện cần thiết | Trước GĐ3 | 🟢 | +| Notification (module nội bộ, ngoài phạm vi, FR-12) | Nhận sự kiện "đơn đã tạo"/"thanh toán thành công" để trigger gửi email/SMS | Tích hợp nội bộ mới (một chiều ra khỏi module này) | STK-06 (Tech Lead) | Xác nhận điều kiện trigger | Trước GĐ3 | 🟢 | +| Khuyến mãi & Loyalty (module nội bộ, ngoài phạm vi, FR-13/14) | Checkout gọi API "áp dụng mã/điểm" và hiển thị kết quả giảm giá đã tính (điểm tích hợp đã xác nhận qua `OQ-004`, xem `DEC-03`) | Tích hợp nội bộ mới (hai chiều: gọi áp dụng + nhận kết quả) | STK-01 (PO sàn) đã xác nhận điểm nối; **đầu mối kỹ thuật (API contract) chưa xác định** | Cung cấp API "áp dụng mã/điểm" trả về giá trị giảm | Trước GĐ3 (màn hình checkout, US-004/US-005) | 🟠 | + +**Nếu bên kia lỗi hoặc chậm thì nghiệp vụ này xử lý thế nào? *(bắt buộc trả lời)*** + +- **VNPay/Momo lỗi/chậm (timeout, không gửi webhook):** theo `PROCESS_CartCheckout_v1.0.md` + bước B9 — đơn giữ `pending_payment`; cơ chế đối soát bù (reconciliation job) được đề xuất ở + `RISK-02` (GĐ1) nhưng **thiết kế chi tiết thuộc phạm vi module Thanh toán ở GĐ3, không phải + một US của module Giỏ hàng & Checkout**. Đây là phụ thuộc bắt buộc phải xử lý trước go-live, + ghi nhận rõ để không rơi vào khoảng trống giữa hai module. +- **GHN/GHTK lỗi/chậm lúc ước tính phí ship (US-005):** nếu `ASM-02` sai (API không khả dụng + thời gian thực lúc checkout), phương án dự phòng là chuyển sang ước tính tĩnh — **chưa được + PO/Tech Lead xác nhận là phương án chính thức**, vẫn ở dạng giả định từ GĐ1. +- **Catalog & Inventory chậm/không phản hồi:** có thể chặn hoàn toàn bước thêm giỏ (US-001) + hoặc checkout (US-004) vì đây là phụ thuộc cứng (không có giá/tồn kho thì không tạo được + `CartItem`/`OrderItem` hợp lệ) — cần Tech Lead xác nhận SLA nội bộ giữa hai service, ngoài + khả năng BA tự quyết. +- **Khuyến mãi & Loyalty lỗi/chậm:** theo `OQ-004`/`DEC-03`, module này chỉ hiển thị kết quả đã + tính — nếu API áp dụng lỗi, hành vi hiển thị cho khách (bỏ qua coupon/điểm, hay chặn checkout + hoàn toàn) **chưa chốt, cần OQ mới ở GĐ3**. + +**Đã rà:** đối chiếu `BRIEF_CartCheckout_v1.0.md` §5.3 (ranh giới hệ thống) và +`RISK_CartCheckout_v1.0.md` §3 (phụ thuộc bên ngoài) — không phát hiện hệ thống tích hợp nào +khác ngoài bảng trên trong phạm vi RQ-001…004. + +### 1.6 Báo cáo / đối soát + +*Rút gọn theo `LIFECYCLE = greenfield` (theo quyết định ở `PROFILE`) — không có báo cáo hiện +hành nào bị đổi cách tính vì đây là module đầu tiên, chưa từng có báo cáo trước đó.* + +| Báo cáo | Số liệu nào đổi | Đổi từ khi nào | Ai dùng báo cáo này | Đã báo chưa | Mức | +|---|---|---|---|---|---| +| *(không có báo cáo hiện hành để đổi)* | — | — | — | — | — | + +**Ghi nhận (không phải "tác động" theo nghĩa template, nhưng quan trọng để không bỏ sót):** +dữ liệu `Order`/`OrderSeller`/`Payment` do module này sinh ra là **đầu vào bắt buộc** cho báo +cáo đối soát doanh thu tương lai (STK-04 Kế toán đối soát, `RACI` ở `STAKEHOLDER` GĐ1) — nhưng +vì chưa có báo cáo nào tồn tại để so sánh, mục này không có gì để điền theo đúng cấu trúc bảng +trên. Đây là lý do `RISK-02` (webhook trễ) quan trọng: dữ liệu sai lệch ngay từ module này sẽ +lan sang mọi báo cáo đối soát sau này — ghi chú lại để module Kế toán/Đối soát (nếu chạy GĐ1/2 +riêng sau này) biết điểm phụ thuộc ngược. + +--- + +## 2. Tác động lên người dùng và vận hành + +| Vai trò | Thay đổi trong công việc | Cần đào tạo | Cần thông báo trước | Mức kháng cự dự kiến | +|---|---|---|---|---| +| Customer/Guest | Trải nghiệm hoàn toàn mới (không có công việc "cũ" bị thay đổi — greenfield) | Hướng dẫn UX tại chỗ (onboarding/tooltip) — thuộc `WF`/`UICONV` GĐ3 | Không áp dụng (chưa có người dùng cũ) | Thấp — nhưng chưa đo được thật (chưa vận hành), xem `GOAL-01` | +| CSKH *(ngoài phạm vi stakeholder module này, nhưng liên đới qua `RISK-02`)* | Có thể cần quy trình mới để xử lý đơn "kẹt chờ thanh toán" — **chưa có quy trình chính thức nào được thiết kế trong phạm vi module này** | Chưa xác định — phụ thuộc thiết kế cơ chế đối soát bù ở GĐ3 module Thanh toán | Cần thông báo trước go-live nếu quy trình này được xác nhận | Chưa đánh giá được — chưa có CSKH thật tham gia (đúng hệ quả G1 chưa ký) | + +## 3. Tác động lên phi chức năng + +| Khía cạnh | Tác động | Ngưỡng hiện tại | Ngưỡng sau thay đổi | Cần đo lại | +|---|---|---|---|---| +| Hiệu năng | Checkout (B1→B5, `PROCESS`) phải hoàn tất trong ngưỡng đề xuất | N/A — chưa vận hành | < 3 giây (đề xuất `NFR-01`, chưa phải SLA hợp đồng — xem `BRIEF` §2) | ☑ (bắt buộc đo ở soft-launch, theo `GOAL-01`/`GOAL-02`) | +| Dung lượng lưu trữ | Chưa đo — greenfield, không có dữ liệu lịch sử để ước lượng tăng trưởng thật | N/A | N/A | ☑ (sau khi có số liệu vận hành thật, không phải việc của GĐ2) | +| Bảo mật / tuân thủ | Chia sẻ PII (địa chỉ, SĐT) cho seller khi tách đơn (`RISK-03`) chưa được Pháp chế/Bảo mật rà soát | N/A | N/A — chờ người phụ trách (`OQ-003`, GĐ1) | ☑ (bắt buộc trước go-live, không phải "nên làm") | + +## 4. Thứ tự triển khai bắt buộc + +| # | Việc | Phải xong trước | Vì sao | Ai làm | +|---|---|---|---|---| +| 1 | Xác minh `ASM-01` (webhook VNPay/Momo khả thi gần thời gian thực) | Thiết kế chi tiết `SRS` US-008 ở GĐ3 | Nếu sai, toàn bộ luồng xác nhận thanh toán (BR-CART-06) phải đổi cơ chế sang polling | Tech Lead | +| 2 | Xác minh `ASM-02` (API GHN/GHTK tính phí ship real-time) | Thiết kế chi tiết `SRS` US-005 ở GĐ3 | Nếu sai, phải đổi sang phương án ước tính tĩnh — thay đổi UX hiển thị phí ship | Tech Lead + STK-05 (Trưởng vận hành) | +| 3 | PO trả lời `OQ-006` (giới hạn COD) | Chốt `BR-CART-03` trước khi viết `AC` của US-007 ở GĐ3 | Không có con số thì không viết được điều kiện chặn/cảnh báo cụ thể | PO, Kế toán đối soát | +| 4 | Xác nhận API contract "áp dụng mã/điểm" với module Khuyến mãi & Loyalty | Thiết kế màn hình checkout (US-004/US-005) ở GĐ3 | Module này chỉ hiển thị kết quả đã tính — không tự thiết kế được UI nếu chưa biết dữ liệu trả về là gì | Tech Lead, PO | + +## 5. Phạm vi hồi quy đề xuất cho QA + +| Khu vực cần test lại | Vì sao | Ưu tiên | +|---|---|---| +| *(không có)* | Module đầu tiên chạy GĐ2 của dự án e-commerce — chưa có tính năng nào đã release để hồi quy (greenfield, `RIGOR = standard` không miễn hoàn toàn nghĩa vụ ghi mục này, nhưng nội dung thật sự là "không có" vì chưa có bản release nào trước đó) | N/A | + +## 6. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | +|---|---|---|---|---| +| OQ-009 | `ASM-06` — giá/tồn kho thay đổi giữa lúc thêm giỏ và checkout | PO + Tech Lead | 2026-09-08 | §1.5 dòng Catalog & Inventory | +| OQ-010 | Xác nhận khả thi `ASM-01` (webhook VNPay/Momo) | Tech Lead | 2026-09-08 | §1.5 dòng VNPay/Momo, §4 mục 1 | +| *(GĐ1)* ASM-02 | Xác nhận API GHN/GHTK tính phí ship real-time | Tech Lead, STK-05 | 2026-09-08 | §1.5 dòng GHN/GHTK, §4 mục 2 | +| *(mới)* OQ-017 | Nếu API "áp dụng mã/điểm" của module Khuyến mãi & Loyalty lỗi/chậm lúc checkout, hệ thống bỏ qua và cho tiếp tục hay chặn checkout hoàn toàn? | PO, Tech Lead | 2026-09-08 | §1.5 dòng Khuyến mãi & Loyalty | + +## 7. Xác nhận + +| Vai trò | Người | Xác nhận nội dung | Ngày | +|---|---|---|---| +| Tech Lead | *(chưa có — chưa xác định tên thật, xem `OQ-001` GĐ1)* | ☐ Khả thi, đã rà đủ | — | +| QA | *(chưa có)* | ☐ Phạm vi hồi quy hợp lý (N/A cho module đầu tiên) | — | +| PO | *(chưa có — chưa xác định tên thật, xem `OQ-001` GĐ1)* | ☐ Chấp nhận tác động lên người dùng | — | diff --git a/ba-output/e-commerce/02-analysis/PROCESS_CartCheckout_v1.0.md b/ba-output/e-commerce/02-analysis/PROCESS_CartCheckout_v1.0.md new file mode 100644 index 0000000..4e525ea --- /dev/null +++ b/ba-output/e-commerce/02-analysis/PROCESS_CartCheckout_v1.0.md @@ -0,0 +1,186 @@ +# PROCESS — Quy trình AS-IS / TO-BE — Giỏ hàng & Checkout (e-commerce) + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-2-analysis) | +| **Status** | 🟡 Draft | +| **Approved by** | — | +| **Profile** | screen · greenfield · standard (xem `00-index/PROFILE_e-commerce.md`) | +| **Source** | `01-discovery/BRIEF_CartCheckout_v1.0.md` · `01-discovery/RISK_CartCheckout_v1.0.md` · `01-discovery/ELICITATION_CartCheckout_2026-09-08.md` · `e-commerce/docs/sections/06-luong-xu-ly.md` §6.1.1, §6.3.1, §6.4 BR-01/BR-02/BR-15 (chỉ dùng làm tài liệu tham chiếu kỹ thuật, không chép nguyên văn thiết kế) · `e-commerce/docs/sections/05-thiet-ke-du-lieu.md` §5.2.3 (tham chiếu entity) | +| **Scope** | Module Giỏ hàng & Checkout — RQ-001…RQ-004 (`BRIEF_CartCheckout_v1.0.md`) | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | CR | +|---|---|---|---|---| +| 1.0 | 2026-09-08 | BA (qua skill ba-2-analysis) | Bản đầu | — | + +--- + +> ⚠️ **Ngoại lệ gate G1** — `BRIEF_CartCheckout_v1.0.md` tự chấm **chưa đủ điều kiện ký chính +> thức** (3/6 tiêu chí G1 còn ☐: thiếu tên thật stakeholder, thiếu buổi làm việc trực tiếp, +> KPI chưa có baseline số — xem mục "Tự chấm" cuối `BRIEF`). Tài liệu này được viết tiếp theo +> **xác nhận rõ ràng của người điều phối** rằng vẫn muốn chạy GĐ2 trong khi chờ G1 ký chính +> thức, cho mục đích đánh giá bộ skill BA. Xem `DEC-02` ở `00-index/DECISION_e-commerce.md`. +> Toàn bộ nội dung dưới đây **phải rà lại** khi G1 được ký thật (đặc biệt phần A3–A5 và B3, vì +> chúng dựa trên `RISK`/`ASM` chưa được PO xác nhận). + +## 1. Phạm vi quy trình + +| | | +|---|---| +| **Tên quy trình** | Giỏ hàng đa seller → Checkout → Tách đơn theo seller → Thanh toán | +| **Điểm bắt đầu** | Customer/Guest có ≥1 sản phẩm trong giỏ hàng và bấm "Đặt hàng" | +| **Điểm kết thúc** | Đơn hàng cha (`Order`) và các đơn con theo seller (`OrderSeller`) đã được tạo, ở trạng thái `pending_payment` hoặc `confirmed` tuỳ phương thức thanh toán — bàn giao cho module Quản lý đơn hàng (FR-08/FR-19, ngoài phạm vi) | +| **Tần suất** | Theo mỗi lượt checkout — chưa đo được (greenfield, chưa vận hành) | +| **Khối lượng** | Chưa đo — quy mô mục tiêu "lớn" theo `BRIEF` §2 (hàng trăm nghìn–hàng triệu user, cao điểm hàng nghìn–chục nghìn concurrent mùa flash sale) | +| **Vai trò tham gia** | Customer, Guest (không có vai trò nội bộ nào tham gia trực tiếp trong phạm vi RQ-001…RQ-004 — đây là luồng self-service) | + +--- + +# PHẦN A — AS-IS (hiện trạng) + +## 0. Vì sao PHẦN A rút gọn còn A3–A5, và vì sao A3–A5 không mô tả "hiện trạng" theo nghĩa thông thường + +Theo `00-index/PROFILE_e-commerce.md` (`LIFECYCLE = greenfield`) và theo `domain-profiles.md` +§2, PHẦN A rút gọn còn **A3 (điểm đau) · A4 (đường tắt) · A5 (ngoại lệ)**, bỏ A1/A2/A6. Lý do +bỏ A1/A2/A6: dự án là marketplace hoàn toàn mới, **không có hệ thống hay quy trình thủ công +nào đang chạy để vẽ sơ đồ luồng/bảng bước** cho việc "một khách mua từ nhiều seller trong một +giỏ hàng, hệ thống tự tách đơn" — xác nhận tại `ELICITATION_CartCheckout_2026-09-08.md` F7: +*"Không có hệ thống cũ (ERP/kho/CRM) cần tích hợp hoặc migrate cho luồng giỏ hàng/checkout — +dự án hoàn toàn mới."* Không có A1 (sơ đồ) thì cũng không có A2 (bảng bước) tương ứng để điền, +và A6 (hệ thống/dữ liệu đang dùng) không áp dụng vì chưa có hệ thống nào đang dùng. + +🔴 Vì không có "hiện trạng" thật, A3–A5 dưới đây **không phải điểm đau/đường tắt/ngoại lệ đã +quan sát được từ vận hành thật** (không thể có, vì chưa vận hành). Thay vào đó, ba mục này +tổng hợp lại **rủi ro và giả định đã ghi ở GĐ1** (`RISK_CartCheckout_v1.0.md`, +`ELICITATION_CartCheckout_2026-09-08.md`) dưới đúng hình thức "spec ẩn" mà A3–A5 được thiết kế +để bắt: chỗ nào TO-BE dễ bỏ sót nhất nếu không đối chiếu lại. Đây là cách diễn giải hợp lý +nhất của A3–A5 cho một luồng greenfield — không tự bịa thêm dữ liệu quan sát không có thật. + +## A3. Điểm đau (rủi ro tương đương — chưa có dữ liệu vận hành thật) + +| ID | Bước TO-BE liên quan | Vấn đề dự kiến | Tần suất | Hậu quả đo được | → RQ | +|---|---|---|---|---|---| +| P1 | B7 (xác nhận đơn COD) | Giỏ hàng đa seller tách thành nhiều đơn COD độc lập; MVP chưa có giới hạn giá trị đơn COD (`ASM-05`, chưa xác minh) → khách có thể chỉ nhận một phần đơn, từ chối phần còn lại | Chưa đo — `RISK-01` đánh giá Khả năng: Cao, Tác động: Cao (🔴) | Seller chịu phí vận chuyển hoàn hàng, tranh chấp seller–sàn hàng loạt ở quy mô lớn | RQ-002, RQ-003 | +| P2 | B8→D3 (chờ xác nhận thanh toán VNPay/Momo) | Webhook xác nhận thanh toán chưa được xác minh khả thi gần thời gian thực (`ASM-01`) → đơn có thể bị trừ tiền nhưng hệ thống không nhận được xác nhận kịp thời | Chưa đo — `RISK-02` đánh giá Khả năng: Trung bình, Tác động: Cao (🔴) | Đơn kẹt "chờ thanh toán" dù tiền đã được gateway ghi nhận, khiếu nại CSKH, sai lệch đối soát với Kế toán (STK-04) | RQ-003 | +| P3 | B3 (ước tính phí ship theo từng seller) | Phí vận chuyển tính riêng cho từng đơn con theo seller có thể cao hơn đáng kể so với mua từ một seller | Chưa đo — `RISK-04` đánh giá Khả năng: Trung bình, Tác động: Trung bình (🟠) | Khách bỏ giỏ hàng ở bước checkout, ảnh hưởng trực tiếp `GOAL-01`/`GOAL-02` | RQ-001, RQ-002 | + +## A4. Đường tắt dự kiến (suy luận — chưa có dữ liệu vận hành thật, đánh dấu rõ là giả định) + +*Vì chưa vận hành, không thể quan sát "người ta đang lách quy trình thế nào". Bảng dưới là suy +luận có nguồn (hành vi thị trường tương tự + rủi ro đã ghi ở GĐ1), **không phải quan sát thật** +— PO/Tech Lead cần xác nhận lại khi có dữ liệu soft-launch.* + +| # | Ai làm | Làm gì ngoài quy trình (dự đoán) | Vì sao phải làm vậy | Ẩn ý về yêu cầu | +|---|---|---|---|---| +| 1 | Customer | Đặt hàng riêng lẻ với từng seller qua kênh khác (mạng xã hội, điện thoại) thay vì dùng giỏ hàng đa seller | Nếu tổng phí ship gộp hiển thị cao hoặc luồng checkout phức tạp, khách có thể quay lại cách mua cũ (nếu seller có kênh riêng) | Cần hiển thị rõ, sớm phí ship theo từng seller trước khi khách cam kết đặt hàng (US-005), không để tới bước cuối mới lộ tổng chi phí thật | +| 2 | CSKH (ngoài phạm vi module này, nhưng liên đới) | Xác nhận thủ công qua điện thoại/email với khách khi đơn kẹt "chờ thanh toán" quá lâu (do `RISK-02`) | Webhook thanh toán chưa được xác minh đáng tin cậy | Module Thanh toán (GĐ3, có thể ngoài phạm vi US của module này) cần cơ chế đối soát bù tự động, không chỉ dựa vào webhook một lần — ghi nhận là phụ thuộc, xem `IMPACT_CartCheckout_v1.0.md` §1.5 | + +## A5. Ngoại lệ đã biết trước (từ tài liệu SAD, cần BA/PO xác nhận lại là spec chính thức của module này) + +🔴 Các dòng dưới đây **tham chiếu** thiết kế kỹ thuật đã có ở +`e-commerce/docs/sections/06-luong-xu-ly.md` (tài liệu SAD, không phải quyết định BA/PO) — dùng +làm gợi ý ngoại lệ cần rà, **không** coi là spec đã chốt cho tới khi PO/Tech Lead xác nhận lại +trong phạm vi BA. + +| # | Ca ngoại lệ | Tần suất | Cách xử lý tham chiếu (SAD) | Ai xử lý | TO-BE của module này có xử lý? | +|---|---|---|---|---|---| +| E1 | Không đủ tồn kho khi checkout (nhiều khách cùng mua sản phẩm sắp hết trong lúc flash sale) | Chưa đo — dự kiến cao trong mùa flash sale (`NFR-02`) | SAD §6.4 BR-02: giữ tồn kho (reserve) khi `POST /checkout`, trả lỗi nếu không đủ, yêu cầu điều chỉnh giỏ hàng | Hệ thống | ✅ Có — US-004 (xem `BR_CartCheckout_v1.0.md` BR-CART-02) | +| E2 | Giá/tồn kho hiển thị trong giỏ thay đổi giữa lúc thêm giỏ và lúc checkout | Chưa đo (`ASM-06`, chưa xác minh) | SAD chưa mô tả cơ chế khoá giá/tồn kho tạm thời (reservation) cho riêng trường hợp này ở mức UX | Chưa xác định | ☐ Chưa xử lý — xem `OQ-009` | +| E3 | Không tạo được vận đơn qua GHN (timeout/lỗi) khi tính phí ship lúc checkout | Chưa đo | SAD §6.4 BR-15: fallback GHTK, nếu cả hai lỗi thì Ops xử lý thủ công | Hệ thống/Ops | ➖ Ngoài phạm vi — BR-15 áp dụng ở bước **tạo vận đơn sau khi đơn đã tồn tại** (FR-26), không phải lúc ước tính phí ship trong checkout. Trong phạm vi module này, nếu GHN/GHTK không phản hồi lúc checkout thì chỉ ảnh hưởng tới việc hiển thị phí ước tính (xem `ASM-02`, chưa xác minh) | +| E4 | Khách chọn thanh toán COD cho đơn giá trị lớn (không có giới hạn ở MVP theo `ASM-05`) | Chưa đo | Không có xử lý nào ở SAD — đây thuần là quyết định nghiệp vụ chưa chốt | PO chưa chỉ định | ☐ Chưa xử lý — xem `OQ-006` (đã mở từ GĐ1, nhắc lại vì chặn `BR-CART-03` ở GĐ2) | + +--- + +# PHẦN B — TO-BE (đề xuất) + +## B1. Sơ đồ luồng + +```mermaid +flowchart TD + START(["Customer/Guest có sản phẩm trong giỏ, bấm Đặt hàng"]) --> B1["🆕 B1. Xem giỏ hàng nhóm theo seller · Customer/Guest · US-002"] + B1 --> B2["🆕 B2. Chọn/nhập địa chỉ giao hàng · Customer/Guest · US-005"] + B2 --> B3["🆕 B3. Hệ thống ước tính phí ship theo từng seller · Hệ thống · US-005"] + B3 --> D1{"Đủ tồn kho tất cả item? (BR-CART-02)"} + D1 -->|Không| B4["🆕 ⚠️ P1' · B4. Báo lỗi, yêu cầu điều chỉnh giỏ hàng · Hệ thống · US-004"] + B4 --> B1 + D1 -->|Có| B5["🆕 B5. Tách giỏ hàng thành các đơn con theo seller (BR-CART-01) · Hệ thống · US-004"] + B5 --> B6["🆕 B6. Chọn phương thức thanh toán COD/VNPay/Momo · Customer/Guest · US-007, US-008"] + B6 --> D2{"Phương thức thanh toán?"} + D2 -->|COD| B7["🆕 B7. Xác nhận đơn COD · Hệ thống · US-007"] + D2 -->|VNPay/Momo| B8["🆕 B8. Chuyển hướng cổng thanh toán, chờ xác nhận · Hệ thống + bên ngoài · US-008"] + B7 --> ENDOK(["Đơn con đã tạo — bàn giao FR-08/FR-19 (ngoài phạm vi)"]) + B8 --> D3{"Thanh toán thành công? (webhook, BR-CART-06)"} + D3 -->|Có| ENDOK + D3 -->|"Không / timeout"| B9["⚠️ P2' · B9. Đơn giữ pending_payment — cần cơ chế đối soát bù (ngoài phạm vi US module này)"] + B9 --> ENDWAIT(["Chờ xử lý bù — xem IMPACT §1.5"]) +``` + +*Đánh dấu `🆕` mọi bước vì không có AS-IS để so sánh (bỏ B4/B5 dạng "bước bị bỏ/bước cũ" — +xem giải thích ở §0 Phần A). `⚠️ P1'/P2'` tham chiếu điểm đau `P1`/`P2` ở A3.* + +## B2. Bảng chi tiết từng bước + +| # | Bước | Loại | Ai làm | Input | Output | Hệ thống | ⏱ Dự kiến | US | +|---|---|---|---|---|---|---|---|---| +| B1 | Xem giỏ hàng nhóm theo seller | 🆕 | Customer/Guest | Danh sách `CartItem` trong `Cart` | Giỏ hàng hiển thị nhóm theo `seller_id` kèm tổng tiền từng nhóm | Cart & Order Service (nội bộ) | Đích NFR-01: phản hồi màn hình < 2 giây | US-002 | +| B2 | Chọn/nhập địa chỉ giao hàng | 🆕 | Customer/Guest | Địa chỉ đã lưu (Customer) hoặc nhập mới (Guest) | Địa chỉ giao hàng gắn với phiên checkout | Identity & Access Service (đọc `customer_address`, nếu có tài khoản) | Chưa ước lượng — phụ thuộc UX GĐ3 | US-005 | +| B3 | Ước tính phí ship theo từng seller | 🆕 | Hệ thống | Địa chỉ giao hàng + danh sách seller trong giỏ | Phí ship ước tính theo từng đơn con (nếu `ASM-02` đúng) | GHN/GHTK (bên ngoài, `ASM-02` chưa xác minh) | Chưa ước lượng — phụ thuộc SLA API GHN/GHTK | US-005 | +| B4 | Báo lỗi không đủ tồn kho | 🆕 | Hệ thống | Kết quả kiểm tra `inventory_stock` | Thông báo lỗi, giữ nguyên giỏ hàng để khách điều chỉnh | Catalog & Inventory Service | Tức thời (đồng bộ, trong luồng checkout) | US-004 | +| B5 | Tách giỏ hàng thành đơn con theo seller | 🆕 | Hệ thống | `Cart` + `CartItem` đã nhóm theo `seller_id` | `Order` (cha) + nhiều `OrderSeller` (con) + `OrderItem` | Cart & Order Service (nội bộ) | Đích NFR-01: hoàn tất checkout < 3 giây (cả B1–B5) | US-004 | +| B6 | Chọn phương thức thanh toán | 🆕 | Customer/Guest | Danh sách phương thức khả dụng (COD/VNPay/Momo) | Phương thức đã chọn gắn với `Order` | Cart & Order Service | Chưa ước lượng | US-007, US-008 | +| B7 | Xác nhận đơn COD | 🆕 | Hệ thống | `Order` + phương thức = COD | `OrderSeller.status` chuyển theo `BR-CART-07`/`BR-CART-03` (chờ PO chốt giới hạn COD) | Cart & Order Service | Tức thời | US-007 | +| B8 | Chuyển hướng cổng thanh toán, chờ xác nhận | 🆕 | Hệ thống + VNPay/Momo | `Order` + phương thức = VNPay/Momo | Redirect URL, sau đó webhook xác nhận | Payment Service + VNPay/Momo (bên ngoài) | Phụ thuộc SLA cổng thanh toán (`ASM-01` chưa xác minh) | US-008 | +| B9 | Giữ đơn `pending_payment`, chờ đối soát bù | ⚠️ | Hệ thống | Không nhận được webhook đúng hạn | Đơn ở trạng thái chờ, cần cơ chế đối soát bù (ngoài phạm vi thiết kế chi tiết US module này) | Payment Service | Chưa xác định — phụ thuộc `RISK-02` | Ghi nhận, không có US riêng trong module này | + +**Tổng thời gian dự kiến:** B1→B5 (đến khi tạo đơn) phải đạt < 3 giây theo `NFR-01`; không có +AS-IS để so sánh (xem §0 Phần A). + +## B3. Đối chiếu điểm đau → cách xử lý + +| Điểm đau | Bước TO-BE xử lý | Cách xử lý | Hiệu quả kỳ vọng | Nếu không xử lý: lý do | +|---|---|---|---|---| +| P1 (COD bùng đơn một phần, `RISK-01`) | B7 | **Chưa xử lý triệt để** — `BR-CART-03` (giới hạn giá trị đơn COD) đang chờ PO chốt (`OQ-006`, đã mở từ GĐ1). B7 chỉ tạo đơn theo phương thức đã chọn, chưa có bước chặn/giới hạn | Nếu PO chốt giới hạn: giảm rủi ro seller chịu phí hoàn hàng | Nếu PO không chốt giới hạn: rủi ro tồn tại nguyên vẹn trong TO-BE — **đây là khoảng trống đã biết, không phải bỏ sót**, ghi rõ trong `IMPACT` §0 | +| P2 (webhook trễ, `RISK-02`) | B9 | Ghi nhận trạng thái chờ; cơ chế đối soát bù (reconciliation job) là đề xuất của GĐ1 (`RISK-02`), **thuộc thiết kế chi tiết của module Thanh toán ở GĐ3**, không phải một US của module Giỏ hàng & Checkout (RQ-001…004 không bao gồm vận hành đối soát) | Giảm số đơn kẹt lâu, giảm khiếu nại CSKH | Nếu không xây cơ chế đối soát bù ở GĐ3: đơn có thể kẹt vô thời hạn — ghi nhận là phụ thuộc bắt buộc, xem `IMPACT` §1.5 | +| P3 (phí ship cao khiến bỏ giỏ, `RISK-04`) | B3 | Hiển thị phí ước tính **sớm** (ngay sau khi nhập địa chỉ, trước khi khách xác nhận thanh toán) để minh bạch hoá — không giải quyết triệt để việc phí cao, chỉ giảm bất ngờ | Giảm tỷ lệ bỏ giỏ do "phí ẩn xuất hiện cuối cùng"; không giảm được tổng phí | Việc giảm phí ship (VD trợ giá) là quyết định thương mại của PO, **ngoài phạm vi BA** — xem `RISK-04` phương án đề xuất | + +## B4. Bước bị bỏ — ai làm thay + +*Không có — không có AS-IS Phần A1/A2 để so sánh (giải thích ở §0 Phần A, greenfield không có +quy trình cũ nào bị thay thế bởi module này).* + +## B5. Bước mới — ai có thời gian làm + +| Bước mới | Ai làm | Thêm bao nhiêu thời gian/ngày | Đã hỏi người đó chưa | +|---|---|---|---| +| B1–B8 (toàn bộ luồng) | Customer/Guest tự thao tác (self-service qua giao diện); không có vai trò nội bộ nào phải làm thêm việc thủ công trong phạm vi RQ-001…004 | 0 — không phát sinh việc thủ công cho nhân sự nội bộ, vì đây là luồng tự phục vụ hoàn toàn | N/A | +| B9 (giữ đơn chờ đối soát) | *Nếu* cần CSKH can thiệp thủ công (theo A4 mục 2) | Chưa ước lượng — phụ thuộc tần suất webhook trễ thực tế (chưa đo) | ☐ Chưa hỏi — CSKH (STK ngoài phạm vi stakeholder module này) chưa được phỏng vấn | + +## B6. Thay đổi với người dùng + +| Vai trò | Trước | Sau | Cần đào tạo gì | Mức kháng cự dự kiến | +|---|---|---|---|---| +| Customer/Guest | Không có trải nghiệm nào (sản phẩm/thị trường hoàn toàn mới) | Trải nghiệm mua từ nhiều seller trong một giỏ, một lần thanh toán | Hướng dẫn UX tại chỗ (onboarding/tooltip) — chi tiết thuộc `WF`/`UICONV` ở GĐ3, ngoài phạm vi tài liệu này | Thấp (không có thói quen cũ để phá vỡ) — nhưng cần đo thật ở soft-launch theo `GOAL-01` | + +--- + +## 2. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | +|---|---|---|---|---| +| OQ-006 | *(đã mở từ GĐ1, nhắc lại)* Chính sách giới hạn giá trị đơn COD là gì? | PO sàn, Kế toán đối soát | 2026-09-08 | `BR-CART-03`, bước B7 | +| OQ-009 | Khi giá/tồn kho thay đổi giữa lúc thêm giỏ và lúc checkout (`ASM-06`), hệ thống tự động cập nhật giá mới và thông báo, hay chặn checkout yêu cầu khách xác nhận lại? | PO + Tech Lead | 2026-09-08 | Bước B3/B5, AC của US-004/US-005 ở GĐ3 | +| OQ-010 | Xác nhận khả thi kỹ thuật `ASM-01` (webhook VNPay/Momo gần thời gian thực) | Tech Lead | 2026-09-08 | Bước B8/D3, `BR-CART-06`, US-008 | + +## 3. Ngoài phạm vi + +- Thiết kế màn hình chi tiết (bố cục, field) → GĐ3 `SRS`/`WF` +- Chi tiết business rule (công thức, ví dụ đúng/sai) → `BR_CartCheckout_v1.0.md` +- Ma trận phân quyền → `RBAC_CartCheckout_v1.0.md` +- Luồng sau khi đơn đã tạo (đóng gói, giao hàng, đổi trả, khiếu nại — FR-08, FR-09, FR-19, + FR-25, FR-26) → module Quản lý đơn hàng, chạy GĐ1/GĐ2 riêng +- Cơ chế đối soát bù thanh toán (bước B9) → thiết kế chi tiết ở GĐ3 của module Thanh toán, + không phải một US của module này diff --git a/ba-output/e-commerce/02-analysis/RBAC_CartCheckout_v1.0.md b/ba-output/e-commerce/02-analysis/RBAC_CartCheckout_v1.0.md new file mode 100644 index 0000000..2c1509c --- /dev/null +++ b/ba-output/e-commerce/02-analysis/RBAC_CartCheckout_v1.0.md @@ -0,0 +1,141 @@ +# RBAC — Ma trận phân quyền — Giỏ hàng & Checkout (e-commerce) + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-2-analysis) | +| **Status** | 🟡 Draft | +| **Approved by** | — | +| **Profile** | screen · greenfield · standard | +| **Source** | `01-discovery/BRIEF_CartCheckout_v1.0.md` · `BACKLOG_CartCheckout_v1.0.md` · `BR_CartCheckout_v1.0.md` · `01-discovery/RISK_CartCheckout_v1.0.md` (RISK-01 phương án OTP) | +| **Scope** | Module Giỏ hàng & Checkout — RQ-001…RQ-004. Chỉ 2 vai trò buyer-side (Guest, Customer); vai trò nội bộ (Seller, Admin, CSR, Ops) **không** thao tác trực tiếp trong phạm vi RQ-001…004, xem ghi chú §1. | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | CR | +|---|---|---|---|---| +| 1.0 | 2026-09-08 | BA (qua skill ba-2-analysis) | Bản đầu — 2 vai trò, ma trận 8 hành động | — | + +--- + +> ⚠️ **Ngoại lệ gate G1** — xem cảnh báo đầy đủ ở đầu `PROCESS_CartCheckout_v1.0.md` và `DEC-02` +> ở `00-index/DECISION_e-commerce.md`. + +## 0. Vì sao không bỏ RBAC dù chỉ có 2 vai trò + +`domain-profiles.md`/`workflow.md` §2 cho phép bỏ `RBAC` ở `RIGOR = light` nếu **đúng 1 vai +trò**. Dự án này ở `RIGOR = standard` (không được bớt theo bảng "Bớt ở light"), và module này +có **2 vai trò** (Guest, Customer) với phạm vi dữ liệu khác nhau (Guest theo phiên, Customer +theo tài khoản) — nên `RBAC` vẫn bắt buộc, không được ghi "1 vai trò" để bỏ qua. + +## 1. Vai trò + +| ID | Vai trò | Ai thuộc vai trò này | Số người ước tính | Phạm vi dữ liệu | Vai trò hệ thống hiện có | +|---|---|---|---|---|---| +| ROLE-01 | Guest | Người dùng chưa đăng nhập, có `session_id` | Không giới hạn (bất kỳ ai truy cập web không đăng nhập) — theo mục tiêu quy mô "lớn" ở `BRIEF` §2 | Chỉ `Cart`/`Order` gắn với `session_id` của chính phiên đó | *(chưa có trong hệ thống — module đầu tiên, tạo mới)* | +| ROLE-02 | Customer | Người dùng đã đăng nhập (`user_account.role = customer`, theo tham chiếu SAD §5.2.1, không phải quyết định của module này) | Không giới hạn — hàng trăm nghìn–hàng triệu theo `BRIEF` §2 | Chỉ `Cart`/`Order` gắn với `customer_id` của chính họ | *(chưa có trong hệ thống — module đầu tiên, tạo mới)* | + +**Vai trò cố ý không đưa vào ma trận này** (thuộc module khác, ngoài phạm vi RQ-001…004): + +| Vai trò | Vì sao không có trong module này | +|---|---| +| Seller | Không thao tác trực tiếp lên `Cart`/`Order` lúc checkout — chỉ nhận `OrderSeller` sau khi đã tạo (thuộc FR-19, module Quản lý đơn hàng seller) | +| PlatformAdmin | Không có hành động quản trị nào trong phạm vi RQ-001…004 (không cấu hình/can thiệp giỏ hàng hay checkout của khách) | +| CSR / Ops | Có thể cần tra cứu đơn "kẹt chờ thanh toán" (`RISK-02`, xem `PROCESS` B9), nhưng đây là hành động **thuộc luồng xử lý sự cố sau checkout**, không phải một hành động của RQ-001…004 — nếu phát sinh nhu cầu tra cứu, cần `RBAC` riêng ở module Thanh toán/CSKH, ghi nhận là `OQ` mới nếu phát sinh ở GĐ3 | + +## 2. Ma trận vai trò × hành động + +*Ô ghi: `✅` được · `❌` không · `🔶` được nhưng có điều kiện (điều kiện ghi ngay trong ô).* + +| Hành động | ROLE-01
Guest | ROLE-02
Customer | BR | +|---|---|---|---| +| Xem giỏ hàng của mình | ✅ (theo `session_id`) | ✅ (theo `customer_id`) | — | +| Thêm sản phẩm vào giỏ | ✅ | ✅ | — | +| Sửa số lượng / xoá sản phẩm trong giỏ | ✅ | ✅ | — | +| Xem giỏ hàng / đơn hàng của người khác | ❌ | ❌ | — | +| Nhập/chọn địa chỉ giao hàng lúc checkout | 🔶 chỉ nhập mới, không có sổ địa chỉ đã lưu (không có tài khoản) | ✅ chọn từ `customer_address` đã lưu hoặc nhập mới | BR-CART-07 | +| Xác nhận đặt hàng (tạo `Order` + tách `OrderSeller`) | ✅ (BR-CART-07 — đủ thông tin liên hệ tối thiểu) | ✅ | BR-CART-01, BR-CART-02, BR-CART-07 | +| Chọn phương thức thanh toán (COD/VNPay/Momo) | ✅ | ✅ | BR-CART-04 | +| Xem kết quả đặt hàng/thanh toán ngay sau khi hoàn tất (của chính đơn vừa tạo) | ✅ | ✅ | — | +| Tra cứu lại đơn đã đặt sau khi rời phiên | 🔶 chỉ trong thời hạn phiên còn hiệu lực (chưa chốt số ngày cụ thể — xem `BR_CartCheckout` §3 `CART`); hết phiên thì **không** tra cứu lại được vì không có tài khoản | ✅ không giới hạn thời gian (thuộc FR-08, tham chiếu, ngoài phạm vi chi tiết hoá ở module này) | — | + +**Kiểm tra chất lượng ma trận:** không có cột nào toàn ✅ tuyệt đối — cả hai vai trò đều có ít +nhất một hành động ❌ (xem đơn hàng của người khác) hoặc 🔶 (tra cứu lại sau khi rời phiên đối +với Guest). Đã hỏi ngược *"vai trò nào KHÔNG được làm việc gì"*: cả Guest và Customer đều +**không** được xem giỏ hàng/đơn hàng của người khác — đây là ranh giới cốt lõi của module. + +## 3. Separation of Duties (SoD) + +🔴 **Không có bảng SoD với nội dung cặp hành động xung đột trong phạm vi RQ-001…004.** Lý do, +ghi rõ thay vì để trống theo đúng quy tắc "🔶 không điều kiện = chưa phân tích xong": + +> Mọi hành động trong ma trận §2 (tạo giỏ, tách đơn, chọn thanh toán) đều do **chính khách hàng +> tự thực hiện trên dữ liệu của họ (self-service)**, không có bước "người thứ hai duyệt/chốt +> sổ" nào trong phạm vi module này — việc tách đơn (BR-CART-01) và xác nhận thanh toán +> (BR-CART-06) đều do **hệ thống tự động thực hiện theo rule**, không phải một nhân sự nội bộ +> phê duyệt. Do đó khái niệm SoD ("người tạo không được tự duyệt") **không áp dụng được** ở +> đây theo đúng nghĩa — không có ai "duyệt" ngoài chính hệ thống. +> +> Điều này **không có nghĩa là module này không cần audit**: mọi lần tạo `Order`/`Payment` +> vẫn phải ghi vết (ai, lúc nào, giá trị) — xem §5. SoD sẽ trở nên cần thiết khi module Quản lý +> đơn hàng (FR-08/19/25, ngoài phạm vi) có bước Seller/CSR/Admin can thiệp thủ công (VD CSR +> duyệt hoàn tiền) — `RBAC` của module đó phải có SoD riêng. + +| ID | Cặp hành động xung đột | Quy tắc | Hệ thống chặn thế nào | Ai giám sát | +|---|---|---|---|---| +| *(không có trong phạm vi module này — xem giải thích trên)* | | | | | + +## 4. Dữ liệu nhạy cảm + +| Trường/dữ liệu | Loại | Ai được xem | Che thế nào | Xuất được không | Lưu bao lâu | Căn cứ | +|---|---|---|---|---|---|---| +| Địa chỉ giao hàng (`recipient_name`, `phone`, `address_line`) | PII | Chính Customer/Guest chủ đơn; hệ thống truyền cho seller tương ứng khi tách đơn (bắt buộc để giao hàng) | Không che khi hiển thị cho chính chủ; **mức che khi hiển thị cho seller — chưa chốt, liên quan `RISK-03` (chưa có đại diện Pháp chế)** | ❌ Không tự xuất được trong phạm vi module này | *(chưa chốt — xem `RISK` §GĐ1 mục retention, thuộc phạm vi Pháp chế/Bảo mật, `OQ-003`)* | `RISK-03`, NĐ13/2023 (dẫn theo `BRIEF` §7) | +| Số điện thoại | PII | Tương tự trên | Tương tự trên | ❌ | Tương tự trên | Tương tự trên | +| Giá trị giao dịch thanh toán (`Payment.amount`) | Tài chính | Chính chủ đơn; nội bộ Kế toán đối soát (STK-04) qua báo cáo — **ngoài phạm vi màn hình của module này** | Không che với chính chủ | ❌ Không tự xuất trong phạm vi module này | *(chưa chốt — thuộc lưu trữ chứng từ tài chính, ngoài phạm vi BA module này)* | NFR-05 | +| `gateway_transaction_ref` (VNPay/Momo) | Tài chính/kỹ thuật | Chính chủ đơn (chỉ hiển thị tham chiếu, không hiển thị chi tiết cổng thanh toán) | Không hiển thị đầy đủ chuỗi thô nếu chứa thông tin nội bộ cổng thanh toán — **chi tiết che thế nào chưa chốt, để GĐ3 xác nhận với Tech Lead** | ❌ | — | BR-CART-05 | + +🔴 **Không có trường thẻ thanh toán** (số thẻ/CVV) trong phạm vi module này theo `BR-CART-05` — +không có gì để phân tích thêm ở dòng này, ghi nhận rõ để tránh hiểu nhầm là bị bỏ sót. + +## 5. Lưu vết (audit) + +| Hành động | Ghi vết | Nội dung ghi | Giữ bao lâu | Ai xem được | +|---|---|---|---|---| +| Tạo `Order`/`OrderSeller` (checkout) | ✅ | ai (customer_id/session_id) · lúc nào · nội dung đơn (US-004) | *(chưa chốt — liên quan retention dữ liệu tài chính, ngoài phạm vi quyết định của module này, xem `IMPACT` §1.6)* | Chính chủ đơn (qua tra cứu); nội bộ — ngoài phạm vi màn hình module này | +| Khởi tạo thanh toán / cập nhật `Payment.status` | ✅ | ai · lúc nào · phương thức · kết quả (BR-CART-06) | *(chưa chốt — tương tự trên)* | Tương tự trên | +| Đăng nhập/định danh Guest thất bại hoặc bất thường (VD spam tạo đơn liên tục) | 🔶 **Chưa chốt có cần cơ chế chống lạm dụng (rate limit) cho Guest checkout không** | — | — | — | + +Ba câu hỏi cho mỗi hành động nhạy cảm: +1. **Ai được xem** — đã trả lời ở §4: chỉ chính chủ đơn trong phạm vi màn hình module này. +2. **Có cần lưu vết** — có, cho mọi hành động tạo `Order`/`Payment` (đúng theo nguyên tắc dữ + liệu tài chính phải có dấu vết), nhưng **thời hạn lưu cụ thể chưa chốt** — xem `IMPACT` + §1.6 và ghi chú retention ở GĐ1. +3. **Có cần lý do** — không áp dụng cho hành động tự phục vụ của khách hàng (tạo đơn/thanh + toán là quyền tự nhiên của họ, không cần giải trình lý do). + +## 6. Hành vi khi không đủ quyền + +*Quy tắc W7 — ba trạng thái khác nhau: không hiển thị · hiển thị nhưng disable · hiển thị và +read-only.* + +| Tình huống | Hành vi | Lý do | +|---|---|---| +| Guest/Customer cố xem giỏ hàng/đơn hàng của người khác (đoán ID/URL) | Không hiển thị dữ liệu, trả lỗi từ chối truy cập (mã lỗi cụ thể — GĐ3) | Tránh lộ dữ liệu PII/tài chính của người khác | +| Guest cố tra cứu lại đơn sau khi hết hạn phiên | Không hiển thị được đơn cũ — hệ thống coi như phiên mới, **hành vi UX cụ thể (thông báo gì) chưa chốt, để GĐ3** | Guest không có cơ chế xác thực định danh liên phiên | +| Guest/Customer bấm "Đặt hàng" khi giỏ hàng không đủ tồn kho | Hiện nút, nhưng chặn hành động khi bấm, báo lỗi cụ thể theo item (BR-CART-02) — **không disable trước vì tồn kho có thể đổi liên tục (ASM-06)** | Giữ trải nghiệm mượt, tránh disable sai do dữ liệu tồn kho chưa cập nhật kịp | +| Guest/Customer bấm "Xác nhận đặt hàng" khi chưa chọn phương thức thanh toán | Hiện nút, **disable** cho tới khi chọn phương thức (BR-CART-04) | Ngăn submit thiếu dữ liệu bắt buộc | +| Gọi thẳng API tạo đơn/thanh toán không đủ điều kiện (VD Guest thiếu field bắt buộc BR-CART-07) | Trả lỗi 4xx + ghi log, không tạo bản ghi | Chặn ở cả FE và BE (W7 nhắc: chặn UI là trải nghiệm, chặn BE mới là bảo mật) | + +## 7. Thay đổi so với phân quyền hiện tại + +*Không áp dụng — `LIFECYCLE = greenfield`, không có phân quyền cũ nào để so sánh (đây là vai +trò/quyền hoàn toàn mới của module đầu tiên).* + +## 8. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | +|---|---|---|---|---| +| OQ-012 | Guest có cần giới hạn giá trị đơn hoặc xác thực OTP cho đơn giá trị cao không (liên quan `RISK-01` phương án (b))? | PO, Bảo mật *(chưa có người — `OQ-003` ở GĐ1)* | 2026-09-08 | §2 hàng "Xác nhận đặt hàng", `BR-CART-03` | +| *(mới)* OQ-015 | Có cần cơ chế chống lạm dụng (rate limit/CAPTCHA) cho Guest checkout để tránh spam tạo đơn giả không? | Tech Lead, Bảo mật | 2026-09-08 | §5, thiết kế kỹ thuật GĐ3 | +| *(mới)* OQ-016 | Mức che dữ liệu PII (địa chỉ/SĐT) khi truyền cho seller lúc tách đơn là gì? | Pháp chế/Bảo mật *(chưa có người — `OQ-003`)*, PO | 2026-09-08 | §4, `RISK-03` | diff --git a/ba-output/e-commerce/03-specification/AC_US-002_v1.0.md b/ba-output/e-commerce/03-specification/AC_US-002_v1.0.md new file mode 100644 index 0000000..cdaba4a --- /dev/null +++ b/ba-output/e-commerce/03-specification/AC_US-002_v1.0.md @@ -0,0 +1,215 @@ +# AC — Acceptance Criteria — US-002 Xem giỏ hàng nhóm theo seller + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-3-specification) | +| **Status** | 🟡 Draft | +| **Approved by** | QA: — *(chưa có QA thật tham gia lần chạy này)* | +| **Source** | `SRS_US002-003_v1.0.md` · `RBAC_CartCheckout_v1.0.md` §2, §6 | +| **Scope** | US-002 | + +## 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 — 6 AC, 4 nhóm | — | + +--- + +## 1. Bốn nhóm bắt buộc + +| Nhóm | Nội dung | Tối thiểu | Số AC đã viết | +|---|---|---|---| +| 1. Luồng thành công | Xem giỏ hàng nhóm theo seller | 1/hành động | 2 | +| 2. Validation | Không áp dụng — US-002 không có input do người dùng nhập, chỉ hiển thị (xem lý do dưới) | — | 0 (N/A có lý do) | +| 3. Lỗi hệ thống | Timeout, 5xx, phân biệt "rỗng thật" vs "không tải được" | ≥1 | 2 | +| 4. Phân quyền | Không đủ quyền, hết phiên | ≥1/vai trò bị chặn | 2 | + +**Vì sao Nhóm 2 (Validation) ghi N/A:** US-002 là hành động **xem** thuần tuý (`SCR-04` khi mở màn hình) — không có trường nào do người dùng nhập trong phạm vi US-002 (nhập số lượng thuộc US-003, xem `AC_US-003_v1.0.md`). Đây không phải "chỉ có nhóm 1" (vi phạm nguyên tắc), vì Nhóm 3 và Nhóm 4 đã viết đủ. + +--- + +## 2. Danh sách AC + +### Nhóm 1 — Luồng thành công + +#### AC-US002-01 — Xem giỏ hàng có nhiều seller + +| | | +|---|---| +| **Liên quan** | SCR-04 · C01, C02, C03–C06, C08, C09, C11 | +| **Vai trò** | ROLE-02 Customer (hành vi tương tự với ROLE-01 Guest, khác ở định danh `X-Guest-Session-Id` thay JWT) | + +``` +Given tôi đăng nhập với ROLE-02 (Customer) và giỏ hàng của tôi (Cart.status=active) có 5 CartItem: + 3 CartItem thuộc seller "Shop A", 2 CartItem thuộc seller "Shop B" +When tôi mở SCR-04 (Giỏ hàng) +Then hệ thống hiển thị đúng 2 nhóm theo seller ("Shop A", "Shop B"), mỗi nhóm hiển thị đúng + số CartItem thuộc nhóm đó + And tạm tính mỗi nhóm (C08) bằng Σ (quantity × đơn giá hiển thị) của các CartItem trong + nhóm đó + And tổng cộng giỏ hàng (C09) bằng Σ tất cả C08 + And nút "Tiến hành Checkout" (C11) hiển thị và không bị disable +``` + +**Dữ liệu mẫu để test:** + +| Field | Giá trị | +|---|---| +| Shop A — CartItem 1 | quantity=2, đơn giá=100.000 ₫ | +| Shop A — CartItem 2 | quantity=1, đơn giá=50.000 ₫ | +| Shop A — CartItem 3 | quantity=1, đơn giá=75.000 ₫ | +| Shop A — tạm tính (C08) kỳ vọng | 2×100.000 + 1×50.000 + 1×75.000 = 325.000 ₫ | +| Shop B — CartItem 1 | quantity=1, đơn giá=200.000 ₫ | +| Shop B — CartItem 2 | quantity=2, đơn giá=30.000 ₫ | +| Shop B — tạm tính (C08) kỳ vọng | 1×200.000 + 2×30.000 = 260.000 ₫ | +| Tổng cộng (C09) kỳ vọng | 325.000 + 260.000 = 585.000 ₫ | + +#### AC-US002-02 — Xem giỏ hàng rỗng + +| | | +|---|---| +| **Liên quan** | SCR-04 · C10, C11 | +| **Vai trò** | ROLE-01, ROLE-02 | + +``` +Given tôi đăng nhập với ROLE-02 và giỏ hàng của tôi không có CartItem nào (Cart.status=active, + 0 dòng) +When tôi mở SCR-04 +Then hệ thống hiển thị trạng thái "Giỏ hàng trống" (khoá cart.empty.title) và nút + "Tiếp tục mua sắm" (C10) + And nút "Tiến hành Checkout" (C11) không hiển thị/bị disable — theo §2.A.3.6 của SRS +``` + +--- + +### Nhóm 2 — Validation + +*N/A — xem lý do ở mục 1.* + +--- + +### Nhóm 3 — Lỗi hệ thống + +#### AC-US002-03 — Lỗi hệ thống khi tải giỏ hàng + +| | | +|---|---| +| **Liên quan** | SCR-04 · C12, C13 | +| **Vai trò** | ROLE-01, ROLE-02 | + +``` +Given tôi đăng nhập với ROLE-02 +When tôi mở SCR-04 và GET /v1/cart trả về 500/503 hoặc timeout (ngưỡng — xem NFR §1, OQ-033) +Then hệ thống hiển thị banner lỗi "Không tải được dữ liệu, thử lại." (E-CART-0004) tại vùng + danh sách + And nút "Thử lại" (C13) hiển thị; bấm vào gọi lại GET /v1/cart +``` + +Ba tình huống tối thiểu của nhóm này: + +| # | Tình huống | AC | +|---|---|---| +| 1 | Server trả 5xx | AC-US002-03 | +| 2 | Timeout / mất mạng | AC-US002-03 | +| 3 | Dữ liệu bị người khác sửa/xoá trong lúc mình đang mở | Không áp dụng ở US-002 (chỉ xem, không sửa) — xem `AC_US-003_v1.0.md` §3 Nhóm 3 (`AC-US003-11`) cho trường hợp này khi có thao tác sửa/xoá | + +#### AC-US002-04 — Phân biệt "giỏ hàng chưa từng có dữ liệu" và "không tải được" + +| | | +|---|---| +| **Liên quan** | SCR-04 · C10, C12 | +| **Vai trò** | ROLE-02 | + +``` +Given tôi đăng nhập với ROLE-02 lần đầu, chưa từng thêm sản phẩm nào vào giỏ (Cart mới tạo, + 0 CartItem); GET /v1/cart trả 200 với danh sách rỗng +When tôi mở SCR-04 +Then hệ thống hiển thị trạng thái "Giỏ hàng trống" (không phải banner lỗi C12) + And hai trạng thái "giỏ hàng trống thật" (AC-US002-02/04) và "không tải được" (AC-US002-03) + dùng hai khối hiển thị khác nhau (data-state khác nhau trong WF), không dùng chung một + thông điệp — kiểm chứng bằng cách tắt mạng khi mở màn hình lần đầu (kỳ vọng thấy banner + lỗi, KHÔNG phải "Giỏ hàng trống") +``` + +--- + +### Nhóm 4 — Phân quyền + +#### AC-US002-05 — Guest chỉ thấy giỏ hàng của session mình + +| | | +|---|---| +| **Liên quan** | SCR-04 | +| **Vai trò** | ROLE-01 | + +``` +Given tôi là Guest với X-Guest-Session-Id = S1; một Guest khác có giỏ hàng thuộc session S2 + (không phải của tôi) +When tôi gọi GET /v1/cart với header X-Guest-Session-Id: S1 +Then hệ thống chỉ trả về giỏ hàng gắn với S1 (dữ liệu của chính tôi), không có cách nào lộ + dữ liệu của S2 qua endpoint này (endpoint không nhận cartId của người khác qua tham số) +``` + +#### AC-US002-06 — Customer hết phiên đăng nhập cố xem giỏ hàng + +| | | +|---|---| +| **Liên quan** | SCR-04, SCR-08 (đăng nhập) | +| **Vai trò** | ROLE-02 | + +``` +Given tôi trước đó đã đăng nhập và có giỏ hàng theo customer_id; nay access token đã hết hạn + (401 ERR_AUTH_INVALID_TOKEN) +When tôi mở SCR-04 +Then hệ thống chuyển hướng về màn đăng nhập (SCR-08) + And giữ đường dẫn quay lại SCR-04 sau khi đăng nhập thành công (theo UICONV §2) +``` + +--- + +## 3. Bảng dữ liệu biên + +*N/A — US-002 không có field nhập liệu (chỉ xem). Xem `AC_US-003_v1.0.md` §4 cho F01 (số lượng).* + +--- + +## 4. Kịch bản kết hợp + +| # | Kịch bản | Các bước | AC liên quan | +|---|---|---|---| +| S1 | Mở giỏ hàng nhiều seller rồi tiến hành checkout | SCR-04 (mở, kiểm tra tổng đúng) → bấm "Tiến hành Checkout" (C11) → điều hướng SCR-05 (chỉ kiểm tra điều hướng, ngoài phạm vi hành vi SCR-05) | AC-US002-01 | + +--- + +## 5. Truy vết + +| AC | US | BR | Field/Thành phần | Mã lỗi | Test case (QA điền) | Kết quả (QA điền) | +|---|---|---|---|---|---|---| +| AC-US002-01 | US-002 | — | C01, C02, C03–C06, C08, C09, C11 | — | | | +| AC-US002-02 | US-002 | BR §3 CART | C10, C11 | — | | | +| AC-US002-03 | US-002 | — | C12, C13 | E-CART-0004 | | | +| AC-US002-04 | US-002 | — | C10, C12 | E-CART-0004 | | | +| AC-US002-05 | US-002 | RBAC §2 | — | — | | | +| AC-US002-06 | US-002 | — | — | — | | | + +--- + +## 6. Xác nhận của QA + +| | | +|---|---| +| **Người xác nhận** | *(chưa có — chưa có QA thật tham gia lần chạy này)* | +| **Ngày** | — | +| ☐ Mọi AC đều test được (không có AC mô tả cảm tính) | | +| ☐ Đủ 4 nhóm (Nhóm 2 N/A có lý do) | | +| ☐ Bảng dữ liệu biên đủ dùng để viết test case (N/A — không có field ở US-002) | | +| ☐ Không có AC nào mâu thuẫn với AC khác | | + +**AC bị QA từ chối:** + +| AC | Lý do từ chối | BA sửa thế nào | +|---|---|---| +| | | | diff --git a/ba-output/e-commerce/03-specification/AC_US-003_v1.0.md b/ba-output/e-commerce/03-specification/AC_US-003_v1.0.md new file mode 100644 index 0000000..37c70fb --- /dev/null +++ b/ba-output/e-commerce/03-specification/AC_US-003_v1.0.md @@ -0,0 +1,267 @@ +# AC — Acceptance Criteria — US-003 Sửa số lượng / xoá sản phẩm trong giỏ hàng + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-3-specification) | +| **Status** | 🟡 Draft | +| **Approved by** | QA: — *(chưa có QA thật tham gia lần chạy này)* | +| **Source** | `SRS_US002-003_v1.0.md` · `RBAC_CartCheckout_v1.0.md` §6 · `BR_CartCheckout_v1.0.md` §3 | +| **Scope** | US-003 | + +## 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 — 13 AC, 4 nhóm (2 AC còn mở chờ `OQ-028`/`OQ-032`, ghi rõ thay vì bịa) | — | + +--- + +## 1. Bốn nhóm bắt buộc + +| Nhóm | Nội dung | Tối thiểu | Số AC đã viết | +|---|---|---|---| +| 1. Luồng thành công | Tăng/giảm số lượng, xoá dòng, xoá nhóm, xoá giỏ, huỷ modal | 1/hành động | 6 | +| 2. Validation | Số lượng không hợp lệ; số lượng về 0 | 1/rule | 2 (1 còn mở — `OQ-028`) | +| 3. Lỗi hệ thống | 5xx cập nhật, timeout xoá, item bị xoá đồng thời | ≥1 | 3 | +| 4. Phân quyền | Sửa/xoá CartItem không thuộc quyền sở hữu (Customer, Guest) | ≥1/vai trò | 2 (1 còn mở — `OQ-032`) | + +--- + +## 2. Danh sách AC + +### Nhóm 1 — Luồng thành công + +#### AC-US003-01 — Tăng số lượng CartItem thành công + +| | | +|---|---| +| **Liên quan** | SCR-04 · F01, C08, C09 | +| **Vai trò** | ROLE-02 (tương tự ROLE-01) | + +``` +Given CartItem X có quantity=2, Cart.status=active +When tôi bấm nút "+" (F01) để tăng số lượng lên 3 +Then hệ thống gọi PATCH /v1/cart/items/{X} với quantity=3, nhận 200 OK + And F01 hiển thị 3; tạm tính nhóm (C08) và tổng cộng (C09) cập nhật lại ngay theo giá trị mới +``` + +#### AC-US003-02 — Giảm số lượng CartItem thành công (còn ≥1) + +``` +Given CartItem X có quantity=3 +When tôi bấm nút "-" (F01) để giảm còn 2 +Then PATCH thành công, F01=2, C08/C09 cập nhật +``` + +#### AC-US003-03 — Xoá CartItem thành công (đã xác nhận modal) + +| | | +|---|---| +| **Liên quan** | SCR-04 · C07, C08, C09 | +| **Vai trò** | ROLE-02 | + +``` +Given CartItem X tồn tại trong nhóm seller "Shop A" (nhóm đang có 2 CartItem) +When tôi bấm "Xoá" (C07) trên CartItem X, modal xác nhận hiện ra (theo UICONV §5), tôi bấm + nút xác nhận trong modal +Then hệ thống gọi DELETE /v1/cart/items/{X}, nhận 200/204 + And dòng CartItem X biến mất khỏi danh sách; tạm tính nhóm "Shop A" (C08) cập nhật (còn + 1 CartItem); tổng cộng (C09) cập nhật +``` + +#### AC-US003-04 — Xoá CartItem cuối cùng của một nhóm seller + +``` +Given nhóm seller "Shop B" chỉ có 1 CartItem +When tôi xoá CartItem đó (đã xác nhận modal) +Then toàn bộ khối nhóm "Shop B" (C02 + dòng CartItem) biến mất khỏi màn hình — không hiển + thị một nhóm rỗng không có dòng nào +``` + +#### AC-US003-05 — Xoá CartItem cuối cùng của toàn giỏ hàng + +``` +Given giỏ hàng chỉ còn duy nhất 1 CartItem (1 nhóm, 1 dòng) +When tôi xoá CartItem đó (đã xác nhận modal) +Then màn hình chuyển sang trạng thái "Giỏ hàng trống" (theo SRS §2.A.3.6); nút + "Tiến hành Checkout" (C11) ẩn/disable + And Cart.status vẫn là active (KHÔNG tự chuyển abandoned — theo BR §3, chỉ hết hạn phiên + mới chuyển abandoned) +``` + +#### AC-US003-06 — Huỷ modal xác nhận xoá + +``` +Given modal xác nhận xoá CartItem X đang mở +When tôi bấm nút huỷ hoặc đóng modal (không xác nhận) +Then CartItem X vẫn còn nguyên trong danh sách; không có request DELETE nào được gửi +``` + +--- + +### Nhóm 2 — Validation + +#### AC-US003-07 — Nhập số lượng không phải số nguyên dương hợp lệ + +| | | +|---|---| +| **Liên quan** | SCR-04 · F01 | +| **Vai trò** | ROLE-02 | + +``` +Given CartItem X có quantity=2 +When tôi nhập trực tiếp vào F01 giá trị không hợp lệ (VD "-1", "1.5", "abc", để trống) +Then hệ thống hiện lỗi inline dưới F01: "Số lượng phải là số nguyên từ 1 trở lên." + (E-CART-0002) + And không gửi request PATCH; F01 giữ nguyên giá trị hợp lệ trước đó (không lưu giá trị lỗi) +``` + +#### AC-US003-08 — Giảm số lượng về 0 *(🔴 chưa viết được đầy đủ — chờ `OQ-028`)* + +``` +Given CartItem X có quantity=1 (đã ở mức tối thiểu) +When tôi bấm nút "-" hoặc nhập trực tiếp "0" vào F01 +Then 🔴 CHƯA XÁC ĐỊNH — phụ thuộc OQ-028 (PO chưa chốt: (a) chặn nút "-"/nhập 0, hiện + thông báo giữ tối thiểu 1, hay (b) tự động mở modal xác nhận xoá dòng) +``` + +*QA không viết test case cho AC này cho tới khi `OQ-028` được trả lời — đây là chỗ SRS chưa +viết xong, không phải QA bỏ sót.* + +--- + +### Nhóm 3 — Lỗi hệ thống + +#### AC-US003-09 — Server lỗi 5xx khi cập nhật số lượng + +| | | +|---|---| +| **Liên quan** | SCR-04 · F01 | +| **Vai trò** | ROLE-02 | + +``` +Given CartItem X có quantity=2 +When tôi đổi thành 5 (bấm "+" 3 lần hoặc nhập tay) và PATCH /v1/cart/items/{X} trả 500 +Then hệ thống hiện banner lỗi tại dòng CartItem: "Không thể cập nhật giỏ hàng, thử lại." + (E-CART-0006) + And 🔴 F01 trở về giá trị trước đó (2), KHÔNG giữ giá trị đã nhập lỗi (5); nút +/- mở lại + được bấm ngay +``` + +#### AC-US003-10 — Timeout khi xoá CartItem + +``` +Given tôi bấm "Xoá" trên CartItem X (đã xác nhận modal) +When request DELETE bị timeout theo ngưỡng NFR §1 (xem OQ-033) +Then hệ thống hiện banner lỗi tại dòng: "Không thể cập nhật giỏ hàng, thử lại." (E-CART-0006) + And CartItem X vẫn hiển thị trong danh sách (không xoá khỏi giao diện khi chưa có xác nhận + từ server); nút "Xoá" bấm lại được +``` + +#### AC-US003-11 — CartItem đã bị xoá bởi thao tác khác (đồng thời, VD 2 tab) + +``` +Given CartItem X đang hiển thị trên màn hình của tôi, nhưng đã bị xoá khỏi giỏ hàng ở một + tab/thiết bị khác trước đó +When tôi bấm sửa số lượng (F01) hoặc bấm "Xoá" (C07) trên CartItem X +Then PATCH/DELETE trả 404 ERR_NOT_FOUND hoặc 409 ERR_CONFLICT (xem API §4) + And hệ thống hiện banner "Sản phẩm này đã được xoá khỏi giỏ hàng trước đó." (E-CART-0003), + sau đó ẩn dòng CartItem X khỏi danh sách và cập nhật lại C08/C09 +``` + +Ba tình huống tối thiểu của nhóm này: + +| # | Tình huống | AC | +|---|---|---| +| 1 | Server trả 5xx | AC-US003-09 | +| 2 | Timeout / mất mạng | AC-US003-10 | +| 3 | Dữ liệu bị người khác sửa/xoá trong lúc mình đang mở | AC-US003-11 | + +--- + +### Nhóm 4 — Phân quyền + +#### AC-US003-12 — Gọi thẳng API sửa/xoá CartItem không thuộc quyền sở hữu (Customer) + +| | | +|---|---| +| **Liên quan** | SCR-04 | +| **Vai trò** | ROLE-02 | + +``` +Given tôi đăng nhập ROLE-02 với customerId = A; CartItem Y thuộc Cart của customerId = B +When tôi gọi thẳng PATCH /v1/cart/items/{Y} với token của A +Then hệ thống trả 403 ERR_FORBIDDEN_OWNERSHIP (E-CART-0005), không cập nhật CartItem Y + And không có thông tin nào của CartItem Y bị lộ ra trong response lỗi +``` + +#### AC-US003-13 — Guest cố sửa/xoá CartItem không thuộc session của mình *(🔴 chưa viết được đầy đủ — chờ `OQ-032`)* + +``` +Given tương tự AC-US003-12 nhưng với ROLE-01 (Guest): X-Guest-Session-Id = S1 của tôi, + CartItem Z thuộc Cart của session S2 +When tôi gọi thẳng PATCH /v1/cart/items/{Z} với X-Guest-Session-Id: S1 +Then 🔴 CHƯA XÁC ĐỊNH — đề xuất BA: trả 403 ERR_FORBIDDEN_OWNERSHIP (E-CART-0005) giống hệt + AC-US003-12, cần Tech Lead xác nhận cơ chế đối chiếu session_id (OQ-032) trước khi coi + AC này là chốt +``` + +🔴 Chặn ở giao diện là trải nghiệm, **chặn ở backend mới là bảo mật**. Cả hai AC nhóm này đều +kiểm tra gọi thẳng API, không chỉ kiểm tra ẩn nút trên giao diện. + +--- + +## 3. Bảng dữ liệu biên + +| Field | Dưới ngưỡng | Ngưỡng dưới | Trong khoảng | Ngưỡng trên | Trên ngưỡng | Rỗng | Ký tự đặc biệt | Khoảng trắng đầu/cuối | +|---|---|---|---|---|---|---|---|---| +| F01 Số lượng (≥1, ngưỡng trên **chưa chốt** — `OQ-030`) | `0` → lỗi `E-CART-0002` (hành vi cụ thể — `OQ-028`) | `1` → OK | `5` → OK | 🔴 chưa có ngưỡng trên xác nhận — `OQ-030` | 🔴 chưa có ngưỡng trên — `OQ-030` | Xoá trắng ô nhập → lỗi bắt buộc (`E-CART-0002`) | `"abc"`, `"1.5"`, `"-1"` → lỗi `E-CART-0002` | N/A — F01 là input dạng số (`type=number`), không nhận khoảng trắng | + +--- + +## 4. Kịch bản kết hợp + +| # | Kịch bản | Các bước | AC liên quan | +|---|---|---|---| +| S1 | Sửa số lượng rồi xoá hết một nhóm seller | SCR-04 (mở) → sửa số lượng CartItem của "Shop B" (tổng cập nhật) → xoá cả 2 CartItem còn lại của "Shop B" → nhóm "Shop B" biến mất, tổng cộng chỉ còn của "Shop A" | AC-US003-01, 03, 04 | + +--- + +## 5. Truy vết + +| AC | US | BR | Field/Thành phần | Mã lỗi | Test case (QA điền) | Kết quả (QA điền) | +|---|---|---|---|---|---|---| +| AC-US003-01 | US-003 | BR §3 CART | F01, C08, C09 | — | | | +| AC-US003-02 | US-003 | BR §3 CART | F01, C08, C09 | — | | | +| AC-US003-03 | US-003 | BR §3 CART | C07, C08, C09 | — | | | +| AC-US003-04 | US-003 | — | C02, C07 | — | | | +| AC-US003-05 | US-003 | BR §3 CART | C07, C10, C11 | — | | | +| AC-US003-06 | US-003 | — | C07 | — | | | +| AC-US003-07 | US-003 | — | F01 | E-CART-0002 | | | +| AC-US003-08 | US-003 | — | F01 | E-CART-0002 (dự kiến) | *(chờ OQ-028)* | | +| AC-US003-09 | US-003 | — | F01 | E-CART-0006 | | | +| AC-US003-10 | US-003 | — | C07 | E-CART-0006 | | | +| AC-US003-11 | US-003 | — | F01, C07 | E-CART-0003 | | | +| AC-US003-12 | US-003 | RBAC §6 | — | E-CART-0005 | | | +| AC-US003-13 | US-003 | RBAC §6 | — | E-CART-0005 (dự kiến) | *(chờ OQ-032)* | | + +--- + +## 6. Xác nhận của QA + +| | | +|---|---| +| **Người xác nhận** | *(chưa có — chưa có QA thật tham gia lần chạy này)* | +| **Ngày** | — | +| ☐ Mọi AC đều test được (2 AC còn mở, chờ OQ trước khi viết test case) | | +| ☐ Đủ 4 nhóm | | +| ☐ Bảng dữ liệu biên đủ dùng để viết test case | | +| ☐ Không có AC nào mâu thuẫn với AC khác | | + +**AC bị QA từ chối:** + +| AC | Lý do từ chối | BA sửa thế nào | +|---|---|---| +| | | | diff --git a/ba-output/e-commerce/03-specification/API_US002-003_v1.0.md b/ba-output/e-commerce/03-specification/API_US002-003_v1.0.md new file mode 100644 index 0000000..d5107dc --- /dev/null +++ b/ba-output/e-commerce/03-specification/API_US002-003_v1.0.md @@ -0,0 +1,235 @@ +# API — Contract — US-002, US-003 (SCR-04 Giỏ hàng) + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-3-specification) | +| **Status** | 🟡 Draft | +| **Nguồn contract** | 🔶 **Hỗn hợp** — method/path/auth: ✅ **BE cung cấp** (`e-commerce/docs/sections/04-api-design.md` §4.1.5 "Cart & Order Service"); request/response body schema: ⚠️ **BA đề xuất — chờ BE xác nhận** (SAD liệt kê method/path/mô tả ngắn nhưng không có ví dụ JSON cho ba endpoint dưới đây, khác với `POST /v1/checkout` là endpoint duy nhất SAD có ví dụ đầy đủ) | +| **Approved by** | BE Lead: — | +| **Source** | `SRS_US002-003_v1.0.md` · `e-commerce/docs/sections/04-api-design.md` §4.1.1, §4.1.5, §4.1.13, §4.2 | +| **Scope** | US-002, US-003 | + +> 🔴 **Đọc dòng `Nguồn contract` trước.** Method/path là ràng buộc thật (đã có trong SAD đã +> duyệt). Cấu trúc request/response bên dưới là **giả định của BA**, dev phải đối chiếu với +> tài liệu BE thật (hoặc OpenAPI spec nếu có) trước khi code. + +--- + +## 1. Ba điểm phải chốt trước tiên + +| # | Vấn đề | Quyết định | Lý do | +|---|---|---|---| +| 1 | **Số lớn** (`cartItemId`, `productVariantId`, `sellerId`) truyền dạng gì | `string` | Khớp ví dụ `POST /v1/checkout` của SAD (`"orderId": "order_001"` dạng string) — áp dụng nhất quán cho mọi id trong hệ thống | +| 2 | **Thời gian** — SCR-04 không hiển thị trường thời gian nào | N/A | Không có trường `*_at` nào cần hiển thị ở US-002/US-003 | +| 3 | **Phân trang** | Không áp dụng — `GET /v1/cart` trả toàn bộ giỏ hàng, không phân trang | Giỏ hàng không có khái niệm "trang", số dòng thực tế nhỏ (không giống danh sách sản phẩm) | + +## 2. Quy ước chung + +| | | +|---|---| +| **Base URL** | `https://api./v1` (theo SAD §4.1.1) | +| **Xác thực** | Bearer JWT (Customer) hoặc header `X-Guest-Session-Id` (Guest) — theo SAD §4.1.1, §4.1.5 | +| **Định dạng phản hồi thành công** | `{ "data": {...} }` (theo SAD §4.1.1) | +| **Định dạng phản hồi lỗi** | `{ "error": { "code", "message", "details" }, "traceId" }` (theo SAD §4.1.13 — **khác** với format mặc định của template BA, ưu tiên đúng theo SAD) | +| **Mã HTTP dùng** | 200 · 204 · 400 · 401 · 403 · 404 · 409 · 500 · 503 | +| **Ngôn ngữ thông điệp** | FE tự dịch theo mã lỗi (`code`) + bảng text §4.2 của `SRS`, không dựa vào `message` trả về từ BE để hiển thị cho người dùng cuối (theo `UICONV` §9 — BA sở hữu text hiển thị, W5) | + +🔴 **Lỗi nghiệp vụ trả mã HTTP 4xx** (không phải 200 kèm cờ lỗi) — đúng theo thiết kế đã có ở +SAD §4.1.13. + +--- + +## 3. Endpoint + +### 3.1 `GET /v1/cart` — Lấy giỏ hàng hiện tại (đa seller) + +| | | +|---|---| +| **Mục đích** | Tải dữ liệu hiển thị SCR-04 (US-002) | +| **Màn hình** | SCR-04 | +| **Quyền** | ROLE-01 Guest (`X-Guest-Session-Id`) hoặc ROLE-02 Customer (Bearer JWT) — không cần scope riêng, chỉ cần định danh hợp lệ | + +**Query parameters:** không có (không phân trang). + +**Response 200** *(⚠️ đề xuất của BA — SAD không có ví dụ JSON cho endpoint này)* + +```json +{ + "data": { + "cartId": "cart_123", + "status": "active", + "sellers": [ + { + "sellerId": "seller_11", + "sellerName": "Shop A", + "subtotalVnd": 325000, + "items": [ + { + "cartItemId": "citem_001", + "productVariantId": "variant_789", + "productName": "Áo thun basic", + "variantLabel": "Size M, Đỏ", + "unitPriceVnd": 100000, + "quantity": 2, + "imageUrl": "https://cdn.example.com/p/789.jpg" + } + ] + } + ], + "totalVnd": 585000, + "totalItemCount": 5 + } +} +``` + +**Từng trường** + +| Trường | Kiểu | Có thể null | Nguồn | Ghi chú | +|---|---|---|---|---| +| `cartId` | string | ❌ | `cart.id` | — | +| `status` | enum | ❌ | `cart.status` | `active`/`converted`/`abandoned` — SCR-04 chỉ hiển thị khi `active` | +| `sellers[].sellerId` | string | ❌ | `cart_item.seller_id` | — | +| `sellers[].sellerName` | string | ❌ | Module Seller Management (tham chiếu) | 🔴 **BA đề xuất BE trả kèm tên đã join sẵn** — cần BE xác nhận, xem §5 mục 1 | +| `sellers[].subtotalVnd` | number | ❌ | Tính từ `items[]` | 🔴 **BA đề xuất BE tính sẵn** (không để FE tự cộng) — tránh sai lệch làm tròn giữa FE/BE, xem §5 mục 2 | +| `items[].unitPriceVnd` | number | ❌ | `cart_item.unit_price_snapshot` hoặc giá real-time | 🔴 Phụ thuộc `OQ-029` (chưa chốt ở `SRS`) | +| `items[].quantity` | number | ❌ | `cart_item.quantity` | Số nguyên | +| `totalVnd` | number | ❌ | Σ `sellers[].subtotalVnd` | — | +| `totalItemCount` | number | ❌ | Σ `items[].quantity` toàn giỏ | Dùng cho C01 | + +**Response lỗi** + +| HTTP | `code` | Khi nào | Mã lỗi SRS | +|---|---|---|---| +| 401 | `ERR_AUTH_INVALID_TOKEN` | Customer token hết hạn/không hợp lệ | Điều hướng đăng nhập (`AC-US002-06`), không có mã `E-CART` riêng | +| 500 / 503 | `ERR_INTERNAL` / `ERR_SERVICE_UNAVAILABLE` | Lỗi hệ thống/timeout | `E-CART-0004` | + +--- + +### 3.2 `PATCH /v1/cart/items/{cartItemId}` — Cập nhật số lượng + +| | | +|---|---| +| **Mục đích** | Cập nhật `quantity` của một `CartItem` (US-003, field F01) | +| **Màn hình** | SCR-04 | +| **Quyền** | Chủ sở hữu `CartItem` (ownership theo `customerId`/`sellerId` trong JWT, hoặc `session_id` cho Guest — cơ chế Guest chưa xác nhận, `OQ-032`) | + +**Request body** *(⚠️ đề xuất)* + +```json +{ "quantity": 3 } +``` + +| Trường | Kiểu | Bắt buộc | Ràng buộc | Field SRS | +|---|---|---|---|---| +| `quantity` | number | ✅ | Số nguyên ≥ 1; ngưỡng trên 🔴 chưa chốt (`OQ-030`) | F01 | + +🔴 **Ràng buộc ở API phải khớp bảng field trong SRS** — giữ nguyên "≥ 1", không thêm ngưỡng +trên tự ý cho tới khi `OQ-030` được trả lời. + +**Response 200** *(⚠️ đề xuất — cần BE xác nhận trả về `CartItem` đã cập nhật hay toàn bộ +`Cart` mới, xem §5 mục 3)* + +```json +{ + "data": { + "cartItemId": "citem_001", + "quantity": 3, + "sellerSubtotalVnd": 375000, + "cartTotalVnd": 635000 + } +} +``` + +**Response lỗi** + +| HTTP | `code` | Khi nào | Mã lỗi SRS | +|---|---|---|---| +| 400 | `ERR_VALIDATION` | `quantity` không phải số nguyên ≥ 1 | `E-CART-0002` | +| 403 | `ERR_FORBIDDEN_OWNERSHIP` | `cartItemId` không thuộc giỏ hàng của caller | `E-CART-0005` | +| 404 | `ERR_NOT_FOUND` | `cartItemId` không tồn tại (đã bị xoá) | `E-CART-0003` | +| 409 | `ERR_CONFLICT` | `cartItemId` đã bị xoá bởi request khác trong lúc xử lý | `E-CART-0003` | +| 422 | `ERR_BUSINESS_RULE` | 🔴 Dự kiến — nếu `OQ-030` chốt có kiểm tra tồn kho tại đây | *(chưa có mã — chỉ tạo khi `OQ-030` xác nhận thuộc scope)* | +| 500 / 503 | `ERR_INTERNAL` / `ERR_SERVICE_UNAVAILABLE` | Lỗi hệ thống/timeout | `E-CART-0006` | + +--- + +### 3.3 `DELETE /v1/cart/items/{cartItemId}` — Xoá sản phẩm khỏi giỏ + +| | | +|---|---| +| **Mục đích** | Xoá một `CartItem` (US-003, nút C07, sau khi xác nhận modal) | +| **Màn hình** | SCR-04 | +| **Quyền** | Chủ sở hữu `CartItem` — cùng quy tắc §3.2 | + +**Response 200/204** *(⚠️ đề xuất — 204 không có body; BA đề xuất 200 kèm `sellerSubtotalVnd`/ +`cartTotalVnd` mới để FE khỏi tự tính lại, cần BE xác nhận, xem §5 mục 4)* + +```json +{ + "data": { + "deletedCartItemId": "citem_001", + "sellerSubtotalVnd": 260000, + "cartTotalVnd": 260000, + "sellerRemoved": false + } +} +``` + +**Response lỗi** + +| HTTP | `code` | Khi nào | Mã lỗi SRS | +|---|---|---|---| +| 403 | `ERR_FORBIDDEN_OWNERSHIP` | Không thuộc quyền sở hữu | `E-CART-0005` | +| 404 | `ERR_NOT_FOUND` | Đã bị xoá trước đó | `E-CART-0003` | +| 409 | `ERR_CONFLICT` | Xung đột đồng thời | `E-CART-0003` | +| 500 / 503 | `ERR_INTERNAL` / `ERR_SERVICE_UNAVAILABLE` | Lỗi hệ thống/timeout | `E-CART-0006` | + +--- + +## 4. Bảng đối chiếu mã lỗi + +| Mã lỗi SRS | Endpoint | HTTP | `code` của API | ☐ Khớp | +|---|---|---|---|---| +| `E-CART-0002` | `PATCH /v1/cart/items/{id}` | 400 | `ERR_VALIDATION` | ☐ | +| `E-CART-0003` | `PATCH`, `DELETE /v1/cart/items/{id}` | 404/409 | `ERR_NOT_FOUND` / `ERR_CONFLICT` | ☐ | +| `E-CART-0004` | `GET /v1/cart` | 500/503 | `ERR_INTERNAL` / `ERR_SERVICE_UNAVAILABLE` | ☐ | +| `E-CART-0005` | `PATCH`, `DELETE /v1/cart/items/{id}` | 403 | `ERR_FORBIDDEN_OWNERSHIP` | ☐ | +| `E-CART-0006` | `PATCH`, `DELETE /v1/cart/items/{id}` | 500/503 | `ERR_INTERNAL` / `ERR_SERVICE_UNAVAILABLE` | ☐ | + +*Cột ☐ do BE đánh dấu khi xác nhận khớp implementation thật.* + +## 5. Điểm cần BE xác nhận + +| # | Điểm cần chốt | Đề xuất của BA | BE trả lời | Ngày | +|---|---|---|---|---| +| 1 | `GET /v1/cart` trả `sellerName` đã join sẵn, hay chỉ `sellerId` để FE tự gọi API khác lấy tên? | Trả sẵn `sellerName` — tránh FE gọi thêm N request cho N seller | | | +| 2 | `sellers[].subtotalVnd`/`totalVnd` do BE tính sẵn, hay FE tự cộng từ `items[]`? | BE tính sẵn — tránh sai lệch làm tròn giữa FE/BE | | | +| 3 | `PATCH /v1/cart/items/{id}` trả về `CartItem` đã cập nhật + tổng nhóm/tổng giỏ, hay toàn bộ `Cart` mới? | Trả `CartItem` + tổng nhóm/tổng giỏ liên quan (nhẹ hơn trả toàn bộ `Cart`) | | | +| 4 | `DELETE /v1/cart/items/{id}` trả `200` kèm body hay `204` rỗng? | `200` kèm tổng nhóm/tổng giỏ mới + cờ `sellerRemoved` (để FE biết có cần ẩn cả nhóm không) | | | +| 5 | `id` (`cartItemId`, `productVariantId`, `sellerId`) dạng `string` hay `number`? | `string` | | | +| 6 | Với Guest, ownership của `cartItemId` có được đối chiếu theo `session_id` giống cơ chế `403 ERR_FORBIDDEN_OWNERSHIP` của JWT không? (`OQ-032`, đã ghi ở `SRS`) | Áp dụng cùng cơ chế | | | +| 7 | `PATCH /v1/cart/items/{id}` có kiểm tra tồn kho (trả `422 ERR_BUSINESS_RULE`) không? Phụ thuộc `OQ-030` ở `SRS` | Không kiểm tra ở endpoint này (giữ đúng khoanh vùng `BACKLOG`) — chờ PO xác nhận | | | + +## 6. Hành vi khi API lỗi *(giao diện phải làm gì)* + +| Tình huống | Giao diện làm gì | AC | +|---|---|---| +| 401 hết phiên (Customer) | Chuyển về đăng nhập, giữ đường dẫn quay lại `/cart` | `AC-US002-06` | +| 403 (ownership) | Chuyển trang "Không có quyền", không hiển thị dữ liệu | `AC-US003-12`, `13` | +| 404/409 (item đã bị xoá) | Banner tại dòng, sau đó ẩn dòng, cập nhật lại tổng | `AC-US003-11` | +| 5xx / timeout khi tải (`GET`) | Banner C12 thay chỗ danh sách, nút "Thử lại" | `AC-US002-03` | +| 5xx / timeout khi sửa/xoá (`PATCH`/`DELETE`) | Banner tại dòng, **giữ nguyên dữ liệu trước đó**, mở lại nút | `AC-US003-09`, `10` | +| Đang gửi `PATCH`/`DELETE` | Khoá F01/C07 của đúng dòng đang xử lý (không khoá toàn trang) để tránh gửi trùng | — | + +🔴 **Khoá đúng nút/dòng đang xử lý, không khoá toàn màn hình** — SCR-04 thường có nhiều dòng +`CartItem` cùng lúc; khoá toàn trang khi chỉ một dòng đang cập nhật sẽ chặn nhầm thao tác trên +các dòng khác. + +## 7. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | +|---|---|---|---|---| +| OQ-032 | Cơ chế ownership check của Guest cho `PATCH`/`DELETE /v1/cart/items/{id}` (xem `SRS` §8) | Tech Lead | 2026-09-08 | §5 mục 6, `E-CART-0005` cho Guest | +| OQ-030 | `PATCH /v1/cart/items/{id}` có kiểm tra tồn kho (`422 ERR_BUSINESS_RULE`) không (xem `SRS` §8) | PO, Tech Lead | 2026-09-08 | §3.2, §5 mục 7 | diff --git a/ba-output/e-commerce/03-specification/NFR_US002-003_v1.0.md b/ba-output/e-commerce/03-specification/NFR_US002-003_v1.0.md new file mode 100644 index 0000000..750a71e --- /dev/null +++ b/ba-output/e-commerce/03-specification/NFR_US002-003_v1.0.md @@ -0,0 +1,124 @@ +# NFR — Yêu cầu phi chức năng — US-002, US-003 (SCR-04 Giỏ hàng) + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-08 | +| **Author** | BA (qua skill ba-3-specification) | +| **Status** | 🟡 Draft | +| **Approved by** | Tech Lead: — | +| **Source** | `SRS_US002-003_v1.0.md` · `e-commerce/docs/sections/02-phan-tich-yeu-cau.md` (NFR-01…08) · `e-commerce/docs/sections/04-api-design.md` §4.1.1, §4.2 (ownership, rate limit, Guest session) · `RBAC_CartCheckout_v1.0.md` §5 | +| **Scope** | US-002, US-003 — màn hình `SCR-04` Giỏ hàng | + +--- + +## Quy tắc + +Mỗi NFR bắt buộc ba thứ: **con số đo được** · **điều kiện đo** · **cách verify**. Con số chưa +có nguồn ⇒ ghi 🔴 + `OQ-nnn`, không tự đặt. + +--- + +## 1. Hiệu năng — `NFR-PERF-nn` + +| ID | Yêu cầu | Ngưỡng | Điều kiện đo | Cách verify | Ai chốt | +|---|---|---|---|---|---| +| NFR-PERF-01 | Thời gian tải giỏ hàng (`GET /v1/cart`) | 🔴 chưa chốt riêng cho US-002/003 — SAD NFR-01 chỉ có ngưỡng cho danh mục/tìm kiếm (<2s) và checkout (<3s); BA đề xuất áp cùng ngưỡng danh mục (≤2s p95) vì cùng là thao tác đọc — xem `OQ-033` | 🔴 chưa xác nhận số `CartItem` tối đa/giỏ để đo (đề xuất ≤50 dòng, chưa có số liệu vận hành — `greenfield`) | k6 kịch bản tải `GET /v1/cart` | Tech Lech (chờ xác nhận) | +| NFR-PERF-02 | Thời gian phản hồi sửa số lượng / xoá (`PATCH`/`DELETE /v1/cart/items`) | 🔴 chưa chốt — BA đề xuất ≤1s p95 (thao tác ghi 1 dòng, đơn giản hơn checkout) — xem `OQ-033` | 1 người dùng, 1 request | k6 kịch bản `PATCH`/`DELETE` đơn lẻ | Tech Lead (chờ xác nhận) | + +🔴 **Không tự đặt số khi PO/Tech Lead chưa xác nhận** — hai dòng trên chỉ là **đề xuất** của BA +dựa trên phép loại suy từ NFR-01 của SAD, không phải giá trị đã chốt. Xem `OQ-033`. + +## 2. Dung lượng & tăng trưởng — `NFR-CAP-nn` + +| Đại lượng | Hiện tại | Sau 1 năm | Sau 3 năm | Nguồn số liệu | +|---|---|---|---|---| +| Số `CartItem` trung bình/tối đa mỗi giỏ hàng | N/A — `greenfield`, chưa vận hành | 🔴 chưa có số liệu | 🔴 chưa có số liệu | Chưa có — cần đo sau go-live (không phải việc của GĐ3) | +| Số giỏ hàng đồng thời (giờ cao điểm) | N/A | 🔴 chưa có | 🔴 chưa có | Tham chiếu `BRIEF_CartCheckout_v1.0.md` §2 quy mô "large" — chưa có con số cụ thể cho riêng module Giỏ hàng | + +**N/A theo `LIFECYCLE = greenfield`** — không có dữ liệu vận hành cũ để ước lượng tăng trưởng +(nhất quán với `IMPACT_CartCheckout_v1.0.md` §1.6). Ghi nhận, không bỏ trống im lặng. + +| Giờ cao điểm | Khi nào | Vì sao | +|---|---|---| +| 🔴 chưa xác nhận | *(đề xuất tham khảo: giờ tối, cuối tuần, mùa sale — theo mô hình marketplace bán lẻ thông thường, chưa có số liệu thật)* | Chưa vận hành để có dữ liệu thật | + +## 3. Bảo mật & quyền riêng tư — `NFR-SEC-nn` + +| ID | Yêu cầu | Chi tiết | Căn cứ | Cách verify | +|---|---|---|---|---| +| NFR-SEC-01 | Mọi `PATCH`/`DELETE` cart item kiểm tra quyền sở hữu (chống IDOR) | Đối chiếu `customerId`/`sellerId` trong JWT (Customer) hoặc `session_id` (Guest — cơ chế cụ thể chờ `OQ-032`) với chủ sở hữu `CartItem`; không khớp → `403 ERR_FORBIDDEN_OWNERSHIP` | `e-commerce/docs/sections/04-api-design.md` §4.1.1 | Test gọi thẳng API với token/session không phải chủ sở hữu — `AC-US003-12`, `13` | +| NFR-SEC-02 | Định danh Guest (`X-Guest-Session-Id`) không lộ qua kênh không an toàn | Cookie `HttpOnly; Secure; SameSite=Lax` (theo SAD §4.1.1) — SRS này chỉ tham chiếu, không định nghĩa lại thiết kế kỹ thuật | `e-commerce/docs/sections/04-api-design.md` §4.1.1 | Kiểm tra thuộc tính cookie trên môi trường staging | +| NFR-SEC-03 | Giới hạn tần suất gọi (rate limit) cho `PATCH`/`DELETE /v1/cart/items` của Guest | Theo IP nguồn, ngưỡng cụ thể do SAD định nghĩa ở tầng kỹ thuật (không phải quyết định của SRS này) | `e-commerce/docs/sections/04-api-design.md` §4.2 | Tham chiếu, không kiểm thử ở phạm vi BA | + +**Rà bốn câu:** + +| Câu hỏi | Trả lời | +|---|---| +| Có thông tin cá nhân không? Loại nào? | Không — `CartItem` chỉ chứa `product_variant_id`, `seller_id`, `quantity`; không có PII của khách trong phạm vi US-002/US-003 | +| Lưu bao lâu? Xoá thế nào khi hết hạn? | Theo vòng đời `Cart` — `BR_CartCheckout_v1.0.md` §3 (Guest 7 ngày, Customer 30 ngày theo `05-thiet-ke-du-lieu.md` §5.3, **chưa được Tech Lead xác nhận áp dụng đúng số này cho module**, xem `BACKLOG` US-001) | +| Ai được xuất ra ngoài hệ thống? | Không áp dụng — không có chức năng xuất dữ liệu giỏ hàng trong US-002/US-003 | +| Có quy định pháp luật nào áp dụng không? | Không trực tiếp — dữ liệu giỏ hàng chưa phải giao dịch tài chính (khác `Order`/`Payment`, thuộc NFR-05) | + +## 4. Lưu vết — `NFR-AUD-nn` + +| Nhóm | N/A vì | +|---|---| +| Lưu vết (audit log) cho sửa/xoá `CartItem` | Đây là thao tác tự phục vụ trên dữ liệu **tạm thời** trước khi đặt hàng, không phải giao dịch tài chính — theo `RBAC_CartCheckout_v1.0.md` §5, yêu cầu ghi vết chỉ bắt buộc từ bước tạo `Order`/`Payment` trở đi (US-004 trở lên). Sửa/xoá `CartItem` không cần audit log riêng ở US-002/US-003 | + +## 5. Khả dụng & xử lý sự cố — `NFR-AVL-nn` + +| ID | Yêu cầu | Ngưỡng | Ghi chú | +|---|---|---|---| +| NFR-AVL-01 | Hành vi khi Cart & Order Service lỗi/chậm khi tải giỏ hàng | Banner lỗi + nút "Thử lại" (không tự động retry lặp lại) | Đã có AC — `AC-US002-03` | +| NFR-AVL-02 | Hành vi khi Cart & Order Service lỗi/chậm khi sửa/xoá | Banner lỗi tại dòng, giữ nguyên dữ liệu trước đó, mở lại nút | Đã có AC — `AC-US003-09`, `10` | + +**Hệ thống ngoài lỗi thì nghiệp vụ này làm gì?** + +| Hệ thống ngoài | Nếu lỗi/chậm | Người dùng thấy gì | Dữ liệu xử lý sao | +|---|---|---|---| +| Catalog & Inventory (nội bộ — cung cấp tên/ảnh/biến thể sản phẩm hiển thị ở C03–C06) | Chậm/không phản hồi khi tải giỏ hàng | 🔴 chưa xác nhận: chặn hoàn toàn tải giỏ hàng, hay hiển thị giỏ hàng với các trường thiếu (VD ảnh trống, tên "—")? | Chưa xác định — cần Tech Lead xác nhận SLA nội bộ giữa Cart & Order Service và Catalog Service (tương tự khoảng trống đã ghi ở `IMPACT_CartCheckout_v1.0.md` §1.5). Ghi nhận là khoảng trống, không tạo `OQ` mới trùng lặp — thuộc phạm vi `IMPACT` đã có | + +## 6. Đa ngữ & định dạng — `NFR-I18N-nn` + +| Khía cạnh | Yêu cầu | Ghi chú | +|---|---|---| +| Ngôn ngữ hỗ trợ | VI (mặc định), EN đầy đủ ở SRS §4.2; ZH/KO/JA để trống — `OQ-023` (đã mở ở `UICONV`) | Tham chiếu `UICONV` §9 | +| Múi giờ hiển thị | N/A — SCR-04 không hiển thị trường thời gian nào | — | +| Định dạng ngày | N/A — không áp dụng cho SCR-04 | — | +| Dấu phân cách số | Theo `UICONV` §8 (`#,##0 ₫`) | — | +| Đơn vị tiền | VND, không đổi tiền tệ giao dịch; giá quy đổi tham khảo (`CurrencyToggle`) — chưa xác nhận có hiển thị ở SCR-04 hay không, mức độ thấp, không chặn G3, ghi nhận cho Dev FE tham khảo `UICONV` §0 | — | +| Sắp xếp chuỗi có dấu | N/A — không có sắp xếp theo tên trên SCR-04 (chỉ nhóm theo seller, thứ tự nhóm — xem `SRS` §2.A.3.2) | — | +| Độ dài text sau khi dịch | Tên sản phẩm/seller dài hơn ở ZH/KO/JA so với VI — layout co giãn theo `UICONV` §0, không fix-width | Tham chiếu `UICONV` §0 | + +## 7. Khả năng truy cập & thiết bị — `NFR-ACC-nn` + +| Khía cạnh | Yêu cầu | +|---|---| +| Trình duyệt hỗ trợ | Tham chiếu `UICONV` — chưa có bảng ma trận trình duyệt riêng, N/A ở mức SRS này | +| Kích thước màn hình nhỏ nhất | Tham chiếu `UICONV` §1 — breakpoint mobile < 768px (giá trị cụ thể `OQ-018`, đã mở) | +| Dùng trên điện thoại không | Có — web responsive (theo SAD §7.0) | +| Thao tác bằng bàn phím | 🔴 chưa xác nhận thứ tự focus cho F01/C07 — mức độ thấp ở `RIGOR = standard` (chỉ bắt buộc đủ ở `strict`), không chặn G3, ghi nhận cho Dev FE | +| Tương phản màu | N/A ở mức BA — thuộc thiết kế visual (`OQ-022`, design system chưa chọn) | + +--- + +## 8. Nhóm không áp dụng + +| Nhóm | N/A vì | +|---|---| +| Lưu vết (`NFR-AUD`) | Xem §4 — thao tác tự phục vụ trên dữ liệu tạm thời, không phải giao dịch tài chính | + +## 9. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | +|---|---|---|---|---| +| 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? | PO, Tech Lead | 2026-09-08 | NFR-PERF-01, NFR-PERF-02 | + +## 10. Xác nhận + +| Vai trò | Người | Nội dung xác nhận | Ngày | +|---|---|---|---| +| Tech Lead | *(chưa có)* | ☐ Ngưỡng khả thi với kiến trúc hiện tại (chờ chốt số ở `OQ-033`) | — | +| QA | *(chưa có)* | ☐ Mọi NFR đều có cách verify chạy được | — | +| PO | *(chưa có)* | ☐ Ngưỡng khớp kỳ vọng người dùng đã trao đổi | — | diff --git a/ba-output/e-commerce/03-specification/SRS_US002-003_v1.0.md b/ba-output/e-commerce/03-specification/SRS_US002-003_v1.0.md new file mode 100644 index 0000000..2107b70 --- /dev/null +++ b/ba-output/e-commerce/03-specification/SRS_US002-003_v1.0.md @@ -0,0 +1,379 @@ +# 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 + +```mermaid +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` + +```mermaid +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`](AC_US-002_v1.0.md) và [`AC_US-003_v1.0.md`](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`](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`](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) | diff --git a/ba-output/e-commerce/03-specification/WF_US002-003_v1.0.html b/ba-output/e-commerce/03-specification/WF_US002-003_v1.0.html new file mode 100644 index 0000000..9b29de1 --- /dev/null +++ b/ba-output/e-commerce/03-specification/WF_US002-003_v1.0.html @@ -0,0 +1,239 @@ + + + + + + +WF — US-002, US-003 — Giỏ hàng (SCR-04) + + + + +
+

WF — US-002, US-003 · Giỏ hàng (SCR-04)

+ + + Nhãn đen = C-id/F-id trong SRS §2.A.3.1 · khung đứt xám = vùng Zn (WF §3.1.1) · khung đứt đỏ = chỉ có ở prototype, chưa có trong SRS (xem WF §5) · hành vi xem SRS, không suy từ hình +
+ +
+ +
+

SCR-04 · Giỏ hàng US-002 (xem) + US-003 (sửa/xoá) · vào từ SCR-01 (icon giỏ hàng) · vai trò: ROLE-01 Guest, ROLE-02 Customer

+
+ +
+ Giỏ hàng của bạn (5 sản phẩm) +
+ +
+ + +
+ +
+ + +
+
Shop A
+ +
+
+
ảnh
+
+
Áo thun basic
+
Size M, Đỏ
+
100.000 ₫
+
+
+
+
chỉ ở prototype
☐ chọn dòng
+ + −2+ + + Xoá +
+
+ +
+
+
ảnh
+
+
Quần jean slimfit
+
Size 30
+
50.000 ₫
+
+
+
+ −1+ + Xoá +
+
+ +
+ Tạm tính: 250.000 ₫ +
+
+ + +
+
Shop B
+
+
+
ảnh
+
+
Balo du lịch
+
Đen
+
200.000 ₫
+
chỉ ở prototype — WF §5 #2 badge "Sản phẩm đã hết hàng"
+
+
+
+ −1+ + Xoá +
+
+
+ Tạm tính: 200.000 ₫ +
+
+ +
+ +
+ +
+
+
minh hoạ
+ Giỏ hàng trống + Tiếp tục mua sắm +
+
+ +
+
+ Không tải được dữ liệu, thử lại. + Thử lại +
+
+ +
+ + +
+
chỉ ở prototype — WF §5 #1 "Tổng số lượng đã chọn" (phụ thuộc checkbox chọn dòng, chưa có trong SRS)
+
Tổng cộng: 585.000 ₫
+
Tiến hành Checkout
+
+ +
+ + +
+
+ Tổng cộng: 585.000 ₫ + Tiến hành Checkout +
+
+ +
+
+ +
+ +
Wireframe low-fi · bố cục và trạng thái · không phải thiết kế visual · nguồn hành vi: SRS_US002-003_v1.0.md · nguồn bố cục: e-commerce/docs/sections/07-giao-dien.md §7.1.1 (chế độ 🎨) · nguồn quy ước: UICONV_e-commerce_v1.0.md
+ + + + diff --git a/ba-output/e-commerce/03-specification/WF_US002-003_v1.0.md b/ba-output/e-commerce/03-specification/WF_US002-003_v1.0.md new file mode 100644 index 0000000..162cb39 --- /dev/null +++ b/ba-output/e-commerce/03-specification/WF_US002-003_v1.0.md @@ -0,0 +1,217 @@ +# 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`).