Files
sys-analysis-design/sa-output/e-commerce/02-architecture/FAIL_e-commerce_v1.0.md
Canhchimlac 343ad8bbbc save
2026-09-15 16:02:30 +07:00

76 KiB
Raw Blame History

FAIL — Failure Mode & Resilience Design — e-commerce

Version 1.1
Date 2026-09-15
Author SA (skill sa-2-architecture, chế độ go, hoạt động fail)
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 bảng 13 phụ thuộc (FM-01…13) đủ timeout/retry/idempotency/fallback, bảng mã lỗi §5, đề xuất FIT-16…22. Chấp nhận TẠM (🔴) các ngưỡng SA đề xuất: circuit breaker (OQ-035), DLQ 14 ngày + ngưỡng cảnh báo lag hàng đợi >5 phút (OQ-036), bulkhead pool chờ POC-02 (OQ-037), timeout RDS/Redis (ASM-27/ASM-28) — các OQ này giữ nguyên mở, chờ Tech Lead/SRE thật xác nhận. Quyết định OQ-034: chọn Lựa chọn B — bất đồng bộ hoá bước khởi tạo thanh toán để đường găng POST /v1/checkout đạt QAS-002 (≤3.000ms) — thay vì Lựa chọn A; yêu cầu SA viết ADR-013 (Proposed) và sửa nhất quán SAD §6.1 + FAIL §1.2 theo hướng B ở lượt kế tiếp (chưa thực hiện ở lượt sign này). OQ-034 chuyển trạng thái "đã chọn hướng B, chờ ADR-013 + Tech Lead/PO thật xác nhận" — giữ nguyên mở, chưa đóng. Ghi thêm DEC-22. · Security: — (chưa ký) · Ops/SRE: — (chưa ký). 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ệ, còn thiếu DAT/SEC/INF (hoạt động 5-7, chưa chạy). Lưu ý v1.1 (2026-09-15): §1.2 vừa được sửa theo ADR-013 (Proposed, hiện thực hoá Lựa chọn B) — tách đường găng đồng bộ (bước 1–7, 10) khỏi bước khởi tạo thanh toán online (bước 8, nay bất đồng bộ), kết quả tổng đồng bộ ≤3.000ms. Đây là nội dung kiến trúc mới theo ADR-013, không phải sửa lỗi tài liệu; chữ ký nêu trên không áp dụng cho §1.2 bản v1.1 — cần Tech Lead + PO thật xác nhận ADR-013 trước khi coi §1.2 là đã duyệt.
Source 02-architecture/SAD_e-commerce_v1.0.md v1.3 §4, §4.1, §6.1, §6.2, §6.3, §7, §8 · 02-architecture/ICD_e-commerce_v1.0.md §1, §2, §2.1, §3.1–§3.7, §4, §6, §8 · 02-architecture/QAS_e-commerce_v1.0.md QAS-002/003/004/005/008/010/013/014 · 02-architecture/ASR_e-commerce_v1.0.md ASR-004/005/007/010/013 · 02-architecture/adr/ADR-004_*.md, ADR-005_*.md, ADR-007_*.md, ADR-009_*.md, ADR-011_*.md, ADR-013_*.md (mới, Proposed) · 01-context/ARISK_e-commerce_v1.0.md §3 (ARISK-01/02/03/04) · 00-index/OQ_e-commerce.md v1.18 (OQ-034, DEC-22) · 00-index/DEC_e-commerce.md v1.20 (DEC-22, DEC-23) · ba-output/e-commerce/02-analysis/IMPACT_CartCheckout_v1.0.md §1.5, §6 (OQ-017) · ba-output/e-commerce/03-specification/AC_US-002_v1.0.md · ba-output/e-commerce/03-specification/AC_US-003_v1.0.md
Scope Toàn sàn theo P2 — đúng 13 phụ thuộc vượt ranh giới process liệt kê ở SAD v1.2 §6.3 + footnote §4.1: VNPay (IF-007), Momo (IF-008), GHN (IF-018), GHTK (IF-019), Email/SMS Provider (IF-020), RDS chính (IF-016), RDS Payment (IF-017), ElastiCache Redis (IF-015), SQS FIFO (IF-009 publish/consume), EventBridge (fan-out, phần của IF-009), Cart&Order→Payment (IF-006), Cart&Order→Promotion&Loyalty (IF-021, ưu tiên cao nhất — đường găng checkout), Cart&Order↔Seller Management (IF-022). Không bao gồm IF-005 (Catalog&Inventory) vì là in-process call cùng ECS task, không vượt ranh giới process (SAD §6.3 dòng 1).
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/ICD/ASR/QAS. AG1 chưa ký thật; AG2 chưa tới hạn; không ADR nào Accepted; không đối tác ngoài nào (VNPay/Momo/GHN/GHTK) có sandbox thật (ARISK-03/04); mọi con số timeout/circuit-breaker/backoff dưới đây là đề xuất SA chưa kiểm chứng, gắn OQ/ASM tương ứng.

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 fail) Bản đầu — hoạt động 8/9 của GĐ2. Bảng phụ thuộc 13 dòng (FM-01…13) đủ timeout/retry/idempotent/hết-retry-thì-sao; 4 câu hỏi D6 cho từng phụ thuộc; ngân sách timeout cộng dồn đường găng checkout (phát hiện xung đột ngân sách: timeout VNPay/Momo kế thừa 10s không thể dùng nguyên trạng trong nhánh đồng bộ IF-006→IF-007/008 vì vượt QAS-002 ≤3s — đề xuất tách timeout riêng 1.500ms cho nhánh này, ghi OQ-034); circuit breaker/backoff/bulkhead cho toàn hệ thống; suy giảm có kiểm soát (Promotion lỗi, COD khi VNPay/Momo lỗi, GHN↔GHTK fallback chéo, đọc giỏ từ Redis khi RDS chậm); 6 kịch bản hỏng toàn hệ thống; dữ liệu trong lúc lỗi; ánh xạ mã lỗi theo AC_US-002/003/ICD §1; đề xuất FIT-16…22 (chaos test) cho GĐ3. Thêm OQ-034…040, ASM-27…33. Ghi ngoại lệ tiếp tục gate ở DEC-21 (tiếp nối DEC-01…20). Không sửa SAD/ICD/ADR đã có. Confidence 🔴 toàn bộ. DEC-21
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 bảng 13 phụ thuộc (FM-01…13), bảng mã lỗi §5, FIT-16…22. Chấp nhận TẠM (🔴) ngưỡng circuit breaker (OQ-035), DLQ 14 ngày + cảnh báo lag >5 phút (OQ-036), bulkhead chờ POC-02 (OQ-037), timeout RDS/Redis (ASM-27/ASM-28) — tất cả giữ nguyên mở. Quyết định OQ-034: chọn Lựa chọn B (bất đồng bộ hoá bước khởi tạo thanh toán) — yêu cầu SA viết ADR-013 (Proposed) và sửa nhất quán SAD §6.1 + FAIL §1.2 ở lượt kế tiếp; OQ-034 cập nhật "đã chọn hướng B, chờ ADR-013 + Tech Lead/PO thật xác nhận", giữ nguyên mở. Không đổi nội dung chuyên môn ở lượt sign này. Security/Ops chưa ký; OQ-004 mở; Confidence giữ 🔴; Status giữ 🟡 Draft; AG2 chưa ký. Ghi thêm DEC-22. DEC-22
1.1 2026-09-15 SA (qua skill sa-2-architecture, chế độ go, hoạt động adr) Sửa nhất quán tối thiểu theo ADR-013 (Proposed), yêu cầu người duyệt 2026-09-15 — hiện thực hoá Lựa chọn B đã chọn ở OQ-034/DEC-22. §1.2 sửa lại bảng ngân sách timeout cộng dồn: tách đường găng đồng bộ (bước 1–6 + xác nhận COD đồng bộ cho nhánh COD, cộng bước 10 serialization) ra khỏi bước khởi tạo thanh toán VNPay/Momo (bước 8 cũ, nay bất đồng bộ, không tính vào ngân sách phản hồi) — kết quả: tổng đồng bộ nhánh COD = 1.720ms, nhánh VNPay/Momo = 1.120ms, cả hai đều ≤3.000ms (QAS-002 Must đạt), không còn vượt ngân sách ~7% như v1.0. Ghi kết quả tính toán mới, đánh dấu OQ-034 "đã chọn hướng B, đã có ADR-013 (Proposed), chờ Tech Lead/PO thật xác nhận" trong sổ 00-index/OQ_e-commerce.md. Thêm OQ-041 (cơ chế FE lấy redirectUrl — polling hay SSE/WebSocket), OQ-042 (thời gian giữ Order ở PENDING_PAYMENT_INIT trước khi coi là kẹt, cần job dọn dẹp) — cả hai từ ADR-013 §3. Không sửa nội dung khác của FAIL (bảng §1.1 13 phụ thuộc, §2 bốn câu hỏi D6, §3 circuit breaker/backoff/bulkhead, §4 suy giảm có kiểm soát, §5 mã lỗi, §6 kịch bản hỏng, §7 dữ liệu lúc lỗi, §8 diễn tập, §9 giả định/ngoài phạm vi giữ nguyên như v1.0) — đúng phạm vi được giao. Ghi ngoại lệ tiếp tục gate ở DEC-23 (00-index/DEC_e-commerce.md), tiếp nối DEC-01…22. Confidence giữ 🔴 — chưa có bằng chứng nguồn mới (chưa đo thật, chưa Tech Lead/PO thật ký); Status giữ 🟡 Draft; §1.2 bản v1.1 chưa được Tech Lead/Security/Ops ký. ADR-013

Sơ đồ thắng về quan hệ và luồng (ai gọi ai, theo thứ tự nào — xem SAD §6.1/§6.2). Bảng/văn bản thắng về ràng buộc và con số (timeout, retry, ngưỡng circuit breaker). 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).


0. Ghi chú Preflight & ngoại lệ gate — bắt buộc đọc trước

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); hoạt động 4 (ICD) đã chạy (DEC-18/19/20). Điều kiện đầu vào cho hoạt động 8 (FAIL) đã đủ. 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-21 (SA) — Tiếp tục sa-2-architecture (hoạt động 8 — FAIL) 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…20. Quyết định: Thiết kế đường lỗi cho 13 phụ thuộc vượt ranh giới process theo SAD v1.2 §6.3, dựa trên ASR-004/005/007/010/013, QAS-002/003/004/005/008/010/013/014, ADR-004/005/007/ 009/011 đã có. Giữ Confidence 🔴 cho tới khi: (a) AG1/AG2 ký thật, (b) đối tác ngoài có sandbox thật để kiểm chứng timeout/retry (ARISK-03/04), (c) Tech Lead/SRE xác nhận các đề xuất mới (timeout riêng cho nhánh checkout đồng bộ, ngưỡng circuit breaker, DLQ retention, bulkhead sizing). 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 (cấu hình timeout/retry là số dễ đổi qua config, không phải viết lại kiến trúc) · bán kính ảnh hưởng: toàn bộ luồng checkout + mọi consumer của message backbone, nhưng bản thân việc ghi tài liệu dưới ngoại lệ thì nhỏ · có chạm QAS-002 Must trực tiếp (phát hiện xung đột ngân sách timeout) 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 (số cấu hình sửa được qua version mới, khác ADR bất biến — các quyết định kiến trúc nền tảng đã có ADR-004/005/007/009/011 riêng) · không tranh cãi mới, tiếp nối tiền lệ DEC-11…20 → ghi DEC-nn, không cần ADR mới cho việc chạy dưới ngoại lệ. Hệ quả nếu không chấp nhận ngoại lệ: AG2 thiếu tiêu chí "mỗi phụ thuộc ra ngoài process có failure mode, timeout, retry, fallback" (workflow.md §2) — Dev sẽ tự chọn timeout/retry lúc code, mỗi người một kiểu, không ai biết tổng thể hệ thống hỏng thế nào (đúng bẫy đã cảnh báo ở SKILL.md "Bẫy thường gặp").

🔴 Phát hiện quan trọng của lượt chạy này (xem §1.2): ngân sách timeout kế thừa cho VNPay/Momo (10s, từ CTX §4.2) không thể áp dụng nguyên trạng cho lời gọi đồng bộ bên trong IF-006 (Cart&Order → Payment Service → VNPay/Momo, theo SAD §6.1) vì một mình con số đó đã vượt toàn bộ ngân sách QAS-002 (≤3.000ms). Đây không phải lỗi tài liệu của SAD/ICD (họ ghi đúng số kế thừa cho ngữ cảnh chung) mà là khoảng trống chưa ai đối chiếu ngân sách theo D6: "Timeout tầng ngoài phải > tổng timeout tầng trong" — ở đây timeout tầng trong (VNPay/Momo, 10s) đang lớn hơn timeout tầng ngoài (toàn bộ checkout, 3s), ngược hoàn toàn nguyên tắc. Xem đề xuất sửa ở §1.2 và OQ-034.


1. Bảng phụ thuộc — 13 lời gọi vượt ranh giới process

1.1 Bảng chính

FM Phụ thuộc Từ CMP IF-nnn Ưu tiên Timeout Retry Idempotent Hết retry thì sao Người dùng thấy gì QAS
FM-01 VNPay CMP-11 Payment IF-007 Cao (checkout) Init đồng bộ trong checkout: 1.500ms (đề xuất mới, thay 10s kế thừa — xem §1.2, OQ-034) · Webhook (inbound, ta là receiver): không áp dụng timeout gọi ra · Job đối soát (poll): 10s (kế thừa CTX §4.2, ngữ cảnh không tính giờ) Init checkout: 0 lần (trừ lỗi kết nối trước khi request rời khỏi máy — cho phép 1 lần retry tức thời, chưa chạm server VNPay) · Job đối soát: 3 lần, backoff mũ (base 500ms ×2, jitter ±20%) Init: có — Idempotency-Key truyền lại từ POST /v1/checkout (ADR-004) · Job đối soát: có — GET tra cứu trạng thái, tự nhiên idempotent Init: rollback TX Order, trả lỗi cho client (client tự bấm "Thử lại", an toàn nhờ idempotency key) · Job đối soát: ghi ReconciliationLog + cảnh báo nếu lệch (ADR-004) "Không thể khởi tạo thanh toán, vui lòng thử lại hoặc chọn phương thức khác" (🔴 mã lỗi mới đề xuất — xem §5, OQ-038) QAS-002, QAS-014
FM-02 Momo CMP-11 Payment IF-008 Cao (checkout) Giống hệt FM-01 Giống hệt FM-01 Giống hệt FM-01 Giống hệt FM-01 Giống hệt FM-01 QAS-002, QAS-014
FM-03 GHN CMP-10 Shipping IF-018 Trung bình (không chặn checkout — chạy sau khi đơn đã xác nhận, async) 8s (kế thừa CTX §4.2, chấp nhận vì không nằm trên đường găng checkout) 3 lần, backoff mũ (base 1s ×2, jitter ±20%), chỉ retry sau khi GET kiểm tra waybill đã tồn tại chưa (🔴 GHN có hỗ trợ tra cứu theo mã đơn của ta không — chưa xác nhận, ARISK-04) 🟡 Có điều kiện — cần "check-then-act" vì chưa xác nhận GHN có idempotency key native Chuyển sang GHTK (fallback chéo, ASR-013) Không hiển thị lỗi trực tiếp cho khách (async sau khi đặt hàng) — nếu cả GHN/GHTK lỗi, đơn ở trạng thái "Đang chuẩn bị vận chuyển" kéo dài, CSKH được cảnh báo QAS-013 (giám sát)
FM-04 GHTK CMP-10 Shipping IF-019 Trung bình Giống FM-03 Giống FM-03 Giống FM-03 Cả GHN lẫn GHTK lỗi → đơn chuyển AWAITING_MANUAL_FULFILLMENT, cảnh báo Ops ngay (không tự động thử lại vô hạn) — xem OQ-039 Không hiển thị lỗi cho khách; CSKH chủ động liên hệ nếu SLA thủ công bị vượt (chưa chốt SLA — OQ-039) QAS-013
FM-05 Email/SMS Provider CMP-09 Notification IF-020 Thấp (không chặn luồng chính) 5s (kế thừa CTX §4.2) 3 lần, backoff mũ (base 1s ×2, jitter ±20%) 🟡 Chấp nhận trùng lặp rủi ro thấp (gửi email 2 lần không hại) — khuyến nghị dedupe theo (orderId, eventType) ở NotificationLog để giảm phiền khách Ghi NotificationLog.status=failed, không chặn luồng chính Không thấy gì (không nhận được thông báo — không có banner lỗi vì đây là kênh phụ) —
FM-06 RDS PostgreSQL chính CMP-04, CMP-03, CMP-05…10 IF-016 Cao (đọc/ghi giỏ hàng + checkout) Ghi (checkout TX, Order/OrderSeller/OrderItem): 300ms · Đọc (GET /v1/cart, catalog): 200ms (đề xuất SA dựa trên biên an toàn ~1,5× ngân sách QAS-003/QAS-006, ASM-27 mới) Ghi: 0 lần trong TX checkout (rely vào Idempotency-Key cho client tự retry) · Đọc: 1 lần, không backoff (đọc idempotent, lỗi transient thường qua ngay) Ghi: bảo vệ qua Idempotency-Key ở tầng API, không qua retry DB nội bộ · Đọc: có (SELECT) Ghi: rollback TX, trả 503, client tự retry · Đọc: fallback đọc từ Redis nếu có cache còn hạn (xem §4), nếu không → 503 GET /v1/cart lỗi → banner "Không tải được dữ liệu, thử lại" (E-CART-0004, AC-US002-03) · PATCH/DELETE lỗi → banner tại dòng "Không thể cập nhật giỏ hàng, thử lại" (E-CART-0006, AC-US003-09/10) · Checkout lỗi → xem FM-01 QAS-002, QAS-003, QAS-004, QAS-006
FM-07 RDS PostgreSQL Payment CMP-11 IF-017 Cao Ghi: 300ms · Đọc: 200ms (cùng cơ sở ASM-27) 0 lần cho ghi (bảo vệ bởi Idempotency-Key/gatewayTransactionRef, ADR-004); 1 lần cho đọc Ghi: có qua idempotency key tầng trên · Đọc: có Ghi lỗi → webhook trả lỗi cho VNPay/Momo (họ tự retry theo chính sách của họ, ARISK-03) hoặc job đối soát phát hiện sau ≤15 phút (ADR-004) Không ảnh hưởng trực tiếp UI khách (Payment DB tách biệt) — chỉ ảnh hưởng nếu Payment Service không phản hồi được IF-006 → xem FM-01/02 QAS-014
FM-08 ElastiCache Redis CMP-02, CMP-04 IF-015 Trung bình (cache, có fallback) 50ms (RESP protocol, cùng VPC — đề xuất SA, ASM-28 mới) 0 lần — lỗi/miss thì fallback thẳng sang DB ngay, không mất thời gian retry cache (retry cache chỉ tổ tốn thêm latency mà không tăng khả năng thành công trong cùng request) N/A (đọc key-value, không có hiệu ứng phụ khi gọi lại) Fallback query DB trực tiếp (ADR-007); nếu 5 lần liên tiếp lỗi trong 10s → "trip" tạm ngừng thử Redis 10s, đi thẳng DB (giảm overhead thử-rồi-fallback lặp lại) Không thấy gì nếu fallback DB kịp ngân sách; nếu DB cũng chậm → xem FM-06 QAS-003, QAS-004, QAS-010
FM-09 SQS FIFO (publish + consume) CMP-04, CMP-11 (publish) / CMP-05…10 (consume) IF-009 Trung bình (async, không chặn phản hồi checkout) Publish (SDK call): 2s (AWS SDK khuyến nghị) · Consume long-poll: 20s (chuẩn SQS) · Visibility timeout xử lý: 30s (đề xuất, ASM-29 mới — đủ cho consumer xử lý 1 event, cần Tech Lead xác nhận theo khối lượng xử lý thật mỗi consumer) Publish: theo AWS SDK default (retry tự động, exponential backoff, tối đa 3 lần) — không cấu hình thêm · Consume: SQS tự động redeliver sau visibility timeout hết hạn nếu consumer không DeleteMessage Có — MessageDeduplicationId = eventId, cửa sổ dedupe 5 phút (SQS FIFO native) + consumer tự upsert theo (orderSellerId, eventType) để chống trùng ngoài cửa sổ 5 phút (ICD §4) Publish thất bại liên tục → lỗi ném lên tầng gọi (Cart&Order/Payment), không chặn response đã trả cho khách (publish xảy ra sau khi đã trả response — xem SAD §6.1), nhưng cần alerting riêng (mất sự kiện OrderPlaced là sự cố nghiêm trọng) · Consume lỗi lặp ≥ ngưỡング maxReceiveCount (đề xuất 5 lần, OQ-036) → DLQ Không thấy gì trực tiếp (async) — hệ quả gián tiếp: hoa hồng/thông báo/tồn kho ở Nhóm Hỗ trợ bị trễ QAS-005, QAS-009
FM-10 EventBridge (fan-out ≥5 consumer) CMP-12 IF-009 Trung bình N/A (managed, không có "gọi" trực tiếp từ code — rule trigger tự động khi có message) Managed retry theo cấu hình rule (đề xuất: 3 lần, khoảng cách tăng dần theo AWS default) Kế thừa dedupe của IF-009 gốc (eventId) Rule retry hết → route sang DLQ riêng cho từng target rule (đề xuất mới — hiện SAD/ICD chỉ nói tới 1 DLQ cho SQS chính, chưa tính DLQ riêng cho từng consumer rule của EventBridge, ASM-30 mới) Không thấy gì (async) QAS-005
FM-11 Cart & Order → Payment Service CMP-04→CMP-11 IF-006 Cao nhất — đường găng checkout 600ms (đề xuất, phần "Payment Service xử lý nội bộ" trong ngân sách — xem §1.2 bảng cộng dồn; KHÔNG bao gồm thời gian gọi VNPay/Momo bên trong, xem FM-01/02) 0 lần (ngân sách không đủ chỗ cho retry; an toàn nhờ Idempotency-Key, client tự retry toàn bộ POST /v1/checkout nếu muốn) Có — Idempotency-Key gốc của POST /v1/checkout (ICD §3.3) Timeout/lỗi → rollback TX Order (chưa COMMIT, theo SAD §6.1), trả lỗi cho client "Không thể khởi tạo thanh toán, vui lòng thử lại" QAS-002
FM-12 Cart & Order → Promotion & Loyalty CMP-04→CMP-07 IF-021 Cao nhất — mới phát hiện cross-network ở v1.2, ưu tiên rà soát đầu tiên theo DEC-20 400ms (đề xuất, xem §1.2) 0 lần trong luồng checkout (ngân sách không đủ; retry ở đây là phản tác dụng — mỗi lần retry ăn hết phần ngân sách còn lại của bước sau) N/A (không ghi dữ liệu ở phía Cart&Order khi gọi; phía Promotion tự quản coupon usage) Circuit breaker mở (§3.1) → bỏ qua bước gọi hoàn toàn (không tốn cả 400ms) → áp dụng mặc định "không giảm giá", tiếp tục checkout — đây là đề xuất SA, chưa phải quyết định PO (xem §4, OQ-017 của BA vẫn mở) Nếu PO chọn "bỏ qua và tiếp tục": banner nhỏ "Không thể áp dụng mã giảm giá lúc này, đơn hàng vẫn được tạo theo giá gốc" · Nếu PO chọn "chặn": lỗi 503 "Không thể hoàn tất đơn hàng, vui lòng thử lại" QAS-002
FM-13 Cart & Order ↔ Seller Management CMP-04↔CMP-05 IF-022 Thấp (không trên đường găng checkout — chỉ gọi lúc thêm sản phẩm vào giỏ, theo denormalize ICD §3.7) 300ms (đề xuất, ngoài ngân sách checkout — chỉ áp dụng cho POST /v1/cart/items, ngoài phạm vi US-002/003) 1 lần, timeout ngắn (150ms) rồi bỏ qua — không chặn thêm giỏ hàng N/A (đọc sellerName, không side-effect) Fallback hiển thị sellerId thay sellerName (ICD §3.7), đánh dấu cần đồng bộ lại sau (batch job — chưa thiết kế) Tên seller hiển thị dạng mã (seller_11) thay vì tên thật, tạm thời —

🔴 Mọi retry ở bảng trên đều chỉ áp dụng cho thao tác idempotent (D6 — cột "Idempotent" phải điền trước khi quyết định "Retry"). Ba dòng có Retry = 0 trong luồng checkout đồng bộ (FM-01/02 init, FM-11, FM-12) không phải vì chúng "không đáng tin cậy" mà vì ngân sách QAS-002 không còn chỗ cho retry — trách nhiệm retry được chuyển sang người dùng (bấm "Thử lại"), an toàn nhờ Idempotency-Key xuyên suốt request gốc.

1.2 Ngân sách timeout cộng dồn — đường găng checkout (POST /v1/checkout, QAS-002 ≤ 3.000ms)

🔴 Sửa v1.1 (ADR-013, Proposed, hiện thực hoá Lựa chọn B của OQ-034/DEC-22): bảng dưới đây thay bảng "một đường găng duy nhất" của FAIL v1.0 (đã phát hiện vượt ngân sách 3.220ms > 3.000ms) bằng hai đường găng đồng bộ tách biệt theo phương thức thanh toán, đúng luồng mới ở SAD §6.1 v1.3. Bước "Payment Service → VNPay/Momo" (bước 8 cũ) không còn nằm trên đường găng đồng bộ — chuyển thành bất đồng bộ, xem chi tiết state machine/timeout/idempotency ở adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md §3. Chưa được Tech Lead/PO thật ký — ADR-013 đang Proposed.

Theo D6: "Ngân sách timeout tầng ngoài phải > tổng timeout tầng trong". Bảng dưới đây cộng dồn mọi bước đồng bộ trên đường găng theo đúng thứ tự SAD §6.1 v1.3.

Đường găng đồng bộ chung (mọi phương thức thanh toán, bước 1–6):

# Bước Thành phần Timeout đề xuất Cộng dồn Ghi chú
1 Client → ALB (network + TLS reuse) IF-001 150ms 150ms Đề xuất SA, phụ thuộc điều kiện mạng người dùng — chưa đo thật (ASM-31)
2 ALB → Cart & Order (routing) IF-002 20ms 170ms Overhead nội bộ VPC, thường < 20ms
3 Xác thực/ownership (cache hit, FM-08) IF-015 50ms 220ms Trường hợp cache hit (kỳ vọng phần lớn request)
4 Kiểm tra/giữ tồn kho (in-process) IF-005 (ngoài phạm vi FAIL — trong process) 150ms 370ms Không thuộc 13 phụ thuộc của tài liệu này, nhưng tính vào ngân sách vì cùng đường găng
5 Áp dụng coupon/điểm IF-021 (FM-12) 400ms 770ms Ưu tiên cao nhất — nếu circuit breaker mở, bước này = 0ms (bỏ qua hoàn toàn)
6 Ghi Order/OrderSeller/OrderItem (TX) + COMMIT ngay IF-016 (FM-06, ghi) 300ms 1.070ms (sửa v1.1) TX commit ngay sau bước này — không còn giữ mở xuyên bước 7/8 như v1.0, giảm trực tiếp rủi ro cạn pool đã nêu ở OQ-037/OQ-038

Nhánh COD — tiếp tục đồng bộ, không đổi (bước 7 + 10):

# Bước Thành phần Timeout đề xuất Cộng dồn Ghi chú
7 Xác nhận COD — xử lý nội bộ Payment Service (không gọi gateway ngoài) IF-006 (FM-11) 600ms 1.670ms Không đổi so với v1.0 — COD không phụ thuộc VNPay/Momo
10 Response serialization + trả về client — 50ms 1.720ms ✅ Trong ngân sách QAS-002 (≤3.000ms), dư ~1.280ms margin

Nhánh VNPay/Momo — dừng đường găng đồng bộ sớm hơn, bước 8 chuyển bất đồng bộ (sửa v1.1):

# Bước Thành phần Timeout đề xuất Cộng dồn Ghi chú
10 Response serialization + trả về client — trả orderId + status: PENDING_PAYMENT_INIT, chưa có redirectUrl — 50ms 1.120ms (tính từ bước 6 = 1.070ms) ✅ Trong ngân sách QAS-002 (≤3.000ms), dư ~1.880ms margin

(Bước 8 — Payment Service → VNPay/Momo — nay chạy sau khi đã trả response, xem bảng "Bất đồng bộ" dưới đây; bước 9 — publish event — không đổi bản chất, vẫn async, chỉ nay publish thêm message PaymentInitRequested cùng lúc với OrderPlaced cho nhánh online.)

Bất đồng bộ (sau khi đã trả response — không tính vào ngân sách QAS-002, chỉ áp dụng nhánh VNPay/Momo):

# Bước Thành phần Timeout đề xuất Ghi chú
8 Payment Service → VNPay/Momo (init) IF-007/IF-008 (FM-01/FM-02) 10s — kế thừa nguyên trạng CTX §4.2, không còn cần ép xuống 1.500ms như đề xuất tạm ở FAIL v1.0 vì không còn nằm trên đường găng phản hồi người dùng Timeout/lỗi → PAYMENT_INIT_FAILED, khách chọn thử lại hoặc chuyển COD (ADR-013 §3.3)
9 Commit TX + publish OrderPlaced/PaymentInitRequested IF-009 (FM-09) N/A (đã publish ngay sau bước 6, trước khi trả response — xem SAD §6.1 v1.3) Không cộng vào thời gian phản hồi người dùng

Kết luận (sửa v1.1): tổng đồng bộ nhánh COD = 1.720ms, nhánh VNPay/Momo = 1.120ms — cả hai đều ≤ 3.000ms (QAS-002, Must), không còn vượt ngân sách ~7% như v1.0. Đây vẫn là ước lượng dựa trên tính toán cộng dồn worst-case của các bước 1–6 (một số con số, ví dụ bước 1/3, chưa đo thật — ASM-27/28/31 — vẫn giữ nguyên như v1.0), nhưng nay margin còn lại (~1.280–1.880ms) đủ lớn để hấp thụ sai lệch của các giả định đó mà không cần phụ thuộc SLA đối tác ngoài (CON-04/ARISK-03). Điều kiện tiên quyết của kết luận này: ADR-013 (Proposed) được Tech Lead + PO thật xác nhận — nếu bị từ chối, FAIL cần quay lại bảng v1.0 (một đường găng, vượt ngân sách) và xét lại Lựa chọn A/C.

Hai lựa chọn đã trình Tech Lead/PO ở v1.0 (không tự quyết — D10) — nay đã chọn B, giữ lại để truy vết:

Lựa chọn Mô tả Hệ quả bằng số Trạng thái
A — Giữ đồng bộ, siết timeout hơn nữa Giảm timeout IF-007/008 xuống 1.200ms (thay 1.500ms) để tổng còn 2.920ms, có margin Rủi ro: nếu VNPay/Momo thật cần > 1.200ms để phản hồi (chưa có sandbox để biết, ARISK-03), tỷ lệ timeout/thất bại init thanh toán tăng — khách phải bấm "Thử lại", có thể tăng tỷ lệ bỏ giỏ hàng ở đúng bước cuối cùng (rủi ro nghiệp vụ, không có số đo thật để định lượng — không bịa tỷ lệ) Loại — xem ADR-013 §4
B — Bất đồng bộ hoá bước khởi tạo thanh toán Tạo Order ở trạng thái PENDING_PAYMENT_INIT trong ngân sách ~1.070ms (bước 1–6), trả response ngay cho client với orderId; gọi VNPay/Momo sau response (async), client poll/nhận kênh đẩy redirectUrl (cơ chế cụ thể chưa chốt — OQ-041) Đảm bảo QAS-002 luôn đạt bất kể VNPay/Momo chậm bao lâu; đổi lại đổi UX checkout — xem bảng ngân sách và luồng mới ở trên Đã chọn (DEC-22) — hiện thực hoá đầy đủ ở ADR-013 (Proposed) và bảng ngân sách trên
C — Giữ đồng bộ, chấp nhận vượt QAS-002 Không sửa gì, chấp nhận p95 lý thuyết 3.220ms Vi phạm trực tiếp một QAS Must — không phải lựa chọn hợp lệ để SA tự chấp nhận (D10) Loại — xem ADR-013 §2/§4 (bổ sung so với 2 lựa chọn đã trình ở v1.0, ghi nhận đầy đủ trong ADR-013 để không ai đề xuất lại mà không đọc lý do loại)

Chi tiết đầy đủ mô tả luồng, phương án bị loại, hệ quả, cách kiểm chứng: xem adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md.


2. Bốn câu hỏi cho mỗi phụ thuộc

Quy tắc D6. Rút gọn theo nhóm phụ thuộc tương tự để tránh lặp lại — tham chiếu FM-nn liên quan.

FM-01/FM-02 — VNPay / Momo

# Câu hỏi Trả lời
1 Nó chậm thì sao? Trong checkout: giữ transaction DB mở (bước 6–8 ở §1.2) → tốn 1 connection pool + có thể giữ lock trên Product/InventoryStock reserve trong tối đa ~2s — rủi ro cạn pool khi tải cao đồng thời nhiều checkout chậm cùng lúc (xem bulkhead §3.3, OQ-037). Trong job đối soát: chỉ làm chậm chu kỳ đối soát, không ảnh hưởng người dùng trực tiếp
2 Nó hỏng thì sao? Không degrade được cho phương thức VNPay/Momo cụ thể đó — checkout với phương thức đó thất bại hoàn toàn (rollback), nhưng COD vẫn hoạt động bình thường (không phụ thuộc FM-01/02) — đây là fallback tự nhiên của hệ thống, không cần thiết kế thêm
3 Nó trả sai dữ liệu thì sao? Webhook: chữ ký không hợp lệ → từ chối, không cập nhật Payment.status, ghi log cảnh báo bảo mật (khả năng giả mạo) — không coi là "lỗi hệ thống" thông thường. Init: response thiếu gatewayTransactionRef hoặc format sai → coi như lỗi (không accept), rollback TX, không đoán giá trị thiếu
4 Nó hồi phục thì sao? Không có retry storm phía ta (0 retry trong checkout); phía VNPay/Momo tự retry webhook theo chính sách của họ (chưa xác nhận, ARISK-03) — idempotency key (gatewayTransactionRef) đã chống được hiệu ứng phụ khi họ gọi lặp (ADR-004)

FM-03/FM-04 — GHN / GHTK

# Câu hỏi Trả lời
1 Nó chậm thì sao? Không chặn checkout (chạy async sau khi đơn đã xác nhận) — chỉ làm chậm thời điểm tạo vận đơn, không giữ tài nguyên lâu vì đây là job/consumer riêng, không giữ connection người dùng
2 Nó hỏng thì sao? GHN hỏng → tự động fallback GHTK (ASR-013); GHTK cũng hỏng → chuyển thủ công (OQ-039), không chết cả luồng đặt hàng (đơn vẫn tồn tại, chỉ chậm khâu vận chuyển)
3 Nó trả sai dữ liệu thì sao? Trạng thái vận đơn "thụt lùi" (VD từ "đang giao" về "đã tạo đơn") → không ghi đè, giữ trạng thái tiến bộ nhất đã ghi nhận, cảnh báo Ops kiểm tra thủ công (dữ liệu bất thường, không tự động tin tưởng bên ngoài)
4 Nó hồi phục thì sao? Cần "check-then-act" trước khi retry tạo waybill (tránh tạo trùng đơn vận chuyển) — 🔴 chưa xác nhận GHN/GHTK có API tra cứu theo mã đơn của ta hay không (ARISK-04), ghi OQ bổ sung nếu không có

FM-05 — Email/SMS Provider

# Câu hỏi Trả lời
1 Nó chậm thì sao? Không ảnh hưởng gì (consumer bất đồng bộ, không giữ tài nguyên người dùng)
2 Nó hỏng thì sao? Degrade hoàn toàn được — khách không nhận thông báo nhưng đơn hàng vẫn xử lý bình thường; ghi NotificationLog.status=failed để biết tồn đọng
3 Nó trả sai dữ liệu thì sao? Không áp dụng (one-way send, không có dữ liệu trả về cần validate ngoài mã trạng thái gửi)
4 Nó hồi phục thì sao? Không rủi ro storm (khối lượng thấp so với checkout); chấp nhận gửi trùng nếu retry, rủi ro thấp

FM-06/FM-07 — RDS chính / RDS Payment

# Câu hỏi Trả lời
1 Nó chậm thì sao? Nguy hiểm nhất trong toàn bộ 13 phụ thuộc — giữ connection pool, có thể lan ngược lên ALB (request xếp hàng), rồi lan lên toàn bộ Nhóm Giao dịch. Đây là lý do bulkhead (§3.3) tách pool theo module là bắt buộc, không phải "nên có"
2 Nó hỏng thì sao? Không degrade được cho ghi (checkout/PATCH/DELETE cần ACID) — trả lỗi 503 toàn bộ. Đọc (GET /v1/cart) có thể degrade một phần bằng Redis nếu cache còn hạn (xem §4)
3 Nó trả sai dữ liệu thì sao? Ứng dụng validate schema/kiểu dữ liệu trước khi dùng (không tin tưởng ngầm) — trường hợp dữ liệu logic sai (VD số âm, foreign key mồ côi) là lỗi ứng dụng cần fitness function riêng (GĐ3), không thuộc phạm vi FAIL
4 Nó hồi phục thì sao? Khi RDS phục hồi sau sự cố, tránh thundering herd bằng cách ECS Fargate health check + readiness probe kiểm soát tốc độ nhận lại traffic (không phải tất cả task cùng lúc đổ dồn query) — 🔴 cấu hình cụ thể thuộc hoạt động inf, chưa chạy

FM-08 — Redis

# Câu hỏi Trả lời
1 Nó chậm thì sao? Vì timeout rất ngắn (50ms) và không retry, tối đa chỉ tốn 50ms trước khi fallback DB — rủi ro thấp
2 Nó hỏng thì sao? Degrade hoàn toàn được — fallback query DB trực tiếp (ADR-007), tăng tải DB tạm thời (cần theo dõi để không lan thành FM-06)
3 Nó trả sai dữ liệu thì sao? Dữ liệu ownership cache cũ (stale) — giảm thiểu bằng TTL ngắn (~5 phút, đề xuất, chưa chốt — ICD §3.5) + invalidate chủ động khi giỏ hàng đổi chủ (hiếm)
4 Nó hồi phục thì sao? Cơ chế "trip" 10s sau 5 lỗi liên tiếp (đề xuất mới, ASM-32) tránh việc mọi request tiếp tục tốn 50ms thử Redis vô ích khi nó đang chắc chắn down

FM-09/FM-10 — SQS FIFO / EventBridge

# Câu hỏi Trả lời
1 Nó chậm thì sao? Không ảnh hưởng phản hồi checkout (publish xảy ra sau khi đã trả response) — chỉ làm trễ các consumer downstream (hoa hồng, thông báo, loyalty)
2 Nó hỏng thì sao? Publish thất bại liên tục → mất sự kiện OrderPlaced/PaymentConfirmed — sự cố nghiêm trọng (hoa hồng/thông báo không bao giờ được tạo) nếu không có alerting riêng cho publish failure (khác với alerting cho DLQ ở phía consumer) — đề xuất thêm alarm riêng, OQ-036
3 Nó trả sai dữ liệu thì sao? Consumer validate schema (eventVersion, field bắt buộc) trước khi xử lý — message không hợp lệ → route thẳng DLQ (poison message), không cố xử lý một phần
4 Nó hồi phục thì sao? Sau sự cố dài (SQS/EventBridge phục hồi), lượng message tồn đọng có thể gây fan-out burst tới 5 consumer cùng lúc — cần backpressure (giới hạn concurrency consumer, đề xuất max 10 message đồng thời/consumer, chưa xác nhận Tech Lead)

FM-11 — Cart & Order → Payment Service (IF-006)

# Câu hỏi Trả lời
1 Nó chậm thì sao? Giữ TX DB mở (xem §1.2 bước 6–8) — rủi ro giống FM-06 nếu tải cao; đây là lý do timeout phải chặt (600ms cho riêng xử lý nội bộ Payment, chưa tính VNPay/Momo)
2 Nó hỏng thì sao? Không degrade được — đây là bước bắt buộc để có gatewayTransactionRef; hỏng thì checkout thất bại toàn bộ, rollback
3 Nó trả sai dữ liệu thì sao? Response thiếu gatewayTransactionRef hoặc orderSellerId không khớp request → coi là lỗi, không accept một phần
4 Nó hồi phục thì sao? Không có storm (0 retry ở tầng này); client tự retry toàn bộ checkout nếu muốn, được bảo vệ bởi Idempotency-Key

FM-12 — Cart & Order → Promotion & Loyalty (IF-021)

# Câu hỏi Trả lời
1 Nó chậm thì sao? Đây là phụ thuộc mới phát hiện cross-network ở v1.2 (OQ-028) — ưu tiên cao nhất theo yêu cầu người duyệt. Chậm ăn trực tiếp vào 400ms ngân sách đã hẹp; do đặt trước bước ghi TX (§1.2 bước 5, trước bước 6) nên chưa giữ DB connection lúc này — rủi ro tài nguyên thấp hơn FM-06/11 nhưng rủi ro ngân sách thời gian cao nhất
2 Nó hỏng thì sao? Chưa chốt — phụ thuộc OQ-017 (BA, IMPACT_CartCheckout §1.5/§6): bỏ qua coupon và tiếp tục, hay chặn checkout hoàn toàn. SA đề xuất mặc định "bỏ qua và tiếp tục" (giảm rủi ro bỏ giỏ hàng ở bước cuối) nhưng đây là quyết định nghiệp vụ của PO, không phải kỹ thuật (D10) — xem §4
3 Nó trả sai dữ liệu thì sao? Validate bounds trước khi áp dụng: giá trị giảm giá phải ≥0 và ≤ tổng tiền đơn hàng — response vi phạm bounds bị từ chối, coi như lỗi (không áp dụng giảm giá âm hoặc giảm giá vượt quá tổng tiền)
4 Nó hồi phục thì sao? Circuit breaker (§3.1) tránh việc mọi checkout tiếp tục chờ 400ms vô ích khi Promotion&Loyalty chắc chắn đang down — mở circuit thì bỏ qua bước gọi hoàn toàn (0ms), không chỉ timeout nhanh hơn

FM-13 — Cart & Order ↔ Seller Management (IF-022)

# Câu hỏi Trả lời
1 Nó chậm thì sao? Không ảnh hưởng QAS-002/QAS-003 (ngoài đường găng checkout/GET cart, chỉ gọi lúc thêm giỏ)
2 Nó hỏng thì sao? Degrade hoàn toàn được — fallback hiển thị sellerId (ICD §3.7)
3 Nó trả sai dữ liệu thì sao? sellerName rỗng/null → coi như "không có", dùng fallback sellerId, không hiển thị chuỗi rỗng
4 Nó hồi phục thì sao? Không có storm (tần suất thấp, chỉ lúc thêm giỏ); không cần backpressure

3. Cơ chế chống lan lỗi

3.1 Circuit breaker

🔴 Toàn bộ ngưỡng dưới đây là đề xuất SA, chưa Tech Lead/SRE xác nhận — OQ-035. ADR-011 đã chốt "phải có chính sách chung" nhưng chưa cho số cụ thể; đây là nơi đề xuất số.

Áp dụng cho Ngưỡng mở Thời gian nửa mở Điều kiện đóng lại Hành vi khi mở
FM-01/FM-02 (init đồng bộ checkout) ≥50% lỗi trong 20 request gần nhất, hoặc 5 timeout liên tiếp trong 30s 30s, thử 1 request 3 lần thành công liên tiếp Trả lỗi ngay (không chờ hết 1.500ms) — "Không thể khởi tạo thanh toán, vui lòng chọn phương thức khác hoặc thử lại sau"
FM-03/FM-04 (GHN/GHTK) ≥30% lỗi trong 20 request/1 phút 60s, thử 1 request 3 lần thành công liên tiếp GHN mở → tự động dùng GHTK; GHTK cũng mở → AWAITING_MANUAL_FULFILLMENT (OQ-039)
FM-12 (IF-021 Promotion) ≥50% lỗi trong 10 request/30s 20s, thử 1 request 3 lần thành công liên tiếp Bỏ qua bước gọi hoàn toàn (0ms) → áp dụng mặc định theo quyết định PO ở OQ-017(BA)
FM-13 (IF-022 Seller) ≥50% lỗi trong 10 request/1 phút 30s 3 lần thành công Dùng sellerId fallback ngay, không thử gọi
FM-06/FM-07/FM-08/FM-09/FM-10 Không dùng circuit breaker truyền thống — dùng health check + bulkhead + backpressure (không thể "bỏ qua" DB/queue) — — Xem §3.3 và kịch bản §5

3.2 Backoff & jitter

Quyết định
Kiểu backoff Mũ (exponential), base × 2 mỗi lần
Có jitter không Bắt buộc có — jitter ngẫu nhiên ±20% trên mọi độ trễ backoff, tránh mọi client retry cùng lúc sau sự cố
Số lần tối đa Theo từng FM — xem bảng §1.1 (0 lần cho các bước đồng bộ trên đường găng checkout; 3 lần cho job/consumer bất đồng bộ)
Tổng thời gian tối đa Job đối soát: tối đa ~3,5s tổng cho 3 lần retry (500ms+1000ms+2000ms, có jitter) — vẫn nằm gọn trong chu kỳ ≤15 phút (QAS-014)

3.3 Bulkhead (tách pool tài nguyên)

Nhóm Pool riêng cho Kích thước Vì sao tách
RDS chính — ghi checkout Connection pool riêng cho Cart & Order (module ghi, đường găng) 🔴 Chưa chốt — cần DBA/Tech Lead xác nhận sau POC-02 (OQ-037) Một module đọc nặng (Catalog search) không được phép ăn hết pool khiến checkout (ghi) không có connection — đúng nguyên tắc "phụ thuộc nào giữ tài nguyên lâu hơn phải bị cô lập"
RDS chính — đọc (Catalog/Review/…) Connection pool riêng, tách khỏi pool ghi ở trên 🔴 Chưa chốt (OQ-037) Tương tự
Mỗi đối tác ngoài (VNPay/Momo/GHN/GHTK/Email-SMS) HTTP client pool/thread pool riêng theo adapter (ADR-011 — mỗi đối tác có adapter riêng) 🔴 Chưa chốt, đề xuất mặc định 20 connection/adapter (tham khảo, chưa đo tải thật) Một đối tác chậm (VD GHN nghẽn) không được rút cạn connection pool dùng chung, làm ảnh hưởng cả GHTK/VNPay/Momo
Redis Pool riêng cho ownership/session cache, tách khỏi bất kỳ cache khác trong tương lai (hiện chỉ có 1 loại) Theo cấu hình ElastiCache mặc định (chưa tối ưu — thuộc inf) Chuẩn bị cho tương lai khi có thêm loại cache khác (VD cache catalog)
SQS consumer Concurrency riêng theo từng trong 5 consumer (Commission, Promotion, Review, Notification, Shipping) Đề xuất max 10 message đồng thời/consumer (chưa xác nhận Tech Lead) Một consumer chậm (VD Shipping gọi GHN chậm) không được chặn 4 consumer còn lại xử lý message của chúng (SQS message riêng theo từng subscription, nhưng cấu hình concurrency sai có thể vẫn gây nghẽn nội bộ consumer đó)

4. Suy giảm có kiểm soát (graceful degradation)

Bốn tình huống theo yêu cầu người duyệt: Promotion lỗi lúc checkout, COD khi VNPay/Momo lỗi, GHN→GHTK fallback chéo, đọc giỏ từ Redis khi RDS chậm.

Thành phần hỏng Chức năng mất Chức năng vẫn chạy Người dùng thấy gì Ai quyết mức degrade
Promotion & Loyalty (FM-12, IF-021) Áp dụng mã giảm giá/điểm Toàn bộ checkout còn lại (tạo Order, thanh toán) Chưa chốt — SA đề xuất mặc định "bỏ qua, tiếp tục với giá gốc" + banner "Không thể áp dụng mã giảm giá lúc này". Phương án ngược (chặn checkout hoàn toàn khi Promotion lỗi): an toàn hơn về mặt "không để khách trả thiếu tiền do giảm giá tưởng đã áp dụng nhưng thực ra không", nhưng chặn toàn bộ đơn hàng chỉ vì một module phụ trợ lỗi — vi phạm nguyên tắc "phụ thuộc không nằm trên đường găng bắt buộc không nên chặn toàn luồng" PO (OQ-017 của BA, vẫn mở — SA không tự quyết theo D10)
VNPay/Momo (FM-01/02) Thanh toán online qua đúng cổng đang lỗi COD vẫn hoạt động đầy đủ (không phụ thuộc FM-01/02); nếu VNPay lỗi, khách vẫn chọn được Momo và ngược lại (không lỗi đồng thời cả hai theo giả định, ASM-33 mới) Banner tại bước chọn phương thức thanh toán: "VNPay hiện không khả dụng, vui lòng chọn phương thức khác" Không cần PO quyết — đây là fallback tự nhiên đã có sẵn trong thiết kế (nhiều phương thức thanh toán độc lập), không phải một quyết định degrade mới
GHN (FM-03) Tạo vận đơn qua GHN Tự động chuyển GHTK (ASR-013, đã là quyết định kiến trúc có sẵn, không phải degrade mới) Không thấy gì (async, sau khi đặt hàng) Đã quyết ở ASR-013/ADR-011 — không cần quyết lại ở đây
RDS chính chậm (FM-06, đọc) Đọc trực tiếp từ DB cho GET /v1/cart Đọc từ Redis nếu cache còn hạn (ownership/session — không phải cache toàn bộ nội dung giỏ hàng, vì Cart/CartItem hiện không được cache theo thiết kế ICD §3.5, chỉ cache session/ownership) 🔴 Giới hạn quan trọng: hiện tại không có cache cho nội dung giỏ hàng (chỉ có cache ownership/session) — nếu RDS chậm, GET /v1/cart không có fallback thật ngoài việc trả lỗi nhanh hơn (timeout 200ms thay vì chờ lâu). Đây là khoảng trống cần Tech Lead quyết định: có đáng để thêm cache nội dung giỏ hàng (đánh đổi độ tươi dữ liệu vs độ sẵn sàng) hay chấp nhận 503 khi RDS chậm Tech Lead — đây là quyết định kỹ thuật (thêm cache hay không), không phải nghiệp vụ thuần, nhưng ảnh hưởng trải nghiệm nên cần cả ý kiến PO nếu muốn đầu tư thêm

🔴 Phát hiện bổ sung: yêu cầu người duyệt "đọc giỏ từ Redis khi RDS chậm" giả định đã có cache nội dung giỏ hàng — nhưng theo thiết kế hiện tại (ICD §3.5), Redis chỉ cache session/ownership, không cache nội dung Cart/CartItem. Đây không phải lỗi của FAIL mà là khoảng trống thiết kế thật sự cần quyết định. Ghi OQ-040.


5. Ánh xạ mã lỗi trả người dùng

Theo AC_US-002/003_v1.0.md và ICD §1 (định dạng {error:{code,message,details}, traceId}).

FM Tình huống HTTP Mã lỗi AC tham chiếu Người dùng thấy gì
FM-06 (đọc, GET /v1/cart) RDS timeout/5xx 500/503 E-CART-0004 AC-US002-03 Banner "Không tải được dữ liệu, thử lại" + nút "Thử lại"
FM-06/FM-08 (ownership check lỗi kỹ thuật — không phải "không phải chủ sở hữu") Redis + DB đều lỗi khi kiểm tra ownership 503 (KHÔNG phải 403 — fail-closed, không mặc định cho phép khi không kiểm tra được) 🔴 Đề xuất mới E-CART-0007 (chưa có trong SRS/API của BA — OQ-040) (chưa có AC riêng — cần BA bổ sung) Banner lỗi chung, không phải "không có quyền" (tránh nhầm lẫn với 403 thật)
FM-06 (ownership xác định rõ không phải chủ) Kiểm tra thành công, kết quả = không phải chủ 403 E-CART-0005 AC-US003-12, AC-US003-13 (chờ OQ-032) Chuyển trang "Không có quyền"
FM-06 (ghi, PATCH/DELETE) RDS timeout/5xx khi cập nhật 500/503 E-CART-0006 AC-US003-09, AC-US003-10 Banner tại dòng "Không thể cập nhật giỏ hàng, thử lại"
FM-06 (item đã bị xoá đồng thời) 404/409 404/409 E-CART-0003 AC-US003-11 Banner "Sản phẩm này đã được xoá khỏi giỏ hàng trước đó"
FM-11/FM-01/FM-02 (checkout, khởi tạo thanh toán lỗi/timeout) Payment Service hoặc VNPay/Momo lỗi/timeout trong nhánh đồng bộ 503 🔴 Đề xuất mới E-CHECKOUT-0001 (chưa có AC/SRS cho US-004 Checkout trong input đã cung cấp — ICD §3.1.4 đã ghi nhận khoảng trống này) (chưa có — cần BA viết AC cho US-004) "Không thể khởi tạo thanh toán, vui lòng thử lại hoặc chọn phương thức khác"
FM-12 (IF-021 lỗi/circuit mở, PO chọn "bỏ qua") Promotion lỗi, tiếp tục checkout 201 (vẫn tạo Order) 🔴 Đề xuất W-CHECKOUT-0001 (warning, không phải error — đơn vẫn thành công) (chưa có — chờ OQ-017 BA) Banner nhỏ không chặn: "Không thể áp dụng mã giảm giá lúc này"
FM-12 (IF-021 lỗi/circuit mở, PO chọn "chặn") Promotion lỗi, chặn checkout 503 🔴 Đề xuất E-CHECKOUT-0002 (chưa có — chờ OQ-017 BA) "Không thể hoàn tất đơn hàng, vui lòng thử lại"
FM-05 (Email/SMS lỗi) Không gửi được thông báo N/A (không có response HTTP hướng tới khách) N/A N/A Không thấy gì (async, không chặn)
FM-03/FM-04 (GHN + GHTK đều lỗi) Không tạo được vận đơn N/A (không có response HTTP hướng tới khách — xảy ra sau khi đặt hàng) N/A N/A Không thấy gì trực tiếp; CSKH có thể chủ động liên hệ nếu SLA thủ công vượt ngưỡng (OQ-039)

🔴 Ba mã lỗi mới đề xuất (E-CART-0007, E-CHECKOUT-0001/0002, W-CHECKOUT-0001) chưa tồn tại trong API_US002-003/SRS của BA — vì phạm vi đó chỉ có US-002/003 (xem/sửa/xoá giỏ), không có US-004 (Checkout). Đây là khoảng trống thật, không phải lỗi bịa — cần BA viết AC/SRS cho US-004 và xác nhận các mã lỗi này (hoặc mã khác) trước khi Dev thi công. Ghi OQ-038.


6. Kịch bản hỏng toàn hệ thống

# Kịch bản Phát hiện bằng Sau bao lâu phát hiện Hệ quả Cách xử lý Runbook
1 Mất kết nối RDS chính (toàn bộ AZ hoặc instance chính) Health check ECS + CloudWatch Alarm (QAS-013: ≤1 phút) ≤1 phút (đề xuất, kế thừa QAS-013, chưa diễn tập — ADR-009) Toàn bộ Nhóm Giao dịch/Hỗ trợ trả 503 cho thao tác ghi/đọc cần DB; checkout, sửa giỏ, xem giỏ đều lỗi Failover Multi-AZ tự động (RDS); nếu failover không tự phục hồi trong RTO ≤1 giờ (ASR-010/ADR-009) → khôi phục từ backup PITR ⚠️ Chưa có runbook viết sẵn — thuộc hoạt động inf, chưa chạy
2 Hàng đợi SQS đầy / lag cao CloudWatch Alarm theo message age (đề xuất ngưỡng >5 phút, chưa xác nhận) 🔴 Chưa chốt ngưỡng cụ thể (OQ-036) Hoa hồng/thông báo/loyalty bị trễ, không ảnh hưởng checkout (publish đã xảy ra sau response) Tăng concurrency consumer tạm thời (nếu do consumer chậm) hoặc kiểm tra seller có volume bất thường chạm trần message group (ADR-005 §7) Chưa có — ứng viên GĐ3
3 Rò rỉ bộ nhớ, ECS task khởi động lại liên tục ECS health check fail liên tục + CloudWatch ≤1 phút (mục tiêu, chưa diễn tập) Giảm capacity phục vụ, có thể timeout tăng đột biến ở mọi FM phụ thuộc service đó Auto-scaling bù tạm số task; rollback về version trước nếu do deploy mới gây ra (xem #6) Chưa có — ứng viên GĐ3
4 Hệ thống ngoài trả 200 nhưng dữ liệu sai (VD VNPay xác nhận thành công nhưng số tiền không khớp) Job đối soát (ADR-004, ≤15 phút, QAS-014) — không phát hiện được ngay lập tức, chỉ phát hiện theo chu kỳ đối soát ≤15 phút (theo QAS-014, chưa xác nhận OQ-021) Rủi ro tài chính nếu không đối soát kịp thời — đây là lý do ADR-004 bắt buộc job đối soát, không chỉ dựa webhook Ghi ReconciliationLog, cảnh báo Tech Lead/CSKH, xử lý thủ công theo từng trường hợp lệch Chưa có — ứng viên GĐ3, phụ thuộc sandbox thật (ARISK-03)
5 Tăng tải đột biến ×10 (flash sale ngoài dự kiến) CloudWatch metrics (request rate, CPU) Theo chu kỳ scale (chưa chốt, thuộc inf) Tất cả timeout ở bảng §1.1 có nguy cơ chạm ngưỡng đồng thời — circuit breaker (§3.1) là tuyến phòng thủ chính để tránh sập dây chuyền Auto-scaling ECS Fargate (ngưỡng chưa chốt, QAS-009); nếu vượt kịch bản B ×2 (~20.000 concurrent) → ngoài phạm vi thiết kế hiện tại (SAD §10) Chưa có — ứng viên GĐ3
6 Deploy sai, phải rollback Theo dõi lỗi 5xx tăng đột biến sau deploy (QAS-013) ≤1 phút phát hiện, thời gian rollback chưa chốt Tuỳ mức độ lỗi — có thể ảnh hưởng toàn bộ hoặc một phần tuỳ chiến lược release Rollback theo chiến lược release (blue-green/canary — chưa chốt, thuộc INF §7, hoạt động inf chưa chạy) INF §7 (chưa tồn tại)

7. Dữ liệu trong lúc lỗi

Câu hỏi Trả lời
Giao dịch đang dở khi service chết ⇒ trạng thái nào còn lại Nếu chết trước COMMIT TX (giữa bước 6–8 ở §1.2): transaction tự động rollback khi connection đóng (hành vi chuẩn PostgreSQL) — không có Order mồ côi trong DB. Nếu chết sau COMMIT nhưng trước khi publish OrderPlaced thành công: Order tồn tại nhưng Nhóm Hỗ trợ không nhận được sự kiện — cần cơ chế phát hiện (🔴 chưa thiết kế: outbox pattern hoặc job quét Order không có OrderPlaced tương ứng sau N phút — ghi nhận khoảng trống, ứng viên DAT)
Ai dọn trạng thái nửa vời, sau bao lâu 🔴 Chưa có job dọn dẹp Order "kẹt" giữa COMMIT và publish — khoảng trống thiết kế, cần DAT/inf xử lý (đề xuất: job quét mỗi 5 phút, tìm Order có tuổi > 5 phút chưa có sự kiện OrderPlaced tương ứng trong log, publish lại — tương tự outbox pattern)
Message đã nhận nhưng chưa xử lý xong ⇒ mất hay xử lý lại SQS visibility timeout (đề xuất 30s, ASM-29) hết hạn mà chưa DeleteMessage → tự động redeliver, xử lý lại (at-least-once, đã có dedupe theo eventId + upsert theo khoá nghiệp vụ, ICD §4)
Poison message (xử lý mãi không được) ⇒ đi đâu DLQ riêng theo queue; thời gian giữ đề xuất 14 ngày (ASM-27 mới, chưa xác nhận — OQ-036); ai xử lý: SRE trực ban + Tech Lead của module consumer tương ứng (theo domain sự kiện, chưa phân công cụ thể tên người — thuộc inf)
Có mất dữ liệu nào chấp nhận được không Khớp RPO ≤15 phút (QAS-008/ADR-009) cho 3 service lõi (Payment, Cart&Order, Identity) — tối đa 15 phút giao dịch có thể mất nếu phải khôi phục từ backup thay vì failover AZ tức thời

8. Diễn tập — đề xuất FIT/bài đo cho GĐ3

🔴 Chưa diễn tập nào được thực hiện (đúng dự kiến ở GĐ2) — bảng dưới là ứng viên cho hoạt động sa-3-enablement. Các diễn tập cần sandbox đối tác ngoài (VNPay/Momo/GHN/GHTK) đều bị chặn bởi ARISK-03/04 (chưa có sandbox).

FM Cách diễn tập Môi trường Chặn bởi FIT ứng viên
FM-06 Chaos: dừng RDS chính (hoặc 1 AZ) giữa lúc có tải, đo thời gian phát hiện + hành vi 503 Staging Không chặn (không cần sandbox ngoài) FIT-16
FM-08 Chaos: chặn mạng tới Redis, xác nhận fallback DB hoạt động đúng và "trip" 10s kích hoạt Staging Không chặn FIT-17
FM-09 Gửi message payload sai schema, xác nhận route thẳng DLQ không cố xử lý Staging Không chặn FIT-18
FM-12 Giả lập IF-021 timeout liên tục, xác nhận circuit breaker mở đúng ngưỡng và bỏ qua bước gọi (đo lại tổng thời gian checkout giảm đúng ~400ms) Staging Không chặn FIT-19
FM-03/FM-04 Chặn mạng tới GHN, xác nhận tự động chuyển GHTK; sau đó chặn cả hai, xác nhận chuyển AWAITING_MANUAL_FULFILLMENT Staging (cần mock GHN/GHTK vì chưa có sandbox thật) 🔴 ARISK-04 (sandbox thật) — dùng mock trước, xác thực lại khi có sandbox FIT-20
FM-01/FM-02 Giả lập VNPay/Momo phản hồi chậm (>1.500ms), xác nhận timeout + rollback TX + không double-charge khi client tự retry Staging (mock, chưa có sandbox thật) 🔴 ARISK-03 FIT-21
§3.3 Bulkhead Chaos: saturate pool của 1 adapter (VD gọi GHN liên tục), xác nhận VNPay/Momo/GHTK/Email-SMS không bị ảnh hưởng Staging Không chặn FIT-22

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

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

ID Giả định Cách xác minh Nếu sai
ASM-27 Timeout RDS đề xuất (ghi 300ms/đọc 200ms) là hợp lý dựa trên biên an toàn ~1,5× ngân sách QAS-003/QAS-004/QAS-006 POC-02 (RDS gộp tải) + đo thật sau khi có kết quả Nếu POC-02 cho thấy latency thật cao hơn nhiều, timeout này quá chặt → tăng tỷ lệ lỗi giả (false timeout); cần điều chỉnh lại toàn bộ ngân sách §1.2
ASM-28 Redis (cùng VPC, ElastiCache) trả lời trong ≤50ms ở điều kiện bình thường Đo thật ở staging trước go-live Nếu chậm hơn đáng kể, ngân sách §1.2 bước 3 cần điều chỉnh, ảnh hưởng dây chuyền tới toàn bộ bảng cộng dồn
ASM-29 Visibility timeout 30s đủ cho mỗi consumer xử lý xong 1 event OrderPlaced/PaymentConfirmed Tech Lead xác nhận theo khối lượng xử lý thật của từng consumer (VD Commission&Payout có thể cần lâu hơn Notification) Nếu một consumer cần >30s, message bị redeliver trong khi vẫn đang xử lý → xử lý trùng nếu không idempotent đúng cách
ASM-30 Mỗi EventBridge rule (5 consumer) cần DLQ riêng, không dùng chung 1 DLQ với SQS chính Tech Lead/SRE xác nhận khi thiết kế inf Nếu dùng chung, khó xác định message lỗi thuộc consumer nào khi debug
ASM-31 Latency mạng client→ALB trung bình ~150ms là hợp lý cho thị trường Việt Nam (3G/4G/wifi hỗn hợp) Đo thật qua RUM (Real User Monitoring) sau go-live Nếu điều kiện mạng thực tế tệ hơn (VD vùng sâu vùng xa), ngân sách §1.2 càng thêm chật, cần xem lại Lựa chọn B (bất đồng bộ hoá)
ASM-32 Cơ chế "trip" Redis 10s sau 5 lỗi liên tiếp là hợp lý để tránh lãng phí 50ms thử vô ích mỗi request trong lúc Redis down Đo thật khi diễn tập FIT-17 Nếu Redis phục hồi nhanh hơn 10s thường xuyên, cơ chế trip có thể trì hoãn việc dùng lại cache không cần thiết — có thể rút ngắn xuống 5s
ASM-33 VNPay và Momo không cùng lúc gặp sự cố (fallback tự nhiên giữa hai phương thức online vẫn còn ít nhất một hoạt động) Theo dõi thực tế sau go-live; không có cách xác minh trước khi vận hành Nếu cả hai cùng lỗi (VD sự cố hạ tầng thanh toán quốc gia), chỉ còn COD hoạt động — cần cảnh báo riêng ("cả 2 cổng thanh toán online đang lỗi") thay vì coi là sự cố cục bộ một bên

Ngoài phạm vi:

  • Timeout/retry/circuit breaker chi tiết cho IF-005 (Catalog&Inventory, in-process) — không vượt ranh giới process nên ngoài phạm vi D6/tài liệu này theo đúng chỉ định phạm vi của người duyệt; lỗi in-process xử lý bằng exception handling thông thường ở tầng code, không cần timeout mạng.
  • Thiết kế outbox pattern đầy đủ cho vấn đề "Order commit nhưng publish thất bại" (§7) — chỉ ghi nhận khoảng trống, thiết kế chi tiết thuộc hoạt động dat (chưa chạy).
  • Số liệu định lượng ảnh hưởng tỷ lệ bỏ giỏ hàng/chuyển đổi khi siết timeout VNPay/Momo (Lựa chọn A ở §1.2) — không có dữ liệu thật, không bịa con số chuyển đổi; PO cần dùng kinh nghiệm nghiệp vụ hoặc dữ liệu thị trường riêng để quyết định.
  • Cấu hình hạ tầng thật cho auto-scaling, health check, blue-green/canary release — thuộc hoạt động inf (chưa chạy).
  • Chi tiết đầy đủ threat model cho các trường hợp "dữ liệu sai" liên quan bảo mật (VD giả mạo webhook) — thuộc hoạt động sec (chưa chạy); FAIL chỉ xử lý khía cạnh resilience/idempotency.

10. Open Questions

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

ID Câu hỏi Hỏi ai Từ ngày Chặn gì Hệ quả nếu trả lời ngược
OQ-034 Ngân sách timeout cộng dồn đường găng checkout vượt QAS-002 ~7% ngay cả khi siết timeout VNPay/Momo xuống 1.500ms (xem §1.2). Chọn Lựa chọn A (siết timeout hơn nữa, chấp nhận rủi ro thất bại init cao hơn nếu đối tác thật chậm) hay Lựa chọn B (bất đồng bộ hoá bước khởi tạo thanh toán, cần ADR mới sửa SAD §6.1)? Tech Lead + PO 2026-09-15 Thiết kế cuối cùng của IF-006/IF-007/IF-008 trong checkout; có thể cần ADR mới nếu chọn B Chọn A mà đối tác thật chậm hơn 1.200-1.500ms ở p95: tăng tỷ lệ lỗi init thanh toán, khách phải tự thử lại nhiều lần, rủi ro bỏ giỏ hàng (không định lượng được, không có số thật). Chọn B: đảm bảo QAS-002 nhưng đổi UX checkout (thêm bước chờ/poll), cần thiết kế lại FE + ADR mới
OQ-035 Xác nhận ngưỡng circuit breaker đề xuất ở §3.1 (mở/nửa mở/đóng) cho FM-01/02/03/04/12/13 — số cụ thể là đề xuất SA, chưa đo thật Tech Lead + SRE 2026-09-15 Cấu hình circuit breaker thi công; FIT-19/20/21 Ngưỡng quá chặt (mở sớm): giảm khả dụng không cần thiết khi đối tác chỉ chậm tạm thời. Ngưỡng quá lỏng (mở muộn): không bảo vệ được hệ thống khi đối tác thật sự down, tiếp tục lãng phí thời gian chờ
OQ-036 Thời gian giữ DLQ (đề xuất 14 ngày) cho SQS FIFO/EventBridge (FM-09/10) và ngưỡng cảnh báo lag hàng đợi (đề xuất >5 phút) là bao nhiêu? Ai xử lý message trong DLQ theo domain? Tech Lead + SRE 2026-09-15 Thiết kế inf (retention, alerting); vận hành GĐ3 Giữ quá ngắn: mất dữ liệu để debug/replay sự cố cũ. Giữ quá dài: tăng chi phí lưu trữ không cần thiết
OQ-037 Kích thước bulkhead (connection pool riêng) cho RDS chính theo module (ghi checkout vs đọc catalog) và cho từng adapter đối tác ngoài — số cụ thể phụ thuộc kết quả POC-02 chưa chạy DBA + Tech Lead 2026-09-15 Cấu hình pool thi công; khả năng chống nghẽn chéo module Pool quá nhỏ cho module ghi: nghẽn checkout khi tải cao dù DB tổng thể còn dư tải. Pool quá lớn: lãng phí connection, có thể vẫn dẫn tới cạn tổng connection của RDS instance
OQ-038 Giữ transaction DB mở xuyên suốt lời gọi đồng bộ IF-006/IF-007/008 (§1.2 bước 6–8) có chấp nhận được không, hay cần tách thành 2 bước riêng (tạo Order nháp trước, gọi Payment sau, không giữ TX mở qua network call)? Đồng thời xác nhận bộ mã lỗi mới đề xuất cho US-004 Checkout (E-CHECKOUT-0001/0002, W-CHECKOUT-0001, E-CART-0007) chưa có trong SRS/API của BA Tech Lead + BA 2026-09-15 Thiết kế transaction boundary của SAD §6.1; SRS/AC của US-004 (BA) Giữ nguyên TX mở: đơn giản hơn nhưng rủi ro cạn pool khi tải cao đồng thời nhiều checkout chậm (liên quan OQ-037). Tách 2 bước: phức tạp hơn (cần trạng thái "nháp" + dọn dẹp đơn nháp bị bỏ dở) nhưng an toàn hơn cho pool
OQ-039 SLA xử lý thủ công khi cả GHN và GHTK đều lỗi (FM-03/04, AWAITING_MANUAL_FULFILLMENT) là bao lâu? Ai (CSKH/Ops) chịu trách nhiệm theo dõi và xử lý? PO + Ops 2026-09-15 Runbook vận hành (inf, GĐ3); cam kết với khách hàng Không có SLA rõ ràng ⇒ đơn có thể bị "quên" ở trạng thái chờ tạo vận đơn vô thời hạn, ảnh hưởng trải nghiệm và uy tín sàn
OQ-040 Có cần thêm cache nội dung Cart/CartItem (không chỉ session/ownership) vào Redis để GET /v1/cart có fallback thật khi RDS chậm không (§4 — hiện không có fallback thật cho tình huống RDS chậm ở đọc nội dung giỏ hàng)? Đánh đổi: độ tươi dữ liệu (giá/tồn kho có thể lệch nếu cache) vs độ sẵn sàng. Đồng thời xác nhận mã lỗi E-CART-0007 cho trường hợp ownership check lỗi kỹ thuật (fail-closed, không phải 403 thật) Tech Lead 2026-09-15 Thiết kế DAT/inf (cache strategy); mã lỗi mới cho SRS (BA) Không thêm cache: GET /v1/cart không có gì cứu khi RDS chậm, trải nghiệm xấu đúng lúc tải cao (flash sale). Thêm cache: tăng độ phức tạp invalidate, rủi ro hiển thị giá/tồn kho cũ nếu TTL không hợp lý

Nhắc: cộng với các OQ còn mở ảnh hưởng trực tiếp FAIL — OQ-017 (BA, hành vi khi Promotion&Loyalty lỗi — SA đã đề xuất mặc định ở §4 nhưng không tự quyết, chờ PO), OQ-012 (POC-01, ảnh hưởng số thật của QAS-005/ngưỡng SQS ở FM-09), OQ-021 (tần suất đối soát, ảnh hưởng FM-01/02 job context), ARISK-03/04 (sandbox đối tác ngoài, chặn FIT-20/21) — xem sổ đầy đủ 00-index/OQ_e-commerce.md.


Tự chấm

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

# Tiêu chí ☐/✅ Ghi chú
— ASR/QAS/SAD/ICD ✅ (đã đạ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 ✅ (không đổi bởi FAIL) 12 ADR đã viết; FAIL không tạo quyết định đạt ngưỡng ADR mới — các con số đề xuất (timeout/circuit breaker) là tham số cấu hình, radar thấp (~2-3), đủ ghi OQ, không cần ADR
— DAT/SEC/INF ☐ Chưa tới — hoạt động 5, 6, 7
1 FAIL — mỗi phụ thuộc ra ngoài process có failure mode, timeout, retry, fallback ✅ Đủ 13/13 phụ thuộc theo phạm vi được giao (§1.1), mỗi cái đủ timeout/retry/idempotent/hết-retry-thì-sao, đủ 4 câu hỏi D6 (§2)
— sa-conformance báo coverage ASR → ADR/CMP ≥ 100% (không đổi bởi FAIL) FAIL không tạo CMP/ASR mới

Kết luận tự chấm (riêng phần FAIL): Hoạt động fail hoàn tất đúng phạm vi được giao — 13/13 phụ thuộc có bảng đầy đủ, 4 câu hỏi D6 cho từng cái, ngân sách timeout cộng dồn đường găng checkout đã tính toán và phát hiện vượt ngân sách ~7% (không giấu diếm, trình 2 lựa chọn kèm hệ quả bằng số ở OQ-034), ánh xạ mã lỗi đầy đủ theo AC/ICD (kèm 4 mã lỗi mới đề xuất, đánh dấu rõ chưa có trong SRS của BA). AG2 còn thiếu DAT/SEC/INF (hoạt động 5-7, chưa chạy) và chữ ký thật của Tech Lead + Security + Ops/SRE.

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

# Mục ☐/✅ Ghi chú
D1 Một ADR một quyết định N/A FAIL không viết ADR mới (các quyết định nền đã có ADR-004/005/007/009/011; đề xuất cấu hình mới trong FAIL chưa đạt ngưỡng radar cần ADR riêng — ghi OQ thay vì ADR)
D2 Không NFR định tính ✅ Mọi ngưỡng đều có con số (timeout ms, % lỗi, số lần retry) — không còn "nhanh"/"ổn định"
D3 Nêu phương án bị loại + lý do ✅ §1.2 nêu rõ 2 lựa chọn (A/B) kèm hệ quả; §3.1 lý giải vì sao không dùng circuit breaker truyền thống cho DB/queue
D4 Sơ đồ khai báo mức + legend N/A FAIL không có sơ đồ mới (chỉ bảng — đúng bản chất tài liệu này)
D5 Interface có chủ/contract N/A Đã xử lý ở ICD (hoạt động 4); FAIL chỉ bổ sung khía cạnh resilience
D6 Phụ thuộc ngoài process có timeout/retry + trả lời 4 câu hỏi ✅ Đủ 13/13, mỗi cái 4 câu hỏi ở §2, không bỏ câu nào (đặc biệt câu 1 "chậm thì sao" — bảng §1.2 chính là minh chứng chi tiết nhất)
D7 Một chủ sở hữu dữ liệu N/A Thuộc DAT (hoạt động 5); FAIL chỉ nhắc ReconciliationLog/NotificationLog cần DAT xác nhận
D8 Ràng buộc có FIT hoặc nhãn khuyến nghị 🟡 Một phần §8 đề xuất FIT-16…22 làm ứng viên GĐ3; 2/7 (FIT-20/21) đánh dấu rõ bị chặn bởi thiếu sandbox (ARISK-03/04), không giả vờ đã kiểm chứng
D9 Con số hạ tầng quy ra tiền + nguồn N/A FAIL không thêm con số hạ tầng mới (chi phí đã ở TCO)
D10 Không quyết định thay người có thẩm quyền ✅ §4 (Promotion lỗi), §1.2 (Lựa chọn A/B), §7 (đọc giỏ từ Redis) đều trình phương án kèm hệ quả, không tự quyết; OQ-017(BA) giữ nguyên là quyết định của PO
D11 Có mục "Ngoài phạm vi" + ASM-nn ✅ §9 đầy đủ — ASM-27…33 mới, mỗi cái có cách xác minh/hệ quả
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

BA Nội dung FAIL tương ứng Khớp? Hành động
IMPACT_CartCheckout §1.5 (VNPay/Momo lỗi/chậm → đơn giữ pending_payment, đối soát bù) Kế thừa nguyên trạng FM-01/02, §6 kịch bản 4, ADR-004 ✅ Không lệch — FAIL chi tiết hoá đúng hướng BA đã ghi
IMPACT_CartCheckout §1.5 (GHN/GHTK lỗi → phương án tĩnh, chưa PO/Tech Lead xác nhận) Chưa chốt FM-03/04, §4 🟡 Một phần FAIL không tự quyết phương án tĩnh — vẫn để BA/Tech Lead chốt, FAIL chỉ thiết kế fallback chéo GHN↔GHTK (đã có ASR-013)
IMPACT_CartCheckout §6 OQ-017 (Promotion lỗi — bỏ qua hay chặn) Chưa chốt, hỏi PO + Tech Lead §4, §1.1 FM-12 🟡 Một phần FAIL đề xuất mặc định "bỏ qua, tiếp tục" nhưng không tự quyết — đúng yêu cầu người duyệt "đề xuất degradation mặc định kèm OQ". BA/PO cần đóng OQ-017 chính thức, FAIL sẽ cập nhật khi có câu trả lời
AC_US-002_v1.0 (AC-US002-03/04, mã E-CART-0004) Timeout/5xx khi tải giỏ hàng FM-06, §5 ✅ Khớp hoàn toàn Không hành động thêm
AC_US-003_v1.0 (AC-US003-09/10/11/12/13, mã E-CART-0003/0005/0006) Lỗi hệ thống + phân quyền khi sửa/xoá FM-06, FM-08, §5 ✅ Khớp hoàn toàn, có bổ sung "fail-closed" cho trường hợp kiểm tra ownership tự lỗi (mã mới E-CART-0007, chưa có trong AC) BA cần bổ sung AC mới cho trường hợp Redis+DB đều lỗi khi kiểm tra ownership (khác với "đã xác định không phải chủ sở hữu") — hiện AC_US-003 chưa phân biệt hai trường hợp này
Không có AC/SRS cho US-004 (Checkout) trong input đã cung cấp — §5 (3 mã lỗi mới đề xuất) ❌ Khoảng trống thật BA cần viết AC/SRS cho US-004 — FAIL chỉ đề xuất mã lỗi tạm thời (E-CHECKOUT-0001/0002, W-CHECKOUT-0001) để không chặn thiết kế kỹ thuật, chưa phải chuẩn chính thức

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

Xem §10 (OQ-034…040 mới) — quan trọng nhất: OQ-034 (xung đột ngân sách timeout checkout, chặn thiết kế cuối cùng của IF-006/007/008, có thể cần ADR mới), OQ-038 (giữ TX mở xuyên network call + mã lỗi US-004 chưa có), OQ-040 (thiếu cache nội dung giỏ hàng cho fallback RDS chậm). Cộng OQ-017(BA, Promotion lỗi — vẫn là quyết định PO), ARISK-03/04 (chặn diễn tập với sandbox thật) — xem sổ đầy đủ 00-index/OQ_e-commerce.md.

Nhắc: AG2 cần Tech Lead + Security + Ops/SRE ký — còn thiếu DAT/SEC/INF (hoạt động 5-7, chưa chạy). FAIL này là input trực tiếp cho hoạt động inf (cấu hình timeout/circuit breaker/bulkhead thật, retention DLQ) và sec (fail-closed cho ownership check là quyết định bảo mật, cần Security xác nhận).