Files
Canhchimlac 343ad8bbbc save
2026-09-15 16:02:30 +07:00

62 KiB
Raw Permalink Blame History

ICD — Integration & Interface Catalog — e-commerce

Version 1.0
Date 2026-09-15
Author SA (skill sa-2-architecture, chế độ go, hoạt động icd)
Status 🟡 Draft (duyệt từng phần — xem Approved by; AG2 cần cả ba vai trò (Tech Lead/Security/Ops-SRE) ký, mới có một chữ ký thay có điều kiện — chưa đủ điều kiện chuyển 🔵 Approved)
Approved by Tech Lead: Điều phối dự án (uỷ quyền, chế độ chạy thử — ký thay theo ngoại lệ DEC-01, không phải chữ ký Tech Lead thật) — duyệt từng phần bản v1.0 · 2026-09-15: chấp nhận catalog 17 IF-nn, chi tiết đầy đủ IF-002 (4 endpoint Cart & Checkout), và kết luận xác nhận/điều chỉnh API_US002-003_v1.0.md của BA tại §5 (GET /v1/cart nhóm theo seller; sellerName denormalize snapshot; thêm unitPriceSnapshotVnd/currentPriceVnd/priceChanged; Guest ownership 403 dùng cùng cơ chế theo ADR-007). Chấp nhận TẠM ASM-24 (IF-021 cross-network), ASM-25 (chiều IF-022 Cart→Seller), ASM-26 (Payment Service nhận sellerId ngay tại IF-006), và hướng denormalize sellerName của OQ-033 làm baseline cho hoạt động dat/sec/inf/fail kế tiếp — OQ-028…033 (SA) giữ nguyên MỞ, chờ Tech Lead thật xác nhận, không coi là đã đóng. Ghi nhận lại: 5 interface đối tác ngoài (VNPay/Momo/GHN/GHTK) và Email/SMS Provider chưa có contract thật (🔴, ARISK-03/04) — không đổi bởi lượt duyệt này. Ký thay Tech Lead theo ngoại lệ DEC-01 (SA) — không phải chữ ký Tech Lead thật. Nhắc BA: chạy ba-pipeline hoạt động specification để cập nhật API_US002-003/SRS_US002-003 theo ICD §5. · Security: — (chưa ký) · Ops/SRE: — (chưa ký) — AG2 cần cả ba cùng ký; tài liệu này vẫn chưa qua AG2, còn xa vì DAT/SEC/INF/FAIL (hoạt động 5–8) chưa chạy và không ADR nào Accepted. OQ-004 (tính hợp lệ ký thay) vẫn mở. Confidence giữ nguyên 🔴 — duyệt từng phần không phải bằng chứng nguồn mới, không nâng Confidence. Status giữ 🟡 Draft — AG2 chưa đủ ba chữ ký thật/hợp lệ. Ghi thêm DEC-19.
Source 02-architecture/SAD_e-commerce_v1.1.md §3, §4, §4.1, §4.3, §6, §6.3, §7 · 02-architecture/ASR_e-commerce_v1.0.md ASR-002/003/004/005/007/008/013 · 02-architecture/QAS_e-commerce_v1.0.md QAS-003/004/005/010/011 · 02-architecture/adr/ADR-003_*.md, ADR-004_*.md, ADR-005_*.md, ADR-007_*.md, ADR-011_*.md · 00-index/OQ_e-commerce.md v1.13 · 00-index/DEC_e-commerce.md v1.15 · ba-output/e-commerce/03-specification/API_US002-003_v1.0.md · ba-output/e-commerce/03-specification/SRS_US002-003_v1.0.md · ba-output/e-commerce/03-specification/AC_US-002_v1.0.md, AC_US-003_v1.0.md · ba-output/e-commerce/02-analysis/RBAC_CartCheckout_v1.0.md · ba-output/e-commerce/00-index/OQ_e-commerce.md (OQ-029/030/032/033/034) · e-commerce/docs/sections/04-api-design.md (§4.1.1, §4.1.5, §4.1.6, §4.1.13, §4.2, §4.3 — quy ước chung tái sử dụng, không tái sử dụng kiểu kiến trúc ~10 microservices/Kafka của tài liệu này)
Scope 22 interface ứng viên IF-nn của SAD §4 — toàn sàn theo P2 (chỉ chốt ở mức catalog: hai đầu/giao thức/owner/versioning/đầu kia hỏng thì sao). Chi tiết contract đầy đủ cho Cart & Order (US-002/US-003: GET/PATCH/DELETE /v1/cart*, POST /v1/checkout) để xác nhận API_US002-003_v1.0.md của BA. 🔴 Xem §0.1 — chỉ 17/22 IF-nn có ID riêng biệt truy được trong nội dung SAD; chênh lệch được ghi nhận, không tự bịa 5 ID còn thiếu.
Confidence 🔴 Giả định chưa xác minh — theo yêu cầu điều phối, tiếp nối Confidence 🔴 của SAD/ASR/QAS. AG1 chưa ký thật; AG2 chưa tới hạn; ADR-001…012 đều Proposed (chưa Accepted); POC-01/POC-02 chưa chạy; không đối tác nào (VNPay/Momo/GHN/GHTK/Email-SMS) có sandbox/tài liệu thật (ARISK-03/04, CTX §4.2).

Change Log

Version Date Người sửa Thay đổi ADR/DEC
1.0 2026-09-15 SA (qua skill sa-2-architecture, chế độ go, hoạt động icd) Bản đầu — hoạt động 4/9 của GĐ2. Chốt catalog cho 17 IF-nn truy được từ SAD §4/§6.3 (chênh lệch với con số "22" của SAD được ghi nhận, không bịa thêm — xem §0.1, OQ-029). Chi tiết đầy đủ (mục đích, quyền, idempotent, tần suất, mã lỗi, versioning) cho IF-002 (client ↔ Nhóm Giao dịch — 4 endpoint Cart & Checkout), IF-005, IF-006, IF-007/008 (VNPay/Momo), IF-009 (event OrderPlaced/PaymentConfirmed, ordering key seller_id theo ADR-005), IF-015, IF-021, IF-022. Xác nhận/điều chỉnh từng endpoint của API_US002-003_v1.0.md (BA) tại §5 — 5 mục xác nhận, 1 mục điều chỉnh (denormalize sellerName), 1 mục chờ OQ-030(BA); đóng đề xuất OQ-034(BA)/OQ-032(BA) (BA cần cập nhật SRS/API để đóng chính thức trong sổ BA). Thêm OQ-028…033 (SA sổ), ASM-24…26. Ghi DEC-18 (tiếp nối DEC-01…17, ngoại lệ gate tiếp tục GĐ2 hoạt động icd). Không sửa SAD/ASR/QAS/ADR đã có. Confidence 🔴 toàn bộ. DEC-18
1.0 2026-09-15 Điều phối dự án (thay mặt Tech Lead, ngoại lệ DEC-01) — tác vụ sign/approve Duyệt từng phần: chấp nhận catalog 17 IF-nn, chi tiết IF-002 (4 endpoint Cart & Checkout), kết luận xác nhận/điều chỉnh API_US002-003 của BA (nhóm theo seller GET /v1/cart; sellerName denormalize snapshot; thêm unitPriceSnapshotVnd/currentPriceVnd/priceChanged; Guest ownership 403 theo ADR-007). Chấp nhận TẠM ASM-24 (IF-021 cross-network), ASM-25 (chiều IF-022 Cart→Seller), ASM-26 (Payment nhận sellerId ở IF-006), và hướng denormalize sellerName của OQ-033 làm baseline cho dat/sec/inf/fail kế tiếp — OQ-028…033 (SA) giữ nguyên MỞ, chờ Tech Lead thật xác nhận. Ghi nhận lại: interface đối tác ngoài (VNPay/Momo/GHN/GHTK) và Email/SMS Provider chưa có contract thật (🔴, ARISK-03/04). Không đổi nội dung chuyên môn. Ký thay Tech Lead theo ngoại lệ DEC-01; Security/Ops chưa ký; OQ-004 mở; Confidence giữ 🔴; Status giữ 🟡 Draft; AG2 chưa ký. Nhắc BA chạy ba-pipeline hoạt động specification để cập nhật API_US002-003/SRS_US002-003 theo ICD §5. Ghi thêm DEC-19. DEC-19

Sơ đồ thắng về quan hệ và luồng (ai gọi ai, theo thứ tự nào). Bảng/văn bản thắng về ràng buộc và con số (timeout, quyền, định dạng, giới hạn). Mâu thuẫn ngoài hai loại trên là lỗi tài liệu, phải sửa chứ không chọn bên (D12).

🔴 Tài liệu này thắng API contract của bộ BA khi hai bên lệch (artifact-map.md §7). BA viết contract đề xuất và đánh dấu "chờ BE xác nhận" — đây là chỗ xác nhận. Mọi chỗ lệch được liệt kê ở §5 kèm hành động cho BA.


0. Ghi chú Preflight & phạm vi — bắt buộc đọc trước

0.0 Ngoại lệ gate

AG1 vẫn chưa ký thật; AG2 (gate của chính GĐ2) chưa tới hạn. Theo SKILL.md, hoạt động 1 (QAS) → 2 (ASR) → 3 (SAD) đã hoàn tất và được duyệt từng phần (DEC-12/14/16) — điều kiện đầu vào cho hoạt động 4 (ICD) đã đủ. Người dùng (vai điều phối dự án chạy thử) đã được cảnh báo lại và khẳng định muốn tiếp tục.

DEC-18 (SA) — Tiếp tục sa-2-architecture (hoạt động 4 — ICD) cho e-commerce trong khi AG1 chưa ký thật và AG2 chưa tới hạn — tiếp nối DEC-01…17. Quyết định: Chốt catalog + chi tiết contract cho các IF-nn liên quan Cart & Order dựa trên SAD v1.1 §4 đã duyệt từng phần, giữ Confidence 🔴 cho tới khi: (a) AG1/AG2 ký thật, (b) đối tác VNPay/Momo/GHN/GHTK có sandbox/tài liệu thật (ARISK-03/04), (c) Tech Lead xác nhận các đề xuất mới của ICD (schema sự kiện, denormalize sellerName, hướng IF-021/IF-022). Người quyết: Điều phối dự án (đại diện PO, dự án chạy thử). Radar (ước lượng): ~4 — chi phí đảo ngược thấp (contract catalog sửa lại khi có Tech Lead thật không tốn nhiều, chưa có dòng code nào phụ thuộc) · bán kính ảnh hưởng: hoạt động dat/ sec/inf/fail kế tiếp và toàn bộ dev BE/FE dùng ICD làm nguồn sự thật, nhưng bản thân việc ghi tài liệu dưới ngoại lệ thì nhỏ · có chạm trực tiếp việc xác nhận API của BA (đúng vai trò ICD phải làm) nhưng chưa phải cam kết thi công (chưa ai ký) · không ràng buộc dài hạn tự thân (ICD sửa được qua version mới) · không tranh cãi mới, tiếp nối tiền lệ DEC-11…17 → ghi DEC-nn, không cần ADR cho việc chạy dưới ngoại lệ. Hệ quả nếu không chấp nhận ngoại lệ: BA không có ai xác nhận chính thức 3 endpoint Cart đang ở trạng thái "chờ BE" — SRS/API của BA tiếp tục treo OQ-030/032/033/034(BA), chặn G3 của bộ BA (cần SA qua AG2, nhưng cần ICD xác nhận API trước khi G3 có ý nghĩa).

0.1 Chênh lệch số lượng IF-nn: SAD nói 22, ICD chỉ truy được 17

SAD_e-commerce_v1.1.md (header Scope, Change Log v1.0, §Tự chấm) nhắc nhiều lần "22 IF-nn ứng viên", nhưng khi rà toàn bộ §3, §4.1 (bảng CMP-nn), §5, §6.3 chỉ có 17 ID riêng biệt thực sự xuất hiện: IF-001, 002, 003, 004, 005, 006, 007, 008, 009, 015, 016, 017, 018, 019, 020, 021, 022. Không có IF-010…014 ở bất kỳ đâu trong văn bản.

🔴 ICD không tự bịa 5 ID còn thiếu để khớp con số "22" (vi phạm nguyên tắc "không bịa"/D1). Hai khả năng hợp lý: (a) tác giả SAD đã đếm nhầm khi tổng hợp số liệu ở header/changelog, hoặc (b) có ý định tách nhỏ hơn (VD từng endpoint GET/PATCH/DELETE /v1/cart* thành các IF riêng thay vì gộp chung IF-002) nhưng chưa thực hiện trong bảng CMP-nn. Ghi nhận ở OQ-029 (SA sổ) — đề nghị rà lại SAD ở lần cập nhật kế tiếp, không chặn hoạt động icd này vì 17 ID hiện có đã đủ bao phủ mọi cặp container/hệ ngoài xuất hiện trong SAD §3/§4/§6.3.

Cách ICD xử lý granularity: ở mức catalog (§2), giữ đúng 17 ID theo SAD (mức container-to- container, đúng độ chi tiết SAD đã chọn). Ở mức chi tiết (§3), với IF-002 (client ↔ Nhóm Giao dịch) — vốn gộp chung Identity/Catalog/Cart&Order ở mức SAD — ICD tách nhỏ theo endpoint ngay bên trong mục IF-002 cho phần Cart & Order (4 endpoint), vì đây là yêu cầu "chi tiết đầy đủ để xác nhận API của BA" — không tạo IF-nnn mới cho việc này, chỉ chia nhỏ nội dung trong cùng một dòng catalog (nhất quán với D5: "mọi lời gọi vượt ranh giới container phải có ≥1 dòng IF-nnn" — 4 endpoint này cùng vượt đúng một ranh giới container Client→Nhóm Giao dịch).


1. Quy ước chốt một lần cho toàn hệ thống

Kế thừa và xác nhận lại (không đổi) từ e-commerce/docs/sections/04-api-design.md §4.1.1, §4.1.13, §4.3 (status: approved trong tài liệu gốc, nhưng tài liệu đó thuộc kiến trúc P1 đã loại — ICD xác nhận các quy ước này độc lập với kiểu kiến trúc, vẫn áp dụng đúng cho P2). Radar ước lượng ~3 (đã có tiền lệ, không tranh cãi, chi phí đảo ngược thấp) ⇒ theo decision-radar.md §2, không cần ADR riêng — ghi nhận tại đây là đủ.

# Vấn đề Quyết định Vì sao
1 Số lớn (id, số tiền) truyền dạng gì string cho mọi id (cartId, cartItemId, orderId, sellerId, productVariantId...); số tiền *Vnd dạng number (VND là số nguyên, không có phần thập phân, không vượt 2^53 ở quy mô GMV hiện tại — xác nhận lại nếu tổng giỏ hàng B2B vượt hàng chục tỷ) Khớp API_US002-003 §1, 04-api-design.md (ví dụ "orderId": "order_001")
2 Thời gian định dạng, múi giờ ISO-8601 UTC (2026-09-15T10:00:00Z) cho mọi trường *At/*_at; hiển thị múi giờ VN (+07:00) do FE tự quy đổi Chưa có trường thời gian nào ở phạm vi Cart hiện tại (API_US002-003 §1); áp dụng cho Order/event khi mở rộng
3 Phân trang Offset (page, pageSize, mặc định 20, tối đa 100), bọc { "data": [...], "pagination": {...} }; GET /v1/cart không phân trang (giỏ hàng không có khái niệm trang) Khớp 04-api-design.md §4.1.1; API_US002-003 §1 xác nhận không áp dụng cho Cart
4 Định dạng phản hồi chung { "data": {...} } thành công · { "error": { "code", "message", "details" }, "traceId" } lỗi Khớp SAD §4.1.1/§4.1.13, API_US002-003 §2
5 Lỗi nghiệp vụ trả HTTP nào 4xx, không phải 200 kèm cờ lỗi D5/SAD §4.1.13 — tránh bug im lặng
6 Ngôn ngữ thông điệp lỗi Trả code (client tự dịch theo bảng text SRS §4.2); không dựa vào message để hiển thị người dùng cuối API_US002-003 §2 — BA sở hữu text hiển thị
7 Khoá idempotency Header Idempotency-Key bắt buộc cho POST /v1/checkout, POST /v1/payments, POST /v1/customers/me/loyalty/redeem; webhook dùng khoá nghiệp vụ gatewayTransactionRef (không phải header Idempotency-Key — bên gửi là đối tác ngoài, không tự đặt header) theo ADR-004 ASR-004, 04-api-design.md §4.1.1/§4.1.6
8 Correlation id 🔴 Chưa có tên header chuẩn cho request — chỉ có traceId ở response lỗi (SAD §4.1.13). Đề xuất SA: header request X-Request-Id (client hoặc gateway sinh nếu thiếu), map 1-1 vào traceId xuyên suốt log OQ-031 (SA, mới) — Tech Lead xác nhận tên header

Bổ sung theo ghi chú người duyệt (không thuộc 8 mục chuẩn của template nhưng bắt buộc chốt ở GĐ2 icd):

# Vấn đề Quyết định ADR
9 Authn (Customer) Bearer JWT, TTL access ~15-60 phút + refresh ~7-30 ngày (kế thừa 04-api-design.md §4.2, chưa xác nhận số cụ thể cho P2) — (chưa có ADR riêng, thuộc hoạt động sec kế tiếp)
10 Authn (Guest) Header X-Guest-Session-Id, giá trị sinh CSPRNG ≥128-bit, cookie HttpOnly; Secure; SameSite=Lax, TTL 30 ngày không hoạt động (kế thừa 04-api-design.md §4.1.1) —
11 Authz (ownership check) Kiểm tra tại service (không phải gateway), cache Redis (TTL ngắn), fallback query DB khi cache miss/lỗi ADR-007
12 Idempotency webhook thanh toán Khoá = gatewayTransactionRef; kèm kiểm tra timestamp trong payload lệch ≤5 phút (chống replay, kế thừa 04-api-design.md §4.1.6) ADR-004
13 Ordering sự kiện OrderPlaced/PaymentConfirmed SQS FIFO, MessageGroupId = seller_id ADR-005

2. Danh mục interface — IF-nnn (17/17 truy được — xem §0.1)

ID Từ Đến Giao thức Sync/Async Ai sở hữu contract Contract ở đâu Versioning Đầu kia hỏng thì sao Ứng viên FAIL
IF-001 Web/Mobile Client (Guest/Customer/Seller/Admin) ALB/API Gateway (CMP-01) HTTPS/TLS 1.2+ Sync Platform/DevOps (routing thuần; schema thật ở IF-002/003/004) Không có schema riêng — L7 routing Theo §1 chung ALB/WAF down → toàn bộ FE lỗi 503 ứng viên #14
IF-002 Web/Mobile Client Nhóm Giao dịch (CMP-02 Identity, CMP-03 Catalog, CMP-04 Cart&Order) qua ALB HTTPS/REST JSON Sync BE Nhóm Giao dịch, tách theo module contracts/openapi/nhom-giao-dich/{identity,catalog,cart-order}.yaml (dự kiến, repo contract chưa tồn tại) Path /v1, deprecation ≥6 tháng (04-api-design.md §4.3) Timeout/5xx → FE banner theo AC-US002-03/AC-US003-09/10 (xem §6) ứng viên #1–#3
IF-003 Web/Mobile Client (Seller/Admin/CSR/Ops) Nhóm Hỗ trợ (CMP-05 Seller Mgmt, CMP-08 Review, CMP-10 Shipping) qua ALB HTTPS/REST JSON Sync BE Nhóm Hỗ trợ, tách theo module contracts/openapi/nhom-ho-tro/*.yaml (dự kiến) Path /v1 Timeout/5xx → theo màn hình Seller/Admin tương ứng (ngoài phạm vi Cart&Checkout, chưa chi tiết hoá) ứng viên (chưa đặt số)
IF-004 Web/Mobile Client (Customer/Guest) Payment Service (CMP-11) qua ALB HTTPS/REST JSON Sync BE Payment (biệt lập) contracts/openapi/payment.yaml (dự kiến) Path /v1 Timeout/5xx → FE hiện lỗi thanh toán, không mất dữ liệu giỏ hàng ứng viên (chưa đặt số)
IF-005 Cart & Order (CMP-04) Catalog & Inventory (CMP-03) In-process call — cùng ECS task "Nhóm Giao dịch" theo P2 modular monolith (🔴 giả định ASM-19, chưa xác nhận OQ-010) Sync BE Nhóm Giao dịch (module Catalog) contracts/internal/catalog-reserve.md (dự kiến — module boundary nội bộ, không cần OpenAPI đầy đủ nếu in-process) Semver module nội bộ Không đủ tồn kho → 409 ERR_CONFLICT; lỗi/timeout nội bộ → checkout thất bại toàn bộ (không tạo Order) ứng viên #1
IF-006 Cart & Order (CMP-04) Payment Service (CMP-11) REST/HTTPS — cross-network (Payment cô lập mạng/IAM theo ASR-002, dù cùng "P2 monolith") Sync BE Payment contracts/openapi/payment-internal.yaml (dự kiến) Path /v1 (internal) Timeout → checkout thất bại, rollback TX, không tạo Order; đơn ở trạng thái chưa commit không hiển thị cho khách ứng viên #3
IF-007 Payment Service (CMP-11) VNPay REST/HTTPS (init redirect) + Webhook IPN (callback) Sync (init) + Async (webhook) VNPay (bên thứ ba) — sàn sở hữu adapter/anti-corruption layer (ADR-011) 🔴 Cần tài liệu API VNPay thật — chưa có sandbox (ARISK-03). Đường dẫn dự kiến khi có: contracts/partners/vnpay.yaml (mirror của tài liệu VNPay, không phải spec do VNPay công bố) Theo VNPay công bố — chưa xác nhận Timeout (đề xuất 10s, chưa kiểm chứng) → không có redirect URL, FE hiện lỗi thanh toán, giữ đơn ở PENDING_PAYMENT ứng viên #4
IF-008 Payment Service Momo Tương tự IF-007 Sync (init) + Async (webhook) Momo (bên thứ ba) 🔴 Cần tài liệu API Momo thật — chưa có sandbox (ARISK-03) Chưa xác nhận Tương tự IF-007 ứng viên #5
IF-009 Cart & Order (CMP-04) + Payment (CMP-11) (publish) ↔ Message Backbone (CMP-12) ↔ Commission&Payout/Promotion&Loyalty/Review/Notification/Shipping (consume, ≥5) SQS FIFO + EventBridge Async Platform/SRE (backbone hạ tầng) + team publish/consume sở hữu schema payload (BE Nhóm Giao dịch/Payment publish; BE Nhóm Hỗ trợ consume) contracts/asyncapi/order-events.yaml (dự kiến) — chi tiết §4 eventVersion trong payload, thay đổi breaking → topic/queue mới (không sửa schema đang chạy) Consumer lỗi lặp lại → DLQ (giữ bao lâu: chưa chốt, xem FAIL); publish lỗi → SQS tự retry theo AWS SLA ứng viên #12/#13
IF-015 Cart & Order (CMP-04), Identity & Access (CMP-02) ElastiCache Redis (CMP-15) Redis protocol (RESP) Sync Ops/SRE (hạ tầng) + BE Nhóm Giao dịch (key schema) contracts/internal/redis-keyspace.md (dự kiến — quy ước đặt tên key, TTL) Không versioning chính thức (naming convention, thay đổi qua migration key) Cache miss/lỗi kết nối → fallback query DB trực tiếp (ADR-007) ứng viên #11
IF-016 Nhóm Giao dịch + Nhóm Hỗ trợ RDS chính (CMP-13) PostgreSQL wire protocol (SQL) Sync Ops/DBA db/migrations/*.sql (dự kiến, schema-per-module, Flyway/Liquibase chưa chọn) Migration versioned tăng dần, không breaking ngược (additive trước, xoá cột ở version sau) DB chậm/lỗi → 503 + circuit breaker (chưa thiết kế ngưỡng, thuộc FAIL) ứng viên #9
IF-017 Payment Service (CMP-11) RDS Payment (CMP-14) PostgreSQL wire protocol Sync Ops/DBA (biệt lập, không chung quyền truy cập với IF-016) db/payment-migrations/*.sql (dự kiến) Tương tự IF-016 Tương tự IF-016, ảnh hưởng riêng luồng thanh toán (không lan sang Nhóm Giao dịch/Hỗ trợ) ứng viên #10
IF-018 Shipping & Fulfillment (CMP-10) GHN REST/HTTPS (tạo/tra vận đơn) + Webhook Sync + Async GHN (bên thứ ba) 🔴 Cần tài liệu API GHN thật — chưa có sandbox (ARISK-04) Chưa xác nhận Timeout (đề xuất 8s) → thử GHTK (fallback chéo, ASR-013); cả hai lỗi → đơn ở trạng thái "chờ tạo vận đơn", cảnh báo Ops ứng viên #6
IF-019 Shipping & Fulfillment GHTK Tương tự IF-018, fallback chéo cho GHN Sync + Async GHTK (bên thứ ba) 🔴 Cần tài liệu API GHTK thật — chưa có sandbox (ARISK-04) Chưa xác nhận Tương tự IF-018 (fallback ngược sang GHN nếu GHTK cũng lỗi — **chưa thiết kế, ARISK-04` chưa kiểm chứng cả hai chiều) ứng viên #7
IF-020 Notification (CMP-09) Email/SMS Provider REST/HTTPS hoặc SDK qua queue Async 🔴🔴 Chưa chọn nhà cung cấp (OQ-016 mở) N/A — chưa có provider để có contract N/A Không gửi được → ghi NotificationLog.status=failed, không chặn luồng chính (Notification là consumer bất đồng bộ, không nằm trên đường găng checkout) ứng viên #8
IF-021 Cart & Order (CMP-04) Promotion & Loyalty (CMP-07) REST/JSON — 🔴 ranh giới mạng chưa rõ: SAD §4 legend gọi đây là "internal call cùng process/network boundary", nhưng SAD §7/OQ-026 (TẠM) mô tả Nhóm Giao dịch và Nhóm Hỗ trợ là 2 ECS Fargate service riêng — hai mô tả này mâu thuẫn nhau (xem OQ-028 mới) Sync (theo cả hai cách hiểu) BE Nhóm Hỗ trợ (module Promotion) contracts/openapi/nhom-ho-tro/promotion-apply.yaml (dự kiến) Path /v1 (internal) Lỗi/timeout → hành vi chưa chốt: bỏ qua coupon hay chặn checkout (OQ-017 của BA, IMPACT_CartCheckout §1.5) ứng viên #2
IF-022 Cart & Order (CMP-04) ↔ Seller Management (CMP-05) REST/JSON nội bộ Sync BE Nhóm Hỗ trợ (module Seller) contracts/openapi/nhom-ho-tro/seller-lookup.yaml (dự kiến) Path /v1 (internal) Lỗi/timeout → đề xuất SA: dùng sellerName snapshot đã denormalize trong CartItem thay vì gọi runtime (xem §5 mục 1, OQ-033) — nếu Tech Lead từ chối denormalize thì cần fallback hiển thị sellerId thay tên ứng viên mới

🔴 IF-003, IF-004, IF-016, IF-017, IF-018, IF-019, IF-020 chỉ được xác nhận ở mức catalog (bảng trên) trong lượt chạy này — không thuộc phạm vi "chi tiết đầy đủ Cart & Order" của ghi chú người duyệt. Chi tiết đầy đủ (mã lỗi, ví dụ JSON, quyền chi tiết) để hoạt động icd lần sau hoặc khi module tương ứng tới lượt là trọng tâm.

🔴 CMP-04 và CMP-05 trong SAD §4.1 đều liệt kê IF-022 ở cột "Interface ra" — không rõ chiều gọi thật (Cart&Order gọi Seller Mgmt, hay ngược lại, hay cả hai chiều dùng chung một ID). ICD tạm giả định chiều Cart&Order → Seller Management (khớp nhu cầu lấy sellerName ở GET /v1/cart) và ghi OQ-032 (SA, mới) để Tech Lead xác nhận khi rà lại SAD.

2.1 Interface với hệ thống ngoài

ID Hệ thống Ai liên hệ được SLA của họ Giới hạn tốc độ Cơ chế xác thực Môi trường thử Đã gọi thử chưa
IF-007 VNPay 🔴 Chưa có đầu mối liên hệ chính thức (CON-04, ARISK-03) 🔴 Chưa xác nhận 🔴 Chưa xác nhận Checksum/chữ ký theo tài liệu VNPay (chưa xác minh chi tiết) Không ☐
IF-008 Momo 🔴 Chưa có đầu mối liên hệ chính thức 🔴 Chưa xác nhận 🔴 Chưa xác nhận Chữ ký theo tài liệu Momo (chưa xác minh chi tiết) Không ☐
IF-018 GHN 🔴 Chưa có đầu mối liên hệ chính thức (ARISK-04) 🔴 Chưa xác nhận 🔴 Chưa xác nhận Token/chữ ký theo tài liệu GHN (chưa xác minh) Không ☐
IF-019 GHTK 🔴 Chưa có đầu mối liên hệ chính thức 🔴 Chưa xác nhận 🔴 Chưa xác nhận Token/chữ ký theo tài liệu GHTK (chưa xác minh) Không ☐
IF-020 Email/SMS Provider 🔴🔴 Chưa chọn nhà cung cấp (OQ-016) N/A N/A N/A Không ☐

🔴 Cả 5 hệ thống ngoài đều "chưa có sandbox" hoặc "chưa chọn nhà cung cấp" — thiết kế phải giả định chúng có thể hỏng bất cứ lúc nào (không có SLA để dựa vào). Đã ghi ARISK-03 (VNPay/ Momo), ARISK-04 (GHN/GHTK). Email/SMS chưa có ARISK riêng cho việc "chưa chọn nhà cung cấp" — đã có ở CTX §4.2 (mức 🔴🔴). Không thiết kế thêm timeout/retry cụ thể mới ở đây ngoài số đã kế thừa (CTX §4.2: VNPay/Momo 10s, GHN/GHTK 8s, Email/SMS 5s) — số này chưa kiểm chứng sandbox thật, giữ nguyên trạng cho tới khi có tài liệu đối tác.


3. Chi tiết từng interface

3.1 IF-002 — Client ↔ Nhóm Giao dịch: Cart & Order (US-002/US-003)

Đây là phần "chi tiết đầy đủ" theo yêu cầu — 4 endpoint dưới đây cùng thuộc IF-002 (ranh giới Client → Nhóm Giao dịch), tách theo endpoint để xác nhận API_US002-003_v1.0.md của BA.

Hai đầu Web/Mobile Client (Guest/Customer) → Cart & Order Service (CMP-04, trong Nhóm Giao dịch)
Giao thức HTTPS/REST JSON, qua ALB (CMP-01, không xử lý authz chi tiết — chỉ chuyển token/session xuống, theo SAD §4.1 cột "cái CMP-01 KHÔNG làm")
Đồng bộ? Sync · timeout đề xuất: chưa chốt ở ICD (thuộc hoạt động fail), tạm dùng ngân sách latency QAS-003/QAS-004 làm giới hạn trên thực tế
Authn Bearer JWT (Customer) hoặc X-Guest-Session-Id (Guest) — theo §1 mục 9/10
Authz Ownership check tại service (không phải gateway) + cache Redis, theo ADR-007; Guest theo session_id, Customer theo customer_id — khớp RBAC_CartCheckout §2 (BA). Không cần scope riêng ngoài định danh hợp lệ (khớp API_US002-003 §3.1)
Idempotent GET: có (đọc). PATCH/DELETE: không cần Idempotency-Key — thao tác tự nhiên idempotent theo semantics (PATCH set quantity tuyệt đối; DELETE trên item đã xoá trả 404, không side-effect kép). POST /v1/checkout: có, Idempotency-Key bắt buộc (theo §1 mục 7, 04-api-design.md §4.1.1)
Tần suất dự kiến GET /v1/cart: đọc nhiều (mỗi lần mở SCR-04); PATCH/DELETE: ghi đơn lẻ theo thao tác người dùng — nguồn: QAS-003/QAS-004 (chưa có con số req/s tuyệt đối, chỉ có ngưỡng latency)
QAS áp dụng QAS-003 (GET /v1/cart p95 ≤500ms 🔴 đề xuất, OQ-018), QAS-004 (PATCH/DELETE p95 ≤300ms 🔴 đề xuất, OQ-019), QAS-010 (0% IDOR thành công), QAS-002 (POST /v1/checkout p95 ≤3s, Must)

Bảng endpoint × xác nhận/điều chỉnh API_US002-003_v1.0.md — xem chi tiết đầy đủ ở §5.

3.1.1 GET /v1/cart

Mục đích Tải dữ liệu SCR-04 (US-002)
Quyền Guest (X-Guest-Session-Id) hoặc Customer (Bearer JWT) — không scope riêng
Idempotent Có (read-only)

Response 200 — XÁC NHẬN có điều chỉnh (so với đề xuất BA §3.1)

{
  "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, Đỏ",
            "unitPriceSnapshotVnd": 100000,
            "currentPriceVnd": 100000,
            "priceChanged": false,
            "quantity": 2,
            "imageUrl": "https://cdn.example.com/p/789.jpg"
          }
        ]
      }
    ],
    "totalVnd": 585000,
    "totalItemCount": 5
  }
}
Trường Kiểu Khác gì so với đề xuất BA Lý do
sellers[].sellerName string Giữ nguyên đề xuất BA (trả sẵn) nhưng đổi nguồn dữ liệu: đề xuất SA — denormalize snapshot vào CartItem lúc thêm giỏ (giống unit_price_snapshot), không gọi runtime IF-022 mỗi request Gọi IF-022 (Cart&Order→Seller Mgmt) mỗi lần GET /v1/cart cạnh tranh trực tiếp ngân sách QAS-003 (≤500ms) — cùng loại xung đột đã ghi ở QAS §A4 dòng 1 cho ownership check. OQ-033 (SA, mới) — cần Tech Lead + DBA xác nhận trước khi đưa vào DAT
items[].unitPriceSnapshotVnd, currentPriceVnd, priceChanged number, number, boolean Điều chỉnh (thêm trường) so với đề xuất BA chỉ có unitPriceVnd OQ-029 (BA) chưa chốt giá hiển thị là snapshot hay real-time — thêm cả hai trường (additive, không breaking) để SCR-04 hoạt động đúng dù PO trả lời theo hướng nào; priceChanged = currentPriceVnd != unitPriceSnapshotVnd. Nếu PO xác nhận chỉ cần 1 trong 2, có thể bỏ trường thừa ở version sau (không breaking vì chỉ xoá field không dùng)
sellers[].subtotalVnd, totalVnd number Xác nhận — BE tính sẵn, không để FE tự cộng Tránh sai lệch làm tròn FE/BE (đúng lý do BA đưa ra)
Cấu trúc nhóm theo sellers[].items[] — Xác nhận — đây chính là câu trả lời cho OQ-034(BA): trả về đã nhóm theo seller, không trả danh sách phẳng Nhất quán trực tiếp với mô hình Order/OrderSeller đã chốt ở ADR-003 — nếu Cart không nhóm theo seller từ đầu, POST /v1/checkout phải tự nhóm lại phía BE mà FE không thấy trước, gây lệch trải nghiệm giữa xem giỏ và xác nhận đơn. Đề nghị BA đóng OQ-034 trong sổ BA, tham chiếu IF-002/ADR-003.

Mã lỗi — xác nhận nguyên trạng theo API_US002-003 §3.1 (401 ERR_AUTH_INVALID_TOKEN, 500/503 ERR_INTERNAL/ERR_SERVICE_UNAVAILABLE, mã SRS E-CART-0004).

3.1.2 PATCH /v1/cart/items/{cartItemId}

Mục đích Cập nhật quantity (US-003 F01)
Quyền Chủ sở hữu CartItem — Guest theo session_id, Customer theo customer_id

XÁC NHẬN request/response body theo đề xuất BA §3.2 nguyên trạng ({ "quantity": 3 } → { "cartItemId", "quantity", "sellerSubtotalVnd", "cartTotalVnd" }) — trả CartItem đã cập nhật

  • tổng nhóm/tổng giỏ liên quan, không trả toàn bộ Cart. Lý do: nhẹ hơn, đủ dữ liệu để FE cập nhật UI dòng đang sửa + tổng, khớp cách BA đã đề xuất ở §5 mục 3.

XÁC NHẬN — đóng OQ-032(BA): cơ chế ownership của Guest dùng cùng cơ chế 403 ERR_FORBIDDEN_OWNERSHIP như Customer (đối chiếu session_id thay vì customerId), theo ADR-007 (chỗ ra quyết định là service, có cache) — không có cơ chế riêng biệt cho Guest. Đề nghị BA đóng OQ-032 trong sổ BA, tham chiếu ADR-007.

CHỜ OQ — mục 7 của BA (PATCH có kiểm tra tồn kho tại đây không, trả 422 ERR_BUSINESS_RULE): đây là quyết định phạm vi nghiệp vụ thuộc PO/Tech Lead (OQ-030(BA)), không phải quyết định kiến trúc — ICD không tự quyết. Ghi chú kiến trúc cho cả hai nhánh: nếu PO chọn "có kiểm tra", PATCH gọi lại IF-005 (đã có sẵn, không cần interface mới); nếu "không", giữ thiết kế hiện tại.

Mã lỗi: xác nhận nguyên trạng API_US002-003 §3.2 (400 ERR_VALIDATION, 403 ERR_FORBIDDEN_OWNERSHIP, 404 ERR_NOT_FOUND, 409 ERR_CONFLICT, 500/503). Mã 422 ERR_BUSINESS_RULE để dự phòng, chỉ kích hoạt nếu OQ-030(BA) trả lời "có kiểm tra".

3.1.3 DELETE /v1/cart/items/{cartItemId}

XÁC NHẬN nguyên trạng đề xuất BA §3.3: 200 kèm body (deletedCartItemId, sellerSubtotalVnd, cartTotalVnd, sellerRemoved), không dùng 204. Lý do: giữ nhất quán với PATCH (đều trả tổng mới để FE khỏi tự tính), và sellerRemoved cần thiết để FE biết ẩn cả nhóm seller khi giỏ hàng của seller đó rỗng — đúng đề xuất BA §5 mục 4. Cùng cơ chế ownership như PATCH (xem 3.1.2).

3.1.4 POST /v1/checkout (không thuộc API_US002-003 của BA nhưng nằm trong IF-002, cần cho luồng Cart&Order đầy đủ)

Mục đích Tạo Order/OrderSeller từ Cart, khởi tạo thanh toán (PROCESS_CartCheckout B5-B8)
Idempotent Có — Idempotency-Key bắt buộc
QAS áp dụng QAS-002 (p95 ≤3s, Must)

Request/response theo ví dụ đã có ở 04-api-design.md §4.1.5 (cartId, shippingAddressId, paymentMethod, couponCode → parentOrderId, orders[], paymentRedirectUrl) — xác nhận kế thừa nguyên trạng, chưa có AC/SRS riêng của BA cho US-004 (Checkout) trong phạm vi input đã cung cấp ở lượt chạy này nên không có gì để "điều chỉnh"; nếu BA viết SRS/API riêng cho US-004 sau, ICD sẽ xác nhận lại tại lượt icd kế tiếp.


3.2 IF-005 — Cart & Order → Catalog & Inventory (kiểm tra/giữ tồn kho)

Mục đích Kiểm tra tồn kho + giữ chỗ (reserve) khi checkout; có thể tái dùng cho PATCH /v1/cart/items nếu OQ-030(BA) chọn kiểm tra tại đây
Đồng bộ? Sync, in-process (cùng ECS task theo ASM-19, chưa xác nhận OQ-010)
Idempotent Không cần — mỗi lần gọi là một hành động "giữ chỗ" mới, có reservationId riêng (đề xuất SA, chưa xác nhận)
QAS áp dụng QAS-002 (nằm trong ngân sách 3s tổng của checkout)
Lỗi thì sao Không đủ tồn kho → trả 409 ERR_CONFLICT, Cart & Order trả 409 cho client (B4, yêu cầu điều chỉnh giỏ)

3.3 IF-006 — Cart & Order → Payment Service (khởi tạo thanh toán)

Mục đích Khởi tạo Payment cho (các) OrderSeller vừa tạo trong một lần checkout
Đồng bộ? Sync, cross-network (Payment cô lập mạng theo ASR-002)
Idempotent Có — truyền lại Idempotency-Key gốc của POST /v1/checkout
QAS áp dụng QAS-002 (nằm trong ngân sách 3s)

Request (đề xuất SA — chưa xác nhận Tech Lead)

{
  "orderSellers": [
    { "orderSellerId": "order_001", "sellerId": "seller_11", "amountVnd": 350000 },
    { "orderSellerId": "order_002", "sellerId": "seller_22", "amountVnd": 120000 }
  ],
  "paymentMethod": "VNPAY",
  "customerId": "cust_123"
}

🔴 Vì sao cần sellerId ở đây: Payment Service phải biết seller_id của từng OrderSeller để publish sự kiện PaymentConfirmed đúng MessageGroupId theo ADR-005 (per-seller FIFO) — nếu không truyền tại lúc khởi tạo, Payment Service phải gọi ngược lại Cart & Order để tra cứu, tạo thêm một phụ thuộc vòng. Đây là đề xuất kiến trúc mới của ICD, ghi OQ-030 (SA) để Tech Lead xác nhận trước khi dùng làm chuẩn thi công.

Response: gatewayTransactionRef (một hoặc nhiều, tuỳ 1 payment cho nhiều OrderSeller hay từng OrderSeller một payment riêng — chưa chốt, phụ thuộc quyết định nghiệp vụ "1 lần thanh toán cho N seller" đã ngụ ý ở 04-api-design.md §4.1.5 ví dụ paymentRedirectUrl số ít). Ghi nhận là điểm cần Tech Lead xác nhận cùng OQ-030.

Lỗi thì sao: Timeout/lỗi → Cart & Order rollback transaction, không tạo Order/OrderSeller (theo sequence diagram SAD §6.1).


3.4 IF-007/IF-008 — Payment Service ↔ VNPay/Momo

Init (sync) POST tới endpoint khởi tạo giao dịch của đối tác — schema thật chưa biết (🔴 cần tài liệu API VNPay/Momo, ARISK-03)
Webhook (async) POST /v1/payments/webhooks/{vnpay,momo} (theo 04-api-design.md §4.1.6) — đối tác gọi vào, xác thực chữ ký/checksum theo tài liệu của họ (chưa xác minh chi tiết)
Idempotency (ADR-004) Khoá = gatewayTransactionRef; kiểm tra timestamp payload lệch ≤5 phút (chống replay); đã xử lý trước đó → trả 200 OK không xử lý lại nghiệp vụ
QAS áp dụng QAS-002 (init, trong ngân sách 3s checkout), QAS-014 (đối soát ≤15 phút 🔴 đề xuất, OQ-021)
Timeout đề xuất 10s (kế thừa CTX §4.2, chưa kiểm chứng sandbox thật)
Đầu kia hỏng thì sao Init timeout → không có paymentRedirectUrl, FE hiện lỗi thanh toán (giữ Order ở PENDING_PAYMENT, không mất giỏ hàng); webhook mất/trễ → job đối soát bù phát hiện lệch trong ≤15 phút (ADR-004)

🔴 Không bịa schema request/response thật của VNPay/Momo — mọi trường cụ thể (vnp_TxnRef, vnp_SecureHash, mã lỗi của VNPay, v.v.) chưa được ghi vì chưa có tài liệu/sandbox chính thức. Xem OQ-014 (biểu phí, đã có), bổ sung nhu cầu tài liệu kỹ thuật ở §8.


3.5 IF-015 — Cart & Order/Identity & Access → Redis (ownership/session cache)

Mục đích Cache session (Guest)/JWT claims đã xác thực (Customer) + ownership Cart/CartItem để tránh query DB mỗi request (ADR-007)
Key đề xuất session:{session_id}, ownership:cart_item:{cartItemId} → {ownerType, ownerId} (đề xuất SA, chưa xác nhận)
TTL đề xuất Theo TTL session Guest (30 ngày) cho session:*; ngắn hơn (VD 5 phút, chưa chốt) cho ownership:* để giảm rủi ro dữ liệu cũ khi giỏ hàng đổi chủ (hiếm khi xảy ra nhưng phải xử lý)
Lỗi thì sao Cache miss/Redis lỗi → fallback query DB trực tiếp (không chặn luồng, chỉ chậm hơn) — chi tiết đầy đủ (retry, circuit breaker) thuộc hoạt động fail

3.6 IF-021 — Cart & Order → Promotion & Loyalty (áp dụng coupon/điểm)

Mục đích Tính giá trị giảm khi checkout (và có thể cả PATCH/GET nếu cần hiển thị giảm giá tạm thời — chưa chốt phạm vi)
Ranh giới mạng 🔴 Chưa rõ — xem cảnh báo ở bảng §2 (OQ-028, mới)
Lỗi thì sao Chưa chốt — phụ thuộc OQ-017 của BA (IMPACT_CartCheckout §1.5): bỏ qua coupon và tiếp tục checkout, hay chặn checkout khi Promotion&Loyalty lỗi. ICD không tự quyết (thuộc PO/Tech Lead)
QAS áp dụng QAS-002 (nằm trong ngân sách 3s checkout — nếu là cross-network call thật, đây là một round-trip mạng thêm cần tính vào ngân sách)

3.7 IF-022 — Cart & Order ↔ Seller Management (tra cứu tên seller)

Mục đích Cung cấp sellerName cho GET /v1/cart (xem §3.1.1, §5 mục 1)
Đề xuất SA Không gọi runtime mỗi request — denormalize sellerName snapshot vào CartItem lúc thêm vào giỏ (tương tự unit_price_snapshot); IF-022 chỉ được gọi khi thêm sản phẩm vào giỏ (POST /v1/cart/items, ngoài phạm vi chi tiết US-002/003 lần này) hoặc khi cần đồng bộ lại (batch job, chưa thiết kế)
Hệ quả nếu Tech Lead từ chối denormalize Mỗi GET /v1/cart phải gọi IF-022 runtime — cần đo lại QAS-003 (giống xung đột đã ghi ở QAS §A4 dòng 1 cho ownership), có thể cần cache riêng cho sellerName (TTL dài hơn vì tên seller ít đổi)
Rủi ro dữ liệu cũ Nếu seller đổi tên gian hàng sau khi khách đã thêm vào giỏ, sellerName hiển thị có thể lệch tới khi giỏ được làm mới — chấp nhận được vì tần suất đổi tên seller thấp và không ảnh hưởng tính đúng đắn giao dịch (chỉ hiển thị)

4. Hợp đồng sự kiện — OrderPlaced / PaymentConfirmed

Theo ADR-005 (SQS FIFO, MessageGroupId = seller_id) và ASR-005 (≥5 consumer). Schema dưới đây là đề xuất SA, chưa được Tech Lead xác nhận (OQ-030) — không phải chuẩn đã chốt.

Sự kiện Nhà phát Người nhận Schema Thứ tự có quan trọng At-least-once? Trùng thì sao
OrderPlaced Cart & Order (CMP-04) Commission&Payout, Promotion&Loyalty, Review, Notification, Shipping&Fulfillment (5 consumer, ASR-005) Xem bên dưới Có — trong cùng seller_id (không cần thứ tự toàn cục) Có (SQS FIFO/EventBridge) Khử trùng theo eventId (SQS FIFO MessageDeduplicationId, cửa sổ 5 phút) + consumer tự upsert theo khoá nghiệp vụ (orderSellerId, eventType) để chống trùng ngoài cửa sổ 5 phút (VD replay thủ công)
PaymentConfirmed Payment Service (CMP-11) Cart & Order (cập nhật OrderSeller.status), Commission&Payout, Notification Xem bên dưới Có — trong cùng seller_id Có Tương tự trên

Schema OrderPlaced (đề xuất SA):

{
  "eventId": "evt_9f8a7b6c",
  "eventType": "OrderPlaced",
  "eventVersion": "1.0",
  "occurredAt": "2026-09-15T10:00:00Z",
  "messageGroupId": "seller_11",
  "data": {
    "orderId": "order_parent_789",
    "orderSellerId": "order_001",
    "sellerId": "seller_11",
    "customerId": "cust_123",
    "guestSessionId": null,
    "items": [
      { "productVariantId": "variant_789", "quantity": 2, "unitPriceVnd": 100000 }
    ],
    "subtotalVnd": 325000,
    "shippingAddressSnapshot": {
      "recipientName": "Nguyễn Văn A",
      "phone": "09xxxxxxxx",
      "addressLine": "..."
    },
    "paymentMethod": "VNPAY",
    "status": "PENDING_PAYMENT"
  }
}

🔴 shippingAddressSnapshot chỉ chứa trường tối thiểu cần giao hàng (data-minimization theo ASR-008) — danh sách trường whitelist cụ thể chưa được Pháp chế/Security rà soát (OQ-007 vẫn mở). Không thêm trường PII khác vào payload event này cho tới khi có xác nhận.

Schema PaymentConfirmed (đề xuất SA):

{
  "eventId": "evt_1a2b3c4d",
  "eventType": "PaymentConfirmed",
  "eventVersion": "1.0",
  "occurredAt": "2026-09-15T10:05:00Z",
  "messageGroupId": "seller_11",
  "data": {
    "orderId": "order_parent_789",
    "orderSellerId": "order_001",
    "sellerId": "seller_11",
    "gatewayTransactionRef": "vnpay_txn_xxx",
    "paymentMethod": "VNPAY",
    "amountVnd": 325000,
    "confirmedAt": "2026-09-15T10:04:50Z"
  }
}
Vấn đề Quyết định
Message hỏng (poison message) DLQ riêng theo queue; thời gian giữ chưa chốt — thuộc hoạt động fail. Ai xử lý: SRE + Tech Lead module tương ứng (chưa phân công cụ thể)
Đọc lại từ đầu (replay) 🔴 Chưa chốt — SQS không hỗ trợ replay tự nhiên như Kafka; nếu cần, phải có cơ chế lưu event log riêng (ngoài phạm vi quyết định ADR-005 hiện tại)
Thứ tự đảm bảo trong phạm vi nào Trong cùng seller_id (message group), không đảm bảo thứ tự giữa các seller khác nhau — đúng thiết kế ADR-005
Versioning schema eventVersion field; thay đổi additive (thêm field) không tăng version; breaking change (đổi kiểu/xoá field bắt buộc) → eventVersion mới + queue/topic mới, giữ producer cũ chạy song song tối thiểu theo chính sách chung §1 (khuyến nghị áp dụng tương tự 6 tháng của REST, chưa chính thức hoá cho event)

5. Đối chiếu với API_US002-003_v1.0.md của bộ BA

Endpoint / mục IF-nnn Khớp? Xác nhận / Điều chỉnh / Chờ OQ Hành động cho BA
GET /v1/cart — cấu trúc chung IF-002 §3.1.1 🟡 Điều chỉnh Xác nhận cấu trúc nhóm theo seller (đóng OQ-034(BA)) BA cập nhật API_US002-003 §3.1 — bỏ dấu ⚠️ đề xuất, ghi "SA xác nhận qua ICD IF-002, đóng OQ-034"
GET /v1/cart — sellers[].sellerName IF-002/IF-022 🟡 Điều chỉnh Điều chỉnh — vẫn trả sẵn nhưng nguồn là denormalize snapshot, không join runtime BA cập nhật API_US002-003 §5 mục 1: "SA điều chỉnh — xem ICD §3.7, chờ OQ-033"
GET /v1/cart — sellers[].subtotalVnd, totalVnd IF-002 ✅ Khớp Xác nhận — BE tính sẵn BA đánh dấu ✅ tại API_US002-003 §5 mục 2
GET /v1/cart — items[].unitPriceVnd IF-002 🟡 Điều chỉnh Điều chỉnh — tách thành unitPriceSnapshotVnd + currentPriceVnd + priceChanged (additive) BA cập nhật SRS_US002-003 field mapping C06 + API §5 — tham chiếu OQ-029, ghi rõ 2 trường mới không breaking
PATCH /v1/cart/items/{id} — request/response IF-002 §3.1.2 ✅ Khớp Xác nhận nguyên trạng đề xuất BA §3.2/§5 mục 3 BA đánh dấu ✅
PATCH — ownership Guest IF-002 ✅ Khớp Xác nhận — đóng OQ-032(BA) BA cập nhật API §7/SRS §8 — đánh dấu đã đóng, tham chiếu ADR-007
PATCH — kiểm tra tồn kho (422) IF-002/IF-005 ➖ Chờ Chờ OQ — OQ-030(BA) là quyết định phạm vi nghiệp vụ (PO/Tech Lead), không phải kiến trúc Không hành động thêm — BA/PO tự xử lý OQ-030(BA), kiến trúc đã sẵn sàng cho cả hai nhánh
DELETE /v1/cart/items/{id} — response 200+body IF-002 §3.1.3 ✅ Khớp Xác nhận nguyên trạng đề xuất BA §3.3/§5 mục 4 BA đánh dấu ✅
Quy ước id dạng string §1 mục 1 ✅ Khớp Xác nhận — khớp §5 mục 5 của BA BA đánh dấu ✅
Định dạng lỗi {error:{code,message,details}, traceId} §1 mục 4/6 ✅ Khớp Xác nhận Không hành động

Endpoint trong API không có IF-nnn riêng: không có — cả 3 endpoint của API_US002-003 đều thuộc IF-002 (đã chi tiết hoá theo endpoint ở §3.1). POST /v1/checkout (US-004, ngoài phạm vi API_US002-003) cũng thuộc IF-002, xác nhận ở §3.1.4.


6. Hành vi giao diện khi API lỗi

Xác nhận nguyên trạng bảng của API_US002-003 §6 — không lệch, không điều chỉnh.

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á 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á đúng dòng đang xử lý, không khoá toàn trang —

7. Giả định & Ngoài phạm vi

Giả định (tiếp số toàn dự án — ASM-01…23 đã dùng, bắt đầu ASM-24):

ID Giả định Cách xác minh Nếu sai
ASM-24 IF-021 (Cart&Order → Promotion&Loyalty) là cross-network call (2 ECS service riêng) chứ không phải in-process, theo hướng TẠM OQ-026/DEC-16 Tech Lead xác nhận khi trả lời OQ-026/OQ-028 IF-021 đổi từ REST sang in-process call — ảnh hưởng thiết kế FAIL (không cần timeout/circuit breaker riêng nữa) và ngân sách latency QAS-002 (giảm 1 network hop)
ASM-25 IF-022 có chiều gọi là Cart&Order → Seller Management (không phải ngược lại) Tech Lead xác nhận khi rà SAD §4.1 (OQ-032) Nếu ngược lại, thiết kế denormalize sellerName ở §3.7/§5 không còn hợp lý — cần thiết kế lại nguồn dữ liệu
ASM-26 Payment Service nhận đủ sellerId của từng OrderSeller ngay tại IF-006 (không cần tra cứu ngược) để publish PaymentConfirmed đúng MessageGroupId Tech Lead xác nhận thiết kế request IF-006 ở §3.3 (OQ-030) Nếu Payment Service không nhận sellerId lúc khởi tạo, cần thêm một lời gọi ngược IF-mới (Payment → Cart&Order) trước khi publish event — thêm 1 network hop vào đường găng xác nhận thanh toán

Ngoài phạm vi:

  • Chi tiết đầy đủ (mã lỗi, ví dụ JSON, quyền chi tiết) cho IF-003, IF-004, IF-016, IF-017, IF-018, IF-019, IF-020 — chỉ có ở mức catalog (§2) trong lượt chạy này; không thuộc phạm vi "Cart & Order" của ghi chú người duyệt.
  • Schema request/response thật của VNPay/Momo/GHN/GHTK — không bịa; chờ tài liệu/sandbox đối tác thật (ARISK-03/04).
  • Thiết kế DLQ, circuit breaker, backoff cụ thể cho mọi IF-nnn — thuộc hoạt động fail (hoạt động 8, chưa chạy); ICD chỉ ghi timeout đề xuất kế thừa và tham chiếu ứng viên FAIL.
  • Endpoint POST /v1/cart/items (thêm sản phẩm vào giỏ, FR-05) — có trong 04-api-design.md và cần cho IF-022 (thời điểm denormalize sellerName) nhưng không có SRS/AC/API riêng của BA trong phạm vi input đã cung cấp (API_US002-003 chỉ có US-002/003: xem/sửa/xoá) — chưa chi tiết hoá đầy đủ ở lượt này, chỉ nhắc tới khi cần giải thích nguồn snapshot.
  • Rà soát lại con số "22 IF-nn" của SAD — xem §0.1, để lần cập nhật SAD kế tiếp, không phải việc của ICD.

8. Open Questions

Tiếp số sổ SA (00-index/OQ_e-commerce.md đang ở OQ-027) — bắt đầu OQ-028.

ID Câu hỏi Hỏi ai Từ ngày Chặn gì Hệ quả nếu trả lời ngược
OQ-028 IF-021 (Cart&Order → Promotion&Loyalty) là in-process call (theo SAD §4 legend) hay cross-network REST (theo OQ-026 TẠM: 2 ECS service riêng)? Hai mô tả trong SAD mâu thuẫn nhau. Tech Lead 2026-09-15 Thiết kế FAIL cho IF-021; ngân sách latency QAS-002 Nếu cross-network: cần thêm timeout/retry/circuit breaker riêng cho IF-021, tăng rủi ro trễ ở bước áp coupon của checkout; nếu in-process: không cần, nhưng phải sửa lại SAD §7 deployment view (đang vẽ 2 ECS service tách biệt hoàn toàn)
OQ-029 SAD §4 (header/Change Log/§Tự chấm) nêu "22 IF-nn ứng viên" nhưng chỉ 17 ID riêng biệt xuất hiện trong nội dung — có 5 IF nào bị bỏ sót khi viết SAD, hay con số "22" là đếm nhầm? SA (rà lại ở lần cập nhật SAD kế tiếp) 2026-09-15 Độ chính xác của SAD §4/§Tự chấm; không chặn AG2 (đã có 17 interface đủ bao phủ mọi cặp container/hệ ngoài xuất hiện trong văn bản) Nếu có 5 interface thật bị bỏ sót: SAD/ICD cần bổ sung — có thể ảnh hưởng sa-conformance coverage nếu ASR/CMP liên quan tới các interface đó chưa được phục vụ
OQ-030 Xác nhận thiết kế schema sự kiện OrderPlaced/PaymentConfirmed (§4) và request IF-006 (§3.3, đặc biệt việc Payment Service nhận sellerId ngay lúc khởi tạo) — đây là đề xuất mới của ICD, chưa có nguồn nào khác xác nhận. Tech Lead 2026-09-15 Thi công Cart&Order/Payment/message backbone; DAT (hoạt động 5, ownership ReconciliationLog/event log) Nếu Tech Lead chọn thiết kế khác (VD 1 payment cho mỗi OrderSeller riêng thay vì có thể gộp): cần sửa lại ví dụ request/response IF-006 và số lượng paymentRedirectUrl trả về ở POST /v1/checkout
OQ-031 Tên header chuẩn cho correlation id ở request là gì? Đề xuất SA: X-Request-Id. Tech Lead 2026-09-15 Chuẩn hoá logging/observability xuyên suốt hệ thống (input cho hoạt động inf) Nếu chọn tên khác hoặc không cần header riêng (chỉ dựa vào traceId sinh phía server): cập nhật lại §1 mục 8, không ảnh hưởng lớn (chỉ đổi tên field)
OQ-032 IF-022 (Cart&Order ↔ Seller Management) — SAD §4.1 liệt kê cả CMP-04 và CMP-05 đều có IF-022 ở cột "Interface ra" — chiều gọi thật là gì? Tech Lead 2026-09-15 §3.7, §5 mục 1 (denormalize sellerName); rà lại SAD §4.1 ở lần cập nhật kế tiếp Nếu chiều thật là Seller Management → Cart&Order (VD đẩy sự kiện đổi tên/khoá seller): cần thiết kế lại theo hướng event-driven thay vì REST đồng bộ, ảnh hưởng cách cập nhật sellerName snapshot
OQ-033 Có chấp nhận denormalize sellerName snapshot vào CartItem (tương tự unit_price_snapshot) để tránh gọi IF-022 runtime mỗi lần GET /v1/cart không? Tech Lead + DBA 2026-09-15 DAT (hoạt động 5, ownership trường denormalize); QAS-003 (ngân sách latency) Nếu từ chối: GET /v1/cart phải gọi IF-022 runtime hoặc thiết kế cache riêng cho sellerName — cần đo lại QAS-003, rủi ro không đạt ngân sách ≤500ms khi giỏ có nhiều seller

Nhắc: cộng với các OQ còn mở ảnh hưởng trực tiếp ICD — OQ-007 (đại diện Pháp chế, chặn whitelist PII trong shippingAddressSnapshot §4), OQ-012 (thời điểm POC-01, chặn Accepted của ADR-005 mà IF-009 phụ thuộc), OQ-014/015/016 (biểu phí + nhà cung cấp đối tác ngoài, chặn hoàn thiện §2.1), OQ-018/019 (ngưỡng QAS-003/004), OQ-021 (tần suất đối soát QAS-014), OQ-023 (rate limit Guest) — xem sổ đầy đủ 00-index/OQ_e-commerce.md. Từ sổ BA: OQ-029/030/033/034(BA) cần BA cập nhật theo hành động ở §5; OQ-032(BA) đề nghị đóng.


Tự chấm

① Bảng tự chấm Gate AG2 (workflow.md §2 — chỉ dòng liên quan tới ICD, tự chấm sớm)

# Tiêu chí ☐/✅ Ghi chú
— ASR/QAS/SAD ✅ (đã đạt ở các hoạt động trước) Không lặp lại
— ADR-nnn tồn tại cho mọi quyết định đạt ngưỡng radar 🟡 Một phần 12 ADR đã viết (hoạt động adr trước icd theo thứ tự chạy thực tế của dự án này — xem DEC-17); ICD không tạo ADR mới (quy ước §1 mục 1-8 chỉ radar ~3, dưới ngưỡng)
1 ICD — mọi interface ra khỏi hệ thống có contract, owner, versioning policy, chế độ sync/async 🟡 Một phần 17/17 IF-nn truy được từ SAD đã có đủ 2 cột owner/versioning/sync-async (§2); nhưng 5/17 giao thức "chưa rõ chiều/ranh giới" (IF-021, IF-022) hoặc "chưa có tài liệu đối tác" (IF-007/008/018/019, IF-020 chưa chọn nhà cung cấp) — đã ghi OQ cho từng trường hợp, không bỏ sót im lặng
— DAT/SEC/INF/FAIL ☐ Chưa tới — hoạt động 5-8
— sa-conformance báo coverage ASR → ADR/CMP ≥ 100% (không đổi bởi ICD) ICD không tạo CMP/ASR mới

Kết luận tự chấm (riêng phần ICD): Hoạt động icd hoàn tất đúng phạm vi được giao — 17/17 IF-nn truy được từ SAD có dòng catalog đầy đủ 9 cột; 4 endpoint Cart & Order (GET/PATCH/ DELETE /v1/cart*, POST /v1/checkout) có chi tiết đầy đủ và đã xác nhận/điều chỉnh/đánh dấu chờ OQ cho toàn bộ API_US002-003_v1.0.md của BA. Không tạo giao ước nào không có nguồn. Chênh lệch "22 vs 17" của SAD được ghi nhận minh bạch, không lấp liếm. AG2 còn xa vì DAT/SEC/INF/ FAIL (hoạt động 5-8) chưa chạy và không ADR nào Accepted.

② Checklist D1–D12 (design-rules.md)

# Mục ☐/✅ Ghi chú
D1 Một ADR một quyết định N/A ICD không viết ADR mới ở lượt này (radar §1 mục 1-8 dưới ngưỡng)
D2 Không NFR định tính N/A ICD không phải QAS; mọi ngân sách latency tham chiếu đúng QAS-002/003/004/010 đã lượng hoá, không tự đặt số mới
D3 Nêu phương án bị loại + lý do 🟡 Một phần Các điều chỉnh ở §5 (VD denormalize sellerName) có nêu lý do gắn QAS-003, nhưng không đầy đủ bảng "phương án đã cân nhắc" kiểu ADR (không bắt buộc vì đây là ICD, không phải ADR)
D4 Sơ đồ khai báo mức + legend N/A ICD không có sơ đồ mới (chỉ bảng + JSON ví dụ)
D5 Interface có chủ/contract ✅ (với ghi chú) 17/17 có cột "ai sở hữu"/"contract ở đâu"/"versioning" — 5 dòng đối tác ngoài + IF-020 ghi rõ "chưa có contract vì chưa có sandbox/nhà cung cấp", không để trống im lặng
D6 Phụ thuộc ngoài process có timeout/retry 🟡 Một phần Timeout đề xuất kế thừa (CTX §4.2) đã ghi cho từng interface đối tác ngoài; retry/circuit breaker/backoff đầy đủ theo 4 câu hỏi D6 vẫn thuộc hoạt động fail (chưa chạy) — ICD chỉ tham chiếu ứng viên FAIL
D7 Một chủ sở hữu dữ liệu N/A Thuộc DAT (hoạt động 5); ICD chỉ nhắc sellerName denormalize cần DAT xác nhận ownership
D8 Ràng buộc có FIT hoặc nhãn khuyến nghị N/A Chưa tới AGD/FIT (GĐ3)
D9 Con số hạ tầng quy ra tiền + nguồn N/A ICD không thêm con số hạ tầng mới
D10 Không quyết định thay người có thẩm quyền ✅ Mục "chờ OQ" (OQ-030(BA) kiểm tra tồn kho) không tự quyết; mọi đề xuất mới (denormalize, event schema, request IF-006) đều gắn OQ kèm hệ quả phương án ngược, không âm thầm coi là quyết định cuối
D11 Có mục "Ngoài phạm vi" + ASM-nn ✅ §7 đầy đủ — ASM-24…26 mới
D12 Câu quy định thẩm quyền sơ đồ vs văn bản ✅ Có ngay sau Change Log

③ Bảng đối chiếu với bộ BA

Xem §5 (bảng đầy đủ endpoint × xác nhận/điều chỉnh/chờ OQ) — đây là bảng đối chiếu API↔ICD theo yêu cầu SKILL.md mục "Trước khi kết thúc". Tóm tắt: 6/9 dòng ✅ khớp hoàn toàn, 3/9 điều chỉnh (có lý do rõ ràng gắn QAS-003/OQ-029/ADR-003), 1/9 chờ quyết định PO/Tech Lead (OQ-030(BA), không phải kiến trúc). Không có endpoint nào trong API thiếu IF-nnn tương ứng.

④ Danh sách OQ mở kèm người phải trả lời, chặn gì

Xem §8 (OQ-028…033 mới) cộng các OQ còn mở liên quan trực tiếp — OQ-007 (PII), OQ-012 (POC-01, chặn Accepted của ADR-005), OQ-014/015/016 (đối tác ngoài), OQ-018/019/021/023 (ngưỡng QAS) — sổ đầy đủ 00-index/OQ_e-commerce.md. Từ sổ BA cần theo dõi: OQ-029/030/033/ 034(BA) (hành động ở §5), OQ-032(BA) (đề nghị đóng, tham chiếu ADR-007/IF-002).

Nhắc: AG2 cần Tech Lead + Security + Ops/SRE ký — còn xa vì DAT/SEC/INF/FAIL (hoạt động 5-8) chưa chạy. Hoạt động kế tiếp có thể chạy song song, dùng IF-nnn ở đây làm đầu vào: dat (bảng "Dữ liệu sở hữu" đã có ở SAD §4.1, cộng sellerName denormalize mới nêu ở ICD §3.7/OQ-033), sec (mô hình authn/authz đã chi tiết hoá thêm ở ICD §1/§3.1), inf, fail (dùng bảng "Đầu kia hỏng thì sao"/"Ứng viên FAIL" ở ICD §2).