diff --git a/.claude/.claude_sa_ba.7z b/.claude/.claude_sa_ba.7z new file mode 100644 index 0000000..637980a Binary files /dev/null and b/.claude/.claude_sa_ba.7z differ diff --git a/.claude/workflows/ba-pipeline.js b/.claude/workflows/ba-pipeline.js index 0d98f1c..26415e9 100644 --- a/.claude/workflows/ba-pipeline.js +++ b/.claude/workflows/ba-pipeline.js @@ -146,7 +146,12 @@ if (stage === 'design') { else lines.push(`Brand guideline: không được cung cấp. Tự tìm theo thứ tự design/, brand/, prototype/, UICONV §0, SAD §7, DEC của Tech Lead về design system; vẫn không có ⇒ dùng token trung tính của template, ghi độ tin cậy 🔴 ở DS §0 + OQ, và nói rõ trong summary. Không tự chọn màu brand.`) lines.push(`Công cụ: runner không có Bash — tokens.css viết tay theo quy tắc --ds-<đường dẫn nối '-'>; phép kiểm design-check.mjs và chụp PNG (render-figma.sh) do người điều phối chạy sau, ghi vào humanInputNeeded nếu cần.`) } -if (a.answers) lines.push(`## Câu trả lời của người dùng cho OQ / humanInputNeeded vòng trước\n${a.answers}`) +if (a.answers) { + const ans = typeof a.answers === 'string' + ? a.answers + : Object.entries(a.answers).map(([k, v]) => `- **${k}**: ${typeof v === 'string' ? v : JSON.stringify(v)}`).join('\n') + lines.push(`## Câu trả lời của người dùng cho OQ / humanInputNeeded vòng trước\n${ans}`) +} if (a.notes) lines.push(`## Ghi chú từ người duyệt (bắt buộc xử lý trước, version +0.1 và Change Log)\n${a.notes}`) if (a.override) lines.push(`## Ngoại lệ gate\nNgười dùng đã được cảnh báo gate trước chưa ✅ Baselined và KHẲNG ĐỊNH LẠI muốn tiếp tục. Làm tiếp, ghi ngoại lệ vào Open Questions + DEC-nn của artifact.`) const common = lines.join('\n\n') diff --git a/.claude/workflows/sa-pipeline.js b/.claude/workflows/sa-pipeline.js index bf6c532..4bbfe62 100644 --- a/.claude/workflows/sa-pipeline.js +++ b/.claude/workflows/sa-pipeline.js @@ -129,7 +129,12 @@ lines.push(`Skill điều phối: ${skillsDir}/${TRACK.lifecycleSkill}/ (referen if (a.profile) lines.push(`Profile đã được người dùng xác nhận: ${Object.keys(a.profile).map((k) => `${k}=${a.profile[k]}`).join(' · ')}.`) else if (TRACK.profileFields.length) lines.push(`Profile: đọc ${root}/${TRACK.indexDir}/PROFILE_${project}.md; chưa có ⇒ dùng mặc định standard và NÓI RÕ điều đó.`) if (Array.isArray(a.inputs) && a.inputs.length) lines.push(`Input bổ sung do người dùng cung cấp (ưu tiên cao nhất):\n${a.inputs.map((i) => `- ${i}`).join('\n')}`) -if (a.answers) lines.push(`## Câu trả lời của người dùng cho OQ / humanInputNeeded vòng trước\n${a.answers}`) +if (a.answers) { + const ans = typeof a.answers === 'string' + ? a.answers + : Object.entries(a.answers).map(([k, v]) => `- **${k}**: ${typeof v === 'string' ? v : JSON.stringify(v)}`).join('\n') + lines.push(`## Câu trả lời của người dùng cho OQ / humanInputNeeded vòng trước\n${ans}`) +} if (a.notes) lines.push(`## Ghi chú từ người duyệt (bắt buộc xử lý trước, version +0.1 và Change Log)\n${a.notes}`) if (a.override) lines.push(`## Ngoại lệ gate\nNgười dùng đã được cảnh báo gate trước chưa ✅ Baselined và KHẲNG ĐỊNH LẠI muốn tiếp tục. Làm tiếp, ghi ngoại lệ vào Open Questions + DEC-nn của artifact.`) const common = lines.join('\n\n') diff --git a/sa-output/e-commerce/00-index/ADL_e-commerce.md b/sa-output/e-commerce/00-index/ADL_e-commerce.md index 5fa220e..75cafdf 100644 --- a/sa-output/e-commerce/00-index/ADL_e-commerce.md +++ b/sa-output/e-commerce/00-index/ADL_e-commerce.md @@ -2,13 +2,54 @@ | | | |---|---| -| **Cập nhật** | 2026-09-10 | -| **Author** | sa-lifecycle (khởi tạo — khung rỗng, chưa có ADR nào) | -| **Tổng số ADR** | 0 | -| **Nguồn quét** | `02-architecture/adr/` *(chưa tồn tại — sẽ tạo khi ADR đầu tiên được sinh ở sa-2-architecture)* | +| **Cập nhật** | 2026-09-15 | +| **Author** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) — cập nhật sổ sau khi viết `ADR-014`/`ADR-015`/`ADR-016`/`ADR-017` (`DEC-31`), trả hết 4 khoản nợ ADR còn treo từ `DEC-25`/`DEC-28`/`DEC-30`; `sa-conformance` nên đối chiếu lại ở lần đồng bộ kế tiếp | +| **Tổng số ADR** | 17 *(mới — thêm `ADR-014`/`ADR-015`/`ADR-016`/`ADR-017`, không còn ADR nào "nợ chưa viết")* | +| **Nguồn quét** | `02-architecture/adr/ADR-001…017_*.md` (đọc header thật của từng file) · `00-index/DEC_e-commerce.md` v1.29 (đối chiếu §7 dưới đây) | > Sổ này là **mục lục**, không phải nơi chứa nội dung quyết định. Nội dung ở từng file ADR. -> Khung khởi tạo — sẽ được `sa-conformance` cập nhật sau mỗi giai đoạn. +> Cập nhật lần trước (12 ADR, 2026-09-15): tất cả ở `Proposed` — không ADR nào `Accepted` vì +> chưa có chữ ký thật (Tech Lead + Security + Ops/SRE) và 3 ADR (`ADR-005`/`ADR-006`/`ADR-009`) +> có radar ≥8 nên **bắt buộc** POC/diễn tập PASS trước khi `Accepted`, hiện chưa chạy. `DEC-06` +> (chọn P2, GĐ1) đã được **trả nợ** bằng `ADR-001` ở lượt đó. +> Cập nhật kế tiếp: thêm `ADR-013` (bất đồng bộ hoá bước khởi tạo thanh toán, radar 7/10, +> `Proposed`) — hiện thực hoá Lựa chọn B đã chọn ở `OQ-034`/`DEC-22`. Dưới ngưỡng 8 nên không bắt +> buộc POC trước `Accepted`, nhưng cần Tech Lead + PO **thật** xác nhận. Không đổi 12 ADR cũ. +> **Cập nhật lần này (2026-09-15, `DEC-26`):** `ADR-013` được **review nội dung** (không phải +> "sign" gate) — chấp nhận §3 làm cơ sở thiết kế tiếp, **giữ nguyên `Proposed`**, ghi dòng +> "Reviewed (Proposed giữ nguyên)" ở `ADR-013 §9`, cùng mẫu 12 ADR trước. Không đổi Status của +> `ADR-013` hay 12 ADR cũ. Cũng ghi nhận `DAT_e-commerce_v1.0.md` (hoạt động 5) đã được duyệt +> từng phần (`DEC-25`) và chọn Transactional Outbox cho `OQ-044` — **còn nợ `ADR-014`** (`Proposed`) +> ở lượt hoạt động `adr` kế tiếp (chưa viết, ngoài phạm vi cập nhật sổ lần này). +> **Cập nhật kế tiếp (2026-09-15, `DEC-28`):** `SEC_e-commerce_v1.0.md` (hoạt động 6) đã được +> duyệt từng phần bởi Tech Lead (ký thay, ngoại lệ `DEC-01`) — ghi nhận nội dung threat model/ +> authn/authz, **không có `ADR` nào được viết** trong lượt `sec`. Chốt TẠM `OQ-050`: chọn **PA-3** +> (service JWT ngắn hạn ký bởi Identity & Access) cho service-to-service authn TB3/TB4 — **còn nợ +> `ADR-015`** (`Proposed`) ở lượt hoạt động `adr` kế tiếp, **cùng lúc** với `ADR-014` đã nợ từ +> `DEC-25`. Tổng số nợ ADR hiện tại: 2 (`ADR-014`, `ADR-015`). Security **không** ký thay — `SEC` +> chưa có hiệu lực phủ quyết `ADR-002`/`ADR-007`/`ADR-008` (bảo mật) cho tới khi có người (`OQ-007`). +> Không đổi 13 ADR hiện có. +> **Cập nhật kế tiếp (2026-09-15, `DEC-31`):** SA viết đủ 4 `ADR` còn nợ — `ADR-014` +> (Transactional Outbox, radar 6/10, nguồn `DAT §4.1`/`OQ-044`), `ADR-015` (Service JWT ngắn hạn +> service-to-service, radar 5/10, nguồn `SEC §2.4`/`OQ-050`), `ADR-016` (Blue-green qua AWS +> CodeDeploy cho 3 dịch vụ ECS, radar 6/10, nguồn `INF §7.2`), `ADR-017` (IaC Terraform, radar +> 7/10, nguồn `INF §11`). **Tất cả 4 `ADR` giữ `Status Proposed`** — không cái nào `Accepted`. +> Không cái nào đạt radar ≥8 nên không bắt buộc POC, nhưng mỗi ADR ghi rõ điều kiện `Accepted` +> riêng (Tech Lead/Ops-SRE xác nhận + bài đo `FIT`). 🔴 **`ADR-015` có điều kiện chặn cứng nhất**: +> đây là quyết định bảo mật (Security chốt theo `decision-radar.md §5`), nhưng Security **chưa có +> người** (`OQ-007`) — `ADR-015` không thể chuyển `Accepted` bất kể Tech Lead có đồng ý hay không. +> Tổng số ADR nay là **17**, không còn khoản nợ nào treo. Đã link cả 4 ADR vào `DAT`/`SEC`/`INF` +> (mỗi file +0.1, chỉ link không đổi nội dung). Không đổi 13 ADR cũ. + +## Change Log (Review — không đổi Status) + +| Ngày | Người review | Vai trò | Việc | Ghi chú | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `approve` yêu cầu ở mức **ghi nhận nội dung**, không phải baseline/accept | Ghi nhận 12 `ADR` (`ADR-001..012`, `02-architecture/adr/`) được chấp nhận về **NỘI DUNG** làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`). **KHÔNG** đề nghị chuyển bất kỳ `ADR` nào sang `Accepted` — tất cả giữ `Proposed` vì: (1) chưa có chữ ký thật Tech Lead/Security; (2) `POC-01`/`POC-02` chưa chạy (`ADR-005`/`ADR-006`); (3) diễn tập DR chưa chạy (`ADR-009`); (4) Security/Legal chưa có người được chỉ định (`ADR-002`/`ADR-007`/`ADR-008`); (5) `OQ-010`/`OQ-011`/`OQ-026` còn mở (`ADR-001`/`ADR-003`/`ADR-012`). Ký thay theo ngoại lệ `DEC-01` (SA). **Confidence: 🔴**. `AG2` chưa ký. Mỗi ADR đã được ghi một dòng "Reviewed (Proposed giữ nguyên)" ở `§9 Review log` riêng của file đó (xem `02-architecture/adr/ADR-001..012_*.md §9`). | +| 2026-09-15 | SA (qua skill `sa-2-architecture`, hoạt động `adr`, phạm vi hẹp) | SA (viết, không phải ký) | Ghi mới `ADR-013` vào sổ | `ADR-013` (bất đồng bộ hoá bước khởi tạo thanh toán, radar 7/10, `Proposed`) hiện thực hoá Lựa chọn B đã chọn ở `OQ-034`/`DEC-22`. **Chưa ai ký thật** — Tech Lead + PO thật cần xác nhận trước `Accepted` (xem `ADR-013 §7`). Không đổi Status của 12 `ADR` cũ. | +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `approve` yêu cầu ở mức **ghi nhận nội dung**, không phải baseline/accept | Ghi nhận `ADR-013` được chấp nhận về **NỘI DUNG** (state machine, timeout async 10s, idempotency, hành vi thất bại) làm cơ sở thiết kế tiếp (`ICD`/`DAT`/FE). **KHÔNG** đề nghị chuyển sang `Accepted` — giữ `Proposed` vì chưa có Tech Lead + PO thật xác nhận (`OQ-034`), BA chưa viết `SRS`/`AC` US-004. Ghi Review log "Reviewed (Proposed giữ nguyên)" như 12 `ADR` trước (`ADR-013 §9`). Ký thay theo ngoại lệ `DEC-01` (SA). **Confidence: 🔴**. `AG2` chưa ký. Ghi thêm `DEC-26`. | +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `approve` yêu cầu ở mức **ghi nhận nội dung** trên `SEC_e-commerce_v1.0.md` — không có `ADR` nào để ký ở lượt này | Không có `ADR` nào được viết/ký trong hoạt động `sec` — chỉ ghi nhận **1 `ADR` ứng viên mới** (service-to-service authn, PA-3, radar ~5) mà `SEC §2.4` phát hiện, chưa viết. Chốt TẠM hướng PA-3 làm baseline cho lượt viết `ADR-015` kế tiếp — **không tự viết/ký `ADR` ngay** vì ngoài phạm vi hoạt động `sec` được giao. **KHÔNG** ký thay Security — `SEC` chưa có hiệu lực phủ quyết `ADR-002`/`ADR-007`/`ADR-008` cho tới khi có người (`OQ-007`). Ghi thêm `DEC-28`. **Confidence: 🔴**. `AG2` chưa ký. | +| 2026-09-15 | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | SA (viết, không phải ký) | Ghi mới `ADR-014`/`ADR-015`/`ADR-016`/`ADR-017` vào sổ | Bốn `ADR` còn nợ đã được viết đủ: `ADR-014` (Transactional Outbox, radar 6/10, `DEC-25`), `ADR-015` (Service JWT service-to-service, radar 5/10, `DEC-28` — **`Accepted` chặn cứng bởi `OQ-007`, Security chưa có người**), `ADR-016` (Blue-green CodeDeploy, radar 6/10, `DEC-30`), `ADR-017` (IaC Terraform, radar 7/10, `DEC-30`). **Chưa ai ký thật** — tất cả giữ `Proposed`. Không đổi Status của 13 ADR cũ. Ghi `DEC-31`. | --- @@ -16,7 +57,7 @@ | Trạng thái | Số lượng | |---|---| -| `Proposed` | 0 | +| `Proposed` | 17 | | `Accepted` | 0 | | `Rejected` | 0 | | `Superseded` | 0 | @@ -24,9 +65,9 @@ | Cảnh báo | Số lượng | |---|---| -| `Proposed` quá 10 ngày | 0 | -| Điểm radar ≥ 8 mà `Accepted` không có POC | 0 | -| Nguồn (`QAS`/`ASR`) đã đổi sau khi ADR được ký | 0 | +| `Proposed` quá 10 ngày | 0 *(mới sinh 2026-09-15, kể cả `ADR-013…017`)* | +| Điểm radar ≥ 8 mà `Accepted` không có POC | 0 *(3 ADR radar ≥8 đều đang giữ `Proposed`, đúng quy tắc — xem §4.3; `ADR-013…017` radar 5–7, dưới ngưỡng)* | +| Nguồn (`QAS`/`ASR`) đã đổi sau khi ADR được ký | 0 *(chưa ADR nào được ký)* | | Chuỗi supersede gãy | 0 | | **Hai ADR mâu thuẫn** | 0 | @@ -34,6 +75,23 @@ | ID | Quyết định | Chủ đề | Status | Ngày | Người quyết | Radar | POC | Nguồn | Supersedes | Superseded by | |---|---|---|---|---|---|---|---|---|---|---| +| `ADR-001` | Kiểu kiến trúc tổng thể — Modular Monolith P2, không phải Microservices P1 | Cấu trúc | `Proposed` | 2026-09-15 | SA + Tech Lead *(chưa ký thật)* | 7 | Cần `POC-01`+`POC-02` | `ASR-001`, `DEC-06` | — | — | +| `ADR-002` | Payment Service — biên cô lập PCI-DSS SAQ A | Bảo mật | `Proposed` | 2026-09-15 | Security *(chưa có người)* | 7 | Không bắt buộc (pháp lý) | `ASR-002`, `CON-06` | — | — | +| `ADR-003` | Mô hình `Order`/`OrderSeller` — tách đơn theo seller | Dữ liệu | `Proposed` | 2026-09-15 | SA + Tech Lead | 6 | Không — chờ `OQ-011` (BA) | `ASR-003`, `BR-CART-01` | — | — | +| `ADR-004` | Idempotency + đối soát bù cho webhook thanh toán | Tích hợp | `Proposed` | 2026-09-15 | SA + Tech Lead | 6 | Không bắt buộc — cần sandbox | `ASR-004`, `BR-CART-06` | — | — | +| `ADR-005` | Message backbone — SQS FIFO + EventBridge | Tích hợp | `Proposed` | 2026-09-15 | SA + Tech Lead | **8** | **Bắt buộc `POC-01` — chưa chạy** | `ASR-005`, `QAS-005` | — | — | +| `ADR-006` | Chiến lược dữ liệu — RDS gộp schema-per-module | Dữ liệu | `Proposed` | 2026-09-15 | SA + Tech Lead/DBA | **8** | **Bắt buộc `POC-02` — chưa chạy** | `ASR-006`, `QAS-006` | — | — | +| `ADR-007` | Chỗ ra quyết định ownership/authz Cart & Order — service + cache Redis | Bảo mật | `Proposed` | 2026-09-15 | SA + Tech Lead | 6 | Không bắt buộc — khuyến nghị đo | `ASR-007`, `QAS-010` | — | — | +| `ADR-008` | Vùng lưu trữ PII & chính sách chia sẻ cho seller | Bảo mật | `Proposed` | 2026-09-15 | Security/Legal *(chưa có người — `OQ-007`)* | 7 | Không — chặn hoàn toàn tới khi có người | `ASR-008`, `QAS-011` | — | — | +| `ADR-009` | Chiến lược HA/DR cho nhóm dịch vụ giao dịch lõi | Hạ tầng | `Proposed` | 2026-09-15 | SA + Ops/SRE | **9** | **Bắt buộc diễn tập DR — chưa chạy** | `ASR-010`, `QAS-008` | — | — | +| `ADR-010` | Kiến trúc observability & alerting | Hạ tầng | `Proposed` | 2026-09-15 | SA + Ops/SRE | 6 | Không bắt buộc — khuyến nghị diễn tập | `ASR-011`, `QAS-013` | — | — | +| `ADR-011` | Chính sách resilience đối tác thanh toán/vận chuyển ngoài | Tích hợp | `Proposed` | 2026-09-15 | SA + Tech Lead | 6 | Không bắt buộc — cần sandbox | `ASR-013` | — | — | +| `ADR-012` | Ranh giới nhóm triển khai theo domain và năng lực đội | Cấu trúc | `Proposed` | 2026-09-15 | SA + Tech Lead | 7 | Không — chờ `OQ-010`/`OQ-026`/`OQ-027` | `ASR-014` | — | — | +| `ADR-013` | Bất đồng bộ hoá bước khởi tạo thanh toán trong checkout (Lựa chọn B của `OQ-034`) | Tích hợp | `Proposed` | 2026-09-15 | Tech Lead + PO *(chưa ký thật)* | 7 | Không bắt buộc (dưới ngưỡng 8) — khuyến nghị `FIT-23` (chaos đo p95) trước go-live | `ASR-004`, `QAS-002`, `DRV-02`, `OQ-034`, `DEC-22` | — | — | +| `ADR-014` | Transactional Outbox cho publish sự kiện Cart & Order / Payment | Tích hợp | `Proposed` | 2026-09-15 | SA + Tech Lead *(chưa ký thật)* | 6 | Không bắt buộc (dưới ngưỡng 8) — khuyến nghị bài đo relay lag (`FIT-26/27`) trước `Accepted` | `ASR-004`, `ASR-005`, `QAS-005`, `DRV-08`, `OQ-044`, `DEC-25` | — | — | +| `ADR-015` | Xác thực service-to-service bằng Service JWT ngắn hạn | Bảo mật | `Proposed` | 2026-09-15 | Security *(chưa có người — `OQ-007`)* + Tech Lead | 5 | Không bắt buộc — nhưng **`Accepted` chặn cứng tới khi có Security thật ký** | `ASR-002`, `ASR-007`, `QAS-002`, `QAS-010`, `THR-09`, `THR-13`, `OQ-050`, `DEC-28` | — | — | +| `ADR-016` | Chiến lược triển khai Blue-Green qua AWS CodeDeploy cho 3 dịch vụ ECS | Hạ tầng | `Proposed` | 2026-09-15 | SA + Ops/SRE *(chưa ký thật)* | 6 | Không bắt buộc — khuyến nghị chạy thử blue-green/rollback ở staging trước `Accepted` | `QAS-007`, `ASR-011`, `OQ-020`, `OQ-056`, `DEC-30` | — | — | +| `ADR-017` | Công cụ Infrastructure as Code — Terraform | Hạ tầng | `Proposed` | 2026-09-15 | Tech Lead + Ops/SRE *(chưa ký thật)* | 7 | Không bắt buộc (dưới ngưỡng 8) | `CON-05`, `OQ-060`, `DEC-30` | — | — | **Chủ đề** *(dùng để rà mâu thuẫn — rà theo chủ đề, không theo số thứ tự)*: cấu trúc · dữ liệu · tích hợp · bảo mật · hạ tầng · frontend · vận hành @@ -44,26 +102,43 @@ tích hợp · bảo mật · hạ tầng · frontend · vận hành | `ADR` | Quyết định | Status | Có mâu thuẫn với | |---|---|---|---| +| `ADR-001` | Modular Monolith P2 | `Proposed` | Không | +| `ADR-012` | Ranh giới nhóm triển khai (Nhóm Giao dịch/Nhóm Hỗ trợ) | `Proposed` | Không — mở rộng `ADR-001`, không mâu thuẫn | ### Dữ liệu | `ADR` | Quyết định | Status | Có mâu thuẫn với | |---|---|---|---| +| `ADR-003` | `Order`/`OrderSeller` | `Proposed` | Không | +| `ADR-006` | RDS gộp schema-per-module | `Proposed` | Không | ### Tích hợp | `ADR` | Quyết định | Status | Có mâu thuẫn với | |---|---|---|---| +| `ADR-004` | Idempotency + đối soát webhook | `Proposed` | Không | +| `ADR-005` | SQS FIFO + EventBridge | `Proposed` | Không | +| `ADR-011` | Resilience đối tác ngoài | `Proposed` | Không | +| `ADR-013` | Bất đồng bộ hoá khởi tạo thanh toán | `Proposed` | Không — mở rộng `ADR-004`/`ADR-005`/`ADR-011` (tái dùng idempotency + message backbone + resilience đối tác đã có), không mâu thuẫn | +| `ADR-014` | Transactional Outbox cho publish sự kiện | `Proposed` | Không — mở rộng `ADR-005`/`ADR-013` (đảm bảo publish nguyên tử cho các sự kiện đã chọn ở hai ADR đó), không mâu thuẫn | ### Bảo mật | `ADR` | Quyết định | Status | Có mâu thuẫn với | |---|---|---|---| +| `ADR-002` | Payment cô lập PCI-DSS | `Proposed` | Không | +| `ADR-007` | Ownership/authz Cart & Order | `Proposed` | Không | +| `ADR-008` | Vùng lưu trữ PII | `Proposed` | Không | +| `ADR-015` | Service JWT service-to-service | `Proposed` | Không — bổ sung một lớp phòng thủ cho TB3/TB4, không thay đổi mô hình authn/authz người dùng cuối đã có ở `ADR-007` | ### Hạ tầng & vận hành | `ADR` | Quyết định | Status | Có mâu thuẫn với | |---|---|---|---| +| `ADR-009` | HA/DR nhóm giao dịch lõi | `Proposed` | Không | +| `ADR-010` | Observability & alerting | `Proposed` | Không | +| `ADR-016` | Blue-green deploy qua AWS CodeDeploy | `Proposed` | Không | +| `ADR-017` | IaC — Terraform | `Proposed` | Không | ## 4. Năm kiểm tra @@ -71,48 +146,125 @@ tích hợp · bảo mật · hạ tầng · frontend · vận hành | `ADR` cũ | Ghi `Superseded by` | `ADR` mới | Ghi `Supersedes` ngược lại | Khớp | |---|---|---|---|---| +| *(không có — 12 ADR đều mới, chưa ADR nào bị supersede)* | | | | | ### 4.2 `Proposed` quá hạn | `ADR` | Đề xuất ngày | Số ngày treo | Ai phải quyết | Đang chặn gì | |---|---|---|---|---| +| *(chưa quá hạn — tất cả đề xuất 2026-09-15, cần theo dõi từ lần đồng bộ sau: > 10 ngày ⇒ cảnh báo)* | | | | | ### 4.3 Điểm radar ≥ 8 chưa có POC | `ADR` | Radar | Status | POC | Vi phạm | |---|---|---|---|---| +| `ADR-005` | 8 | `Proposed` | `POC-01` chưa chạy | Không vi phạm — đúng quy tắc (giữ `Proposed`, chưa `Accepted`) | +| `ADR-006` | 8 | `Proposed` | `POC-02` chưa chạy | Không vi phạm — đúng quy tắc | +| `ADR-009` | 9 | `Proposed` | Diễn tập DR chưa chạy | Không vi phạm — đúng quy tắc, cũng là điều kiện tiên quyết AG2 | +| `ADR-013` | 7 | `Proposed` | *(không áp dụng — dưới ngưỡng 8, POC không bắt buộc)* | Không vi phạm — radar 7 chỉ cần Tech Lead + PO thật xác nhận trước `Accepted`, không bắt buộc POC (`decision-radar.md §2/§6`) | +| `ADR-014` | 6 | `Proposed` | *(không áp dụng — dưới ngưỡng 8)* | Không vi phạm — khuyến nghị bài đo relay lag (`FIT-26/27`) trước `Accepted`, không bắt buộc POC | +| `ADR-015` | 5 | `Proposed` | *(không áp dụng — dưới ngưỡng 8)* | Không vi phạm — nhưng `Accepted` bị **chặn cứng bởi `OQ-007`** (Security chưa có người), độc lập với ngưỡng radar | +| `ADR-016` | 6 | `Proposed` | *(không áp dụng — dưới ngưỡng 8)* | Không vi phạm — khuyến nghị chạy thử blue-green/rollback ở staging trước `Accepted` | +| `ADR-017` | 7 | `Proposed` | *(không áp dụng — dưới ngưỡng 8)* | Không vi phạm — cần Tech Lead + Ops/SRE xác nhận công cụ trước `Accepted` | ### 4.4 Nguồn đã đổi | `ADR` | Dựa trên | Nguồn đó đã đổi | Quyết định còn đúng không | |---|---|---|---| +| *(chưa phát hiện — `ASR`/`QAS` nguồn chưa đổi kể từ khi 12 ADR này được viết)* | | | | ### 4.5 Mâu thuẫn | `ADR` A | `ADR` B | Cùng chủ đề | Mâu thuẫn ở đâu | Xử lý | |---|---|---|---|---| +| *(không phát hiện mâu thuẫn giữa 12 ADR ở lượt rà này — xem §3 theo chủ đề)* | | | | | ## 5. Điều kiện xét lại đã chạm ngưỡng | `ADR` | Điều kiện (§7 của ADR) | Ngưỡng | Thực tế | Chạm | Hành động | |---|---|---|---|---|---| +| *(chưa chạm — mới sinh, chưa có dữ liệu production để đối chiếu)* | | | | | | ## 6. ADR không có `FIT` bảo vệ | `ADR` | Ràng buộc nó đặt ra | `FIT` | Nhãn `⚠️ Khuyến nghị` | Đứt | |---|---|---|---|---| +| `ADR-001` | Ranh giới module không import chéo | `FIT-01`, `FIT-02` (ứng viên, chưa viết ở GĐ3) | — | 🟡 Ứng viên ghi nhận, `FIT` thật thuộc GĐ3 | +| `ADR-002` | Không truy cập chéo RDS Payment | `FIT-03`, `FIT-04` (ứng viên) | — | 🟡 | +| `ADR-003` | `OrderSeller` luôn thuộc đúng 1 `Order`/1 seller | `FIT-05`, `FIT-06` (ứng viên) | — | 🟡 | +| `ADR-004` | Webhook idempotent | `FIT-07` (ứng viên) | — | 🟡 | +| `ADR-005` | Publish luôn có `seller_id` làm message group | `FIT-08` (ứng viên) | — | 🟡 | +| `ADR-006` | Không truy cập chéo schema | `FIT-09` (ứng viên) | — | 🟡 | +| `ADR-007` | Gateway không chứa authz chi tiết | `FIT-10` (ứng viên) | — | 🟡 | +| `ADR-008` | Response cho seller chỉ chứa whitelist | `FIT-11` (ứng viên) | `⚠️ Khuyến nghị` cho audit định kỳ | 🟡 | +| `ADR-009` | Backup PITR đúng tần suất | `FIT-12` (ứng viên) | `⚠️ Khuyến nghị` cho diễn tập | 🟡 | +| `ADR-010` | Log format chuẩn có `correlation_id` | `FIT-13` (ứng viên) | `⚠️ Khuyến nghị` cho kiểm on-call | 🟡 | +| `ADR-011` | Idempotency key cho mọi lời gọi ghi đối tác ngoài | `FIT-14`, `FIT-15` (ứng viên) | — | 🟡 | +| `ADR-012` | Đúng 2 ECS service + 1 Payment | `FIT-16` (ứng viên) | — | 🟡 | +| `ADR-013` | p95 checkout ≤3.000ms (`QAS-002`) bất kể VNPay/Momo chậm; TX không giữ mở quá bước tạo `Order`; `PaymentInitRequested` idempotent | `FIT-23`, `FIT-24`, `FIT-25` (ứng viên) | — | 🟡 | +| `ADR-014` | Không publish sự kiện nào bỏ qua `outbox_event`; relay không mất/không publish thiếu khi bị kill | `FIT-26`, `FIT-27` (ứng viên) | — | 🟡 | +| `ADR-015` | Mọi lời gọi `IF-006`/`IF-021`/`IF-022` phải có service JWT hợp lệ | `FIT-31` (ứng viên) | — | 🟡 | +| `ADR-016` | Blue-green deploy tự động rollback khi health check fail | `FIT-37` (ứng viên) | — | 🟡 | +| `ADR-017` | Hạ tầng thật khớp Terraform state; đủ tag bắt buộc; đúng cấu trúc service/SG | `FIT-34`, `FIT-35`, `FIT-36` (ứng viên) | — | 🟡 | + +🟡 Toàn bộ `FIT-01…16`, `FIT-23…27`, `FIT-31`, `FIT-34…37` là **ứng viên** ghi nhận trong ADR — +chưa viết `FIT` thật (thuộc GĐ3 `sa-3-enablement`). Không tính là "Đứt" theo nghĩa vi phạm `D8` vì +GĐ3 chưa chạy; đây là danh sách việc bàn giao cho GĐ3. ## 7. Quyết định KHÔNG đủ tầm ADR — `DEC` +*(Đồng bộ 2026-09-15 từ `00-index/DEC_e-commerce.md` v1.15 — `DEC-01..17` hiện có đều là ngoại lệ +gate hoặc phê duyệt từng phần, radar ước lượng 3–7. `DEC-06` (radar ~7, "kiểu kiến trúc tổng +thể") **đã được trả nợ** bằng `ADR-001` ở lượt này — không còn treo. Không có `DEC` nào khác +vượt ngưỡng 8 mà bị "giấu" thay vì `ADR`.)* + | `DEC` | Quyết định | Ngày | Ai | Radar | |---|---|---|---|---| +| `DEC-01` | Chạy `sa-1-context` (Driver) khi BA chưa qua G1 | 2026-09-12 | Điều phối dự án | ~4 | +| `DEC-02` | Giả định tạm "team MVP chuẩn" cho ràng buộc Con người | 2026-09-12 | Điều phối dự án | ~4–5 | +| `DEC-03` | Tiếp tục ngoại lệ gate sang Bước 2 (Ràng buộc) | 2026-09-12 | Điều phối dự án | ~3–4 | +| `DEC-04` | Đóng `OQ-009` — dùng `SAD.md`/hồ sơ thầu làm điểm khởi đầu tham khảo cho `OPT`, có điều kiện | 2026-09-12 | Điều phối dự án | ~3–4 (ngoại lệ) / ~4–5 (nội dung) | +| `DEC-05` | Tiếp tục ngoại lệ gate sang Bước 4 (Phương án) | 2026-09-12 | Điều phối dự án | ~3–4 | +| `DEC-06` | **Chọn P2** làm hướng đi tạm cho Bước 5/GĐ2, có điều kiện `OQ-010`/`OQ-012` — **đã trả nợ bằng `ADR-001`** ở lượt `adr` này (2026-09-15) | 2026-09-12 | Điều phối dự án | ~7 — không còn "nợ" treo, xem `ADR-001` | +| `DEC-07` | Tiếp tục ngoại lệ gate sang Bước 5, phần `TCO` | 2026-09-12 | Điều phối dự án | ~3–4 | +| `DEC-08` | Tiếp tục ngoại lệ gate sang Bước 5, phần `ARISK` | 2026-09-12 | Điều phối dự án | ~3–4 | +| `DEC-09` | Duyệt từng phần `TCO` v1.1 (cấu trúc chi phí + kết luận P2 rẻ hơn P1) | 2026-09-12 | Điều phối dự án | ~3–4 | +| `DEC-10` | Duyệt từng phần `ARISK` v1.0 (10 rủi ro + kế hoạch `POC-01`/`POC-02`) | 2026-09-12 | Điều phối dự án | ~3–4 | +| `DEC-11` | Bắt đầu hoạt động `QAS` (GĐ2) dù AG1 chưa ký thật | 2026-09-14 | Điều phối dự án | ~4 | +| `DEC-12` | Duyệt từng phần `QAS` v1.0 | 2026-09-14 | Điều phối dự án (thay Tech Lead) | ~4 | +| `DEC-13` | Bắt đầu hoạt động `ASR` (GĐ2) | 2026-09-14 | Điều phối dự án | ~4 | +| `DEC-14` | Duyệt từng phần `ASR` v1.0 (15 `ASR` + 12 `ADR` ứng viên) | 2026-09-15 | Điều phối dự án (thay Tech Lead) | ~4 | +| `DEC-15` | Bắt đầu hoạt động `SAD` (GĐ2) | 2026-09-15 | Điều phối dự án | ~4 | +| `DEC-16` | Duyệt từng phần `SAD` v1.0 | 2026-09-15 | Điều phối dự án (thay Tech Lead) | ~4 | +| `DEC-17` | Bắt đầu hoạt động `adr` (GĐ2) — viết 12 ADR ứng viên | 2026-09-15 | Điều phối dự án | ~4 | +| `DEC-25` | Duyệt từng phần `DAT` v1.0 (ownership 15 `CMP`, mô hình `Order`/`OrderSeller`/`Payment`, idempotency, backup); TẠM `ASM-35`/Outbox (`OQ-044`, yêu cầu `ADR-014`)/audit phương án (a)/job quét 5 phút/polling; §5 PII chưa có hiệu lực (`OQ-007`) | 2026-09-15 | Điều phối dự án (thay Tech Lead) | ~4 | +| `DEC-26` | Review nội dung `ADR-013` (không chuyển `Accepted`, giữ `Proposed`) | 2026-09-15 | Điều phối dự án (thay Tech Lead) | ~7 *(radar gốc của `ADR-013`, không đổi bởi việc review)* | +| `DEC-28` | Duyệt từng phần `SEC` v1.0 (31 `THR` STRIDE, mô hình authn/authz đề xuất, SAQ A, rate limit đề xuất); chốt TẠM `OQ-050` chọn **PA-3** (service-to-service authn), yêu cầu `ADR-015`; §5/§8.2 PII/residency chưa có hiệu lực (`OQ-007`, Security chưa có người) | 2026-09-15 | Điều phối dự án (thay Tech Lead) | ~5 *(radar ước lượng PA-3, `SEC §2.4`)* | ## 8. Việc phải làm | # | Việc | ADR liên quan | Chủ | Hạn | Mức | |---|---|---|---|---|---| +| 1 | ~~Viết `ADR-001`~~ **Đã xong** ở lượt `adr` 2026-09-15 — 12 ADR viết đủ, tất cả `Proposed` | `ADR-001…012` | SA | — | ✅ Đóng | +| 2 | Chạy `POC-01` (throughput SQS/EventBridge) — chặn `ADR-005` chuyển `Accepted` | `ADR-005` | Tech Lead + DevOps | Trước khi `Accepted` `ADR-005`/`ADR-001` | 🔴 | +| 3 | Chạy `POC-02` (RDS gộp tải) — chặn `ADR-006` chuyển `Accepted` | `ADR-006` | Tech Lead/DBA | Trước khi `Accepted` `ADR-006`/`ADR-001` | 🔴 | +| 4 | Diễn tập DR (failover drill) — chặn `ADR-009` chuyển `Accepted`, cũng là điều kiện tiên quyết AG2 | `ADR-009` | Ops/SRE | Trước khi ký AG2 | 🔴 | +| 5 | PO chỉ định đại diện Pháp chế/Bảo mật — chặn `ADR-008` hoàn toàn (`OQ-007`) | `ADR-008` | PO | Càng sớm càng tốt | 🔴 | +| 6 | Tech Lead xác nhận `OQ-010`/`OQ-026`/`OQ-027` — chặn `ADR-012` chuyển `Accepted` | `ADR-012` | Tech Lead + Ops/SRE | Trước khi `Accepted` `ADR-012` | 🟠 | +| 7 | Security ký `ADR-002` (Payment cô lập) và `ADR-007` (ownership/authz) | `ADR-002`, `ADR-007` | Security | Trước AG2 | 🟠 | +| 8 | BA xác nhận `OQ-011` — chặn `ADR-003` chuyển `Accepted` | `ADR-003` | BA + PO | Trước khi `Accepted` `ADR-003` | 🟡 | +| 9 | Tech Lead + PO **thật** xác nhận `ADR-013` (không chỉ ký thay `DEC-01`); BA viết `SRS`/`AC` US-004 theo trạng thái mới; `ICD` lượt sau chốt endpoint polling/retry/chuyển COD (`OQ-041`) | `ADR-013` | Tech Lead + PO + BA + SA | Trước khi `Accepted` `ADR-013` / trước Dev thi công US-004 | 🟠 | +| 10 | ~~Viết `ADR-014`~~ **Đã xong** ở lượt `adr` 2026-09-15 (`DEC-31`) — Transactional Outbox, `Proposed` | `ADR-014` | SA | — | ✅ Đóng — còn nợ: Tech Lead xác nhận thiết kế relay (`OQ-044`) trước `Accepted` | +| 11 | ~~Viết `ADR-015`~~ **Đã xong** ở lượt `adr` 2026-09-15 (`DEC-31`) — Service JWT ngắn hạn (PA-3), `Proposed` | `ADR-015` | SA | — | ✅ Đóng — còn nợ: có đại diện Security thật ký (`OQ-007`, **chặn cứng `Accepted`**) + Tech Lead xác nhận hướng (`OQ-050`) | +| 12 | Tech Lead + Security + Ops/SRE xác nhận hướng PA-3 (không phải PA-2 mTLS) trước khi `ADR-015` có thể `Accepted` — `OQ-050`. **Security chưa có người (`OQ-007`) — đây là điều kiện chặn cứng nhất, đứng trước cả việc Tech Lead đồng ý nội dung** | `ADR-015` | Tech Lead + Security + Ops/SRE | Trước khi `Accepted` `ADR-015` | 🔴 | +| 13 | Viết `ADR-016`/`ADR-017` — **Đã xong** ở lượt `adr` 2026-09-15 (`DEC-31`) — Blue-green CodeDeploy + IaC Terraform, cả hai `Proposed` | `ADR-016`, `ADR-017` | SA | — | ✅ Đóng — còn nợ: Ops/SRE xác nhận năng lực vận hành + chạy thử ở staging (`ADR-016`); Tech Lead + Ops/SRE xác nhận công cụ (`OQ-060`, `ADR-017`) | +| 14 | Ops/SRE chạy thử blue-green deploy + rollback thành công ít nhất 1 lần ở staging — chặn `ADR-016` chuyển `Accepted` | `ADR-016` | Ops/SRE | Trước AG2 | 🟠 | +| 15 | Tech Lead + Ops/SRE xác nhận công cụ Terraform (`OQ-060`) và thiết lập backend state (S3+DynamoDB) — chặn `ADR-017` chuyển `Accepted` | `ADR-017` | Tech Lead + Ops/SRE | Trước AG2 | 🟠 | ## 9. Thống kê theo thời gian | Kỳ | ADR mới | Superseded | Ghi chú | |---|---|---|---| +| 2026-09-15 | 12 (`ADR-001…012`, tất cả `Proposed`) | 0 | Lượt chạy đầu tiên của hoạt động `adr` — trả nợ `DEC-06` | +| 2026-09-15 (cùng ngày, lượt sau) | 1 (`ADR-013`, `Proposed`) | 0 | Hoạt động `adr` phạm vi hẹp — hiện thực hoá Lựa chọn B của `OQ-034`/`DEC-22` (bất đồng bộ hoá bước khởi tạo thanh toán) | +| 2026-09-15 (cùng ngày, lượt cuối) | 4 (`ADR-014…017`, tất cả `Proposed`) | 0 | Hoạt động `adr` — trả hết 4 khoản nợ ADR còn treo từ `DEC-25`/`DEC-28`/`DEC-30` (outbox, service JWT, blue-green, Terraform). Tổng ADR nay là 17, không còn nợ nào | diff --git a/sa-output/e-commerce/00-index/DEC_e-commerce.md b/sa-output/e-commerce/00-index/DEC_e-commerce.md index 3d5b420..3c8230e 100644 --- a/sa-output/e-commerce/00-index/DEC_e-commerce.md +++ b/sa-output/e-commerce/00-index/DEC_e-commerce.md @@ -2,20 +2,49 @@ | | | |---|---| -| **Version** | 1.0 | -| **Date** | 2026-09-10 | -| **Author** | SA (qua skill sa-lifecycle — khởi tạo) | +| **Version** | 1.29 | +| **Date** | 2026-09-15 | +| **Author** | SA (qua skill sa-1-context, sa-2-architecture) | | **Status** | 🟡 Draft — cập nhật liên tục qua các giai đoạn | | **Approved by** | — *(sổ theo dõi, không cần baseline riêng)* | -| **Source** | Khởi tạo trống — chưa có artifact GĐ nào của SA | +| **Source** | `01-context/CTX_e-commerce_v1.0.md (v1.2 trong header)` §0, §3, §4, §7, §7.1 · `01-context/OPT_e-commerce_v1.0.md` §0, §1, §2, §9 · `01-context/TCO_e-commerce_v1.0.md` §0 · `01-context/ARISK_e-commerce_v1.0.md` §0 · `02-architecture/ASR_e-commerce_v1.0.md` §0 · `02-architecture/SAD_e-commerce_v1.0.md` v1.3 §0 · `02-architecture/adr/ADR-001…013_*.md` §0 · `02-architecture/ICD_e-commerce_v1.0.md` §0 · `02-architecture/FAIL_e-commerce_v1.0.md` v1.1 §0 · `02-architecture/DAT_e-commerce_v1.0.md` §0 · `02-architecture/SEC_e-commerce_v1.0.md` §0.1 · `02-architecture/INF_e-commerce_v1.0.md` §0 | | **Scope** | Toàn dự án e-commerce (kiến trúc) | -| **Confidence** | 🟡 Sổ theo dõi rỗng lúc khởi tạo, chưa có nội dung để đánh giá | +| **Confidence** | 🟡 Sổ theo dõi — nội dung tham chiếu từ `CTX`/`OPT`/`TCO`/`ARISK` (các tài liệu đó là 🔴) | ## Change Log | Version | Date | Người sửa | Thay đổi | ADR | |---|---|---|---|---| | 1.0 | 2026-09-10 | SA (qua skill sa-lifecycle) | Khởi tạo sổ DEC kiến trúc, khung rỗng | — | +| 1.1 | 2026-09-12 | SA (qua skill sa-1-context) | Thêm `DEC-01` (ngoại lệ gate GĐ1 SA chạy khi BA chưa qua G1) | — | +| 1.2 | 2026-09-12 | PO (uỷ quyền, Điều phối dự án) — tác vụ sign | Thêm `DEC-02` (chốt hướng trả lời `OQ-002`: dùng giả định "team MVP chuẩn" `Confidence` 🔴 cho ràng buộc Con người ở Bước 2); ghi nhận phê duyệt tạm §2 Driver của `CTX v1.0` (xem Change Log của `CTX`) | — | +| 1.3 | 2026-09-12 | SA (qua skill sa-1-context, hoạt động `constraints`) | Thêm `DEC-03` (tiếp tục ngoại lệ gate `DEC-01` sang Bước 2 — Ràng buộc; người dùng tái khẳng định muốn tiếp tục dù AG1/G1 chưa qua) | — | +| 1.4 | 2026-09-12 | SA (qua skill sa-1-context, hoạt động `as-is`) | Thêm `DEC-04` (đóng `OQ-009` — chấp nhận `SAD.md`/hồ sơ thầu làm điểm khởi đầu tham khảo cho Bước 4 `OPT`, có điều kiện); tiếp tục ngoại lệ gate `DEC-01`/`DEC-03` sang Bước 3 — Hiện trạng (AS-IS); người dùng tái khẳng định muốn tiếp tục dù AG1/G1 chưa qua | — | +| 1.5 | 2026-09-12 | SA (qua skill sa-1-context, hoạt động `options`) | Thêm `DEC-05` (tiếp tục ngoại lệ gate `DEC-01`/`DEC-03`/`DEC-04` sang Bước 4 — Phương án `OPT`; người dùng tái khẳng định muốn tiếp tục dù AG1/G1 chưa qua). `OPT_e-commerce_v1.0.md` tạo mới, khuyến nghị P2 có điều kiện, chưa PO/Tech Lead ký | — | +| 1.6 | 2026-09-12 | PO (uỷ quyền, Điều phối dự án) — tác vụ sign | Thêm `DEC-06` (duyệt từng phần `OPT_e-commerce_v1.0.md` v1.0: chấp nhận bộ tiêu chí/trọng số mặc định (đóng `ASM-09`), bảng chấm điểm, phương án bị loại P3/P4, khuyến nghị P2 có điều kiện; **chọn P2** làm nền cho Bước 5/GĐ2 với điều kiện `OQ-010`/`OQ-012`). Đóng `OQ-011` trong sổ `00-index/OQ_e-commerce.md`. `OPT` giữ Status Draft, Tech Lead chưa ký, `Confidence` giữ 🔴 | — | +| 1.7 | 2026-09-12 | SA (qua skill sa-1-context, hoạt động `cost-risk`) | Thêm `DEC-07` (tiếp tục ngoại lệ gate sang Bước 5, phần `TCO`; người dùng tái khẳng định muốn tiếp tục) và `DEC-08` (tiếp tục ngoại lệ gate sang Bước 5, phần `ARISK`). `TCO_e-commerce_v1.0.md` và `ARISK_e-commerce_v1.0.md` tạo mới — GĐ1 SA nay đủ 4 artifact (`CTX`/`OPT`/`TCO`/`ARISK`) để audit AG1, dù tự chấm từng file vẫn cho thấy AG1 chưa đủ điều kiện ký chính thức (nhiều `OQ` còn mở) | `DEC-07`, `DEC-08` | +| 1.8 | 2026-09-12 | PO (uỷ quyền, Điều phối dự án) — tác vụ sign | Thêm `DEC-09` (duyệt từng phần `TCO_e-commerce_v1.0.md` v1.1 sau khi sửa lỗi chép số §1 P2-B: chấp nhận cấu trúc 4 nhóm chi phí, 2 kịch bản tải A/B, kết luận "P2 rẻ hơn P1"; đơn giá AWS/tỷ giá/FTE Ops/5 khoản non-labor chưa xác nhận) và `DEC-10` (duyệt từng phần `ARISK_e-commerce_v1.0.md` v1.0: chấp nhận 10 rủi ro và kế hoạch `POC-01`/`POC-02`; POC chưa chạy). Cả hai giữ Status Draft, `Confidence` 🔴, `OQ-004` mở, AG1 chưa ký. | `DEC-09`, `DEC-10` | +| 1.9 | 2026-09-14 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `qas`) | Thêm `DEC-11` (bắt đầu `sa-2-architecture` hoạt động `QAS` dù AG1 chưa có chữ ký PO/Tech Lead thật và `POC-01`/`POC-02` chưa chạy — tiếp nối `DEC-01…10`, người dùng tái khẳng định muốn tiếp tục). `QAS_e-commerce_v1.0.md` tạo mới — 14 `QAS` lượng hoá từ `NFR-01…08` (SAD) và `NFR-PERF/SEC/AVL` (BA), `Confidence` 🔴 toàn bộ. Không tạo `ASR`/`SAD`/`ADR` ở lượt này theo yêu cầu điều phối. | `DEC-11` | +| 1.10 | 2026-09-14 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign | Thêm `DEC-12` (duyệt từng phần `QAS_e-commerce_v1.0.md` v1.0: chấp nhận 14 `QAS` đủ 6 phần và cách đo; chấp nhận TẠM các số SA đề xuất `QAS-003/004/007/014`, `OQ-018…021` giữ mở; chốt điều kiện diễn tập DR `QAS-008` phải thực hiện trước khi ký AG2, cập nhật `OQ-022`). 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ý. | `DEC-12` | +| 1.11 | 2026-09-14 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `asr`) | Thêm `DEC-13` (tiếp tục `sa-2-architecture` hoạt động `ASR` dù AG1 chưa ký thật và AG2 chưa tới hạn — tiếp nối `DEC-01…12`). `ASR_e-commerce_v1.0.md` tạo mới — 15 `ASR`, 12/15 có `ADR` ứng viên (radar 4–9), `ADR-001` (kiểu kiến trúc tổng thể P2) vẫn nợ từ `DEC-06`. Thêm `OQ-024/025`, `ASM-19…21`. Không viết `ADR` nào. | `DEC-13` | +| 1.12 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign | Thêm `DEC-14` (duyệt từng phần `ASR_e-commerce_v1.0.md`: chấp nhận 15 `ASR-001…015` và 12 `ADR` ứng viên `ADR-001…012` với radar ước lượng; `ADR-005/006/009` (radar ≥8) chỉ `Accepted` sau `POC-01`/`POC-02`/diễn tập DR. Chốt TẠM `OQ-024` (MFA Admin = TOTP app, `ASM-20`) và `OQ-025` (không dịch nội dung seller ở MVP, `ASM-21`) — cả hai giữ nguyên mở). 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ý. | `DEC-14` | +| 1.13 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `sad`) | Thêm `DEC-15` (tiếp tục `sa-2-architecture` hoạt động `SAD` dù AG1 chưa ký thật và AG2 chưa tới hạn — tiếp nối `DEC-01…14`). `SAD_e-commerce_v1.0.md` tạo mới — C4 Context/Container/Component (Cart&Order), deployment view AWS `ap-southeast-1` đối chiếu `TCO §3.2` (1 điểm lệch mức chi tiết phát hiện, ghi `OQ-026`, không tự đổi số `TCO`), 15 `CMP` (ma trận `ASR×CMP` đủ 15/15), 22 `IF-nn` ứng viên cho `ICD`, đánh dấu 12 chỗ chờ `ADR-001…012` (không viết `ADR`). Thêm `OQ-026/027`, `ASM-22/23`. | `DEC-15` | +| 1.14 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign | Thêm `DEC-16` (duyệt từng phần `SAD_e-commerce_v1.0.md` bản v1.0: chấp nhận C4 Context/Container/Component, deployment view, bảng `CMP-01…15`, ma trận `ASR→CMP` đủ 15/15, 22 `IF-nn` ứng viên, 12 chỗ chờ `ADR`. Chốt TẠM `OQ-026` (2 ECS Fargate service riêng theo Nhóm Giao dịch/Nhóm Hỗ trợ, `TCO §3.2` giữ nguyên tới khi hoạt động `inf` xác nhận, `ASM-23`) và `OQ-027` (Identity & Access thuộc Nhóm Giao dịch, `ASM-22`) — cả hai **giữ nguyên mở**). 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ý. | `DEC-16` | +| 1.15 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `adr`) | Thêm `DEC-17` (tiếp tục `sa-2-architecture` hoạt động `adr` cho e-commerce dù AG1 chưa ký thật và AG2 chưa tới hạn — tiếp nối `DEC-01…16`). Viết đủ 12 `ADR-001…012` trong `02-architecture/adr/` theo danh sách ứng viên đã duyệt từng phần ở `ASR §B2`/`DEC-14` và `SAD §8`/`DEC-16` — không đổi số thứ tự, không đổi radar ước lượng. **Tất cả 12 ADR ở Status `Proposed`** — không ADR nào `Accepted` vì chưa có chữ ký thật (Tech Lead + Security + Ops/SRE); `ADR-005`/`ADR-006`/`ADR-009` (radar ≥8) ghi rõ điều kiện `Accepted` là `POC-01`/`POC-02`/diễn tập DR PASS, hiện chưa chạy; `ADR-008` (PII) ghi phủ quyết Security/Legal, chặn hoàn toàn tới khi có người (`OQ-007`). Cập nhật `ADL_e-commerce.md` (12 ADR `Proposed`, radar, nguồn, `ASR` phục vụ, §7/§8/§9). Cập nhật `SAD_e-commerce_v1.0.md` §8 lên v1.1 (chỉ link ADR đã viết vào bảng đã có, không đổi nội dung chuyên môn khác). `DEC-06` (chọn P2, GĐ1) được trả nợ bằng `ADR-001` — không còn "nợ" treo ở `DTM`/`ADL`. Không sửa `SAD`/`ASR`/`QAS` phần nội dung đã duyệt từng phần khác. `Confidence` 🔴 toàn bộ 12 ADR. | `DEC-17`, `ADR-001…012` | +| 1.16 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `icd`) | Thêm `DEC-18` (tiếp tục `sa-2-architecture` hoạt động `icd` cho e-commerce dù AG1 chưa ký thật và AG2 chưa tới hạn — tiếp nối `DEC-01…17`). `ICD_e-commerce_v1.0.md` tạo mới — catalog 17/17 `IF-nn` truy được từ `SAD §4` (chênh lệch "22" ghi ở `OQ-029`), chi tiết đầy đủ `IF-002` (4 endpoint Cart & Checkout) và `IF-005/006/007/008/009/015/021/022`. Xác nhận/điều chỉnh `API_US002-003_v1.0.md` của BA tại §5. Thêm `OQ-028…033`, `ASM-24…26`. *(Ghi bổ sung: Change Log này bị thiếu ở lượt chạy trước, bổ sung lại khi sign `DEC-19` để không đứt mạch version — không đổi nội dung `ICD` đã ghi.)* | `DEC-18` | +| 1.17 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign | Thêm `DEC-19` (duyệt từng phần `ICD_e-commerce_v1.0.md` bản v1.0: 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. Chấp nhận TẠM `ASM-24/25/26` và hướng denormalize `sellerName` (`OQ-033`) — `OQ-028…033` (SA) giữ nguyên mở). 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ý. | `DEC-19` | +| 1.18 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `sad`, sửa lỗi) | Thêm `DEC-20` (tiếp tục ngoại lệ gate cho e-commerce dù AG1 chưa ký thật và AG2 chưa tới hạn — tiếp nối `DEC-01…19` — để sửa lỗi nhất quán `SAD` theo phát hiện của `ICD`, `OQ-028`/`OQ-029`, theo yêu cầu người duyệt 2026-09-15). `SAD_e-commerce_v1.0.md` lên v1.2: (1) `IF-021` sửa mọi mô tả thành cross-network REST (không còn "internal") — legend §4, footnote §4.1, bảng §6.1/§6.3, bổ sung cạnh mạng còn thiếu ở §7; rà `IF-022` theo cùng nguyên tắc (làm rõ cũng cross-network, không đổi loại vì trước đó chưa có nhãn); `IF-005`/`IF-006` không đổi. (2) Đếm lại `IF-nn`: kết luận "22" là đếm nhầm, đúng 17 ID, không bỏ sót interface — sửa "22"→"17" ở header/Change Log/Tự chấm. Đóng `OQ-029` trong sổ `00-index/OQ_e-commerce.md`; `OQ-028` giữ nguyên mở. Đây là sửa lỗi tài liệu, không phải quyết định kiến trúc — không cần `ADR` mới, không sửa §8/`ASR`/`QAS`/`ADR`/`ICD`. `Confidence` giữ 🔴; Status giữ Draft; §4/§6/§7 v1.2 chưa được ký lại. | `DEC-20` | +| 1.19 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `fail`) | Thêm `DEC-21` (tiếp tục `sa-2-architecture` hoạt động 8 — `FAIL` — cho e-commerce dù AG1 chưa ký thật và AG2 chưa tới hạn — tiếp nối `DEC-01…20`). `FAIL_e-commerce_v1.0.md` tạo mới — bảng 13 phụ thuộc vượt ranh giới process (`FM-01…13`, theo `SAD` v1.2 §6.3: VNPay, Momo, GHN, GHTK, Email/SMS, RDS chính, RDS Payment, Redis, SQS FIFO, EventBridge, `IF-006`, `IF-021` ưu tiên cao nhất, `IF-022`) đủ timeout/retry/idempotent/hết-retry-thì-sao/người dùng thấy gì; đủ 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 vượt ngân sách `QAS-002` ~7%** ngay cả sau khi siết timeout VNPay/Momo xuống 1.500ms — trình 2 lựa chọn kèm hệ quả bằng số, ghi `OQ-034`); circuit breaker/backoff/bulkhead cho toàn hệ thống; suy giảm có kiểm soát (Promotion lỗi — đề xuất mặc định không tự quyết, nối `OQ-017` BA; COD khi VNPay/Momo lỗi; GHN↔GHTK fallback chéo; phát hiện thiếu cache nội dung giỏ hàng cho fallback 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` (3 mã lỗi mới đề xuất cho US-004 Checkout, chưa có trong `SRS` BA); đề xuất `FIT-16…22` (chaos test) cho GĐ3. Thêm `OQ-034…040`, `ASM-27…33`. Không sửa `SAD`/`ICD`/`ADR` đã có. `Confidence` 🔴 toàn bộ. | `DEC-21` | +| 1.20 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign | Thêm `DEC-22` (duyệt từng phần `FAIL_e-commerce_v1.0.md` bản v1.0: chấp nhận bảng 13 phụ thuộc, 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ữ mở. **Chọn Lựa chọn B cho `OQ-034`** (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 `SAD §6.1`/`FAIL §1.2` ở lượt kế tiếp; `OQ-034` chuyển "đã chọn hướng B, chờ `ADR-013` + Tech Lead/PO thật xác nhận", giữ mở). 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ý. | `DEC-22` | +| 1.21 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `adr`, phạm vi hẹp) | Thêm `DEC-23` (viết `ADR-013` — bất đồng bộ hoá bước khởi tạo thanh toán, hiện thực hoá Lựa chọn B của `OQ-034`/`DEC-22` — và sửa nhất quán tối thiểu `SAD §6.1`/`§8` lên v1.3 + `FAIL §1.2` lên v1.1). Không viết ADR khác, không sửa 12 ADR cũ. | `DEC-23` | +| 1.22 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `dat`) | Thêm `DEC-24` (tiếp tục `sa-2-architecture` hoạt động 5 — `DAT` — cho e-commerce dù AG1 chưa ký thật và AG2 chưa tới hạn — tiếp nối `DEC-01…23`). `DAT_e-commerce_v1.0.md` tạo mới — bảng ownership `D7` cho toàn bộ 15 `CMP` (schema-per-module theo `ADR-006`, RDS Payment riêng theo `ADR-002`); mô hình `Order`/`OrderSeller`/`OrderItem` chi tiết theo `ADR-003`, bổ sung `order.payment_init_status` theo `ADR-013` và `cart_item.seller_name_snapshot`/`unit_price_snapshot` theo `ICD` (`OQ-033`); phân loại PII/Payment/nghiệp vụ + đề xuất retention (chờ Legal, `OQ-007`) và whitelist chia sẻ seller theo `ADR-008`; chiến lược đọc/ghi (index, read replica chỉ Catalog, đánh giá cache `Cart` cho `OQ-040`); đề xuất Transactional Outbox pattern cho khoảng trống `FAIL §7` (ADR ứng viên radar ~6, chưa viết — `OQ-044`) và idempotency store cho `POST /v1/checkout`; backup/PITR đối chiếu `QAS-008`/`ADR-009`; migration/versioning schema (đề xuất Flyway, `OQ-045`); dữ liệu đối soát (`ReconciliationLog`) và đề xuất ngưỡng job dọn `Order` kẹt cho `OQ-042`. Đối chiếu `docs/sections/05-thiet-ke-du-lieu.md` (P1) — phát hiện P2 thiếu `CMP` Audit & Compliance riêng (`OQ-047`). Thêm `OQ-043…047`, cập nhật `OQ-007/040/042`, `ASM-35…38`. Không sửa `SAD`/`ICD`/`FAIL`/`ADR`. `Confidence` 🔴 toàn bộ. | `DEC-24` | +| 1.23 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign | Thêm `DEC-25` (duyệt từng phần `DAT_e-commerce_v1.0.md` v1.0: chấp nhận ownership 15 `CMP`, mô hình `Order`/`OrderSeller`/`Payment`, idempotency, backup/PITR; chấp nhận TẠM `ASM-35`, Transactional Outbox cho `OQ-044` (yêu cầu `ADR-014` ở lượt `adr` kế), phương án (a) audit cho `OQ-047`, ngưỡng job quét 5 phút cho `OQ-042`, polling cho `OQ-041` — cả bốn giữ mở; `OQ-045/046` không đổi. §5 PII/retention/whitelist CHƯA CÓ HIỆU LỰC, chờ Legal/Security (`OQ-007`)). 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ý. | `DEC-25` | +| 1.24 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign | Thêm `DEC-26` (review nội dung `adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md`: chấp nhận nội dung §3 làm cơ sở thiết kế tiếp; **KHÔNG** đề nghị `Accepted` — giữ `Proposed` vì chưa có chữ ký thật Tech Lead + PO và BA chưa viết `SRS`/`AC` US-004. Ghi dòng "Reviewed (Proposed giữ nguyên)" ở `ADR-013 §9`, cùng mẫu 12 ADR trước). Ký thay Tech Lead theo ngoại lệ `DEC-01`; `Confidence` 🔴; `AG2` chưa ký. | `DEC-26` | +| 1.25 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `sec`) | Thêm `DEC-27` (tiếp tục `sa-2-architecture` hoạt động 6 — `SEC` — cho e-commerce dù AG1 chưa ký thật và AG2 chưa tới hạn — tiếp nối `DEC-01…26`). `SEC_e-commerce_v1.0.md` tạo mới — threat model STRIDE cho 8 ranh giới tin cậy (`THR-01…31`), mô hình authn (Guest/Customer/Seller/Admin + đề xuất mới service-to-service, `OQ-050`), mô hình authz (map đủ `ROLE-01/02` của `RBAC_CartCheckout`, fail-closed `E-CART-0007`), phân loại/mã hoá/masking PII (toàn bộ đánh dấu "đề xuất chờ Legal/Security", `OQ-007`), PCI-DSS SAQ A (xác nhận `ADR-002`, phát hiện khoảng trống xác nhận hình thức tích hợp redirect với đối tác — `OQ-048`), webhook signature/anti-replay (chưa có tài liệu đối tác, không bịa — `OQ-049`, `ARISK-03/04`), đề xuất số rate-limit Guest cart/checkout/login (`OQ-023` trả lời có số cụ thể, không tự quyết), secret management, audit log theo phương án (a) đã chốt (`OQ-047`), chuỗi cung ứng (scan/pentest/ASV). Đề xuất `FIT-29…33` cho GĐ3. Thêm `OQ-048…053`, cập nhật `OQ-007/023/024/047`, `ASM-39…41`. Không sửa `SAD`/`ICD`/`DAT`/`FAIL`/`ADR` đã có; không viết `ADR` mới (chỉ đề xuất 1 ứng viên — service-to-service authn — cho hoạt động `adr` kế tiếp). `Confidence` 🔴 toàn bộ. **Phát hiện quan trọng nhất:** Security **chưa có người** (`OQ-007`) — `SEC` chưa có hiệu lực phủ quyết AG2 cho bất kỳ nội dung nào của tài liệu này. | `DEC-27` | +| 1.26 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign | Thêm `DEC-28` (duyệt từng phần `SEC_e-commerce_v1.0.md` v1.0: ghi nhận nội dung 31 `THR` STRIDE, map `ROLE-01/02`, mô hình authn/authz đề xuất, SAQ A, đề xuất rate limit **30/10/10 req/phút** (`ASM-40`), quản lý secret/scanning, audit log theo phương án (a). Chốt TẠM `OQ-050`: chọn **PA-3** (service JWT ngắn hạn ký bởi Identity & Access) cho service-to-service authn — yêu cầu SA viết `ADR-015` (`Proposed`) ở lượt hoạt động `adr` kế tiếp cùng `ADR-014`; `OQ-050` giữ nguyên mở, chờ Security + Ops/SRE. **KHÔNG ký thay Security**: header `Approved by → Security` giữ `—`, `SEC` chưa có hiệu lực phủ quyết AG2 (`OQ-007`); mọi kết luận PII/residency/retention (§5, §8.2) là đề xuất chờ Legal/Security). Ký thay Tech Lead theo ngoại lệ `DEC-01`; Ops/SRE chưa ký; `OQ-004` mở; `Confidence` giữ 🔴; Status giữ Draft; AG2 chưa ký. | `DEC-28` | +| 1.27 | 2026-09-15 | SA (qua skill `sa-2-architecture`, chế độ `go`, hoạt động `inf`) | Thêm `DEC-29` (tiếp tục `sa-2-architecture` hoạt động 7 — `INF` — cho e-commerce dù AG1 chưa ký thật và AG2 chưa tới hạn — tiếp nối `DEC-01…28`). `INF_e-commerce_v1.0.md` tạo mới — topology AWS `ap-southeast-1` (VPC/2 AZ/subnet, ALB+WAF, 2 ECS Fargate Nhóm Giao dịch/Nhóm Hỗ trợ + Payment tách biệt, RDS chính Multi-AZ + RDS Payment, Redis, SQS FIFO+EventBridge+DLQ, S3/CloudFront, Secrets Manager/KMS, NAT), đối chiếu từng dòng với `TCO §3.2` (khớp toàn bộ trừ 1 điểm bản chất — cross-region snapshot Payment trong `TCO` vs "không multi-region" của `ADR-009`, ghi `OQ-054`, không tự sửa `TCO`/`ADR`); đề xuất split ECS task GD/HT (A: 2/2, B: 6/4, khớp tổng `TCO`, `OQ-055`); HA (auto-scaling A→B theo `QAS-009`, phát hiện SPOF ElastiCache kịch bản A không có replica, `OQ-058`); DR (RPO≤15’/RTO≤1h theo `QAS-008`/`ADR-009`, backup/PITR, **kế hoạch diễn tập DR 3 kịch bản** — mất AZ/mất RDS primary/mất Redis — kèm tiêu chí PASS/FAIL đo thật, đề xuất hạn trước AG2, `OQ-022`/`OQ-056` ngày thật chờ Ops/SRE); observability (alert ≤1 phút nhóm giao dịch cốt lõi theo `QAS-013`, DLQ 14 ngày + alert lag >5 phút theo `OQ-036`/`DEC-22`, error budget 43 phút/tháng loại trừ bảo trì ≤2h theo `OQ-020`, on-call theo `CON-08`+`OQ-008`); CI/CD (pipeline build→test→SAST→SCA(Trivy/Snyk)→migration→deploy, blue-green cho 3 service, migration schema Flyway theo `OQ-045`); network/SG + egress đối tác ngoài (`OQ-057` IP allowlist); giải quyết khoảng trống service discovery GD↔HT của `SAD §7`/`OQ-028` bằng AWS Cloud Map/ECS Service Connect (ghi `DEC` mức thấp, không `ADR`); IaC (đề xuất Terraform) + `FIT-34…38` ứng viên GĐ3. Đề xuất 2 `ADR` ứng viên mới cho hoạt động `adr` kế tiếp (`ADR-016` chiến lược triển khai blue-green, `ADR-017` công cụ IaC) — **không viết `ADR` ở lượt này**. Thêm `OQ-054…063`, `ASM-42…46`. Không sửa `SAD`/`ICD`/`DAT`/`SEC`/`FAIL`/`ADR` đã có. `Confidence` 🔴 toàn bộ. | `DEC-29` | +| 1.28 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign | Thêm `DEC-30` (duyệt từng phần `INF_e-commerce_v1.0.md` v1.0: chấp nhận topology AWS `ap-southeast-1`, bảng đối chiếu `INF↔TCO` §10, HA/auto-scaling split ECS GD/HT A 2/2 – B 6/4 (`ASM-42`, `OQ-055` giữ mở), kế hoạch diễn tập DR 3 kịch bản (`OQ-022`/`OQ-056`, ngày thật chờ Ops/SRE — điều kiện AG2), observability, CI/CD blue-green (`ADR-016` ứng viên), network/egress, IaC Terraform (`ADR-017` ứng viên). Chốt TẠM `OQ-058`: giữ `TCO`, KHÔNG thêm replica Redis ở kịch bản A, chấp nhận SPOF với fail-closed theo `FAIL` — `OQ-058` giữ nguyên mở, chờ PO. Đồng ý viết `ADR-016`/`ADR-017` (`Proposed`) cùng `ADR-014`/`ADR-015` ở lượt `adr` kế tiếp. `OQ-054` giữ nguyên mở. **KHÔNG ký thay Ops/SRE**: header `Approved by → Ops/SRE` giữ `—`. Security chưa ký; Ký thay Tech Lead theo ngoại lệ `DEC-01`; `OQ-004` mở; `Confidence` giữ 🔴; Status giữ Draft; AG2 chưa ký. | `DEC-30` | +| 1.29 | 2026-09-15 | SA (qua skill `sa-2-architecture`, chế độ `go`, hoạt động `adr`) | Thêm `DEC-31` (viết 4 `ADR` còn nợ 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…30`). Viết `ADR-014` (Transactional Outbox — hiện thực hoá hướng đã chọn TẠM ở `DAT §4.1`/`OQ-044`/`DEC-25`, radar 6/10), `ADR-015` (Service JWT ngắn hạn service-to-service — hiện thực hoá PA-3 đã chọn TẠM ở `SEC §2.4`/`OQ-050`/`DEC-28`, radar 5/10, **chặn cứng `Accepted` bởi `OQ-007` — Security chưa có người**), `ADR-016` (Blue-green qua AWS CodeDeploy cho 3 dịch vụ ECS — hiện thực hoá đề xuất `INF §7.2`/`DEC-30`, radar 6/10), `ADR-017` (IaC Terraform — hiện thực hoá đề xuất `INF §11`/`DEC-30`, radar 7/10) trong `02-architecture/adr/`. **Cả 4 ADR giữ Status `Proposed`** — không ADR nào `Accepted` (chưa có chữ ký thật Tech Lead/Security/Ops-SRE; không cái nào đạt radar ≥8 nên không bắt buộc POC, nhưng mỗi ADR đều ghi rõ điều kiện `Accepted` riêng ở §3). Link 4 `ADR` này vào `DAT_e-commerce_v1.0.md` (v1.1, §4.1), `SEC_e-commerce_v1.0.md` (v1.1, §2.4/§4 TB3-TB4), `INF_e-commerce_v1.0.md` (v1.1, §7.2/§11/§13) — **chỉ thay "ứng viên"/"chưa viết" bằng đường dẫn thật, không đổi nội dung chuyên môn khác** của ba tài liệu đó, mỗi file bump `+0.1` kèm Change Log "chỉ link ADR, không đổi nội dung". Cập nhật `ADL_e-commerce.md` (17 ADR, tất cả `Proposed`) và `DTM_e-commerce.md` (`ASR-004`/`ASR-005` → thêm `ADR-014`; `ASR-007` → thêm `ADR-015`; `QAS-007` → `ADR-016`; ghi nhận `ADR-017` không có `ASR`/`QAS` nguồn trực tiếp, hợp lệ vì gắn `CON-05`/`D9`). Không sửa 13 `ADR` cũ, không sửa nội dung `SAD`/`ASR`/`QAS`/`ICD`/`FAIL`. `Confidence` 🔴 toàn bộ 4 ADR mới. | `DEC-31`, `ADR-014…017` | --- @@ -23,6 +52,37 @@ | ID | Quyết định | Người quyết | Ngày | Radar | Ảnh hưởng | |---|---|---|---|---|---| +| DEC-01 (SA) | Chạy `sa-1-context` (hoạt động Driver) cho e-commerce trong khi BA chưa ký G1 chính thức (`BRIEF_CartCheckout` Draft, `OQ-001`/`OQ-007` BA mở) và không có gate SA nào trước GĐ1 để chờ — tham chiếu mô hình ngoại lệ `DEC-02..07` của bộ BA (dự án chạy thử). Toàn bộ `DRV` giữ `Confidence` 🔴 tới khi BA ký G1 thật. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-12 | ~4 (chi phí đảo ngược thấp · toàn bộ GĐ1 SA · không chạm `QAS` cụ thể · không ràng buộc dài hạn · đã có tiền lệ) | `CTX_e-commerce_v1.0.md` (toàn bộ), `OQ-001`, `OQ-004` | +| DEC-02 (SA) | Trả lời `OQ-002` (ràng buộc Con người chưa có thông tin số đội/số người/kỹ năng): dùng giả định mặc định "team MVP chuẩn" (quy mô/kỹ năng đội hình tối thiểu đủ vận hành một MVP, chưa xác nhận số thật) làm đầu vào tạm cho `CON` nhóm Con người ở Bước 2 của `sa-1-context`. `Confidence` của giả định này là 🔴; giả định thật (`ASM-nn`) sẽ được lập trong `CTX` §5/§3 khi Bước 2 chạy, và phải được thay bằng số thật khi PM/Tech Lead xác nhận (`OQ-002` đóng nhưng nội dung chưa "xác nhận", chỉ là "chọn giả định tạm để không nghẽn tiến độ"). | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-12 | ~4–5 (ảnh hưởng ranh giới service GĐ2 nếu team thực tế khác đáng kể · chi phí đảo ngược trung bình nếu phải vẽ lại ranh giới domain · chưa chạm `QAS` cụ thể · có tiền lệ dùng giả định mặc định ở dự án chạy thử) | `CTX_e-commerce_v1.0.md` §7 `OQ-002`, Bước 2 (`CON`) sắp tới | +| DEC-03 (SA) | Tiếp tục chạy `sa-1-context` Bước 2 (Ràng buộc — `CON-nn`, đủ 6 nhóm) và bổ sung `ASM-nn` cấp `CTX` cho dự án e-commerce trong khi BA **vẫn chưa** qua G1 chính thức và AG1 (gate của chính GĐ1 SA) vẫn chưa từng chạy — tiếp nối `DEC-01`. Người điều phối dự án đã được cảnh báo lại về việc gate trước chưa `✅ Baselined` và **tái khẳng định muốn tiếp tục**. Toàn bộ `CON`/`ASM` mới thêm giữ `Confidence` 🔴; phần lớn giá trị "Cứng/Mềm" của `CON` ghi "Chưa xác định" vì nguồn duy nhất là ước lượng hồ sơ thầu (`e-commerce/bid/`, Draft, chưa hợp đồng), không phải số PO đã duyệt. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-12 | ~3–4 (chi phí đảo ngược thấp — chỉ là nội dung `CON`/`ASM`, sửa lại khi có số thật không tốn nhiều · bán kính ảnh hưởng: toàn bộ `OPT`/`TCO` ở các Bước 4–5 kế tiếp phụ thuộc vào `CON` này · chưa chạm `QAS` cụ thể · không ràng buộc dài hạn (là ngoại lệ tạm thời, tiếp nối tiền lệ `DEC-01`) · không tranh cãi mới, đã có tiền lệ) | `CTX_e-commerce_v1.0.md (v1.1 trong header)` §0, §3, `OQ-005`…`OQ-009` | +| DEC-04 (SA) | (1) Tiếp tục chạy `sa-1-context` Bước 3 (Hiện trạng — AS-IS, §4) cho e-commerce trong khi BA **vẫn chưa** qua G1 và AG1 vẫn chưa từng chạy — tiếp nối `DEC-01`/`DEC-03`; người dùng tái khẳng định muốn tiếp tục. (2) Trả lời và đóng `OQ-009`: chấp nhận dùng `SAD.md` v0.2 (approved nội bộ nhà thầu, KHÔNG phải kiến trúc đang chạy) và hồ sơ thầu làm **điểm khởi đầu tham khảo** cho một phương án ở Bước 4 (`OPT`), với điều kiện bắt buộc Bước 4 vẫn phải dựng và chấm điểm ≥1 phương án độc lập khác — không mặc định `SAD.md` là phương án thắng sẵn (tránh bẫy "một phương án duy nhất", `GUIDE.md`). | Điều phối dự án (đại diện PO, dự án chạy thử) — riêng phần (2) là ghi chú điều phối, không phải PO/Tech Lead ký trực tiếp qua tác vụ `sign` | 2026-09-12 | ~3–4 cho (1) (giống `DEC-03`, ngoại lệ gate tạm thời, tiếp nối tiền lệ); ~4–5 cho (2) (ảnh hưởng cách tổ chức toàn bộ Bước 4 `OPT` · chi phí đảo ngược trung bình nếu phải bỏ neo `SAD.md` sau này và dựng lại từ đầu · chưa chạm `QAS` cụ thể · có điều kiện ràng buộc rõ ràng đi kèm (bắt buộc ≥1 phương án độc lập) nên giảm rủi ro thiên vị) | `CTX_e-commerce_v1.0.md (v1.2 trong header)` §0, §4, §7, §7.1, `OQ-009` (đóng) | +| DEC-05 (SA) | Tiếp tục chạy `sa-1-context` Bước 4 (Phương án — `OPT`) cho e-commerce trong khi BA **vẫn chưa** qua G1 và AG1 vẫn chưa từng chạy — tiếp nối `DEC-01`/`DEC-03`/`DEC-04`; người dùng tái khẳng định muốn tiếp tục. `OPT_e-commerce_v1.0.md` tạo mới: 3 phương án chấm điểm (P0, P1 theo `SAD.md`/hồ sơ thầu, P2 modular monolith + managed AWS — đối trọng độc lập) + 2 phương án bị loại (P3 mua/tích hợp nền tảng sẵn có, P4 serverless-first); khuyến nghị P2 có điều kiện, chưa PO/Tech Lead ký. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-12 | ~3–4 (chi phí đảo ngược thấp — nội dung `OPT` sửa lại khi có số thật không tốn nhiều · bán kính ảnh hưởng: quyết định kiến trúc GĐ2 phụ thuộc phương án chọn, nhưng việc ghi tài liệu dưới ngoại lệ thì nhỏ · chưa chạm `QAS` cụ thể (`QAS` chưa tồn tại) · không ràng buộc dài hạn (ngoại lệ tạm thời) · không tranh cãi mới, tiếp nối tiền lệ) | `OPT_e-commerce_v1.0.md` §0, `OQ-010…012` | +| DEC-06 (SA) | PO (uỷ quyền, Điều phối dự án) duyệt **từng phần** `OPT_e-commerce_v1.0.md` bản v1.0: chấp nhận bộ tiêu chí và trọng số mặc định (đóng `ASM-09`), bảng chấm điểm, hai phương án bị loại (P3, P4), và khuyến nghị P2 có điều kiện. **Chọn P2** (modular monolith + managed AWS, tách riêng Payment Service) làm nền cho Bước 5 (`TCO`/`ARISK`) và GĐ2, với điều kiện: (1) `OQ-010` — Tech Lead xác nhận đội thi công thật (không phải đề xuất hồ sơ thầu); (2) POC đo throughput SQS/EventBridge (`ASM-07`) ghi vào `ARISK` kèm kế hoạch ở Bước 5, trước khi chốt `ADR` message backbone GĐ2 (`OQ-012`). Ký thay PO theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký PO/Tech Lead thật**; `OQ-004` giữ mở, Tech Lead chưa ký. `Confidence`/Status của `OPT` **giữ nguyên** (🔴 / 🟡 Draft) — duyệt từng phần không phải AG1 toàn phần. Đóng `OQ-011` bằng chính quyết định này. 🔴 **Lưu ý:** "kiểu kiến trúc tổng thể" là quyết định thuộc danh mục thường đạt ngưỡng `ADR` bắt buộc (`decision-radar.md §3`) — `DEC-06` chỉ ghi nhận **hướng đi tạm** để bắt đầu Bước 5/GĐ2 dưới ngoại lệ gate hiện có, **không thay thế** yêu cầu viết `ADR` chính thức khi GĐ2 (`sa-2-architecture`) chốt kiểu kiến trúc, và ADR đó vẫn phải qua đủ điều kiện `Accepted` (POC/bài đo nếu radar ≥ 8) độc lập với `DEC-06`. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-12 | ~7 (chi phí đảo ngược cao hơn các `DEC` trước — đổi hướng kiến trúc tổng thể sau khi GĐ2 đã bắt đầu tốn > vài tuần · bán kính ảnh hưởng: toàn bộ GĐ2 (kiến trúc, ranh giới service, ADR) phụ thuộc trực tiếp · chưa chạm một `QAS` cụ thể đã tồn tại (GĐ1 chưa có `QAS`) nhưng ảnh hưởng gián tiếp toàn bộ chất lượng kiến trúc tương lai · ràng buộc trong khoảng GĐ2 cho tới khi có `ADR`/POC chính thức, không phải vĩnh viễn · chưa có tranh cãi mới — tiếp nối khuyến nghị SA). **Do thuộc danh mục "kiểu kiến trúc tổng thể" nên khuyến nghị nâng thành `ADR` chính thức ngay khi GĐ2 bắt đầu, không chỉ dừng ở `DEC-nn`** | `OPT_e-commerce_v1.0.md` (header, Change Log), `OQ-011` (đóng) | +| DEC-07 (SA) | Tiếp tục chạy `sa-1-context` Bước 5 (phần `TCO`) cho e-commerce trong khi BA vẫn chưa qua G1 và AG1 vẫn chưa từng chạy — tiếp nối `DEC-01/03/04/05`. `TCO_e-commerce_v1.0.md` tạo mới: chi phí 3 năm cho P2 (chính) và P1 (đối chiếu) theo 2 kịch bản tải, đơn giá AWS/tỷ giá gắn `ASM-11/12` (cần xác minh), 5 khoản non-labor chưa tính được (`NL-03/04/05/07/08`) chuyển thành `OQ-014…017`. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-12 | ~3–4 (giống `DEC-05`: chi phí đảo ngược thấp, chưa chạm `QAS` cụ thể, không ràng buộc dài hạn, tiếp nối tiền lệ) | `TCO_e-commerce_v1.0.md` (toàn bộ) | +| DEC-08 (SA) | Tiếp tục chạy `sa-1-context` Bước 5 (phần `ARISK`) cho e-commerce — tiếp nối `DEC-01/03/04/05/07`. `ARISK_e-commerce_v1.0.md` tạo mới: 10 rủi ro (`ARISK-01…10`), 2 kế hoạch POC bắt buộc (`POC-01` throughput SQS/EventBridge, `POC-02` RDS gộp tải) với tiêu chí pass/fail suy từ `DRV-04`, phải chạy xong trước `ADR` message backbone GĐ2. GĐ1 SA nay đủ 4 artifact để audit AG1. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-12 | ~3–4 (cùng lý lẽ `DEC-07`) | `ARISK_e-commerce_v1.0.md` (toàn bộ) | +| DEC-09 (SA) | PO (uỷ quyền, Điều phối dự án) duyệt **từng phần** `TCO_e-commerce_v1.0.md` bản v1.1 (sau khi sửa lỗi chép số §1 P2-B: "Vận hành/nhân sự (3 năm)" P2-B = 5.600 triệu, Tổng 3 năm P2-B = 13.977,5 triệu): chấp nhận cấu trúc 4 nhóm chi phí (hạ tầng AWS/license/vận hành/xây dựng một lần), 2 kịch bản tải A/B, và kết luận thứ tự tương đối **P2 rẻ hơn P1** ở cả hai kịch bản. **Chưa xác nhận**: đơn giá AWS (`ASM-11`), tỷ giá (`ASM-12`), số FTE vận hành (`ASM-14`), 5 khoản non-labor (`OQ-013…017`) — `Confidence` giữ 🔴. Ký thay PO theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký PO/Tech Lead thật**; `OQ-004` giữ mở, Tech Lead chưa ký. `TCO` giữ Status 🟡 Draft — duyệt từng phần không phải AG1 toàn phần. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-12 | ~3–4 (giống `DEC-07` — chi phí đảo ngược thấp, chưa chạm `QAS` cụ thể, không ràng buộc dài hạn, tiếp nối tiền lệ) | `TCO_e-commerce_v1.0.md` (header, Change Log) | +| DEC-10 (SA) | PO (uỷ quyền, Điều phối dự án) duyệt **từng phần** `ARISK_e-commerce_v1.0.md` bản v1.0: chấp nhận 10 rủi ro `ARISK-01…10` (chủ + biện pháp) và kế hoạch `POC-01` (SQS/EventBridge throughput) + `POC-02` (RDS gộp tải) với tiêu chí PASS/FAIL viết trước ở §6. **POC chưa chạy** — bắt buộc chạy xong trước khi chốt `ADR` message backbone GĐ2. Ký thay PO theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký PO/Tech Lead thật**; `OQ-004` giữ mở, Tech Lead/PM chưa ký. `ARISK` giữ Status 🟡 Draft, `Confidence` 🔴 — duyệt từng phần không phải AG1 toàn phần. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-12 | ~3–4 (cùng lý lẽ `DEC-09`; POC chưa chạy nên chưa thể nâng radar cho quyết định kiến trúc liên quan) | `ARISK_e-commerce_v1.0.md` (header, Change Log) | +| DEC-11 (SA) | Bắt đầu `sa-2-architecture` (hoạt động 1 — `QAS`) cho e-commerce dù AG1 (gate GĐ1 SA) chưa có chữ ký PO/Tech Lead thật (audit 2026-09-12: AG1 🟠 — 4 artifact GĐ1 duyệt từng phần bởi PO uỷ quyền, `Confidence` 🔴 toàn bộ; `POC-01`/`POC-02` chưa chạy; BA chưa ký G1 cho `BRIEF_CartCheckout`) — tiếp nối `DEC-01…10`. Người dùng (điều phối dự án) tái khẳng định muốn tiếp tục. Toàn bộ 14 `QAS` mới giữ `Confidence` 🔴 cho tới khi: (a) PO/Tech Lead ký AG1 thật; (b) `POC-01`/`POC-02` chạy xong; (c) các con số SA tự đề xuất (`QAS-003/004/007/014`) được PO/Tech Lead xác nhận qua `OQ-018…023`. Không tạo `ADR` riêng cho việc chạy dưới ngoại lệ (khác quyết định kiến trúc P2, vẫn cần `ADR` ở hoạt động `asr`/`adr` kế tiếp). | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-14 | ~4 (chi phí đảo ngược thấp — sửa `QAS` khi có số thật không tốn nhiều · bán kính ảnh hưởng: toàn bộ GĐ2 phụ thuộc `QAS` nhưng việc ghi tài liệu dưới ngoại lệ thì nhỏ · có chạm `QAS` Must trực tiếp (đang tạo chính nó) nhưng chưa phải quyết định kiến trúc đã cam kết · không ràng buộc dài hạn (ngoại lệ tạm thời) · không tranh cãi mới, tiếp nối tiền lệ) | `QAS_e-commerce_v1.0.md` (toàn bộ), `OQ-018…023` | +| DEC-12 (SA) | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) duyệt **từng phần** `QAS_e-commerce_v1.0.md` bản v1.0: chấp nhận 14 `QAS-001…014` đủ 6 phần và cách đo (Phần A); chấp nhận **TẠM** các số SA tự đề xuất — `QAS-003` p95 ≤500ms, `QAS-004` p95 ≤300ms, `QAS-007` loại trừ bảo trì ≤2 giờ/tháng, `QAS-014` đối soát ≤15 phút — làm baseline tạm; **`OQ-018…021` giữ nguyên mở**, chờ PO/Tech Lead thật xác nhận số cuối cùng. Chốt thêm điều kiện mới: diễn tập DR (`QAS-008`) **phải thực hiện trước khi ký AG2** — cập nhật `OQ-022` thành điều kiện tiên quyết của AG2, cũng là input bắt buộc cho hoạt động `inf` khi tới lượt. Ký thay Tech Lead theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký Tech Lead thật**; Security/Ops/SRE **chưa ký**; `OQ-004` giữ mở. `Confidence`/Status của `QAS` **giữ nguyên** (🔴 / 🟡 Draft) — duyệt từng phần không phải AG2 toàn phần, không phải bằng chứng nguồn mới nên không nâng `Confidence`. | Điều phối dự án (đại diện PO/Tech Lead, dự án chạy thử) | 2026-09-14 | ~4 (giống `DEC-11` — chi phí đảo ngược thấp (sửa số khi có PO/Tech Lead thật không tốn nhiều) · bán kính ảnh hưởng: toàn bộ GĐ2 phụ thuộc `QAS` này nhưng bản thân việc ký thay/duyệt từng phần thì nhỏ · có chạm `QAS` Must trực tiếp (chính các `QAS` đang được duyệt) nhưng chưa phải cam kết thi công · không ràng buộc dài hạn (điều kiện AG2 có thể điều chỉnh khi Ops/SRE xác nhận lịch thật) · không tranh cãi mới, tiếp nối tiền lệ `DEC-06/09/10`) | `QAS_e-commerce_v1.0.md` (header, Change Log), `OQ-022` (cập nhật, không đóng) | +| DEC-13 (SA) | Tiếp tục `sa-2-architecture` (hoạt động 2 — `ASR`) cho e-commerce dù AG1 chưa có chữ ký PO/Tech Lead thật và AG2 chưa tới hạn — tiếp nối `DEC-01…12`. Người dùng (điều phối dự án) tái khẳng định muốn tiếp tục. `ASR_e-commerce_v1.0.md` tạo mới — 15 `ASR` chưng cất từ `DRV`/`CON`/`QAS`/`BR-CART`/`ROLE`, mỗi cái có nguồn, "vì sao định hình kiến trúc", và `ADR` ứng viên (12/15 có ứng viên, radar ước lượng 4–9; `ADR-001` kiểu kiến trúc tổng thể P2 vẫn là nợ từ `DEC-06`, chưa viết). Thêm `OQ-024/025`, `ASM-19…21`. Không viết `ADR` nào ở lượt này. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-14 | ~4 (chi phí đảo ngược thấp — chưng cất từ tài liệu đã có, sửa lại không tốn nhiều nếu nguồn đổi · bán kính ảnh hưởng: toàn bộ hoạt động `sad`/`adr` kế tiếp phụ thuộc nhưng việc ghi tài liệu dưới ngoại lệ thì nhỏ · có chạm `QAS` Must trực tiếp (đang chưng cất từ chính các `QAS` Must) nhưng chưa phải quyết định kiến trúc đã cam kết · không ràng buộc dài hạn · không tranh cãi mới, tiếp nối tiền lệ `DEC-11/12`) | `ASR_e-commerce_v1.0.md` (toàn bộ), `OQ-024/025` | +| DEC-14 (SA) | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) duyệt **từng phần** `ASR_e-commerce_v1.0.md` bản v1.0: chấp nhận 15 `ASR-001…015` (14 `Must` + 1 `Should`) đủ nguồn/"vì sao định hình kiến trúc" và danh sách 12 `ADR` ứng viên (`ADR-001…012`, §B2) với radar ước lượng đã ghi kèm. Xác nhận **`ADR-005`/`ADR-006`/`ADR-009`** (radar ước lượng ≥8) **chỉ được chuyển `Accepted`** sau khi `POC-01` (SQS/EventBridge), `POC-02` (RDS gộp tải), và diễn tập DR (Ops/SRE) chạy xong — đúng `decision-radar.md §2`/§6, không ký tắt qua bước đo. Chốt **TẠM** `OQ-024` (phương thức MFA Admin = TOTP app, theo `ASM-20`) và `OQ-025` (không dịch nội dung seller tự nhập ở MVP, chỉ i18n UI hệ thống, theo `ASM-21`) làm hướng đi tạm cho `sad`/`sec` kế tiếp — **`OQ-024`/`OQ-025` giữ nguyên MỞ**, chờ Security/PO thật xác nhận, không coi là đã đóng. Ký thay Tech Lead theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký Tech Lead thật**; Security/Ops/SRE **chưa ký**; `OQ-004` giữ mở. `Confidence`/Status của `ASR` **giữ nguyên** (🔴 / 🟡 Draft) — duyệt từng phần không phải AG2 toàn phần, không phải bằng chứng nguồn mới nên không nâng `Confidence`. | Điều phối dự án (đại diện PO/Tech Lead, dự án chạy thử) | 2026-09-15 | ~4 (giống `DEC-12` — chi phí đảo ngược thấp (sửa `ASR`/`ADR` ứng viên khi có PO/Tech Lead thật không tốn nhiều) · bán kính ảnh hưởng: toàn bộ hoạt động `sad`/`adr` kế tiếp phụ thuộc danh sách này nhưng bản thân việc ký thay/duyệt từng phần thì nhỏ · có chạm `QAS` Must trực tiếp (chính các `ASR` đang được duyệt, chưng cất từ `QAS` Must) nhưng chưa phải cam kết thi công (chưa có `ADR` nào `Accepted`) · không ràng buộc dài hạn (các `ADR` ứng viên vẫn `Proposed`, chưa `Accepted`) · không tranh cãi mới, tiếp nối tiền lệ `DEC-06/09/10/12`) | `ASR_e-commerce_v1.0.md` (header, Change Log), `OQ-024/025` (cập nhật, không đóng) | +| DEC-15 (SA) | Tiếp tục `sa-2-architecture` (hoạt động 3 — `SAD`) cho e-commerce dù AG1 chưa có chữ ký PO/Tech Lead thật và AG2 (gate của chính GĐ2) chưa tới hạn — tiếp nối `DEC-01…14`. Người dùng (điều phối dự án) tái khẳng định muốn tiếp tục. `SAD_e-commerce_v1.0.md` tạo mới — C4 Context (4 actor + 5 hệ ngoài), C4 Container (Mermaid, legend theo `D4`), C4 Component cho container "Nhóm Giao dịch" (Cart & Order), 2 sequence diagram (checkout, webhook+đối soát), deployment view AWS `ap-southeast-1` đối chiếu `TCO §3.2` (phát hiện 1 điểm lệch mức chi tiết giữa ranh giới 2 nhóm triển khai của `ASR-001`/`ASR-014` và cách `TCO` tính gộp compute — ghi `OQ-026`, không tự đổi số `TCO`), bảng `CMP-01…15` (ma trận `ASR-001…015` × `CMP` đủ 15/15, không `CMP` mồ côi), 22 `IF-nn` ứng viên cho `ICD` (hoạt động 4), thực thể dữ liệu sở hữu ứng viên cho `DAT` (hoạt động 5), phụ thuộc vượt ranh giới process ứng viên cho `FAIL` (hoạt động 8). Đánh dấu 12 chỗ chờ `ADR-001…012` (không viết `ADR` nào). Thêm `OQ-026/027` (khớp số ECS Fargate với `TCO`; vị trí nhóm triển khai của Identity & Access), `ASM-22/23`. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-15 | ~4 (chi phí đảo ngược thấp — bản vẽ C4 sửa lại khi `ADR-001` đổi hướng không tốn nhiều so với đã code · bán kính ảnh hưởng: hoạt động `icd`/`dat`/`sec`/`inf`/`fail` kế tiếp phụ thuộc `SAD` này nhưng việc ghi tài liệu dưới ngoại lệ thì nhỏ · có chạm `QAS`/`ASR` Must trực tiếp (đang hiện thực hoá thành component) nhưng chưa phải cam kết thi công (chưa `ADR` nào `Accepted`) · không ràng buộc dài hạn tự thân (văn bản sửa được qua version mới, khác `ADR` bất biến) · không tranh cãi mới, tiếp nối tiền lệ `DEC-11…14`) | `SAD_e-commerce_v1.0.md` (toàn bộ), `OQ-026/027` | +| DEC-16 (SA) | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) duyệt **từng phần** `SAD_e-commerce_v1.0.md` bản v1.0: chấp nhận C4 Context/Container/Component (Cart & Order), deployment view, bảng `CMP-01…15` và ma trận `ASR-001…015` × `CMP` đủ 15/15 (không `CMP` mồ côi), 22 `IF-nn` ứng viên cho `ICD`, và 12 chỗ chờ `ADR-001…012` (kế thừa nguyên trạng từ `ASR §B2`/`DEC-14`, không đổi radar). Chốt **TẠM** `OQ-026` (P2 có 2 ECS Fargate service riêng — Nhóm Giao dịch/Nhóm Hỗ trợ — để scale độc lập, `TCO §3.2` giữ nguyên tới khi hoạt động `inf` xác nhận, theo `ASM-23`) và `OQ-027` (Identity & Access thuộc Nhóm Giao dịch, theo `ASM-22`) làm hướng đi tạm cho `icd`/`dat`/`sec`/`inf`/`fail` kế tiếp — **`OQ-026`/`OQ-027` giữ nguyên MỞ**, chờ Tech Lead/Ops thật xác nhận, không coi là đã đóng. Ký thay Tech Lead theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký Tech Lead thật**; Security/Ops/SRE **chưa ký**; `OQ-004` giữ mở. `Confidence`/Status của `SAD` **giữ nguyên** (🔴 / 🟡 Draft) — duyệt từng phần không phải AG2 toàn phần, không phải bằng chứng nguồn mới nên không nâng `Confidence`. | Điều phối dự án (đại diện PO/Tech Lead, dự án chạy thử) | 2026-09-15 | ~4 (giống `DEC-12`/`DEC-14` — chi phí đảo ngược thấp (sửa `SAD`/`CMP` khi có PO/Tech Lead thật không tốn nhiều) · bán kính ảnh hưởng: toàn bộ hoạt động `icd`/`dat`/`sec`/`inf`/`fail`/`adr` kế tiếp phụ thuộc `SAD` này nhưng bản thân việc ký thay/duyệt từng phần thì nhỏ · có chạm `QAS`/`ASR` Must trực tiếp (đang hiện thực hoá thành component) nhưng chưa phải cam kết thi công (chưa `ADR` nào `Accepted`) · không ràng buộc dài hạn (deployment view sửa được qua version mới, khác `ADR` bất biến) · không tranh cãi mới, tiếp nối tiền lệ `DEC-06/09/10/12/14`) | `SAD_e-commerce_v1.0.md` (header, Change Log), `OQ-026/027` (cập nhật, không đóng) | +| DEC-17 (SA) | Tiếp tục `sa-2-architecture` (hoạt động 9 — `adr`) cho e-commerce trong khi AG1 chưa có chữ ký PO/Tech Lead thật và AG2 (gate của chính GĐ2) chưa tới hạn — tiếp nối `DEC-01…16`. Người dùng (điều phối dự án) tái khẳng định muốn tiếp tục. Viết đủ `ADR-001…012` trong `02-architecture/adr/`, mỗi ADR có Bối cảnh (truy về `ASR`/`QAS`/`DRV`/`CON` nguồn), Phương án đã cân nhắc (≥2, có phương án bị loại + lý do gắn `CON`/`QAS`), Quyết định, Hệ quả (tích cực/tiêu cực/nợ kỹ thuật), Radar (điểm + căn cứ), Điều kiện chuyển `Accepted`, Cách kiểm chứng (`FIT` ứng viên cho GĐ3), Supersedes/Related. **Tất cả 12 ADR giữ Status `Proposed`** — không ADR nào `Accepted` vì chưa có chữ ký thật (Tech Lead + Security + Ops/SRE); `ADR-005`/`ADR-006`/`ADR-009` (radar ≥8) ghi rõ điều kiện `Accepted` là `POC-01`/`POC-02`/diễn tập DR PASS (đúng `decision-radar.md §2`/§6); `ADR-008` (PII) ghi phủ quyết Security/Legal, chặn hoàn toàn tới khi PO chỉ định người (`OQ-007`). Cập nhật `ADL_e-commerce.md` (mục lục 12 ADR, radar, nguồn, `ASR` phục vụ; `DEC-06` được ghi nhận là đã trả nợ). Cập nhật `SAD_e-commerce_v1.0.md` §8 lên v1.1 (chỉ thay cột "chưa viết" bằng link file ADR thật, không đổi nội dung chuyên môn khác của `SAD`). Không sửa `ASR`/`QAS` đã duyệt từng phần. `Confidence` 🔴 toàn bộ 12 ADR (chưa ai ký thật). | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-15 | ~4 (chi phí đảo ngược thấp — *việc ghi 12 ADR dưới ngoại lệ gate* thì sửa lại không tốn nhiều khi có chữ ký thật, khác với *nội dung từng ADR* vốn đã được chấm radar riêng biệt trong từng file (6–9) · bán kính ảnh hưởng: AG2 phụ thuộc trực tiếp 12 ADR này nhưng bản thân hành vi "chạy dưới ngoại lệ" thì nhỏ · có chạm `QAS`/`ASR` Must trực tiếp (đang hình thức hoá quyết định) nhưng chưa cam kết thi công (không ADR nào `Accepted`) · không ràng buộc dài hạn tự thân (ADR giữ `Proposed`, chưa bất biến) · không tranh cãi mới, tiếp nối tiền lệ `DEC-11…16`) → **ghi `DEC-nn` cho việc chạy dưới ngoại lệ, không cần thêm `ADR` cho chính hành vi này** (`decision-radar.md §1–§2`) — tách biệt với 12 `ADR` nội dung đã viết. **Hệ quả nếu không chấp nhận ngoại lệ:** dừng GĐ2 ở hoạt động `sad`, không có `ADR` chính thức nào cho 12 quyết định đã đạt ngưỡng radar 5–7/8–9 — AG2 không thể tự chấm mục "`ADR-nnn` tồn tại cho mọi quyết định đạt ngưỡng radar", và `DEC-06` (GĐ1) tiếp tục treo như một khoản nợ chưa trả. | `ADR-001…012` (toàn bộ), `ADL_e-commerce.md`, `SAD_e-commerce_v1.0.md §8` (v1.1) | +| DEC-18 (SA) | Tiếp tục `sa-2-architecture` (hoạt động 4 — `ICD`) cho e-commerce trong khi AG1 chưa có chữ ký PO/Tech Lead thật và AG2 (gate của chính GĐ2) chưa tới hạn — tiếp nối `DEC-01…17`. Người dùng (điều phối dự án) tái khẳng định muốn tiếp tục. `ICD_e-commerce_v1.0.md` tạo mới — catalog cho 17/17 `IF-nn` truy được từ `SAD §4` (chênh lệch với con số "22" của `SAD` được ghi nhận ở `OQ-029`, không bịa thêm 5 ID); chi tiết đầy đủ cho `IF-002` (4 endpoint Cart & Checkout: `GET`/`PATCH`/`DELETE /v1/cart*`, `POST /v1/checkout`), `IF-005/006/007/008/009/015/021/022`. Xác nhận/điều chỉnh toàn bộ `API_US002-003_v1.0.md` của BA tại §5 (6 xác nhận, 3 điều chỉnh có lý do gắn `QAS-003`/`ADR-003`, 1 chờ `OQ-030(BA)`) — đóng đề xuất cho `OQ-034(BA)`/`OQ-032(BA)` (BA cần tự cập nhật sổ để đóng chính thức). Thêm `OQ-028…033`, `ASM-24…26`. Không sửa `SAD`/`ASR`/`QAS`/`ADR` đã có. `Confidence` 🔴 toàn bộ. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-15 | ~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. | `ICD_e-commerce_v1.0.md` (toàn bộ), `OQ-028…033` | +| DEC-19 (SA) | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) duyệt **từng phần** `ICD_e-commerce_v1.0.md` bản v1.0: chấp nhận catalog 17 `IF-nn` (§2), chi tiết đầy đủ `IF-002` (4 endpoint Cart & Checkout, §3.1), 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 (nhóm `GET /v1/cart` theo seller; `sellerName` denormalize snapshot thay vì join runtime; thêm `unitPriceSnapshotVnd`/`currentPriceVnd`/`priceChanged`; Guest ownership dùng cùng cơ chế `403 ERR_FORBIDDEN_OWNERSHIP` theo `ADR-007`). Chấp nhận **TẠM** `ASM-24` (`IF-021` là cross-network, không in-process), `ASM-25` (chiều gọi `IF-022` là Cart&Order → Seller Management), `ASM-26` (Payment Service nhận `sellerId` ngay tại `IF-006`), và hướng denormalize `sellerName` đề xuất ở `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: 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 thay đổ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**; Security/Ops/SRE **chưa ký**; `OQ-004` giữ mở. `Confidence`/Status của `ICD` **giữ nguyên** (🔴 / 🟡 Draft) — duyệt từng phần không phải AG2 toàn phần, không phải bằng chứng nguồn mới nên không nâng `Confidence`. Nhắc BA chạy `ba-pipeline` hoạt động `specification` để cập nhật `API_US002-003`/`SRS_US002-003` theo `ICD §5`. | Điều phối dự án (đại diện PO/Tech Lead, dự án chạy thử) | 2026-09-15 | ~4 (giống `DEC-12/14/16` — chi phí đảo ngược thấp (sửa `ICD` khi có Tech Lead thật không tốn nhiều) · bán kính ảnh hưởng: toàn bộ hoạt động `dat`/`sec`/`inf`/`fail` kế tiếp và dev BE/FE phụ thuộc `ICD` này nhưng bản thân việc ký thay/duyệt từng phần thì nhỏ · có chạm trực tiếp việc xác nhận `API` của BA (đã làm) nhưng chưa phải cam kết thi công (chưa ai ký thật) · không ràng buộc dài hạn (contract sửa được qua version mới) · không tranh cãi mới, tiếp nối tiền lệ `DEC-06/09/10/12/14/16`) | `ICD_e-commerce_v1.0.md` (header, Change Log), `OQ-028…033` (cập nhật, không đóng) | +| DEC-20 (SA) | Tiếp tục ngoại lệ gate cho e-commerce (AG1 chưa ký thật, AG2 chưa tới hạn) — tiếp nối `DEC-01…19` — để **sửa lỗi nhất quán** trong `SAD_e-commerce_v1.0.md` (lên v1.2) theo phát hiện của hoạt động `icd` (`OQ-028` mâu thuẫn in-process/cross-network của `IF-021`; `OQ-029` chênh lệch "22 vs 17" `IF-nn`), theo yêu cầu người duyệt 2026-09-15. Đây là **sửa lỗi tài liệu**, không phải quyết định kiến trúc mới — không cần `ADR`, không đổi `CMP`. Kết luận: (1) `IF-021`/`IF-022` (Cart&Order ↔ Promotion&Loyalty/Seller Management) là cross-network REST giữa 2 ECS Fargate service riêng (Nhóm Giao dịch/Nhóm Hỗ trợ), không phải in-process — sửa thống nhất ở legend §4, footnote §4.1, §5, bảng §6.1/§6.3, bổ sung cạnh mạng còn thiếu ở §7 (đánh dấu 🔴 chờ `inf` thiết kế đường kết nối thật); `IF-005` (in-process, cùng Nhóm Giao dịch) và `IF-006` (cross-network, Payment) không đổi. (2) "22 `IF-nn`" là đếm nhầm ở bản gốc — đúng 17 ID (`IF-001…009, 015…022`), không bỏ sót interface nào — sửa "22"→"17" ở header/Change Log/Tự chấm của `SAD`. Đóng `OQ-029` trong sổ `00-index/OQ_e-commerce.md` (SA); `OQ-028` giữ nguyên mở (chờ Tech Lead thật xác nhận ranh giới mạng, dù `SAD` nay đã hết mâu thuẫn nội bộ). Không sửa §8 (`ADR` links), không sửa `ASR`/`QAS`/`ADR`/`ICD`. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-15 | ~3 (chi phí đảo ngược rất thấp — thuần sửa lỗi mô tả/đếm số, không đổi cấu trúc `CMP`/quyết định kiến trúc · bán kính ảnh hưởng: làm rõ cho hoạt động `fail`/`inf` kế tiếp (mức ưu tiên `IF-021` cross-network) nhưng bản thân việc sửa lỗi thì nhỏ · không chạm `QAS`/`ASR` Must nào mới, chỉ làm nhất quán nội dung đã có · không ràng buộc dài hạn (sửa lỗi văn bản) · không tranh cãi — là sửa lỗi khách quan (đối chiếu sơ đồ với bảng), có tiền lệ `DEC-11…19`) | `SAD_e-commerce_v1.0.md` (v1.2), `OQ-029` (đóng), `OQ-028` (không đóng, ghi nhận SAD hết mâu thuẫn nội bộ) | +| DEC-21 (SA) | Tiếp tục `sa-2-architecture` (hoạt động 8 — `FAIL`) cho e-commerce dù AG1 chưa ký thật và AG2 (gate của chính GĐ2) chưa tới hạn — tiếp nối `DEC-01…20`. Người dùng (điều phối dự án) tái khẳng định muốn tiếp tục. `FAIL_e-commerce_v1.0.md` tạo mới — 13 phụ thuộc vượt ranh giới process theo `SAD` v1.2 §6.3 (VNPay, Momo, GHN, GHTK, Email/SMS, RDS chính, RDS Payment, Redis, SQS FIFO, EventBridge, `IF-006`, `IF-021` ưu tiên cao nhất, `IF-022`), mỗi cái đủ timeout/retry/idempotent/hết-retry-thì-sao và 4 câu hỏi `D6`. Dựng bảng ngân sách timeout cộng dồn đường găng checkout và **phát hiện xung đột**: timeout VNPay/Momo kế thừa 10s không dùng được nguyên trạng trong nhánh đồng bộ `IF-006`→`IF-007/008` vì một mình nó đã vượt `QAS-002` (≤3.000ms); ngay cả khi siết xuống 1.500ms, tổng cộng dồn vẫn vượt ngân sách ~7% (3.220ms) — trình 2 lựa chọn (siết thêm timeout vs bất đồng bộ hoá bước khởi tạo thanh toán) kèm hệ quả bằng số, không tự quyết (`OQ-034`). Thiết kế circuit breaker/backoff/bulkhead toàn hệ thống; suy giảm có kiểm soát (Promotion lỗi — đề xuất mặc định "bỏ qua, tiếp tục" nhưng không tự quyết, nối `OQ-017` của BA; COD khi VNPay/Momo lỗi; GHN↔GHTK fallback chéo theo `ASR-013`; phát hiện thiếu cache nội dung giỏ hàng thật cho fallback 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` (3 mã lỗi mới đề xuất cho US-004 Checkout, chưa có trong `SRS` của BA); đề xuất `FIT-16…22` (chaos test/kill dependency) cho GĐ3. Thêm `OQ-034…040`, `ASM-27…33`. Không sửa `SAD`/`ICD`/`ADR` đã có. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-15 | ~4 (chi phí đảo ngược thấp — số cấu hình timeout/retry/circuit breaker sửa được qua config, không phải viết lại kiến trúc; các quyết định kiến trúc nền đã có `ADR-004/005/007/009/011` riêng · bán kính ảnh hưởng: toàn bộ luồng checkout + mọi consumer 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) 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 · 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" — Dev tự chọn timeout/retry lúc code, không ai biết tổng thể hệ thống hỏng thế nào. | `FAIL_e-commerce_v1.0.md` (toàn bộ), `OQ-034…040` | +| DEC-22 (SA) | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) duyệt **từng phần** `FAIL_e-commerce_v1.0.md` bản v1.0: 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` (GĐ3). Chấp nhận **TẠM** (🔴) các ngưỡng SA đề xuất — circuit breaker §3.1 (`OQ-035`), DLQ retention 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`) — tất cả **giữ nguyên MỞ**, chờ Tech Lead/SRE thật xác nhận, không coi là đã đóng. **Quyết định `OQ-034`** (xung đột ngân sách timeout đường găng checkout, `FAIL §1.2`): chọn **Lựa chọn 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`, trả response trong ngân sách ~1.670ms, gọi VNPay/Momo sau response) để đảm bảo `QAS-002` (≤3.000ms) không phụ thuộc SLA bên thứ ba — thay vì Lựa chọn A (siết timeout hơn nữa, chấp nhận rủi ro tăng tỷ lệ lỗi init khi đối tác thật chậm). Yêu cầu SA (lượt kế tiếp): viết `ADR-013` (`Proposed`, `Supersedes` một phần sequence diagram `SAD §6.1`) và sửa nhất quán `SAD §6.1` + `FAIL §1.2` theo hướng B — **chưa thực hiện ở lượt sign này** (đúng nguyên tắc chỉ sửa header/Change Log/INDEX khi `sign`, không đổi nội dung chuyên môn). `OQ-034` cập nhật 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Ở**, không đóng (chưa có `ADR-013` thật, chưa Tech Lead/PO xác nhận chính thức). Ký thay Tech Lead theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký Tech Lead thật**; Security/Ops/SRE **chưa ký**; `OQ-004` giữ mở. `Confidence`/Status của `FAIL` **giữ nguyên** (🔴 / 🟡 Draft) — duyệt từng phần không phải AG2 toàn phần, không phải bằng chứng nguồn mới nên không nâng `Confidence`. | Điều phối dự án (đại diện PO/Tech Lead, dự án chạy thử) | 2026-09-15 | ~5 (chi phí đảo ngược trung bình — cao hơn các `DEC` sign trước của `FAIL` vì đây không chỉ là chấp nhận TẠM số cấu hình mà là **chọn hướng kiến trúc** (bất đồng bộ hoá bước khởi tạo thanh toán) ảnh hưởng sequence diagram `SAD §6.1` đã duyệt từng phần và cần thiết kế lại UX checkout (FE thêm bước chờ/poll `paymentRedirectUrl`) · bán kính ảnh hưởng: toàn bộ luồng checkout (`IF-006`/`IF-007`/`IF-008`) + FE + `ADR-013` mới · có chạm `QAS-002` Must trực tiếp (chính là lý do chọn B) nhưng `ADR-013` chưa viết nên chưa `Accepted`, chưa cam kết thi công · ràng buộc trung hạn (tới khi `ADR-013` viết xong và Tech Lead/PO thật xác nhận) · không tranh cãi mới về mặt lập luận kỹ thuật (SA đã khuyến nghị B ở §1.2) nhưng là quyết định hướng đầu tiên trong chuỗi `DEC` của `FAIL`, tiếp nối tiền lệ `DEC-12/14/16/19`) | `FAIL_e-commerce_v1.0.md` (header, Change Log), `OQ-034` (cập nhật, không đóng), `OQ-035/036/037` (cập nhật, không đóng) | +| DEC-23 (SA) | Tiếp tục `sa-2-architecture` (hoạt động `adr`, phạm vi hẹp — chỉ `ADR-013` + sửa nhất quán tối thiểu) cho e-commerce dù AG1 chưa ký thật và AG2 (gate của chính GĐ2) chưa tới hạn — tiếp nối `DEC-01…22`. Người dùng (điều phối dự án) tái khẳng định muốn tiếp tục. Viết `adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md` (`Proposed`, radar 7/10) hiện thực hoá đầy đủ Lựa chọn B đã chọn ở `OQ-034`/`DEC-22`: mô tả state machine `Order` (`PENDING_PAYMENT_INIT`→`PAYMENT_INIT_READY`/`PAYMENT_INIT_FAILED`), cơ chế trigger async qua message `PaymentInitRequested` (tái dùng `ADR-005`), idempotency (tái dùng `ADR-004`), hành vi khi init thất bại (thử lại/chuyển COD); nêu đủ 3 phương án (A siết timeout — loại, B — chọn, C giữ đồng bộ chấp nhận vượt `QAS-002` — loại vì vi phạm `D10`); hệ quả tích cực/tiêu cực, việc phát sinh (BA viết `SRS`/`AC` US-004, `ICD` lượt sau chốt endpoint polling/retry/chuyển COD). Sửa nhất quán tối thiểu: `SAD_e-commerce_v1.0.md` lên v1.3 (§6.1 sequence diagram chèn nhánh rẽ COD/online + bất đồng bộ, §8 thêm dòng `ADR-013`) và `FAIL_e-commerce_v1.0.md` lên v1.1 (§1.2 tách đường găng đồng bộ bước 1–6+COD/10 khỏi bước khởi tạo VNPay/Momo bất đồng bộ, kết quả tổng đồng bộ ≤3.000ms cho cả hai nhánh). Không sửa nội dung khác của `SAD`/`FAIL`, không viết ADR nào khác, không sửa 12 ADR cũ (`ADR-001…012`). `OQ-034` cập nhật "đã chọn hướng B, đã có `ADR-013`, chờ Tech Lead + PO thật xác nhận" — giữ mở. Thêm `OQ-041`/`OQ-042` (cơ chế FE polling/SSE; thời gian giữ `Order` chờ init trước khi coi là kẹt). Cập nhật `ADL_e-commerce.md` (thêm `ADR-013 Proposed`) và `DTM_e-commerce.md` (`ASR-004`/`QAS-002` → `ADR-013`). `Confidence` 🔴 toàn bộ. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-15 | ~4 (chi phí đảo ngược thấp cho *việc ghi tài liệu dưới ngoại lệ* — khác điểm radar 7/10 của chính nội dung `ADR-013` đã chấm riêng trong file đó · bán kính ảnh hưởng: `SAD`/`FAIL` đã tồn tại, chỉ sửa đúng 2 mục theo yêu cầu người duyệt, không viết lại toàn bộ · chạm `QAS-002` Must gián tiếp (đang sửa cách đạt nó, không hạ chuẩn) · không ràng buộc dài hạn tự thân (khác `ADR-013`) · không tranh cãi mới, tiếp nối tiền lệ `DEC-11…22`) → **ghi `DEC-nn` cho việc chạy dưới ngoại lệ, không cần `ADR` riêng** — tách biệt với `ADR-013` (nội dung, đã chấm radar riêng). **Hệ quả nếu không chấp nhận ngoại lệ:** `OQ-034` tiếp tục treo ở "đã chọn B nhưng chưa có ADR", Dev không có tài liệu chính thức để thi công lại luồng checkout, `SAD`/`FAIL` tiếp tục mô tả một luồng đã biết vượt ngân sách `QAS-002`. | `ADR-013` (mới), `SAD_e-commerce_v1.0.md` (v1.3), `FAIL_e-commerce_v1.0.md` (v1.1), `OQ-034` (cập nhật, không đóng), `OQ-041/042` (mới) | +| DEC-24 (SA) | Tiếp tục `sa-2-architecture` (hoạt động 5 — `DAT`) cho e-commerce dù AG1 chưa ký thật và AG2 (gate của chính GĐ2) chưa tới hạn — tiếp nối `DEC-01…23`. `DAT_e-commerce_v1.0.md` tạo mới — bảng ownership `D7` cho toàn bộ 15 `CMP`, mô hình `Order`/`OrderSeller`/`OrderItem` chi tiết theo `ADR-003`/`ADR-013`, phân loại PII/Payment/nghiệp vụ + đề xuất retention (chờ Legal, `OQ-007`) và whitelist chia sẻ seller theo `ADR-008`, chiến lược đọc/ghi/consistency/idempotency, đề xuất Transactional Outbox (ADR ứng viên, chưa viết — `OQ-044`), backup/PITR, migration/versioning, dữ liệu đối soát và job dọn `Order` kẹt. Đối chiếu `docs/05` P1 — phát hiện thiếu `CMP` Audit & Compliance (`OQ-047`). Thêm `OQ-043…047`, cập nhật `OQ-007/040/042`, `ASM-35…38`. Không sửa `SAD`/`ICD`/`FAIL`/`ADR`. `Confidence` 🔴 toàn bộ. *(Ghi bổ sung: dòng này bị thiếu ở lượt chạy trước, bổ sung lại khi sign `DEC-25` để không đứt mạch — không đổi nội dung `DAT` đã ghi.)* | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-15 | ~4 (giống `DEC-21` — chi phí đảo ngược thấp, ghi tài liệu thiết kế chưa có dòng code phụ thuộc · bán kính ảnh hưởng: `sec`/`inf` kế tiếp và dev BE dùng `DAT` làm nguồn sự thật ownership · có chạm `QAS-003/004/006/008/011/014` Must trực tiếp nhưng chưa phải cam kết thi công · không ràng buộc dài hạn tự thân · không tranh cãi mới, tiếp nối tiền lệ `DEC-11…23`) | `DAT_e-commerce_v1.0.md` (toàn bộ), `OQ-043…047` | +| DEC-25 (SA) | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) duyệt **từng phần** `DAT_e-commerce_v1.0.md` bản v1.0: chấp nhận bảng ownership 15 `CMP` (§1), mô hình `Order`/`OrderSeller`/`OrderItem` + `payment_init_status` (`ADR-013`, §2), snapshot giá/`sellerName`, idempotency store cho `POST /v1/checkout` (§4.2), PITR RPO ≤15 phút (§9). Chấp nhận **TẠM** (🔴): `ASM-35` (1 `Order` = 1 `Payment`) — `OQ-043` **giữ nguyên MỞ**; chọn **Transactional Outbox** (không phải job quét PA-1) cho khoảng trống `FAIL §7` — yêu cầu SA viết `ADR-014` (`Proposed`) ở lượt hoạt động `adr` kế tiếp, `OQ-044` **giữ MỞ** tới khi có ADR; chọn phương án (a) — mỗi module tự ghi `audit_log` riêng trong schema của mình cho `OQ-047`, **không thêm `CMP-16`** Audit tập trung; ngưỡng job quét `Order` kẹt ở `PENDING_PAYMENT_INIT` **5 phút** cho `OQ-042`; cơ chế FE lấy `redirectUrl` là **polling** cho `OQ-041` — cả bốn `OQ-041/042/044/047` **giữ nguyên MỞ**, chờ Tech Lead thật xác nhận, không coi là đã đóng. `OQ-045` (Flyway/Liquibase) và `OQ-046` (routing read replica) **giữ nguyên MỞ**, không có hướng TẠM nào được chốt. **§5 (phân loại PII/retention/whitelist chia sẻ seller) CHƯA CÓ HIỆU LỰC** — nằm ngoài phạm vi duyệt lần này, chờ đại diện Pháp chế/Bảo mật phủ quyết (`OQ-007`). Ký thay Tech Lead theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký Tech Lead thật**; Security/Ops/SRE **chưa ký**; `OQ-004` giữ mở. `Confidence`/Status của `DAT` **giữ nguyên** (🔴 / 🟡 Draft) — duyệt từng phần không phải AG2 toàn phần, không phải bằng chứng nguồn mới nên không nâng `Confidence`. | Điều phối dự án (đại diện PO/Tech Lead, dự án chạy thử) | 2026-09-15 | ~4 (giống `DEC-12/14/16/19` — chi phí đảo ngược thấp (sửa `DAT` khi có Tech Lead/DBA thật không tốn nhiều, chưa có dòng migration nào chạy) · bán kính ảnh hưởng: toàn bộ hoạt động `sec`/`inf` kế tiếp và dev BE dùng `DAT` làm nguồn sự thật ownership, nhưng bản thân việc ký thay/duyệt từng phần thì nhỏ · có chạm `QAS-003/004/006/008/011/014` Must trực tiếp (đang duyệt cách hiện thực hoá) nhưng chưa phải cam kết thi công (idempotency/outbox chưa viết `ADR`/code) · không ràng buộc dài hạn tự thân (văn bản `DAT` sửa được qua version mới) · không tranh cãi mới, tiếp nối tiền lệ `DEC-06/09/10/12/14/16/19/22`) | `DAT_e-commerce_v1.0.md` (header, Change Log), `OQ-041/042/044/047` (cập nhật, không đóng) | +| DEC-26 (SA) | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) **review nội dung** `adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md`: chấp nhận nội dung §3 (state machine `PENDING_PAYMENT_INIT`/`PAYMENT_INIT_READY`/`PAYMENT_INIT_FAILED`, timeout async 10s, idempotency, hành vi thất bại) làm cơ sở thiết kế tiếp (`ICD`/`DAT`/FE). **KHÔNG** đề nghị chuyển `Accepted` — `ADR-013` **giữ nguyên `Proposed`** vì chưa có chữ ký thật Tech Lead + PO (`ADR-013 §7`) và BA chưa viết `SRS`/`AC` cho US-004 (`OQ-034`). Ghi dòng "Reviewed (Proposed giữ nguyên)" ở `ADR-013 §9` — cùng mẫu với 12 ADR trước (`ADR-001…012`). Ký thay Tech Lead theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký Tech Lead thật**. `Confidence` 🔴; `AG2` chưa ký. | Điều phối dự án (đại diện PO/Tech Lead, dự án chạy thử) | 2026-09-15 | ~7 *(radar gốc của chính `ADR-013`, không đổi bởi việc review — chi phí đảo ngược cao (>4 tuần, đã lộ FE) · bán kính ảnh hưởng Cart&Order/Payment/FE/BA/ICD · chạm `QAS-002` Must trực tiếp · ràng buộc trung hạn · không tranh cãi mới)* | `adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md §9`, `00-index/ADL_e-commerce.md` | +| DEC-27 (SA) | Tiếp tục `sa-2-architecture` (hoạt động 6 — `SEC`) cho e-commerce dù AG1 chưa ký thật và AG2 (gate của chính GĐ2) chưa tới hạn — tiếp nối `DEC-01…26`. Người dùng (điều phối dự án) tái khẳng định muốn tiếp tục. `SEC_e-commerce_v1.0.md` tạo mới — threat model STRIDE cho 8 ranh giới tin cậy (`THR-01…31`, mỗi cái truy về `QAS`/`ASR`/`ADR` nguồn); mô hình authn (Guest/Customer/Seller/Admin, phát hiện khoảng trống service-to-service authn giữa Nhóm Giao dịch↔Nhóm Hỗ trợ↔Payment — đề xuất PA-3 service JWT, radar ~5, `ADR` bắt buộc chưa viết, `OQ-050`); mô hình authz (map đủ 2/2 `ROLE-nn` của `RBAC_CartCheckout`, chỗ ra quyết định = service theo `ADR-007`, fail-closed `E-CART-0007`); phân loại/mã hoá/masking PII và tuân thủ PCI-DSS/NĐ13/2023 — **toàn bộ đánh dấu "đề xuất chờ Legal/Security phủ quyết"** vì chưa có người (`OQ-007`); webhook: chưa bịa cơ chế chữ ký cụ thể của VNPay/Momo/GHN/GHTK (chưa có tài liệu đối tác, `OQ-049`, `ARISK-03/04`); trả lời `OQ-023` bằng đề xuất số cụ thể (30 req/phút Guest cart) kèm hệ quả hai chiều, không tự quyết thay Security; secret management (Secrets Manager, rotation), audit log (trường bắt buộc + retention theo phương án (a) đã chốt ở `OQ-047`), chuỗi cung ứng (SCA/container scan, pentest/ASV). Đề xuất `FIT-29…33` cho GĐ3. Thêm `OQ-048…053`, `ASM-39…41`. Không viết `ADR` mới (chỉ đề xuất 1 ứng viên cho hoạt động `adr` kế tiếp). Không sửa `SAD`/`ICD`/`DAT`/`FAIL`/`ADR` đã có. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-15 | ~4 (chi phí đảo ngược thấp — ghi tài liệu threat model, chưa có dòng code phụ thuộc · bán kính ảnh hưởng: hoạt động `inf` kế tiếp và toàn bộ dev dùng `SEC` làm nguồn sự thật authn/authz/PII, nhưng bản thân việc ghi tài liệu dưới ngoại lệ thì nhỏ · có chạm `QAS-010/011/012` Must trực tiếp (đang thiết kế cách đạt chúng) nhưng chưa phải cam kết thi công (chưa `FIT` nào chạy) · không ràng buộc dài hạn tự thân (văn bản sửa được qua version mới) · không tranh cãi mới, tiếp nối tiền lệ `DEC-11…26`) → **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ệ:** hoạt động `inf` (hoạt động 7) không có mô hình threat/authn/authz để thiết kế network segmentation/secret management thật — chậm tiến độ tương ứng thời gian xử lý `OQ-007` (chặn hoàn toàn hiệu lực phủ quyết của `SEC`). | `SEC_e-commerce_v1.0.md` (toàn bộ), `OQ-048…053` | +| DEC-28 (SA) | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) duyệt **từng phần** `SEC_e-commerce_v1.0.md` bản v1.0: ghi nhận nội dung 31 `THR` STRIDE (§4), map `ROLE-01/02` (§3.1), mô hình authn/authz đề xuất (§2, §3), SAQ A (§8.1), đề xuất rate limit **30/10/10 req/phút** (§5.3, `ASM-40`), quản lý secret/scanning (§6), audit log theo phương án (a) (§7). Chốt **TẠM** `OQ-050`: chọn **PA-3** (service JWT ngắn hạn ký bởi Identity & Access, không phải PA-2 mTLS/App Mesh) cho service-to-service authn giữa Nhóm Giao dịch↔Nhóm Hỗ trợ↔Payment — yêu cầu SA viết `ADR-015` (`Proposed`) ở lượt hoạt động `adr` kế tiếp cùng `ADR-014` đang nợ; `OQ-050` **giữ nguyên MỞ**, chờ Security + Ops/SRE thật xác nhận trước khi `Accepted`. **KHÔNG ký thay Security**: header `Approved by → Security` giữ `—`, `SEC` **chưa có hiệu lực phủ quyết AG2** cho tới khi có đại diện Security/Legal thật (`OQ-007`); mọi kết luận PII/residency/retention (§5, §8.2) vẫn là đề xuất chờ Legal/Security, không phải quyết định cuối. Ops/SRE **chưa ký**. Ký thay Tech Lead theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký Tech Lead thật**; `OQ-004` giữ mở. `Confidence`/Status của `SEC` **giữ nguyên** (🔴 / 🟡 Draft) — duyệt từng phần không phải AG2 toàn phần, không phải bằng chứng nguồn mới nên không nâng `Confidence`. | Điều phối dự án (đại diện PO/Tech Lead, dự án chạy thử) | 2026-09-15 | ~5 (giống radar ước lượng PA-3 của chính `SEC §2.4` — chi phí đảo ngược trung bình (đổi cơ chế sau khi code tốn sửa cả hai đầu gọi) · bán kính ảnh hưởng: mọi lời gọi cross-network nội bộ TB3/TB4 + tiền lệ cho `IF` tương lai · chạm gián tiếp `QAS-002`/`QAS-010` · ràng buộc ≥1 năm (chuẩn nội bộ service-to-service) · không tranh cãi mới, tiếp nối tiền lệ `DEC-12/14/16/19/25`) | `SEC_e-commerce_v1.0.md` (header, Change Log), `OQ-050` (cập nhật, không đóng) | +| DEC-29 (SA) | Tiếp tục `sa-2-architecture` (hoạt động 7 — `INF`) cho e-commerce dù AG1 chưa ký thật và AG2 (gate của chính GĐ2) chưa tới hạn — tiếp nối `DEC-01…28`. Người dùng (điều phối dự án) tái khẳng định muốn tiếp tục. `INF_e-commerce_v1.0.md` tạo mới — topology AWS `ap-southeast-1` (2 AZ, ALB+WAF, 2 ECS Fargate Nhóm Giao dịch/Nhóm Hỗ trợ + Payment tách biệt, RDS chính Multi-AZ + RDS Payment, ElastiCache Redis, SQS FIFO+EventBridge+DLQ, S3/CloudFront, Secrets Manager/KMS, NAT) đối chiếu `TCO §3.2` từng dòng (khớp toàn bộ trừ 1 điểm bản chất — cross-region snapshot Payment vs `ADR-009` "không multi-region", `OQ-054`, không tự sửa); split ECS task GD/HT đề xuất khớp tổng `TCO` (`OQ-055`); HA/auto-scaling A→B theo `QAS-009`, phát hiện SPOF ElastiCache kịch bản A (`OQ-058`); DR RPO≤15’/RTO≤1h theo `QAS-008`/`ADR-009` + **kế hoạch diễn tập DR 3 kịch bản** (mất AZ/RDS primary/Redis) kèm tiêu chí PASS/FAIL đo thật (`OQ-022`/`OQ-056`, ngày thật chờ Ops/SRE); observability alert ≤1 phút nhóm giao dịch cốt lõi (`QAS-013`), DLQ 14 ngày + alert lag>5 phút (`OQ-036`), error budget 43 phút/tháng trừ bảo trì ≤2h (`OQ-020`), on-call theo `CON-08`/`OQ-008`; CI/CD (build→test→SAST→SCA(Trivy/Snyk)→migration→deploy, blue-green 3 service, migration Flyway theo `OQ-045`); network/SG + egress đối tác ngoài (`OQ-057`); giải quyết khoảng trống service discovery GD↔HT (`SAD §7`/`OQ-028`) bằng AWS Cloud Map/ECS Service Connect (ghi mức `DEC`, không `ADR`); IaC đề xuất Terraform + `FIT-34…38` GĐ3; đề xuất 2 `ADR` ứng viên mới (`ADR-016` blue-green, `ADR-017` Terraform) cho hoạt động `adr` kế tiếp — không viết `ADR` ở lượt này. Thêm `OQ-054…063`, `ASM-42…46`. Không sửa `SAD`/`ICD`/`DAT`/`SEC`/`FAIL`/`ADR` đã có. `Confidence` 🔴 toàn bộ. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-15 | ~4 (chi phí đảo ngược thấp — tài liệu hạ tầng, chưa IaC thật · bán kính ảnh hưởng: `sa-3-enablement` phụ thuộc `INF` nhưng bản thân việc ghi tài liệu dưới ngoại lệ thì nhỏ · chạm `QAS-008/009/013` Must trực tiếp nhưng chưa cam kết thi công · không ràng buộc dài hạn tự thân · không tranh cãi mới, tiếp nối tiền lệ `DEC-11…28`) | `INF_e-commerce_v1.0.md` (toàn bộ), `OQ-054…063` | +| DEC-30 (SA) | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) duyệt **từng phần** `INF_e-commerce_v1.0.md` bản v1.0: chấp nhận topology AWS `ap-southeast-1`, bảng đối chiếu `INF↔TCO` (§10), HA/auto-scaling split ECS Nhóm Giao dịch/Nhóm Hỗ trợ A 2/2 – B 6/4 (`ASM-42`, `OQ-055` giữ mở), kế hoạch diễn tập DR 3 kịch bản (`OQ-022`/`OQ-056`, ngày thật chờ Ops/SRE — điều kiện tiên quyết AG2), observability, chiến lược CI/CD blue-green (`ADR-016` ứng viên), network/egress, IaC Terraform (`ADR-017` ứng viên). Chốt **TẠM** `OQ-058`: giữ nguyên `TCO` — **KHÔNG** thêm replica Redis ở kịch bản A, chấp nhận rủi ro SPOF ElastiCache kịch bản A với hành vi fail-closed theo `FAIL` (không mất dữ liệu nghiệp vụ, chỉ gián đoạn dịch vụ tạm thời) — `OQ-058` **giữ nguyên MỞ**, chờ PO xác nhận cuối cùng (đây là đánh đổi chi phí/rủi ro của PO, không phải SA/Tech Lead tự quyết). Đồng ý để SA viết `ADR-016` (blue-green) và `ADR-017` (Terraform) ở mức `Proposed` cùng lúc với `ADR-014` (outbox, `DAT`) và `ADR-015` (service JWT, `SEC`) ở lượt hoạt động `adr` kế tiếp. `OQ-054` (cross-region snapshot Payment vs `ADR-009` "không multi-region") **giữ nguyên mở**, không tự chọn hướng. **KHÔNG ký thay Ops/SRE**: header `Approved by → Ops/SRE` của `INF` giữ `—` — `INF` **chưa có hiệu lực xác nhận HA/DR/observability thật** cho tới khi Ops/SRE ký (`INF` là artifact cuối cần chữ ký Ops/SRE trực tiếp theo `workflow.md §2`). Security **chưa ký**. Ký thay Tech Lead theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký Tech Lead thật**; `OQ-004` (tính hợp lệ ký thay) giữ mở. `Confidence`/Status của `INF` **giữ nguyên** (🔴 / 🟡 Draft) — duyệt từng phần không phải AG2 toàn phần, không phải bằng chứng nguồn mới nên không nâng `Confidence`. | Điều phối dự án (đại diện PO/Tech Lead, dự án chạy thử) | 2026-09-15 | ~4 (giống radar gốc ước lượng của `INF` — chi phí đảo ngược thấp (tài liệu hạ tầng, sửa được qua version mới, chưa IaC thật) · bán kính ảnh hưởng: `sa-3-enablement` dùng `INF` làm đầu vào chuẩn bị go-live · chạm `QAS-008/009/013` Must trực tiếp nhưng chưa cam kết thi công (chưa IaC/diễn tập thật) · không ràng buộc dài hạn tự thân (văn bản sửa được) · không tranh cãi mới, tiếp nối tiền lệ `DEC-12/14/16/19/25/28`) | `INF_e-commerce_v1.0.md` (header, Change Log), `OQ-058` (cập nhật, không đóng), `OQ-054`/`OQ-055`/`OQ-056` (không đổi) | +| DEC-31 (SA) | Viết 4 `ADR` còn nợ cho e-commerce trong khi AG1 chưa ký thật và AG2 (gate của chính GĐ2) chưa tới hạn — tiếp nối `DEC-01…30`. Người dùng (điều phối dự án) tái khẳng định muốn tiếp tục. Viết `ADR-014` (Transactional Outbox, hiện thực hoá hướng đã chọn TẠM ở `DAT §4.1`/`OQ-044`/`DEC-25`, radar 6/10), `ADR-015` (Service JWT ngắn hạn service-to-service, hiện thực hoá PA-3 đã chọn TẠM ở `SEC §2.4`/`OQ-050`/`DEC-28`, radar 5/10 — **`Accepted` bị chặn cứng bởi `OQ-007`, Security chưa có người**), `ADR-016` (Blue-green qua AWS CodeDeploy cho 3 dịch vụ ECS, hiện thực hoá đề xuất `INF §7.2`/`DEC-30`, radar 6/10), `ADR-017` (IaC Terraform, hiện thực hoá đề xuất `INF §11`/`DEC-30`, radar 7/10). **Cả 4 `ADR` giữ `Proposed`** — không cái nào `Accepted` (chưa chữ ký thật; không cái nào đạt radar ≥8 nên không bắt buộc POC, nhưng mỗi ADR ghi rõ điều kiện `Accepted` riêng ở §3 của từng file). Link 4 `ADR` vào `DAT_e-commerce_v1.0.md` (v1.1, §4.1), `SEC_e-commerce_v1.0.md` (v1.1, §2.4/§4 TB3-TB4), `INF_e-commerce_v1.0.md` (v1.1, §7.2/§11/§13) — chỉ thay "ứng viên"/"chưa viết" bằng đường dẫn thật, không đổi nội dung chuyên môn khác, mỗi file bump `+0.1` kèm Change Log "chỉ link ADR, không đổi nội dung". Cập nhật `ADL_e-commerce.md` (17 `ADR`, tất cả `Proposed`) và `DTM_e-commerce.md` (`ASR-004`/`ASR-005` → thêm `ADR-014`; `ASR-007` → thêm `ADR-015`; `QAS-007` → `ADR-016`; ghi nhận `ADR-017` không có `ASR`/`QAS` nguồn trực tiếp, hợp lệ vì gắn `CON-05`/`D9`). Không sửa 13 `ADR` cũ, không sửa nội dung `SAD`/`ASR`/`QAS`/`ICD`/`FAIL`. `Confidence` 🔴 toàn bộ 4 `ADR` mới. | Điều phối dự án (đại diện PO, dự án chạy thử) | 2026-09-15 | ~4 (chi phí đảo ngược thấp — ghi 4 ADR + link tài liệu, chưa có dòng code phụ thuộc · bán kính ảnh hưởng: AG2 phụ thuộc nhưng bản thân việc ghi dưới ngoại lệ thì nhỏ · chạm gián tiếp `QAS-005/007/002/010` Must nhưng chưa cam kết thi công (không ADR nào `Accepted`) · không ràng buộc dài hạn tự thân (nội dung từng ADR đã chấm radar riêng 5–7, không cái nào ≥8) · không tranh cãi mới, tiếp nối tiền lệ `DEC-17/23`) | `ADR-014…017` (toàn bộ), `DAT_e-commerce_v1.0.md` (v1.1), `SEC_e-commerce_v1.0.md` (v1.1), `INF_e-commerce_v1.0.md` (v1.1), `ADL_e-commerce.md`, `DTM_e-commerce.md` | ## Ghi chú diff --git a/sa-output/e-commerce/00-index/DTM_e-commerce.md b/sa-output/e-commerce/00-index/DTM_e-commerce.md index dd40eef..ee4770a 100644 --- a/sa-output/e-commerce/00-index/DTM_e-commerce.md +++ b/sa-output/e-commerce/00-index/DTM_e-commerce.md @@ -2,14 +2,15 @@ | | | |---|---| -| **Cập nhật** | 2026-09-10 | -| **Author** | sa-lifecycle (khởi tạo — khung rỗng, chưa có artifact GĐ2 nào để quét) | -| **Nguồn quét** | *(chưa có — `01-context/`, `02-architecture/` chưa tồn tại)* | -| **Artifact 🟡 Draft bị tách riêng** | *(chưa có)* | +| **Cập nhật** | 2026-09-15 | +| **Author** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) — cập nhật thay `sa-conformance` vì `ADR-014…017` vừa được sinh (trả hết nợ ADR, `DEC-31`); `sa-conformance` nên rà lại độc lập ở lần đồng bộ kế tiếp. GĐ2 nay đủ 9/9 hoạt động (`qas`/`asr`/`sad`/`icd`/`dat`/`sec`/`inf`/`fail`/`adr`) — §3 (`ASR × ADR`) cập nhật thêm `ADR-014` cho `ASR-004`/`ASR-005`, `ADR-015` cho `ASR-007`; bổ sung ánh xạ `QAS-007 → ADR-016` (ngoài chuỗi `ASR` chính) | +| **Nguồn quét** | `01-context/CTX_e-commerce_v1.0.md` (v1.2) · `01-context/OPT_e-commerce_v1.0.md` (v1.0) · `01-context/TCO_e-commerce_v1.0.md` (v1.1) · `01-context/ARISK_e-commerce_v1.0.md` (v1.0) · `02-architecture/QAS_e-commerce_v1.0.md` (v1.0) · `02-architecture/ASR_e-commerce_v1.0.md` (v1.0) · `02-architecture/SAD_e-commerce_v1.0.md` (v1.3) · `02-architecture/ICD_e-commerce_v1.0.md` (v1.0) · `02-architecture/DAT_e-commerce_v1.0.md` (v1.1) · `02-architecture/SEC_e-commerce_v1.0.md` (v1.1) · `02-architecture/INF_e-commerce_v1.0.md` (v1.1) · `02-architecture/FAIL_e-commerce_v1.0.md` (v1.1) · `02-architecture/adr/ADR-001…017_*.md` (mới: `ADR-014…017`) · `00-index/OQ_e-commerce.md` · `00-index/DEC_e-commerce.md` (v1.29). | +| **Artifact 🟡 Draft bị tách riêng** | `CTX`/`OPT`/`TCO`/`ARISK`/`QAS`/`ASR`/`SAD`/`ICD`/`DAT`/`SEC`/`INF`/`FAIL` đều `🟡 Draft` (duyệt **từng phần** bởi PO/Tech Lead uỷ quyền — điều phối dự án, **không phải chữ ký thật**, `OQ-004` còn mở). 17 `ADR` đều `Proposed` (chưa `Accepted`). Mọi liên kết rút ra từ các file này được ghi nhận nhưng **không tính là đã "chặn gate qua"** — AG1 toàn phần chưa ký, AG2 còn xa. | > Ma trận **trống trung thực tốt hơn ma trận đầy do suy diễn**. Ô trống là danh sách việc; -> ô điền bừa là cảm giác an toàn giả. Khung khởi tạo — sẽ được `sa-conformance` cập nhật sau -> mỗi giai đoạn. +> ô điền bừa là cảm giác an toàn giả. Cập nhật lần này chỉ điền được chuỗi `DRV → (ASR/QAS chưa +> có)` và ghi nhận `ARISK`/`POC`/`ASM` của GĐ1 — theo đúng yêu cầu đồng bộ sau khi GĐ1 hoàn tất. +> Không tạo nội dung mới, không sửa artifact nguồn. --- @@ -17,10 +18,10 @@ | Chuỗi | Tỉ lệ | % | Mức | ID bị đứt | Chặn gate | |---|---|---|---|---|---| -| `DRV` → `ASR`/`QAS` | 0/0 | — | — | — | AG2 | -| `ASR` → `ADR` | 0/0 | — | — | — | AG2 | -| `ADR` → nguồn (`DRV`/`CON`/`QAS`/`ASR`) | 0/0 | — | — | — | — | -| `ADR` → `CMP` | 0/0 | — | — | — | AG2 | +| `DRV` → `ASR`/`QAS` | 9/9 | 100% | 🟢 | Không — mọi `DRV-01…09` nay có `QAS`/`ASR` phục vụ (xem `QAS §C`, `ASR §B2`) | AG2 | +| `ASR` → `ADR` | 12/15 | 80% | 🟡 | `ASR-009`, `ASR-012`, `ASR-015` — không có `ADR` (xem lý do ở §3, không phải chặn) | AG2 — mục tiêu 15/15 *hoặc* lý do hợp lệ; đã đạt | +| `ADR` → nguồn (`DRV`/`CON`/`QAS`/`ASR`) | 15/17 | 88% | 🟡 | `ADR-016`/`ADR-017` không có `ASR` trực tiếp — nhưng có nguồn hợp lệ khác (`ADR-016` → `QAS-007`; `ADR-017` → `CON-05`/`D9`), xem §3 ghi chú | — | +| `ADR` → `CMP` | 0/12 | 0% | — *(chưa tới — `SAD §8` mới link file `ADR`, chưa có cột `CMP` do `ADR` kích hoạt trực tiếp; quan hệ `ASR × CMP` đã đủ 15/15 ở `SAD §4.3`)* | Không tính là đứt — `ADR` không nhất thiết map 1-1 sang `CMP` | AG2 | | `QAS` (Must) → bài đo | 0/0 | — | — | — | AG3 | | `QAS` (Must) → kết quả đo thật | 0/0 | — | — | — | AG3 | | Ràng buộc `AGD` → `FIT` hoặc nhãn khuyến nghị | 0/0 | — | — | — | AG3 | @@ -30,45 +31,183 @@ | `THR` → biện pháp → cách kiểm chứng | 0/0 | — | — | — | AG2 | | Phụ thuộc ngoài process → `FM` | 0/0 | — | — | — | AG2 | +**Riêng cho GĐ1 (không có cột chính thức ở trên, ghi bổ sung theo yêu cầu đồng bộ):** + +| Chuỗi bổ sung GĐ1 | Tỉ lệ | Ghi chú | +|---|---|---| +| `ARISK` có biện pháp hạ rủi ro cụ thể | 9/10 | `ARISK-07` chỉ có "trình số liệu", chưa "đã hạ" — chờ PO/tài chính xác nhận `TCO` (`OQ-005`) | +| `ARISK` mức 🔴 Cao có kế hoạch `POC` khi cần | 2/2 cần POC | `ARISK-01`→`POC-01`, `ARISK-02`→`POC-02` — **cả hai POC chưa chạy** | +| `POC` đã chạy / tổng `POC` đã lập | 0/2 | `POC-01`, `POC-02` — tiêu chí PASS/FAIL đã viết trước (`ARISK §6`), chưa có ngày chạy | +| `ASM` đã xác minh / tổng `ASM` | 0/15 | `ASM-01..15` (CTX 01-06, OPT 07-09, TCO 10-15) — toàn bộ vẫn ở trạng thái giả định, xem §2.1 | + ## 2. `DRV` × `ASR` / `QAS` -| | **Đứt** | -|---|---| +*Cập nhật 2026-09-15 — `QAS`/`ASR` nay tồn tại (hoạt động `qas`/`asr` của `sa-2-architecture` đã +chạy). Mọi `DRV` dưới đây nay có ít nhất một `QAS`/`ASR` phục vụ trực tiếp hoặc gián tiếp.* + +| `DRV` | Phát biểu ngắn | Ưu tiên | Confidence nguồn | `ASR`/`QAS` phục vụ | Đứt | +|---|---|---|---|---|---| +| `DRV-01` | Chưa có luồng giỏ hàng–checkout–thanh toán ⇒ không ra mắt được MVP (blocker) | Must | 🔴 (BA chưa ký G1, nguồn trực tiếp `BRIEF`) | `ASR-001`, `ASR-003`, `QAS-002` | 🟢 | +| `DRV-02` | Giỏ hàng ≥2 seller có nguy cơ tỷ lệ bỏ giỏ cao hơn ở checkout | Must | 🔴 (nguồn trực tiếp, baseline thật chưa có) | `ASR-003`, `QAS-002`, `QAS-003` | 🟢 | +| `DRV-03` | Thanh toán không lưu thẻ để giảm phạm vi tuân thủ PCI-DSS | Must | 🔴 (nguồn trực tiếp) | `ASR-002` | 🟢 | +| `DRV-04` | Quy mô mục tiêu lớn, đỉnh hàng nghìn–chục nghìn concurrent user mùa flash sale | Must | 🔴 (chỉ có nguồn `SAD.md`/brief, chưa qua BRIEF module hoá) | `ASR-001`, `ASR-014`, `QAS-001`, `QAS-005`, `QAS-006`, `QAS-009` | 🟢 | +| `DRV-05` | Uptime 99.9% cho dịch vụ giao dịch lõi | Must | 🔴 (giả định mặc định trong brief, chưa phải SLA) | `ASR-010`, `QAS-007`, `QAS-008` | 🟢 | +| `DRV-06` | Dòng tiền minh bạch 3 bên (khách–sàn–seller), hoa hồng + payout có kỳ giữ tiền | Must | 🔴 (chỉ có nguồn `SAD.md`/brief) | `ASR-003`, `ASR-005` | 🟢 | +| `DRV-07` | Chia sẻ PII cho seller khi tách đơn chưa rà soát NĐ13/2023 | Must | 🔴 (nguồn trực tiếp `RISK-03` BA) | `ASR-008`, `QAS-011` | 🟢 | +| `DRV-08` | Xác nhận thanh toán qua webhook bên thứ ba chưa xác minh khả thi gần thời gian thực | Must | 🔴 (nguồn trực tiếp `RISK-02`/`ASM-01` BA) | `ASR-004`, `QAS-014` | 🟢 | +| `DRV-09` | Đa ngôn ngữ 5 thứ tiếng để mở rộng thị trường | Should | 🔴 (chỉ có nguồn `SAD.md`/brief) | `ASR-015` *(borderline, không có `ADR` — xem §3)* | 🟢 | **Đọc ngược** — `ASR`/`QAS` không sinh từ `DRV`/`CON` nào: | ID | Sinh từ đâu | Hợp lệ? | |---|---|---| +| *(rà 15 `ASR` + 14 `QAS` — không phát hiện `ASR`/`QAS` nào thiếu nguồn `DRV`/`CON`/`BR`/`ROLE`; mỗi mục đều có cột "Nguồn" trong `ASR §B2`/`QAS §A3`)* | | ✅ | + +**Kết luận chuỗi này:** 9/9 `DRV` nay có `ASR`/`QAS` phục vụ (🟢) — đạt mục tiêu đặt ra ở lượt +đồng bộ trước. Không còn `DRV` mồ côi. + +### 2.1 `ARISK` / `POC` / `ASM` của GĐ1 — ghi nhận để mang sang GĐ2 + +*(Không phải ma trận truy vết chính thức của DTM — GĐ1 không có `ASR`/`ADR`/`CMP` để đối +chiếu. Ghi ở đây theo yêu cầu đồng bộ, để `sa-2-architecture` không phải đọc lại toàn bộ 4 file +GĐ1 mới biết còn gì treo.)* + +**`ARISK` mức 🔴 Cao (6/10) — chưa đóng, phải mang sang GĐ2:** + +| `ARISK` | Chủ | Chặn gì ở GĐ2 | `POC`/biện pháp | +|---|---|---|---| +| `ARISK-01` | Tech Lead | `ADR-005` chuyển `Accepted` | `POC-01` (chưa chạy) | +| `ARISK-02` | Tech Lead/DBA | `ADR-006` chuyển `Accepted`, `DAT` (hoạt động 5) | `POC-02` (chưa chạy) | +| `ARISK-03` | Tech Lead + PO | `ICD` (VNPay/Momo), `ADR-004` kiểm chứng đầy đủ | Đàm phán sandbox + job đối soát bù (chưa xác minh lại) | +| `ARISK-05` | Tech Lead | `ADR-005`/`ADR-001` chuyển `Accepted` (năng lực đội) | Xác nhận `OQ-010` | +| `ARISK-06` | PO → Legal/Security | `ADR-008` chuyển `Accepted` (chặn hoàn toàn), `DAT`/`INF` (residency NĐ13/2023) | Chỉ định người (`OQ-007`), chưa có | +| `ARISK-07` | PO/tài chính | Ký AG1 (ngân sách vận hành thật) | Trình `TCO` — chưa xác nhận | + +**`POC` đã lập, chưa chạy (2/2):** + +| `POC` | Hạ rủi ro | Tiêu chí PASS | Hạn | Trạng thái | +|---|---|---|---|---| +| `POC-01` | `ARISK-01` | Throughput ≥100 msg/s sustained 30 phút, p99 ≤2s, 0 mất message | Trước `ADR-001`/`ADR-005` chuyển `Accepted` | Chưa chạy | +| `POC-02` | `ARISK-02` | p95 write ≤300ms, p95 read ≤200ms, CPU RDS <75% | Trước `ADR-001`/`ADR-006` chuyển `Accepted` | Chưa chạy | + +**`ASM` chưa xác minh, ảnh hưởng lớn nhất (không liệt kê đủ 15, chỉ các dòng có hệ quả định +lượng theo chính `CTX`/`OPT`/`TCO`):** + +| `ASM` | Nội dung ngắn | Nguồn | Hệ quả nếu sai | Hạn | +|---|---|---|---|---| +| `ASM-01` | Số lao động hồ sơ thầu (~3,76 tỷ VND) "trong khoảng hợp lý" | `CTX §5` | Phải loại phương án kiến trúc nặng ở `OPT` nếu ngân sách thật thấp hơn | Trước `OPT` (đã trễ — `OPT` đã chạy dưới giả định này) | +| `ASM-04` | Region `ap-southeast-1` đáp ứng đủ residency NĐ13/2023 | `CTX §5` | Phải chuyển hạ tầng dữ liệu về region VN nếu sai | Trước `DAT`/`INF` GĐ2, chậm nhất trước go-live | +| `ASM-07` | SQS/EventBridge đủ throughput thay Kafka/MSK | `OPT §8` | P2 phải bổ sung Kafka/MSK cho hot-path nếu sai | Trước `ADR` message backbone GĐ2 (`POC-01`) | +| `ASM-08` | 1 cụm RDS chính đủ chịu tải ghi/đọc gộp | `OPT §8` | Phải tách read replica sớm hơn dự kiến nếu sai | Trước `DAT` GĐ2 (`POC-02`) | +| `ASM-11` | Đơn giá AWS `ap-southeast-1` ước tính, chưa tra Pricing Calculator thật | `TCO §8` | ±50% ⇒ hạ tầng 3 năm lệch ±0,9–3,7 tỷ VND | Trước khi duyệt ngân sách (`OQ-013`) | +| `ASM-14` | Số FTE vận hành (dòng nhạy cảm nhất của `TCO`) | `TCO §8` | ±50% ⇒ lệch ±2,7–3,5 tỷ VND | Trước khi chốt `INF` GĐ2 (`OQ-008`) | + +*Danh sách đầy đủ `ASM-01..15` xem `CTX §5`, `OPT §8`, `TCO §8`. Không copy lại toàn bộ ở đây +theo nguyên tắc "không sao chép giữa tài liệu" (`artifact-map.md §7`) — tham chiếu bằng ID.* ## 3. `ASR` × `ADR` +*Cập nhật 2026-09-15 — mục tiêu 15/15 `ASR` có ≥1 `ADR` **hoặc** lý do hợp lệ ("ràng buộc đầu +vào"/"không phải quyết định kiến trúc"). Đạt **12/15 có `ADR`, 3/15 có lý do ghi rõ** — không +`ASR` nào bị bỏ sót không giải thích.* + | `ASR` | Phát biểu ngắn | `ADR` hiện thực hoá | Trạng thái ADR | Đứt | |---|---|---|---|---| +| `ASR-001` | Kiểu kiến trúc tổng thể — Modular Monolith P2 | `ADR-001` | `Proposed` (radar ~7, cần `POC-01`/`POC-02`) | 🟢 | +| `ASR-002` | Payment cô lập PCI-DSS SAQ A | `ADR-002` | `Proposed` (radar ~7, cần Security ký) | 🟢 | +| `ASR-003` | Mô hình `Order`/`OrderSeller` | `ADR-003` | `Proposed` (radar ~6, chờ `OQ-011` BA) | 🟢 | +| `ASR-004` | Idempotency + đối soát webhook | `ADR-004`, `ADR-013`, `ADR-014` *(mới — Transactional Outbox đảm bảo publish nguyên tử cho sự kiện xác nhận/khởi tạo thanh toán, mở rộng tinh thần idempotency/không-mất-giao-dịch sang bước publish)* | `ADR-004`: `Proposed` (radar ~6, chờ sandbox) · `ADR-013`: `Proposed` (radar 7, chờ Tech Lead + PO thật) · `ADR-014`: `Proposed` (radar 6, chờ Tech Lead xác nhận relay) | 🟢 | +| `ASR-005` | Message backbone SQS FIFO + EventBridge | `ADR-005`, `ADR-014` *(mới — outbox là cơ chế publish nguyên tử lên trên backbone này)* | `ADR-005`: `Proposed` (radar **8**, cần `POC-01`) · `ADR-014`: `Proposed` (radar 6) | 🟢 | +| `ASR-006` | RDS gộp schema-per-module | `ADR-006` | `Proposed` (radar **8**, cần `POC-02`) | 🟢 | +| `ASR-007` | Chỗ quyết định ownership/authz | `ADR-007`, `ADR-015` *(mới — Service JWT mở rộng xác thực từ người dùng cuối sang service-to-service nội bộ, TB3/TB4)* | `ADR-007`: `Proposed` (radar ~6) · `ADR-015`: `Proposed` (radar 5, **`Accepted` chặn cứng bởi `OQ-007` — Security chưa có người**) | 🟢 | +| `ASR-008` | Vùng lưu trữ PII & chia sẻ seller | `ADR-008` | `Proposed` (radar ~7, chặn tới khi có Security/Legal — `OQ-007`) | 🟢 | +| `ASR-009` | MFA Admin (TOTP app) | *(không — xem lý do dưới)* | — | ➖ N/A hợp lệ | +| `ASR-010` | HA/DR nhóm giao dịch lõi | `ADR-009` | `Proposed` (radar **9**, cần diễn tập DR) | 🟢 | +| `ASR-011` | Observability & alerting | `ADR-010` | `Proposed` (radar ~6) | 🟢 | +| `ASR-012` | AWS bắt buộc | *(không — xem lý do dưới)* | — | ➖ N/A hợp lệ | +| `ASR-013` | Resilience đối tác thanh toán/vận chuyển ngoài | `ADR-011` | `Proposed` (radar ~6, chờ sandbox 4 đối tác) | 🟢 | +| `ASR-014` | Ranh giới nhóm triển khai theo domain | `ADR-012` | `Proposed` (radar ~7, chờ `OQ-010`/`OQ-026`/`OQ-027`) | 🟢 | +| `ASR-015` | Chiến lược i18n | *(không — xem lý do dưới)* | — | ➖ N/A hợp lệ (borderline) | + +**Lý do 3 `ASR` không có `ADR` *(đúng theo `decision-radar.md §2`, không phải bỏ sót)*:** + +| `ASR` | Lý do không cần `ADR` | Ghi ở đâu thay thế | +|---|---|---| +| `ASR-009` (MFA Admin) | Radar ước lượng ~4 (3–4 ⇒ `DEC-nn` là đủ theo `decision-radar.md §2`) — bán kính hẹp (chỉ Identity/Admin), không ràng buộc dài hạn. **Không phải "ràng buộc đầu vào"** mà là "quyết định thi công nhỏ" | `DEC-nn` khi hoạt động `sec` chốt phương thức cụ thể; tạm chốt TOTP app ở `OQ-024`/`ASM-20` | +| `ASR-012` (AWS bắt buộc) | **Ràng buộc đầu vào** — `CON-03` do khách hàng chốt, không phải quyết định SA cân nhắc giữa nhiều phương án; đã phản ánh làm điều kiện tiên quyết trong `ADR-001` | `ADR-001` §1 Bối cảnh (tham chiếu, không lặp) | +| `ASR-015` (i18n) | Radar ước lượng ~5 (borderline theo `ASR §B2`) — không chạm `QAS` Must (chỉ Should), bán kính hẹp (chỉ FE). SA đã ghi rõ đây là lựa chọn borderline, khuyến nghị `DEC-nn` + `AGD` (GĐ3) nếu Tech Lead không thấy tranh cãi | `DEC-nn` (chưa ghi — việc phải làm ở hoạt động `sec`/GĐ3); có thể nâng thành `ADR-013` nếu phát sinh tranh luận công nghệ i18n cụ thể | + +🔴 **Ghi chú đối chiếu:** `ASR-013` (đối tác ngoài) **có** `ADR-011` — khác với gợi ý ban đầu +"ASR-012/013/015 không cần ADR" của ghi chú người duyệt. Đã kiểm tra lại `ASR_e-commerce_v1.0.md +§B2 ASR-013`: mục này ghi rõ "Quyết định cần `ADR` | Có — `ADR-011`" (radar ~6, đã duyệt từng +phần ở `DEC-14`). Giữ nguyên theo nội dung đã duyệt, không tự sửa để khớp gợi ý — ba `ASR` thực +sự không cần `ADR` là `ASR-009`/`012`/`015` (xem bảng trên). **Đọc ngược** — `ADR` không phục vụ `ASR`/`QAS` nào: | `ADR` | Quyết định gì | Nguồn ghi trong §1 | Hợp lệ? | |---|---|---|---| +| `ADR-016` | Blue-green deploy qua AWS CodeDeploy | Không có `ASR` trực tiếp — nguồn là `QAS-007` (error budget, xem bổ sung "QAS Must ↔ ADR" ngay dưới) | ✅ Hợp lệ — `INF §7.2` ghi rõ nguồn là bảo vệ ngân sách lỗi `QAS-007`, không phải một `ASR` | +| `ADR-017` | Công cụ IaC — Terraform | Không có `ASR`/`QAS` trực tiếp — nguồn là `CON-05` (năng lực đội) và `D9` (quy tắc: mọi con số hạ tầng phải quy ra tiền/tái lập được) | ✅ Hợp lệ — quyết định thiết lập tiền lệ theo `decision-radar.md §3` "công cụ hạ tầng", không bắt buộc có `ASR` nguồn khi lý do gắn `CON`/quy tắc thiết kế đã ghi rõ trong `ADR-017 §1` | +| *(13 `ADR` còn lại đều có ≥1 `ASR` nguồn ở bảng trên, không mồ côi)* | | | ✅ | + +**Kết luận chuỗi này:** 12/15 `ASR` có `ADR`, 3/15 có lý do hợp lệ ghi rõ — đạt mục tiêu 15/15 "có +`ADR` hoặc có lý do". `ASR-004` nay có 3 `ADR` (`ADR-004` + `ADR-013` + `ADR-014`), `ASR-005` có 2 +`ADR` (`ADR-005` + `ADR-014`), `ASR-007` có 2 `ADR` (`ADR-007` + `ADR-015`) — không mâu thuẫn giữa +các cặp này (xem `ADL §3`). `ADR-016`/`ADR-017` không có `ASR` trực tiếp nhưng có nguồn hợp lệ khác +đã ghi rõ (`QAS-007`, `CON-05`/`D9`) — không phải "ADR mồ côi" theo nghĩa D3 (mọi ADR đều truy vết +được về một nguồn có tên). Không còn `ASR` nào bị bỏ sót không giải thích. + +**Bổ sung `QAS` Must ↔ `ADR` hiện thực hoá** *(ngoài chuỗi `ASR` chính, theo yêu cầu đồng bộ)*: + +| `QAS` | Phát biểu ngắn | Mức | `ADR` hiện thực hoá | Đứt | +|---|---|---|---|---| +| `QAS-007` | Error budget 99,9%/tháng ⇒ 43 phút/tháng, loại trừ bảo trì ≤2h (`OQ-020`) | Must | `ADR-016` — chiến lược blue-green đảm bảo chiến lược deploy không tự ăn vào ngân sách lỗi này | 🟢 | ## 4. `ADR` × `CMP` -| | **Không hiện ở đâu** | -|---|---| +*`SAD §4.3` đã có ma trận `ASR × CMP` đủ 15/15 (không lặp lại ở đây, tham chiếu bằng ID theo +`artifact-map.md §7`). `ADR` không nhất thiết map trực tiếp 1-1 sang `CMP` — một `ADR` (VD +`ADR-001` kiểu kiến trúc tổng thể) áp dụng cho toàn bộ cấu trúc container, không phải một `CMP` +đơn lẻ. Bảng dưới đối chiếu `ADR` nào ràng buộc trực tiếp `CMP` nào qua `ASR` trung gian.* + +| `ADR` | `ASR` trung gian | `CMP` bị ràng buộc *(qua `SAD §4.3`)* | +|---|---|---| +| `ADR-001` | `ASR-001` | Toàn bộ cấu trúc container (§4 `SAD`) | +| `ADR-002` | `ASR-002` | `CMP-11`, `CMP-14` | +| `ADR-003` | `ASR-003` | `CMP-04`, `CMP-06`, `CMP-10` | +| `ADR-004` | `ASR-004` | `CMP-11`, `CMP-04` | +| `ADR-005` | `ASR-005` | `CMP-12`, `CMP-06/07/08/09/10` | +| `ADR-006` | `ASR-006` | `CMP-13`, `CMP-14` | +| `ADR-007` | `ASR-007` | `CMP-01`, `CMP-02`, `CMP-04`, `CMP-15` | +| `ADR-008` | `ASR-008` | `CMP-04`, `CMP-05` | +| `ADR-009` | `ASR-010` | `CMP-02`, `CMP-04`, `CMP-11` | +| `ADR-010` | `ASR-011` | `CMP-02`, `CMP-04`, `CMP-11` | +| `ADR-011` | `ASR-013` | `CMP-11`, `CMP-10` | +| `ADR-012` | `ASR-014` | Cột "Nhóm triển khai" toàn bộ `SAD §4.1` | +| `ADR-013` | `ASR-004` | `CMP-04`, `CMP-11` *(mới — sửa `SAD §6.1` v1.3, tách đường găng đồng bộ khỏi bước khởi tạo thanh toán VNPay/Momo)* | +| `ADR-014` | `ASR-004`, `ASR-005` | `CMP-04`, `CMP-11` *(mới — outbox áp dụng cho cả hai module publish sự kiện)* | +| `ADR-015` | `ASR-007` | `CMP-02` (cấp token), `CMP-04`, `CMP-11`, `CMP-05`/`CMP-07` (Nhóm Hỗ trợ, qua TB3) *(mới)* | +| `ADR-016` | *(không qua `ASR`, xem §3 bổ sung `QAS-007`)* | `CMP-01…15` (áp dụng cho cả 3 đơn vị triển khai) *(mới)* | +| `ADR-017` | *(không qua `ASR`, nguồn `CON-05`)* | Toàn bộ hạ tầng AWS, không map riêng `CMP` *(mới)* | **Đọc ngược** — `CMP` không phục vụ `ASR` nào và không có nhu cầu chức năng rõ: | `CMP` | Trách nhiệm | Sinh từ | Hợp lệ? | |---|---|---|---| +| *(không có — `SAD §4.1` đã tự chấm "15/15 `CMP` có ít nhất một `ASR` phục vụ, không có `CMP` mồ côi")* | | | ✅ | ## 5. `QAS` × kiểm chứng | `QAS` | Mức | Bài đo (`FIT`/tên bài) | Đã chạy | Kết quả | Nguồn kết quả | Đứt | |---|---|---|---|---|---|---| +| *(chưa có `QAS`)* | | | | | | | ## 6. Ràng buộc `AGD` × `FIT` | Ràng buộc `AGD` | Nguồn | `FIT` | Nhãn `⚠️ Khuyến nghị` | Đứt | |---|---|---|---|---| +| *(chưa có `AGD`, còn xa GĐ3)* | | | | | ## 7. Kiểm tra chuyên biệt @@ -76,40 +215,46 @@ | `IF-nnn` | Chủ sở hữu contract | Contract tồn tại | Versioning policy | `FM` khi hỏng | Đứt | |---|---|---|---|---|---| +| *(chưa có `ICD`)* | | | | | | ### 7.2 Dữ liệu | Thực thể | Số chủ sở hữu | Hợp lệ | Ghi chú | |---|---|---|---| +| *(chưa có `DAT`)* | | | | ### 7.3 Bảo mật | `THR-nn` | Có biện pháp | Có cách kiểm chứng | Đứt | |---|---|---|---| +| *(chưa có `SEC`)* | | | | ### 7.4 Đường lỗi | Phụ thuộc ngoài process *(từ `SAD`+`ICD`)* | Có `FM-nn` | Trả lời đủ 4 câu | Đứt | |---|---|---|---| +| *(chưa có `SAD`/`ICD`/`FAIL`)* | | | | ## 8. Đối chiếu chéo với bộ BA | Kiểm | Kết quả | Hành động | |---|---|---| -| Mọi `NFR-nn` của BA có `QAS` tương ứng | chưa đo được — SA GĐ2 chưa chạy | — | -| Mọi endpoint trong `API` của BA có `IF-nnn` | chưa đo được — SA GĐ2 chưa chạy | — | -| Mọi `ROLE-nn` trong `RBAC` map xuống `SEC` §3.1 | chưa đo được — SA GĐ2 chưa chạy | — | -| `BR-nnn` ép ràng buộc kiến trúc đã có `ADR` | chưa đo được — SA GĐ2 chưa chạy | — | +| Mọi `NFR-nn` của BA có `QAS` tương ứng | ✅ Đạt phần lớn — xem `QAS_e-commerce_v1.0.md §C`; `NFR-SEC-02/03`, `NFR-AVL-01/02` chờ hoạt động `sec`/`fail` (chưa chạy) | Tiếp tục hoạt động `sec`/`icd`/`fail` | +| Mọi endpoint trong `API` của BA có `IF-nnn` | chưa đo được — hoạt động `icd` (GĐ2) chưa chạy; `SAD §4.1/§6.3` đã liệt kê 22 `IF-nnn` ứng viên | Chạy `/sa-2-architecture e-commerce --focus icd` | +| Mọi `ROLE-nn` trong `RBAC` map xuống `SEC` §3.1 | chưa đo được — hoạt động `sec` (GĐ2) chưa chạy | Chạy `/sa-2-architecture e-commerce --focus sec` | +| `BR-nnn` ép ràng buộc kiến trúc đã có `ADR` | ✅ Đạt — `BR-CART-01`→`ADR-003`, `BR-CART-05`→`ADR-002`, `BR-CART-06`→`ADR-004`; `DEC-06` (chọn P2) đã được trả nợ bằng `ADR-001` | Không còn hành động — `DEC-06` không còn "nợ" (xem `ADL §7`) | ## 9. ID trùng lặp | ID | Xuất hiện ở | Mức | |---|---|---| +| *(không phát hiện trùng giữa `CTX`/`OPT`/`TCO`/`ARISK` ở lượt quét này — `DRV-01..09`, `CON-01..09`, `ASM-01..15`, `ARISK-01..10` đều dùng dải số liên tục không chồng lấn)* | | | ## 10. Tham chiếu gãy | Từ | Trỏ tới | Vấn đề | |---|---|---| +| *(không phát hiện tham chiếu gãy trong 4 file GĐ1 ở lượt quét này; chưa có `ADR`/`ASR`/`SAD` để kiểm tham chiếu GĐ2)* | | | ## 11. Phát hiện — xếp theo mức @@ -117,29 +262,62 @@ | # | Phát hiện | File · mục | Hành động | Skill sửa | Chặn | |---|---|---|---|---|---| +| 1 | `POC-01`/`POC-02` chưa chạy — chặn `ADR-001`/`ADR-005`/`ADR-006` chuyển `Accepted` | `ARISK_e-commerce_v1.0.md §6`, `adr/ADR-005`, `adr/ADR-006` | Chạy POC theo tiêu chí PASS/FAIL đã viết trước | Tech Lead/DBA (ngoài pipeline SA) | AG1 (ký chính thức), AG2 | +| 2 | Diễn tập DR chưa chạy — chặn `ADR-009` chuyển `Accepted`, cũng là điều kiện tiên quyết AG2 | `adr/ADR-009`, `QAS_e-commerce_v1.0.md OQ-022` | Ops/SRE lên lịch và chạy diễn tập | Ops/SRE (ngoài pipeline SA) | AG2 | +| 3 | Chưa có đại diện Pháp chế/Bảo mật — chặn `ADR-008` hoàn toàn (`OQ-007`) | `adr/ADR-008` | PO chỉ định người | PO | AG2 | +| 4 | `OQ-004` (tính hợp lệ ngoại lệ ký thay PO) còn mở — mọi phê duyệt hiện tại đều "PO/Tech Lead uỷ quyền", không phải chữ ký thật | `CTX`/`OPT`/`TCO`/`ARISK`/`QAS`/`ASR`/`SAD` — header `Approved by` | PO/Tech Lead thật xác nhận lại bằng văn bản, hoặc chấp nhận rủi ro và ghi `DEC-nn` mới | Điều phối dự án / PO thật | AG1, AG2 | ### 🟠 Nợ — phải trả trước gate sau | # | Phát hiện | File · mục | Hành động | Skill sửa | |---|---|---|---|---| +| 1 | ~~`DEC-06` chưa nâng thành `ADR`~~ **Đã trả nợ** — `ADR-001` viết 2026-09-15, vẫn `Proposed` chờ `POC-01`/`POC-02` | `ADR-001`, `ADL §7` | Không còn hành động — theo dõi điều kiện `Accepted` | — | +| 2 | 6 `OQ` (`OQ-005/006/007/008/013..017`) chưa có số thật — `TCO`/`ARISK` đang chạy trên giả định | `TCO_e-commerce_v1.0.md`, `ARISK_e-commerce_v1.0.md` | PO/PM/Tech Lead trả lời trước khi AG1 ký chính thức | Điều phối dự án | +| 3 | 3 câu hỏi mới của `ADR-012` (`OQ-010`/`OQ-026`/`OQ-027`) chưa trả lời — chặn `ADR-012` chuyển `Accepted` | `adr/ADR-012` | Tech Lead + Ops/SRE trả lời | Tech Lead/Ops (ngoài pipeline SA) | +| 4 | Security chưa ký `ADR-002`/`ADR-007` (radar ≥6, thuộc phạm vi bảo mật) | `adr/ADR-002`, `adr/ADR-007` | Security review + ký khi có người | Security | ### 🟡 Cải thiện | # | Phát hiện | File · mục | Hành động | |---|---|---|---| +| 1 | `DRV-04/05/06/09` (module ngoài Giỏ hàng & Checkout) chỉ có nguồn `SAD.md`/brief, chưa qua BRIEF/RISK module hoá riêng — Confidence thấp hơn `DRV-01/02/03/07/08` | `CTX_e-commerce_v1.0.md` §2 (ghi chú cuối bảng) | Khi BA module hoá các phần còn lại của sàn, cập nhật `CTX` và rà lại `OQ-003` (giữ toàn sàn hay thu hẹp) | +| 2 | `ASR-013` có `ADR-011` nhưng ghi chú người duyệt gợi ý "012/013/015 không cần ADR" — đã đối chiếu và giữ nguyên nội dung `ASR` đã duyệt (`DEC-14`), không tự sửa để khớp gợi ý | `DTM §3` (ghi chú), `ASR_e-commerce_v1.0.md §B2 ASR-013` | Không cần hành động — đã minh bạch hoá sự khác biệt, tham chiếu cho lần rà sau | ## 12. Kết luận gate ``` -AG1: — chưa tới (chưa có CTX/OPT/TCO/ARISK) -AG2: — chưa tới +AG1: 🟡 CHƯA ĐỦ ĐIỀU KIỆN KÝ CHÍNH THỨC — đủ 4/4 artifact (CTX/OPT/TCO/ARISK), mỗi file tự + chấm 7/7 tiêu chí cấu trúc, nhưng nội dung còn: OQ-004 (tính hợp lệ ký thay) mở, OQ-005/006/ + 007/008/013..017 (số thật) mở, POC-01/POC-02 chưa chạy. PO uỷ quyền đã duyệt từng phần + dưới ngoại lệ DEC-01..17 — không thay thế chữ ký PO/Tech Lead thật. +AG2: 🟡 CÒN XA — 9/9 hoạt động GĐ2 xong (qas/asr/sad/icd/dat/sec/inf/fail/adr); 17/17 ADR viết + (ADR-001…013 + ADR-014 outbox + ADR-015 service JWT + ADR-016 blue-green + ADR-017 Terraform), + tất cả Proposed (đúng — không ADR nào Accepted khi chưa có chữ ký thật). ASR → ADR đạt 12/15 + + lý do hợp lệ cho 3/15 còn lại (mục tiêu đạt; ASR-004 nay có 3 ADR, ASR-005/ASR-007 mỗi cái có + 2 ADR, không mâu thuẫn). POC-01/POC-02/diễn tập DR/inject lỗi chưa chạy (chặn ADR-005/006/009 + chuyển Accepted); chưa có Security/Legal (chặn ADR-008 hoàn toàn, và chặn cứng ADR-015 — + quyết định bảo mật không ai có thẩm quyền ký); Tech Lead + Security + Ops/SRE chưa ký thật; + ADR-013 cần Tech Lead + PO thật xác nhận; ADR-016 cần Ops/SRE chạy thử blue-green ở staging; + ADR-017 cần Tech Lead + Ops/SRE xác nhận công cụ (OQ-060). AG3: — chưa tới AG4: — chưa tới ``` -**Việc gần nhất:** `/sa-1-context e-commerce` *(sau khi BA qua G1 hoặc có ngoại lệ gate ghi rõ)* +**Việc gần nhất:** (1) Tech Lead/DBA chạy `POC-01`/`POC-02`; (2) Ops/SRE lên lịch và chạy diễn tập +DR + diễn tập inject lỗi; (3) PO chỉ định đại diện Pháp chế/Bảo mật (`OQ-007` — chặn `ADR-008` +hoàn toàn **và** chặn cứng `ADR-015`); (4) Tech Lead trả lời `OQ-010`/`OQ-026`/`OQ-027`/`OQ-060`; +(5) Ops/SRE chạy thử blue-green/rollback ở staging cho `ADR-016`; (6) khi đủ, chạy `sa-conformance` +xác nhận coverage rồi trình AG2 cho Tech Lead + Security + Ops/SRE ký thật. ## 13. Chấp nhận có ý thức +*Chỗ đứt được chấp nhận có ghi chép. Khác hoàn toàn với bỏ qua.* + | Chỗ đứt | Vì sao chấp nhận | Ai chấp nhận · ngày | Hạn xử lý | `DEC` | |---|---|---|---|---| +| `POC-01` (throughput SQS/EventBridge) chưa chạy | `ARISK-01`/`ADR-005` đã có kế hoạch POC + tiêu chí PASS/FAIL viết trước; chưa tới hạn (trước `ADR-001`/`ADR-005` chuyển `Accepted`) | PO uỷ quyền (duyệt từng phần `ARISK` v1.0) · 2026-09-12 | Trước khi `ADR-001`/`ADR-005` chuyển `Accepted` | `DEC-10` | +| `POC-02` (RDS gộp tải) chưa chạy | `ARISK-02`/`ADR-006` đã có kế hoạch POC + tiêu chí PASS/FAIL viết trước; chưa tới hạn (trước `ADR-001`/`ADR-006` chuyển `Accepted`) | PO uỷ quyền (duyệt từng phần `ARISK` v1.0) · 2026-09-12 | Trước khi `ADR-001`/`ADR-006` chuyển `Accepted` | `DEC-10` | +| Diễn tập DR chưa chạy | `QAS-008`/`ADR-009` đã ghi rõ điều kiện, đã chốt là điều kiện tiên quyết AG2 (`DEC-12`) | Điều phối dự án (thay Tech Lead, duyệt từng phần `QAS` v1.0) · 2026-09-14 | Trước khi ký AG2 | `DEC-12` | +| `ASM-11`/`ASM-12`/`ASM-14` (đơn giá AWS/tỷ giá/FTE Ops) chưa xác nhận | `TCO` duyệt từng phần chấp nhận cấu trúc 4 nhóm chi phí + kết luận thứ tự P2 rẻ hơn P1; số tuyệt đối chưa cần thiết để giữ hướng đi này | PO uỷ quyền (duyệt từng phần `TCO` v1.1) · 2026-09-12 | Trước khi ký AG1 toàn phần | `DEC-09` | +| 12 `ADR` giữ `Proposed`, chưa `Accepted` | Chưa có chữ ký thật Tech Lead + Security + Ops/SRE; 3/12 (`ADR-005/006/009`) còn cần POC/diễn tập PASS theo đúng `decision-radar.md §2/§6` | SA (theo quy tắc bộ SA, không tự chuyển `Accepted`) · 2026-09-15 | Trước khi ký AG2 | `DEC-17` | +| Mọi phê duyệt GĐ1/GĐ2 là "PO/Tech Lead uỷ quyền — điều phối dự án", không phải chữ ký thật | Dự án chạy thử, theo ngoại lệ gate đã ghi từ `DEC-01`; người dùng đã được cảnh báo lại nhiều lần và tái khẳng định muốn tiếp tục | Điều phối dự án (đại diện PO, dự án chạy thử) · 2026-09-12…15 | Trước khi trình AG1/AG2 cho người thật ký (`OQ-004`) | `DEC-01` | diff --git a/sa-output/e-commerce/00-index/INDEX_e-commerce.md b/sa-output/e-commerce/00-index/INDEX_e-commerce.md index c8d30d1..958afac 100644 --- a/sa-output/e-commerce/00-index/INDEX_e-commerce.md +++ b/sa-output/e-commerce/00-index/INDEX_e-commerce.md @@ -2,38 +2,160 @@ | | | |---|---| -| **Cập nhật** | 2026-09-10 | -| **Giai đoạn hiện tại** | Chưa bắt đầu — project mới khởi tạo qua `sa-lifecycle` (init) | -| **Gate gần nhất đã qua** | Chưa có | -| **ADR đang Proposed** | — | +| **Cập nhật** | 2026-09-15 | +| **Giai đoạn hiện tại** | GĐ2 · `sa-2-architecture` — **đủ 9/9 hoạt động** (`qas`/`asr`/`sad`/`icd`/`dat`/`sec`/`inf`/`fail`/`adr`). Đủ **8/8 loại artifact GĐ2** (`QAS` v1.0, `ASR` v1.0, `SAD` v1.3, `ICD` v1.0, `DAT` v1.1, `SEC` v1.1, `INF` v1.1, `FAIL` v1.1) + **17 `ADR`** (`ADR-001…017`). Mọi artifact 🟡 Draft đã được duyệt **từng phần** bởi "Điều phối dự án (thay mặt Tech Lead)" theo ngoại lệ gate `DEC-01` (dự án chạy thử, xem `DEC_e-commerce.md`) — **không phải chữ ký Tech Lead thật**. **Security và Ops/SRE chưa ký bất kỳ artifact nào** ở GĐ1 lẫn GĐ2 (`OQ-007` — chưa có người Pháp chế/Bảo mật; `OQ-004` — tính hợp lệ ký thay còn mở). GĐ1 (`sa-1-context`) đủ 4 artifact (`CTX` v1.2, `OPT` v1.0, `TCO` v1.1, `ARISK` v1.0), mỗi file duyệt từng phần bởi PO uỷ quyền. `OPT` chọn **P2** (modular monolith + managed AWS, tách riêng Payment) làm hướng đi cho GĐ2, điều kiện `OQ-010`/`OQ-012` (`DEC-06`) — đã được trả nợ ADR bằng `ADR-001`. | +| **Gate gần nhất đã qua** | **Chưa có.** AG1 — 4/4 artifact GĐ1 tồn tại, mỗi file tự chấm đủ tiêu chí cấu trúc nhưng nội dung còn `OQ-004` (tính hợp lệ ký thay), `OQ-005/006/007/008/013…017` (số thật ngân sách/deadline/vận hành/nhà cung cấp) mở, và `POC-01`/`POC-02` chưa chạy — PO/Tech Lead thật chưa ký. AG2 — 9/9 hoạt động và 8/8 artifact + 17 ADR đã có về **nội dung**, coverage `ASR→ADR` đạt 12/15 + 3 lý do hợp lệ (xem `DTM §3`), nhưng thiếu: chữ ký thật Tech Lead + Security + Ops/SRE (mới có Tech Lead ký thay có điều kiện trên từng file); `POC-01`/`POC-02`/diễn tập DR/diễn tập inject lỗi chưa chạy (chặn `ADR-005`/`ADR-006`/`ADR-009` `Accepted`, đồng thời diễn tập DR là điều kiện tiên quyết ký AG2 theo `DEC-12`); Security chưa có người (`OQ-007` — chặn `ADR-008` hoàn toàn, chặn cứng `ADR-015`, `SEC` chưa có hiệu lực phủ quyết AG2). | +| **ADR đang Proposed** | **17** (`ADR-001…017`) — tất cả `Proposed`, **không cái nào `Accepted`**. 3 ADR radar ≥8 (`ADR-005` SQS FIFO+EventBridge, `ADR-006` RDS gộp schema-per-module, `ADR-009` HA/DR nhóm giao dịch lõi) bắt buộc `POC-01`/`POC-02`/diễn tập DR PASS trước khi `Accepted` (`decision-radar.md §2/§6`). `ADR-008` (vùng lưu trữ PII) chặn hoàn toàn tới khi có đại diện Pháp chế/Bảo mật (`OQ-007`). `ADR-015` (Service JWT service-to-service) **chặn cứng** bởi cùng lý do — quyết định bảo mật không ai có thẩm quyền ký. 4 ADR mới nhất (`DEC-31`, 2026-09-15): `ADR-014` (Transactional Outbox cho publish sự kiện, radar 6), `ADR-015` (Service JWT ngắn hạn, radar 5), `ADR-016` (Blue-green qua AWS CodeDeploy, radar 6), `ADR-017` (IaC Terraform, radar 7). Xem `ADL_e-commerce.md` để biết mục lục đầy đủ, nguồn, và điều kiện `Accepted` riêng từng ADR. | ## Artifact | Loại | File mới nhất | Version | Status | Confidence | Cập nhật | |---|---|---|---|---|---| -| — | *(chưa có artifact giai đoạn nào — sẽ điền khi `sa-1-context` chạy)* | | | | | +| CTX | `01-context/CTX_e-commerce_v1.0.md` | 1.2 | 🟡 Draft (duyệt từng phần §2/§3/§5 — §4 chờ AG1 toàn phần cùng đợt) | 🔴 | 2026-09-12 | +| OPT | `01-context/OPT_e-commerce_v1.0.md` | 1.0 | 🟡 Draft (duyệt từng phần — chọn P2 có điều kiện `OQ-010`/`OQ-012`, Tech Lead chưa ký thật) | 🔴 | 2026-09-12 | +| TCO | `01-context/TCO_e-commerce_v1.0.md` | 1.1 | 🟡 Draft (duyệt từng phần — cấu trúc 4 nhóm chi phí + kết luận "P2 rẻ hơn P1"; đơn giá AWS/tỷ giá/FTE Ops chưa xác nhận) | 🔴 | 2026-09-12 | +| ARISK | `01-context/ARISK_e-commerce_v1.0.md` | 1.0 | 🟡 Draft (duyệt từng phần — 10 rủi ro + kế hoạch `POC-01`/`POC-02`; POC chưa chạy) | 🔴 | 2026-09-12 | +| QAS | `02-architecture/QAS_e-commerce_v1.0.md` | 1.0 | 🟡 Draft (duyệt từng phần — Tech Lead ký thay có điều kiện; 14 `QAS`; diễn tập DR chốt là điều kiện tiên quyết AG2; Security/Ops chưa ký) | 🔴 | 2026-09-14 | +| ASR | `02-architecture/ASR_e-commerce_v1.0.md` | 1.0 | 🟡 Draft (duyệt từng phần — 15 `ASR` + 12 `ADR` ứng viên chấp nhận; `ADR-005/006/009` chờ POC/diễn tập DR; Security/Ops chưa ký) | 🔴 | 2026-09-15 | +| SAD | `02-architecture/SAD_e-commerce_v1.0.md` | 1.3 | 🟡 Draft (duyệt từng phần bản v1.0; v1.1 link 12 ADR; v1.2 sửa lỗi đếm `IF-nn` 22→17 — đóng `OQ-029`; v1.3 sửa nhất quán §6.1/§8 theo `ADR-013`; C4 Context/Container/Component + deployment view + 15 `CMP` (ma trận `ASR→CMP` 15/15); Security/Ops chưa ký) | 🔴 | 2026-09-15 | +| ICD | `02-architecture/ICD_e-commerce_v1.0.md` | 1.0 | 🟡 Draft (duyệt từng phần — catalog 17 `IF-nn` + chi tiết `IF-002` (Cart&Checkout); xác nhận/điều chỉnh `API_US002-003` của BA; đối tác ngoài/Email-SMS chưa có contract thật; Security/Ops chưa ký) | 🔴 | 2026-09-15 | +| DAT | `02-architecture/DAT_e-commerce_v1.0.md` | 1.1 | 🟡 Draft (duyệt từng phần bản v1.0 — ownership 15 `CMP`, mô hình `Order`/`OrderSeller`/`Payment`, idempotency, PITR; v1.1 chỉ link `ADR-014` (Outbox), không đổi nội dung khác; **§5 PII/retention/whitelist CHƯA CÓ HIỆU LỰC** — chờ `OQ-007`; Security/Ops chưa ký) | 🔴 | 2026-09-15 | +| SEC | `02-architecture/SEC_e-commerce_v1.0.md` | 1.1 | 🟡 Draft (duyệt từng phần bản v1.0 — 31 `THR` STRIDE, map `ROLE-01/02`, mô hình authn/authz, SAQ A, rate limit đề xuất 30/10/10 req/phút; v1.1 chỉ link `ADR-015` (Service JWT); **§5/§8.2 CHƯA CÓ HIỆU LỰC** — Security chưa có người (`OQ-007`), `SEC` chưa có hiệu lực phủ quyết AG2; Ops/SRE chưa ký) | 🔴 | 2026-09-15 | +| INF | `02-architecture/INF_e-commerce_v1.0.md` | 1.1 | 🟡 Draft (duyệt từng phần bản v1.0 — topology AWS `ap-southeast-1`, HA/auto-scaling, kế hoạch diễn tập DR 3 kịch bản, CI/CD blue-green; v1.1 chỉ link `ADR-016`/`ADR-017`; Security/Ops/SRE chưa ký) | 🔴 | 2026-09-15 | +| FAIL | `02-architecture/FAIL_e-commerce_v1.0.md` | 1.1 | 🟡 Draft (duyệt từng phần bản v1.0 — 13 phụ thuộc `FM-01…13`, bảng mã lỗi §5, `FIT-16…22`; **`OQ-034` chọn Lựa chọn B** (bất đồng bộ hoá khởi tạo thanh toán) → `ADR-013`; v1.1 sửa nhất quán §1.2 theo `ADR-013`; Security/Ops chưa ký) | 🔴 | 2026-09-15 | +| ADR-001…017 | `02-architecture/adr/ADR-001…017_*.md` | — | 17× `Proposed` — không ADR nào `Accepted` (thiếu chữ ký thật Tech Lead/Security/Ops; `ADR-005/006/009` radar ≥8 chờ `POC-01`/`POC-02`/diễn tập DR; `ADR-008`/`ADR-015` chặn cứng bởi `OQ-007`) | 🔴 | 2026-09-15 | ## Open Question đang mở -| ID | Nội dung | Hỏi ai | Từ ngày | Chặn gì | -|---|---|---|---|---| +*(Sổ đầy đủ tại `00-index/OQ_e-commerce.md` v1.25. Bảng dưới liệt kê **toàn bộ 59 OQ đang mở** +— `OQ-001..063` trừ 4 câu đã đóng: `OQ-002`, `OQ-009`, `OQ-011`, `OQ-029`, xem "Open Question đã +đóng" trong sổ gốc để biết nội dung/người trả lời.)* + +| ID | Nội dung ngắn | Hỏi ai | Chặn gì | +|---|---|---|---| +| OQ-001 | BA chưa ký G1 chính thức cho `BRIEF_CartCheckout` — chấp nhận `DRV` giữ Confidence 🔴 tiếp tục hay dừng? | PO sàn + BA | Nâng Confidence `CTX`; ký AG1 | +| OQ-003 | Giữ phạm vi Toàn sàn hay thu hẹp về Giỏ hàng & Checkout? | PO sàn + Tech Lead | Khối lượng/độ tin cậy `OPT`/`TCO`/`ARISK` | +| OQ-004 | Ngoại lệ gate `DEC-01` có cần PO sàn thật xác nhận lại bằng văn bản riêng? | PO sàn (người thật) | Tính hợp lệ mọi phê duyệt GĐ1/GĐ2 khi trình AG1/AG2 | +| OQ-005 | Ngân sách hạ tầng/tháng + chi phí một lần đã duyệt là bao nhiêu? | PO/tài chính | `CON-01`; `TCO`; loại phương án `OPT` | +| OQ-006 | Deadline dự án chính thức? (brief "~9-12 tháng" vs hồ sơ thầu "7 tháng" không khớp) | PO/PM | `CON-02`; kịch bản `OPT` | +| OQ-007 | Ai là đại diện Pháp chế/Bảo mật xác nhận residency NĐ13/2023? `DAT §5`/`SEC §5,§8.2` là đề xuất CHƯA CÓ HIỆU LỰC tới khi có người | PO sàn (chỉ định người) | `CON-06`; `DAT`/`INF`; hiệu lực phủ quyết `SEC`; `ADR-008`/`ADR-015` `Accepted` | +| OQ-008 | Đội vận hành sau go-live nội bộ hay thuê ngoài, quy mô? | PM/SRE | `CON-05`/`08`; `INF` | +| OQ-010 | Tech Lead xác nhận đội thi công thật có kinh nghiệm production Kafka/MSK/OpenSearch/EKS? | Tech Lead | Rủi ro kỹ thuật `OPT`; `ARISK-05`; `ADR-001`/`ADR-005` `Accepted` | +| OQ-012 | Chạy POC throughput SQS/EventBridge trước khi chốt P2, hay chấp nhận rủi ro tạm? | Tech Lead | `ADR` message backbone; `ARISK-01`/`POC-01` | +| OQ-013 | Xác nhận đơn giá AWS `ap-southeast-1` thật (Pricing Calculator/báo giá) | Tech Lead/DevOps + tài chính | Độ tin cậy `TCO`; ngân sách `INF` | +| OQ-014 | Biểu phí giao dịch VNPay/Momo thật + GMV dự kiến năm 1? | PO/tài chính | `TCO` (`NL-03`) | +| OQ-015 | Biểu phí API GHN/GHTK theo hợp đồng thật? | PM | `TCO` (`NL-05`); `ARISK-04` | +| OQ-016 | Nhà cung cấp Email/SMS cụ thể + biểu phí? | PM/Tech Lead | `TCO` (`NL-04`); `ARISK-10`; `ICD` | +| OQ-017 | Báo giá pentest hàng năm + ASV scan hàng quý (SAQ A) thật? | PO/Security | `TCO` (`NL-07`) | +| OQ-018 | Ngưỡng p95 `GET /v1/cart` — SA đề xuất ≤500ms | PO + Tech Lead | `QAS-003` baseline; `FIT` GĐ3 | +| OQ-019 | Ngưỡng p95 `PATCH`/`DELETE /v1/cart/items` — SA đề xuất ≤300ms | PO + Tech Lead | `QAS-004` baseline; `FIT` GĐ3 | +| OQ-020 | Cửa sổ bảo trì loại trừ ngân sách lỗi — SA đề xuất ≤2 giờ/tháng | PO | `QAS-007`; chính sách release `INF` | +| OQ-021 | Tần suất job đối soát thanh toán — SA đề xuất ≤15 phút/lần | Tech Lead | `QAS-014`; `DAT`/`INF` | +| OQ-022 | Lịch diễn tập DR đầu tiên — **điều kiện tiên quyết ký AG2** đã chốt (`DEC-12`), ngày thật chờ Ops/SRE (nối `OQ-056`) | Ops/SRE | `QAS-008`; điều kiện AG2 | +| OQ-023 | Ngưỡng rate limit Guest cart — SEC đề xuất 30 req/phút theo `session_id` + 60 req/phút theo IP, không tự quyết thay Security | Tech Lead + Security | Hoạt động `sec`/`icd`; `NFR-SEC-03` (BA) | +| OQ-024 | Phương thức MFA Admin — chốt TẠM TOTP app (`ASM-20`), chưa xác nhận thật | Tech Lead + Security | `ASR-009`; `SEC` | +| OQ-025 | Dịch nội dung seller sang 5 ngôn ngữ ở MVP? — chốt TẠM không dịch (`ASM-21`) | PO + Tech Lead | `ASR-015`; `DAT` | +| OQ-026 | Số ECS service thật cho 2 nhóm triển khai — chốt TẠM 2 service riêng (`ASM-23`, nối `OQ-055`) | Tech Lead + Ops/SRE | `SAD §7`; `ADR-012` | +| OQ-027 | Identity & Access thuộc nhóm nào — chốt TẠM Nhóm Giao dịch (`ASM-22`) | Tech Lead | `CMP-02`; `ADR-012` | +| OQ-028 | `IF-021` in-process hay cross-network? — chốt TẠM cross-network (`ASM-24`) | Tech Lead | `ICD §3.6`; `FAIL`; `QAS-002` | +| OQ-030 | Xác nhận schema sự kiện `OrderPlaced`/`PaymentConfirmed` + `IF-006` nhận `sellerId` — chốt TẠM chấp nhận (`ASM-26`) | Tech Lead | Thi công Cart&Order/Payment; `DAT` | +| OQ-031 | Tên header correlation id — đề xuất `X-Request-Id` | Tech Lead | Chuẩn hoá observability | +| OQ-032 (SA) | Chiều gọi `IF-022` — chốt TẠM Cart&Order → Seller Mgmt (`ASM-25`) | Tech Lead | `ICD §3.7`; denormalize `sellerName` | +| OQ-033 (SA) | Denormalize `sellerName` vào `CartItem`? — chốt TẠM chấp nhận | Tech Lead + DBA | `DAT`; `QAS-003` | +| OQ-034 | Ngân sách timeout checkout vượt `QAS-002` — **đã chọn Lựa chọn B** (bất đồng bộ hoá khởi tạo thanh toán), đã viết `ADR-013`, chờ Tech Lead + PO **thật** xác nhận | Tech Lead + PO | `ADR-013` `Accepted`; `SRS`/`AC` US-004 (BA); `ICD` polling | +| OQ-035 | Ngưỡng circuit breaker `FM-01/02/03/04/12/13` — chốt TẠM đề xuất SA | Tech Lead + SRE | Cấu hình thi công; `FIT-19/20/21` | +| OQ-036 | DLQ retention 14 ngày + cảnh báo lag >5 phút — chốt TẠM | Tech Lead + SRE | `INF` retention/alerting | +| OQ-037 | Kích thước bulkhead (connection pool) — chờ `POC-02` (nối `OQ-061`) | DBA + Tech Lead | Cấu hình pool thi công | +| OQ-038 | Giữ transaction DB mở xuyên `IF-006`/`007/008`? + 3 mã lỗi mới US-004 chưa có trong `SRS` | Tech Lead + BA | `SAD §6.1`; `SRS`/`AC` US-004 | +| OQ-039 | SLA xử lý thủ công khi GHN+GHTK cùng lỗi? | PO + Ops | Runbook vận hành GĐ3 | +| OQ-040 | Cache nội dung `Cart` cho fallback RDS chậm? — SA nghiêng Phương án B (cache-aside); mã lỗi `E-CART-0007` | Tech Lead | `DAT`/`INF` cache strategy; mã lỗi `SRS` | +| OQ-041 | Cơ chế FE lấy `redirectUrl` — chốt TẠM polling, hay SSE/WebSocket? | Tech Lead (+ FE) | Contract endpoint `ICD` lượt sau; thiết kế FE US-004 | +| OQ-042 | Ngưỡng job dọn `Order` kẹt `PENDING_PAYMENT_INIT` — chốt TẠM 5 phút | Tech Lead | Thiết kế job quét `dat`/`inf` | +| OQ-043 | 1 `Order` = 1 `Payment` hay tách theo `OrderSeller`? | Tech Lead + PO | Mô hình `payment.order_id`; `IF-006` | +| OQ-044 | Transactional Outbox (chốt TẠM, đã viết `ADR-014`) hay job quét đơn giản? | Tech Lead | `ADR-014` `Accepted`; thiết kế relay `INF` | +| OQ-045 | Công cụ migration schema — Flyway hay Liquibase? | Tech Lead | CI/CD; rollback schema | +| OQ-046 | Đọc `Cart`/`Order` route sang read replica hay luôn primary? — SA đề xuất chỉ Catalog dùng replica | Tech Lead | Cấu hình routing `INF`; độ tươi dữ liệu | +| OQ-047 | Kiến trúc audit trail — chốt TẠM (a) mỗi module tự ghi, không thêm `CMP-16` | Tech Lead + Security | Danh sách `CMP`; `ADR-001` nếu đổi hướng | +| OQ-048 | VNPay/Momo hỗ trợ redirect thuần (giữ phạm vi SAQ A)? | Tech Lead + Security | `SEC §8.1`; `ADR-002` | +| OQ-049 | Cơ chế chữ ký/HMAC webhook cụ thể của 4 đối tác? | Tech Lead | `THR-17`/`22`; kiểm chứng `ADR-004` | +| OQ-050 | PA-3 service JWT (chốt TẠM, đã viết `ADR-015`) hay PA-2 mTLS? | Tech Lead + Security + Ops/SRE | `ADR-015` `Accepted`; `INF` TB3/TB4; `THR-09`/`13` | +| OQ-051 | Số cụ thể Customer JWT TTL/refresh/thu hồi/rotation | Tech Lead | Thiết kế `CMP-02` | +| OQ-052 | Ngưỡng account lockout theo vai trò + rate-limit login | Tech Lead + Security | `THR-28`/`31`; `CMP-02` | +| OQ-053 | 3 trường whitelist chia sẻ seller hiển thị đầy đủ hay che một phần? | Security/Legal + PO | `DAT §5.2`; UI đơn hàng Seller | +| OQ-054 | Cross-region snapshot Payment (`TCO`) mâu thuẫn `ADR-009` (không multi-region)? | Tech Lead + Ops/SRE + PO | `INF §5.2` đối chiếu `TCO`; `ADR-009` | +| OQ-055 | Split ECS task GD/HT (A 2/2, B 6/4) + ngưỡng auto-scaling — nối `OQ-026` | Tech Lead + Ops/SRE | `INF §4.2`; Terraform GĐ3 | +| OQ-056 | Lịch diễn tập DR thật (3 kịch bản) — nối `OQ-022` | Ops/SRE | Điều kiện tiên quyết ký AG2 | +| OQ-057 | IP allowlist đối tác ngoài? | Tech Lead | `INF §8.3`; phối hợp đối tác | +| OQ-058 | ElastiCache SPOF kịch bản A — chốt TẠM giữ nguyên (không thêm replica), đánh đổi thuộc PO | PO + Ops/SRE | `INF §4.3`; cấu hình GĐ3 | +| OQ-059 | Retention log/backup + tỉ lệ sample X-Ray | Tech Lead + Ops/SRE | `INF §5.2`/`§6.1`; chi phí lưu trữ | +| OQ-060 | Công cụ IaC (chốt TẠM Terraform, đã viết `ADR-017`) + ngưỡng coverage test | Tech Lead | `ADR-017` `Accepted`; `INF §7.1` | +| OQ-061 | Kích thước connection pool RDS/HTTP — chờ `POC-02` — nối `OQ-037` | DBA + Tech Lead | Cấu hình RDS thật GĐ3 | +| OQ-062 | Non-prod tách VPC riêng hay account riêng? | Tech Lead + Ops/SRE | `INF §2`/`§3` | +| OQ-063 | Đội Ops/SRE thật (nội bộ/thuê ngoài, quy mô) — nối `OQ-008` | PM/SRE | `INF §5.4`/`§6.5`; on-call; tần suất diễn tập DR | + +## Sổ quyết định (`DEC`) — tóm tắt DEC-01..31 + +*(Nội dung đầy đủ tại `00-index/DEC_e-commerce.md` v1.29. Toàn bộ 31 `DEC` đều gắn ngoại lệ gate +`DEC-01` (dự án chạy thử, Điều phối dự án ký thay PO/Tech Lead) — không phải chữ ký thật.)* + +| ID | Việc chính | Ngày | +|---|---|---| +| DEC-01 | Ngoại lệ gate — chạy `sa-1-context` khi BA chưa qua G1 | 2026-09-12 | +| DEC-02 | Giả định tạm "team MVP chuẩn" cho `CON` nhóm Con người | 2026-09-12 | +| DEC-03 | Tiếp tục ngoại lệ gate sang Bước 2 (Ràng buộc) | 2026-09-12 | +| DEC-04 | Đóng `OQ-009` — `SAD.md`/hồ sơ thầu làm điểm khởi đầu tham khảo cho `OPT`, có điều kiện | 2026-09-12 | +| DEC-05 | Tiếp tục ngoại lệ gate sang Bước 4 (Phương án) | 2026-09-12 | +| DEC-06 | Chọn **P2** làm hướng đi tạm cho GĐ2, điều kiện `OQ-010`/`OQ-012` — đã trả nợ bằng `ADR-001` | 2026-09-12 | +| DEC-07 | Tiếp tục ngoại lệ gate sang Bước 5, phần `TCO` | 2026-09-12 | +| DEC-08 | Tiếp tục ngoại lệ gate sang Bước 5, phần `ARISK` | 2026-09-12 | +| DEC-09 | Duyệt từng phần `TCO` v1.1 | 2026-09-12 | +| DEC-10 | Duyệt từng phần `ARISK` v1.0 | 2026-09-12 | +| DEC-11 | Bắt đầu hoạt động `QAS` (GĐ2) dù AG1 chưa ký thật | 2026-09-14 | +| DEC-12 | Duyệt từng phần `QAS` v1.0 — chốt diễn tập DR là điều kiện tiên quyết AG2 | 2026-09-14 | +| DEC-13 | Bắt đầu hoạt động `ASR` | 2026-09-14 | +| DEC-14 | Duyệt từng phần `ASR` v1.0 (15 `ASR` + 12 `ADR` ứng viên) | 2026-09-15 | +| DEC-15 | Bắt đầu hoạt động `SAD` | 2026-09-15 | +| DEC-16 | Duyệt từng phần `SAD` v1.0 | 2026-09-15 | +| DEC-17 | Bắt đầu hoạt động `adr` — viết đủ `ADR-001…012` | 2026-09-15 | +| DEC-18 | Bắt đầu hoạt động `ICD` | 2026-09-15 | +| DEC-19 | Duyệt từng phần `ICD` v1.0 (17 `IF-nn`) | 2026-09-15 | +| DEC-20 | Sửa lỗi nhất quán `SAD` (đếm `IF-nn` 22→17, đóng `OQ-029`) lên v1.2 | 2026-09-15 | +| DEC-21 | Bắt đầu hoạt động `FAIL` | 2026-09-15 | +| DEC-22 | Duyệt từng phần `FAIL` v1.0 — chọn Lựa chọn B cho `OQ-034` | 2026-09-15 | +| DEC-23 | Viết `ADR-013` (bất đồng bộ hoá khởi tạo thanh toán) + sửa `SAD` lên v1.3, `FAIL` lên v1.1 | 2026-09-15 | +| DEC-24 | Bắt đầu hoạt động `DAT` | 2026-09-15 | +| DEC-25 | Duyệt từng phần `DAT` v1.0 — chốt TẠM Outbox/audit (a)/5 phút/polling | 2026-09-15 | +| DEC-26 | Review nội dung `ADR-013` — giữ `Proposed` | 2026-09-15 | +| DEC-27 | Bắt đầu hoạt động `SEC` | 2026-09-15 | +| DEC-28 | Duyệt từng phần `SEC` v1.0 — chốt TẠM PA-3 cho `OQ-050` | 2026-09-15 | +| DEC-29 | Bắt đầu hoạt động `INF` | 2026-09-15 | +| DEC-30 | Duyệt từng phần `INF` v1.0 — chốt TẠM giữ nguyên `TCO` (không thêm replica) cho `OQ-058` | 2026-09-15 | +| DEC-31 | Viết `ADR-014`/`015`/`016`/`017`, link vào `DAT`/`SEC`/`INF` (mỗi file `+0.1`, chỉ link) | 2026-09-15 | ## Rủi ro kiến trúc mức cao đang mở +*(6/10 rủi ro mức 🔴 Cao trong sổ `01-context/ARISK_e-commerce_v1.0.md` §1/§3; 3 mức 🟠 Trung bình ++ 1 mức 🟡 Thấp không liệt kê ở đây, xem sổ đầy đủ.)* + | ID | Rủi ro | Chủ | Cách hạ | Hạn | |---|---|---|---|---| +| ARISK-01 | SQS/EventBridge chưa đo throughput thật cho `OrderPlaced`/`PaymentConfirmed` ở tải đỉnh flash sale | Tech Lead | `POC-01` (chưa chạy) — throughput ≥100 msg/s, p99 ≤2s, 0 mất message | Trước `ADR-005` chuyển `Accepted` (`OQ-012`) | +| ARISK-02 | 1 cụm RDS chính chưa đo tải ghi/đọc gộp cho toàn bộ module ngoài Payment | Tech Lead/DBA | `POC-02` (chưa chạy) — p95 write ≤300ms, p95 read ≤200ms, CPU <75% | Trước `ADR-006` chuyển `Accepted` | +| ARISK-03 | VNPay/Momo chưa sandbox/hợp đồng thật; webhook xác nhận thanh toán chưa xác minh gần thời gian thực | Tech Lead + PO | Đàm phán sandbox sớm; job đối soát bù (`FAIL`/`DAT`, cần xác minh lại) | Trước GĐ2 kết thúc (`ICD`) | +| ARISK-05 | Đội thi công thật chưa xác nhận kinh nghiệm production Kafka/MSK/OpenSearch/EKS (`OQ-010`) | Tech Lead | Xác nhận năng lực đội thật; thuê chuyên gia tư vấn nếu `POC-01` fail | Trước khi chốt `ADR-001`/`ADR-005` `Accepted` | +| ARISK-06 | Chia sẻ PII cho seller khi tách đơn chưa rà soát theo NĐ13/2023; residency chưa xác nhận | PO (chỉ định người) → Legal/Security | PO chỉ định đại diện Pháp chế (`OQ-007`); `DAT §5`/`SEC §5,§8.2` đã chuẩn bị đề xuất — **CHƯA CÓ HIỆU LỰC**, chờ Legal/Security phủ quyết | Trước `ADR-008`/`ADR-015` `Accepted`, chậm nhất trước go-live | +| ARISK-07 | Ngân sách vận hành 3 năm thật (11,2–19,1 tỷ VND tuỳ phương án) chưa được PO/tài chính xác nhận khả năng chi trả | PO/tài chính | Trình `TCO` đầy đủ (đã lập); nếu ngân sách thấp hơn — dùng P2 làm phương án cắt giảm | Trước khi ký AG1 | ## Ghi chú khởi tạo -- Cây thư mục `01-context/`, `02-architecture/adr/`, `03-enablement/`, `04-evolution/` sẽ được - tạo bởi skill giai đoạn tương ứng khi có artifact đầu tiên (không tạo thư mục/rỗng trước). -- Trạng thái đồng bộ với bộ BA tại thời điểm init: `ba-output/e-commerce/00-index/INDEX_e-commerce.md` - ghi "Giai đoạn hiện tại: GĐ1 · Discovery (chưa bắt đầu)", **BA chưa qua G1**. Theo - `references/workflow.md §4`, SA GĐ1 cần BA đã qua G1 (có `BRIEF`/`GOAL`/`RQ`) để có driver - chấm phương án. Đây chỉ là ghi nhận hiện trạng lúc `init`, không chặn việc tạo cấu trúc thư - mục rỗng; nó **sẽ chặn** khi chạy `/sa-1-context` thật (xem `Bẫy thường gặp` trong - `sa-lifecycle/SKILL.md`). -- Dự án e-commerce là "dự án chạy thử" theo ghi chú điều phối: gate BA đang chạy bằng các - ngoại lệ `DEC-02..07` (không có Designer, PO ký thay). Việc này không ảnh hưởng cấu trúc SA - vừa khởi tạo, nhưng sẽ ảnh hưởng `Confidence` của `CTX`/`OPT` khi GĐ1 SA thực sự bắt đầu nếu - BA vẫn chưa qua G1 tại thời điểm đó. +- Cây thư mục `01-context/`, `02-architecture/adr/`, `03-enablement/`, `04-evolution/` được tạo + bởi skill giai đoạn tương ứng khi có artifact đầu tiên. `03-enablement/` và `04-evolution/` + **chưa được tạo** — GĐ3/GĐ4 chưa bắt đầu. +- Dự án e-commerce là "dự án chạy thử": gate SA/BA đang chạy bằng các ngoại lệ `DEC-01..31` (SA) + và `DEC-02..07` (BA), không có Designer, PO ký thay. Mọi phê duyệt hiện tại là "PO/Tech Lead + uỷ quyền — Điều phối dự án", **không phải chữ ký PO/Tech Lead/Security/Ops-SRE thật** (`OQ-004`). +- `sa-conformance` nên rà lại độc lập ở lần đồng bộ kế tiếp — `ADL`/`DTM` đã được cập nhật bởi + `sa-2-architecture` (hoạt động `adr`, `DEC-31`) khi ghi 4 ADR cuối, chưa qua `sa-conformance` + độc lập xác nhận coverage. +- Trạng thái đồng bộ với bộ BA: `ba-output/e-commerce/00-index/INDEX_e-commerce.md` — đối chiếu + `NFR↔QAS`, `API↔ICD`, `RBAC↔SEC`, `BR↔ADR` xem `DTM §8` (Đối chiếu chéo với bộ BA). diff --git a/sa-output/e-commerce/00-index/OQ_e-commerce.md b/sa-output/e-commerce/00-index/OQ_e-commerce.md index 2530c3f..197ec95 100644 --- a/sa-output/e-commerce/00-index/OQ_e-commerce.md +++ b/sa-output/e-commerce/00-index/OQ_e-commerce.md @@ -2,20 +2,45 @@ | | | |---|---| -| **Version** | 1.0 | -| **Date** | 2026-09-10 | -| **Author** | SA (qua skill sa-lifecycle — khởi tạo) | +| **Version** | 1.25 | +| **Date** | 2026-09-15 | +| **Author** | SA (qua skill sa-1-context, sa-2-architecture) | | **Status** | 🟡 Draft — cập nhật liên tục qua các giai đoạn | | **Approved by** | — *(sổ theo dõi, không cần baseline riêng)* | -| **Source** | Khởi tạo trống — chưa có artifact GĐ nào của SA | +| **Source** | `01-context/CTX_e-commerce_v1.0.md` (v1.2 trong header) §3, §4, §7, §7.1 · `01-context/OPT_e-commerce_v1.0.md` §1, §2, §9 · `01-context/TCO_e-commerce_v1.0.md` §4, §8 · `01-context/ARISK_e-commerce_v1.0.md` §8 · `02-architecture/QAS_e-commerce_v1.0.md` §E · `02-architecture/ASR_e-commerce_v1.0.md` §E · `02-architecture/SAD_e-commerce_v1.0.md` v1.3 §6.1, §8, §11 · `02-architecture/ICD_e-commerce_v1.0.md` §0.1, §8 · `02-architecture/FAIL_e-commerce_v1.0.md` v1.1 §1.2, §10 · `02-architecture/adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md` · `02-architecture/DAT_e-commerce_v1.0.md` §4.1, §4.3, §7.3, §10, §12 · `02-architecture/SEC_e-commerce_v1.0.md` §2.4, §5.3, §11 · `02-architecture/INF_e-commerce_v1.0.md` §10, §15 | | **Scope** | Toàn dự án e-commerce (kiến trúc) | -| **Confidence** | 🟡 Sổ theo dõi rỗng lúc khởi tạo, chưa có nội dung để đánh giá | +| **Confidence** | 🔴 Theo `CTX`/`OPT`/`TCO`/`ARISK`/`QAS`/`ASR`/`SAD` gốc — BA chưa ký G1, AG1 chưa ký, xem `DEC-01`/`DEC-11`/`DEC-12`/`DEC-14`/`DEC-15`/`DEC-16`/`DEC-27` (SA) | ## Change Log | Version | Date | Người sửa | Thay đổi | ADR/DEC | |---|---|---|---|---| | 1.0 | 2026-09-10 | SA (qua skill sa-lifecycle) | Khởi tạo sổ OQ kiến trúc, khung rỗng | — | +| 1.1 | 2026-09-12 | SA (qua skill sa-1-context) | Thêm `OQ-001..OQ-004` từ `CTX_e-commerce_v1.0.md` (hoạt động Driver, GĐ1) | `DEC-01` | +| 1.2 | 2026-09-12 | PO (uỷ quyền, Điều phối dự án) — tác vụ sign | Đóng `OQ-002` bằng quyết định dùng giả định tạm "team MVP chuẩn" (🔴) cho Bước 2, xem `DEC-02` | `DEC-02` | +| 1.3 | 2026-09-12 | SA (qua skill sa-1-context, hoạt động `constraints`) | Thêm `OQ-005..OQ-009` từ `CTX_e-commerce_v1.0.md (v1.1 trong header)` §3/§7 (ngân sách, deadline, đại diện Pháp chế cho residency NĐ13/2023, đội vận hành sau go-live, có neo theo `SAD.md`/hồ sơ thầu cho Bước 4 hay không) | `DEC-03` | +| 1.4 | 2026-09-12 | SA (qua skill sa-1-context, hoạt động `as-is`) | Đóng `OQ-009` (chấp nhận `SAD.md`/hồ sơ thầu làm điểm khởi đầu tham khảo cho Bước 4, với điều kiện vẫn dựng ≥1 phương án độc lập) — xem `DEC-04`. Bổ sung "câu trả lời tạm" cho `OQ-005`/`OQ-006` (giữ mở, dùng số hồ sơ thầu làm mốc tham khảo, chưa PO xác nhận số thật) theo `CTX_e-commerce_v1.0.md (v1.2 trong header)` §4.3, §7 | `DEC-04` | +| 1.5 | 2026-09-12 | SA (qua skill sa-1-context, hoạt động `options`) | Thêm `OQ-010..OQ-012` từ `OPT_e-commerce_v1.0.md` §9 (kinh nghiệm team thật với Kafka/MSK/OpenSearch/EKS; chọn P1 hay P2 — nội dung cần ký AG1; thời điểm chạy POC throughput SQS/EventBridge) | `DEC-05` | +| 1.6 | 2026-09-12 | PO (uỷ quyền, Điều phối dự án) — tác vụ sign | Đóng `OQ-011` bằng quyết định duyệt từng phần: chọn **P2** làm nền cho Bước 5/GĐ2, điều kiện `OQ-010`/`OQ-012` (xem `DEC-06`). `OQ-010`, `OQ-012`, `OQ-004` giữ mở nguyên trạng | `DEC-06` | +| 1.7 | 2026-09-12 | SA (qua skill sa-1-context, hoạt động `cost-risk`) | Thêm `OQ-013..OQ-017` từ `TCO_e-commerce_v1.0.md` §4/§8 và `ARISK_e-commerce_v1.0.md` §8 (xác minh đơn giá AWS; biểu phí VNPay/Momo + GMV; biểu phí GHN/GHTK; nhà cung cấp Email/SMS; báo giá pentest/ASV) | `DEC-07`, `DEC-08` | +| 1.8 | 2026-09-14 | SA (qua skill sa-2-architecture, hoạt động `qas`) | Thêm `OQ-018..OQ-023` từ `QAS_e-commerce_v1.0.md` §E (ngưỡng latency `GET /v1/cart` và `PATCH`/`DELETE /v1/cart/items` — SA đề xuất, nối `OQ-033` của BA; cửa sổ bảo trì loại trừ ngân sách lỗi; tần suất job đối soát thanh toán; lịch diễn tập DR đầu tiên; ngưỡng rate limit Guest) | `DEC-11` | +| 1.9 | 2026-09-14 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign trên `QAS_e-commerce_v1.0.md` | `OQ-018/019/020/021` **giữ nguyên mở** (chỉ chấp nhận TẠM số đề xuất làm baseline, chưa xác nhận thật). `OQ-022` cập nhật: đã chốt điều kiện "diễn tập DR phải thực hiện trước khi ký AG2", ngày/lịch cụ thể vẫn chờ Ops/SRE — **giữ mở**. `OQ-023` không đổi. | `DEC-12` | +| 1.10 | 2026-09-14 | SA (qua skill sa-2-architecture, hoạt động `asr`) | Thêm `OQ-024..OQ-025` từ `ASR_e-commerce_v1.0.md` §E (phương thức MFA cho Admin — TOTP/SMS/khoá cứng; phạm vi i18n cho nội dung seller tự nhập và ai cung cấp bản dịch) | `DEC-13` | +| 1.11 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign trên `ASR_e-commerce_v1.0.md` | `OQ-024`/`OQ-025` **giữ nguyên mở** — chỉ chấp nhận TẠM hướng đi mặc định (`OQ-024`: TOTP app theo `ASM-20`; `OQ-025`: không dịch nội dung seller ở MVP theo `ASM-21`) làm baseline cho hoạt động `sad`/`sec` kế tiếp, chưa xác nhận thật bởi Security/PO. | `DEC-14` | +| 1.12 | 2026-09-15 | SA (qua skill sa-2-architecture, hoạt động `sad`) | Thêm `OQ-026..OQ-027` từ `SAD_e-commerce_v1.0.md` §7/§11 (khớp số ECS Fargate "monolith" của `TCO §3.2` với ranh giới 2 nhóm triển khai của `ASR-001`/`ASR-014`; vị trí Identity & Access trong nhóm triển khai nào, `ASM-22`) | `DEC-15` | +| 1.13 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign trên `SAD_e-commerce_v1.0.md` | `OQ-026`/`OQ-027` **giữ nguyên mở** — chỉ chấp nhận TẠM hướng đi mặc định (`OQ-026`: 2 ECS Fargate service riêng theo Nhóm Giao dịch/Nhóm Hỗ trợ, `ASM-23`; `OQ-027`: Identity & Access thuộc Nhóm Giao dịch, `ASM-22`) làm baseline cho hoạt động `icd`/`dat`/`sec`/`inf`/`fail` kế tiếp, chưa xác nhận thật bởi Tech Lead/Ops. | `DEC-16` | +| 1.14 | 2026-09-15 | SA (qua skill sa-2-architecture, hoạt động `icd`) | Thêm `OQ-028..OQ-033` từ `ICD_e-commerce_v1.0.md` §8 (ranh giới mạng `IF-021` mâu thuẫn giữa `SAD §4` legend và `OQ-026`; chênh lệch "22 vs 17" `IF-nn` của `SAD`; xác nhận schema sự kiện `OrderPlaced`/`PaymentConfirmed` + request `IF-006`; tên header correlation-id; chiều gọi `IF-022`; denormalize `sellerName` vào `CartItem`). Ghi nhận: `ICD` xác nhận/đóng đề xuất cho `OQ-034(BA)` (cấu trúc `GET /v1/cart` nhóm theo seller) và `OQ-032(BA)` (ownership Guest cùng cơ chế JWT) trong sổ BA — BA cần tự cập nhật sổ của mình để đóng chính thức. | `DEC-18` | +| 1.15 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign trên `ICD_e-commerce_v1.0.md` | `OQ-028`, `OQ-030`, `OQ-032`, `OQ-033` chốt TẠM hướng đi đề xuất của `ICD` (`ASM-24/25/26`, denormalize `sellerName`) làm baseline cho hoạt động `dat`/`sec`/`inf`/`fail` kế tiếp — cả bốn **giữ nguyên mở**, chờ Tech Lead thật xác nhận. `OQ-029` (chênh lệch số `IF-nn`) và `OQ-031` (tên header correlation-id) không đổi. | `DEC-19` | +| 1.16 | 2026-09-15 | SA (qua skill sa-2-architecture, hoạt động `sad`, sửa lỗi theo yêu cầu người duyệt) | **Đóng `OQ-029`**: rà toàn bộ `SAD` kết luận "22" là đếm nhầm, đúng 17 `IF-nn` (không bỏ sót interface nào) — `SAD_e-commerce_v1.0.md` sửa lên v1.2. `OQ-028` không đóng (vẫn chờ Tech Lead thật xác nhận ranh giới mạng `IF-021`) nhưng ghi nhận `SAD` nay đã hết mâu thuẫn nội bộ (legend §4, §4.1, §5, §6.1, §6.3, §7 đều nhất quán cross-network theo `ASM-24`). Ghi ngoại lệ tiếp tục gate ở `DEC-20`. | `DEC-20` | +| 1.17 | 2026-09-15 | SA (qua skill sa-2-architecture, hoạt động `fail`) | Thêm `OQ-034..040` từ `FAIL_e-commerce_v1.0.md` §10 (xung đột ngân sách timeout cộng dồn checkout — VNPay/Momo 10s kế thừa không dùng được nguyên trạng trong nhánh đồng bộ `IF-006`→`IF-007/008`, vượt `QAS-002` ~7% ngay cả sau khi siết còn 1.500ms; ngưỡng circuit breaker; DLQ retention SQS/EventBridge; bulkhead RDS/adapter đối tác; giữ transaction DB mở xuyên lời gọi Payment + thiếu mã lỗi US-004 Checkout; SLA xử lý thủ công khi GHN+GHTK cùng lỗi; thiếu cache nội dung giỏ hàng cho fallback khi RDS chậm). | `DEC-21` | +| 1.18 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign trên `FAIL_e-commerce_v1.0.md` | **`OQ-034`** cập nhật: chọn **Lựa chọn B** (bất đồng bộ hoá bước khởi tạo thanh toán) — trạng thái chuyển "đã chọn hướng B, chờ `ADR-013` (chưa viết) + Tech Lead/PO thật xác nhận", **giữ nguyên mở**. `OQ-035`/`OQ-036`/`OQ-037` chốt TẠM hướng đi/số đề xuất của `FAIL` (circuit breaker, DLQ retention 14 ngày + cảnh báo lag >5 phút, bulkhead chờ `POC-02`) làm baseline — cả ba **giữ nguyên mở**, chờ Tech Lead/SRE thật xác nhận. `OQ-038`, `OQ-039`, `OQ-040` không đổi. | `DEC-22` | +| 1.19 | 2026-09-15 | SA (qua skill sa-2-architecture, hoạt động `adr`) | Viết `ADR-013` (`Proposed`, bất đồng bộ hoá bước khởi tạo thanh toán — hiện thực hoá Lựa chọn B đã chọn ở `OQ-034`/`DEC-22`) và sửa nhất quán `SAD_e-commerce_v1.0.md` (lên v1.3, §6.1/§8) + `FAIL_e-commerce_v1.0.md` (lên v1.1, §1.2). **`OQ-034` cập nhật**: "đã chọn hướng B, đã có `ADR-013`, chờ Tech Lead + PO thật xác nhận trước khi `Accepted`" — **giữ nguyên mở**. Thêm `OQ-041` (cơ chế FE lấy `redirectUrl` — polling hay SSE/WebSocket) và `OQ-042` (thời gian giữ `Order` ở `PENDING_PAYMENT_INIT` trước khi coi là kẹt, cần job dọn dẹp) từ `ADR-013 §3`. Không sửa ADR khác, không sửa 12 ADR cũ. | `DEC-23`, `ADR-013` | +| 1.20 | 2026-09-15 | SA (qua skill sa-2-architecture, hoạt động `dat`) | Thêm `OQ-043..047` từ `DAT_e-commerce_v1.0.md` §12 (cardinality `Payment`/`Order` — 1 hay tách theo `OrderSeller`; chấp nhận Transactional Outbox pattern cho khoảng trống `FAIL §7` hay job quét đơn giản hơn, radar ~6, `ADR` bắt buộc chưa viết; công cụ migration schema Flyway/Liquibase; routing đọc `Cart`/`Catalog` sang read replica; thiếu `CMP` Audit & Compliance riêng ở P2 so với `docs/05` P1). **Bổ sung nội dung cho `OQ-007`** (đề xuất phân loại PII/retention + whitelist chia sẻ seller theo `ADR-008` PA-2 — vẫn chờ Pháp chế/Bảo mật, giữ mở), **`OQ-040`** (đánh giá 2 phương án cache nội dung `Cart` kèm hệ quả — SA nghiêng phương án B, giữ mở), **`OQ-042`** (đề xuất ngưỡng quét 5 phút + hành động job dọn `Order` kẹt — giữ mở, chờ Tech Lead). Không đóng `OQ` nào. | `DEC-24` | +| 1.21 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign trên `DAT_e-commerce_v1.0.md` | **`OQ-041`** (cơ chế FE): chốt TẠM **polling** làm baseline — giữ nguyên mở. **`OQ-042`** (ngưỡng job quét `Order` kẹt): chốt TẠM **5 phút** — giữ nguyên mở. **`OQ-044`** (Outbox vs job quét): chọn TẠM **Transactional Outbox** — yêu cầu SA viết `ADR-014` (`Proposed`) ở lượt hoạt động `adr` kế tiếp trước khi coi là chốt kiến trúc — giữ nguyên mở. **`OQ-047`** (kiến trúc audit trail): chọn TẠM **phương án (a)** — mỗi module tự ghi `audit_log` riêng, **không thêm `CMP-16`** — giữ nguyên mở, chờ Tech Lead + Security thật xác nhận. `OQ-043`, `OQ-045`, `OQ-046` **không đổi** — chưa có hướng TẠM nào được chọn. `OQ-007` (§5 DAT — PII/retention/whitelist): ghi nhận đề xuất DAT **CHƯA CÓ HIỆU LỰC**, vẫn chờ đại diện Pháp chế/Bảo mật phủ quyết — giữ nguyên mở. Tất cả chấp nhận ở mức TẠM (🔴), không phải xác nhận thật. | `DEC-25` | +| 1.22 | 2026-09-15 | SA (qua skill sa-2-architecture, hoạt động `sec`) | Thêm `OQ-048..053` từ `SEC_e-commerce_v1.0.md` §11 (hình thức tích hợp redirect/iframe với VNPay/Momo cho phạm vi SAQ A; cơ chế chữ ký/HMAC webhook cụ thể của 4 đối tác; chọn phương án service-to-service authn giữa Nhóm Giao dịch/Nhóm Hỗ trợ/Payment — PA-3 service JWT đề xuất, `ADR` ứng viên chưa viết; số cụ thể TTL/refresh/thu hồi JWT Customer; ngưỡng account lockout + rate-limit login; mức che 3 trường whitelist PII cho seller). **Bổ sung nội dung cho `OQ-007`** (SEC ghi rõ toàn bộ §5/§8.2 của `SEC` là đề xuất chờ Legal/Security phủ quyết, không coi là đã xác nhận — giữ mở) và **`OQ-023`** (SEC đề xuất số cụ thể 30 req/phút cho Guest cart `PATCH`/`DELETE` kèm hệ quả hai chiều, không tự quyết thay Security — giữ mở). `OQ-024` không đổi hướng TẠM (TOTP app), chỉ bổ sung ghi chú về backup code chưa thiết kế. Không đóng `OQ` nào. | `DEC-27` | +| 1.23 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign trên `SEC_e-commerce_v1.0.md` | **`OQ-050`** chốt TẠM hướng **PA-3** (service JWT ngắn hạn) cho service-to-service authn — yêu cầu SA viết `ADR-015` (`Proposed`) ở lượt hoạt động `adr` kế tiếp cùng `ADR-014` đang nợ; **giữ nguyên mở**, chờ Security + Ops/SRE thật xác nhận trước khi `Accepted`. `OQ-007` (SEC §5/§8.2 vẫn là đề xuất chờ Legal/Security, KHÔNG ký thay Security) và `OQ-023`/`OQ-024` **không đổi thêm** ở lượt sign này — giữ nguyên như đã ghi ở v1.22. | `DEC-28` | +| 1.24 | 2026-09-15 | SA (qua skill `sa-2-architecture`, chế độ `go`, hoạt động `inf`) | Thêm `OQ-054..OQ-063` từ `INF_e-commerce_v1.0.md` (hoạt động `inf`, GĐ2): `OQ-054` (mâu thuẫn `TCO §3.2` "cross-region snapshot Payment" vs `ADR-009` "không multi-region"), `OQ-055` (split ECS task GD/HT + ngưỡng auto-scaling, nối `OQ-026`), `OQ-056` (lịch diễn tập DR thật, nối `OQ-022`), `OQ-057` (IP allowlist đối tác ngoài), `OQ-058` (SPOF ElastiCache kịch bản A — thêm replica hay chấp nhận), `OQ-059` (retention log/backup, tỉ lệ sample X-Ray), `OQ-060` (công cụ IaC + ngưỡng coverage test cho P2), `OQ-061` (kích thước connection pool RDS/HTTP, nối `OQ-037`), `OQ-062` (tách VPC/account non-prod), `OQ-063` (nối `OQ-008`, đội Ops thật — không lặp lại nội dung, chỉ tham chiếu). | `DEC-29` | +| 1.25 | 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, ngoại lệ `DEC-01`) — tác vụ sign trên `INF_e-commerce_v1.0.md` | **`OQ-058`** chốt TẠM hướng **giữ nguyên `TCO`** — không thêm replica Redis ở kịch bản A, chấp nhận SPOF với hành vi fail-closed theo `FAIL`; **giữ nguyên mở**, chờ PO xác nhận cuối (đánh đổi chi phí/rủi ro thuộc thẩm quyền PO). `OQ-054`/`OQ-055`/`OQ-056`/`OQ-057` **không đổi** ở lượt sign này — giữ nguyên như đã ghi ở v1.24. | `DEC-30` | --- @@ -23,11 +48,80 @@ | ID | Nội dung | Hỏi ai | Từ ngày | Chặn gì | Nguồn | |---|---|---|---|---|---| +| OQ-001 | BA chưa ký G1 chính thức cho `BRIEF_CartCheckout` (`OQ-001`/`OQ-007` của BA còn mở). Xác nhận: chấp nhận để `DRV-01,02,03,07,08` giữ `Confidence` 🔴 và tiếp tục GĐ1 SA, hay dừng chờ BA ký G1 thật? | PO sàn (điều phối) + BA | 2026-09-12 | Nâng `Confidence` của `CTX`; ký AG1 | `CTX_e-commerce_v1.0.md` §7 | +| OQ-003 | Giữ nguyên phạm vi **Toàn sàn** cho Bước 2–5 GĐ1 SA hay thu hẹp về Giỏ hàng & Checkout để có Confidence cao hơn (driver các module khác chưa qua BRIEF/RISK module hoá)? | PO sàn + Tech Lead | 2026-09-12 | Khối lượng/độ tin cậy `OPT`/`TCO`/`ARISK` | `CTX_e-commerce_v1.0.md` §7 | +| OQ-004 | Xác nhận ngoại lệ gate `DEC-01` (SA) — chạy GĐ1 SA khi BA chưa qua G1 — có cần PO sàn thật xác nhận lại bằng văn bản riêng? | PO sàn (người thật) | 2026-09-12 | Tính hợp lệ của `CTX` khi trình AG1 | `CTX_e-commerce_v1.0.md` §0, §7 | +| OQ-005 | Ngân sách hạ tầng/tháng và chi phí một lần đã duyệt cho dự án là bao nhiêu? Nguồn tham khảo duy nhất hiện có là hồ sơ thầu (`e-commerce/bid/estimate.computed.json`, Draft, chưa hợp đồng): lao động ≈3,76 tỷ VND đã VAT/53,02 người-tháng; 8 khoản chi phí không lao động chưa có số. | PO / tài chính | 2026-09-12 | `CON-01`; `TCO` Bước 5; loại bớt phương án ở `OPT` Bước 4 | `CTX_e-commerce_v1.0.md (v1.1 trong header)` §3, §7 | +| OQ-006 | Deadline dự án chính thức là ngày nào (nếu có)? Brief giả định "~9-12 tháng"; hồ sơ thầu tính "7 tháng thực hiện" + 12 tháng bảo hành — hai số này KHÔNG khớp và đều chưa được PO xác nhận là mốc thật. | PO / PM | 2026-09-12 | `CON-02`; kịch bản thời gian ở `OPT` Bước 4 | `CTX_e-commerce_v1.0.md (v1.1 trong header)` §3, §7 | +| OQ-007 | Ai là đại diện Pháp chế/Bảo mật xác nhận yêu cầu residency (nơi lưu trữ dữ liệu) theo NĐ13/2023 cho mô hình marketplace hai loại chủ thể dữ liệu (khách hàng + seller, gồm KYC)? *(kế thừa `OQ-003` của BA — vẫn chưa có người)* **Bổ sung (2026-09-15, `DAT §5`):** SA đã phân loại PII/Payment/nghiệp vụ đầy đủ + đề xuất retention (30 ngày ẩn danh hoá PII khách hàng, 5 năm KYC, 10 năm tài chính — tham khảo `docs/05`, `ASM-37`) và whitelist chia sẻ seller (`recipient_name`/`phone`/`address_line`, hiện thực hoá `ADR-008` PA-2) — **vẫn chờ đại diện Pháp chế/Bảo mật phủ quyết**, giữ nguyên mở. **Bổ sung (2026-09-15, `SEC §5`/`§8.2`):** SEC ghi rõ toàn bộ phân loại dữ liệu, mã hoá, masking, và tuân thủ NĐ13/2023 trong `SEC` là **đề xuất chờ phủ quyết**, không phải quyết định cuối — SEC **chưa có hiệu lực phủ quyết AG2** cho tới khi có người này. Giữ nguyên mở. | PO sàn (chỉ định người) | 2026-09-12 | `CON-06`, `ASM-04`; ranh giới hạ tầng dữ liệu ở `DAT`/`INF` GĐ2; hiệu lực phủ quyết `SEC` | `CTX_e-commerce_v1.0.md (v1.1 trong header)` §3, §5, §7 · `DAT_e-commerce_v1.0.md` §5, §5.2 · `SEC_e-commerce_v1.0.md` §0.1, §5, §8.2 | +| OQ-008 | Đội vận hành (Ops/SRE) sau go-live là nội bộ PO hay thuê ngoài, quy mô bao nhiêu người, có sẵn sàng trực 24/7 cho sự cố nghiêm trọng (NFR-08) hay chưa? | PM / SRE | 2026-09-12 | `CON-05`, `CON-08`; thiết kế on-call/`INF` GĐ2; ranh giới service (Conway) | `CTX_e-commerce_v1.0.md (v1.1 trong header)` §3, §5, §7 | +| OQ-010 | Tech Lead xác nhận: đội thi công thật (không phải đề xuất hồ sơ thầu) có kinh nghiệm vận hành production nào với Kafka/MSK, OpenSearch cluster, EKS chưa? Input trực tiếp cho tiêu chí "Rủi ro kỹ thuật" đã chấm P1=2/P2=4 trong `OPT`. | Tech Lead | 2026-09-12 | Điểm "Rủi ro kỹ thuật" của P1 trong `OPT`; `ARISK` Bước 5 | `OPT_e-commerce_v1.0.md` §4, §9 | +| OQ-012 | Có cần chạy POC đo throughput SQS/EventBridge (`ASM-07`) trước khi chốt P2 làm phương án chính thức, hay chấp nhận rủi ro tạm thời và bổ sung `ARISK`/kế hoạch POC ở Bước 5? | Tech Lead | 2026-09-12 | `ADR` message backbone GĐ2; kế hoạch POC `ARISK` Bước 5 | `OPT_e-commerce_v1.0.md` §8, §9 | +| OQ-013 | Xác nhận đơn giá AWS `ap-southeast-1` ước tính ở `TCO §3.1` (`ASM-11`) bằng AWS Pricing Calculator thật hoặc báo giá đại lý AWS tại VN — chênh lệch bao nhiêu so với ước tính? | Tech Lead/DevOps + tài chính | 2026-09-12 | Độ tin cậy `TCO` toàn bộ; ngân sách hạ tầng `INF` GĐ2 phải khớp (`D9`) | `TCO_e-commerce_v1.0.md` §3, §8 | +| OQ-014 | Biểu phí giao dịch VNPay/Momo thật (theo % hay phí cố định) và GMV dự kiến năm 1 là bao nhiêu, để tính `NL-03` trong `TCO`? | PO/tài chính + đàm phán VNPay/Momo | 2026-09-12 | `TCO §4` (khoản chưa tính được) | `TCO_e-commerce_v1.0.md` §4 | +| OQ-015 | Biểu phí API GHN/GHTK theo hợp đồng thật là bao nhiêu (`NL-05`)? | PM (đàm phán hợp đồng vận chuyển) | 2026-09-12 | `TCO §4`; `ARISK-04` | `TCO_e-commerce_v1.0.md` §4; `ARISK_e-commerce_v1.0.md` §3 | +| OQ-016 | Nhà cung cấp Email/SMS cụ thể là gì, biểu phí bao nhiêu (`NL-04`)? | PM/Tech Lead | 2026-09-12 | `TCO §4`; `ARISK-10`; `ICD` GĐ2 | `TCO_e-commerce_v1.0.md` §4; `ARISK_e-commerce_v1.0.md` §3 | +| OQ-017 | Báo giá pentest ứng dụng hàng năm + ASV scan hàng quý (SAQ A) từ nhà cung cấp thật là bao nhiêu (`NL-07`)? | PO/Security (khi có người) | 2026-09-12 | `TCO §4` | `TCO_e-commerce_v1.0.md` §4 | +| OQ-018 | Ngưỡng p95 cho `GET /v1/cart` là bao nhiêu? SA đề xuất ≤500ms (nối `OQ-033` của BA). | PO + Tech Lead | 2026-09-14 | `QAS-003` baseline; bài đo `FIT` ở GĐ3 | `QAS_e-commerce_v1.0.md` §A3, §E | +| OQ-019 | Ngưỡng p95 cho `PATCH`/`DELETE /v1/cart/items` là bao nhiêu? SA đề xuất ≤300ms (nối `OQ-033` của BA). | PO + Tech Lead | 2026-09-14 | `QAS-004` baseline; bài đo `FIT` ở GĐ3 | `QAS_e-commerce_v1.0.md` §A3, §E | +| OQ-020 | Cửa sổ bảo trì có báo trước (nếu có) được loại trừ khỏi ngân sách lỗi 99.9%/tháng là bao nhiêu giờ? SA đề xuất ≤2 giờ/tháng. | PO | 2026-09-14 | `QAS-007` (ngân sách lỗi thật); chính sách release ở `INF` (chưa chạy) | `QAS_e-commerce_v1.0.md` §A3, §E | +| OQ-021 | Tần suất chạy job đối soát thanh toán (reconciliation) là bao nhiêu? SA đề xuất ≤15 phút/lần. | Tech Lead | 2026-09-14 | `QAS-014`; thiết kế job đối soát ở `DAT`/`INF` (chưa chạy) | `QAS_e-commerce_v1.0.md` §A3, §E | +| OQ-022 | Lịch diễn tập DR (failover drill) đầu tiên cho nhóm service giao dịch cốt lõi là khi nào? **Điều kiện đã chốt (sign 2026-09-14, `DEC-12`): phải diễn tập TRƯỚC khi ký AG2** — ngày cụ thể vẫn chờ Ops/SRE. | Ops/SRE | 2026-09-14 | `QAS-008` (nâng `Confidence`); điều kiện tiên quyết ký AG2 (bắt buộc, không còn tuỳ chọn) | `QAS_e-commerce_v1.0.md` §A3, §E, header | +| OQ-023 | Ngưỡng rate limit cụ thể (số request/phút theo IP) cho `PATCH`/`DELETE /v1/cart/items` của Guest là bao nhiêu? **Bổ sung (2026-09-15, `SEC §5.3`):** SA đề xuất **30 request/phút theo `session_id`** + 60 req/phút theo IP (phòng vệ phụ), kèm hệ quả cả hai chiều (chặt hơn/lỏng hơn) — **không tự quyết thay Security**, giữ nguyên mở. | Tech Lead + Security | 2026-09-14 | Hoạt động `sec`/`icd` kế tiếp; `NFR-SEC-03` của BA | `QAS_e-commerce_v1.0.md` §A3, §E · `SEC_e-commerce_v1.0.md` §5.3 | +| OQ-024 | Phương thức MFA cho Admin là gì — TOTP app, SMS OTP, hay khoá bảo mật cứng? **Chốt TẠM (sign 2026-09-15, `DEC-14`): TOTP app (`ASM-20`)** làm baseline cho `sad`/`sec` — chưa phải xác nhận thật của Security, **giữ mở**. | Tech Lead + Security | 2026-09-14 | `ASR-009`; thiết kế `SEC` (mô hình xác thực) | `ASR_e-commerce_v1.0.md` §B2 (ASR-009), §E | +| OQ-025 | Nội dung do seller tự nhập có cần dịch sang 5 ngôn ngữ ở MVP không? Nếu cần, ai cung cấp bản dịch? **Chốt TẠM (sign 2026-09-15, `DEC-14`): không dịch nội dung seller ở MVP, chỉ i18n UI hệ thống (`ASM-21`)** — chưa phải xác nhận thật của PO, **giữ mở**. | PO + Tech Lead | 2026-09-14 | `ASR-015`; `DAT` (mô hình lưu trữ đa ngôn ngữ) | `ASR_e-commerce_v1.0.md` §B2 (ASR-015), §E | +| OQ-026 | `TCO §3.2` tính compute ECS Fargate P2 là 1 dòng "monolith" gộp — có đúng là 2 ECS service riêng (Nhóm Giao dịch/Nhóm Hỗ trợ, như `ASR-001`/`ASR-014`/`OPT §3` mô tả) hay chỉ 1 ECS service duy nhất chưa tách nhóm? **Chốt TẠM (sign 2026-09-15, `DEC-16`): 2 ECS Fargate service riêng để scale độc lập (`ASM-23`)** làm baseline cho `icd`/`dat`/`sec`/`inf`/`fail` — chưa phải xác nhận thật của Tech Lead/Ops, **giữ mở**. | Tech Lead + Ops/SRE | 2026-09-15 | `SAD §7` deployment view; `ADR-012`; khả năng đáp ứng `DRV-04` | `SAD_e-commerce_v1.0.md` §7, §11 | +| OQ-027 | Identity & Access nên thuộc Nhóm Giao dịch (suy từ `ASM-22`, dựa trên `ASR-010`/`011`) hay là nhóm riêng/thuộc Nhóm Hỗ trợ? `OPT §3` không nói rõ vị trí của Identity. **Chốt TẠM (sign 2026-09-15, `DEC-16`): Identity & Access thuộc Nhóm Giao dịch (`ASM-22`)** làm baseline cho `sad`/`sec`/`inf` kế tiếp — chưa phải xác nhận thật của Tech Lead, **giữ mở**. | Tech Lead | 2026-09-15 | `CMP-02`; `SAD §4.1/§7`; `ADR-012` | `SAD_e-commerce_v1.0.md` §4.1, §10, §11 | +| 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. **Chốt TẠM (sign 2026-09-15, `DEC-19`):** cross-network REST (`ASM-24`) làm baseline cho thiết kế `FAIL`/ngân sách `QAS-002` — chưa phải xác nhận thật của Tech Lead, **giữ mở**. | Tech Lead | 2026-09-15 | `ICD §3.6`; thiết kế `FAIL` cho `IF-021`; ngân sách `QAS-002` | `ICD_e-commerce_v1.0.md` §2, §7, §8 | +| OQ-030 | Xác nhận thiết kế schema sự kiện `OrderPlaced`/`PaymentConfirmed` (`ICD §4`) và request `IF-006` (`ICD §3.3`, đặc biệt Payment Service nhận `sellerId` ngay lúc khởi tạo) — đề xuất mới của `ICD`, chưa có nguồn khác xác nhận. **Chốt TẠM (sign 2026-09-15, `DEC-19`):** chấp nhận thiết kế đề xuất — Payment Service nhận `sellerId` ngay tại `IF-006` (`ASM-26`) — làm baseline cho thi công; schema sự kiện giữ nguyên đề xuất — chưa phải xác nhận thật của Tech Lead, **giữ mở**. | Tech Lead | 2026-09-15 | Thi công Cart&Order/Payment/message backbone; `DAT` (hoạt động 5) | `ICD_e-commerce_v1.0.md` §3.3, §4, §8 | +| 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 (input `inf`) | `ICD_e-commerce_v1.0.md` §1, §8 | +| OQ-032 (SA) | `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ì? *(khác `OQ-032` của sổ BA — xem `ba-output/.../00-index/OQ_e-commerce.md`)* **Chốt TẠM (sign 2026-09-15, `DEC-19`):** chiều gọi Cart&Order → Seller Management (`ASM-25`) làm baseline cho §3.7/denormalize `sellerName` — chưa phải xác nhận thật của Tech Lead, **giữ mở**. | Tech Lead | 2026-09-15 | `ICD §3.7`; denormalize `sellerName`; rà lại `SAD §4.1` | `ICD_e-commerce_v1.0.md` §2, §3.7, §7, §8 | +| OQ-033 (SA) | 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? *(khác `OQ-033` của sổ BA)* **Chốt TẠM (sign 2026-09-15, `DEC-19`):** chấp nhận denormalize `sellerName` snapshot vào `CartItem` làm baseline cho `DAT` kế tiếp — chưa phải xác nhận thật của Tech Lead + DBA, **giữ mở**. | Tech Lead + DBA | 2026-09-15 | `DAT` (hoạt động 5); `QAS-003` (ngân sách latency) | `ICD_e-commerce_v1.0.md` §3.1.1, §3.7, §5, §8 | +| OQ-034 | Ngân sách timeout cộng dồn đường găng checkout vượt `QAS-002` (~3.220ms > 3.000ms, xem `FAIL v1.0 §1.2`) ngay cả sau khi siết timeout VNPay/Momo xuống 1.500ms (thay 10s kế thừa). Chọn Lựa chọn A (siết timeout hơn nữa) 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`)? **Chốt (sign 2026-09-15, `DEC-22`): chọn Lựa chọn B.** **Cập nhật (2026-09-15, `DEC-23`): đã viết `ADR-013` (`Proposed`) và sửa nhất quán `SAD §6.1`/`§8` (lên v1.3) + `FAIL §1.2` (lên v1.1)** — tổng ngân sách đồng bộ nay ≤3.000ms cho cả nhánh COD (1.720ms) và VNPay/Momo (1.120ms). Trạng thái: "đã chọn hướng B, đã có `ADR-013`, chờ Tech Lead + PO **thật** xác nhận trước khi `Accepted`" — chưa phải xác nhận thật, **giữ mở**. | Tech Lead + PO | 2026-09-15 | `ADR-013` chuyển `Accepted`; BA viết `SRS`/`AC` cho US-004 Checkout theo trạng thái mới; `ICD` lượt sau chốt endpoint polling/retry/chuyển COD | `FAIL_e-commerce_v1.0.md` §1.2, §10 · `SAD_e-commerce_v1.0.md` §6.1, §8 · `adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md` | +| OQ-041 | Cơ chế FE lấy `redirectUrl` sau khi khởi tạo thanh toán online bất đồng bộ hoàn tất (`ADR-013 §3.2`) — polling (đề xuất mặc định) hay kênh đẩy (SSE/WebSocket)? **Chốt TẠM (sign 2026-09-15, `DEC-25`): polling** làm baseline cho `ICD` lượt sau — chưa phải xác nhận thật của Tech Lead/FE, **giữ mở**. | Tech Lead (kèm ý kiến FE) | 2026-09-15 | Contract endpoint mới ở `ICD` lượt sau; thiết kế FE cho US-004 | Chọn polling mà tải cao bất thường: tăng số request nhỏ không cần thiết (giảm thiểu bằng interval + dừng sau 15s). Chọn SSE/WebSocket mà đội chưa có kinh nghiệm vận hành kênh kết nối lâu dài (`OQ-010` mở): rủi ro sự cố khó chẩn đoán đúng lúc ra mắt | `adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md` §3.2 | +| OQ-042 | `Order` giữ trạng thái `PENDING_PAYMENT_INIT` bao lâu trước khi coi là "kẹt" (async init không bao giờ hoàn tất) và cần job dọn dẹp/hủy tự động? SA đề xuất ngưỡng UX 15 giây (10s timeout đối tác + margin), nhưng thời gian giữ trước khi job dọn dẹp chạy (khác ngưỡng UX) chưa chốt. **Bổ sung (2026-09-15, `DAT §4.3`):** SA đề xuất ngưỡng quét **5 phút** (kể từ `order.placed_at`) + job chạy mỗi 5 phút, hành động: cập nhật `payment_init_status = payment_init_failed`, giải phóng `inventory_stock.quantity_reserved`, ghi `order_status_history`, cảnh báo Ops nếu số lượng phát hiện bất thường (>5 đơn/lần quét) — **chưa tự quyết**, giữ nguyên mở, chờ Tech Lead xác nhận. **Chốt TẠM (sign 2026-09-15, `DEC-25`): ngưỡng quét 5 phút** làm baseline — chưa phải xác nhận thật của Tech Lead, **giữ mở**. | Tech Lead | 2026-09-15 | Thiết kế job quét dọn ở hoạt động `dat`/`inf` lượt sau; cùng bản chất khoảng trống outbox đã ghi ở `FAIL §7` | Ngưỡng quá ngắn: huỷ nhầm `Order` đang xử lý bình thường (VNPay/Momo chỉ chậm, chưa timeout thật). Ngưỡng quá dài: `Order` "ma" tồn đọng lâu, gây nhiễu báo cáo/tồn kho reserve không giải phóng đúng lúc | `adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md` §3.1, §5 · `DAT_e-commerce_v1.0.md` §4.3 | +| OQ-035 | Xác nhận ngưỡng circuit breaker (mở/nửa mở/đóng) đề xuất cho `FM-01/02/03/04/12/13` — số cụ thể là đề xuất SA, chưa đo thật. **Chốt TẠM (sign 2026-09-15, `DEC-22`):** chấp nhận ngưỡng đề xuất §3.1 làm baseline cấu hình — chưa phải xác nhận thật của Tech Lead/SRE, **giữ mở**. | Tech Lead + SRE | 2026-09-15 | Cấu hình circuit breaker thi công; `FIT-19/20/21` (GĐ3) | `FAIL_e-commerce_v1.0.md` §3.1, §10 | +| OQ-036 | Thời gian giữ DLQ (đề xuất 14 ngày) cho SQS FIFO/EventBridge và ngưỡng cảnh báo lag hàng đợi (đề xuất >5 phút) là bao nhiêu? Ai xử lý message DLQ theo domain? **Chốt TẠM (sign 2026-09-15, `DEC-22`):** chấp nhận 14 ngày + ngưỡng cảnh báo >5 phút làm baseline — phân công xử lý theo domain vẫn chưa chốt, chưa phải xác nhận thật của Tech Lead/SRE, **giữ mở**. | Tech Lead + SRE | 2026-09-15 | Thiết kế `inf` (retention, alerting) | `FAIL_e-commerce_v1.0.md` §1.1 (`FM-09/10`), §7, §10 | +| 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 — phụ thuộc kết quả `POC-02` chưa chạy. **Chốt TẠM (sign 2026-09-15, `DEC-22`):** giữ nguyên chờ `POC-02` (chưa chạy) trước khi chốt số — DBA/Tech Lead thật xác nhận sau, **giữ mở**. | DBA + Tech Lead | 2026-09-15 | Cấu hình pool thi công; chống nghẽn chéo module | `FAIL_e-commerce_v1.0.md` §3.3, §10 | +| OQ-038 | Giữ transaction DB mở xuyên suốt lời gọi đồng bộ `IF-006`/`IF-007/008` có chấp nhận được không, hay cần tách 2 bước? Đồ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 | Transaction boundary `SAD §6.1`; `SRS`/`AC` US-004 (BA) | `FAIL_e-commerce_v1.0.md` §1.2, §5, §10 | +| OQ-039 | SLA xử lý thủ công khi cả GHN và GHTK đều lỗi (`AWAITING_MANUAL_FULFILLMENT`) là bao lâu? Ai (CSKH/Ops) chịu trách nhiệm? | PO + Ops | 2026-09-15 | Runbook vận hành (`inf`, GĐ3) | `FAIL_e-commerce_v1.0.md` §1.1 (`FM-03/04`), §10 | +| OQ-040 | Có cần thêm cache nội dung `Cart`/`CartItem` vào Redis để `GET /v1/cart` có fallback thật khi RDS chậm không (hiện chỉ cache session/ownership, không cache nội dung giỏ)? Đồng thời xác nhận mã lỗi `E-CART-0007` cho ownership check lỗi kỹ thuật (fail-closed, khác 403 thật). **Bổ sung (2026-09-15, `DAT §7.3`):** SA đã đánh giá 2 phương án (A — không cache, B — cache-aside có write-through invalidation) kèm hệ quả bằng bảng so sánh; **nghiêng về Phương án B** nếu Tech Lead chấp nhận độ phức tạp invalidation (chi phí hạ tầng thấp, cải thiện khả dụng đúng lúc flash sale) — **chưa tự quyết**, giữ nguyên mở. | Tech Lead | 2026-09-15 | Thiết kế `DAT`/`inf` (cache strategy); mã lỗi mới cho `SRS` (BA) | `FAIL_e-commerce_v1.0.md` §4, §5, §10 · `DAT_e-commerce_v1.0.md` §7.3 | +| OQ-043 | 1 `Order` (cha) có đúng 1 `Payment` (đa seller, 1 phương thức chung, theo `BR_CartCheckout §4` ERD) hay có ngoại lệ tách `Payment` theo `OrderSeller`/phương thức? (nối `OQ-030` của `ICD`) | Tech Lead + PO | 2026-09-15 | Mô hình `payment.order_id`; `IF-006` request/response (`ICD §3.3`); `order.payment_init_status` | `DAT_e-commerce_v1.0.md` §1.4.1, §2.1, §11 (`ASM-35`) | +| OQ-044 | Chấp nhận **Transactional Outbox pattern** (`outbox_event` + relay poller) làm cơ chế chính thức xử lý khoảng trống "commit `Order` nhưng publish event thất bại" (`FAIL §7`) không, hay dùng job quét đối chiếu đơn giản hơn (PA-1)? Radar ước lượng ~6/10 — `ADR` bắt buộc, chưa viết. **Chốt TẠM (sign 2026-09-15, `DEC-25`): chọn Transactional Outbox** — yêu cầu SA viết `ADR-014` (`Proposed`) ở lượt hoạt động `adr` kế tiếp trước khi coi là chốt kiến trúc chính thức; chưa phải xác nhận thật của Tech Lead, **giữ mở**. | Tech Lead | 2026-09-15 | `ADR` mới (`ADR-014`) ở hoạt động `adr` kế tiếp; thiết kế relay ở `inf` | `DAT_e-commerce_v1.0.md` §4.1 | +| OQ-045 | Công cụ quản lý migration schema — Flyway hay Liquibase (hoặc khác)? | Tech Lead | 2026-09-15 | Quy trình CI/CD; khả năng rollback schema | `DAT_e-commerce_v1.0.md` §8.2 | +| OQ-046 | Đọc `Cart`/`Order` có nên route sang RDS read replica (chỉ có ở kịch bản B) hay luôn đọc primary? SA đề xuất: chỉ Catalog dùng replica, Cart&Order luôn đọc primary. | Tech Lead | 2026-09-15 | Cấu hình routing đọc ở `inf`; độ tươi dữ liệu `GET /v1/cart` (`ASM-36`) | `DAT_e-commerce_v1.0.md` §7.2 | +| OQ-047 | P2 (`SAD` 15 `CMP`) không có `CMP` Audit & Compliance riêng như P1 (`docs/05` v3) — audit trail xuyên module (`RBAC_CartCheckout §5`, `ADR-008 §6`) nên kiến trúc theo cách nào: (a) mỗi module tự ghi `audit_log` trong schema riêng, hay (b) thêm 1 `CMP` Audit tập trung? **Chốt TẠM (sign 2026-09-15, `DEC-25`): phương án (a)** — mỗi module tự ghi `audit_log` riêng, **không thêm `CMP-16`** — làm baseline; chưa phải xác nhận thật của Tech Lead + Security, **giữ mở**. **Bổ sung (2026-09-15, `SEC §7`):** SEC chốt trường bắt buộc (actor/action/resource/correlation_id/timestamp/result), retention (10 năm cho hành động tài chính, 5 năm còn lại — đề xuất) và cơ chế append-only theo schema — vẫn theo phương án (a), giữ nguyên mở. | Tech Lead + Security | 2026-09-15 | Danh sách `CMP` (không thêm `CMP-16` theo hướng TẠM); `ADR-001` nếu sau này đổi hướng ảnh hưởng cấu trúc tổng thể | `DAT_e-commerce_v1.0.md` §10, §11 · `SEC_e-commerce_v1.0.md` §7 | +| OQ-048 | VNPay/Momo có hỗ trợ tích hợp dạng redirect thuần (không iframe/SDK nhập thẻ trên domain sàn) không — điều kiện để giữ phạm vi PCI-DSS SAQ A (`ASM-39`)? | Tech Lead + Security (khi có người) | 2026-09-15 | `SEC §8.1`; giả định nền của `ASR-002`/`ADR-002` | `SEC_e-commerce_v1.0.md` §8.1, §10, §11 | +| OQ-049 | Cơ chế xác thực chữ ký/HMAC webhook cụ thể của VNPay, Momo, GHN, GHTK là gì (thuật toán, header, cách tính chữ ký)? | Tech Lead (khi có tài liệu đối tác) | 2026-09-15 | `THR-17`/`THR-22` (`SEC`); kiểm chứng `ADR-004` thật | `SEC_e-commerce_v1.0.md` §4.5, §4.6, §8.1, §11 | +| OQ-050 | Chấp nhận đề xuất PA-3 (service JWT ngắn hạn ký bởi Identity & Access) cho service-to-service authn giữa Nhóm Giao dịch ↔ Nhóm Hỗ trợ ↔ Payment (`IF-006`/`IF-021`/`IF-022`) không, hay chọn PA-2 (mTLS/App Mesh, cần thêm hạ tầng)? Radar ước lượng ~5 — `ADR` bắt buộc. **Cập nhật (2026-09-15, `DEC-28`):** Tech Lead (ký thay, ngoại lệ `DEC-01`) chốt TẠM hướng **PA-3** làm baseline — yêu cầu SA viết `ADR-015` (`Proposed`) ở lượt hoạt động `adr` kế tiếp cùng `ADR-014`. **Giữ nguyên mở** — chưa `Accepted`, chờ Security + Ops/SRE thật xác nhận. | Tech Lead + Security + Ops/SRE | 2026-09-15 | `ADR-015` (chưa viết) ở hoạt động `adr` kế tiếp; thiết kế `inf` cho TB3/TB4; `THR-09`/`THR-13` | `SEC_e-commerce_v1.0.md` §2.4, §11 · `DEC_e-commerce.md` `DEC-28` | +| OQ-051 | Xác nhận số cụ thể cho Customer JWT: TTL access (đề xuất 15 phút), TTL refresh (đề xuất 14 ngày), cơ chế thu hồi tức thời (đề xuất denylist Redis theo `jti`), tần suất xoay khoá ký (đề xuất 90 ngày), rotation Guest session lúc chuyển đổi thành Customer | Tech Lead | 2026-09-15 | Thiết kế `CMP-02` (Identity & Access) khi tới lượt module đó | `SEC_e-commerce_v1.0.md` §2, §2.1, §2.2, §11 | +| OQ-052 | Xác nhận ngưỡng account lockout theo vai trò (đề xuất: customer/seller 5 lần sai/15 phút; admin 3 lần sai/30 phút) và rate-limit login theo IP (đề xuất 10 request/phút) | Tech Lead + Security | 2026-09-15 | `THR-28`/`THR-31` (`SEC`); thiết kế `CMP-02` | `SEC_e-commerce_v1.0.md` §2.3, §5.3, §11 | +| OQ-053 | Ba trường whitelist chia sẻ cho seller (`recipient_name`/`phone`/`address_line`, `ADR-008` PA-2) hiển thị đầy đủ hay che một phần (VD số điện thoại che 3-4 số giữa)? | Security/Legal (khi có người) + PO | 2026-09-15 | `DAT §5.2`; UI hiển thị đơn hàng cho Seller (ngoài phạm vi US-002/003) | `SEC_e-commerce_v1.0.md` §5.2, §11 | +| OQ-054 | `TCO §3.2` tính "cross-region snapshot (Payment)" (~$30/A, ~$60/B) trong dòng Backup & DR — có mâu thuẫn với `ADR-009` (chọn PA-1, không multi-region) không, hay đây chỉ là snapshot phụ không nằm trong cam kết RTO≤1h? | Tech Lead + Ops/SRE + PO | 2026-09-15 | `INF §5.2`/§10 đối chiếu `TCO`; nội dung `ADR-009` | `INF_e-commerce_v1.0.md` §5.2, §10, §15 | +| OQ-055 | Xác nhận split ECS task đề xuất giữa Nhóm Giao dịch/Nhóm Hỗ trợ (A: 2/2, B: 6/4) và ngưỡng auto-scaling (CPU 60%/70%, request count) — nối `OQ-026` | Tech Lead + Ops/SRE | 2026-09-15 | `INF §4.2`, §10; cấu hình Terraform thật ở GĐ3 | `INF_e-commerce_v1.0.md` §4.2, §10, §15 | +| OQ-056 | Lịch diễn tập DR thật (3 kịch bản DR-1/2/3 ở `INF §5.4`) là ngày nào? SA đề xuất trong vòng 2 tuần kể từ khi xác định Ops/SRE, trước khi trình AG2 — nối `OQ-022` | Ops/SRE | 2026-09-15 | Điều kiện tiên quyết ký AG2 (`DEC-12`) | `INF_e-commerce_v1.0.md` §5.4, §15 | +| OQ-057 | VNPay/Momo/GHN/GHTK/Email-SMS có yêu cầu IP allowlist cho traffic outbound từ sàn không? Nếu có, cần đăng ký 2 Elastic IP NAT với từng đối tác | Tech Lead (khi có tài liệu đối tác thật) | 2026-09-15 | `INF §8.3`; phối hợp hành chính với đối tác trước go-live | `INF_e-commerce_v1.0.md` §8.3, §15 | +| OQ-058 | Chấp nhận ElastiCache kịch bản A không có replica (SPOF) hay muốn thêm 1 replica ngay (chi phí ước tính +~$92/tháng, chưa xác nhận)? **Cập nhật (2026-09-15, `DEC-30`):** Tech Lead (ký thay, ngoại lệ `DEC-01`) chốt TẠM hướng **giữ nguyên `TCO`** — không thêm replica ở kịch bản A, chấp nhận SPOF với hành vi fail-closed theo `FAIL` (không mất dữ liệu nghiệp vụ, chỉ gián đoạn dịch vụ tạm thời). **Giữ nguyên mở** — đây là đánh đổi chi phí/rủi ro của PO, chưa phải quyết định cuối, chờ PO xác nhận. | PO + Ops/SRE | 2026-09-15 | `INF §4.3`; cấu hình ElastiCache thật ở GĐ3 | `INF_e-commerce_v1.0.md` §4.1, §4.3, §15 · `DEC_e-commerce.md` `DEC-30` | +| OQ-059 | Xác nhận (a) retention log CloudWatch/S3 archive, (b) tỉ lệ lấy mẫu X-Ray trace, (c) retention backup RDS (đề xuất 7 ngày, khác 35 ngày ở tài liệu P1 gốc) | Tech Lead + Ops/SRE | 2026-09-15 | `INF §6.1`, §5.2; chi phí lưu trữ thực tế | `INF_e-commerce_v1.0.md` §5.2, §6.1, §15 | +| OQ-060 | Xác nhận công cụ IaC (Terraform, đề xuất — `ADR-017` ứng viên) và ngưỡng coverage unit test cho P2 (đề xuất kế thừa 70%/50% từ tài liệu P1, cần xác nhận lại) | Tech Lead | 2026-09-15 | `INF §11` (`ADR-017`); §7.1 pipeline | `INF_e-commerce_v1.0.md` §7.1, §11, §15 | +| OQ-061 | Kích thước connection pool RDS theo module (ghi checkout vs đọc catalog) và pool HTTP theo từng adapter đối tác ngoài — phụ thuộc `POC-02` chưa chạy — nối `OQ-037` | DBA + Tech Lead | 2026-09-15 | Cấu hình RDS parameter group thật ở GĐ3 | `INF_e-commerce_v1.0.md` §14, §15 | +| OQ-062 | Non-prod (dev/stg) nên tách VPC riêng trong cùng account hay tách hẳn AWS account riêng (đề xuất SA: account riêng theo AWS Organizations)? | Tech Lead + Ops/SRE | 2026-09-15 | `INF §2`, §3 (bảng "Non-prod") | `INF_e-commerce_v1.0.md` §2, §3, §15 | +| OQ-063 | *(nối `OQ-008`, không lặp lại)* Đội Ops/SRE thật (nội bộ/thuê ngoài, quy mô) — chặn trực tiếp khả năng đáp ứng on-call và tần suất diễn tập DR | PM/SRE | 2026-09-12 *(đã mở từ `CTX`)* | `INF §5.4`, §6.5 | `CTX_e-commerce_v1.0.md` §7 · `INF_e-commerce_v1.0.md` §6.5, §15 | + +**Câu trả lời tạm (bổ sung 2026-09-12, hoạt động `as-is`):** `OQ-005` và `OQ-008` ở trên chưa có +xác nhận thật từ PO/PM/tài chính trong vòng chạy này. Riêng `OQ-005`/`OQ-006` (deadline, xem +dòng phía trên các mục pháp lý/vận hành) có ghi "câu trả lời tạm" tại +`CTX_e-commerce_v1.0.md (v1.2 trong header)` §4.3, §7: tạm dùng số hồ sơ thầu (`e-commerce/bid/`) +làm mốc tham khảo duy nhất, `Confidence` 🔴, cả hai **giữ mở** cho tới khi có số PO xác nhận thật. ## Open Question đã đóng | ID | Nội dung | Trả lời | Ngày đóng | Người trả lời | |---|---|---|---|---| +| OQ-029 | `SAD §4` 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 — 5 `IF` bị bỏ sót khi viết `SAD`, hay con số "22" đếm nhầm? | **Đếm nhầm** — rà toàn bộ sơ đồ Context/Container/Component (`SAD §3/§4/§5`) đối chiếu bảng `CMP-nn` (§4.1) và bảng phụ thuộc (§6.3): chỉ 17 ID thực sự xuất hiện (`IF-001…009, 015…022`), không có `IF-010…014` ở bất kỳ đâu, không có mũi tên nào thiếu ID. **Không có interface nào bị bỏ sót** — không bổ sung `IF` mới. `SAD_e-commerce_v1.0.md` đã sửa "22"→"17" ở header/Change Log/Tự chấm tại v1.2 (2026-09-15). | 2026-09-15 | SA (qua skill sa-2-architecture, hoạt động `sad`, sửa lỗi theo yêu cầu người duyệt) | +| OQ-002 | Ràng buộc "Con người" (số đội, số người, kỹ năng, ai vận hành sau go-live) chưa có thông tin — cần để biến định hướng "kiến trúc module hoá độc lập" (NFR-07) thành `DRV`/`CON` có số liệu. | Dùng giả định tạm "team MVP chuẩn" ở `Confidence` 🔴 cho Bước 2 (`CON` nhóm Con người), xem `DEC-02` (SA). **Không phải số thật** — số đội/số người/kỹ năng thật vẫn cần PM/Tech Lead xác nhận trước khi ranh giới service GĐ2 được coi là vững; nếu team thực tế khác biệt đáng kể (VD rất nhỏ so với giả định "chuẩn"), phải rà lại `CON` và ranh giới domain đã chia. | 2026-09-12 | Điều phối dự án (đại diện PO, dự án chạy thử) — ký thay, không phải PM/Tech Lead thật | +| OQ-009 | Có chấp nhận dùng kiến trúc/stack đã đề xuất sẵn trong `SAD.md`/hồ sơ thầu (modular microservices ~10 service, Kafka/MSK, RDS Multi-AZ, OpenSearch, Redis) làm điểm khởi đầu cho Bước 4 (`OPT`) của GĐ1 SA, hay yêu cầu SA dựng phương án độc lập? | **Chấp nhận** dùng làm điểm khởi đầu tham khảo cho một phương án ở Bước 4 — điều kiện bắt buộc: vẫn phải dựng và chấm điểm ≥1 phương án độc lập khác (không mặc định `SAD.md` thắng sẵn). Xem `CTX_e-commerce_v1.0.md` §4.3, §7.1, `DEC-04` (SA). | 2026-09-12 | Ghi chú người duyệt (đại diện PO/điều phối dự án, dự án chạy thử) — không phải PO/Tech Lead ký trực tiếp qua tác vụ `sign` | +| OQ-011 | PO + Tech Lead chọn phương án nào giữa P1 (theo `SAD.md`/hồ sơ thầu) và P2 (khuyến nghị SA), hay yêu cầu SA dựng thêm phương án lai? Đây là nội dung cần ký AG1 cho `OPT`. | **Chọn P2** (modular monolith + managed AWS, tách riêng Payment Service) làm nền cho Bước 5 (`TCO`/`ARISK`) và GĐ2 — **có điều kiện**: (1) `OQ-010` — Tech Lead xác nhận đội thi công thật; (2) POC đo throughput SQS/EventBridge (`ASM-07`) ghi vào `ARISK` ở Bước 5, trước khi chốt `ADR` message backbone GĐ2 (`OQ-012`, vẫn mở). Đây **không phải** chữ ký AG1 toàn phần của PO + Tech Lead thật — chỉ là hướng đi tạm dưới ngoại lệ ký thay (`DEC-01`); `OPT` giữ Status Draft, Tech Lead chưa ký (`OQ-004` giữ mở). Xem `DEC-06` (SA). | 2026-09-12 | Điều phối dự án (đại diện PO, dự án chạy thử) — ký thay theo ngoại lệ `DEC-01`, không phải chữ ký PO/Tech Lead thật | ## Ghi chú diff --git a/sa-output/e-commerce/01-context/ARISK_e-commerce_v1.0.md b/sa-output/e-commerce/01-context/ARISK_e-commerce_v1.0.md new file mode 100644 index 0000000..2f02e26 --- /dev/null +++ b/sa-output/e-commerce/01-context/ARISK_e-commerce_v1.0.md @@ -0,0 +1,234 @@ +# ARISK — Architecture Risk Register & POC Plan — e-commerce + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-12 | +| **Author** | SA (skill sa-1-context, chế độ `go`, hoạt động `cost-risk`) | +| **Status** | 🟡 Draft *(duyệt từng phần — xem `Approved by`; chấp nhận 10 rủi ro `ARISK-01…10` (mức, chủ, biện pháp) và 2 kế hoạch `POC-01`/`POC-02` với tiêu chí PASS/FAIL viết trước ở §6; POC **chưa chạy** — phải xong trước `ADR` message backbone GĐ2; đây **chưa phải** AG1 toàn phần, Tech Lead/PM chưa ký thật, `OQ-004` còn mở; xem "Tự chấm" §①)* | +| **Approved by** | PO (uỷ quyền, chế độ chạy thử): **Điều phối dự án** — duyệt **từng phần** bản v1.0 · 2026-09-12: chấp nhận 10 rủi ro `ARISK-01…10`, chủ sở hữu và biện pháp hạ rủi ro tương ứng (§3), và kế hoạch `POC-01` (throughput SQS/EventBridge) + `POC-02` (RDS gộp tải) với tiêu chí PASS/FAIL viết trước (§6). **POC chưa chạy** — bắt buộc chạy xong trước khi chốt `ADR` message backbone GĐ2. Ký thay PO theo ngoại lệ `DEC-01` (SA), ghi thêm `DEC-10`; **không phải chữ ký PO/Tech Lead thật** — `OQ-004` giữ mở. `Confidence` giữ 🔴; Status **giữ** 🟡 Draft — AG1 toàn phần vẫn chưa đủ điều kiện. · Tech Lead: — *(chưa ký)* · PM: — *(chưa ký)* | +| **Source** | `01-context/CTX_e-commerce_v1.0.md` (v1.2 trong header) §3, §4.2, §4.4, §5 `ASM-01…06` · `01-context/OPT_e-commerce_v1.0.md` §1, §4, §5, §8 `ASM-07…09` · `01-context/TCO_e-commerce_v1.0.md` §2, §8 `ASM-10…15` · `ba-output/e-commerce/01-discovery/RISK_CartCheckout_v1.0.md` `RISK-01…04`, `ASM-01…06` (BA — tham chiếu ID, không copy) | +| **Scope** | Toàn sàn e-commerce (marketplace đa seller), trọng tâm rủi ro kiến trúc gắn với phương án đã chọn tạm thời **P2** (`DEC-06`) và các rủi ro độc lập với lựa chọn kiến trúc nội bộ (đối tác bên ngoài, pháp lý, ngân sách, năng lực team) | +| **Confidence** | 🔴 Giả định chưa xác minh — kế thừa nguyên nhân của `CTX`/`OPT`/`TCO` (BA chưa ký G1, AG1 GĐ1 SA chưa từng chạy, ngoại lệ gate `DEC-01/03/04/05/07` tiếp tục ở `DEC-08`). Riêng mức độ (XS/TĐ) của từng `ARISK` là đánh giá kỹ thuật của SA dựa trên nguồn hiện có — sẽ điều chỉnh khi có xác nhận thật từ Tech Lead/PM/Security | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | ADR/DEC | +|---|---|---|---|---| +| 1.0 | 2026-09-12 | SA (qua skill sa-1-context, chế độ `go`, hoạt động `cost-risk`) | Bản đầu — Bước 5 (phần `ARISK`) của `sa-1-context`. Lập sổ 10 rủi ro kiến trúc (`ARISK-01…10`), kế thừa ứng viên từ `CTX §4.2/§4.4`, `OPT ASM-07/08/09`, `TCO ASM-14`, và tham chiếu `RISK-01…04`/`ASM-01…06` của BA bằng ID (không copy nội dung). Lập 2 kế hoạch POC bắt buộc (`POC-01` SQS/EventBridge throughput, `POC-02` RDS gộp tải) có tiêu chí pass/fail suy từ `DRV-04`, phải chạy xong **trước khi** chốt `ADR` message backbone ở GĐ2 (theo cam kết `OQ-012`/`DEC-06`). Tiếp tục ngoại lệ gate `DEC-01/03/04/05/07`, ghi thêm `DEC-08`. `Confidence` 🔴 toàn tài liệu. | `DEC-08` | +| 1.0 | 2026-09-12 | PO (uỷ quyền, Điều phối dự án) — tác vụ **sign/approve** | Duyệt **từng phần** bản v1.0: chấp nhận 10 rủi ro `ARISK-01…10`, chủ và biện pháp (§3), và kế hoạch `POC-01`/`POC-02` với tiêu chí PASS/FAIL viết trước (§6). Không đổi nội dung chuyên môn. **POC chưa chạy** — phải chạy xong trước `ADR` message backbone GĐ2. Ký thay PO theo ngoại lệ `DEC-01` (SA), ghi thêm `DEC-10`; **không phải chữ ký PO/Tech Lead thật** — `OQ-004` giữ mở, Tech Lead/PM **chưa ký**. `Confidence` giữ 🔴. Status **giữ** 🟡 Draft — AG1 toàn phần chưa đủ điều kiện (xem "Tự chấm" §①). | `DEC-10` | + +> Sổ này **sống suốt dự án**, không đóng ở AG1. Mỗi rủi ro chỉ đóng khi có bằng chứng (kết quả +> POC, xác nhận hợp đồng, xác nhận bằng văn bản), không đóng vì hết hạn. + +--- + +## 0. Ghi chú Preflight & ngoại lệ gate — tiếp nối `CTX`/`OPT`/`TCO` + +> **DEC-08 (SA)** — Tiếp tục chạy `sa-1-context` Bước 5 (phần `ARISK`) cho e-commerce trong khi +> BA vẫn chưa qua G1 và AG1 vẫn chưa từng chạy — tiếp nối `DEC-01/03/04/05/07`. Người dùng tái +> khẳng định muốn tiếp tục. +> **Quyết định:** Tiếp tục, lập sổ `ARISK` và kế hoạch POC với `Confidence 🔴` cho mức độ đánh giá +> (xác suất/tác động), cho tới khi Tech Lead/PM xác nhận lại từng dòng. +> **Người quyết:** Điều phối dự án (đại diện PO, dự án chạy thử). +> **Radar (ước lượng):** ~3–4 — cùng lý lẽ như `DEC-07`. +> **Hệ quả nếu không chấp nhận ngoại lệ:** GĐ1 SA không đủ 4 artifact (`CTX`/`OPT`/`TCO`/`ARISK`) +> để audit AG1 theo đúng yêu cầu "sau lượt này GĐ1 đủ 4 artifact" của ghi chú người duyệt. + +--- + +## 1. Tóm tắt + +| Mức | Số lượng | Đã có biện pháp cụ thể | Quá hạn | +|---|---|---|---| +| 🔴 Cao | 6 (`ARISK-01,02,03,05,06,07`) | 5/6 (trừ `ARISK-07` — chờ `OQ-005`) | 0 (sổ mới lập) | +| 🟠 Trung bình | 3 (`ARISK-04,08,09`) | 3/3 | 0 | +| 🟡 Thấp | 1 (`ARISK-10`) | 1/1 | 0 | + +**Ba rủi ro cần chú ý nhất tuần này:** `ARISK-01` (throughput SQS/EventBridge — chặn `ADR` message +backbone GĐ2 theo `OQ-012`), `ARISK-02` (RDS gộp tải — chặn `DAT` GĐ2), `ARISK-06` (residency +NĐ13/2023 — chặn `DAT`/`INF` GĐ2, người phủ quyết muộn nhất theo `GUIDE.md`). + +## 2. Cách chấm mức + +| | Tác động thấp | Tác động vừa | Tác động lớn *(lệch tiến độ >4 tuần, vượt ngân sách, không đáp ứng `DRV` Must)* | +|---|---|---|---| +| **Xác suất cao** | 🟠 | 🔴 | 🔴 | +| **Xác suất vừa** | 🟡 | 🟠 | 🔴 | +| **Xác suất thấp** | 🟡 | 🟡 | 🟠 | + +## 3. Sổ rủi ro + +| ID | Rủi ro | Nguồn | XS | TĐ | Mức | Biện pháp hạ rủi ro | Chủ | Hạn | Trạng thái | +|---|---|---|---|---|---|---|---|---|---| +| `ARISK-01` | SQS/EventBridge (P2, thay Kafka/MSK) chưa được đo throughput thật cho luồng `OrderPlaced`/`PaymentConfirmed` ở tải đỉnh flash sale — nếu không đủ, luồng đặt hàng nghẽn đúng lúc doanh thu cao nhất | Hiệu năng — kế thừa `ASM-07` (`OPT §8`) | Vừa | Lớn | 🔴 | `POC-01` (§6) — đo throughput thật trước khi chốt `ADR` message backbone GĐ2 | Tech Lead | Trước `ADR` message backbone GĐ2 (`OQ-012`) | Mở | +| `ARISK-02` | 1 cụm RDS PostgreSQL chính (schema-per-module, P2) chưa đo tải ghi/đọc gộp cho toàn bộ module ngoại trừ Payment — nếu quá tải, mọi module (Catalog/Cart/Seller/Commission…) cùng bị ảnh hưởng vì chung 1 instance | Hiệu năng — kế thừa `ASM-08` (`OPT §8`) | Vừa | Lớn | 🔴 | `POC-02` (§6) — load test trước khi chốt `DAT` GĐ2 | Tech Lead/DBA | Trước `DAT` GĐ2 | Mở | +| `ARISK-03` | VNPay/Momo chưa có sandbox/hợp đồng thật; xác nhận thanh toán qua webhook chưa xác minh khả thi gần thời gian thực — đơn hàng có thể kẹt "chờ thanh toán" dù tiền đã thu | Phụ thuộc ngoài — kế thừa `CTX §4.2`, `RISK-02` (BA), `ASM-01` (BA) | Vừa | Lớn | 🔴 | Đàm phán sandbox VNPay/Momo sớm (trước GĐ2 `ICD`); thiết kế job đối soát bù (reconciliation) — đã có trong `SAD.md §3.4`, kế thừa nguyên trạng, xác minh lại khi có sandbox thật | Tech Lead (đàm phán) + PO (ưu tiên lịch) | Trước GĐ2 kết thúc (`ICD`) | Mở | +| `ARISK-04` | GHN/GHTK chưa có sandbox/hợp đồng thật; cơ chế fallback chéo (GHN→GHTK) chưa kiểm chứng hoạt động đúng giữa hai API khác nhau | Phụ thuộc ngoài — kế thừa `CTX §4.2`, phần liên quan `RISK-04` (BA), `ASM-02` (BA) | Vừa | Vừa | 🟠 | Xin tài liệu API + sandbox trước GĐ2 `ICD`; viết integration test riêng cho luồng fallback (đã định hướng ở `docs/sections/09-van-hanh-kiem-thu.md` §9.1.2 "trọng tâm rủi ro cao") | Tech Lead | Trước GĐ2 `ICD` | Mở | +| `ARISK-05` | Đội thi công thật chưa xác nhận kinh nghiệm production với Kafka/MSK/OpenSearch/EKS (`OQ-010`) — ảnh hưởng trực tiếp nếu `POC-01` fail và phải bổ sung Kafka/MSK cho hot-path (kiến trúc lai theo `OPT §1`) | Con người — kế thừa `CTX §4.4` | Cao | Vừa | 🔴 | Tech Lead xác nhận năng lực đội thật (`OQ-010`); nếu thiếu kinh nghiệm — thuê chuyên gia tư vấn ngắn hạn cho riêng giai đoạn triển khai Kafka/MSK nếu `POC-01` fail (không phải "sẽ theo dõi") | Tech Lead | Trước khi chốt `ADR` message backbone GĐ2 | Mở | +| `ARISK-06` | Chia sẻ PII (địa chỉ, SĐT người nhận) cho seller khi tách đơn chưa được rà soát theo NĐ13/2023; residency dữ liệu (`ap-southeast-1`) chưa được đại diện Pháp chế xác nhận | Tuân thủ — kế thừa `CTX ASM-04`, `RISK-03` (BA), `OQ-007` | Vừa | Lớn | 🔴 | PO chỉ định đại diện Pháp chế/Bảo mật (`OQ-007`); SA chuẩn bị danh sách trường PII chia sẻ cho seller để người đó rà soát trước khi chốt `DAT`/`INF` GĐ2 | PO (chỉ định người) → Legal/Security (rà soát) | Trước GĐ2 (`DAT`/`INF`), chậm nhất trước go-live | Mở | +| `ARISK-07` | Ngân sách vận hành 3 năm thật (`TCO` §1: 11,2–19,1 tỷ VND tuỳ phương án/kịch bản) chưa được PO/tài chính xác nhận có đủ khả năng chi trả hay không — con số duy nhất PO từng thấy (~3,76 tỷ) chỉ là chi phí xây dựng | Chi phí — kế thừa `CON-01`, `OQ-005`, `TCO §1` | Cao | Lớn | 🔴 | Trình `TCO` đầy đủ (đã lập) cho PO/tài chính; nếu ngân sách thật thấp hơn nhiều, loại bớt cấu phần hạ tầng nặng (đã có phương án P2 rẻ hơn P1 làm phương án dự phòng "cắt giảm") | PO/tài chính | Trước khi ký AG1 | Mở *(biện pháp = trình số liệu; chưa có xác nhận ngân sách nên chưa "đã hạ")* | +| `ARISK-08` | Đội vận hành (Ops/SRE) sau go-live chưa xác nhận nội bộ hay thuê ngoài, quy mô bao nhiêu người (`OQ-008`) — ảnh hưởng cả khả năng đạt `DRV-05` (99.9% uptime) lẫn chi phí `TCO` (`ASM-14`, dòng nhạy cảm nhất) | Con người — kế thừa `CON-05/08` | Vừa | Vừa | 🟠 | PM/SRE xác nhận số người thật trước GĐ2 (`OQ-008`); tạm dùng giả định 2 FTE (`ASM-14`) làm mốc thiết kế `INF`/on-call ban đầu, sẽ điều chỉnh khi có số thật | PM/SRE | Trước khi chốt `INF` GĐ2 | Mở | +| `ARISK-09` | Cảnh báo tự động `estimate.computed.json.crosscheck`: effort WBS (42,48 MM) lệch 54,47% so với UCP (27,5 MM), vượt ngưỡng 25% — dấu hiệu ước lượng effort xây dựng chưa ổn định, có thể ảnh hưởng cả tiến độ lẫn `TCO` §6 | Chi phí/ước lượng | Vừa | Vừa | 🟠 | Nhà thầu/PM giải thích chênh lệch tại mục C1 hồ sơ thầu (đã có lý giải sơ bộ: mật độ hạng mục kỹ thuật xuyên suốt cao hơn UCP phản ánh được); Tech Lead xác nhận lại effort WBS-03/05/06 (3 hạng mục XL/high risk) độc lập trước khi ký hợp đồng | PM/Tech Lead | Trước khi chốt hợp đồng thi công | Mở | +| `ARISK-10` | Email/SMS Provider và ngân hàng đối tác payout chưa chốt cụ thể (`SAD.md §3.4` tự ghi "chưa chốt") — ảnh hưởng cả `ICD` GĐ2 lẫn `TCO §4` (`OQ-016`) | Phụ thuộc ngoài | Thấp | Vừa | 🟡 | PO/PM chọn nhà cung cấp cụ thể trước GĐ2 `ICD`; không chặn Bước 4/5 của GĐ1 vì đây không phải luồng giao dịch lõi (`DRV-01`) | PM | Trước GĐ2 `ICD` | Mở | + +**Trạng thái:** Mở · Đang hạ · Đã đóng (kèm bằng chứng) · Đã chấp nhận (kèm ai chấp nhận) + +## 4. Rà sáu nguồn rủi ro *(checklist)* + +| Nguồn | Câu hỏi | Trả lời | Sinh `ARISK` nào | +|---|---|---|---| +| Công nghệ mới | Có ai trong team từng chạy production cái này chưa? | Chưa xác nhận cho Kafka/MSK/OpenSearch/EKS (`OQ-010`); SQS/EventBridge/ECS Fargate là công nghệ managed phổ biến hơn, rủi ro thấp hơn nhưng chưa đo throughput trong ngữ cảnh này | `ARISK-01`, `ARISK-05` | +| Phụ thuộc bên ngoài | Bên kia có SLA không? Ta có phương án khi họ hỏng/đổi/ngừng? | VNPay/Momo/GHN/GHTK: chưa sandbox/hợp đồng thật, chưa có SLA xác nhận; Email/SMS/ngân hàng: chưa chọn nhà cung cấp | `ARISK-03`, `ARISK-04`, `ARISK-10` | +| Dữ liệu | Migration có rollback được không? Dữ liệu bẩn tới mức nào? | Không áp dụng — greenfield (`CTX §4.1`), không có dữ liệu cũ để migrate | *(không sinh ARISK — ghi nhận N/A trong "Ngoài phạm vi")* | +| Hiệu năng | Con số throughput/latency lấy từ bài đo hay từ suy đoán? | Suy đoán/giả định (`ASM-07/08` của `OPT`) — chưa có bài đo thật | `ARISK-01`, `ARISK-02` | +| Con người | Người duy nhất biết hệ thống cũ có còn ở công ty không? | Không áp dụng (greenfield, không có hệ thống cũ); nhưng đội vận hành/thi công thật chưa xác nhận | `ARISK-05`, `ARISK-08` | +| Chi phí | Khoản nào tăng phi tuyến theo tải? | Egress CDN và RDS scale-up (§3 `TCO`) tăng theo tải nhưng đã mô hình hoá 2 kịch bản; ngân sách 3 năm thật chưa xác nhận đủ hay không | `ARISK-07`, `ARISK-09` | + +## 5. Rủi ro đã chấp nhận + +*Chưa có rủi ro nào được chính thức chấp nhận (cần người có thẩm quyền ký) ở lượt chạy này.* +`ARISK-06` (residency NĐ13/2023) là ứng viên gần nhất nếu Legal/Security sau này xác nhận +`ap-southeast-1` đủ đáp ứng — khi đó chuyển dòng này xuống bảng dưới kèm chữ ký thật, không tự +đóng bằng đánh giá của SA (`D10`). + +| ID | Rủi ro | Vì sao chấp nhận | Ai ký · ngày | Dấu hiệu cảnh báo sớm | Kế hoạch dự phòng | +|---|---|---|---|---|---| +| *(trống)* | | | | | | + +## 6. Kế hoạch POC + +*`ARISK-01`/`ARISK-02` là rủi ro 🔴 chưa chứng minh được — bắt buộc POC theo `decision-radar.md +§6` (quyết định "kiểu kiến trúc tổng thể"/"đồng bộ hay bất đồng bộ" đạt radar ≥ 8 ở `DEC-06` +cần POC trước khi `ADR` GĐ2 chuyển `Accepted`). Tiêu chí pass/fail viết **trước** khi làm.* + +### POC-01 — Throughput SQS/EventBridge cho luồng đặt hàng + +| | | +|---|---| +| **Hạ rủi ro** | `ARISK-01` | +| **Câu hỏi cần trả lời** | SQS FIFO (per-seller message group) + EventBridge có xử lý được ≥ 100 message/giây bền vững (payload ~2KB, giống `OrderPlaced`/`PaymentConfirmed`) mà không mất message và độ trễ chấp nhận được không? | +| **Tiêu chí PASS** | Thông lượng sustained **≥ 100 msg/s** trong 30 phút liên tục; **p99 độ trễ publish→consume ≤ 2 giây**; **0 message mất**; EventBridge fan-out tới ≥ 5 consumer rule không lag quá 5 giây. *(Cơ sở con số: `DRV-04` đỉnh ~15.000 đơn/giờ × ~5 event/đơn ≈ 21 event/giây trung bình; thiết kế biên an toàn ×5 cho burst ⇒ ngưỡng 100 msg/s)* | +| **Tiêu chí FAIL** | Thông lượng sustained < 100 msg/s, hoặc p99 > 2 giây, hoặc có message mất, hoặc lag > 5 giây kéo dài > 5 phút liên tục | +| **Phạm vi** | Chỉ đo throughput/latency/độ tin cậy message — **không** đo chi phí (đã có ở `TCO`), **không** đo tích hợp với Payment Service thật (dùng giả lập payload) | +| **Thời lượng tối đa** | 5 ngày làm việc — dừng khi hết thời lượng dù chưa xong, báo cáo kết quả dở dang | +| **Ai làm** | Tech Lead + 1 DevOps | +| **Môi trường** | AWS `ap-southeast-1` (SQS FIFO + EventBridge thật, không giả lập), payload JSON ~2KB theo schema `OrderPlaced` dự kiến, load generator k6/artillery | + +**Kết quả** *(điền sau khi chạy)* + +| | | +|---|---| +| **Ngày chạy** | *(chưa chạy — theo `OQ-012`, POC phải xong trước `ADR` message backbone GĐ2)* | +| **Kết quả đo** | — | +| **PASS / FAIL** | — | +| **Điều bất ngờ phát hiện được** | — | +| **Quyết định rút ra** | ⟶ sẽ tham chiếu `ADR` message backbone GĐ2 (`sa-2-architecture`) | + +### POC-02 — RDS PostgreSQL gộp chịu tải ghi/đọc kết hợp (P2) + +| | | +|---|---| +| **Hạ rủi ro** | `ARISK-02` | +| **Câu hỏi cần trả lời** | 1 cụm RDS chính (giả định `db.r6g.xlarge` Multi-AZ, `TCO §3.2`) có đáp ứng đủ tải ghi (checkout) + đọc (catalog) gộp cho các module ngoài Payment ở tải đỉnh flash sale không? | +| **Tiêu chí PASS** | Đồng thời ~15.000 đơn/giờ (ghi) + ~150.000 truy vấn catalog/giờ (đọc, ước ×10 tải ghi) trong 30 phút liên tục: **p95 write latency (checkout) ≤ 300ms**, **p95 read latency (catalog) ≤ 200ms** (khớp `NFR-01` của `docs/sections/09` §9.1.4), **CPU RDS < 75%**, **connection pool không bị exhaust** | +| **Tiêu chí FAIL** | Vượt một trong các ngưỡng trên, hoặc xuất hiện lỗi connection/timeout do exhaust pool | +| **Phạm vi** | Chỉ đo tải DB gộp — **không** đo chịu lỗi/failover (đã có kịch bản chaos riêng ở `docs/sections/09` §9.1.4 NFR-03, thuộc GĐ3) | +| **Thời lượng tối đa** | 5 ngày làm việc | +| **Ai làm** | Tech Lead/DBA | +| **Môi trường** | Staging cấu hình instance class thật (`db.r6g.xlarge` Multi-AZ), dataset synthetic quy mô tương đương Năm 1 (`TCO §2` kịch bản A: ~50GB, 300.000 SKU) | + +**Kết quả** *(điền sau khi chạy)* + +| | | +|---|---| +| **Ngày chạy** | *(chưa chạy — cần trước khi chốt `DAT` GĐ2)* | +| **Kết quả đo** | — | +| **PASS / FAIL** | — | +| **Điều bất ngờ phát hiện được** | — | +| **Quyết định rút ra** | ⟶ sẽ tham chiếu `DAT`/`ADR` liên quan ở GĐ2 | + +🔴 **POC fail vẫn phải ghi lại đầy đủ** — nếu `POC-01` fail: bổ sung Kafka/MSK riêng cho hot-path +đặt hàng (kiến trúc lai, theo điều kiện đã nêu ở `OPT §1`), **không** chuyển hẳn sang P1. Nếu +`POC-02` fail: tách read replica/DB riêng cho Catalog/Search sớm hơn dự kiến, cập nhật `TCO` +(chi phí hạ tầng P2 tăng, tiệm cận P1 cho phần đó — đã cảnh báo ở `TCO §3.3` cuối). + +## 7. Rủi ro đã đóng + +| ID | Rủi ro | Đóng ngày | Bằng chứng | +|---|---|---|---| +| *(chưa có — sổ mới lập)* | | | | + +## 8. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | +|---|---|---|---|---| +| `OQ-013` | Xác nhận đơn giá AWS `ap-southeast-1` ước tính ở `TCO §3.1` (`ASM-11`) bằng AWS Pricing Calculator thật hoặc báo giá đại lý AWS tại VN — chênh lệch bao nhiêu so với ước tính? | Tech Lead/DevOps + tài chính | 2026-09-12 | Độ tin cậy `TCO` toàn bộ; ngân sách hạ tầng `INF` GĐ2 phải khớp (`D9`) | +| `OQ-014` | Biểu phí giao dịch VNPay/Momo thật (theo % hay phí cố định) và GMV (tổng giá trị giao dịch) dự kiến năm 1 là bao nhiêu, để tính `NL-03` trong `TCO`? | PO/tài chính + đàm phán với VNPay/Momo | 2026-09-12 | `TCO §4` (hiện chưa tính được khoản này) | +| `OQ-015` | Biểu phí API GHN/GHTK theo hợp đồng thật là bao nhiêu (`NL-05`)? | PM (đàm phán hợp đồng vận chuyển) | 2026-09-12 | `TCO §4`, `ARISK-04` | +| `OQ-016` | Nhà cung cấp Email/SMS cụ thể (SES/SNS hay SendGrid/Twilio hay nhà cung cấp nội địa) là gì, biểu phí bao nhiêu (`NL-04`)? | PM/Tech Lead | 2026-09-12 | `TCO §4`, `ARISK-10`, `ICD` GĐ2 | +| `OQ-017` | Báo giá pentest ứng dụng hàng năm + ASV scan hàng quý (phạm vi PCI-DSS SAQ A) từ nhà cung cấp thật là bao nhiêu (`NL-07`)? | PO/Security (khi có người) | 2026-09-12 | `TCO §4` | + +**Nhắc:** cùng với `OQ-005/006/007/008/010/011/012` (còn mở, xem `00-index/OQ_e-commerce.md`), +năm câu hỏi mới ở trên hoàn thiện bức tranh input còn thiếu cho `TCO`/`ARISK`. Sau lượt này, GĐ1 +SA đã đủ 4 artifact (`CTX`/`OPT`/`TCO`/`ARISK`) để **audit AG1** — nhưng tự chấm cho thấy AG1 +**vẫn chưa đủ điều kiện ký chính thức** (xem Tự chấm ở cuối mỗi artifact); cần PO + Tech Lead xử +lý các `OQ` chặn trước khi ký. + +--- + +## Tự chấm + +### ① Bảng tự chấm Gate AG1 *(`workflow.md §2`, cập nhật cuối cùng của GĐ1)* + +| # | Tiêu chí | ☐/✅ | Ghi chú | +|---|---|---|---| +| 1 | `CTX` có `DRV-nn` | ✅ | `CTX §2` | +| 2 | `CTX` có `CON-nn` | ✅ *(với lưu ý)* | `CTX §3` | +| 3 | `CTX` mô tả hiện trạng as-is | ✅ *(với lưu ý)* | `CTX §4` | +| 4 | `OPT` có ≥2 phương án, chấm điểm, nêu phương án bị loại | ✅ | `OPT §4`/§5 | +| 5 | `TCO` có chi phí 3 năm, ≥2 kịch bản tải | ✅ | `TCO_e-commerce_v1.0.md` toàn bộ | +| 6 | `ARISK` có rủi ro cao kèm chủ + biện pháp | ✅ | §3 — `ARISK-01,02,03,05,06,07` mức 🔴, mỗi cái có chủ + biện pháp cụ thể (POC, đàm phán sandbox, chỉ định người rà soát pháp lý) — không có biện pháp "sẽ theo dõi" | +| 7 | Rủi ro cao chưa chứng minh được có kế hoạch POC | ✅ | §6 — `POC-01` (SQS/EventBridge), `POC-02` (RDS gộp tải), mỗi cái có tiêu chí PASS/FAIL viết trước khi làm, thời lượng tối đa, ai làm, môi trường | + +**Kết luận tự chấm AG1 (toàn GĐ1):** **7/7 tiêu chí đủ về cấu trúc** — GĐ1 SA hoàn tất đủ 4 +artifact bắt buộc (`CTX`, `OPT`, `TCO`, `ARISK`) theo đúng `artifact-map.md`. **Vẫn chưa đủ điều +kiện để PO + Tech Lead ký AG1 chính thức** vì: (a) BA chưa ký G1 thật cho `BRIEF_CartCheckout` +(`OQ-001` còn mở); (b) nhiều con số nền (`CON-01/02/05`, đơn giá AWS, đội vận hành) vẫn ở mức +🔴 giả định/tham khảo, chưa được PO/PM/Tech Lead xác nhận bằng số thật; (c) hai `POC` bắt buộc +(`POC-01`, `POC-02`) **chưa chạy** — chỉ mới có kế hoạch. Khuyến nghị trình tự trước khi ký: +(1) PO/PM trả lời `OQ-005` (ngân sách) và `OQ-008` (đội vận hành) bằng số thật; (2) Tech Lead trả +lời `OQ-010` (năng lực team); (3) chạy `POC-01`/`POC-02`, cập nhật kết quả vào `ARISK §6`; (4) khi +đó AG1 mới có đủ bằng chứng để ký thay vì "trông hợp lý" (đúng tinh thần `workflow.md §2`: *"Gate +kiến trúc khác gate BA ở một điểm: không ký được bằng trông hợp lý"*). + +### ② Checklist D1–D12 *(`design-rules.md`)* + +| # | Mục | ☐/✅ | Ghi chú | +|---|---|---|---| +| D1 | Một ADR một quyết định | N/A | Không có `ADR` trong tài liệu này | +| D2 | Không NFR định tính | N/A | Không chứa `QAS` | +| D3 | Nêu phương án bị loại + lý do | N/A | Không áp dụng cho sổ rủi ro (đã có ở `OPT §5`) | +| D4 | Sơ đồ khai báo mức + legend | N/A | Không có sơ đồ mới | +| D5 | Interface có chủ/contract | N/A | Chưa tới `ICD` | +| D6 | Phụ thuộc ngoài process có timeout/retry | 🟡 Một phần | §3 `ARISK-03/04` kế thừa nguyên trạng timeout/retry đề xuất từ `SAD.md §3.4` (VNPay/Momo 10s, GHN/GHTK 8s) — chưa kiểm chứng sandbox thật, ghi rõ trạng thái | +| D7 | Một chủ sở hữu dữ liệu | N/A | Chưa tới `DAT` | +| D8 | Ràng buộc có FIT hoặc nhãn khuyến nghị | N/A | Chưa tới `AGD`/`FIT` | +| D9 | Con số hạ tầng quy ra tiền + nguồn | N/A | Đã xử lý ở `TCO`; `ARISK` không lặp lại con số | +| D10 | Không quyết định thay người có thẩm quyền | ✅ | Mọi rủi ro cần quyết định của PO/Security (ngân sách, chấp nhận rủi ro residency) đều ghi ở dạng `ARISK` + `OQ` kèm biện pháp đề xuất, không tự chấp nhận thay (§5 "Rủi ro đã chấp nhận" còn trống — đúng, vì chưa ai ký) | +| D11 | Có mục "Ngoài phạm vi" + `ASM-nn` | ✅ *(tham chiếu)* | Không tạo `ASM` mới riêng — tham chiếu `ASM-04/07/08` (`CTX`/`OPT`) và `ASM-10…15` (`TCO`) theo đúng nguyên tắc "không copy, chỉ tham chiếu ID" (`artifact-map.md §7`); mục dữ liệu/migration ghi rõ N/A ở §4 (greenfield) | +| D12 | Câu quy định thẩm quyền sơ đồ vs văn bản | ☐ | *(Thiếu — sổ rủi ro dạng bảng, không có sơ đồ, nên không bắt buộc câu này; ghi nhận để nhất quán với các artifact khác nếu cần)* | + +### ③ Danh sách `OQ` mở kèm người phải trả lời, chặn gì + +Xem bảng đầy đủ §8 (`OQ-013…017`, mới) cộng sổ `00-index/OQ_e-commerce.md` (`OQ-001, 003, 004, +005, 006, 007, 008, 010, 012` còn mở). Hai câu chặn trực tiếp việc chạy `POC`: **`OQ-010`** +(năng lực team — ảnh hưởng quyết định có cần `POC-01` hay không nếu team đã có kinh nghiệm) và +**`OQ-012`** (đã đóng có điều kiện — POC phải chạy trước `ADR` message backbone GĐ2, xem `DEC-06`). + +**Nhắc cuối GĐ1:** AG1 cần **PO + Tech Lead ký** (điền `Approved by` vào header `OPT`, xem +`workflow.md §2`) trước khi chạy `/sa-2-architecture`. Bốn điều kiện ra khỏi GĐ1 theo `GUIDE.md`: +(1) bảng tự chấm AG1 toàn ✅ *(đạt về cấu trúc, chưa đạt về nội dung đã xác nhận)*; (2) PO **và** +Tech Lead điền `Approved by` thật vào `OPT` *(chưa — vẫn là ký thay theo ngoại lệ)*; (3) mọi +`ARISK` mức cao có chủ + biện pháp cụ thể *(đạt)*; (4) `POC-01`/`POC-02` đã **chạy xong**, kết quả +ghi vào `ARISK` *(chưa — mới có kế hoạch)*. Còn thiếu (2) và (4) trước khi coi AG1 là qua thật. diff --git a/sa-output/e-commerce/01-context/CTX_e-commerce_v1.0.md b/sa-output/e-commerce/01-context/CTX_e-commerce_v1.0.md new file mode 100644 index 0000000..cd2a25b --- /dev/null +++ b/sa-output/e-commerce/01-context/CTX_e-commerce_v1.0.md @@ -0,0 +1,356 @@ +# CTX — Solution Context & Drivers — e-commerce + +| | | +|---|---| +| **Version** | 1.2 | +| **Date** | 2026-09-12 | +| **Author** | SA (skill sa-1-context, chế độ `go`, hoạt động `as-is`) | +| **Status** | 🟡 Draft *(duyệt tạm/từng phần — xem `Approved by`; §2 Driver và §3 Ràng buộc/§5 Giả định đã duyệt tạm ở v1.0/v1.1; **§4 Hiện trạng (AS-IS) vừa bổ sung ở v1.2** theo ghi chú người duyệt — chưa được PO/Tech Lead ký riêng, sẽ ký cùng đợt AG1 toàn phần; Bước 4–5 (`OPT`/`TCO`/`ARISK`) vẫn chưa làm; AG1 toàn phần **chưa** đủ điều kiện, xem "Tự chấm" §① bên dưới, 3/7 tiêu chí ✅)* | +| **Approved by** | PO (uỷ quyền, chế độ chạy thử): **Điều phối dự án** — duyệt **§2 Driver (`DRV-01`…`DRV-09`)** của bản v1.0 · 2026-09-12; và duyệt **§3 Ràng buộc (`CON-01`…`CON-09`) + §5 Giả định (`ASM-01`…`ASM-06`)** của bản v1.1 · 2026-09-12, cùng cách và cùng ngoại lệ như đã áp dụng cho §2. Ký thay PO theo mô hình ngoại lệ `DEC-01` (SA) / `DEC-01` (BA); **không phải chữ ký PO thật** — `OQ-004` giữ mở cho tới khi PO sàn thật xác nhận lại. `Confidence` của `CTX` giữ 🔴 cho tới khi BA ký G1 thật (không đổi bởi phê duyệt này — phê duyệt không phải bằng chứng nguồn mới, đặc biệt vì phần lớn `CON` neo theo hồ sơ thầu Draft chưa hợp đồng). Duyệt này vẫn là duyệt **từng phần**, không phải AG1 toàn phần. · Tech Lead: — *(chưa ký)* · **§4 Hiện trạng (AS-IS, v1.2) chưa được ai duyệt** — chờ cùng đợt duyệt AG1 toàn phần với Bước 4–5 | +| **Source** | `ba-output/e-commerce/01-discovery/BRIEF_CartCheckout_v1.0.md` (Draft) · `ba-output/e-commerce/01-discovery/STAKEHOLDER_CartCheckout_v1.0.md` · `ba-output/e-commerce/01-discovery/RISK_CartCheckout_v1.0.md` · `ba-output/e-commerce/02-analysis/PROCESS_CartCheckout_v1.0.md` §0 (khẳng định greenfield, AS-IS rút gọn) · `ba-output/e-commerce/02-analysis/IMPACT_CartCheckout_v1.0.md` · `ba-output/e-commerce/00-index/PROFILE_e-commerce.md` (LIFECYCLE=greenfield) · `e-commerce/docs/SAD.md` v0.2 (§0–§3, §5.3.6, §8, §9.5.2) · `e-commerce/docs/00-project-brief.md` (v3) · `e-commerce/docs/sections/01-tong-quan.md` · `e-commerce/docs/sections/02-phan-tich-yeu-cau.md` · `e-commerce/docs/sections/03-kien-truc.md` §3.3–§3.4 (môi trường, tích hợp bên thứ ba) · `e-commerce/docs/sections/09-van-hanh-kiem-thu.md` §9.5.2 (RTO/RPO kế thừa) · `e-commerce/bid/bid-config.md` (Draft — hồ sơ thầu, chưa hợp đồng) · `e-commerce/bid/30-implementation-plan.md` (Draft) · `e-commerce/bid/estimate.computed.json` (Draft, `priceComplete: false`) | +| **Scope** | Toàn sàn e-commerce (marketplace đa seller) theo `SAD.md` v0.2. Trọng tâm chi tiết nhất: module **Giỏ hàng & Checkout** (FR-05/06/07, US-002/003, RQ-001…004) — nguồn driver có Confidence cao nhất. Các module khác của sàn (Catalog, Seller/KYC, Commission & Payout, Loyalty, Notification…) suy driver từ `SAD.md`/`docs/sections/01,02` — chưa qua BRIEF/RISK cấp module riêng, Confidence thấp hơn. **Phạm vi hoạt động của lượt chạy này (v1.2): Bước 3 — Hiện trạng (AS-IS), §4**, tiếp nối Bước 1 (Driver, v1.0) và Bước 2 (Ràng buộc, v1.1) đã làm trước đó. Phương án (`OPT`)/Chi phí (`TCO`)/Rủi ro kiến trúc (`ARISK`) **vẫn chưa** thực hiện — xem §6 "Ngoài phạm vi". | +| **Confidence** | 🔴 Giả định chưa xác minh — *(bắt buộc theo ghi chú điều phối: BA chưa ký G1 chính thức cho `BRIEF_CartCheckout` — Draft, `OQ-001`/`OQ-007` (BA) còn mở; đồng thời AG1 (gate của chính GĐ1 SA) chưa từng chạy cho dự án này. Mọi `DRV` suy ra từ nguồn Draft giữ mức 🔴 cho tới khi BA ký G1 thật. §3/§5 (v1.1) dùng nhiều số liệu từ hồ sơ thầu `e-commerce/bid/` — đây là ƯỚC LƯỢNG DỰ THẦU (Draft, `priceComplete: false`, chưa PO ký hợp đồng), KHÔNG phải ràng buộc cứng đã duyệt. §4 (v1.2, mới) có phần **khẳng định greenfield** đủ tin cậy 🟢 (nguồn `PROFILE_e-commerce.md` đã PO chốt 2026-09-08) nhưng phần **tài sản thiết kế `SAD.md`/hồ sơ thầu dùng làm điểm khởi đầu OPT** và **trạng thái đối tác tích hợp** vẫn 🔴 (chưa sandbox/hợp đồng thật với bất kỳ đối tác nào — kế thừa `CON-04`). Header giữ mức thấp nhất toàn tài liệu: 🔴, cho tới khi PO/PM/Tech Lead xác nhận bằng số/tài liệu thật.)* | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | ADR/DEC | +|---|---|---|---|---| +| 1.0 | 2026-09-12 | SA (qua skill sa-1-context) | Bản đầu — chỉ hoạt động **Driver** (Bước 1/5 của `sa-1-context`), theo yêu cầu phạm vi hẹp của lượt chạy này. Ràng buộc/Hiện trạng/Giả định/`OPT`/`TCO`/`ARISK` để lượt sau. Chạy dưới ngoại lệ gate (BA chưa ký G1, AG1 của chính GĐ1 SA cũng chưa có tiền lệ) theo yêu cầu điều phối viên. | `DEC-01` (SA) | +| 1.0 | 2026-09-12 | PO (uỷ quyền, Điều phối dự án) — tác vụ **sign/approve** | Duyệt **tạm/từng phần** §2 Driver (`DRV-01`…`DRV-09`) của bản v1.0. Không đổi nội dung chuyên môn. Ký thay PO theo ngoại lệ `DEC-01`; `OQ-004` (tính hợp lệ của ngoại lệ ký thay) **giữ mở**. `Confidence` giữ 🔴 (không nâng lên do phê duyệt này — phê duyệt không phải là bằng chứng mới về nguồn driver). Tech Lead **chưa ký** — theo "Tự chấm AG1" trong tài liệu, gate AG1 toàn phần (đủ 7 tiêu chí, cần cả PO + Tech Lead) **chưa đạt**; đây chỉ là ghi nhận đồng thuận tạm thời trên phần Driver để cho phép các bước sau của `sa-1-context` (Ràng buộc/Hiện trạng/Giả định/`OPT`/`TCO`/`ARISK`) tiếp tục dưới ngoại lệ đã có. Đồng thời, người dùng chốt hướng trả lời `OQ-002` (Bước 2 — ràng buộc Con người): dùng giả định "team MVP chuẩn" ở `Confidence` 🔴, ghi tại `DEC-02` (SA) và đóng `OQ-002` trong sổ `00-index/OQ_e-commerce.md` (giả định thật `ASM-nn` sẽ được lập khi `CON` Bước 2 chạy, tham chiếu `DEC-02`). | `DEC-01`, `DEC-02` (SA) | +| 1.1 | 2026-09-12 | SA (qua skill sa-1-context, chế độ `go`, hoạt động `constraints`) | Bổ sung §3 Ràng buộc — đủ 6 nhóm (`CON-01` Tiền; `CON-02` Thời gian; `CON-03`/`CON-04` Công nghệ; `CON-05` Con người; `CON-06`/`CON-07` Pháp lý; `CON-08`/`CON-09` Tổ chức/Vận hành) và §5 Giả định (`ASM-01`…`ASM-06`), theo ghi chú người duyệt. Ngân sách/deadline tham khảo `e-commerce/bid/` (hồ sơ thầu ước lượng, **không phải hợp đồng** — nêu rõ độ tin cậy thấp, không coi là ràng buộc cứng khi chưa có PO xác nhận). Pháp lý bổ sung chi tiết PCI-DSS (SAQ A, không lưu thẻ), NĐ13/2023 (residency/retention/quyền xoá dữ liệu, theo `SAD.md` §5.3.6/§8.2.4), hoá đơn điện tử (đã xác nhận hoãn phase 2, không phải khoảng trống). Tiếp tục ngoại lệ gate `DEC-01` (BA chưa qua G1) — người dùng tái khẳng định muốn tiếp tục, ghi nhận thêm tại `DEC-03` (SA); `Confidence` giữ 🔴 toàn bộ tài liệu. Thêm `OQ-005`…`OQ-009` (ngân sách, deadline, đại diện Pháp chế cho residency, đội vận hành sau go-live, có neo theo `SAD.md`/hồ sơ thầu cho Bước 4 hay không) vào §7 và sổ `00-index/OQ_e-commerce.md`. Không sửa §2 Driver đã duyệt từng phần. | `DEC-01`, `DEC-03` (SA) | +| 1.1 | 2026-09-12 | PO (uỷ quyền, Điều phối dự án) — tác vụ **sign/approve** | Duyệt **từng phần** §3 Ràng buộc (`CON-01`…`CON-09`) và §5 Giả định (`ASM-01`…`ASM-06`) của bản v1.1 — cùng cách ký thay PO theo ngoại lệ `DEC-01` (SA) đã dùng cho §2 Driver ở v1.0, **không phải chữ ký PO thật**. Không đổi nội dung chuyên môn. `OQ-004` (tính hợp lệ của ngoại lệ ký thay) giữ **mở**; Tech Lead **chưa ký**. `Confidence` giữ 🔴 (không nâng — phê duyệt không phải bằng chứng nguồn mới, và phần lớn `CON` vẫn neo theo hồ sơ thầu Draft/`priceComplete:false`, chưa PO xác nhận số thật). Status **giữ** 🟡 Draft — AG1 toàn phần vẫn chưa đủ điều kiện baseline (2/7 tiêu chí ✅, xem "Tự chấm" §①); §4 Hiện trạng và Bước 4–5 (`OPT`/`TCO`/`ARISK`) vẫn để lượt sau. | `DEC-01` (SA) | +| 1.2 | 2026-09-12 | SA (qua skill sa-1-context, chế độ `go`, hoạt động `as-is`) | Bổ sung §4 Hiện trạng (AS-IS) theo ghi chú người duyệt — bốn phần: (a) khẳng định greenfield + hệ quả (không dữ liệu migrate, không baseline tải/KPI thật); (b) hệ sinh thái bên ngoài phải tích hợp và trạng thái từng đối tác (VNPay, Momo, GHN, GHTK, Email/SMS, hoá đơn điện tử — hoãn phase 2); (c) tài sản thiết kế đã có (`SAD.md` v0.2 approved + hồ sơ thầu) — ghi rõ đây là **thiết kế đề xuất chưa thi công**, dùng làm điểm khởi đầu cho một phương án `OPT` theo trả lời `OQ-009`; (d) kỹ năng/tài sản tổ chức đã biết (AWS bắt buộc `CON-03`, team giả định `DEC-02`). Đóng `OQ-009` (chấp nhận `SAD.md` làm điểm khởi đầu tham khảo cho Bước 4, không phải phương án đã thắng sẵn) — ghi `DEC-04` (SA); `OQ-005`/`OQ-006` **giữ mở**, bổ sung ghi chú "câu trả lời tạm" (dùng số hồ sơ thầu làm mốc tham khảo, chưa PO xác nhận số thật) tại §7 và sổ `00-index/OQ_e-commerce.md`. Không sửa §2 Driver, §3 Ràng buộc, §5 Giả định đã duyệt từng phần trước đó. Tiếp tục ngoại lệ gate `DEC-01`/`DEC-03` (BA chưa qua G1, AG1 chưa từng chạy) — người dùng tái khẳng định muốn tiếp tục; `Confidence` giữ 🔴 cho phần lớn nội dung mới, riêng khẳng định greenfield (a) đạt 🟢 vì có nguồn `PROFILE_e-commerce.md` đã PO chốt. | `DEC-04` (SA) | + +> Sơ đồ thắng về **quan hệ và luồng** (không có sơ đồ trong phần Driver của lượt chạy này). +> Bảng/văn bản thắng về **ràng buộc và con số**. Mâu thuẫn ngoài hai loại này là lỗi tài liệu. + +--- + +## 0. Ghi chú Preflight & ngoại lệ gate — bắt buộc đọc trước + +Đây là **GĐ1 đầu tiên của bộ SA** cho dự án e-commerce — không có gate SA nào trước nó +(`sa-lifecycle/workflow.md §4` chỉ yêu cầu điều kiện *ngoài bộ*: BA đã qua **G1** với `BRIEF`, +`GOAL`, `RQ`). Điều kiện đó **chưa đạt**: + +- `BRIEF_CartCheckout_v1.0.md` — Status `🟡 Draft`, tự chấm G1 = **chưa đủ điều kiện ký chính + thức** (3/6 tiêu chí ☐: tên thật stakeholder `OQ-001`, buổi làm việc trực tiếp `OQ-005`, + baseline KPI thật `OQ-007`). +- Không có `BRIEF`/`RISK`/`STAKEHOLDER` cấp module cho các phần còn lại của sàn (Catalog, + Seller/KYC, Commission & Payout, Loyalty, Notification…) — driver các phần này chỉ suy được + từ `SAD.md` (đã "approved" ở cấp tài liệu BA nội bộ riêng, không đi qua pipeline `ba-*` module + hoá theo đúng quy trình). + +**Người dùng (vai điều phối dự án chạy thử) đã được cảnh báo và khẳng định lại muốn tiếp tục**, +tham chiếu mô hình ngoại lệ đã dùng ở bộ BA (`DEC-02..07`, dự án e-commerce là dự án chạy thử, +không có Designer, PO ký thay). Quyết định ngoại lệ này được ghi tại `DEC-01` (SA) — +xem sổ `00-index/DEC_e-commerce.md` (sẽ đồng bộ khi chạy `/sa-lifecycle`). + +> **DEC-01 (SA)** — Chạy `sa-1-context` (hoạt động Driver) cho dự án e-commerce trong khi BA +> chưa ký G1 chính thức và bản thân GĐ1 SA chưa có gate trước nó để chờ. +> **Quyết định:** Tiếp tục, gắn `Confidence 🔴` cho toàn bộ `DRV` cho tới khi BA ký G1 thật. +> **Người quyết:** Điều phối dự án (đại diện PO, theo ghi chú vận hành dự án chạy thử). +> **Radar (ước lượng):** chi phí đảo ngược thấp (viết lại phần Driver mất < 1 tuần nếu BA đổi +> phát biểu bài toán) · bán kính ảnh hưởng toàn bộ GĐ1 SA (một dự án) · không chạm trực tiếp một +> `QAS` cụ thể (chưa có `QAS` vì đây là GĐ1) · không ràng buộc dài hạn (là ngoại lệ tạm thời, +> không phải quyết định kiến trúc) · đã có tiền lệ ở bộ BA, ít tranh cãi. Tổng ước ~4 → **ghi +> `DEC-nn`, không cần `ADR`** theo `decision-radar.md §1–§2`. +> **Hệ quả nếu không chấp nhận ngoại lệ:** dừng toàn bộ GĐ1 SA cho tới khi BA ký G1 thật (cần +> tối thiểu: tên thật stakeholder, 1 buổi elicitation trực tiếp, baseline KPI đo được) — ước +> chậm tiến độ chạy thử ít nhất bằng thời gian BA hoàn tất các mục đó (không có con số cụ thể vì +> đây là dự án chạy thử không có lịch thật). + +--- + +## 1. Tóm tắt cho người quyết định + +Sàn marketplace đa seller (e-commerce) cần kiến trúc chịu được quy mô "lớn" (hàng trăm nghìn +SKU, hàng trăm nghìn–hàng triệu user, đỉnh hàng nghìn–chục nghìn concurrent user mùa flash sale) +trong khi vẫn giữ đúng luồng giao dịch lõi (giỏ hàng đa seller → tách đơn → thanh toán) không +mất tiền, không mất dữ liệu, và tách bạch dòng tiền giữa khách–sàn–seller. Áp lực lớn nhất +không nằm ở tính năng mà ở: (1) luồng giao dịch lõi là blocker của toàn bộ MVP, (2) đỉnh tải +flash sale, (3) tuân thủ pháp lý (PCI-DSS, NĐ13/2023) khi xử lý tiền và PII của hai loại chủ +thể (khách hàng và seller). Tài liệu này **chỉ chốt phần Driver** (`DRV-nn`) của GĐ1; Ràng buộc, +hiện trạng, phương án, chi phí và rủi ro sẽ chạy ở các lượt kế tiếp — xem `Ngoài phạm vi`. + +--- + +## 2. Driver — `DRV-nn` + +*Áp lực kinh doanh ép ra kiến trúc, không phải tính năng. Ưu tiên nguồn: `BRIEF_CartCheckout` +(GOAL-01/02, RQ-001…004) cho module Giỏ hàng & Checkout; `SAD.md` v0.2 §1–§2 (FR-01…27, +NFR-01…08) cho các module còn lại của sàn — Confidence thấp hơn vì chưa qua BRIEF module hoá.* + +| ID | Áp lực (định lượng) | Nguồn | Ai xác nhận · ngày | Thuộc tính chất lượng bị ép | Ưu tiên | +|---|---|---|---|---|---| +| `DRV-01` | Chưa có luồng giỏ hàng–checkout–thanh toán đa seller hoạt động ⇒ sàn **không thể ra mắt MVP**: 0 giao dịch ghi nhận được, seller không nhận được đơn, mọi module phụ thuộc (quản lý đơn hàng, hoa hồng, payout, đánh giá) bị **chặn hoàn toàn** — đây là blocker, không phải cải tiến. | `BRIEF_CartCheckout` §3 "Điều gì xảy ra nếu không làm gì cả" · §5.1 RQ-001…004 (Must) | STK-01 (PO sàn) qua `00-project-brief.md` vòng 1 — **chưa có tên thật**, `OQ-001` (BA) còn mở | Tính đúng đắn giao dịch · tính nhất quán dữ liệu qua nhiều seller · thông lượng | Must | +| `DRV-02` | Giỏ hàng ≥2 seller có nguy cơ tỷ lệ bỏ giỏ ở bước checkout cao hơn giỏ 1 seller (phí ship tính riêng theo từng seller, `RISK-04` mức 🟠). `GOAL-01` đề xuất ngưỡng chấp nhận ≤ (tỷ lệ bỏ giỏ 1 seller) + 10 điểm phần trăm — **baseline thật chưa có** (greenfield, `OQ-007` BA còn mở). | `BRIEF_CartCheckout` §4 GOAL-01 · `RISK_CartCheckout` RISK-04 | STK-01 (PO sàn) — đề xuất đo baseline 4–6 tuần đầu soft-launch, **chưa xác nhận số thật** | Độ trễ hiển thị phí ship theo seller · trải nghiệm nhất quán khi tách đơn | Must (gắn RQ-001/002 Must) | +| `DRV-03` | Thanh toán phải chấp nhận VNPay/Momo/COD **không lưu thông tin thẻ** để giảm phạm vi tuân thủ PCI-DSS — nếu tự lưu/xử lý thẻ, phạm vi kiểm toán PCI-DSS đầy đủ (thay vì rút gọn qua bên thứ ba) kéo theo chi phí tuân thủ và rủi ro pháp lý cao hơn đáng kể (con số tuân thủ cụ thể chưa có — cần Legal, xem `OQ` mới ở §7). | `BRIEF_CartCheckout` §5.1 RQ-003 · `docs/sections/01-tong-quan.md` §1.5 · `docs/sections/02-phan-tich-yeu-cau.md` NFR-05 | STK-01 (PO sàn), STK-06 (Tech Lead — chưa xác nhận khả thi), qua `00-project-brief.md` vòng 1 | Bảo mật/tuân thủ (ranh giới phạm vi PCI-DSS) | Must | +| `DRV-04` | Quy mô mục tiêu "lớn": hàng trăm nghìn SKU trở lên, hàng trăm nghìn–hàng triệu user đăng ký, đỉnh **hàng nghìn–chục nghìn concurrent user** mùa flash sale. Không scale-out ngay từ đầu ⇒ hệ thống có nguy cơ sập đúng lúc doanh thu cao nhất trong năm (flash sale). | `00-project-brief.md` mục 3 (Q&A vòng 1) · `docs/sections/02-phan-tich-yeu-cau.md` NFR-02 | STK-01 (PO sàn) qua vòng 1 brief — **chưa có tên thật, chưa có số đo thật** (dự án chưa vận hành, đây là mục tiêu quy mô đã "chốt" ở mức mô tả định tính "lớn", không phải SLA hợp đồng) | Khả năng mở rộng (scale-out) · thông lượng · độ trễ dưới tải đỉnh | Must | +| `DRV-05` | Uptime mục tiêu 99.9% cho dịch vụ giao dịch lõi (catalog, checkout, thanh toán) vì doanh thu phụ thuộc trực tiếp; escalation 24/7 cho sự cố nghiêm trọng. 99.9%/tháng ⇒ ngân sách lỗi ≈ 43 phút/tháng — vượt ngân sách này ở đúng dịch vụ giao dịch nghĩa là mất doanh thu trực tiếp trong khung giờ đó. | `docs/sections/02-phan-tich-yeu-cau.md` NFR-03, NFR-08 · `00-project-brief.md` mục 5 giả định #6 | STK-01 (PO sàn) — 🔴 **đây là "giả định mặc định đã chốt trong brief", CHƯA phải SLA hợp đồng thật** (ghi rõ trong `docs/sections/02-phan-tich-yeu-cau.md` cuối §2.2) | Sẵn sàng (availability) · khả năng phục hồi | Must | +| `DRV-06` | Dòng tiền phải minh bạch giữa 3 bên (khách–sàn–seller): hoa hồng tính theo ngành hàng (cấu hình được), payout hàng tuần qua chuyển khoản có kỳ giữ tiền (hold) 3–7 ngày sau giao hàng thành công. Sai lệch đối soát phát sinh từ tầng giao dịch (checkout/payment) sẽ lan sang toàn bộ hệ thống payout/commission — ở quy mô "lớn" (hàng trăm nghìn giao dịch), một lỗi hệ thống nhỏ nhân lên thành tranh chấp tài chính hàng loạt. | `docs/sections/01-tong-quan.md` §1.1 · `00-project-brief.md` mục 2 & mục 5 (giả định #3) · `docs/sections/02-phan-tich-yeu-cau.md` FR-17/FR-21/FR-22 | STK-01 (PO sàn), STK-04 (Kế toán đối soát — vai trò, chưa tên thật) | Tính nhất quán dữ liệu tài chính · khả năng kiểm toán (audit) · ranh giới sở hữu dữ liệu | Must | +| `DRV-07` | Chia sẻ PII (địa chỉ giao hàng, số điện thoại người nhận) cho từng seller khi tách đơn theo seller **chưa được rà soát** theo Nghị định 13/2023 vì dự án chưa có đại diện Pháp chế/Bảo mật được chỉ định. Rủi ro tương ứng đã được BA ghi nhận mức **Cao/Trung bình** (`RISK-03`). | `RISK_CartCheckout_v1.0.md` RISK-03 · `docs/sections/02-phan-tich-yeu-cau.md` NFR-04, NFR-05 | *(Chưa có người — `OQ-003` BA còn mở)* | Bảo mật/quyền riêng tư · phân loại dữ liệu nhạy cảm | Must | +| `DRV-08` | Xác nhận thanh toán qua webhook VNPay/Momo (bên thứ ba) **chưa được xác minh khả thi gần thời gian thực** (`ASM-01`, chưa xác minh). Nếu webhook trễ/lỗi, đơn hàng kẹt "chờ thanh toán" dù tiền đã thu ⇒ khiếu nại CSKH + sai lệch đối soát (`RISK-02`, tác động Cao, khả năng Trung bình). | `RISK_CartCheckout_v1.0.md` RISK-02, ASM-01 · `IMPACT_CartCheckout_v1.0.md` §1.5 | STK-06 (Tech Lead) + STK-01 (PO sàn) — chưa xác nhận khả thi thật (cần đọc tài liệu/gọi sandbox VNPay/Momo) | Tính nhất quán (eventual) · khả năng đối soát bù · quan sát được (observability) | Must | +| `DRV-09` | Đa ngôn ngữ 5 thứ tiếng (VI mặc định/EN/ZH/KO/JA) để mở rộng tệp khách hàng mục tiêu ra ngoài thị trường Việt Nam thuần tuý — Should, không chặn MVP nếu thiếu, nhưng thiếu thì giới hạn khả năng tiếp cận thị trường theo đúng mô hình kinh doanh đã chốt (marketplace quy mô lớn). | `docs/sections/01-tong-quan.md` §1.1 · `docs/sections/02-phan-tich-yeu-cau.md` NFR-06 | STK-01 (PO sàn) qua vòng 3 brief — chưa tên thật | Khả năng bảo trì (kiến trúc i18n/l10n tách nội dung khỏi code) | Should | + +**Ghi chú Confidence theo dòng:** `DRV-01, 02, 03, 07, 08` có nguồn trực tiếp từ `BRIEF/RISK/ +IMPACT` cấp module Giỏ hàng & Checkout (dù bản thân các tài liệu đó còn Draft) — Confidence +🔴 hiện tại chỉ vì BA chưa ký G1, **không phải vì thiếu nguồn**. `DRV-04, 05, 06, 09` chỉ có +nguồn từ `SAD.md`/`docs/sections` (chưa qua BRIEF/RISK module hoá riêng cho các phần đó của sàn) +— Confidence 🔴 vì **cả hai lý do**: chưa qua G1 và chưa có phân tích module hoá cấp BA. Ghi rõ +để người ký AG1 sau này biết mức độ rủi ro khác nhau giữa các dòng. + +### 2.1 Định hướng khách gợi ý *(tham khảo, KHÔNG phải driver)* + +| Khách/tài liệu nói | Đây là giải pháp cho vấn đề gì | Đã hỏi ngược chưa | `DRV` thật rút ra được | +|---|---|---|---| +| "Kiến trúc cần cache (Redis), CDN, message queue (Kafka/RabbitMQ), scale-out ngang ngay từ đầu" (`00-project-brief.md` mục 2 "NFR tiêu biểu"; lặp lại ở NFR-02) | Giải pháp cho vấn đề chịu tải đỉnh mùa flash sale — nhưng câu này tự nó không định lượng được tải đỉnh | ☐ Chưa hỏi trực tiếp PO/Tech Lead; suy luận qua con số ở NFR-02 ("hàng nghìn–chục nghìn concurrent user") | `DRV-04` — công nghệ cụ thể (Redis/Kafka/RabbitMQ) là đề xuất, **không phải ràng buộc bắt buộc**; việc chọn công nghệ nào thuộc Bước 4 (Phương án) của GĐ1, chưa làm ở lượt này | +| "Kiến trúc module hoá để các nhóm (catalog, order, seller, payment) phát triển độc lập" (NFR-07) | Giải pháp cho vấn đề đội ngũ chờ nhau khi release (Conway) — nhưng **số đội/số người CHƯA có** | ☐ Chưa hỏi — đây là câu hỏi thuộc nhóm ràng buộc "Con người" (Bước 2, ngoài phạm vi lượt chạy này) | Chưa rút ra được driver cụ thể — ghi `OQ-002` (SA) ở §7 | +| "Tech stack không bắt buộc, kiến trúc sư tự đề xuất theo best practice cho quy mô lớn; cloud = AWS" (`00-project-brief.md` mục 2 & 5) | Đây là **ràng buộc** (`CON`), không phải driver — AWS đã được xác nhận là bắt buộc (cứng) | N/A — không phải driver | Sẽ thành `CON-nn` (nhóm Công nghệ) khi chạy Bước 2 — ngoài phạm vi lượt này | + +--- + +## 3. Ràng buộc — `CON-nn` + +*Thứ KHÔNG thương lượng được — sở thích không phải ràng buộc. Rà đủ sáu nhóm theo +`sa-1-context/SKILL.md` Bước 2. Ngân sách/deadline dưới đây tham khảo `e-commerce/bid/` +(`bid-config.md`, `30-implementation-plan.md`, `estimate.computed.json`) — đây là **hồ sơ thầu +ước lượng của nhà thầu, Status `draft`, `cost.priceComplete=false`, KHÔNG phải hợp đồng đã ký**. +Dùng làm điểm tham khảo duy nhất hiện có, ghi rõ độ tin cậy 🔴, KHÔNG coi là ràng buộc cứng cho +tới khi PO xác nhận bằng số thật — theo đúng ghi chú người duyệt.* + +| ID | Nhóm | Ràng buộc | Nguồn (ai · ngày) | Cứng/Mềm | Hệ quả kiến trúc | +|---|---|---|---|---|---| +| `CON-01` | Tiền | Ngân sách hạ tầng/tháng và chi phí một lần **CHƯA được PO duyệt chính thức** (`00-project-brief.md` mục 6: "ngân sách/timeline chưa xác định"; mục 5 giả định: "ngân sách theo business case"). Tham khảo duy nhất hiện có: hồ sơ thầu ước lượng — lao động ≈ 3.420.500.000 VND (chưa VAT) + VAT 10% (342.050.000 VND) = **≈ 3.762.550.000 VND** cho 53,02 người-tháng/7 tháng thực hiện (`estimate.computed.json` → `cost.subtotal/vat/total`); **8 khoản chi phí không lao động** (hạ tầng AWS 3 môi trường, OpenSearch cluster, phí giao dịch VNPay/Momo, phí Email/SMS, phí API GHN/GHTK, domain/SSL/WAF, pentest/ASV hàng năm, đào tạo) đều `amount: null` — **chưa có số**, kể cả trong chính hồ sơ thầu. | `00-project-brief.md` mục 6 · `e-commerce/bid/estimate.computed.json` `cost` (Draft, chưa PO xác nhận) | **Chưa xác định cứng/mềm** — không có ngân sách nào được PO duyệt để đối chiếu | Không thể chấm điểm `TCO` (Bước 5, ngoài phạm vi lượt này) một cách có ý nghĩa cho tới khi có số ngân sách thật — xem `OQ-005` | +| `CON-02` | Thời gian | Không có deadline hợp đồng/pháp lý bên ngoài được xác nhận (`bid-config.projectDeadline`/`submissionDeadline` rỗng; `estimate.computed.json` → `timeline.deadlineFit.fits = null`). **Hai con số tham khảo KHÔNG khớp nhau:** brief giả định định tính "~9-12 tháng" (mục 5, giả định cuối) vs hồ sơ thầu tính toán "7 tháng thực hiện" (`timeline.durationMonths=7`, teamSize trung bình 9, đỉnh điểm 10 người) + 12 tháng bảo hành sau đó (`bid-config.warrantyMonths=12`). | `00-project-brief.md` mục 5, giả định #7 · `e-commerce/bid/estimate.computed.json` `timeline` · `e-commerce/bid/30-implementation-plan.md` §B7.1, §B7.5 | Mềm (chưa có ràng buộc cứng nào được xác nhận bằng văn bản) | `OPT` Bước 4 (ngoài phạm vi lượt này) phải trình ≥2 kịch bản thời gian (7 tháng "đẩy nhanh" theo bid vs 9-12 tháng "chuẩn" theo brief) thay vì giả định một mốc duy nhất — xem `OQ-006` | +| `CON-03` | Công nghệ | Cloud **AWS bắt buộc** — đã xác nhận tại vòng 3 Q&A của brief, không phải sở thích của kiến trúc sư | `00-project-brief.md` mục 5 (Q&A vòng 3: "cloud AWS") · `docs/sections/01-tong-quan.md` §1.5 | **Cứng** | Loại mọi phương án dùng cloud khác/on-prem ngay từ Bước 4 (`OPT`) | +| `CON-04` | Công nghệ | Đối tác thanh toán **VNPay + Momo + COD**, đối tác vận chuyển **GHN + GHTK** đã xác nhận làm mặc định tích hợp (không phải "chờ chọn tuỳ ý") — nhưng dự án **chưa có tài liệu API/tài khoản sandbox thật** với bất kỳ đối tác nào trong bốn đối tác này | `00-project-brief.md` mục 1 vòng 1 & mục 4 vòng 1 | Cứng (danh tính đối tác đã chốt) / Mềm (thời điểm có sandbox/hợp đồng thật — phụ thuộc bên ngoài) | Thiết kế tích hợp (`ICD`, GĐ2) phải giả định theo tài liệu công khai của 4 đối tác này cho tới khi có sandbox thật xác nhận (kế thừa `ASM-01`/`ASM-02` của BA ở `RISK_CartCheckout_v1.0.md` §1, §3) | +| `CON-05` | Con người | Số đội/số người/kỹ năng team thi công + đội vận hành sau go-live **CHƯA được PM/Tech Lead xác nhận số thật** — hiện dùng giả định tạm "team MVP chuẩn" theo `DEC-02` (SA, 🔴). Tham khảo duy nhất: hồ sơ thầu ước lượng teamSize trung bình **9 vị trí đồng thời**, đỉnh điểm **10 đầu người**, 8 vai trò (PM/BA/SA/UIUX/BE/FE/QA/DEVOPS) — đây là cách tổ chức nhân sự **do nhà thầu đề xuất cho hồ sơ thầu của chính họ**, không phải đội hình mà PO/chủ dự án đã cam kết tuyển/thuê nội bộ; toàn bộ tên/CV nhân sự trong hồ sơ thầu vẫn là `[[CẦN ĐIỀN]]` | `DEC-02` (SA) · `e-commerce/bid/30-implementation-plan.md` §B8.2 (tên/CV `[[CẦN ĐIỀN]]`), §B8.3 (đơn vị FTE, không phải cam kết nhân sự) | Chưa xác định — chỉ là số liệu tham khảo, không có giá trị ràng buộc | Ranh giới service ở `SAD` (GĐ2) không nên chốt cứng theo số liệu này cho tới khi có số team thật — xem `OQ-002` (mở từ v1.0) và `OQ-008` (mới, riêng phần đội vận hành sau go-live) | +| `CON-06` | Pháp lý | Bắt buộc tuân thủ: **NĐ52/2013 + NĐ85/2021** (thông báo website TMĐT dạng sàn giao dịch với Bộ Công Thương), **NĐ13/2023** (bảo vệ dữ liệu cá nhân — cả PII khách hàng lẫn giấy tờ KYC seller), **PCI-DSS phạm vi thu hẹp** (SAQ A — không lưu thông tin thẻ, giao VNPay/Momo xử lý, cô lập trong một Payment Service duy nhất theo `SAD.md` §3.1) | `docs/sections/01-tong-quan.md` §1.5 · `docs/sections/02-phan-tich-yeu-cau.md` NFR-05 · `SAD.md` §3.1, §8 (§8.4 pentest/ASV cho SAQ A) | **Cứng** (pháp luật, không thương lượng được) | Payment Service phải là biên cô lập duy nhất chạm dữ liệu thẻ (đã phản ánh trong `SAD.md`, GĐ2 SA kế thừa nguyên trạng, không thiết kế lại); mọi luồng chia sẻ địa chỉ/SĐT cho seller khi tách đơn phải qua rà soát Pháp chế trước go-live — **chưa có người rà soát** (kế thừa `RISK-03`/`OQ-003` của BA) | +| `CON-07` | Pháp lý | Hoá đơn điện tử cho seller **đã xác nhận hoãn sang phase 2** (không thuộc MVP) — đây là **quyết định kinh doanh đã chốt**, không phải khoảng trống thông tin | `00-project-brief.md` mục 2, dòng "Hoá đơn điện tử cho seller — hoãn sang giai đoạn sau, đã xác nhận (vòng 3)" | Cứng (phạm vi đã chốt cho MVP) | Không thiết kế module hoá đơn điện tử ở GĐ2 MVP; ghi vào §6 "Ngoài phạm vi" và để cho `TRM` (GĐ4) khi có phase sau — xem `ASM-06` | +| `CON-08` | Tổ chức/Vận hành | Đội vận hành (Ops) trực theo ca giờ hành chính + escalation 24/7 cho sự cố nghiêm trọng (do doanh thu phụ thuộc hệ thống) — hiện là **giả định mặc định đã chốt trong brief**, CHƯA xác nhận đội ops là nội bộ PO hay thuê ngoài, quy mô bao nhiêu người | `00-project-brief.md` §5, giả định cuối ("Vận hành: … đội ops trực theo ca…") · `docs/sections/02-phan-tich-yeu-cau.md` NFR-08 | Mềm (giả định, chưa xác nhận thật) | Thiết kế on-call/`INF` ở GĐ2 phải giả định một mô hình vận hành cụ thể cho tới khi có xác nhận thật — xem `OQ-008` | +| `CON-09` | Tổ chức/Vận hành | Bảo hành 12 tháng sau nghiệm thu tổng thể (`bid-config.warrantyMonths=12`) là điều khoản **đề xuất của nhà thầu trong hồ sơ thầu**, chưa phải điều khoản hợp đồng đã ký; mô hình bàn giao vận hành lâu dài cho PO sau khi hết bảo hành (ai tiếp nhận, có chuyển giao kiến thức không) **chưa được mô tả ở đâu** | `e-commerce/bid/bid-config.md` (`warrantyMonths: 12`) · `e-commerce/bid/30-implementation-plan.md` §B7.2 Giai đoạn 7 | Mềm (đề xuất, chưa ký hợp đồng) | `AGD`/`DREV` ở GĐ3 (ngoài phạm vi lượt này) cần biết ai là đội vận hành lâu dài để viết guideline đúng đối tượng — ghi nhận sớm, không quyết thay PM/PO | + +**Cứng** = vi phạm thì dự án bị chặn (pháp luật, cloud bắt buộc). **Mềm** = đổi được nhưng tốn +tiền/thời gian — ở đây phần lớn còn ghi "Mềm/Chưa xác định" vì các nguồn duy nhất hiện có +(brief giả định, hồ sơ thầu ước lượng) chưa được PO/PM/Tech Lead xác nhận là ràng buộc thật. + +### 3.1 Nhóm ràng buộc chưa có thông tin (còn cần xác nhận thật) + +| Nhóm | Ai phải trả lời | Đã hỏi ngày | `OQ` | Chặn gì | +|---|---|---|---|---| +| Tiền (số ngân sách thật, không phải ước lượng thầu) | PO / tài chính | 2026-09-12 (qua tài liệu, chưa phải buổi hỏi trực tiếp) | `OQ-005` | `CON-01` (cứng/mềm), `TCO` Bước 5 | +| Thời gian (deadline thật, nếu có) | PO / PM | 2026-09-12 | `OQ-006` | `CON-02`, kịch bản thời gian ở `OPT` Bước 4 | +| Con người (đội vận hành sau go-live: nội bộ hay thuê ngoài, quy mô) | PM / SRE | 2026-09-12 | `OQ-008` | `CON-05`, `CON-08`, thiết kế `INF`/on-call GĐ2 | +| Pháp lý (đại diện Pháp chế/Bảo mật xác nhận yêu cầu residency theo NĐ13/2023) | Legal / Security | 2026-09-12 (kế thừa `OQ-003` của BA, vẫn chưa có người) | `OQ-007` | `CON-06`, `ASM-04`, ranh giới hạ tầng dữ liệu ở `DAT`/`INF` GĐ2 | + +## 4. Hiện trạng (AS-IS) + +*Bước 3 của `sa-1-context`, chạy ở lượt này (hoạt động `as-is`). Dự án e-commerce là +**greenfield** — không có hệ thống/dữ liệu cũ để khảo sát trực tiếp theo bốn mục +`GUIDE.md` (hệ thống/dữ liệu/tích hợp/vận hành). Theo `SKILL.md` §Bước 3 và +`artifact-map.md` §7 (loại LIFECYCLE=greenfield ⇒ rút gọn CTX phần as-is), "hiện trạng" ở đây +gồm bốn phần: (a) khẳng định greenfield + hệ quả, (b) hệ sinh thái bên ngoài bắt buộc tích hợp +(đây là "as-is" thật duy nhất của một dự án greenfield — các đối tác đã tồn tại và có ràng buộc +kỹ thuật/pháp lý riêng của họ), (c) tài sản thiết kế nội bộ đã có (`SAD.md`/hồ sơ thầu), (d) +kỹ năng/tài sản tổ chức đã biết.* + +### 4.1 Khẳng định greenfield và hệ quả + +**Khẳng định:** Dự án e-commerce là hệ thống **mới hoàn toàn** — không có hệ thống, cơ sở dữ +liệu, hay quy trình thủ công nào đang chạy để thay thế/tích hợp cho lõi giao dịch (giỏ hàng → +checkout → thanh toán → tách đơn theo seller → vận chuyển → hoa hồng/payout). Nguồn: +`PROFILE_e-commerce.md` (`LIFECYCLE: greenfield`, PO chốt 2026-09-08) · `PROCESS_CartCheckout_v1.0.md` +§0 ("dự án là marketplace hoàn toàn mới, không có hệ thống hay quy trình thủ công… không có hệ +thống cũ (ERP/kho/CRM) cần tích hợp hoặc migrate cho luồng giỏ hàng/checkout"). + +| # | Hệ quả của greenfield | Diễn giải cho GĐ1/GĐ2 SA | Nguồn | +|---|---|---|---| +| 1 | **Không có dữ liệu để migrate** | `OPT` (Bước 4) không cần kịch bản migration/rollback dữ liệu cũ, khác dự án loại 3 (migration) theo `SKILL.md` Bước 0.2; `DAT` ở GĐ2 thiết kế mô hình dữ liệu từ đầu, không cần ánh xạ từ schema cũ | `PROFILE_e-commerce.md`; `workflow.md §5` (bảng phân loại dự án) | +| 2 | **Không có baseline tải/KPI đo được thật** | Mọi con số trong `DRV-02` (tỷ lệ bỏ giỏ ≤ baseline 1-seller + 10 điểm %), `DRV-04` (đỉnh "hàng nghìn–chục nghìn concurrent user"), `DRV-05` (uptime 99.9%) là **mục tiêu/giả định đã chốt trong brief**, KHÔNG phải số đo từ hệ thống đang chạy — xác nhận lại điều đã ghi ở các dòng `DRV` tương ứng (§2), không đổi nội dung `DRV` | `BRIEF_CartCheckout` §4 GOAL-01; `docs/sections/02-phan-tich-yeu-cau.md` NFR-02/03; `00-project-brief.md` §5 giả định #6 | +| 3 | **Không có nợ kỹ thuật/hệ thống legacy** | GĐ2 (`SAD`/`ADR`) không cần rà soát tương thích ngược hay "strangler pattern"; toàn bộ ranh giới service trong `SAD.md` §3.1 có thể thiết kế theo domain lý tưởng, không bị ràng buộc bởi cấu trúc code cũ | `SAD.md` §3.1 | +| 4 | **Không có người dùng/seller thật đang hoạt động cần continuity** | Không cần chiến lược cutover zero-downtime từ hệ thống cũ sang mới khi go-live; rủi ro go-live là "ra mắt lần đầu" (chưa từng có traffic thật để so sánh), không phải "chuyển đổi không được gián đoạn" | `PROFILE_e-commerce.md`; `PROCESS_CartCheckout_v1.0.md` §0 | + +🔴 **Hệ quả ngược nếu khẳng định greenfield sai** (VD phát hiện có một hệ thống nội bộ cũ dùng +tạm cho vận hành thủ công mà brief chưa nhắc tới): phải chạy lại Bước 3 đầy đủ theo bốn mục +`GUIDE.md` (hệ thống/dữ liệu/tích hợp/vận hành cũ), và `DRV-01` (blocker MVP) có thể phải viết +lại vì đã có một phần luồng đang chạy thủ công — chưa có dấu hiệu này trong mọi tài liệu đã đọc. + +### 4.2 Hệ sinh thái bên ngoài phải tích hợp — trạng thái từng đối tác + +*Đây là "hiện trạng" thật của một dự án greenfield: các đối tác này đã tồn tại độc lập với dự +án, có ràng buộc kỹ thuật/hợp đồng riêng của họ mà SA phải khảo sát trước khi thiết kế `ICD` +(GĐ2). Cột "Trạng thái sẵn sàng" đối chiếu với `CON-04` (§3) — dự án **chưa có** tài liệu API +sandbox/tài khoản thật với bất kỳ đối tác nào dưới đây.* + +| Đối tác | Vai trò trong luồng nghiệp vụ | Giao thức đề xuất (`SAD.md` §3.4) | Trạng thái sẵn sàng thật (khảo sát) | Nguồn | +|---|---|---|---|---| +| **VNPay** | Cổng thanh toán online (redirect + IPN callback xác nhận giao dịch), không lưu thẻ | REST/HTTPS, timeout 10s, retry callback idempotent ≤3 lần | 🔴 Chưa có tài khoản sandbox/hợp đồng — thiết kế timeout/retry ở `SAD.md` §3.4 là **đề xuất chưa xác minh với sandbox thật** (kế thừa `ASM-01`/`ASM-02` của BA, `DRV-08`) | `SAD.md` §3.4; `CON-04`; `RISK_CartCheckout` ASM-01 | +| **Momo** | Cổng thanh toán online (redirect + IPN), không lưu thẻ | REST/HTTPS, timeout 10s, retry callback idempotent ≤3 lần | 🔴 Chưa có tài khoản sandbox/hợp đồng — tương tự VNPay | `SAD.md` §3.4; `CON-04` | +| **COD** | Thu tiền mặt khi giao — không phải API bên ngoài, là luồng nghiệp vụ nội bộ xác nhận qua đơn vị vận chuyển | Không áp dụng (không phải tích hợp API) | 🟢 Không phụ thuộc đối tác công nghệ — phụ thuộc quy trình xác nhận thủ công của GHN/GHTK/Ops | `SAD.md` §3.4 | +| **GHN** | Vận chuyển: tạo vận đơn, tra cứu trạng thái, webhook cập nhật | REST/HTTPS, timeout 8s, retry ≤3 lần, webhook idempotent | 🔴 Chưa có tài liệu API/sandbox thật — `SAD.md` §3.4 đề xuất fallback chéo sang GHTK khi GHN lỗi, **chưa kiểm chứng** khả năng fallback này có hoạt động đúng giữa hai API khác nhau trong thực tế | `SAD.md` §3.4; `CON-04` | +| **GHTK** | Vận chuyển (tương tự GHN), fallback chéo cho GHN | REST/HTTPS, timeout 8s, retry ≤3 lần | 🔴 Chưa có tài liệu API/sandbox thật — tương tự GHN | `SAD.md` §3.4; `CON-04` | +| **Email/SMS Provider** | Thông báo đơn hàng/giao hàng, nội dung đa ngôn ngữ | REST/HTTPS hoặc SDK qua queue, timeout 5s, retry ≤5 lần backoff | 🔴🔴 **Nhà cung cấp cụ thể CHƯA CHỐT** (SAD.md §3.4 tự ghi "đề xuất: SES/SNS hoặc SendGrid/Twilio — nhà cung cấp cụ thể chưa chốt, xem giả định") — mức độ chưa sẵn sàng cao hơn VNPay/Momo/GHN/GHTK vì còn chưa chọn đối tác, chưa dừng ở "chưa có sandbox" | `SAD.md` §3.4 | +| **Ngân hàng (payout)** | Chuyển khoản hoa hồng/payout hàng tuần cho seller | Batch file chuẩn ngân hàng (VD NAPAS) hoặc API — *ngân hàng cụ thể chưa chốt* | 🔴🔴 Chưa chọn ngân hàng đối tác, chưa có định dạng batch xác nhận | `SAD.md` §3.4 | +| **Google/Facebook OAuth** | Đăng nhập mạng xã hội (Should, không chặn MVP vì email/password vẫn hoạt động độc lập) | OAuth 2.0/OIDC redirect flow, timeout 10s | 🟡 Chuẩn mở, không cần hợp đồng riêng như các đối tác thương mại ở trên, nhưng vẫn chưa có app/client ID thật được đăng ký | `SAD.md` §3.4 | +| **Hoá đơn điện tử cho seller** | Xuất hoá đơn điện tử tự động khi seller phát sinh doanh thu | *(không thiết kế ở MVP)* | ⏸️ **Hoãn sang phase 2 — đã xác nhận (vòng 3 brief), không phải khoảng trống thông tin.** Không phải rủi ro tích hợp of MVP; ghi nhận cho `TRM` (GĐ4) khi có phase sau | `00-project-brief.md` dòng "Ngoài phạm vi MVP… hoá đơn điện tử tự động cho seller"; `CON-07` | + +**Đọc bảng:** 🔴 = chưa sandbox/hợp đồng thật nhưng đối tác đã xác định danh tính (kế thừa từ +Bước 1/2). 🔴🔴 = chưa cả chọn đối tác cụ thể (mức chưa sẵn sàng cao hơn). 🟡 = chuẩn mở, ít rủi +ro hơn. 🟢 = không phụ thuộc đối tác công nghệ bên ngoài. ⏸️ = ngoài phạm vi MVP theo quyết định +kinh doanh đã chốt, không phải rủi ro. + +Hệ quả cho GĐ2: `ICD` không thể chốt contract thật (owner, SLA, mã lỗi cụ thể) cho VNPay/Momo/ +GHN/GHTK/Email-SMS cho tới khi có tài liệu/sandbox thật — GĐ2 sẽ phải thiết kế theo tài liệu +công khai của đối tác và đánh dấu `Confidence` 🔴 cho các `IF-nnn` tương ứng, kế thừa `ASM-01` +(BA) và `CON-04` (SA). + +### 4.3 Tài sản thiết kế nội bộ đã có + +Dự án **không** ở tình trạng "trắng hoàn toàn" về mặt thiết kế — đã có hai tài sản tham khảo: + +| Tài sản | Trạng thái ghi trong chính tài liệu | Bản chất thật — SA phải hiểu đúng | Dùng làm gì ở GĐ1 SA | +|---|---|---|---| +| `e-commerce/docs/SAD.md` v0.2 (toàn bộ 9 mục `docs/sections/01…09`) | `status: approved` ở mọi mục con và ở bản ráp tổng thể (§0.2/§0.3 của `SAD.md`: "Product Owner/Kiến trúc sư trưởng đã phê duyệt") | Đây là **"approved" ở cấp phê duyệt nội bộ bản vẽ** (PO/Kiến trúc sư trưởng ký trên giấy khi làm hồ sơ), **KHÔNG phải kiến trúc đang chạy production**, không phải nghiệm thu vận hành, và không đi qua gate `AG1`/`AG2` của chính bộ `sa-*` này (được viết trước khi có pipeline `sa-lifecycle`) | Theo trả lời **`OQ-009` (đã đóng, xem `DEC-04`)**: dùng làm **điểm khởi đầu tham khảo** (baseline candidate) cho một trong các phương án ở Bước 4 (`OPT`) — KHÔNG mặc định là phương án thắng sẵn; Bước 4 vẫn phải dựng ≥1 phương án độc lập khác để so sánh thật (tránh bẫy "một phương án đã thắng sẵn", `GUIDE.md` "Bẫy thường gặp") | +| `e-commerce/bid/` (`bid-config.md`, `30-implementation-plan.md`, `estimate.computed.json`) | `status: draft`, `cost.priceComplete: false` — tự ghi rõ là ước lượng dự thầu, chưa hợp đồng | Ước lượng của **nhà thầu** cho mục đích đấu thầu (nhân công, timeline, đội hình đề xuất) — khác mục đích với `TCO` (ước lượng vận hành 3 năm theo phương án kiến trúc SA chọn) đã ghi ở §6 "Ngoài phạm vi" | Tham khảo duy nhất hiện có cho `CON-01`/`CON-02`/`CON-05` (đã ghi ở §3) — không dùng làm số `TCO` thật ở Bước 5 | + +🔴 **Ranh giới thẩm quyền quan trọng:** "approved" trong `SAD.md` là do PO/Kiến trúc sư trưởng +**nội bộ nhà thầu** ký trong quá trình chuẩn bị hồ sơ — không phải PO thật của dự án chạy thử +này ký qua pipeline `sa-*`. Coi `SAD.md` là "đã chốt, không được đổi" là hiểu sai bản chất và vi +phạm chính Bước 4 của `SKILL.md` (nguy cơ "một phương án duy nhất" — mục "Bẫy thường gặp"). + +**Quyết định đóng `OQ-009`:** xem `DEC-04` (SA) — chấp nhận dùng `SAD.md`/hồ sơ thầu làm điểm +khởi đầu tham khảo cho `OPT`, với điều kiện Bước 4 vẫn phải dựng và chấm điểm ≥1 phương án độc +lập khác theo đúng quy trình bắt buộc của `SKILL.md` Bước 4. + +### 4.4 Kỹ năng/tài sản tổ chức đã biết + +| Tài sản/ràng buộc tổ chức | Trạng thái | Hệ quả cho `OPT`/GĐ2 | Nguồn | +|---|---|---|---| +| **AWS bắt buộc** | Cứng, đã xác nhận vòng 3 Q&A brief (không phải sở thích SA) | Loại mọi phương án cloud khác/on-prem ngay từ Bước 4; mọi dịch vụ managed đề xuất trong `SAD.md`/`docs/sections/09` (ECS Fargate/EKS, RDS, ElastiCache, MSK, OpenSearch, CloudFront, WAF, Secrets Manager, PagerDuty/OpsGenie tích hợp qua AWS) đều khả thi về mặt nền tảng — chưa khả thi về ngân sách (`OQ-005`) | `CON-03`; `00-project-brief.md` mục 5 | +| **Team thi công + vận hành** | Chưa có số thật — dùng giả định tạm "team MVP chuẩn" theo `DEC-02` (🔴); tham khảo duy nhất là đội hình đề xuất của nhà thầu (9 vị trí TB, đỉnh 10, 8 vai trò) | Ranh giới ~10 service trong `SAD.md` §3.1 (mỗi service 3–6 kỹ sư theo mô tả §3.1) **chưa được đối chiếu** với số người thật của team dự án chạy thử này — rủi ro Conway nếu team thật nhỏ hơn nhiều | `CON-05`; `DEC-02`; `SAD.md` §3.1; `OQ-002`, `OQ-008` (còn mở) | +| **Pipeline CI/CD, bảo mật vận hành đề xuất** | `docs/sections/09-van-hanh-kiem-thu.md` đề xuất: OIDC federation (CI ↔ AWS IAM), AWS Secrets Manager cho toàn bộ secret/API key đối tác, CloudWatch Logs + X-Ray/OpenTelemetry, PagerDuty/OpsGenie cho on-call | Tài liệu tự ghi rõ đây là **"đề xuất minh hoạ theo best practice AWS — không phải ràng buộc bắt buộc từ brief"** (brief không chỉ định công cụ cụ thể) — không coi là `CON`, chỉ là năng lực/công cụ tham khảo có sẵn trong thiết kế đề xuất | `docs/sections/09-van-hanh-kiem-thu.md` §9.3, ghi chú cuối | +| **RTO/RPO đề xuất** | Kế thừa từ `SAD.md` §5.3.2, nhắc lại nguyên trạng ở §9.5.2 — tự ghi rõ "là **giả định** đã chốt (brief không có SLA hợp đồng cụ thể)" | Chưa phải ràng buộc cứng đã xác nhận bởi PO/SRE thật — dùng tham khảo cho `INF`/`ARISK` ở các bước sau, không coi là số đã chốt | `SAD.md` §5.3.2, §9.5.2 | +| **Đội vận hành (Ops/SRE) sau go-live** | Chưa xác nhận nội bộ hay thuê ngoài, quy mô bao nhiêu người | Chặn thiết kế on-call/`INF` thật ở GĐ2 | `CON-08`; `OQ-008` (còn mở) | + +Không có bằng chứng về năng lực/kinh nghiệm thật của tổ chức với các công nghệ cụ thể (Kafka/MSK, +OpenSearch, Kubernetes/EKS) ngoài việc chúng được đề xuất trong `SAD.md` — đây là khoảng trống +cho `ARISK` (nguồn rủi ro "Con người": *"có ai trong team từng chạy production cái này chưa?"*) +sẽ được lập ở Bước 5 (ngoài phạm vi lượt chạy này). + +## 5. Giả định — `ASM-nn` + +*Giả định cấp `CTX` (kiến trúc), sinh ra khi rà §3 Ràng buộc. Không copy `ASM-01…06` của BA ở +`RISK_CartCheckout_v1.0.md` §1 — chỉ tham chiếu bằng ID, theo `artifact-map.md §7`. Đánh số +độc lập, bắt đầu từ `ASM-01` cho sổ của `CTX`.* + +| ID | Giả định | Cách xác minh | Hệ quả nếu sai | Chủ | Hạn | +|---|---|---|---|---|---| +| `ASM-01` | Con số lao động trong hồ sơ thầu (≈3,76 tỷ VND đã VAT, 53,02 người-tháng) nằm "trong khoảng hợp lý" mà PO có thể chấp nhận — dùng làm điểm neo tạm cho `CON-01`, KHÔNG phải ngân sách đã duyệt | PO/tài chính xác nhận bằng văn bản: ngân sách hạ tầng/tháng đã duyệt + chi phí một lần cho phép | Nếu ngân sách thật thấp hơn nhiều: `OPT` Bước 4 phải loại các phương án kiến trúc nặng (Kafka/MSK, RDS Multi-AZ đầy đủ, OpenSearch cluster đa node đề xuất trong `SAD.md`) và chuyển hướng phương án rẻ hơn ngay từ đầu, tránh thiết kế xong mới phát hiện không đủ tiền vận hành | PO | Trước khi chạy Bước 4 (`OPT`) | +| `ASM-02` | Không có mốc thời gian bên ngoài (hợp đồng/pháp lý/mùa vụ) ép buộc ngày ra mắt — deadline chỉ là "lộ trình MVP tiêu chuẩn" mang tính tham khảo, không phải cam kết cứng | PM/PO xác nhận `projectStartDate`/`projectDeadline` thật (hiện `[[CẦN ĐIỀN]]`/rỗng trong `bid-config.md`) | Nếu có deadline ngắn hơn 7 tháng ép buộc bởi bên ngoài (VD phải kịp mùa sale cụ thể): phải đánh đổi phạm vi MVP hoặc tăng song song hoá đội ngũ (rủi ro tăng chi phí phối hợp, theo chính `30-implementation-plan.md` §B7.5) | PM | Trước khi chạy Bước 4 (`OPT`) | +| `ASM-03` | Đội vận hành sau go-live sẽ là một đội SRE/Ops (nội bộ hoặc thuê ngoài) trực theo ca hành chính + escalation 24/7 — kế thừa giả định "team MVP chuẩn" của `DEC-02` (🔴), CHƯA có số người/kỹ năng thật | PM/SRE xác nhận số người, kỹ năng, ai trực, mô hình on-call cụ thể | Nếu team vận hành thực tế rất nhỏ hoặc chưa tồn tại: ranh giới ~10 service theo `SAD.md` §3.1 có thể vi phạm Conway (đội quá nhỏ để vận hành nhiều service độc lập), phải gộp bớt ranh giới ở `OPT` Bước 4/GĐ2 | PM/SRE | Trước khi chốt ranh giới service ở GĐ2 | +| `ASM-04` | Vùng cloud AWS hiện dùng trong `SAD.md` (ap-southeast-1 + region dự phòng cross-region) đáp ứng đủ yêu cầu residency của NĐ13/2023 cho dữ liệu cá nhân khách hàng + seller — NĐ13/2023 không tuyệt đối bắt buộc lưu trữ trong lãnh thổ VN cho mọi loại PII, nhưng giả định này **chưa được đại diện Pháp chế xác nhận** cho đúng mô hình marketplace hai loại chủ thể của dự án này | Đại diện Pháp chế/Bảo mật (chưa được chỉ định — kế thừa `OQ-003` của BA) xác nhận yêu cầu residency cụ thể | Nếu sai (bắt buộc lưu trong lãnh thổ VN cho một số loại dữ liệu): phải chuyển hạ tầng dữ liệu liên quan về region VN hoặc dùng nhà cung cấp trong nước, ảnh hưởng trực tiếp `CON-03`/`CON-06` và `TCO` | Legal/Security (chưa có người — `OQ-007`) | Trước GĐ2 (`DAT`/`INF`), chậm nhất trước go-live | +| `ASM-05` | Kiến trúc/stack cụ thể mô tả sẵn trong `SAD.md`/hồ sơ thầu (modular "microservices" theo bounded-context ~10 service, Kafka/MSK, RDS PostgreSQL Multi-AZ database-per-service, Redis, OpenSearch, CDN) là **đề xuất của SA/nhà thầu**, có thể dùng làm điểm khởi đầu tham khảo cho Bước 4 (`OPT`) của chính GĐ1 SA này, nhưng KHÔNG coi là đã được khách hàng/PO chốt cứng | Tech Lead + PO xác nhận: chấp nhận `SAD.md` làm baseline cho `OPT`, hay yêu cầu SA dựng phương án độc lập không neo theo tài liệu có sẵn (tránh bẫy "một phương án duy nhất" đã thắng sẵn — xem `GUIDE.md` "Bẫy thường gặp") | Nếu sai (không được neo theo `SAD.md`): Bước 4 phải dựng ≥2 phương án hoàn toàn độc lập, tốn thêm thời gian nhưng giảm rủi ro "chấm điểm để hợp thức hoá lựa chọn đã có" | Tech Lead + PO | Trước khi bắt đầu Bước 4 (`OPT`) | +| `ASM-06` | Quyết định "hoá đơn điện tử cho seller hoãn phase 2" (đã xác nhận vòng 3 brief) vẫn còn hiệu lực tại thời điểm `CTX` này — không có phản hồi trái ngược mới từ PO | PO xác nhận lại nếu có yêu cầu pháp lý mới bắt buộc hoá đơn điện tử sớm hơn (VD thay đổi quy định về hoá đơn điện tử cho sàn TMĐT) | Nếu sai: phải bổ sung `CON` pháp lý mới và mở rộng phạm vi MVP, ảnh hưởng cả `OPT`/`TCO`/lịch trình đã ước lượng trong hồ sơ thầu | PO | Trước khi chốt `OPT` Bước 4 | + +Giả định sai mà hệ quả lớn ⇒ nâng thành `ARISK` và xác minh ngay trong GĐ1. `ASM-01`, `ASM-03`, +`ASM-04` có hệ quả đủ lớn (ảnh hưởng trực tiếp phạm vi/kiến trúc) — ứng viên rõ nhất để nâng +thành `ARISK-nn` khi Bước 5 (`ARISK`) chạy ở lượt sau. + +## 6. Ngoài phạm vi + +*Những thứ người đọc có thể tưởng tài liệu này đã có, nhưng chưa có ở lượt chạy này:* + +- Khảo sát hiện trạng **kỹ thuật sâu hơn** cho các đối tác tích hợp (gọi thử sandbox thật, đọc + toàn bộ tài liệu API chi tiết của VNPay/Momo/GHN/GHTK) — §4.2 mới dừng ở mức "biết đối tác nào, + trạng thái sẵn sàng ở đâu" từ tài liệu sẵn có, chưa phải khảo sát kỹ thuật trực tiếp (gọi API + thử, đọc rate limit thật) theo đúng nghĩa `GUIDE.md` Bước 3 "Tích hợp — gọi thử nếu được". +- `OPT` (phương án + chấm điểm), `TCO` (chi phí 3 năm), `ARISK` (rủi ro kiến trúc + POC) — + chưa chạy Bước 4–5. Không thể chạy các bước này một cách có ý nghĩa cho tới khi các `OQ-005` + (ngân sách), `OQ-006` (deadline), `OQ-008` (team vận hành) được trả lời bằng số thật — chấm + điểm phương án chỉ dựa trên ước lượng hồ sơ thầu (`CON-01`, `CON-02`, `CON-05` đều "Chưa xác + định/Mềm") là chấm bừa. +- Driver của các module ngoài Giỏ hàng & Checkout (`DRV-04,05,06,09`) mới ở mức suy từ `SAD.md`, + **chưa** được xác nhận qua một vòng elicitation/BRIEF module hoá riêng như module Giỏ hàng & + Checkout — không nên coi các dòng này có độ tin cậy ngang với `DRV-01,02,03,07,08`. +- Hoá đơn/mức giá cụ thể trong `e-commerce/bid/` (rateCard, VAT, các khoản non-labor còn + `amount: null`) **không phải** là `TCO` của GĐ1 SA — đây là ước lượng dự thầu cho một hợp + đồng, khác mục đích với `TCO` (ước lượng vận hành 3 năm theo phương án kiến trúc đã chọn). + SA sẽ tự tính `TCO` riêng ở Bước 5, có thể tham khảo nhưng không sao chép con số thầu. +- Số liệu cứng/mềm ở `CON-01`, `CON-02`, `CON-05` mới là **đánh giá của SA dựa trên tài liệu + hiện có**, chưa phải xác nhận từ PO/PM/Tech Lead thật — không nên coi các dòng này đã "chốt". + +## 7. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược | +|---|---|---|---|---|---| +| `OQ-001` | BA chưa ký G1 chính thức cho `BRIEF_CartCheckout` (`OQ-001`/`OQ-007` của BA còn mở: tên thật stakeholder, baseline KPI). Xác nhận: có chấp nhận để `DRV-01,02,03,07,08` giữ Confidence 🔴 và tiếp tục sang Bước 2–5 của GĐ1 SA, hay dừng chờ BA ký G1 thật? | PO sàn (điều phối) + BA | 2026-09-12 | Nâng `Confidence` của toàn bộ `CTX`/`DRV` lên 🟡/🟢; ký AG1 thật (cần PO + Tech Lead, nhưng PO không nên ký trên driver còn 🔴 nếu tránh được) | Nếu PO/BA sau này đổi phát biểu bài toán ở `BRIEF §3` (VD: bỏ yêu cầu guest checkout, hoặc đổi mô hình tách đơn) ⇒ phải viết lại `DRV-01,02` và rà lại mọi `ADR` GĐ2 tham chiếu tới chúng | +| `OQ-002` | Ràng buộc "Con người" (số đội, số người, kỹ năng, ai vận hành sau go-live) hoàn toàn chưa có thông tin — cần thiết để biến định hướng "kiến trúc module hoá độc lập theo nhóm" (NFR-07, §2.1) thành một `DRV`/`CON` có số liệu, thay vì chỉ là câu mô tả chung chung. | PM / Tech Lead | 2026-09-12 | Bước 2 (`CON` nhóm Con người); ranh giới service khả thi (Conway) ở GĐ2 | Nếu team thực tế rất nhỏ (VD 5 người) mà kiến trúc GĐ2 chia 8+ service theo domain (catalog/order/seller/payment/commission/loyalty/notification/CSKH) ⇒ vi phạm Conway, chậm release hơn cả kiến trúc gộp module | +| `OQ-003` | Người dùng (điều phối) đã chọn phạm vi **Toàn sàn** cho GĐ1 SA dù được cảnh báo driver ngoài module Giỏ hàng & Checkout (`DRV-04,05,06,09`) chỉ có nguồn `SAD.md`, chưa qua BRIEF/RISK/STAKEHOLDER module hoá riêng như module Giỏ hàng & Checkout. Xác nhận: giữ nguyên phạm vi toàn sàn cho các bước 2–5 tiếp theo, hay thu hẹp về Giỏ hàng & Checkout để có Confidence cao hơn trước? | PO sàn + Tech Lead | 2026-09-12 | Khối lượng và độ tin cậy của `OPT`/`TCO`/`ARISK` ở các bước kế tiếp | Nếu giữ toàn sàn mà không bổ sung BRIEF module hoá cho Catalog/Seller/Commission/Loyalty, `OPT` GĐ1 SA sẽ phải chấm điểm phương án dựa trên driver suy diễn (không phải driver đã xác nhận) — rủi ro chọn sai phương án kiến trúc cho các module đó, phát hiện muộn ở GĐ2/GĐ3 | +| `OQ-004` | Xác nhận ngoại lệ gate `DEC-01` (SA): chạy GĐ1 SA (Driver) khi BA chưa qua G1 — có đúng là quyết định của người có thẩm quyền điều phối dự án chạy thử, hay cần PO sàn thật xác nhận lại bằng văn bản riêng? | PO sàn (người thật, không phải vai trò) | 2026-09-12 | Tính hợp lệ của toàn bộ `CTX` này khi trình AG1 | Nếu PO thật sau này không công nhận ngoại lệ này, toàn bộ `CTX`/`DRV` phải làm lại sau khi BA ký G1 — chi phí làm lại phần Driver ước < 1 tuần (ít, vì đã có khung sẵn) | +| `OQ-005` | Ngân sách hạ tầng/tháng và chi phí một lần đã duyệt cho dự án là bao nhiêu? Nguồn tham khảo duy nhất hiện có (`e-commerce/bid/estimate.computed.json`) là ước lượng dự thầu, **chưa hợp đồng**: lao động ≈3,76 tỷ VND đã VAT cho 53,02 người-tháng; 8 khoản chi phí không lao động (hạ tầng AWS, OpenSearch, phí VNPay/Momo, phí GHN/GHTK, Email/SMS, domain/SSL/WAF, pentest, đào tạo) đều chưa có số. **Câu trả lời tạm (2026-09-12, ghi tại §4.3):** chưa nhận được xác nhận số thật từ PO trong vòng chạy này — tạm dùng số hồ sơ thầu làm mốc tham khảo duy nhất, `Confidence` 🔴, `OQ-005` **giữ mở**. | PO / tài chính | 2026-09-12 | `CON-01` (cứng/mềm); `TCO` Bước 5; loại bớt phương án ở `OPT` Bước 4 | Nếu ngân sách thật thấp hơn đáng kể so với ước lượng thầu: phải loại các phương án kiến trúc nặng (Kafka/MSK, RDS Multi-AZ đầy đủ, OpenSearch đa node) ngay từ Bước 4, tránh thiết kế xong ở GĐ2 mới phát hiện không đủ tiền vận hành (tháng thứ 13 trở đi) | +| `OQ-006` | Deadline dự án chính thức là ngày nào (nếu có)? Hai con số tham khảo hiện KHÔNG khớp: brief nói "~9-12 tháng" (định tính), hồ sơ thầu tính "7 tháng thực hiện" (teamSize trung bình 9, đỉnh điểm 10 người) + 12 tháng bảo hành — cả hai đều CHƯA được PO xác nhận là mốc thật (`bid-config.projectDeadline` rỗng). **Câu trả lời tạm (2026-09-12, ghi tại §4.3):** chưa nhận được xác nhận mốc thật từ PO trong vòng chạy này — tạm giữ song song cả hai con số tham khảo (7 tháng thầu / 9–12 tháng brief), không chọn một, `Confidence` 🔴, `OQ-006` **giữ mở**. | PO / PM | 2026-09-12 | `CON-02`; kịch bản thời gian ở `OPT` Bước 4 | Nếu deadline thật ngắn hơn 7 tháng (do ràng buộc bên ngoài mới xuất hiện): phải cắt phạm vi MVP hoặc tăng song song hoá đội ngũ — theo chính hồ sơ thầu (§B7.5), đòn bẩy này làm tăng chi phí phối hợp và rủi ro tích hợp, không miễn phí | +| `OQ-007` | Ai là đại diện Pháp chế/Bảo mật xác nhận yêu cầu về nơi lưu trữ dữ liệu (residency) theo NĐ13/2023 cho mô hình marketplace có hai loại chủ thể dữ liệu (khách hàng + seller, gồm cả giấy tờ KYC)? *(kế thừa `OQ-003` của BA — vẫn chưa có người sau khi BA chạy GĐ1)* | PO sàn (chỉ định người) | 2026-09-12 | `CON-06`, `ASM-04`; ranh giới hạ tầng dữ liệu ở `DAT`/`INF` GĐ2 | Nếu về sau phát hiện bắt buộc lưu trữ trong lãnh thổ VN cho một số loại PII: phải chuyển hạ tầng dữ liệu liên quan (hoặc toàn bộ) về region VN/nhà cung cấp trong nước — phát hiện càng muộn (VD sau khi GĐ2 đã chốt `DAT`/`INF` theo `ap-southeast-1`) thì chi phí sửa càng cao, có thể phải viết lại `ADR` hạ tầng | +| `OQ-008` | Đội vận hành (Ops/SRE) sau go-live là nội bộ PO hay thuê ngoài, quy mô bao nhiêu người, có sẵn sàng trực 24/7 cho sự cố nghiêm trọng theo giả định NFR-08 hay chưa? | PM / SRE | 2026-09-12 | `CON-05`, `CON-08`; thiết kế on-call/`INF` ở GĐ2; ranh giới service (Conway) | Nếu chưa có đội ops sẵn sàng khi go-live: phải tính thêm chi phí thuê ngoài/tuyển dụng vào `TCO` Bước 5, và mục tiêu uptime 99.9% (`DRV-05`) có thể không đạt được trong thực tế dù kiến trúc đúng thiết kế | +| ~~`OQ-009`~~ | *(Đã đóng ở v1.2, xem "Open Question đã đóng" ngay dưới)* | — | — | — | — | + +### 7.1 Open Question đã đóng *(mới từ v1.2)* + +| ID | Câu hỏi | Trả lời | Ngày đóng | Người trả lời | Ghi chú | +|---|---|---|---|---|---| +| `OQ-009` | Có chấp nhận dùng kiến trúc/stack đã đề xuất sẵn trong `SAD.md`/hồ sơ thầu (modular microservices ~10 service, Kafka/MSK, RDS Multi-AZ, OpenSearch, Redis) làm điểm khởi đầu cho Bước 4 (`OPT`) của GĐ1 SA, hay yêu cầu SA dựng phương án hoàn toàn độc lập? | **Chấp nhận** dùng `SAD.md`/hồ sơ thầu làm **điểm khởi đầu tham khảo** cho một phương án ở Bước 4 — với điều kiện bắt buộc: Bước 4 vẫn phải dựng và chấm điểm ≥1 phương án độc lập khác theo đúng `SKILL.md` Bước 4, không mặc định `SAD.md` là phương án thắng sẵn. Xem §4.3, `DEC-04` (SA). | 2026-09-12 | Ghi chú người duyệt (đại diện PO/điều phối dự án) | `Confidence` của quyết định này: 🟡 (rõ ràng về điều kiện áp dụng, nhưng người duyệt là ghi chú điều phối, không phải PO/Tech Lead ký trực tiếp qua `sign`) | + +--- + +## Tự chấm + +### ① Bảng tự chấm Gate AG1 *(`workflow.md §2`)* + +| # | Tiêu chí | ☐/✅ | Ghi chú | +|---|---|---|---| +| 1 | `CTX` có `DRV-nn`, mỗi driver ghi rõ áp lực kinh doanh | ✅ | 9 `DRV` (`DRV-01…09`), mỗi dòng có áp lực định lượng (nơi có thể), nguồn, thuộc tính chất lượng bị ép. `DRV-04/05` dùng số mô tả định tính "lớn"/"99.9%" đã được chính nguồn (`00-project-brief`) gắn nhãn "giả định mặc định", không phải SA tự bịa | +| 2 | `CTX` có `CON-nn` (ràng buộc 6 nhóm) | ✅ *(với lưu ý)* | Đủ 6 nhóm (`CON-01` Tiền … `CON-09` Tổ chức/Vận hành, xem §3). Nhưng phần lớn giá trị "Cứng/Mềm" ghi "Chưa xác định" vì nguồn chỉ là ước lượng hồ sơ thầu (Draft, chưa hợp đồng) — chưa phải số PO đã duyệt. Đạt tiêu chí "có mặt và đủ 6 nhóm", chưa đạt mức "đã xác nhận thật" | +| 3 | `CTX` mô tả hiện trạng as-is: hệ thống, dữ liệu, tích hợp, hợp đồng vendor đang có | ✅ *(với lưu ý)* | §4 mới bổ sung ở v1.2: (a) khẳng định greenfield + hệ quả, (b) bảng trạng thái 9 đối tác tích hợp (VNPay/Momo/GHN/GHTK/Email-SMS/Ngân hàng/OAuth/hoá đơn điện tử), (c) tài sản thiết kế đã có (`SAD.md`/hồ sơ thầu, có ghi rõ ranh giới thẩm quyền), (d) kỹ năng/tài sản tổ chức. "Hệ thống/dữ liệu đang có" = None (greenfield, đã xác nhận nguồn `PROFILE_e-commerce.md`); "hợp đồng vendor đang có" = None (mọi đối tác đều 🔴/🔴🔴 chưa sandbox/hợp đồng thật) — đạt tiêu chí "mô tả hiện trạng", nội dung chính là "hiện trạng = chưa có gì tự vận hành, có đối tác bên ngoài chưa sẵn sàng" | +| 4 | `OPT` có ≥2 phương án, chấm điểm, nêu phương án bị loại | ☐ | **Chưa tạo file `OPT`** — thuộc Bước 4, ngoài phạm vi lượt chạy này; phụ thuộc `OQ-005`/`OQ-006` trả lời trước (đã có nền: `OQ-009` đóng ở §4.3/§7.1 cho phép dùng `SAD.md` làm điểm khởi đầu tham khảo) | +| 5 | `TCO` có chi phí 3 năm, ≥2 kịch bản tải | ☐ | **Chưa tạo file `TCO`** — thuộc Bước 5, ngoài phạm vi lượt chạy này | +| 6 | `ARISK` có rủi ro cao kèm chủ + biện pháp | ☐ | **Chưa tạo file `ARISK`** — thuộc Bước 5, ngoài phạm vi lượt chạy này. §4.2/§4.4 đã nêu sẵn một số ứng viên rủi ro (đối tác chưa sandbox, năng lực team chưa xác nhận với Kafka/MSK/OpenSearch/EKS) để Bước 5 kế thừa | +| 7 | Rủi ro cao chưa chứng minh được có kế hoạch POC | ☐ | Phụ thuộc `ARISK`, chưa làm | + +**Kết luận tự chấm AG1:** **Chưa đủ điều kiện ký** — đúng như phạm vi được giao (Driver + +Ràng buộc + Hiện trạng). 3/7 tiêu chí ✅. Cần chạy tiếp Bước 4–5 (`OPT`, `TCO`, `ARISK`) trước +khi PO + Tech Lead có thể ký AG1, và cần `OQ-005`/`OQ-006`/`OQ-007`/`OQ-008` được trả +lời bằng số/người thật trước khi Bước 4–5 có ý nghĩa (`OQ-009` đã đóng). Ngoài ra, ngay cả `DRV` và `CON` đang ở +`Confidence 🔴` vì lý do preflight (BA chưa ký G1) và vì `CON` dựa trên ước lượng hồ sơ thầu +chưa xác nhận — nên **không đủ điều kiện baseline `CTX`** dù đã điền đủ nội dung của mục Driver, +Ràng buộc và Hiện trạng. + +### ② Checklist D1–D12 *(`design-rules.md`)* + +| # | Mục | ☐/✅ | Ghi chú | +|---|---|---|---| +| D1 | Một ADR một quyết định | N/A | Tài liệu này không có `ADR` | +| D2 | Không NFR định tính; đủ 4 câu | 🟡 Một phần | Driver không phải `QAS` nên không bắt buộc đủ "4 câu", nhưng đã cố định lượng tối đa có thể (DRV-01,02,03,04,06,07,08 có con số/nguồn cụ thể); `DRV-05,09` còn dùng mô tả định tính do chính nguồn brief chỉ ghi ở mức đó — đã gắn nhãn rõ "giả định mặc định", không che giấu | +| D3 | Nêu phương án bị loại | N/A | `OPT` (nơi bắt buộc nêu phương án loại) chưa chạy ở lượt này; `CON-05` đã ghi rõ số liệu team hồ sơ thầu KHÔNG được coi là phương án đã chọn | +| D4 | Sơ đồ khai báo mức + legend | N/A | Không có sơ đồ mới thêm ở §3/§5 | +| D5 | Interface có chủ/contract | N/A | Chưa tới `ICD` (GĐ2); `CON-04`/§4.2 đã nêu đối tác tích hợp bắt buộc và trạng thái sẵn sàng nhưng chưa có contract thật | +| D6 | Phụ thuộc ngoài process có timeout/retry | N/A | Chưa tới `FAIL`/`SAD` (GĐ2); §4.2 kế thừa nguyên trạng timeout/retry **đề xuất** từ `SAD.md` §3.4 (VNPay/Momo 10s, GHN/GHTK 8s, Email/SMS 5s) — ghi rõ là đề xuất chưa kiểm chứng với sandbox thật, không phải ràng buộc SA tự đặt mới | +| D7 | Một chủ sở hữu dữ liệu | N/A | Chưa tới `DAT` (GĐ2) | +| 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 | 🟡 Một phần | `CON-01` có trích dẫn con số (≈3,76 tỷ VND đã VAT) kèm nguồn (`estimate.computed.json`), nhưng đây là số của hồ sơ thầu (nhân công + VAT), KHÔNG phải con số hạ tầng quy đổi kiến trúc — `TCO`/`INF` thật (nơi D9 áp dụng đầy đủ) chưa chạy. §4.3/§4.4 không thêm số hạ tầng mới, chỉ dẫn nguồn cho các bước sau | +| D10 | Không quyết định thay người có thẩm quyền | ✅ | Mọi chỗ chưa rõ (ngân sách, deadline, đội vận hành, residency pháp lý) đều ghi `OQ-005…008` kèm hệ quả phương án ngược bằng số/định tính rõ ràng, không tự quyết. `OQ-009` đã đóng nhưng bằng **ghi chú điều phối** (không phải PO/Tech Lead ký trực tiếp) — ghi rõ mức độ thẩm quyền thật ở §7.1, không che giấu. Riêng việc gán "Cứng/Mềm" cho từng `CON` và trạng thái 🔴/🔴🔴/🟡/🟢/⏸️ cho từng đối tác ở §4.2 là đánh giá kỹ thuật của SA dựa trên nguồn hiện có, không phải quyết định thay PO | +| D11 | Có mục "Ngoài phạm vi" + `ASM-nn` | ✅ | §6 "Ngoài phạm vi" đầy đủ (đã cập nhật: as-is kỹ thuật sâu hơn — gọi sandbox thật — vẫn ngoài phạm vi); §5 có `ASM-01`…`ASM-06` cấp `CTX`, mỗi cái có cách xác minh, hệ quả, chủ, hạn (không sửa ở lượt này) | +| D12 | Câu quy định thẩm quyền sơ đồ vs văn bản | ✅ | Có câu chuẩn ngay sau Change Log | + +### ③ Danh sách `OQ` mở kèm người phải trả lời, chặn gì + +Xem bảng đầy đủ ở §7. Tóm tắt tám câu hỏi đang chặn (`OQ-009` đã đóng, xem §7.1): **(1)** `OQ-001` +chặn nâng `Confidence` của toàn `CTX` — hỏi PO sàn + BA; **(2)** `OQ-002` chặn số liệu team thật +ở `CON-05` — hỏi PM/Tech Lead; **(3)** `OQ-003` chặn quyết định giữ/thu hẹp phạm vi toàn sàn — +hỏi PO + Tech Lead; **(4)** `OQ-004` chặn tính hợp lệ của ngoại lệ gate `DEC-01` — hỏi PO sàn +(người thật); **(5)** `OQ-005` chặn `CON-01`/`TCO` — hỏi PO/tài chính (có câu trả lời tạm, xem +§7); **(6)** `OQ-006` chặn `CON-02`/kịch bản thời gian ở `OPT` — hỏi PO/PM (có câu trả lời tạm); +**(7)** `OQ-007` chặn `CON-06`/`ASM-04` (residency pháp lý) — hỏi PO (chỉ định người); **(8)** +`OQ-008` chặn `CON-05`/`CON-08` (đội vận hành) — hỏi PM/SRE. + +**Nhắc:** AG1 cần **PO + Tech Lead ký** (điền `Approved by` vào header `OPT`) trước khi chạy +`/sa-2-architecture`. `OPT` chưa tồn tại — phải chạy tiếp Bước 4–5 của `sa-1-context` trước, và +nên có `OQ-005/006/007/008` trả lời trước để Bước 4–5 không phải chấm bừa. diff --git a/sa-output/e-commerce/01-context/OPT_e-commerce_v1.0.md b/sa-output/e-commerce/01-context/OPT_e-commerce_v1.0.md new file mode 100644 index 0000000..b8b9b8d --- /dev/null +++ b/sa-output/e-commerce/01-context/OPT_e-commerce_v1.0.md @@ -0,0 +1,368 @@ +# OPT — Solution Options & Trade-off — e-commerce + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-12 | +| **Author** | SA (skill sa-1-context, chế độ `go`, hoạt động `options`) | +| **Status** | 🟡 Draft *(duyệt từng phần — xem `Approved by`; §1 Khuyến nghị, §2 Bộ tiêu chí và trọng số mặc định (đóng `ASM-09`), §4 Bảng chấm điểm, §5 Phương án bị loại (P3/P4) đã được duyệt tạm để làm nền cho Bước 5/GĐ2 — **chọn P2** có điều kiện (`OQ-010`, `OQ-012`); đây **chưa phải** AG1 toàn phần — Tech Lead chưa ký, `OQ-004` còn mở, quyết định kiến trúc chính thức (`ADR`) vẫn để GĐ2; xem "Tự chấm" §① — vẫn 4/7 tiêu chí ✅)* | +| **Approved by** | PO (uỷ quyền, chế độ chạy thử): **Điều phối dự án** — duyệt **từng phần** bản v1.0 · 2026-09-12: chấp nhận bộ tiêu chí và trọng số mặc định (§2, đóng `ASM-09`), bảng chấm điểm (§4), hai phương án bị loại P3/P4 (§5), và khuyến nghị P2 có điều kiện (§1). **Chọn P2** (modular monolith + managed AWS, tách riêng Payment) làm nền cho Bước 5 và GĐ2, điều kiện: (1) `OQ-010` — Tech Lead xác nhận đội thi công thật; (2) POC SQS/EventBridge được ghi vào `ARISK` ở Bước 5 (`OQ-012`), trước khi chốt `ADR` message backbone GĐ2. Ký thay PO theo ngoại lệ `DEC-01` (SA), ghi thêm `DEC-06`; **không phải chữ ký PO/Tech Lead thật** — `OQ-004` giữ mở. Duyệt này vẫn là duyệt **từng phần**, không phải AG1 toàn phần, và **không thay thế yêu cầu `ADR` chính thức ở GĐ2** (kiểu kiến trúc tổng thể là quyết định thuộc danh mục bắt buộc ADR theo `decision-radar.md §3`). · Tech Lead: — *(chưa ký)* | +| **Source** | `01-context/CTX_e-commerce_v1.0.md` (v1.2 trong header) §2 (`DRV-01…09`), §3 (`CON-01…09`), §4.2 (đối tác 🔴), §4.4 (năng lực tổ chức) · `e-commerce/docs/SAD.md` v0.2 §3.1–§3.4 (`e-commerce/docs/sections/03-kien-truc.md`) · `e-commerce/docs/sections/02-phan-tich-yeu-cau.md` (FR/NFR) · `e-commerce/bid/estimate.computed.json` (Draft, `priceComplete:false`) · `e-commerce/bid/bid-config.md` (Draft) · `00-index/OQ_e-commerce.md` v1.4 · `00-index/DEC_e-commerce.md` v1.4 | +| **Scope** | Toàn sàn e-commerce (marketplace đa seller) theo `SAD.md` v0.2 — phạm vi đã chốt cho lượt chạy này; `OQ-003` (giữ toàn sàn hay thu hẹp về Giỏ hàng & Checkout) **vẫn mở**, chưa ảnh hưởng cấu trúc phương án ở đây vì cả ba phương án đều mô tả ở mức kiến trúc tổng thể toàn sàn | +| **Confidence** | 🔴 Giả định chưa xác minh — kế thừa nguyên nhân của `CTX` (BA chưa ký G1 thật, AG1 GĐ1 SA chưa từng chạy, ngoại lệ gate `DEC-01/03/04` tiếp tục ở `DEC-05`). Riêng phần điểm số ở đây còn thêm hai lý do: (a) `CON-01`/`CON-02`/`CON-05` — ba tiêu chí input trực tiếp cho bảng chấm — đều "Chưa xác định/Mềm" trong `CTX`, chỉ có số tham khảo từ hồ sơ thầu Draft; (b) con số hạ tầng dùng để so sánh P1/P2 ở đây là **số lượng/loại thành phần quản lý (managed component)**, không phải tiền — `TCO` bằng VND thật để Bước 5, ngoài phạm vi lượt chạy này. Duyệt từng phần theo `DEC-06` +**không** nâng `Confidence` này (phê duyệt không phải bằng chứng nguồn mới) — vẫn chờ `OQ-004` +(tính hợp lệ ký thay), `OQ-010` (kinh nghiệm team thật), `OQ-012` (POC SQS/EventBridge) | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | ADR/DEC | +|---|---|---|---|---| +| 1.0 | 2026-09-12 | SA (qua skill sa-1-context, chế độ `go`, hoạt động `options`) | Bản đầu — Bước 4 của `sa-1-context`: chốt bộ tiêu chí (từ `DRV`/`CON`), dựng 3 phương án chấm điểm (P0 giữ nguyên, P1 modular microservices theo `SAD.md`/hồ sơ thầu, P2 modular monolith + managed AWS — phương án đối trọng độc lập), 2 phương án bị loại có lý do (P3 mua/tích hợp nền tảng sẵn có, P4 serverless-first). Khuyến nghị **P2 có điều kiện** — không tự quyết thay PO/Tech Lead (`D10`). Tiếp tục ngoại lệ gate `DEC-01`/`DEC-03`/`DEC-04`, ghi thêm `DEC-05`. Không sửa `CTX` §2–§5 đã duyệt từng phần; chỉ tham chiếu. `Confidence` 🔴 toàn tài liệu. | `DEC-05` | +| 1.0 | 2026-09-12 | PO (uỷ quyền, Điều phối dự án) — tác vụ **sign/approve** | Duyệt **từng phần** bản v1.0: chấp nhận bộ tiêu chí và trọng số mặc định (§2, đóng `ASM-09`), bảng chấm điểm (§4), hai phương án bị loại P3/P4 (§5), khuyến nghị P2 có điều kiện (§1). **Chọn P2** (modular monolith + managed AWS, tách riêng Payment) làm nền cho Bước 5 và GĐ2, điều kiện: (1) `OQ-010` — Tech Lead xác nhận đội thi công thật; (2) POC SQS/EventBridge (`ASM-07`) ghi vào `ARISK` ở Bước 5, trước khi chốt `ADR` message backbone GĐ2 (`OQ-012`). Không đổi nội dung chuyên môn. Ký thay PO theo ngoại lệ `DEC-01` (SA), ghi thêm `DEC-06`; **không phải chữ ký PO/Tech Lead thật** — `OQ-004` giữ mở, Tech Lead **chưa ký**. `Confidence` giữ 🔴. Status **giữ** 🟡 Draft — AG1 toàn phần vẫn chưa đủ điều kiện (4/7 tiêu chí ✅, xem §①); quyết định kiến trúc chính thức vẫn để `ADR` ở GĐ2, DEC-06 chỉ ghi nhận hướng đi tạm. `OQ-011` đóng trong sổ `00-index/OQ_e-commerce.md` bằng chính câu trả lời có điều kiện này. | `DEC-06` | + +> ⚠️ **Đây là tài liệu PO + Tech Lead ký để qua AG1.** Đọc §1 và §5 là đủ để quyết. Tài liệu này +> **chưa đủ điều kiện baseline AG1 một mình** — vẫn thiếu `TCO` (Bước 5) và `ARISK`/kế hoạch POC +> (Bước 5), xem "Tự chấm" ở cuối `CTX_e-commerce_v1.0.md` §Tự chấm ① (cập nhật lại ở cuối file +> này). + +> Sơ đồ thắng về **quan hệ và luồng** (ai gọi ai, đồng bộ/bất đồng bộ). Bảng/văn bản thắng về +> **ràng buộc và con số** (timeout, quyền, đơn vị hạ tầng). Mâu thuẫn ngoài hai loại này 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 — tiếp nối `CTX` + +Gate AG1 (PO + Tech Lead) của chính GĐ1 SA **chưa từng chạy** cho dự án e-commerce, và BA vẫn +chưa ký G1 chính thức (`BRIEF_CartCheckout` Draft) — như đã ghi ở `CTX §0`, `DEC-01`, `DEC-03`, +`DEC-04`. Người dùng (vai điều phối dự án chạy thử) **tái khẳng định muốn tiếp tục** sang Bước 4 +(`OPT`) của `sa-1-context` dù các điều kiện trên chưa đạt. + +> **DEC-05 (SA)** — Tiếp tục chạy `sa-1-context` Bước 4 (Phương án — `OPT`) cho dự án e-commerce +> trong khi BA vẫn chưa qua G1 và AG1 (gate của chính GĐ1 SA) vẫn chưa từng chạy — tiếp nối +> `DEC-01`/`DEC-03`/`DEC-04`. +> **Quyết định:** Tiếp tục, `Confidence 🔴` cho toàn bộ nội dung điểm số (dựa trên `CON` còn +> "Chưa xác định/Mềm") cho tới khi có số ngân sách/deadline/team thật (`OQ-005`, `OQ-006`, +> `OQ-008`). +> **Người quyết:** Điều phối dự án (đại diện PO, dự án chạy thử). +> **Radar (ước lượng):** ~3–4 (chi phí đảo ngược thấp — nội dung `OPT` sửa lại khi có số thật +> không tốn nhiều · bán kính ảnh hưởng: toàn bộ quyết định kiến trúc GĐ2 phụ thuộc phương án +> chọn ở đây, nhưng bản thân *việc ghi tài liệu dưới ngoại lệ* thì nhỏ · chưa chạm trực tiếp một +> `QAS` cụ thể (`QAS` chưa tồn tại, đây vẫn là GĐ1) · không ràng buộc dài hạn (ngoại lệ tạm thời) +> · không tranh cãi mới, tiếp nối tiền lệ) → **ghi `DEC-nn`, không cần `ADR`** theo +> `decision-radar.md §1–§2`. +> **Hệ quả nếu không chấp nhận ngoại lệ:** dừng `sa-1-context` ở cuối Bước 3, không có `OPT` để +> PO/Tech Lech tham khảo cho tới khi BA ký G1 thật và/hoặc AG1 chạy đủ vòng đầu — chậm tiến độ +> chạy thử tương ứng. + +🔴 **Lưu ý quan trọng cho người ký:** bảng chấm điểm dưới đây dùng số liệu tham khảo từ hồ sơ +thầu (`e-commerce/bid/`, Draft, `priceComplete:false`) cho các tiêu chí Chi phí/Thời gian/Team — +đây là ước lượng của **nhà thầu cho mục đích đấu thầu**, không phải số đã được PO xác nhận +(`OQ-005`, `OQ-006`, `OQ-008` vẫn mở). Điểm số vì vậy phản ánh **thứ tự tương đối** hợp lý giữa +các phương án hơn là giá trị tuyệt đối đáng tin cậy. + +--- + +## 1. Khuyến nghị *(đọc mục này trước)* + +| | | +|---|---| +| **Phương án khuyến nghị** | **P2 — Modular monolith + managed AWS services, tách riêng Payment Service** | +| **Vì sao** | Khớp Conway với team giả định `DEC-02`/hồ sơ thầu (BE trung bình chỉ ~2,6 FTE/tháng trên 7 tháng — xem §3 P2 "Ai vận hành") — 10 service độc lập của P1 vượt quá năng lực vận hành thực tế của một team cỡ này (`CON-05`); đồng thời P2 vẫn giữ nguyên yêu cầu cứng `CON-06` (cô lập Payment Service cho PCI-DSS SAQ A) và không đổi vùng AWS (`CON-03`) | +| **Chỗ phương án này THUA** | Thua P1 ở tiêu chí "Đáp ứng `DRV` Must" (4 so với 5) — khả năng scale-out **độc lập** Catalog/Search khỏi Cart/Checkout (`DRV-04`) yếu hơn khi cả hai còn chung một nhóm deployable ở giai đoạn đầu; đây là đánh đổi thật, không phải P2 thắng tuyệt đối | +| **Điều kiện kèm theo** | (1) Tech Lead xác nhận đội thi công thật (không phải đề xuất hồ sơ thầu) — trả lời `OQ-010`; (2) trước khi chốt `ADR` message backbone ở GĐ2, chạy POC đo throughput SQS/EventBridge cho luồng `OrderPlaced`/`PaymentConfirmed` ở tải tương đương `DRV-04` (`ASM-07`, `OQ-012`) — **POC fail (không đạt thông lượng cần thiết) ⇒ bổ sung Kafka/MSK riêng cho hot-path đặt hàng (kiến trúc lai), không chuyển hẳn sang P1** vì phần còn lại của P1 (10 service tách rời) vẫn vi phạm Conway; (3) PO xác nhận ngân sách đủ để về sau tách Catalog/Search ra khỏi monolith nếu traffic thật vượt ngưỡng dự kiến (`ASM-08`) | +| **Quyết định này cần ai ký** | PO (đánh đổi giữa scale-out sớm và phù hợp năng lực team hiện tại) · Tech Lead (khả thi thi công/vận hành với team thật) — **chưa ký, đây vẫn là khuyến nghị của SA, không phải quyết định** (`D10`) | + +--- + +## 2. Bộ tiêu chí *(chốt TRƯỚC khi mô tả phương án)* + +*Tiêu chí sinh từ `DRV` (Must trước) và `CON` (cứng là điều kiện loại, không phải điểm số). +Trọng số dùng nguyên bộ mặc định của `sa-1-context/templates/option-tradeoff.md` — chưa có +buổi duyệt trọng số riêng với PO/Tech Lead (kế thừa hạn chế elicitation của `CTX`), ghi nhận là +giả định tiếp theo.* + +### 2.1 Điều kiện loại (gate cứng — pass/fail trước khi chấm điểm) + +| `CON` | Nội dung | Bắt buộc gì | P0 | P1 | P2 | P3 | P4 | +|---|---|---|---|---|---|---|---| +| `CON-03` | Cloud AWS bắt buộc | Không dùng cloud khác/on-prem | N/A (không xây) | ✅ Pass | ✅ Pass | ⚠️ Phụ thuộc bản build nền tảng — hầu hết nền tảng open-source multi-vendor có thể tự host trên AWS, coi là Pass được nếu tự triển khai | ✅ Pass (Lambda/Step Functions đều AWS) | +| `CON-06` | PCI-DSS SAQ A (không lưu thẻ) + NĐ13/2023 (PII/KYC) — Payment phải là biên cô lập duy nhất | Thiết kế phải tách được Payment Service/module ra làm biên cô lập | N/A | ✅ Pass — đã thiết kế sẵn trong `SAD.md` §3.1 | ✅ Pass — Payment tách riêng dù phần còn lại gộp (xem §3 P2) | ❌ **Không kiểm chứng được** với lõi đóng gói sẵn của nền tảng mua/tích hợp mà không sửa sâu — xem §5 lý do loại | ⚠️ Chưa kiểm chứng cô lập Payment trong mô hình serverless (Lambda dùng chung VPC/role) — chưa loại nhưng là rủi ro cao, xem §5 | + +**Đọc bảng:** `CON-06` là lý do loại chính của P3. `P4` không bị loại bởi gate cứng nhưng bị +loại ở bước chấm điểm rủi ro kỹ thuật + thiếu bằng chứng năng lực team (§5). + +### 2.2 Tiêu chí chấm điểm (áp dụng cho phương án đã qua gate cứng) + +| # | Tiêu chí | Trọng số | Sinh từ | Đo bằng | +|---|---|---|---|---| +| 1 | Đáp ứng `DRV` mức Must (`DRV-01,02,03,04,05,06,07,08`) | 25% | `DRV-01…08` | Có/không cho từng driver, quy về thang 1–5 | +| 2 | Chi phí 3 năm (sơ bộ — số lượng/loại managed component, **không** phải VND; `TCO` VND thật ở Bước 5) | 20% | `CON-01` (chưa xác định số thật) | Số lượng thành phần hạ tầng quản lý riêng biệt phải vận hành | +| 3 | Thời gian tới bản chạy được | 15% | `CON-02` (7 tháng thầu / 9–12 tháng brief) | Effort WBS liên quan tới việc dựng nền tảng (tuần/MD, theo `estimate.computed.json`) | +| 4 | Rủi ro kỹ thuật | 15% | Nguồn rủi ro "Công nghệ mới"/"Phụ thuộc bên ngoài" (`decision-radar.md`) | Có bằng chứng team từng chạy production công nghệ này chưa (`CTX §4.4`) | +| 5 | Phù hợp năng lực team & vận hành (Conway) | 15% | `CON-05`, `DEC-02` | Số service/module so với FTE BE trung bình thật (nguồn `estimate.computed.json.mmByRole`) | +| 6 | Khả năng tiến hoá (chi phí đảo ngược) | 10% | — | Chi phí tách/gộp lại về sau | + +**Trọng số do ai duyệt · ngày:** Chưa ai duyệt chính thức — SA dùng bộ mặc định của template vì +chưa có buổi làm việc PO/Tech Lech riêng cho trọng số (kế thừa hạn chế elicitation, xem `OQ-001` +của `CTX`). Ghi nhận: nếu PO/Tech Lead muốn đổi trọng số (ví dụ tăng "Rủi ro kỹ thuật" hoặc "Chi +phí" vì ngân sách hạn chế theo `CON-01`), chấm lại theo trọng số mới trước khi ký AG1. + +🔴 Trọng số này **không** được chốt trong một buổi làm việc PO xác nhận — nếu điểm tổng P2 so +với P1 (§4) đổi thứ hạng khi tăng trọng số "Chi phí" hoặc "Năng lực team" (hai tiêu chí P2 đang +mạnh), khuyến nghị càng vững; nếu PO tăng mạnh trọng số "Đáp ứng DRV Must" (tiêu chí P1 mạnh +hơn), thứ hạng có thể đổi — xem `OQ-011`. + +--- + +## 3. Các phương án + +### P0 — Không làm gì / giữ nguyên *(mốc so sánh, bắt buộc có)* + +| | | +|---|---| +| **Mô tả** | Không triển khai sàn e-commerce ở giai đoạn này. Vì đây là dự án **greenfield** (`CTX §4.1`), "giữ nguyên" nghĩa là **không có gì để giữ** — khách hàng/seller tiếp tục không có nền tảng giao dịch tập trung nào (không có quy trình thủ công đang chạy để so sánh, khác dự án loại "mở rộng") | +| **Chi phí 3 năm** | Không phát sinh chi phí xây dựng/vận hành kiến trúc. **Chi phí cơ hội không định lượng được ở lượt này** — `DRV-01` đã ghi rõ: không có luồng giao dịch ⇒ **0 giao dịch ghi nhận, toàn bộ mô hình kinh doanh marketplace bị chặn hoàn toàn**, đây là hệ quả định tính nghiêm trọng nhất trong toàn bộ `CTX`, dù không quy ra được một con số tiền cụ thể (không có doanh thu mục tiêu bằng số trong nguồn hiện có) | +| **Vì sao không chọn** | Vi phạm trực tiếp `DRV-01` (Must, blocker) — đây là driver mạnh nhất trong toàn bộ `CTX`. Giữ P0 làm mốc so sánh, không phải phương án khả thi | + +### P1 — Modular microservices theo `SAD.md` v0.2 / hồ sơ thầu (điểm khởi đầu tham khảo, `DEC-04`) + +| | | +|---|---| +| **Ý tưởng một câu** | ~10 service theo bounded-context, database-per-service, giao tiếp REST đồng bộ + Kafka/MSK bất đồng bộ cho chuỗi nghiệp vụ sau đặt hàng | +| **Thành phần chính** | Identity, Catalog & Inventory, Search (OpenSearch), Cart & Order (+ Dispute), Payment, Seller Management, Commission & Payout, Promotion & Loyalty, Review, Notification, Shipping & Fulfillment — mỗi service một RDS PostgreSQL Multi-AZ logic riêng, ElastiCache Redis dùng chung cho cache/session/giỏ hàng, Kafka/MSK là xương sống bất đồng bộ, ECS Fargate/EKS auto-scaling theo domain, CloudFront + WAF phía trước | +| **Mua gì / tự làm gì** | Toàn bộ business logic tự xây; hạ tầng dùng AWS managed service (RDS, MSK, ElastiCache, OpenSearch, ECS/EKS, CloudFront, WAF) — không mua phần mềm lõi thương mại nào | +| **Dữ liệu nằm ở đâu, ai sở hữu** | Mỗi service sở hữu schema/DB riêng (database-per-service) — không service nào truy cập trực tiếp DB service khác, chỉ qua API/event (`SAD.md §3.2`) | +| **Ai vận hành** | Đội DevOps/SRE phải vận hành ~10 service group riêng + 1 cụm Kafka/MSK + 1 cụm OpenSearch đa node — theo hồ sơ thầu, FTE DevOps trung bình toàn dự án chỉ **~4,92 MM/~7 tháng ≈ 0,7 FTE trung bình** (`estimate.computed.json.mmByRole.DEVOPS`), đỉnh điểm cao hơn ở WBS-01/02/03 | +| **Thời gian tới bản chạy được** | Riêng hạng mục nền tảng dịch vụ & event backbone (`WBS-03`, complexity **XL**, risk **high**) đã ước **52 MD + 18,2 MD dự phòng (35%) = 70,2 MD** chỉ để dựng xương sống, **trước khi** làm bất kỳ nghiệp vụ nào (nguồn: `estimate.computed.json`) | +| **Chi phí 3 năm (sơ bộ, số lượng thành phần — chưa quy đổi VND)** | ~10 RDS logic + 1 cụm MSK (Kafka) + 1 cụm OpenSearch đa node + ~10 ECS/EKS service group tự động mở rộng riêng — nhiều thành phần phải trả phí/quản lý độc lập nhất trong 3 phương án đã qua gate cứng. **8/8 khoản chi phí non-labor trong hồ sơ thầu đều `amount: null`** (`CON-01`) — không có số VND thật để so sánh, chỉ so sánh được số lượng/loại thành phần | +| **Rủi ro chính** | (a) Không có bằng chứng team từng vận hành Kafka/MSK, OpenSearch cluster, EKS trong production (`CTX §4.4`); (b) 4 đối tác tích hợp bên ngoài (VNPay/Momo/GHN/GHTK) chưa sandbox thật (`CTX §4.2`, độc lập với lựa chọn kiến trúc nội bộ nhưng số lượng service tăng số điểm tích hợp phải xử lý retry/idempotent riêng lẻ); (c) `WBS (42,48 MM) lệch 54,47% so với UCP (27,5 MM)` — cảnh báo tự động trong `estimate.computed.json.crosscheck` vượt ngưỡng 25%, dấu hiệu ước lượng effort chưa ổn định. *(Chưa lập `ARISK-nn` chính thức — thuộc Bước 5, ngoài phạm vi lượt chạy này; ba điểm trên là ứng viên trực tiếp)* | +| **Đảo ngược được không, tốn bao nhiêu** | Ranh giới service theo domain đã rõ — dễ **thay/rút bớt từng service riêng lẻ** về sau (ví dụ gộp Review vào Promotion nếu tải thấp) mà không phải viết lại toàn bộ; nhưng **gộp ngược lại thành ít service hơn** (nếu phát hiện team quá nhỏ để vận hành 10 service) tốn công tái cấu trúc network/DB đáng kể | + +**Sơ đồ mức khối** *(C4 Context/Container — chỉ hộp lớn, chưa phải component; xem legend §3.3)* + +```mermaid +flowchart LR + subgraph P1["P1 — Modular microservices (~10 service, database-per-service)"] + Client1["Web/Seller/Admin Clients"] -->|"1 · HTTPS REST, sync"| GW1["API Gateway / BFF"] + GW1 -->|"2 · REST, sync"| SVC1["~10 bounded-context services\n(Identity, Catalog, Search, Cart&Order,\nPayment, Seller, Commission, Promo,\nReview, Notify, Shipping)"] + SVC1 -->|"3 · publish, async"| MQ1[("Kafka / Amazon MSK")] + MQ1 -->|"4 · consume, async"| SVC1 + SVC1 -->|"5 · SQL, sync"| DB1[("RDS PostgreSQL Multi-AZ\ndatabase-per-service, ~10 logic DB")] + SVC1 -->|"6 · cache/session, sync"| CACHE1[("ElastiCache Redis")] + SVC1 -->|"7 · index/query, sync"| SEARCH1[("OpenSearch, đa node")] + SVC1 -->|"8 · REST/webhook, sync+async"| EXT1["VNPay · Momo · GHN · GHTK · Email/SMS"] + end +``` + +### P2 — Modular monolith + managed AWS services, tách riêng Payment *(phương án đối trọng độc lập)* + +| | | +|---|---| +| **Ý tưởng một câu** | Một (hoặc vài) deployable module hoá theo domain, chạy trên ECS Fargate với 2–3 nhóm service thay vì 10, dùng SQS/EventBridge thay Kafka/MSK, tách riêng duy nhất **Payment Service** để giữ ranh giới PCI-DSS | +| **Thành phần chính** | Modular monolith gồm module: Identity, Catalog & Inventory, Cart & Order (+ Dispute), Seller Management, Commission & Payout, Promotion & Loyalty, Review, Notification, Shipping & Fulfillment — chạy trong 2–3 nhóm ECS Fargate service (ví dụ: nhóm "giao dịch" Cart/Order/Catalog tách riêng để scale nhanh hơn nhóm "hỗ trợ" Seller/Promo/Review/Notify/Shipping); **Payment Service** tách hoàn toàn độc lập (network + IAM riêng) — bắt buộc theo `CON-06`, không phải tuỳ chọn | +| **Mua gì / tự làm gì** | Giống P1 về business logic tự xây; khác ở lựa chọn hạ tầng: SQS/EventBridge (không cần cụm Kafka tự quản lý), OpenSearch **hoãn** dùng managed service đa node ngay từ đầu — dùng Postgres full-text search cho giai đoạn đầu MVP, chuyển sang OpenSearch khi có bằng chứng cần (dựa `DRV-04` số liệu thật sau go-live) | +| **Dữ liệu nằm ở đâu, ai sở hữu** | 1 RDS PostgreSQL Multi-AZ chính, chia theo schema-per-module (ranh giới logic rõ ràng dù chung instance) — **trừ** Payment có RDS riêng nhỏ, tách biệt hoàn toàn khỏi cụm chính (không service khác truy cập trực tiếp) | +| **Ai vận hành** | Cùng team FTE như P1 (chưa có số thật khác biệt — cả hai phương án dùng chung giả định `DEC-02`), nhưng **số đơn vị triển khai cần vận hành/on-call giảm từ ~10 xuống ~3** (2–3 nhóm monolith + 1 Payment Service riêng) — khớp trực tiếp với FTE DevOps trung bình thấp (~0,7 FTE, nguồn giống P1) | +| **Thời gian tới bản chạy được** | Không cần hạng mục dựng "event backbone Kafka/MSK" (XL, 35% contingency) như P1 — SQS/EventBridge là managed service dùng ngay, giảm phần lớn effort tương ứng trong `WBS-03`; các hạng mục nghiệp vụ (WBS-18…43) không đổi giữa P1/P2 vì cùng phạm vi FR | +| **Chi phí 3 năm (sơ bộ, số lượng thành phần — chưa quy đổi VND)** | 1–2 RDS instance (thay vì ~10 logic DB cần theo dõi riêng) + SQS/EventBridge (không có cụm phải patch/scale thủ công như MSK) + Postgres FTS giai đoạn đầu (không cần cụm OpenSearch đa node ngay) + 2–3 ECS service group (thay vì ~10) — ít thành phần quản lý độc lập hơn hẳn P1. Cùng hạn chế: **8/8 khoản non-labor trong hồ sơ thầu `amount: null`** — không có số VND thật, chỉ so sánh số lượng/loại thành phần | +| **Rủi ro chính** | (a) SQS/EventBridge chưa được đo throughput thật cho tải đỉnh `DRV-04` — `ASM-07`; (b) 1 RDS chính cho nhiều module chưa đo tải ghi/đọc gộp — `ASM-08`; (c) cùng rủi ro đối tác bên ngoài 🔴 như P1 (`CTX §4.2`, không phụ thuộc kiến trúc nội bộ); (d) nếu traffic thật vượt xa dự kiến, tách Catalog/Search ra khỏi monolith muộn sẽ tốn hơn tách từ đầu (đánh đổi đã nêu ở §1). *(Chưa lập `ARISK-nn` chính thức — Bước 5)* | +| **Đảo ngược được không, tốn bao nhiêu** | Module hoá rõ theo domain trong code (namespace/package riêng biệt) giúp tách thành service riêng về sau **có kế hoạch** khi có bằng chứng tải thật cần (khác gộp ngược từ 10 service như P1) — nhưng tốn công tách hạ tầng (network, DB, CI/CD riêng) tại thời điểm tách, không miễn phí | + +**Sơ đồ mức khối** *(C4 Context/Container — chỉ hộp lớn; xem legend §3.3)* + +```mermaid +flowchart LR + subgraph P2["P2 — Modular monolith + managed AWS, Payment tách riêng"] + Client2["Web/Seller/Admin Clients"] -->|"1 · HTTPS REST, sync"| GW2["API Gateway / ALB"] + GW2 -->|"2 · REST, sync"| MONO2["Modular monolith\n(Identity, Catalog, Cart&Order, Seller,\nCommission, Promo, Review, Notify, Shipping)\n2-3 nhóm ECS Fargate"] + GW2 -->|"2b · REST, sync, cô lập mạng riêng"| PAY2["Payment Service\n(tách bắt buộc — CON-06 PCI-DSS SAQ A)"] + MONO2 -->|"3 · publish, async"| BUS2[("SQS / EventBridge")] + PAY2 -->|"3b · publish, async"| BUS2 + BUS2 -->|"4 · consume, async"| MONO2 + MONO2 -->|"5 · SQL, sync"| DB2[("RDS PostgreSQL Multi-AZ\n1 cụm chính, schema-per-module")] + PAY2 -->|"5b · SQL, sync"| DBPAY2[("RDS riêng, nhỏ — chỉ Payment")] + MONO2 -->|"6 · cache/session, sync"| CACHE2[("ElastiCache Redis")] + MONO2 -->|"7 · index/query, sync"| SEARCH2[("Postgres full-text (giai đoạn đầu)\n→ OpenSearch khi có bằng chứng cần")] + MONO2 -->|"8 · REST/webhook, sync+async"| EXT2["GHN · GHTK · Email/SMS"] + PAY2 -->|"8b · REST/webhook, sync+async"| EXTPAY2["VNPay · Momo"] + end +``` + +### 3.3 Legend cho cả hai sơ đồ P1/P2 *(bắt buộc theo `D4`)* + +| Số | Loại mũi tên | Giao thức | Sync/Async | Ghi chú | +|---|---|---|---|---| +| 1 | Client → Gateway | HTTPS REST | Sync | Người dùng chờ phản hồi | +| 2 / 2b | Gateway → Service | REST (nội bộ) | Sync | 2b (P2): Payment nằm sau ranh giới mạng/IAM riêng, không chung network với monolith | +| 3 / 3b | Service → Message bus | Publish event | Async | Domain event (VD `OrderPlaced`) | +| 4 | Message bus → Service | Consume event | Async | Xử lý chuỗi sau đặt hàng (hoa hồng, payout, notify, loyalty) | +| 5 / 5b | Service → Database | SQL (JDBC/driver) | Sync | 5b (P2): Payment có RDS riêng, không service khác truy cập | +| 6 | Service → Cache | Redis protocol | Sync | Session, giỏ hàng, cache đọc | +| 7 | Service → Search | Query API | Sync | P1: OpenSearch ngay từ đầu · P2: Postgres FTS giai đoạn đầu | +| 8 / 8b | Service ↔ Đối tác ngoài | REST/webhook (theo `SAD.md §3.4`) | Sync (gọi) + Async (webhook/IPN) | Timeout/retry cụ thể: xem `CTX §4.2`, kế thừa `SAD.md §3.4` — **chưa kiểm chứng với sandbox thật** (🔴, `CON-04`) | + +*C4 mức: **Container** (không phải Component) — mỗi hộp là một đơn vị triển khai/nhóm đơn vị +triển khai, chưa xuống tới class/module code. Không trộn mức.* + +--- + +## 4. Bảng chấm điểm + +*Thang 1–5. Chỉ chấm các phương án đã qua gate cứng §2.1 (P0, P1, P2). P3, P4 bị loại ở §5, +không chấm điểm đầy đủ.* + +| Tiêu chí | Trọng số | P0 | P1 | P2 | +|---|---|---|---|---| +| 1. Đáp ứng `DRV` Must | 25% | 1 | 5 | 4 | +| 2. Chi phí 3 năm (sơ bộ) | 20% | 5 | 2 | 4 | +| 3. Thời gian tới bản chạy được | 15% | 5 | 2 | 4 | +| 4. Rủi ro kỹ thuật | 15% | 5 | 2 | 4 | +| 5. Năng lực team & vận hành (Conway) | 15% | 5 | 2 | 5 | +| 6. Khả năng tiến hoá | 10% | 1 | 4 | 3 | +| **Tổng có trọng số** | 100% | **3.60** | **2.95** | **4.05** | + +**Lý do từng ô** + +| Tiêu chí | P0 | P1 | P2 | +|---|---|---|---| +| 1. `DRV` Must | Không xây gì ⇒ vi phạm trực tiếp `DRV-01` (blocker) — điểm sàn | Đáp ứng đầy đủ nhất: scale-out **độc lập** Catalog/Search khỏi Checkout ngay từ đầu (`DRV-04`), event backbone tách chuỗi hoa hồng/payout khỏi luồng chính (`DRV-06`) | Đáp ứng phần lớn nhưng scale-out Catalog/Search **chưa độc lập** ở giai đoạn đầu (chung nhóm monolith) — thua P1 đúng một bậc, không giả vờ ngang bằng | +| 2. Chi phí (sơ bộ) | Không phát sinh chi phí hạ tầng | Nhiều thành phần managed độc lập nhất phải vận hành (~10 RDS logic + MSK + OpenSearch đa node + ~10 ECS group) — chi phí vận hành sơ bộ cao nhất trong 2 phương án đã qua gate | Ít thành phần hơn hẳn (1–2 RDS + SQS/EventBridge + Postgres FTS + 2–3 ECS group) — chi phí vận hành sơ bộ thấp hơn P1 | +| 3. Thời gian | Có ngay, 0 effort | `WBS-03` (dựng nền tảng dịch vụ & event backbone) một mình đã 70,2 MD (XL, +35% contingency) trước khi làm nghiệp vụ | Không cần dựng cụm Kafka/MSK — dùng managed service có sẵn ngay, effort nền tảng thấp hơn đáng kể so với P1 | +| 4. Rủi ro kỹ thuật | Không có rủi ro kỹ thuật (không xây) | Không có bằng chứng team từng vận hành Kafka/MSK, OpenSearch, EKS production (`CTX §4.4`); cảnh báo lệch WBS↔UCP 54,47% (`estimate.computed.json.crosscheck`) | Công nghệ managed phổ biến hơn (RDS, SQS/EventBridge, ECS Fargate) — rủi ro "công nghệ mới" thấp hơn; rủi ro đối tác bên ngoài 🔴 giữ nguyên như P1 (không đổi bởi kiến trúc nội bộ) | +| 5. Năng lực team (Conway) | Không cần team | ~10 service độc lập trong khi FTE BE trung bình toàn dự án chỉ **~18,31 MM/~7 tháng ≈ 2,6 FTE trung bình** (`estimate.computed.json.mmByRole.BE`) — mỗi kỹ sư BE ôm trung bình 3–4 service, vi phạm Conway rõ theo `DEC-02` | Số đơn vị triển khai cần vận hành giảm còn ~3 (2–3 nhóm monolith + Payment) — khớp với cùng FTE BE ~2,6 trung bình tốt hơn P1 | +| 6. Khả năng tiến hoá | Giữ nguyên = không tiến hoá được, mỗi ngày trì hoãn là một ngày mất cơ hội thị trường không thu hồi được | Ranh giới service đã tách sẵn — dễ thay/rút từng service riêng lẻ về sau | Module hoá trong code dễ tách dần khi có bằng chứng tải thật, nhưng tách hạ tầng lúc đó tốn công hơn P1 (đã tách sẵn) — thua P1 đúng ở tiêu chí này | + +🔴 **Điểm tổng P1 (2.95) và P2 (4.05) chênh 1.10 — đủ phân biệt**, không rơi vào bẫy "chênh <0.3". +P0 (3.60) và P2 (4.05) chênh 0.45 — cũng đủ phân biệt, nhưng nhắc lại: **P0 vi phạm `DRV-01` +(Must, blocker)** nên dù điểm tổng gần P2, P0 **không phải lựa chọn khả thi** — đây là lý do +điểm P0 cao ở nhiều tiêu chí "chi phí/thời gian/rủi ro" (vì không làm gì thì các tiêu chí đó tự +nhiên thấp) nhưng lại thua tuyệt đối ở tiêu chí có trọng số cao nhất (Đáp ứng `DRV` Must, 25%). + +--- + +## 5. Phương án bị loại và lý do *(bắt buộc — quy tắc `D3`)* + +| Phương án | Đã cân nhắc vì | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---|---| +| **P3 — Mua/tích hợp nền tảng multi-vendor mã nguồn mở** (VD Medusa.js, Bagisto) + tuỳ biến tách đơn đa seller, hoa hồng/payout, KYC seller | Có thể giảm effort xây lõi catalog/cart/order từ đầu, tăng tốc thời gian ra bản chạy được — đúng như gợi ý cân nhắc trong ghi chú người duyệt | (a) Không có bằng chứng nền tảng ứng viên nào hỗ trợ sẵn mô hình hold 3–7 ngày + audit trail tài chính riêng theo đúng `DRV-06`/FR-21/22 — phải sửa lõi sâu, mất lợi thế "mua sẵn"; (b) **không kiểm chứng được cô lập Payment Service** cho PCI-DSS SAQ A nếu không sửa sâu lõi nền tảng — vi phạm `CON-06` (gate cứng §2.1); (c) chưa có bằng chứng năng lực team với stack cụ thể của nền tảng này (PHP/Laravel hay Node tuỳ nền tảng) — `ASM` mới, không phải số liệu đã có | `CON-06` (loại cứng), `CON-05` (rủi ro năng lực) | Nếu Tech Lead xác nhận có kinh nghiệm sâu với một nền tảng cụ thể **và** nền tảng đó chứng minh được (qua POC) khả năng cô lập Payment đúng yêu cầu SAQ A mà không sửa lõi — xét lại cho các module không nhạy cảm tài chính (VD Catalog/Review) | +| **P4 — Serverless-first** (Lambda + API Gateway + Step Functions + DynamoDB/Aurora Serverless, EventBridge cho toàn bộ luồng, không container) | Chi phí theo request, không cần quản lý cluster, scale tự động cho flash sale — đúng gợi ý cân nhắc trong ghi chú người duyệt | (a) Cold-start của Lambda cho luồng checkout đồng bộ có nguy cơ ảnh hưởng trải nghiệm ở đúng bước `DRV-02` (bỏ giỏ) — **chưa có POC đo cold-start trong ngữ cảnh VPC + kết nối RDS**; (b) chưa có bằng chứng năng lực team với serverless-at-scale (`CON-05`); (c) mô hình chi phí theo request khó ước lượng ở quy mô "hàng nghìn–chục nghìn concurrent user" (`DRV-04`) mà không có bài đo — rủi ro hoá đơn tăng phi tuyến (nguồn rủi ro "Chi phí", `SKILL.md` Bước 5) | `DRV-02`, `CON-05` | Nếu có POC đo cold-start đạt yêu cầu checkout và Tech Lead xác nhận năng lực serverless-at-scale — xét lại cho các luồng bất đồng bộ thuần (VD Notification, Commission batch) như một lựa chọn lai với P2, không nhất thiết toàn bộ hệ thống | + +*"Team quen công nghệ X" là lý do hợp lệ — ở đây áp dụng ngược: P3/P4 bị loại một phần vì +**chưa có bằng chứng** team quen (`ASM` mới), không phải vì SA không thích công nghệ đó.* + +--- + +## 6. Bảng đánh đổi trình PO + +*Dịch lựa chọn kỹ thuật thành ngôn ngữ PO hiểu được — so sánh P1 và P2 (P0 đã loại ở §4 vì vi +phạm `DRV-01`).* + +| Nếu chọn | Được | Mất | Tiền chênh 3 năm | Thời gian chênh | +|---|---|---|---|---| +| **P1** (giữ theo `SAD.md`/hồ sơ thầu) | Scale-out độc lập Catalog/Search khỏi Checkout **ngay từ đầu**; không cần thiết kế lại nếu traffic tăng nhanh hơn dự kiến | Rủi ro Conway cao với team hiện tại (mỗi BE ôm 3–4 service); effort dựng nền tảng lớn hơn; nhiều thành phần managed phải vận hành hơn (MSK, OpenSearch đa node) | **Chưa quy đổi VND** (`TCO` Bước 5) — sơ bộ **cao hơn P2** vì số lượng managed component nhiều hơn (8/8 khoản non-labor hồ sơ thầu đều chưa có số, không thể so tuyệt đối) | +70,2 MD riêng cho nền tảng event backbone (`WBS-03`) so với P2 không cần cụm Kafka/MSK riêng | +| **P2** (khuyến nghị SA) | Khớp Conway với team giả định `DEC-02`; thời gian tới bản chạy được nhanh hơn; ít managed component phải vận hành hơn | Scale-out độc lập Catalog/Search **kém hơn ngay từ đầu** — có thể phải tách service khi traffic thật vượt ngưỡng, tốn chi phí tái cấu trúc lúc đó (không miễn phí, không định lượng được ở lượt này) | **Chưa quy đổi VND** — sơ bộ **thấp hơn P1** | **-70,2 MD** so với P1 ở riêng hạng mục nền tảng; effort nghiệp vụ (WBS-18…43) không đổi giữa hai phương án | + +--- + +## 7. Cắt gì thì giảm bao nhiêu + +*Chưa áp dụng ở lượt chạy này.* `TCO` bằng VND thật (Bước 5) chưa tồn tại, và `CON-01` (ngân +sách) vẫn "Chưa xác định" (`OQ-005` còn mở) — không có số ngân sách đã duyệt để đối chiếu và đề +xuất cắt giảm có ý nghĩa. Mục này sẽ điền khi `TCO` (Bước 5) hoàn thành **và** `OQ-005` có câu +trả lời bằng số thật. + +--- + +## 8. Giả định & Ngoài phạm vi + +**Giả định** — `ASM-nn` ảnh hưởng tới lựa chọn này *(tiếp số từ `CTX §5`, bắt đầu `ASM-07`)*: + +| ID | Giả định | Nếu sai thì phương án nào đổi | +|---|---|---| +| `ASM-07` | Amazon SQS/EventBridge (không phải Kafka/MSK) đủ đáp ứng thông lượng cho luồng `OrderPlaced`/`PaymentConfirmed` ở tải đỉnh flash sale (`DRV-04`, "hàng nghìn–chục nghìn concurrent user") — **chưa có POC đo throughput thật trong ngữ cảnh này**. Cách xác minh: POC đo SQS FIFO/EventBridge với payload tương tự `OrderPlaced` ở tải giả lập tương ứng `DRV-04`. Chủ: Tech Lead. Hạn: trước khi chốt `ADR` message backbone ở GĐ2 | Nếu sai (không đủ throughput): P2 phải bổ sung Kafka/MSK riêng cho hot-path đặt hàng (kiến trúc lai P1+P2 cho riêng luồng này), không chuyển hẳn sang P1 vì phần còn lại của P1 vẫn vi phạm Conway | +| `ASM-08` | 1 cụm RDS PostgreSQL Multi-AZ chính (schema-per-module) đủ chịu tải ghi/đọc gộp cho toàn bộ module ngoại trừ Payment tách riêng — **chưa đo**. Cách xác minh: POC load test theo kịch bản `NFR-01`/`NFR-02`. Chủ: Tech Lead/DBA. Hạn: trước GĐ2 (`DAT`) | Nếu sai: phải tách read replica/DB riêng cho Catalog/Search sớm hơn dự kiến trong P2, tăng chi phí vận hành tiệm cận P1 cho phần đó | +| `ASM-09` | Bộ tiêu chí và trọng số ở §2.2 (mặc định từ template, chưa qua buổi duyệt riêng với PO/Tech Lead) phản ánh đúng ưu tiên thật của dự án — xem cảnh báo cuối §2.2 | Nếu PO tăng mạnh trọng số "Đáp ứng `DRV` Must", thứ hạng P1/P2 có thể đổi (P1 mạnh nhất ở tiêu chí này) — xem `OQ-011` | + +*Giả định `ASM-01…06` của `CTX` (ngân sách, deadline, đội vận hành, residency, dùng `SAD.md` làm +điểm khởi đầu, hoá đơn điện tử hoãn) vẫn áp dụng nguyên trạng cho toàn bộ `OPT` — không lặp lại +nội dung ở đây, chỉ tham chiếu.* + +**Ngoài phạm vi:** + +- `TCO` bằng VND thật, 3 năm, ≥2 kịch bản tải — thuộc Bước 5, **chưa làm** ở lượt chạy này. Mọi + con số "chi phí" trong tài liệu này là **số lượng/loại thành phần hạ tầng để so sánh tương + đối**, không phải tiền. +- `ARISK` (sổ rủi ro kiến trúc chính thức) và kế hoạch POC có tiêu chí pass/fail viết trước — + thuộc Bước 5, **chưa lập**. `ASM-07`/`ASM-08` ở trên là ứng viên trực tiếp để nâng thành + `ARISK-nn` khi Bước 5 chạy. +- Thiết kế chi tiết ranh giới service/module (contract cụ thể, tên bảng, tên topic/queue) — + thuộc GĐ2 (`SAD`, `ADR`), **không** được vẽ ở đây dù đã có gợi ý từ `SAD.md`/hồ sơ thầu. +- Quyết định cuối cùng chọn P1 hay P2 (hay phương án lai) — đây là khuyến nghị của SA, **chưa + phải quyết định**; quyết định thật cần PO + Tech Lead ký (`OQ-011`). +- Đối chiếu chi tiết với `OQ-003` (giữ toàn sàn hay thu hẹp phạm vi) — cả ba phương án ở đây mô + tả kiến trúc tổng thể toàn sàn theo phạm vi đã chốt của lượt chạy này; nếu `OQ-003` sau này + quyết định thu hẹp, bảng chấm điểm có thể cần chấm lại với phạm vi hẹp hơn. + +--- + +## 9. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược | +|---|---|---|---|---|---| +| `OQ-010` | Tech Lead xác nhận: đội thi công **thật** (không phải đề xuất trong hồ sơ thầu) có kinh nghiệm vận hành production nào với Kafka/MSK, OpenSearch cluster, EKS chưa? Đây là input trực tiếp cho tiêu chí "Rủi ro kỹ thuật" đã chấm P1=2/P2=4 ở §4. | Tech Lead | 2026-09-12 | Điểm "Rủi ro kỹ thuật" của P1 trong `OPT`; `ARISK` Bước 5 | Nếu đội thật có kinh nghiệm Kafka/MSK/OpenSearch/EKS production: nâng điểm rủi ro kỹ thuật P1 lên 3–4, thu hẹp khoảng cách điểm tổng với P2 (từ 1.10 xuống có thể ~0.4–0.7) — vẫn cần xem lại tiêu chí "Năng lực team & vận hành" (Conway) vì đó không phụ thuộc kinh nghiệm công nghệ mà phụ thuộc **số người** so với **số service** | +| `OQ-011` | PO + Tech Lead chọn phương án nào giữa P1 (theo `SAD.md`/hồ sơ thầu hiện có) và P2 (khuyến nghị SA), hay yêu cầu SA dựng thêm phương án lai (VD P2 nhưng tách Catalog/Search từ đầu)? Đây chính là nội dung cần ký ở AG1 cho `OPT`. | PO + Tech Lead | 2026-09-12 | Ký AG1 cho `OPT`; bắt đầu Bước 5 (`TCO`/`ARISK`) theo đúng phương án đã chọn | Nếu chọn P1 dù rủi ro Conway cao: phải tăng team BE thật lên gần mức bid đề xuất (đỉnh điểm 10 người, chủ yếu BE) **hoặc** giảm số service xuống dưới 10 trước khi GĐ2 chốt ranh giới — nếu không, ranh giới service ở `SAD` GĐ2 sẽ vi phạm Conway ngay từ thiết kế, phát hiện muộn hơn và tốn hơn theo đúng cảnh báo của `GUIDE.md` | +| `OQ-012` | Có cần chạy POC đo throughput SQS/EventBridge (`ASM-07`) **trước khi** chốt P2 làm phương án chính thức, hay chấp nhận rủi ro tạm thời và bổ sung `ARISK` + kế hoạch POC ở Bước 5 rồi mới đo? | Tech Lead | 2026-09-12 | `ADR` message backbone ở GĐ2; kế hoạch POC ở `ARISK` Bước 5 | Nếu không đo trước khi chốt `ADR` GĐ2 mà đo sau mới phát hiện SQS/EventBridge không đủ throughput: phải viết lại `ADR` (Supersede) sau khi đã thiết kế chi tiết — tốn hơn phát hiện ở GĐ1 theo đúng nguyên tắc `workflow.md §6` "GĐ2 → GĐ1" | + +--- + +## Tự chấm + +### ① Bảng tự chấm Gate AG1 *(`workflow.md §2`, cập nhật từ `CTX`)* + +| # | Tiêu chí | ☐/✅ | Ghi chú | +|---|---|---|---| +| 1 | `CTX` có `DRV-nn`, mỗi driver ghi rõ áp lực kinh doanh | ✅ | Không đổi — xem `CTX §2` | +| 2 | `CTX` có `CON-nn` (ràng buộc 6 nhóm) | ✅ *(với lưu ý)* | Không đổi — xem `CTX §3` | +| 3 | `CTX` mô tả hiện trạng as-is | ✅ *(với lưu ý)* | Không đổi — xem `CTX §4` | +| 4 | `OPT` có ≥2 phương án được chấm điểm, nêu rõ phương án bị loại + lý do | ✅ | **Mới đạt ở lượt này** — 3 phương án chấm điểm (P0, P1, P2) + 2 phương án bị loại có lý do gắn `CON`/`DRV` cụ thể (P3, P4). Trọng số tiêu chí **chưa qua buổi duyệt riêng với PO/Tech Lead** (`ASM-09`) — đây là hạn chế cần ghi nhận, không phải lý do đánh rớt tiêu chí này (tiêu chí AG1 chỉ đòi hỏi "có ≥2 phương án chấm điểm + nêu loại", không đòi hỏi trọng số đã duyệt) | +| 5 | `TCO` có chi phí 3 năm, ≥2 kịch bản tải | ☐ | **Chưa tạo file `TCO`** — thuộc Bước 5, ngoài phạm vi lượt chạy này. `OPT` chỉ so sánh số lượng/loại thành phần hạ tầng, không phải VND | +| 6 | `ARISK` có rủi ro cao kèm chủ + biện pháp | ☐ | **Chưa tạo file `ARISK`** — thuộc Bước 5. `ASM-07`/`ASM-08` ở §8 là ứng viên trực tiếp để nâng thành `ARISK-nn` | +| 7 | Rủi ro cao chưa chứng minh được có kế hoạch POC | ☐ | Phụ thuộc `ARISK`, chưa làm. `OQ-012` đã đặt câu hỏi về thời điểm chạy POC SQS/EventBridge | + +**Kết luận tự chấm AG1:** **Vẫn chưa đủ điều kiện ký** — 4/7 tiêu chí ✅ (tăng từ 3/7 ở `CTX`). +Cần Bước 5 (`TCO`, `ARISK` + kế hoạch POC) trước khi PO + Tech Lead có thể ký AG1 đầy đủ. Ngay +cả khi ký AG1 chỉ dựa trên `OPT` này, **khuyến nghị không ký cho tới khi `OQ-005`/`OQ-006`/ +`OQ-008`/`OQ-010`/`OQ-011` có câu trả lời** vì bảng chấm điểm ở đây dùng số liệu tham khảo hồ sơ +thầu (Draft), không phải số đã xác nhận. + +### ② Checklist D1–D12 *(`design-rules.md`)* + +| # | Mục | ☐/✅ | Ghi chú | +|---|---|---|---| +| D1 | Một ADR một quyết định | N/A | Tài liệu này không tạo `ADR` — quyết định kiến trúc chính thức (nếu có) sẽ thành `ADR` ở GĐ2 sau khi P1/P2 được PO/Tech Lead chọn | +| D2 | Không NFR định tính | N/A | `OPT` không chứa `QAS`; các con số hạ tầng dùng nguồn cụ thể (`estimate.computed.json`), không phải mô tả định tính | +| D3 | Nêu phương án bị loại + lý do gắn `CON`/`QAS` | ✅ | §5 — P3 loại vì `CON-06` (gate cứng); P4 loại vì `DRV-02`/`CON-05` (rủi ro + thiếu bằng chứng năng lực). Cả hai đều có điều kiện xét lại rõ ràng, không phải loại vĩnh viễn theo cảm tính | +| D4 | Sơ đồ khai báo mức C4 + legend | ✅ | P1/P2 đều khai báo "C4 mức Container", có bảng legend chung §3.3 giải thích từng loại mũi tên + sync/async | +| D5 | Interface có chủ/contract | N/A | Chưa tới `ICD` (GĐ2) — §3.4 `SAD.md` chỉ kế thừa nguyên trạng đề xuất, ghi rõ chưa xác minh sandbox thật (`CON-04`) | +| D6 | Phụ thuộc ngoài process có timeout/retry | N/A | Chưa tới `FAIL` (GĐ2); bảng legend §3.3 dòng 8/8b dẫn về `CTX §4.2`/`SAD.md §3.4` cho chi tiết timeout/retry hiện có (đề xuất, chưa kiểm chứng) | +| D7 | Một chủ sở hữu dữ liệu | ✅ *(ở mức khối)* | Cả P1 và P2 đều ghi rõ Payment có DB riêng, không service/module khác truy cập trực tiếp — chi tiết từng thực thể để `DAT` (GĐ2) | +| 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; `INF` khớp `TCO` | 🟡 Một phần | Mọi con số hạ tầng ở đây có **nguồn** (`estimate.computed.json`, `SAD.md §3.1-3.4`) nhưng **chưa quy ra tiền** — đúng theo yêu cầu "chỉ mức sơ bộ để so sánh tương đối" của ghi chú người duyệt; quy đổi VND đầy đủ + khớp `TCO`/`INF` là việc của Bước 5/GĐ2 | +| D10 | Không quyết định thay người có thẩm quyền | ✅ | §1 ghi rõ "khuyến nghị… chưa phải quyết định"; mọi lựa chọn cuối (P1 vs P2, trọng số tiêu chí, thời điểm chạy POC) đều để `OQ-010/011/012` kèm hệ quả phương án ngược bằng số/định tính cụ thể, không tự quyết | +| D11 | Có mục "Ngoài phạm vi" + `ASM-nn` | ✅ | §8 đầy đủ — `ASM-07/08/09` mới, có cách xác minh/chủ/hạn; mục "Ngoài phạm vi" liệt kê rõ `TCO`/`ARISK`/thiết kế chi tiết GĐ2/quyết định cuối cùng đều chưa làm | +| D12 | Câu quy định thẩm quyền sơ đồ vs văn bản | ✅ | Có ngay sau Change Log | + +### ③ Danh sách `OQ` mở kèm người phải trả lời, chặn gì + +Ba câu hỏi mới của `OPT` (`OQ-010`, `OQ-011`, `OQ-012`) cộng với các câu hỏi còn mở từ `CTX` +(`OQ-001`, `OQ-002` *(đã đóng, xem `CTX`)*, `OQ-003`, `OQ-004`, `OQ-005`, `OQ-006`, `OQ-007`, +`OQ-008`) — xem sổ đầy đủ tại `00-index/OQ_e-commerce.md` (đã đồng bộ ở Change Log v1.5). +Ba câu quan trọng nhất cho việc ký AG1 của chính `OPT` này: **`OQ-011`** (chọn P1/P2 — chặn ký +AG1 trực tiếp), **`OQ-010`** (kinh nghiệm team thật — chặn độ tin cậy điểm "Rủi ro kỹ thuật"), +**`OQ-005`/`OQ-006`/`OQ-008`** (ngân sách/deadline/team thật — chặn `TCO`/`ARISK` Bước 5 có ý +nghĩa). + +**Nhắc:** AG1 cần **PO + Tech Lead ký** (điền `Approved by` vào header file này) trước khi chạy +`/sa-2-architecture`. Cần chạy tiếp Bước 5 (`TCO`, `ARISK`) của `sa-1-context` trước khi bảng tự +chấm AG1 đạt đủ 7/7 tiêu chí. diff --git a/sa-output/e-commerce/01-context/TCO_e-commerce_v1.0.md b/sa-output/e-commerce/01-context/TCO_e-commerce_v1.0.md new file mode 100644 index 0000000..25331fa --- /dev/null +++ b/sa-output/e-commerce/01-context/TCO_e-commerce_v1.0.md @@ -0,0 +1,397 @@ +# TCO — Cost Model — e-commerce · Phương án P2 (chính) và P1 (đối chiếu) + +| | | +|---|---| +| **Version** | 1.1 | +| **Date** | 2026-09-12 | +| **Author** | SA (skill sa-1-context, chế độ `go`, hoạt động `cost-risk`) | +| **Status** | 🟡 Draft *(duyệt từng phần — xem `Approved by`; chấp nhận cấu trúc 4 nhóm chi phí (§3–§6), 2 kịch bản tải A/B (§2), và kết luận thứ tự tương đối "P2 rẻ hơn P1" ở cả hai kịch bản (§1, §7); đơn giá AWS (`ASM-11`), tỷ giá (`ASM-12`), số FTE vận hành (`ASM-14`) và 5 khoản non-labor (`OQ-013…017`) **chưa xác nhận** — đây **chưa phải** AG1 toàn phần, Tech Lead chưa ký, `OQ-004` còn mở; xem "Tự chấm" §①)* | +| **Approved by** | PO (uỷ quyền, chế độ chạy thử): **Điều phối dự án** — duyệt **từng phần** bản v1.1 · 2026-09-12 (sau khi đã sửa lỗi chép số §1 P2-B: dòng "Vận hành/nhân sự (3 năm)" P2-B = 5.600 triệu, Tổng 3 năm P2-B = 13.977,5 triệu): chấp nhận cấu trúc 4 nhóm chi phí (hạ tầng AWS · license/SaaS · vận hành/nhân sự · chi phí một lần xây dựng), 2 kịch bản tải A/B, và kết luận thứ tự tương đối **P2 rẻ hơn P1** ở cả hai kịch bản. **Chưa xác nhận** (giữ `Confidence` 🔴): đơn giá AWS (`ASM-11`), tỷ giá quy đổi USD/VND (`ASM-12`), số FTE đội Ops (`ASM-14`), và 5 khoản non-labor chưa tính được (`OQ-013…017`). Ký thay PO theo ngoại lệ `DEC-01` (SA), ghi thêm `DEC-09`; **không phải chữ ký PO/Tech Lead thật** — `OQ-004` giữ mở. Status **giữ** 🟡 Draft — AG1 toàn phần vẫn chưa đủ điều kiện. · Tech Lead: — *(chưa ký)* | +| **Source** | `01-context/CTX_e-commerce_v1.0.md` (v1.2 trong header) §2 `DRV-04/05/06`, §3 `CON-01/02/03/04/05/08`, §4.1, §4.2, §4.4 · `01-context/OPT_e-commerce_v1.0.md` §1, §3 (P1/P2), §4, §8 `ASM-07/08/09` · `e-commerce/bid/estimate.computed.json` (`totals`, `cost`, `timeline`, `staffing`) · `e-commerce/bid/bid-config.md` (`rateCard`, `vatPct`) · `e-commerce/bid/40-financial-proposal.md` §C2–C5 · `e-commerce/docs/sections/03-kien-truc.md` §3.2–§3.4 · `e-commerce/docs/sections/09-van-hanh-kiem-thu.md` §9.3–§9.5 · `ba-output/e-commerce/01-discovery/RISK_CartCheckout_v1.0.md` (tham chiếu ID, không copy) | +| **Scope** | Chi phí 3 năm cho **P2** (modular monolith + managed AWS, Payment tách riêng — phương án chính theo `DEC-06`) và **P1** (modular microservices theo `SAD.md`/hồ sơ thầu — đối chiếu), mỗi phương án tính theo 2 kịch bản tải. Đơn vị tiền: **VND**. Đơn giá hạ tầng AWS quy đổi từ USD (khu vực tham chiếu `ap-southeast-1`, xem `ASM-11`) | +| **Confidence** | 🔴 Giả định chưa xác minh — kế thừa nguyên nhân của `CTX`/`OPT` (BA chưa ký G1, AG1 GĐ1 SA chưa từng chạy, ngoại lệ gate `DEC-01/03/04/05` tiếp tục ở `DEC-07`). Thêm hai lý do riêng của `TCO`: (a) đơn giá AWS **không** được truy vấn từ AWS Pricing Calculator/báo giá đại lý thời điểm hiện tại — là ước tính từ tri thức bảng giá công khai đã biết, **bắt buộc xác minh lại** trước khi PO dùng để duyệt ngân sách (`ASM-11`); (b) không có baseline tải thật (greenfield, `CTX §4.1`) nên toàn bộ kịch bản tải là giả định suy từ `DRV-04` (`ASM-10`), không phải đo lường | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | ADR/DEC | +|---|---|---|---|---| +| 1.1 | 2026-09-12 | SA (qua skill sa-1-context, chế độ `go`, hoạt động `cost-risk`) | Sửa lỗi chép số §1 P2-B theo phát hiện của người duyệt 2026-09-12: dòng "Vận hành/nhân sự (3 năm)" P2 — Kịch bản B đổi từ 5.800 triệu → **5.600 triệu** (đúng theo chi tiết cộng dồn ở §5: 5.400 nhân sự + 200 surge); Tổng 3 năm P2-B đổi từ 14.177,5 triệu (~14,18 tỷ) → **13.977,5 triệu (~13,98 tỷ)**, khớp số đã có sẵn ở §7. Viết lại ghi chú 🔴 "Ghi chú khớp số" ở §7 — nguyên nhân lệch là lỗi chép số ở §1, không phải làm tròn. Đã rà soát: dải tổng ở §1 "So sánh nhanh"/ARISK-07/OQ-005 (~11,2–19,1 tỷ) **không đổi** vì cận dưới (P2-A ~11,17 tỷ) và cận trên (P1-B ~19,06 tỷ) không liên quan tới ô bị sửa. Không sửa ARISK/OQ (không trích đúng con số 14.177,5/14,18). Không chạy lại ước lượng, không đổi Status/Confidence/Approved by. | — | +| 1.1 | 2026-09-12 | PO (uỷ quyền, Điều phối dự án) — tác vụ **sign/approve** | Duyệt **từng phần** bản v1.1 (sau khi sửa lỗi chép số §1 P2-B ở dòng trên): chấp nhận cấu trúc 4 nhóm chi phí, 2 kịch bản tải A/B, kết luận thứ tự tương đối **P2 rẻ hơn P1**. Không đổi nội dung chuyên môn. Đơn giá AWS (`ASM-11`), tỷ giá (`ASM-12`), số FTE vận hành (`ASM-14`) và 5 khoản non-labor (`OQ-013…017`) **chưa xác nhận** — `Confidence` giữ 🔴. Ký thay PO theo ngoại lệ `DEC-01` (SA), ghi thêm `DEC-09`; **không phải chữ ký PO/Tech Lead thật** — `OQ-004` giữ mở, Tech Lead **chưa ký**. Status **giữ** 🟡 Draft — AG1 toàn phần chưa đủ điều kiện (xem "Tự chấm" §①). | `DEC-09` | +| 1.0 | 2026-09-12 | SA (qua skill sa-1-context, chế độ `go`, hoạt động `cost-risk`) | Bản đầu — Bước 5 (phần `TCO`) của `sa-1-context`. Tính chi phí 3 năm cho P2 (chính, theo `DEC-06`) và P1 (đối chiếu) theo 2 kịch bản tải (A — tải dự kiến, B — đỉnh flash sale/tăng trưởng, neo `DRV-04`). Tách 4 nhóm: hạ tầng AWS · license/SaaS · vận hành/nhân sự · chi phí một lần (xây dựng). Mọi con số hạ tầng có công thức + nguồn hoặc gắn `ASM-nn` kèm cờ "cần xác minh" theo `D9`. 8 khoản non-labor còn `amount: null` trong `estimate.computed.json` được xử lý: NL-01/NL-02 (hạ tầng AWS, OpenSearch) tính bằng công thức riêng của SA (mục đích khác ước lượng thầu); NL-03/04/05/07/08 chưa có cơ sở tính (phí giao dịch/vận chuyển/pentest/đào tạo phụ thuộc hợp đồng nhà cung cấp) — ghi `OQ-014…OQ-017`. Tiếp tục ngoại lệ gate `DEC-01/03/04/05`, ghi thêm `DEC-07`. `Confidence` 🔴 toàn tài liệu. | `DEC-07` | + +> Sơ đồ thắng về **quan hệ và luồng** (không có sơ đồ mới trong tài liệu này — xem sơ đồ khối P1/P2 ở `OPT §3`). Bảng/văn bản thắng về **ràng buộc và con số**. Mâu thuẫn ngoài hai loại này là lỗi tài liệu (`D12`). + +--- + +## 0. Ghi chú Preflight & ngoại lệ gate — tiếp nối `CTX`/`OPT` + +Gate AG1 (PO + Tech Lead) chưa từng chạy cho dự án e-commerce; BA vẫn chưa ký G1 chính thức. +Người dùng (vai điều phối dự án chạy thử) **tái khẳng định muốn tiếp tục** sang phần `TCO` của +Bước 5 (`sa-1-context`) theo đúng ghi chú người duyệt của lượt chạy này. + +> **DEC-07 (SA)** — Tiếp tục chạy `sa-1-context` Bước 5 (phần `TCO`) cho e-commerce trong khi BA +> vẫn chưa qua G1 và AG1 vẫn chưa từng chạy — tiếp nối `DEC-01/03/04/05`. +> **Quyết định:** Tiếp tục, `Confidence 🔴` cho toàn bộ con số (giả định tải + giả định đơn giá +> AWS) cho tới khi có số liệu tải thật (sau go-live) và báo giá AWS/đại lý chính thức. +> **Người quyết:** Điều phối dự án (đại diện PO, dự án chạy thử). +> **Radar (ước lượng):** ~3–4 (chi phí đảo ngược thấp — sửa lại `TCO` khi có số thật không tốn +> nhiều · bán kính ảnh hưởng: `INF`/ngân sách GĐ2 phụ thuộc con số này nhưng bản thân việc ghi +> tài liệu dưới ngoại lệ thì nhỏ · chưa chạm một `QAS` cụ thể · không ràng buộc dài hạn · không +> tranh cãi mới, tiếp nối tiền lệ) → **ghi `DEC-nn`, không cần `ADR`**. +> **Hệ quả nếu không chấp nhận ngoại lệ:** dừng Bước 5, GĐ1 SA không đủ 4 artifact để audit AG1, +> chậm tiến độ chạy thử tương ứng thời gian BA/PO hoàn tất các điều kiện gate thật. + +🔴 **Lưu ý quan trọng cho người ký:** đơn giá AWS dưới đây **không phải báo giá thật** — đây là +ước tính dựa trên tri thức bảng giá công khai của AWS (không truy vấn AWS Pricing Calculator hay +báo giá đại lý tại thời điểm chạy skill này), khu vực tham chiếu `ap-southeast-1` (Singapore, gần +nhất với ràng buộc `CON-03`/`ASM-04` cho tới khi `OQ-007` xác nhận residency VN). **Bắt buộc** +chạy lại qua AWS Pricing Calculator hoặc xin báo giá đại lý AWS tại Việt Nam trước khi dùng các +con số này để duyệt ngân sách chính thức — xem `ASM-11`, `OQ-013`. + +--- + +## 1. Tóm tắt cho người quyết định + +| | P2 — Kịch bản A | P2 — Kịch bản B | P1 — Kịch bản A | P1 — Kịch bản B | +|---|---|---|---|---| +| **Chi phí một lần (xây dựng, đã VAT)** | 3.552,2 triệu | 3.552,2 triệu | 3.762,6 triệu | 3.762,6 triệu | +| **OpEx hạ tầng AWS (3 năm)** | 1.818,8 triệu | 4.425,8 triệu | 3.776,1 triệu | 7.339,2 triệu | +| **License/SaaS (3 năm)** | 349,5 triệu | 349,5 triệu | 409,5 triệu | 409,5 triệu | +| **Vận hành/nhân sự (3 năm)** | 5.400 triệu | 5.600 triệu | 6.750 triệu | 7.350 triệu | +| **Đào tạo (một lần, Năm 1)** | 50 triệu | 50 triệu | 200 triệu | 200 triệu | +| **Tổng 3 năm (VND)** | **≈ 11.170,5 triệu (~11,17 tỷ)** | **≈ 13.977,5 triệu (~13,98 tỷ)** | **≈ 14.898,2 triệu (~14,90 tỷ)** | **≈ 19.061,3 triệu (~19,06 tỷ)** | +| **So với `CON-01` (ngân sách duyệt)** | ❌ **Không đối chiếu được** — `CON-01` mới có số lao động build (~3,76 tỷ, từ hồ sơ thầu), **không có** ngân sách vận hành 3 năm đã duyệt để so sánh (`OQ-005` còn mở) | | | | + +🔴 **Phát hiện quan trọng nhất của `TCO` này, cần trình PO ngay:** con số duy nhất PO/tài chính +từng thấy (~3,76 tỷ VND, hồ sơ thầu) **chỉ là chi phí xây dựng một lần**. Chi phí vận hành 3 năm +(hạ tầng + license + con người) — phần mà mọi dự án thật sự phải trả sau go-live — **lớn hơn** +chi phí xây dựng ban đầu **2,1–4,0 lần** tuỳ phương án/kịch bản. Đây chính xác là điều `GUIDE.md` +cảnh báo: *"TCO ra con số quá lớn, khách sẽ sốc — đó là giá trị của TCO, không phải vấn đề của +nó."* `OQ-005` (ngân sách) cần được hỏi lại với con số full 3 năm này, không phải con số build. + +**P2 rẻ hơn P1 ở cả hai kịch bản** (~2,7 tỷ ở kịch bản A, ~4,9 tỷ ở kịch bản B) — khớp hướng +khuyến nghị định tính của `OPT` (P2 ít managed component hơn, không cần cụm Kafka/MSK + OpenSearch +đa node chạy 24/7 bất kể tải). + +--- + +## 2. Giả định tải — nền của mọi con số dưới đây + +*Dự án greenfield (`CTX §4.1`) — không có baseline tải thật. Toàn bộ số dưới đây là `ASM-10`, +suy từ `DRV-04` ("hàng trăm nghìn SKU, hàng trăm nghìn–hàng triệu user, đỉnh hàng nghìn–chục +nghìn concurrent user mùa flash sale"), chọn **cận dưới/giữa dải** cho kịch bản A và **cận dưới +của dải "chục nghìn"** cho kịch bản B — không phải số đo được.* + +| Chỉ số | Kịch bản A *(tải dự kiến)* | Kịch bản B *(đỉnh flash sale)* | Nguồn | +|---|---|---|---| +| Người dùng hoạt động | 200.000 | 600.000 | `ASM-10`, suy từ `DRV-04` | +| SKU | 300.000 | 500.000 (tăng trưởng) | `ASM-10` | +| Giao dịch/ngày (trung bình) | 5.000 đơn | 15.000 đơn (≈ 625 đơn/giờ đỉnh × hệ số dồn) | `ASM-10` | +| Giao dịch/giờ (đỉnh) | ~400 đơn/giờ | ~15.000 đơn/giờ (≈ 4,2 đơn/giây) | `ASM-10`, tương ứng "chục nghìn concurrent" của `DRV-04` | +| Concurrent user (đỉnh) | 2.000 | 10.000 | `ASM-10`, cận dưới dải `DRV-04` | +| Dung lượng dữ liệu năm 1 / 3 | ~50GB / ~110GB | ~80GB / ~200GB | `ASM-10` | +| Tốc độ tăng dữ liệu | ~5GB/tháng | ~10GB/tháng | `ASM-10` | +| Băng thông ra ngoài (egress qua CDN) | ~400GB/tháng | ~1.200GB/tháng (1,2TB) | `ASM-10` | + +🔴 **`ASM-10`** — Chủ: PM/Tech Lead. Cách xác minh: đo lại sau 4–6 tuần soft-launch (khớp +`DRV-02` §GOAL-01 của `CTX`), thay số giả định bằng số đo thật. Nếu sai lệch > 50%: toàn bộ bảng +chi phí hạ tầng bên dưới phải tính lại — đây là điểm nhạy cảm nhất của `TCO`, xem §8. + +--- + +## 3. Chi phí hạ tầng AWS — theo phương án + +*Tất cả đơn giá dưới đây: `ASM-11` — ước tính bảng giá công khai AWS, khu vực `ap-southeast-1`, +**không tra cứu API Pricing thời gian thực**, cờ 🔴 **cần xác minh**. Tỷ giá quy đổi dùng +`ASM-12`: 1 USD ≈ 25.000 VND (**cần xác minh tỷ giá thật tại ngày duyệt ngân sách**).* + +### 3.1 Đơn giá tham khảo dùng chung *(`ASM-11`, tất cả 🔴 cần xác minh)* + +| Hạng mục | Đơn giá ước tính (USD) | Nguồn/ghi chú | +|---|---|---| +| ECS Fargate (Linux/x86) | $0,0466/vCPU-giờ · $0,0051/GB-giờ | Bảng giá công khai AWS Fargate, `ap-southeast-1` | +| RDS PostgreSQL Multi-AZ, `db.r6g.xlarge` (4vCPU/32GB) | ≈ $0,973/giờ | Ước tính ~2× đơn giá Single-AZ tương ứng | +| RDS PostgreSQL Multi-AZ, `db.t4g.medium` (2vCPU/4GB) | ≈ $0,146/giờ | Ước tính, dùng cho DB nhỏ (Payment riêng, hoặc từng logic DB của P1) | +| RDS PostgreSQL Multi-AZ, `db.r6g.2xlarge` (8vCPU/64GB) | ≈ $1,946/giờ | Ước tính, dùng khi scale DB chính P2 kịch bản B | +| ElastiCache Redis `cache.r6g.large` | ≈ $0,252/giờ/node | Ước tính | +| ElastiCache Redis `cache.r6g.xlarge` | ≈ $0,504/giờ/node | Ước tính, dùng kịch bản B | +| Amazon MSK broker `kafka.m5.large` | ≈ $0,21/giờ/broker + $0,10/GB-tháng lưu trữ | Ước tính — **chỉ P1 dùng**, cụm tối thiểu 3 broker chạy 24/7 bất kể tải | +| OpenSearch `r6g.large.search` | ≈ $0,167/giờ/node + $0,135/GB-tháng EBS | Ước tính — P1 dùng ngay từ đầu (3 node tối thiểu); P2 hoãn dùng Postgres FTS ở kịch bản A | +| SQS/EventBridge | $0,40/triệu request (SQS chuẩn) · $1,00/triệu event (EventBridge) | Ước tính — rẻ, rủi ro nằm ở **throughput/độ trễ** (`ASM-07`), không phải chi phí | +| S3 Standard | $0,025/GB-tháng | Ước tính | +| CloudFront (egress) | ≈ $0,085/GB | Ước tính, tier đầu | +| WAF | $5/tháng + ~$1/rule + $0,60/triệu request | Ước tính | +| ALB | $0,0225/giờ + LCU | Ước tính | +| NAT Gateway (2 AZ) | $0,045/giờ/gateway + $0,045/GB xử lý | Ước tính | + +### 3.2 P2 — Modular monolith + managed AWS (phương án chính) + +| Hạng mục | Cấu hình (A) | Tiền/tháng (A) | Cấu hình (B) | Tiền/tháng (B) | +|---|---|---|---|---| +| Compute (ECS Fargate) — monolith + Payment | ~4 tasks×1vCPU/2GB (monolith) + 2 tasks×0,5vCPU/1GB (Payment) | ≈ $207 | ~10 tasks×1vCPU/2GB + 4 tasks×0,5vCPU/1GB | ≈ $498 | +| CSDL (RDS) — 1 cụm chính + Payment riêng | `r6g.xlarge` Multi-AZ + `t4g.medium` Multi-AZ (Payment) | ≈ $817 | `r6g.2xlarge` Multi-AZ + 1 read replica + Payment `r6g.large` Multi-AZ | ≈ $2.470 | +| Cache | `r6g.large` × 1 node | ≈ $184 | `r6g.xlarge` × 1 node + 1 replica | ≈ $736 | +| Message broker (SQS/EventBridge) | ~750K msg/tháng | ≈ $2 | ~2,25M msg/tháng | ≈ $6 | +| Lưu trữ đối tượng (S3) | ~500GB | ≈ $12,5 | ~1,5TB | ≈ $38 | +| Load balancer/gateway (ALB) | | ≈ $31 | | ≈ $61 | +| **Băng thông ra (CloudFront)** | ~400GB | ≈ $34 | ~1,2TB | ≈ $102 | +| WAF | | ≈ $25 | | ≈ $35 | +| NAT Gateway | | ≈ $85 | | ≈ $125 | +| Backup & DR | Automated backup + cross-region snapshot (Payment) | ≈ $30 | | ≈ $60 | +| Observability (log/metric/trace, ~25% hạ tầng — xem cảnh báo `cost-model.md` §3) | | ≈ $357 | | ≈ $1.033 | +| Môi trường non-prod (dev/stg, ~35% Production) | | ≈ $624 | | ≈ $700 | +| **Cộng hạ tầng/tháng (Production + non-prod)** | | **≈ $2.409** | | **≈ $5.862** | +| **Quy đổi VND/tháng** (`ASM-12`) | | **≈ 60,2 triệu** | | **≈ 146,6 triệu** | + +**P2 3 năm** *(Năm 1 = 5 tháng vận hành sau go-live tháng 7; Năm 2 = 12 tháng; Năm 3 = 12 tháng +× 1,1 tăng trưởng, `ASM-15`)*: + +| | Kịch bản A | Kịch bản B | +|---|---|---| +| Năm 1 (5 tháng) | 301,1 triệu | 732,8 triệu | +| Năm 2 (12 tháng) | 722,7 triệu | 1.758,6 triệu | +| Năm 3 (12 tháng × 1,1) | 795,0 triệu | 1.934,5 triệu | +| **Tổng hạ tầng 3 năm** | **1.818,8 triệu** | **4.425,8 triệu** | + +### 3.3 P1 — Modular microservices theo `SAD.md`/hồ sơ thầu (đối chiếu) + +| Hạng mục | Cấu hình (A) | Tiền/tháng (A) | Cấu hình (B) | Tiền/tháng (B) | +|---|---|---|---|---| +| Compute (ECS Fargate) — ~10 service × 2 task (HA) | 20 task × 0,5vCPU/1GB | ≈ $415 | scale ~40 task | ≈ $829 | +| CSDL (RDS) — ~10 logic DB Multi-AZ | 10 × `t4g.medium` Multi-AZ | ≈ $1.066 | 3 DB nâng `r6g.large` + 7 DB `t4g.medium` | ≈ $1.762 | +| **Message broker (Kafka/MSK) — chạy 24/7 bất kể tải** | 3 broker `m5.large` + 900GB lưu trữ | ≈ $550 | 6 broker + 1,8TB lưu trữ | ≈ $1.100 | +| **Search (OpenSearch, dùng ngay từ đầu)** | 3 node `r6g.large.search` + 300GB | ≈ $406 | 5 node + 500GB | ≈ $677 | +| Cache | `r6g.large` × 1 node | ≈ $184 | `r6g.xlarge` + 1 replica | ≈ $736 | +| Lưu trữ đối tượng (S3) | ~500GB | ≈ $12,5 | ~1,5TB | ≈ $38 | +| Load balancer/gateway | | ≈ $31 | | ≈ $61 | +| Băng thông ra (CloudFront) | ~400GB | ≈ $34 | ~1,2TB | ≈ $102 | +| WAF | | ≈ $25 | | ≈ $35 | +| NAT Gateway | | ≈ $85 | | ≈ $125 | +| Backup & DR (10 DB + 2 cụm) | | ≈ $50 | | ≈ $90 | +| Observability (~25%) | | ≈ $715 | | ≈ $1.389 | +| Môi trường non-prod (~40% — Kafka/OpenSearch tối thiểu vẫn cần ở Staging) | | ≈ $1.429 | | ≈ $2.777 | +| **Cộng hạ tầng/tháng** | | **≈ $5.002** | | **≈ $9.721** | +| **Quy đổi VND/tháng** | | **≈ 125,0 triệu** | | **≈ 243,0 triệu** | + +**P1 3 năm** *(cùng cách tính Năm 1/2/3 như P2)*: + +| | Kịch bản A | Kịch bản B | +|---|---|---| +| Năm 1 (5 tháng) | 625,2 triệu | 1.215,1 triệu | +| Năm 2 (12 tháng) | 1.500,5 triệu | 2.916,2 triệu | +| Năm 3 (12 tháng × 1,1) | 1.650,5 triệu | 3.207,9 triệu | +| **Tổng hạ tầng 3 năm** | **3.776,1 triệu** | **7.339,2 triệu** | + +🔴 Chênh lệch hạ tầng P1 so với P2 đến chủ yếu từ **hai cụm chạy 24/7 bất kể tải** (Kafka/MSK + +OpenSearch đa node) mà P1 phải có ngay từ ngày một, trong khi P2 hoãn OpenSearch và dùng +SQS/EventBridge managed (không cụm phải patch/scale) — đúng như nhận định định tính ở `OPT §4`. + +--- + +## 4. License & dịch vụ mua ngoài + +*Không phương án nào cần license phần mềm lõi thương mại (P3 — mua nền tảng — đã bị loại ở +`OPT §5`). Các dòng dưới đây là công cụ/dịch vụ hỗ trợ vận hành.* + +| Hạng mục | Mô hình tính giá | Đơn giá ước tính | P2/năm | P1/năm | Nguồn | +|---|---|---|---|---|---| +| PagerDuty/OpsGenie (on-call) | Theo user | ~$21/user/tháng × 5 user | ≈ 31,5 triệu | ≈ 31,5 triệu | `ASM-11`, đề xuất minh hoạ ở `docs/sections/09` §9.4.1 | +| Domain/SSL (ACM miễn phí + Route53) | Cố định | ~$15/năm domain + $6/tháng hosted zone | ≈ 5 triệu | ≈ 5 triệu | `ASM-11` | +| SAST/SCA/APM tooling (SonarQube/Snyk/X-Ray) | Theo seat/gói | Gói nhỏ ước tính | ≈ 80 triệu | ≈ 80 triệu | `ASM-11`, `docs/sections/09` §9.3.1 | +| Quản trị cụm Kafka/MSK bổ sung (Confluent Control Center hoặc tương đương) | — | — | N/A (không cần) | ≈ 20 triệu | Chỉ P1 cần — MSK cần công cụ giám sát cụm riêng | +| **Cộng/năm** | | | **≈ 116,5 triệu** | **≈ 136,5 triệu** | | +| **Cộng 3 năm** | | | **≈ 349,5 triệu** | **≈ 409,5 triệu** | | + +🔴 **Mô hình tính giá quan trọng hơn đơn giá** — PagerDuty tính theo user, tăng cùng quy mô đội +vận hành; nếu `OQ-008` (đội vận hành) trả lời số người lớn hơn 5, chi phí này tăng tuyến tính. + +**8 khoản non-labor trong hồ sơ thầu (`NL-01…NL-08`, `estimate.computed.json`) — đối chiếu:** + +| NL | Hạng mục | Xử lý trong `TCO` này | +|---|---|---| +| NL-01 | Hạ tầng cloud AWS năm đầu | Tính bằng công thức riêng ở §3 (không dùng số thầu, vì thầu chưa có số) | +| NL-02 | OpenSearch cluster | Tính trong §3 (P1: có ngay; P2: hoãn tới khi có bằng chứng cần) | +| NL-03 | Phí giao dịch VNPay/Momo | **Chưa tính được** — cần GMV (tổng giá trị giao dịch) giả định + biểu phí thật của VNPay/Momo, cả hai đều chưa có → `OQ-014` | +| NL-04 | Phí Email/SMS | **Chưa tính được** — nhà cung cấp cụ thể chưa chốt (`SAD.md §3.4`) nên chưa có biểu phí → `OQ-016` | +| NL-05 | Phí API GHN/GHTK | **Chưa tính được** — phí theo hợp đồng đơn vị vận chuyển, chưa có hợp đồng → `OQ-015` | +| NL-06 | Domain/SSL/WAF | Tính trong §3 (WAF) và §4 (domain/SSL) | +| NL-07 | Pentest/ASV | **Chưa tính được** — cần báo giá nhà cung cấp pentest tại VN, SA không có cơ sở để tự ước lượng đáng tin cậy → `OQ-017` | +| NL-08 | Đào tạo & tài liệu bàn giao | Trùng lặp một phần với §5 "Đào tạo" bên dưới (WBS-09 lao động đã tính trong chi phí xây dựng §6) — không cộng hai lần | + +--- + +## 5. Vận hành + +*Kế thừa giả định "team MVP chuẩn" `DEC-02` (🔴) — số người/kỹ năng thật chưa xác nhận +(`OQ-008` còn mở). `ASM-14`: giả định 2 FTE Ops/SRE (P2) hoặc 2,5 FTE (P1, do nhiều service + +Kafka/OpenSearch cần vận hành hơn) ở mức lương `DEVOPS` theo rate card hồ sơ thầu +(75.000.000 VND/người-tháng).* + +| Hạng mục | Cách tính | P2/năm | P1/năm | Nguồn | +|---|---|---|---|---| +| Nhân sự vận hành (Ops/SRE) | P2: 2 FTE × 75tr × 12 · P1: 2,5 FTE × 75tr × 12 | 1.800 triệu | 2.250 triệu | `ASM-14`, `DEC-02`, `bid-config.rateCard.DEVOPS` | +| Trực sự cố / surge mùa cao điểm (kịch bản B, chỉ Năm 2/3) | Ước tính phụ phí on-call mùa flash sale | +200 triệu (2 năm) | +600 triệu (2 năm) | `ASM-14` | +| Đào tạo kỹ năng mới *(sinh từ `CON-05`/`OQ-010`)* | P2: AWS ECS/SQS phổ biến hơn · P1: cần đào tạo Kafka/MSK/OpenSearch/EKS — kế thừa rủi ro năng lực team (`ARISK-05`) | 50 triệu (Năm 1, một lần) | 200 triệu (Năm 1, một lần) | `ASM-14`, tham chiếu `OPT §4` tiêu chí "Rủi ro kỹ thuật" | +| Công cụ (đã tính ở §4) | — | (xem §4) | (xem §4) | | +| **Cộng vận hành 3 năm (kịch bản A)** | | **5.400 triệu + 50 triệu = 5.450 triệu** | **6.750 triệu + 200 triệu = 6.950 triệu** | | +| **Cộng vận hành 3 năm (kịch bản B)** | | **5.400 + 200 + 50 = 5.650 triệu** | **6.750 + 600 + 200 = 7.550 triệu** | | + +🔴 `CON-05`/`OQ-008` chưa trả lời số đội vận hành thật — nếu đội thật nhỏ hơn 2 FTE (VD PO chỉ +định 1 người kiêm nhiệm), dòng này giảm nhưng rủi ro không đáp ứng `DRV-05` (99.9% uptime, +escalation 24/7) tăng — đây là đánh đổi PO/PM phải quyết, không phải SA tự chọn số nhỏ hơn cho +`TCO` đẹp hơn. + +--- + +## 6. Chi phí xây dựng (một lần) + +*Lấy nền từ `estimate.computed.json`/`40-financial-proposal.md` §C2–C5 (lao động dự thầu). Vì +hồ sơ thầu ước lượng theo kiến trúc gốc kiểu P1 (Kafka/MSK, `WBS-03` XL/high risk, 52 MD + 18,2 MD +dự phòng = 70,2 MD), P2 cần tách riêng: SQS/EventBridge managed nhẹ hơn đáng kể — `ASM-13` ước +tính effort `WBS-03` tương đương P2 chỉ bằng ~30% P1 (15,6 MD cơ sở + 20% dự phòng thấp hơn vì +rủi ro công nghệ managed thấp hơn = 18,7 MD), **chưa qua ước lượng lại chi tiết của nhà thầu**.* + +| Hạng mục | P1 (theo hồ sơ thầu, VND) | P2 (điều chỉnh theo `ASM-13`, VND) | +|---|---|---| +| Lao động (43 hạng mục WBS, 53,02 MM) | 3.420.500.000 | 3.420.500.000 − 191.200.000 *(giảm `WBS-03`)* ≈ **3.229.300.000** | +| VAT (10%) | 342.050.000 | 322.930.000 | +| **Tổng (đã VAT)** | **3.762.550.000** | **3.552.230.000** | + +Chi tiết `ASM-13` (công thức giảm `WBS-03`): P1 `WBS-03` = 70,2 MD, đơn giá bình quân theo tỷ +trọng vai trò tham gia (PM 3,85% · SA 28,85% · BE 48,08% · DEVOPS 19,23%) ≈ 3.714.000 VND/MD ⇒ +70,2 MD × 3.714.000 ≈ **260,7 triệu VND**. P2 `WBS-03` ước 18,7 MD cùng tỷ trọng ⇒ 18,7 × 3.714.000 +≈ **69,5 triệu VND**. Chênh lệch ≈ **191,2 triệu VND** (chưa VAT), khớp hướng "**-70,2 MD** so với +P1" đã nêu ở `OPT §6`. + +🔴 **`ASM-13`** — Chủ: Tech Lead + PM. Cách xác minh: nhà thầu/đội thi công ước lượng lại WBS-03 +riêng cho kiến trúc P2 (SQS/EventBridge) thay vì suy tỷ lệ %. Hệ quả nếu sai: chi phí xây dựng +một lần của P2 có thể lệch ±100–150 triệu VND so với số ở trên — không đổi kết luận "P2 rẻ hơn +P1" (chênh lệch hạ tầng 3 năm lớn hơn nhiều biên độ sai số này). + +Effort nghiệp vụ (`WBS-18…43`) **không đổi** giữa P1/P2 (đã xác nhận ở `OPT §6`) — không lặp lại +bảng chi tiết ở đây, chỉ tham chiếu `40-financial-proposal.md` §C2. + +--- + +## 7. Tổng hợp 3 năm + +| Nhóm | P2 — A | P2 — B | P1 — A | P1 — B | +|---|---|---|---|---| +| Hạ tầng | 1.818,8 triệu | 4.425,8 triệu | 3.776,1 triệu | 7.339,2 triệu | +| License | 349,5 triệu | 349,5 triệu | 409,5 triệu | 409,5 triệu | +| Vận hành (gồm đào tạo) | 5.450 triệu | 5.650 triệu | 6.950 triệu | 7.550 triệu | +| Xây dựng (một lần, Năm 1) | 3.552,2 triệu | 3.552,2 triệu | 3.762,6 triệu | 3.762,6 triệu | +| **Tổng 3 năm** | **11.170,5 triệu** | **13.977,5 triệu** | **14.898,2 triệu** | **19.061,3 triệu** | + +**Ghi chú khớp số (sửa tại v1.1):** bảng §1 trước đây (v1.0) ghi nhầm dòng "Vận hành/nhân sự (3 +năm)" của P2 — Kịch bản B là 5.800 triệu và Tổng 3 năm là 14.177,5 triệu (~14,18 tỷ) — đây là +**lỗi chép số ở §1**, không phải sai lệch do làm tròn. Số đúng theo chi tiết cộng dồn ở §5 (2 FTE +× 75tr × 12 × 3 năm = 5.400 triệu + surge kịch bản B 200 triệu = 5.600 triệu; cộng đào tạo 50 +triệu = 5.650 triệu vận hành, khớp dòng "Vận hành (gồm đào tạo)" ở bảng này) là: dòng +"Vận hành/nhân sự (3 năm)" P2-B = **5.600 triệu**, Tổng 3 năm P2-B = **13.977,5 triệu (~13,98 +tỷ)**. Bảng §1 đã được sửa lại khớp số này (xem Change Log v1.1). Các cột P2-A, P1-A, P1-B không +bị ảnh hưởng bởi lỗi này. + +--- + +## 8. Điểm nhạy cảm + +| Giả định | Nếu sai ±50% thì tổng 3 năm lệch | Cách giảm bất định | +|---|---|---| +| `ASM-10` (kịch bản tải) | Có thể đổi hẳn kịch bản áp dụng (A↔B), chênh lệch tới ~3–5 tỷ VND | Đo tải thật sau soft-launch 4–6 tuần (khớp `DRV-02`) | +| `ASM-11` (đơn giá AWS) | ±50% đơn giá ⇒ hạ tầng 3 năm lệch ±0,9–3,7 tỷ VND tuỳ phương án/kịch bản | Chạy AWS Pricing Calculator thật hoặc xin báo giá đại lý AWS tại VN trước khi duyệt ngân sách | +| `ASM-12` (tỷ giá USD/VND) | Tỷ lệ thuận với toàn bộ dòng hạ tầng | Dùng tỷ giá bán ra của ngân hàng tại ngày lập ngân sách chính thức | +| `ASM-14` (số FTE vận hành) | ±50% ⇒ lệch ±2,7–3,5 tỷ VND (dòng chi phí lớn nhất trong toàn `TCO`) | `OQ-008` cần trả lời trước khi con số này được coi là đáng tin | +| `ASM-13` (tách effort xây dựng P2) | ±100–150 triệu VND (biên độ nhỏ so với tổng) | Ước lượng lại WBS-03 riêng cho P2 khi vào GĐ2 | + +🔴 **Dòng nhạy cảm nhất là `ASM-14` (vận hành/nhân sự)** — không phải hạ tầng AWS như trực giác +thường nghĩ. Nếu PO/PM chỉ có thể xác nhận 1 điều trước khi dùng `TCO` này, nên là `OQ-008`. + +--- + +## 9. Điểm hoà vốn so với P0 *(giữ nguyên hiện trạng)* + +**Không áp dụng theo đúng nghĩa template** — dự án là **greenfield** (`CTX §4.1`, `OPT` P0): +không có hệ thống/chi phí vận hành hiện tại để so sánh, và P0 ("không làm gì") không tạo ra +doanh thu để tính "tiết kiệm được". `OPT §3` đã ghi rõ: hệ quả của P0 là **định tính nghiêm +trọng nhất** (chặn toàn bộ mô hình kinh doanh marketplace theo `DRV-01`) nhưng **không quy ra +được một con số tiền cụ thể** vì không có doanh thu mục tiêu bằng số trong nguồn hiện có. Đây là +giới hạn đã biết của lượt chạy này — không phải SA bỏ sót. + +--- + +## 10. Giả định & Ngoài phạm vi + +**Giả định** *(tiếp số từ `CTX §5`/`OPT §8`, bắt đầu `ASM-10`)*: + +| ID | Giả định | Nếu sai | +|---|---|---| +| `ASM-10` | Kịch bản tải A/B (§2) phản ánh đúng độ lớn thực tế của `DRV-04` | Toàn bộ `TCO` phải tính lại theo kịch bản đúng | +| `ASM-11` | Đơn giá AWS `ap-southeast-1` ước tính ở §3.1 gần đúng với giá thật tại thời điểm duyệt ngân sách | Chi phí hạ tầng 3 năm lệch tỷ lệ thuận — xem §8 | +| `ASM-12` | Tỷ giá 1 USD ≈ 25.000 VND giữ ổn định trong 3 năm | Chi phí hạ tầng lệch theo biến động tỷ giá thật | +| `ASM-13` | Effort xây dựng `WBS-03` của P2 ước bằng ~30% P1 theo tỷ lệ suy diễn, chưa qua ước lượng lại chi tiết | Chi phí xây dựng một lần của P2 lệch ±100–150 triệu VND | +| `ASM-14` | Đội vận hành 2 FTE (P2)/2,5 FTE (P1) đủ đáp ứng `DRV-05` (99.9% uptime, escalation 24/7) | Nếu đội thật nhỏ hơn: rủi ro không đạt `DRV-05`; nếu lớn hơn: chi phí vận hành tăng — xem `ARISK-08` | +| `ASM-15` | Tăng trưởng chi phí hạ tầng Năm 3 so với Năm 2 là +10% (không có số liệu thị trường cụ thể, chỉ là hệ số làm tròn hợp lý) | Nếu tăng trưởng thật nhanh hơn (VD traffic tăng gấp đôi mỗi năm theo mô hình kinh doanh thành công), Năm 3 phải tính lại theo đúng kịch bản B hoặc kịch bản mới | + +**Ngoài phạm vi:** + +- Phí giao dịch VNPay/Momo, phí API GHN/GHTK, phí Email/SMS, phí pentest/ASV — không tính được + vì thiếu biểu phí/hợp đồng nhà cung cấp thật, xem `OQ-014…OQ-017`. +- Chi phí dịch thuật nội dung đa ngôn ngữ (`FR-15`) — đã loại trừ tường minh trong + `40-financial-proposal.md` §C1.1, không thuộc `TCO` kiến trúc này. +- Ứng dụng di động native, affiliate marketing, subscription, hoá đơn điện tử tự động cho seller, + SSO doanh nghiệp — ngoài phạm vi MVP theo `40-financial-proposal.md` §C1.1 và `CON-07`. +- Chi phí cơ hội của việc trì hoãn go-live (P0) — không quy ra được số, xem §9. +- Kịch bản lai (P2 + Kafka/MSK riêng cho hot-path nếu `POC-01` fail) — chưa tính; nếu `POC-01` + (xem `ARISK_e-commerce_v1.0.md`) thất bại, `TCO` P2 phải cộng thêm một phần chi phí MSK của P1 + (§3.3, dòng "Message broker") cho riêng hot-path đặt hàng. + +--- + +## Tự chấm + +### ① Bảng tự chấm Gate AG1 *(`workflow.md §2`, cập nhật từ `CTX`/`OPT`)* + +| # | Tiêu chí | ☐/✅ | Ghi chú | +|---|---|---|---| +| 1 | `CTX` có `DRV-nn` | ✅ | Không đổi — xem `CTX §2` | +| 2 | `CTX` có `CON-nn` | ✅ *(với lưu ý)* | Không đổi — xem `CTX §3` | +| 3 | `CTX` mô tả hiện trạng as-is | ✅ *(với lưu ý)* | Không đổi — xem `CTX §4` | +| 4 | `OPT` có ≥2 phương án, chấm điểm, nêu phương án bị loại | ✅ | Không đổi — xem `OPT §4`/§5 | +| 5 | `TCO` có chi phí 3 năm, ≥2 kịch bản tải | ✅ | **Mới đạt ở lượt này** — §1/§3/§7, 2 phương án × 2 kịch bản tải, tách 4 nhóm (hạ tầng/license/vận hành/xây dựng). Đơn giá AWS/tỷ giá/GMV nhiều chỗ 🔴 chưa xác minh (`OQ-013…017`) — đạt tiêu chí "có mặt và đủ cấu trúc", chưa đạt mức "số đã xác nhận thật" | +| 6 | `ARISK` có rủi ro cao kèm chủ + biện pháp | ✅ | Xem `ARISK_e-commerce_v1.0.md` §3 — 6 rủi ro 🔴, mỗi cái có chủ + biện pháp cụ thể (không phải "sẽ theo dõi") | +| 7 | Rủi ro cao chưa chứng minh được có kế hoạch POC | ✅ | Xem `ARISK_e-commerce_v1.0.md` §6 — `POC-01`/`POC-02` có tiêu chí pass/fail viết trước | + +**Kết luận tự chấm AG1:** **7/7 tiêu chí có mặt về mặt cấu trúc** — GĐ1 SA nay đủ 4 artifact +(`CTX`/`OPT`/`TCO`/`ARISK`) để audit AG1. **Nhưng chưa đủ điều kiện ký chính thức**: nhiều dòng +vẫn ở `Confidence` 🔴 vì (a) BA chưa ký G1 thật, (b) `OQ-005/006/007/008/010/012` (ngân sách, +deadline, residency, đội vận hành, năng lực team, thời điểm POC) còn mở, (c) `OQ-013…017` (đơn +giá AWS, phí đối tác) mới phát sinh ở `TCO`. Khuyến nghị: chạy `POC-01`/`POC-02` và trả lời tối +thiểu `OQ-005`/`OQ-008`/`OQ-010` trước khi PO + Tech Lead ký AG1 thật. + +### ② Checklist D1–D12 *(`design-rules.md`)* + +| # | Mục | ☐/✅ | Ghi chú | +|---|---|---|---| +| D1 | Một ADR một quyết định | N/A | Tài liệu này không có `ADR` | +| D2 | Không NFR định tính | N/A | `TCO` không chứa `QAS` | +| D3 | Nêu phương án bị loại + lý do | N/A | Đã nêu ở `OPT §5`; `TCO` chỉ định lượng hai phương án còn lại | +| D4 | Sơ đồ khai báo mức + legend | N/A | Không có sơ đồ mới ở `TCO` | +| D5 | Interface có chủ/contract | N/A | Chưa tới `ICD` | +| D6 | Phụ thuộc ngoài process có timeout/retry | N/A | Chưa tới `FAIL` | +| D7 | Một chủ sở hữu dữ liệu | N/A | Chưa tới `DAT` | +| D8 | Ràng buộc có FIT hoặc nhãn khuyến nghị | N/A | Chưa tới `AGD`/`FIT` | +| D9 | Con số hạ tầng quy ra tiền + nguồn; `INF` khớp `TCO` | ✅ *(với cờ cần xác minh)* | Mọi dòng hạ tầng ở §3 có công thức + đơn giá + nguồn (`ASM-11`, region, ngày tham chiếu ghi rõ "cần xác minh"); `INF` (GĐ2) sẽ phải khớp con số này hoặc giải thích chênh lệch | +| D10 | Không quyết định thay người có thẩm quyền | ✅ | Ngân sách vượt/không vượt để PO quyết (§1 "phát hiện quan trọng nhất"); mọi giả định đơn giá/FX/team đều gắn `OQ` kèm hệ quả, không tự quyết | +| D11 | Có mục "Ngoài phạm vi" + `ASM-nn` | ✅ | §10 đầy đủ, `ASM-10…15` 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 | + +### ③ Danh sách `OQ` mở kèm người phải trả lời, chặn gì + +`OQ-013…017` (mới, xem §4/§8) cộng các câu còn mở từ `CTX`/`OPT` (`OQ-001, 003, 004, 005, 006, +007, 008, 010, 012` — xem sổ đầy đủ `00-index/OQ_e-commerce.md`). Quan trọng nhất cho `TCO`: +**`OQ-005`** (ngân sách — chặn việc coi con số `TCO` này là "đã duyệt hay chưa"), **`OQ-008`** +(đội vận hành — dòng nhạy cảm nhất, xem §8), **`OQ-013`** (đơn giá AWS thật). + +**Nhắc:** AG1 cần **PO + Tech Lead ký** (điền `Approved by` vào header `OPT`) trước khi chạy +`/sa-2-architecture`. diff --git a/sa-output/e-commerce/02-architecture/ASR_e-commerce_v1.0.md b/sa-output/e-commerce/02-architecture/ASR_e-commerce_v1.0.md new file mode 100644 index 0000000..10e511e --- /dev/null +++ b/sa-output/e-commerce/02-architecture/ASR_e-commerce_v1.0.md @@ -0,0 +1,416 @@ +# ASR — Architecturally Significant Requirements — e-commerce + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-14 | +| **Author** | SA (skill sa-2-architecture, chế độ `go`, hoạt động `asr`) | +| **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 15 `ASR-001…015` (14 `Must` + 1 `Should`) đủ nguồn/"vì sao định hình kiến trúc"/cấu trúc bị ép, và chấp nhận danh sách 12 `ADR` ứng viên (`ADR-001…012`, §B2) với radar ước lượng đã ghi kèm; xác nhận `ADR-005`/`ADR-006`/`ADR-009` (radar ước lượng ≥8) **chỉ được chuyển `Accepted`** sau khi `POC-01`/`POC-02`/diễn tập DR (Ops/SRE) chạy xong, đúng `decision-radar.md §2`/§6 — không ký tắt qua bước đo. Chốt **TẠM** `OQ-024` (phương thức MFA Admin = TOTP app, theo `ASM-20`) và `OQ-025` (không dịch nội dung seller tự nhập ở MVP, chỉ i18n UI hệ thống, theo `ASM-21`) làm hướng đi tạm để `sad`/`sec` kế tiếp không nghẽn — **`OQ-024`/`OQ-025` giữ nguyên MỞ**, chờ Security/PO thật xác nhận, không coi là đã đóng. Ký thay Tech Lead theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký Tech Lead thật**. · 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**. `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-14`. | +| **Source** | `01-context/CTX_e-commerce_v1.0.md` (v1.2) §2 (`DRV-01…09`), §3 (`CON-01…09`) · `01-context/OPT_e-commerce_v1.0.md` §1, §3 (P2), §5 (P3/P4 loại), §8 (`ASM-07…09`) · `01-context/ARISK_e-commerce_v1.0.md` §3 (`ARISK-01…10`), §6 (`POC-01`/`POC-02`) · `02-architecture/QAS_e-commerce_v1.0.md` v1.0 (toàn bộ `QAS-001…014`, đặc biệt Phần B "Ghi chú phạm vi") · `00-index/OQ_e-commerce.md` v1.9 · `00-index/DEC_e-commerce.md` v1.10 · `00-index/DTM_e-commerce.md` §11 ("🟠 Nợ #1" — `ADR-001`) · `00-index/ADL_e-commerce.md` §8 (việc phải làm #1) · `ba-output/e-commerce/02-analysis/BR_CartCheckout_v1.0.md` (`BR-CART-01…09`) · `ba-output/e-commerce/02-analysis/RBAC_CartCheckout_v1.0.md` (`ROLE-01/02`, ma trận §2, §4, §6) · `ba-output/e-commerce/02-analysis/IMPACT_CartCheckout_v1.0.md` · `ba-output/e-commerce/03-specification/API_US002-003_v1.0.md` · `e-commerce/docs/sections/02-phan-tich-yeu-cau.md` (`NFR-01…08`) · `e-commerce/docs/sections/03-kien-truc.md` §3.1–§3.4 (tham khảo, kế thừa nguyên trạng — không thiết kế lại ở lượt này) | +| **Scope** | Toàn sàn e-commerce theo phương án **P2** (modular monolith + managed AWS, tách riêng Payment Service — `DEC-06`, chưa phải `ADR` chính thức). Chi tiết nhất: module **Giỏ hàng & Checkout** (US-002/003, `BR-CART-01…09`, `RBAC` `ROLE-01/02`). Chỉ hoạt động 2/9 của `sa-2-architecture` (**ASR**) — không tạo `SAD`/`ADR`/`ICD`/`DAT`/`SEC`/`INF`/`FAIL` ở lượt này; `QAS` (hoạt động 1) đã có ở `QAS_e-commerce_v1.0.md`, duyệt từng phần theo `DEC-12`. | +| **Confidence** | 🔴 Giả định chưa xác minh — theo yêu cầu điều phối. AG1 chưa có chữ ký PO/Tech Lead thật (`OQ-004` mở); `POC-01`/`POC-02` chưa chạy; BA chưa ký G1 cho `BRIEF_CartCheckout`; `QAS` nguồn của phần lớn `ASR` dưới đây cũng đang giữ `Confidence` 🔴 (xem `QAS_e-commerce_v1.0.md` header). Mọi `ASR` giữ mức thấp nhất cho tới khi: (a) AG1 ký thật, (b) `POC-01`/`POC-02` chạy xong, (c) các `OQ` nguồn (`OQ-002/007/010/012/018…025`) được trả lời. | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | ADR/DEC | +|---|---|---|---|---| +| 1.0 | 2026-09-14 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `asr`) | Bản đầu — chưng cất 15 `ASR-nnn` từ `DRV`/`CON`/`QAS` (GĐ1–2 SA) và `BR-CART`/`ROLE` (BA), bao phủ đủ 14 nhóm bắt buộc theo ghi chú người duyệt (tách đơn theo seller, Payment cô lập, webhook idempotent + đối soát, message backbone + giới hạn FIFO group, RDS gộp, ownership check, PII/residency, MFA Admin, HA/DR + drill, observability, AWS bắt buộc, đối tác thanh toán/vận chuyển, ranh giới module Conway, đa ngôn ngữ) cộng 1 `ASR` tổng thể (kiểu kiến trúc P2, gắn `ADR-001` đang nợ theo `DTM`/`ADL`). Mỗi `ASR` có nguồn, "vì sao định hình kiến trúc", cấu trúc bị ép, đánh giá radar ước lượng và `ADR` ứng viên (số dự kiến — hoạt động `adr` kế tiếp xác nhận lại thứ tự thật). Không viết `ADR` ở lượt này. Thêm `OQ-024`/`OQ-025` (phương thức MFA Admin, chủ sở hữu chiến lược i18n) và `ASM-19…21`. Ghi `DEC-13` (tiếp nối `DEC-01…12`, ngoại lệ gate tiếp tục GĐ2 hoạt động `asr`). Không sửa `QAS`/`CTX`/`OPT` đã duyệt từng phần. `Confidence` 🔴 toàn bộ. | `DEC-13` | +| 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 15 `ASR-001…015` (14 `Must` + 1 `Should`) và danh sách 12 `ADR` ứng viên (`ADR-001…012`, §B2) với radar ước lượng; xác nhận `ADR-005`/`ADR-006`/`ADR-009` (radar ≥8) chỉ được `Accepted` sau khi `POC-01`/`POC-02`/diễn tập DR chạy xong. Chốt **TẠM** `OQ-024` (MFA Admin = TOTP app, `ASM-20`) và `OQ-025` (không dịch nội dung seller tự nhập ở MVP, chỉ i18n UI hệ thống, `ASM-21`) làm hướng đi tạm — cả hai **giữ nguyên mở**, chờ Security/PO thật xác nhận. Không đổi nội dung chuyên môn. Security/Ops chưa ký; `OQ-004` mở; `Confidence` giữ 🔴; Status giữ 🟡 Draft; AG2 **chưa** ký. Ghi thêm `DEC-14`. | `DEC-14` | + +> Sơ đồ thắng về **quan hệ và luồng** — tài liệu này không có sơ đồ mới (chỉ bảng chưng cất yêu +> cầu). Bảng/văn bản thắng về **ràng buộc và con số**. Mâu thuẫn ngoài hai loại này 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 (gate GĐ1 SA) vẫn chưa được ký chính thức**, và **AG2 (gate của chính GĐ2) càng chưa tới +hạn** — tài liệu này mới là hoạt động 2/9 của GĐ2. Tình trạng kế thừa nguyên vẹn từ +`QAS_e-commerce_v1.0.md` §0 và `ARISK`/`OPT` §Tự chấm: AG1 4/4 artifact đủ cấu trúc nhưng nội +dung còn `OQ-004` (tính hợp lệ ký thay), `OQ-005/006/007/008/010/012` (số/người thật) mở, +`POC-01`/`POC-02` chưa chạy. + +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** +sang hoạt động 2 (`ASR`) của `sa-2-architecture`, sau khi hoạt động 1 (`QAS`) đã được duyệt từng +phần (`DEC-12`). Quyết định ngoại lệ này được ghi tại `DEC-13` dưới đây và tại sổ +`00-index/DEC_e-commerce.md`. + +> **DEC-13 (SA)** — Tiếp tục `sa-2-architecture` (hoạt động 2 — `ASR`) cho e-commerce trong khi +> AG1 chưa có chữ ký PO/Tech Lead thật và AG2 (gate của chính GĐ2) chưa tới hạn — tiếp nối +> `DEC-01…12`. +> **Quyết định:** Chưng cất 15 `ASR` từ `DRV`/`CON`/`QAS`/`BR-CART`/`ROLE` đã có, giữ +> `Confidence 🔴` cho tới khi nguồn tương ứng được xác nhận thật (đặc biệt: AG1 ký thật, +> `POC-01`/`POC-02` chạy xong, `OQ-002/007/010/012/018…025` được trả lời). +> **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 (chưng cất `ASR` từ tài liệu đã có, sửa lại +> không tốn nhiều nếu nguồn đổi) · bán kính ảnh hưởng: toàn bộ hoạt động `sad`/`adr` kế tiếp phụ +> thuộc danh sách này, nhưng bản thân *việc ghi tài liệu dưới ngoại lệ* thì nhỏ · có chạm `QAS` +> Must trực tiếp (đang chưng cất từ chính các `QAS` Must) nhưng chưa phải quyết định kiến trúc đã +> cam kết thi công · không ràng buộc dài hạn (danh sách `ASR` có thể sửa khi nguồn đổi, chưa phải +> `ADR` bất biến) · không tranh cãi mới, tiếp nối tiền lệ `DEC-11/12` → **ghi `DEC-nn`, không cần +> `ADR` cho việc chạy dưới ngoại lệ** (`decision-radar.md §1–§2`) — khác với các `ADR` ứng viên +> liệt kê ở §B2 dưới đây, việc đó vẫn để hoạt động `sad`/`adr` kế tiếp. +> **Hệ quả nếu không chấp nhận ngoại lệ:** dừng GĐ2 ở hoạt động `qas`, không có `ASR` để hoạt +> động `sad` (bắt buộc có trước theo thứ tự 1→2→3 của `SKILL.md`) dùng làm đầu vào — chậm tiến độ +> chạy thử tương ứng thời gian xử lý các `OQ` đang mở. + +🔴 **Nhắc quan trọng:** đây là hoạt động 2/9. `SAD` (hoạt động 3), `ADR`, `ICD`, `DAT`, `SEC`, +`INF`, `FAIL` **chưa được tạo**. Theo `SKILL.md`: "1→2→3 bắt buộc trước; 4–8 chạy song song +được" — `ASR` này là điều kiện đầu vào bắt buộc cho `SAD` (hoạt động 3) kế tiếp. + +--- + +# PHẦN B — Architecturally Significant Requirements + +## B0. Tóm tắt + +| Nhóm | Số `ASR` | Must | Should | Có ứng viên `ADR` | Chỉ cần `DEC` | +|---|---|---|---|---|---| +| Cấu trúc hệ thống (kiểu kiến trúc, ranh giới, tách đơn) | 3 (`ASR-001,003,014`) | 3/3 | — | 3/3 | 0 | +| Bảo mật & tuân thủ | 4 (`ASR-002,007,008,009`) | 3/4 | 1/4 *(MFA Admin Must, phần Seller Should)* | 3/4 | 1 (`ASR-009`, borderline) | +| Tích hợp & dữ liệu | 3 (`ASR-004,005,006`) | 3/3 | — | 3/3 | 0 | +| Hạ tầng & vận hành | 2 (`ASR-010,011`) | 2/2 | — | 2/2 | 0 | +| Ràng buộc nền tảng (đầu vào, không phải quyết định SA) | 1 (`ASR-012`) | 1/1 | — | 0/1 *(đã phản ánh trong `ADR-001`)* | — | +| Phụ thuộc bên ngoài | 1 (`ASR-013`) | 1/1 | — | 1/1 | 0 | +| Frontend / i18n | 1 (`ASR-015`) | — | 1/1 | 0/1 *(borderline)* | 1 | +| **Tổng** | **15** | **13/15** | **2/15** | **12/15** | **2/15** (+1 N/A) | + +**Đọc bảng:** 15 nằm trong khoảng "8–15 mục" khuyến nghị của `SKILL.md` §2 — không phải danh +sách 200 mục. Ba `ASR` không bắt buộc `ADR` (`ASR-009`, `ASR-012`, `ASR-015`) vẫn được giữ trong +sổ vì đều có `QAS` Must hoặc Should đứng sau (tiêu chí B1), chỉ khác ở việc quyết định cụ thể có +thể chốt bằng `DEC-nn`/`AGD` thay vì `ADR` bất biến. + +## B1. Tiêu chí một yêu cầu là `ASR` *(tham chiếu — xem đầy đủ ở `templates/quality-scenarios.md` §B1)* + +Có ≥ 1 điều: ép một **cấu trúc** · ép một **ràng buộc không đảo ngược** · ép một **đánh đổi** · +có `QAS` mức **Must** đứng sau. Mỗi `ASR` dưới đây ghi rõ đang thoả điều nào. + +## B2. Danh sách `ASR` — chi tiết + +### ASR-001 — Kiểu kiến trúc tổng thể phải là Modular Monolith + managed AWS, Payment tách riêng (P2) `[Must]` + +| | | +|---|---| +| **Phát biểu** | Toàn sàn phải được tổ chức thành 2–3 nhóm triển khai ECS Fargate (modular monolith theo domain), **không** phải ~10 microservices độc lập database-per-service (P1); duy nhất Payment Service tách hoàn toàn khỏi phần còn lại. | +| **Nguồn** | `DEC-06` (chọn P2, chưa phải `ADR`) · `OPT_e-commerce_v1.0.md` §1, §3, §4 (điểm 4.05 vs 2.95) · `CON-05` (năng lực team, Conway) · `CON-01`/`CON-02` (chi phí/thời gian) | +| **Vì sao định hình kiến trúc** | **Chi phí đổi sau cao** (đảo từ monolith sang microservices hay ngược lại tốn tái cấu trúc network/DB/CI-CD, không phải một buổi chiều) **+ cắt ngang mọi component** (mọi module — Catalog, Cart&Order, Seller, Commission, Promo, Review, Notify, Shipping — đều nằm trong ranh giới triển khai này) | +| **Ép ra cấu trúc gì** | Ranh giới triển khai (deployment boundary): tối đa 2–3 đơn vị ECS Fargate cho phần monolith + 1 đơn vị Payment riêng biệt mạng/IAM; 1 RDS chính schema-per-module (xem `ASR-006`); SQS/EventBridge thay Kafka/MSK (xem `ASR-005`) | +| **Quyết định cần `ADR`** | **Có — `ADR-001`** (số đã "nợ" theo `DTM §11`/`ADL §8`) — *"Kiểu kiến trúc tổng thể GĐ2 — Modular Monolith P2, không phải Microservices P1"*. Radar ước lượng **~7** (chi phí đảo ngược cao=2 · bán kính toàn hệ thống=2 · chạm `QAS` Must gián tiếp qua `QAS-005/006/009`=1 · ràng buộc ≥1 năm=2 · chưa tranh cãi mới=0). **Dưới ngưỡng 8 cứng nhưng vẫn cần `POC-01`/`POC-02` trước khi `Accepted`** vì bản thân `ASM-07`/`ASM-08` (SQS đủ throughput, RDS đủ tải gộp) chưa xác minh — nếu một trong hai `POC` fail, quyết định này phải viết lại một phần (kiến trúc lai), không phải toàn bộ. | +| **Trạng thái** | Đã ghi nhận — `ADR-001` chưa viết (hoạt động `sad`/`adr` kế tiếp phải viết ngay khi bắt đầu, theo cảnh báo đã có ở `DTM`/`ADL`) | + +--- + +### ASR-002 — Payment Service là biên cô lập PCI-DSS SAQ A, không lưu thông tin thẻ `[Must]` + +| | | +|---|---| +| **Phát biểu** | Payment Service phải là ranh giới mạng + IAM + dữ liệu (RDS riêng) hoàn toàn tách biệt khỏi phần monolith còn lại; hệ thống sàn không được lưu số thẻ/CVV ở bất kỳ đâu — mọi xử lý thẻ do VNPay/Momo thực hiện, sàn chỉ lưu `gateway_transaction_ref` + kết quả. | +| **Nguồn** | `DRV-03` (giảm phạm vi PCI-DSS) · `CON-06` (PCI-DSS SAQ A + NĐ13/2023, cứng) · `BR-CART-05` (BA, "Không lưu trữ thông tin thẻ thanh toán" — không thể đổi trong 1 năm) | +| **Vì sao định hình kiến trúc** | **Ràng buộc công nghệ/pháp lý không đảo ngược** (vi phạm PCI-DSS/hợp đồng với VNPay/Momo, không phải quyết định kỹ thuật có thể đổi ý sau) **+ cắt ngang** (mọi luồng chạm dữ liệu thanh toán trong toàn hệ thống phải đi qua đúng một biên này) | +| **Ép ra cấu trúc gì** | Payment Service = container riêng, network/IAM riêng, RDS riêng nhỏ (đã phản ánh sơ bộ ở `OPT §3` P2); mọi module khác chỉ nhận `gateway_transaction_ref`/`status`, không bao giờ nhận/lưu dữ liệu thẻ | +| **Quyết định cần `ADR`** | **Có — `ADR-002`** (dự kiến) — *"Payment Service là biên cô lập PCI-DSS SAQ A"*. Radar ước lượng **~7** (đảo ngược tốn — tách lại sau khi đã gộp nhầm sẽ phải audit lại toàn bộ luồng thẻ=2 · bán kính: mọi module chạm thanh toán=1 · chạm `QAS-011` Must (PII) gián tiếp=1 · ràng buộc pháp lý ≥1 năm, không thương lượng=2 · chưa tranh cãi=1). Không cần POC bắt buộc (không phải con số hiệu năng chưa đo — đây là ràng buộc pháp lý đã có sẵn), nhưng cần Security ký (theo `decision-radar.md §5`: bảo mật/quyền riêng tư do Security chốt). | +| **Trạng thái** | Đã ghi nhận — `ADR-002` chưa viết; input trực tiếp cho hoạt động `sec` (threat model) và `dat` (ownership dữ liệu Payment) kế tiếp | + +--- + +### ASR-003 — Tách đơn hàng theo seller khi checkout (Order cha / OrderSeller con) `[Must]` + +| | | +|---|---| +| **Phát biểu** | Khi checkout, hệ thống phải nhóm `CartItem` theo `seller_id` và tạo một `OrderSeller` (đơn con) riêng cho mỗi nhóm; `Order` (đơn cha) là tập hợp các `OrderSeller`, mỗi `OrderSeller` có vòng đời trạng thái độc lập. | +| **Nguồn** | `BR-CART-01` (BA) · `DRV-01` (blocker MVP) · `DRV-02` (bỏ giỏ đa seller) · `DRV-06` (minh bạch dòng tiền 3 bên) | +| **Vì sao định hình kiến trúc** | **Chi phí đổi sau cao** (đổi mô hình dữ liệu Order/OrderSeller sau go-live cần migrate toàn bộ đơn hàng lịch sử + sửa mọi module đọc `Order`) **+ cắt ngang nhiều component** (Cart&Order, Commission&Payout, Shipping&Fulfillment, Review đều phụ thuộc cấu trúc cha-con này) | +| **Ép ra cấu trúc gì** | Mô hình dữ liệu 1 `Order` — N `OrderSeller` — N `OrderItem`; mỗi `OrderSeller` là đơn vị hạch toán/vận chuyển/đối soát độc lập; ranh giới sở hữu dữ liệu giữa Cart&Order (tạo `Order`/`OrderSeller`) và Commission&Payout/Shipping (tiêu thụ) | +| **Quyết định cần `ADR`** | **Có — `ADR-003`** (dự kiến) — *"Mô hình Order/OrderSeller — tách đơn theo seller"*. Radar ước lượng **~6** (đảo ngược cao=2 · bán kính nhiều module=2 · chạm `QAS` Must gián tiếp (không có `QAS` số riêng nhưng là nền cho toàn luồng checkout `QAS-002`)=1 · ràng buộc ≥1 năm (mô hình dữ liệu lõi)=1 · ít tranh cãi, đã là mô hình kinh doanh đã chốt=0). *Lưu ý: cơ chế tách chi tiết "luôn đúng N đơn cho N seller, không gộp" vẫn phụ thuộc `OQ-011` (BA) chưa đóng — `ADR-003` phải chờ hoặc ghi rõ giả định.* | +| **Trạng thái** | Đã ghi nhận — `ADR-003` chưa viết; phụ thuộc `OQ-011` (BA) trước khi có thể coi là "Đã kiểm chứng" | + +--- + +### ASR-004 — Webhook xác nhận thanh toán phải idempotent + có job đối soát bù `[Must]` + +| | | +|---|---| +| **Phát biểu** | Cập nhật `Payment.status = success` chỉ được thực hiện khi webhook VNPay/Momo có chữ ký hợp lệ và xử lý **idempotent** (webhook gọi lại nhiều lần không tạo hiệu ứng phụ); đồng thời phải có job đối soát bù chạy định kỳ để phát hiện lệch trạng thái khi webhook trễ/mất. | +| **Nguồn** | `QAS-014` (đối soát ≤15 phút, đề xuất SA, `OQ-021`) · `DRV-08` (webhook chưa xác minh khả thi gần thời gian thực) · `BR-CART-06` (BA) · `ARISK-03` | +| **Vì sao định hình kiến trúc** | **Ép một đánh đổi** (không thể đảm bảo consistency mạnh cho trạng thái thanh toán vì phụ thuộc bên thứ ba — phải chấp nhận eventual consistency có giới hạn thời gian, đây là quyết định kiến trúc không phải chi tiết code) **+ cắt ngang** (chạm Payment Service, Cart&Order — cập nhật `OrderSeller.status`, và tầng quan sát được — job đối soát cần alerting riêng) | +| **Ép ra cấu trúc gì** | Idempotency key (theo `gateway_transaction_ref`) cho endpoint nhận webhook; job đối soát bù (reconciliation) chạy định kỳ, độc lập với luồng webhook chính; cần bảng log webhook đã nhận để so khớp | +| **Quyết định cần `ADR`** | **Có — `ADR-004`** (dự kiến) — *"Cơ chế idempotency & đối soát cho webhook thanh toán bên thứ ba"*. Radar ước lượng **~6** (đảo ngược trung bình-cao (đổi cơ chế đối soát sau khi có dữ liệu thật tốn công viết lại job + backfill)=1 · bán kính: Payment + Cart&Order + Observability=1 · chạm `QAS-014` Must trực tiếp=2 · ràng buộc trong khoảng GĐ2, có thể đổi khi có sandbox thật=1 · chưa tranh cãi=1). | +| **Trạng thái** | Đã ghi nhận — `ADR-004` chưa viết; phụ thuộc sandbox VNPay/Momo thật (`ARISK-03`, chưa có) để kiểm chứng | + +--- + +### ASR-005 — Message backbone SQS FIFO (per-seller group) + EventBridge cho luồng đặt hàng, có giới hạn thông lượng theo group `[Must]` + +| | | +|---|---| +| **Phát biểu** | Luồng sự kiện `OrderPlaced`/`PaymentConfirmed` phải dùng SQS FIFO (message group theo `seller_id`, đảm bảo thứ tự xử lý trong cùng seller) + EventBridge fan-out cho các consumer chuỗi sau đặt hàng (hoa hồng, payout, notify, loyalty); phải có phương án cho seller có volume cao chạm trần throughput của một message group. | +| **Nguồn** | `QAS-005` (≥100 msg/s sustained, p99 ≤2s, 0 mất message) · `ARISK-01` · `DEC-06` (P2 chọn SQS/EventBridge thay Kafka/MSK) · `ASM-07` (chưa xác minh) | +| **Vì sao định hình kiến trúc** | **Ràng buộc công nghệ không đảo ngược trong ngắn hạn** (đổi từ SQS/EventBridge sang Kafka/MSK sau khi đã có producer/consumer thật là viết lại toàn bộ tầng tích hợp bất đồng bộ, không phải cấu hình) **+ cắt ngang** (mọi module tiêu thụ event `OrderPlaced` — Commission, Payout, Notification, Loyalty — đều phụ thuộc cơ chế này) | +| **Ép ra cấu trúc gì** | SQS FIFO queue với message group key = `seller_id`; EventBridge rule cho fan-out ≥5 consumer; cơ chế giám sát riêng cho seller có volume cao (theo dõi/cảnh báo riêng theo `QAS` A4 xung đột dòng 2); **KHÔNG** dùng Kafka/MSK trừ khi `POC-01` fail | +| **Quyết định cần `ADR`** | **Có — `ADR-005`** (dự kiến) — *"Message backbone cho luồng đặt hàng — SQS FIFO + EventBridge"*. Radar ước lượng **~8** (đảo ngược cao=2 · bán kính nhiều module=2 · chạm `QAS-005` Must trực tiếp=2 · ràng buộc ≥1 năm (chọn message broker là quyết định dài hạn)=1 · chưa tranh cãi mới=1). **≥8 ⇒ theo `decision-radar.md §2`, `ADR` này không được chuyển `Accepted` khi chưa có `POC`/bài đo — `POC-01` (`ARISK §6`) chính là bài đo bắt buộc, hiện CHƯA CHẠY.** | +| **Trạng thái** | Đã ghi nhận — `ADR-005` chưa viết; **chặn `Accepted` cho tới khi `POC-01` chạy xong** (đã ghi ở `OQ-012`, `ARISK §6`) | + +--- + +### ASR-006 — Một cụm RDS PostgreSQL chính, schema-per-module, chịu tải ghi/đọc gộp (trừ Payment) `[Must]` + +| | | +|---|---| +| **Phát biểu** | Toàn bộ module ngoại trừ Payment phải dùng chung 1 cụm RDS PostgreSQL Multi-AZ, phân tách theo schema-per-module (ranh giới logic rõ ràng dù chung instance); cụm này phải chịu được tải ghi (checkout) + đọc (catalog) gộp ở tải đỉnh. | +| **Nguồn** | `QAS-006` (p95 write ≤300ms, p95 read ≤200ms, CPU <75%) · `ARISK-02` · `DEC-06` (P2) · `ASM-08` (chưa xác minh) | +| **Vì sao định hình kiến trúc** | **Chi phí đổi sau cao** (tách read replica/DB riêng cho từng module sau khi đã gộp là một dự án migration riêng, không phải config) **+ cắt ngang** (mọi module ngoài Payment — Catalog, Cart&Order, Seller, Commission, Promo, Review, Notify, Shipping — đều chia sẻ cùng một instance, một module quá tải ảnh hưởng tất cả) | +| **Ép ra cấu trúc gì** | 1 RDS instance chính (`db.r6g.xlarge` Multi-AZ theo `TCO`/`ARISK`, tham khảo — số thật thuộc hoạt động `inf`), schema riêng cho từng module, connection pool chia sẻ có giới hạn theo module để tránh một module chiếm hết pool | +| **Quyết định cần `ADR`** | **Có — `ADR-006`** (dự kiến) — *"Chiến lược dữ liệu — RDS gộp schema-per-module cho P2"*. Radar ước lượng **~8** (đảo ngược cao=2 · bán kính toàn bộ module ngoài Payment=2 · chạm `QAS-006` Must trực tiếp=2 · ràng buộc ≥1 năm=1 · chưa tranh cãi=1). **≥8 ⇒ bắt buộc `POC`/bài đo trước `Accepted` — `POC-02` (`ARISK §6`) là bài đo bắt buộc, hiện CHƯA CHẠY.** | +| **Trạng thái** | Đã ghi nhận — `ADR-006` chưa viết; **chặn `Accepted` cho tới khi `POC-02` chạy xong** | + +--- + +### ASR-007 — Mọi thao tác Cart/Order phải qua kiểm tra quyền sở hữu (ownership check) `[Must]` + +| | | +|---|---| +| **Phát biểu** | Mọi request đọc/sửa/xoá `Cart`/`CartItem`/`Order` phải được đối chiếu quyền sở hữu: Guest theo `session_id` của chính phiên, Customer theo `customer_id` của chính họ — 0% truy cập chéo (IDOR) thành công. | +| **Nguồn** | `QAS-010` (100% request qua kiểm tra, 0 IDOR thành công) · `RBAC_CartCheckout_v1.0.md` §2 (ma trận: "Xem giỏ hàng/đơn hàng của người khác" = ❌ cho cả `ROLE-01` Guest và `ROLE-02` Customer) | +| **Vì sao định hình kiến trúc** | **Ép một đánh đổi** (kiểm tra ownership mỗi request cạnh tranh trực tiếp với ngân sách latency `QAS-003`/`QAS-004` — đã ghi nhận ở `QAS` A4 xung đột dòng 1, cần quyết định cache ownership hay query DB mỗi lần) **+ cắt ngang** (mọi endpoint `GET`/`PATCH`/`DELETE` của `/v1/cart*` đều cần cùng một cơ chế) | +| **Ép ra cấu trúc gì** | Chỗ ra quyết định authz (API gateway hay từng service) phải nhất quán cho toàn bộ nhóm "giao dịch"; cần cơ chế cache session/ownership (VD Redis) nếu chọn tối ưu latency thay vì query DB mỗi request | +| **Quyết định cần `ADR`** | **Có — `ADR-007`** (dự kiến) — *"Chỗ ra quyết định ownership/authz cho Cart & Order — gateway hay service, có cache không"*. Radar ước lượng **~6** (đảo ngược trung bình=1 · bán kính: toàn bộ endpoint Cart&Order=1 · chạm `QAS-010` Must trực tiếp + xung đột trực tiếp với `QAS-003/004`=2 · ràng buộc trong khoảng GĐ2=1 · đã có xung đột ghi nhận ở `QAS` A4, cần Tech Lead quyết=1). | +| **Trạng thái** | Đã ghi nhận — `ADR-007` chưa viết; input trực tiếp cho hoạt động `sec` (mô hình phân quyền) và `sad` (nơi đặt logic authz) | + +--- + +### ASR-008 — Dữ liệu PII chia sẻ cho seller phải qua data-minimization + xác nhận residency NĐ13/2023 `[Must]` + +| | | +|---|---| +| **Phát biểu** | Khi tách đơn theo seller, chỉ những trường PII (địa chỉ, SĐT người nhận) thực sự cần thiết để giao hàng mới được chia sẻ cho seller tương ứng; toàn bộ dữ liệu này (và mọi PII khách hàng/seller khác) phải được xác nhận nơi lưu trữ (residency) đáp ứng NĐ13/2023 trước go-live. | +| **Nguồn** | `QAS-011` (100% trường PII đã rà soát, 0 trường dư thừa) · `CON-06` (NĐ13/2023, cứng) · `DRV-07` (chưa rà soát) · `ARISK-06` · `ASM-04` (`ap-southeast-1` chưa xác nhận đủ) | +| **Vì sao định hình kiến trúc** | **Ràng buộc pháp lý không đảo ngược** (vi phạm NĐ13/2023 là vi phạm pháp luật, không phải lựa chọn kỹ thuật) **+ cắt ngang** (mọi module có PII — Identity, Cart&Order khi tách đơn, Seller Management với KYC — đều chịu ràng buộc vùng lưu trữ và chính sách chia sẻ này) | +| **Ép ra cấu trúc gì** | Danh sách trường PII được phép truyền cho seller (whitelist, không phải blacklist); vùng lưu trữ dữ liệu (region AWS) phải được Legal/Security xác nhận; cơ chế che/ẩn field khi hiển thị cho seller (mức che — theo `RBAC` §4, chưa chốt) | +| **Quyết định cần `ADR`** | **Có — `ADR-008`** (dự kiến) — *"Vùng lưu trữ dữ liệu cá nhân & chính sách chia sẻ PII cho seller"*. Radar ước lượng **~7** (đảo ngược cao — đổi region sau go-live là migration dữ liệu thật=2 · bán kính nhiều module có PII=1 · chạm `QAS-011` Must trực tiếp=2 · ràng buộc pháp lý ≥1 năm, không thương lượng=2 · chưa tranh cãi (chờ người rà soát)=0). **Phủ quyết thuộc Security/Legal** (`decision-radar.md §5`), không phải SA — SA chỉ chuẩn bị danh sách trường để người đó rà soát (đã ghi ở `ARISK-06`). | +| **Trạng thái** | Đã ghi nhận — `ADR-008` chưa viết; **chặn hoàn toàn cho tới khi có đại diện Pháp chế/Bảo mật** (`OQ-007`, vẫn chưa có người sau cả GĐ1 lẫn hoạt động `qas`) | + +--- + +### ASR-009 — Đăng nhập Admin bắt buộc MFA (Seller khuyến khích, không bắt buộc) `[Must cho Admin / Should cho Seller]` + +| | | +|---|---| +| **Phát biểu** | 100% đăng nhập tài khoản Admin phải qua bước xác thực thứ hai (MFA); 0 lượt bypass được chấp nhận. Seller được khuyến khích bật MFA nhưng không bắt buộc ở MVP. | +| **Nguồn** | `QAS-012` (100% Admin qua MFA, Must; Seller Should) | +| **Vì sao định hình kiến trúc** | Chủ yếu **chạm `QAS` Must** (tiêu chí thứ tư của B1) — bán kính hẹp hơn các `ASR` khác (chỉ Identity/Admin module), chi phí đổi sau ở mức trung bình (thêm MFA sau go-live không tốn quá nhiều nếu thiết kế đúng ngay từ đầu, nhưng đổi phương thức MFA sau khi user đã đăng ký thì tốn UX) | +| **Ép ra cấu trúc gì** | Identity/Access module cần bước xác thực thứ hai (TOTP app / SMS OTP / khác — **chưa chốt phương thức cụ thể**, xem `OQ-024` mới) trong luồng đăng nhập Admin; cần lưu trạng thái MFA đã bật/thu hồi được | +| **Quyết định cần `ADR`** | **Không bắt buộc `ADR`** — radar ước lượng **~4** (đảo ngược trung bình=1 · bán kính hẹp, 1 module=0 · chạm `QAS-012` Must trực tiếp=2 · ràng buộc trong 1 release, có thể đổi nhà cung cấp MFA sau=1 · chưa tranh cãi=0). Theo `decision-radar.md §2` (3–4 điểm) ⇒ **`DEC-nn` là đủ** khi Tech Lead chốt phương thức cụ thể ở hoạt động `sec`. *Ngoại lệ: nếu chọn nhà cung cấp MFA bên thứ ba ràng buộc hợp đồng dài hạn, nâng lên `ADR` theo `decision-radar.md §4` "ngoại lệ tiền lệ".* | +| **Trạng thái** | Đã ghi nhận — quyết định cụ thể (phương thức MFA) để hoạt động `sec` chốt bằng `DEC-nn`, không nhất thiết `ADR` | + +--- + +### ASR-010 — HA/DR cho nhóm dịch vụ giao dịch lõi: RPO ≤15 phút, RTO ≤1 giờ, bắt buộc diễn tập trước AG2 `[Must]` + +| | | +|---|---| +| **Phát biểu** | Payment, Cart & Order, Identity & Access phải có khả năng khôi phục sau sự cố với RPO ≤15 phút và RTO ≤1 giờ; **con số này phải được chứng minh bằng diễn tập (failover drill) thật trước khi AG2 được ký** — không chấp nhận RTO/RPO chỉ tồn tại trên giấy. | +| **Nguồn** | `QAS-008` · `OQ-022` (đã chốt điều kiện qua `DEC-12`: diễn tập là điều kiện tiên quyết AG2) | +| **Vì sao định hình kiến trúc** | **Chi phí đổi sau cao** (thiết kế lại chiến lược backup/failover sau khi đã go-live là một dự án riêng, có rủi ro downtime khi thực hiện) **+ cắt ngang** (ảnh hưởng chiến lược backup, network, và runbook vận hành của cả 3 service lõi) **+ chạm `QAS` Must trực tiếp** | +| **Ép ra cấu trúc gì** | Chiến lược backup point-in-time (RPO ≤15 phút ⇒ tần suất backup/WAL archiving tương ứng); kiến trúc Multi-AZ + quy trình failover có runbook; **lịch diễn tập cụ thể — vẫn chưa có, `OQ-022` giữ mở chờ Ops/SRE** | +| **Quyết định cần `ADR`** | **Có — `ADR-009`** (dự kiến) — *"Chiến lược HA/DR cho nhóm dịch vụ giao dịch lõi"*. Radar ước lượng **~9** (đảo ngược cao=2 · bán kính 3 service lõi + toàn bộ vận hành=2 · chạm `QAS-008` Must trực tiếp=2 · ràng buộc hạ tầng ≥1 năm=2 · chưa tranh cãi nhưng con số kế thừa từ `SAD.md` chưa được SA thiết kế lại=1). **≥8 ⇒ bắt buộc bài đo (diễn tập DR) trước `Accepted`** — đây chính là điều kiện đã chốt ở `DEC-12`/`OQ-022`, nhất quán với `decision-radar.md §6`. | +| **Trạng thái** | Đã ghi nhận — `ADR-009` chưa viết; input bắt buộc cho hoạt động `inf` kế tiếp; **chặn `Accepted` cho tới khi diễn tập DR chạy** (đã là điều kiện ký AG2, không chỉ điều kiện `Accepted` của riêng ADR này) | + +--- + +### ASR-011 — Observability phải cảnh báo lỗi 5xx tăng đột biến trong ≤1 phút cho nhóm giao dịch lõi `[Must]` + +| | | +|---|---| +| **Phát biểu** | Sự cố lỗi 5xx tăng đột biến ở Cart & Order, Payment, Identity phải được cảnh báo tự động trong ≤1 phút; on-call phải acknowledge trong ≤15 phút. | +| **Nguồn** | `QAS-013` | +| **Vì sao định hình kiến trúc** | **Cắt ngang** (mọi service lõi cần cùng chuẩn logging/metric để pipeline cảnh báo hoạt động nhất quán) **+ chạm `QAS` Must trực tiếp**; chi phí đổi sau ở mức trung bình (đổi công cụ observability sau này khả thi nhưng tốn công di chuyển dashboard/alert đã cấu hình) | +| **Ép ra cấu trúc gì** | Chuẩn log/metric/trace thống nhất cho 3 service lõi; pipeline cảnh báo (CloudWatch Synthetics/Alarms hoặc tương đương) kết nối kênh on-call (PagerDuty/OpsGenie); ngưỡng cấu hình cảnh báo phải khớp ≤1 phút | +| **Quyết định cần `ADR`** | **Có — `ADR-010`** (dự kiến) — *"Kiến trúc observability & alerting cho dịch vụ giao dịch lõi"*. Radar ước lượng **~6** (đảo ngược trung bình=1 · bán kính 3 service lõi=1 · chạm `QAS-013` Must trực tiếp=2 · ràng buộc trong khoảng GĐ2/GĐ3, có thể đổi công cụ=1 · chưa tranh cãi=1). | +| **Trạng thái** | Đã ghi nhận — `ADR-010` chưa viết; input cho hoạt động `inf` (observability) kế tiếp | + +--- + +### ASR-012 — Toàn bộ hạ tầng phải chạy trên AWS `[Must — ràng buộc đầu vào]` + +| | | +|---|---| +| **Phát biểu** | Không dùng cloud khác hoặc on-premise cho bất kỳ thành phần nào của hệ thống. | +| **Nguồn** | `CON-03` (cứng, đã xác nhận vòng 3 Q&A brief — không phải sở thích SA) | +| **Vì sao định hình kiến trúc** | **Ràng buộc công nghệ không đảo ngược** — nhưng đây là **ràng buộc đầu vào** (khách hàng đã chốt), không phải một quyết định do SA cân nhắc và chọn giữa nhiều phương án | +| **Ép ra cấu trúc gì** | Loại toàn bộ phương án dùng cloud khác/on-prem ngay từ `OPT` (đã thực hiện ở GĐ1); mọi dịch vụ managed trong `ASR-001…011` (ECS Fargate, RDS, SQS/EventBridge, CloudWatch) đều phải là dịch vụ AWS | +| **Quyết định cần `ADR`** | **Không cần `ADR` riêng** — đây là input, không phải quyết định SA; đã được phản ánh làm điều kiện tiên quyết trong `ADR-001` (kiểu kiến trúc tổng thể). Ghi lại ở đây để đầy đủ theo yêu cầu bao phủ, không phải vì cần quyết định thêm. | +| **Trạng thái** | Đã ghi nhận — không cần thiết kế thêm, chỉ cần tuân thủ xuyên suốt `SAD`/`INF` | + +--- + +### ASR-013 — Tích hợp bắt buộc VNPay/Momo (thanh toán) + GHN/GHTK (vận chuyển, có fallback chéo) `[Must]` + +| | | +|---|---| +| **Phát biểu** | Hệ thống phải tích hợp đúng 4 đối tác đã chốt (không phải "chờ chọn tuỳ ý"); GHN/GHTK phải có cơ chế fallback chéo khi một bên lỗi. Mỗi đối tác cần chính sách timeout/retry/idempotent nhất quán. | +| **Nguồn** | `CON-04` (cứng về danh tính đối tác) · `ARISK-03` (VNPay/Momo) · `ARISK-04` (GHN/GHTK fallback chưa kiểm chứng) | +| **Vì sao định hình kiến trúc** | **Ràng buộc hợp đồng/công nghệ không đảo ngược** (đổi đối tác thanh toán/vận chuyển là quyết định kinh doanh + hợp đồng, không phải cấu hình) **+ cắt ngang** (Payment Service phụ thuộc VNPay/Momo; Shipping & Fulfillment phụ thuộc GHN/GHTK; cùng một chính sách resilience nên áp dụng nhất quán) | +| **Ép ra cấu trúc gì** | Adapter/anti-corruption layer riêng cho từng đối tác; chính sách timeout/retry/idempotent chung (kế thừa đề xuất từ `SAD.md §3.4`: VNPay/Momo 10s, GHN/GHTK 8s — **chưa kiểm chứng sandbox thật**); cơ chế fallback GHN↔GHTK cần test riêng | +| **Quyết định cần `ADR`** | **Có — `ADR-011`** (dự kiến) — *"Chính sách resilience khi đối tác thanh toán/vận chuyển bên ngoài lỗi (timeout/retry/fallback chung)"*. Radar ước lượng **~6** (đảo ngược trung bình=1 · bán kính Payment + Shipping=1 · chạm gián tiếp `QAS-002`/`QAS-014`=1 · ràng buộc hợp đồng đối tác, khó đổi giữa chừng=2 · chưa tranh cãi=1). Đây cũng là input trực tiếp cho hoạt động `fail` (đường lỗi) — không trùng lặp, `ADR` chốt chính sách chung, `FAIL` áp dụng chi tiết từng phụ thuộc. | +| **Trạng thái** | Đã ghi nhận — `ADR-011` chưa viết; phụ thuộc sandbox thật của cả 4 đối tác (chưa có, `CON-04`/`ARISK-03/04`) để kiểm chứng đầy đủ | + +--- + +### ASR-014 — Ranh giới nhóm triển khai (deployment grouping) phải khớp năng lực đội thi công thật (Conway) `[Must]` + +| | | +|---|---| +| **Phát biểu** | Việc gom module vào 2–3 nhóm ECS Fargate (thay vì ~10 service độc lập như P1) phải phản ánh đúng số người/kỹ năng đội thi công thật, không chỉ theo giả định "team MVP chuẩn" (`DEC-02`, 🔴 chưa xác nhận) hay đội hình đề xuất của hồ sơ thầu (9 vị trí TB, đỉnh 10). | +| **Nguồn** | `DEC-02` (giả định tạm, chưa xác nhận) · `CON-05` (con người, chưa xác nhận số thật) · `OQ-002`/`OQ-010` (còn mở) · `OPT §1`/§4 (tiêu chí 5 "Năng lực team & vận hành") | +| **Vì sao định hình kiến trúc** | **Chi phí đổi sau cao** (vẽ lại ranh giới triển khai sau khi team đã quen vận hành theo ranh giới cũ tốn công tái tổ chức CI/CD + on-call) **+ cắt ngang** (ảnh hưởng toàn bộ cách tổ chức code, quyền truy cập, và trách nhiệm vận hành của mọi module) | +| **Ép ra cấu trúc gì** | Nhóm "giao dịch" (Cart/Order/Catalog, scale nhanh) tách khỏi nhóm "hỗ trợ" (Seller/Promo/Review/Notify/Shipping) — theo đề xuất `OPT §3` P2; **ranh giới cụ thể này chưa được xác nhận lại ở mức chi tiết ASR khi có số team thật** (xem `ASM-19` mới) | +| **Quyết định cần `ADR`** | **Có — `ADR-012`** (dự kiến) — *"Ranh giới nhóm triển khai (deployment boundary) theo domain và năng lực đội"* — khác `ADR-001` (kiểu kiến trúc tổng thể: monolith hay không) ở chỗ đây là quyết định **cụ thể module nào nằm nhóm nào**. Radar ước lượng **~7** (đảo ngược cao=2 · bán kính toàn bộ tổ chức code/vận hành=2 · chạm gián tiếp mọi `QAS` (mở rộng, quan sát được)=1 · ràng buộc ≥1 năm=1 · chưa tranh cãi, nhưng phụ thuộc số liệu chưa xác nhận=1). | +| **Trạng thái** | Đã ghi nhận — `ADR-012` chưa viết; **phụ thuộc `OQ-010` (Tech Lead xác nhận đội thật)** trước khi có thể coi ranh giới này là vững | + +--- + +### ASR-015 — Chiến lược đa ngôn ngữ (5 thứ tiếng) phải tách chuỗi hiển thị khỏi code ngay từ đầu `[Should]` + +| | | +|---|---| +| **Phát biểu** | Nội dung hiển thị (VI mặc định/EN/ZH/KO/JA) phải được quản lý tách biệt khỏi logic code (resource file/bảng dịch theo locale), để bổ sung ngôn ngữ mới không cần sửa code nghiệp vụ. | +| **Nguồn** | `DRV-09` (Should, không chặn MVP) | +| **Vì sao định hình kiến trúc** | Chủ yếu **ràng buộc kiến trúc bảo trì dài hạn** — nếu không tách ngay từ đầu, retrofit i18n sau khi đã có hàng trăm màn hình là công việc tốn kém hơn nhiều lần so với làm đúng từ đầu; bán kính rộng (toàn bộ tầng hiển thị FE) nhưng không chạm `QAS` Must nào (chỉ Should) | +| **Ép ra cấu trúc gì** | Framework i18n ở tầng FE (tách string ra resource file theo locale); chiến lược lưu trữ nội dung động (VD tên sản phẩm do seller nhập — có cần dịch không, ai dịch — **chưa chốt**, xem `OQ-025` mới) | +| **Quyết định cần `ADR`** | **Borderline, không bắt buộc** — radar ước lượng **~5** (đảo ngược trung bình=1 · bán kính rộng nhưng chỉ FE=1 · không chạm `QAS` Must (chỉ Should)=0 · ràng buộc trong khoảng dự án=1 · chưa tranh cãi=0, +2 vì đây là danh mục "Chiến lược đa ngôn ngữ" được `decision-radar.md §3` liệt kê rõ trong nhóm Frontend). Khuyến nghị: nếu Tech Lead không thấy tranh cãi, ghi `DEC-nn` + đưa framework cụ thể vào `AGD` (GĐ3) thay vì mở một `ADR` riêng; nâng lên `ADR-013` nếu phát sinh tranh luận về công nghệ i18n cụ thể. | +| **Trạng thái** | Đã ghi nhận — quyết định công cụ cụ thể để hoạt động `sad`/GĐ3 (`AGD`) chốt | + +--- + +## B3. Ma trận `ASR` × `CMP` + +*Chưa điền — `SAD` (hoạt động 3, kế tiếp) chưa tồn tại nên chưa có `CMP-nn` để đối chiếu. Khung +để hoạt động `sad` điền khi có bảng component:* + +| | `CMP-nn` (điền ở hoạt động `sad`) | +|---|---| +| `ASR-001…015` | *(chờ `SAD`)* | + +🔴 Nhắc cho hoạt động `sad` kế tiếp: mỗi `CMP` phải phục vụ được ít nhất một `ASR` ở trên (cột +"cái nó KHÔNG làm" của `SAD` giúp kiểm tra ngược); `ASR-012` (AWS) không sinh ra `CMP` riêng, chỉ +là ràng buộc nền cho mọi `CMP`. + +--- + +## C. Đối chiếu với `BR`/`ROLE` của bộ BA + +| `BR`/`ROLE` (BA) | Nội dung gốc | `ASR` tương ứng | Khớp? | Hành động | +|---|---|---|---|---| +| `BR-CART-01` | Tách đơn theo seller | `ASR-003` | ✅ | Không lệch — `BR-CART-01` chính là nguồn của `ASR-003`; cơ chế chi tiết vẫn chờ `OQ-011` (BA) | +| `BR-CART-02` | Giữ tồn kho khi checkout (chống oversell) | *(không có `ASR` riêng)* | ➖ N/A | Đây là quy tắc nghiệp vụ thuần (điều kiện hành động), không ép cấu trúc kiến trúc riêng — thuộc `SAD`/logic thi công, không phải `ASR` | +| `BR-CART-03` | Giới hạn giá trị đơn COD (chưa chốt) | *(không có `ASR`)* | ➖ N/A | Đây là quyết định nghiệp vụ/rủi ro tài chính (PO chọn phương án), không ép cấu trúc kiến trúc — nếu PO chọn phương án (b) "xác thực bổ sung" (OTP), có thể phát sinh `ASR` mới (tích hợp OTP) — chưa xảy ra | +| `BR-CART-04` | Điều kiện chọn phương thức thanh toán | Gián tiếp qua `ASR-002`/`ASR-013` | 🟡 Một phần | Không có `ASR` riêng vì bản thân việc "cho chọn 1 trong 3 phương thức" không ép cấu trúc — cấu trúc bị ép là do *mỗi* phương thức cần tích hợp riêng (`ASR-002` Payment, `ASR-013` đối tác ngoài) | +| `BR-CART-05` | Không lưu thông tin thẻ | `ASR-002` | ✅ | Khớp hoàn toàn | +| `BR-CART-06` | Xác thực webhook thanh toán | `ASR-004` | ✅ | Khớp hoàn toàn | +| `BR-CART-07` | Điều kiện tối thiểu Guest checkout | *(không có `ASR`)* | ➖ N/A | Danh sách field bắt buộc là chi tiết UI/validation, không ép cấu trúc kiến trúc | +| `ROLE-01` Guest / `ROLE-02` Customer (`RBAC` §1, §2) | 2 vai trò, phạm vi dữ liệu theo `session_id`/`customer_id` | `ASR-007` | ✅ | Khớp — `ASR-007` chính là hoá kỹ thuật của ranh giới "không xem được giỏ/đơn người khác" trong ma trận `RBAC` §2 | +| `RBAC` §4 (PII địa chỉ/SĐT chia sẻ cho seller) | Mức che khi hiển thị cho seller — chưa chốt | `ASR-008` | 🟡 Một phần | `ASR-008` bao phủ phần "vùng lưu trữ + data minimization"; phần "mức che hiển thị cụ thể" vẫn chờ Pháp chế/Bảo mật — ghi nhận là chưa tách rời được cho tới khi có người đó | +| `RBAC` §8 `OQ-012` (RISK-01 phương án OTP cho Guest giá trị cao) | Guest cần giới hạn/OTP cho đơn giá trị cao? | *(chưa có `ASR` — phụ thuộc `BR-CART-03`)* | ➖ Chờ PO | Nếu PO chọn phương án OTP ở `BR-CART-03`, sẽ phát sinh `ASR` mới (tích hợp OTP) ở lần cập nhật `ASR` tiếp theo | + +*`BR-nnn` ép ràng buộc kiến trúc ⇒ `ADR` (theo `artifact-map.md §7`) — bảng trên xác nhận 4/7 +`BR-CART` có `ASR` tương ứng trực tiếp; 3 còn lại (`BR-CART-02/03/07`) là quy tắc nghiệp vụ thuần +không ép cấu trúc, đúng theo tiêu chí B1 (không phải mọi `BR` đều thành `ASR`).* + +--- + +## D. Giả định & Ngoài phạm vi + +**Giả định** *(tiếp số toàn dự án — `ASM-01…18` đã dùng ở `CTX`/`OPT`/`TCO`/`QAS`, bắt đầu `ASM-19`)*: + +| ID | Giả định | Cách xác minh | Nếu sai thì `ASR`/`ADR` nào đổi | +|---|---|---|---| +| `ASM-19` | Ranh giới "nhóm giao dịch" (Cart/Order/Catalog) vs "nhóm hỗ trợ" (Seller/Promo/Review/Notify/Shipping) theo `OPT §3` P2 vẫn là ranh giới đúng ở mức chi tiết `ASR-014`/`ADR-012` | Tech Lead xác nhận lại tại hoạt động `sad`, sau khi có số đội thi công thật (`OQ-010`) | `ASR-014`/`ADR-012` (dự kiến) — nếu team thật nhỏ hơn/khác cơ cấu, phải vẽ lại nhóm (VD gộp thêm module vào 1 nhóm duy nhất) | +| `ASM-20` | MFA cho Admin dùng TOTP app (không phụ thuộc thêm nhà cung cấp SMS gateway) làm mặc định đề xuất cho `ASR-009` | Security xác nhận phương thức tại hoạt động `sec` (`OQ-024` mới) | `ASR-009` — nếu cần SMS OTP, phát sinh phụ thuộc nhà cung cấp SMS mới (chi phí + `ASR` phụ thuộc bên ngoài mới) | +| `ASM-21` | Nội dung do seller tự nhập (tên sản phẩm, mô tả) **không** cần dịch tự động sang 5 ngôn ngữ ở MVP — chỉ UI hệ thống (nhãn, thông báo) cần i18n theo `ASR-015` | PO xác nhận phạm vi i18n tại hoạt động `sad`/GĐ3 (`OQ-025` mới) | `ASR-015` — nếu seller content cũng cần dịch, cần thêm chiến lược dịch thuật (thủ công/máy) và ảnh hưởng `DAT` (lưu bản dịch) | + +*`ASM-01…18` của `CTX`/`OPT`/`TCO`/`QAS` vẫn áp dụng nguyên trạng — không lặp lại nội dung, chỉ +tham chiếu (đặc biệt `ASM-04`→`ASR-008`, `ASM-07`→`ASR-005`, `ASM-08`→`ASR-006`).* + +**Ngoài phạm vi:** + +- `SAD`/`ADR`/`ICD`/`DAT`/`SEC`/`INF`/`FAIL` — chưa thực hiện ở lượt chạy này (chỉ hoạt động + `asr`). Mọi "`ADR` ứng viên" ở §B2 là **đề xuất số thứ tự**, chưa phải file `ADR` thật — hoạt + động `adr` kế tiếp xác nhận lại số thật theo thứ tự viết, không nhất thiết khớp số đề xuất ở đây. +- Ma trận `ASR` × `CMP` (§B3) — để trống, chờ `SAD`. +- `BR-CART-02/03/07` không có `ASR` tương ứng (xem §C) — đây là quyết định nghiệp vụ thuần, đúng + theo tiêu chí B1, không phải bỏ sót. +- `ASR` mới có thể phát sinh nếu PO chọn phương án OTP cho `BR-CART-03` (xem §C, dòng cuối) — + chưa xảy ra ở lượt này. + +## E. Open Questions + +*Tiếp số sổ SA (`00-index/OQ_e-commerce.md` đang ở `OQ-023`) — bắt đầu `OQ-024`.* + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược | +|---|---|---|---|---|---| +| `OQ-024` | Phương thức MFA cho Admin là gì — TOTP app (Google Authenticator/Authy), SMS OTP, hay khoá bảo mật cứng? | Tech Lead + Security | 2026-09-14 | `ASR-009`; thiết kế `SEC` (mô hình xác thực) | Nếu chọn SMS OTP: phát sinh phụ thuộc nhà cung cấp SMS gateway mới (chi phí + `ARISK` phụ thuộc ngoài mới, tương tự `ARISK-10`); nếu chọn TOTP app: không phát sinh chi phí vận hành thêm nhưng cần hướng dẫn user cài app | +| `OQ-025` | Nội dung do seller tự nhập (tên/mô tả sản phẩm) có cần dịch sang 5 ngôn ngữ ở MVP không, hay chỉ UI hệ thống cần i18n? Nếu cần dịch, ai cung cấp bản dịch (dịch máy tự động hay seller tự nhập đa ngôn ngữ)? | PO + Tech Lead | 2026-09-14 | `ASR-015`; `DAT` (có cần lưu bản dịch theo locale không) | Nếu cần dịch nội dung seller: `DAT` phải thêm mô hình lưu trữ đa ngôn ngữ cho `Product`/`ProductVariant` (ngoài phạm vi module Giỏ hàng & Checkout hiện tại), tăng effort đáng kể so với chỉ dịch UI tĩnh | + +**Nhắc:** cộng với các `OQ` còn mở ảnh hưởng trực tiếp `ASR` ở tài liệu này — `OQ-002`/`OQ-010` +(team thật, chặn `ASR-001`/`ASR-014`), `OQ-007` (đại diện Pháp chế, chặn `ASR-008`), `OQ-011` (BA, +cơ chế tách đơn, chặn `ASR-003`), `OQ-012` (thời điểm `POC-01`, chặn `ASR-001`/`ASR-005`), +`OQ-018…023` (số `QAS` nguồn của nhiều `ASR`) — 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 `ASR`, tự chấm sớm)* + +| # | Tiêu chí | ☐/✅ | Ghi chú | +|---|---|---|---| +| 1 | `ASR` liệt kê yêu cầu thực sự định hình kiến trúc, mỗi cái truy về `DRV` hoặc `QAS` | ✅ | 15 `ASR`, mỗi cái có cột "Nguồn" trỏ về `DRV`/`CON`/`QAS`/`BR`/`ROLE` cụ thể, không có `ASR` "mồ côi" nguồn | +| — | `QAS` — mọi NFR đã lượng hoá | ✅ *(đã đạt ở hoạt động `qas` trước)* | Xem `QAS_e-commerce_v1.0.md`, không lặp lại ở đây | +| — | `SAD` có sơ đồ C4 | ☐ | **Chưa tới** — hoạt động 3, kế tiếp | +| 2 | `ADR-nnn` tồn tại cho mọi quyết định đạt ngưỡng radar | ☐ | **Chưa viết `ADR` nào** — đúng theo yêu cầu điều phối "không viết ADR ở lượt này"; §B2 đã liệt kê đủ 12/15 ứng viên `ADR` (radar 6–9) để hoạt động `adr` kế tiếp không phải dò lại từ đầu | +| — | `ICD`/`DAT`/`SEC`/`INF`/`FAIL` | ☐ | Chưa tới — hoạt động 4–8 | +| — | `sa-conformance` báo coverage `ASR → ADR/CMP` ≥ 100% | ☐ | **0/15** — kỳ vọng đúng lúc này (đã ghi nhận là "🟠 Nợ" trong `DTM`/`ADL` từ trước khi file này tồn tại), sẽ chặn AG2 thật nếu vẫn 0/15 khi hoạt động `adr`/`sad` đã chạy xong | + +**Kết luận tự chấm (riêng phần `ASR`):** Hoạt động `asr` hoàn tất đúng phạm vi được giao — 15 +`ASR` có nguồn, có "vì sao định hình kiến trúc", có `ADR` ứng viên (hoặc lý do không cần). AG2 +**còn xa** vì 7/9 hoạt động khác của GĐ2 chưa chạy — đây là tiến độ kỳ vọng, không phải lỗi. + +### ② Checklist D1–D12 *(`design-rules.md`)* + +| # | Mục | ☐/✅ | Ghi chú | +|---|---|---|---| +| D1 | Một ADR một quyết định | N/A | Tài liệu này không viết `ADR` — chỉ liệt kê ứng viên; mỗi ứng viên đã được tách theo đúng nguyên tắc một quyết định (VD `ADR-001` kiểu kiến trúc tổng thể tách khỏi `ADR-012` ranh giới nhóm triển khai cụ thể, dù liên quan) | +| D2 | Không NFR định tính; đủ 4 câu | N/A | `ASR` không phải `QAS` — không áp dụng trực tiếp; mọi `ASR` tham chiếu đúng `QAS` đã lượng hoá ở hoạt động trước, không tự đặt số mới | +| D3 | Nêu phương án bị loại + lý do gắn `CON`/`QAS` | ✅ *(kế thừa)* | `ASR-001` tham chiếu `OPT §5` (P1/P3/P4 đã loại) làm nền; không lặp lại nội dung, chỉ dẫn | +| D4 | Sơ đồ khai báo mức + legend | N/A | Không có sơ đồ mới trong tài liệu này | +| D5 | Interface có chủ/contract | N/A | Chưa tới `ICD` | +| D6 | Phụ thuộc ngoài process có timeout/retry | 🟡 Một phần | `ASR-004`/`ASR-013` đã nêu yêu cầu (idempotent, timeout/retry) nhưng chi tiết đầy đủ 4 câu hỏi D6 thuộc hoạt động `fail` kế tiếp | +| D7 | Một chủ sở hữu dữ liệu | 🟡 Một phần | `ASR-006` xác nhận 1 RDS chính là chủ cho các module ngoài Payment, `ASR-002` xác nhận Payment có DB riêng — chi tiết từng thực thể để `DAT` | +| 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 | `ASR` không thêm con số hạ tầng mới — kế thừa `TCO`/`ARISK` | +| D10 | Không quyết định thay người có thẩm quyền | ✅ | `ASR-008` ghi rõ phủ quyết thuộc Security/Legal; `ASR-002` ghi Security cần ký; mọi chỗ chưa rõ đều có `OQ` kèm hệ quả phương án ngược (§E, và trong từng khối ASR) | +| D11 | Có mục "Ngoài phạm vi" + `ASM-nn` | ✅ | §D đầy đủ — `ASM-19…21` mới, có cách xác minh/hệ quả; mục "Ngoài phạm vi" liệt kê rõ những gì chưa làm | +| 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 Phần C ở trên (`BR`/`ROLE` × `ASR`) — 4/7 `BR-CART` có `ASR` tương ứng trực tiếp; 3 còn lại +xác nhận đúng là không ép cấu trúc (không phải bỏ sót). Không có hành động "BA cập nhật SRS" nào +cần thiết ở lượt này vì không phát hiện lệch nội dung, chỉ có 1 dòng chờ quyết định PO +(`BR-CART-03`) có thể sinh `ASR` mới sau. + +### ④ Danh sách `OQ` mở kèm người phải trả lời, chặn gì + +Xem §E (mới: `OQ-024`, `OQ-025`) cộng các `OQ` còn mở từ `CTX`/`OPT`/`ARISK`/`QAS` +(`OQ-002/004/005/006/007/008/010/012/013…023`) — sổ đầy đủ tại `00-index/OQ_e-commerce.md`. Ba +câu quan trọng nhất cho tiến độ `ASR`→`ADR`/`SAD` kế tiếp: **`OQ-010`** (team thật — chặn +`ASR-001`/`ASR-014`), **`OQ-012`** (thời điểm `POC-01` — chặn `ASR-001`/`ASR-005`), **`OQ-007`** +(đại diện Pháp chế — chặn `ASR-008`). + +**Nhắc:** AG2 cần **Tech Lead + Security + Ops/SRE ký** — còn xa vì `SAD`/`ADR`/`ICD`/`DAT`/`SEC`/ +`INF`/`FAIL` chưa chạy. Hoạt động kế tiếp bắt buộc là **`sad`** (hoạt động 3, theo đúng thứ tự +1→2→3 của `SKILL.md`), dùng chính 15 `ASR` ở tài liệu này làm đầu vào để phân rã component và vẽ +C4; `ADR-001` (kiểu kiến trúc tổng thể) nên được viết ngay khi `sad`/`adr` bắt đầu, theo đúng cảnh +báo đã có từ `DTM §11`/`ADL §8`. diff --git a/sa-output/e-commerce/02-architecture/DAT_e-commerce_v1.0.md b/sa-output/e-commerce/02-architecture/DAT_e-commerce_v1.0.md new file mode 100644 index 0000000..301c676 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/DAT_e-commerce_v1.0.md @@ -0,0 +1,685 @@ +# DAT — Data Architecture — e-commerce + +| | | +|---|---| +| **Version** | 1.1 | +| **Date** | 2026-09-15 | +| **Author** | SA (skill sa-2-architecture, chế độ `go`, hoạt động `dat`) | +| **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 ownership 15 `CMP` (§1), mô hình `Order`/`OrderSeller`/`OrderItem` + `payment_init_status` (`ADR-013`, §2), snapshot giá/`sellerName`, idempotency store (§4.2), PITR RPO ≤15 phút (§9). Chấp nhận **TẠM** (🔴): `ASM-35` (1 `Order` = 1 `Payment`) — `OQ-043` **giữ nguyên mở**; chọn **Transactional Outbox** cho `OQ-044` — yêu cầu SA viết `ADR-014` (`Proposed`) ở lượt hoạt động `adr` kế tiếp, `OQ-044` **giữ mở** tới khi có ADR; chọn phương án (a) — mỗi module tự ghi `audit_log` riêng cho `OQ-047`, **không thêm `CMP-16`**; ngưỡng job quét `Order` kẹt **5 phút** cho `OQ-042`; cơ chế FE **polling** cho `OQ-041` — cả bốn `OQ-041/042/044/047` **giữ nguyên mở**, chờ Tech Lead thật xác nhận. `OQ-045`/`OQ-046` **giữ nguyên mở**, không có hướng TẠM. **§5 (phân loại PII/retention/whitelist chia sẻ seller) CHƯA CÓ HIỆU LỰC** — chờ đại diện Pháp chế/Bảo mật phủ quyết (`OQ-007`), không nằm trong phạm vi duyệt lần này. Ghi thêm `DEC-25`. Security/Legal: — *(chưa ký; §5 chặn hoàn toàn tới khi có người, `OQ-007`)* · 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. Status **giữ** 🟡 Draft — AG2 chưa đủ ba chữ ký thật/hợp lệ. | +| **Source** | `02-architecture/SAD_e-commerce_v1.0.md` v1.3 §4.1 (bảng `CMP-nn`, cột "Dữ liệu sở hữu"), §6.1/§6.3, §7 · `02-architecture/ICD_e-commerce_v1.0.md` v1.0 §3.1.1, §3.7, §5 (denormalize `sellerName`, `unitPriceSnapshotVnd`) · `02-architecture/FAIL_e-commerce_v1.0.md` v1.1 §1.2, §4, §7, §9 (khoảng trống outbox, `OQ-040/042`) · `02-architecture/QAS_e-commerce_v1.0.md` `QAS-003/004/006/008/011/014` · `02-architecture/ASR_e-commerce_v1.0.md` `ASR-002/003/006/008` · `02-architecture/adr/ADR-002_*.md`, `ADR-003_*.md`, `ADR-004_*.md`, `ADR-005_*.md`, `ADR-006_*.md`, `ADR-007_*.md`, `ADR-008_*.md`, `ADR-009_*.md`, `ADR-011_*.md`, `ADR-013_*.md`, `ADR-014_*.md` · `00-index/OQ_e-commerce.md` v1.20 · `00-index/DEC_e-commerce.md` v1.21 · `01-context/TCO_e-commerce_v1.0.md` §3.2 · `ba-output/e-commerce/02-analysis/BR_CartCheckout_v1.0.md` §4 (ERD khái niệm), §3 (vòng đời) · `ba-output/e-commerce/02-analysis/RBAC_CartCheckout_v1.0.md` §4 (dữ liệu nhạy cảm) · `ba-output/e-commerce/03-specification/SRS_US002-003_v1.0.md` · `e-commerce/docs/sections/05-thiet-ke-du-lieu.md` (tham khảo P1 — database-per-service, Kafka/MSK; **không** kế thừa kiểu kiến trúc đó, chỉ tham khảo tên bảng/cột và số retention đề xuất) | +| **Scope** | Toàn sàn e-commerce theo P2 (SAD v1.3) — kiến trúc dữ liệu + ownership cho toàn bộ 15 `CMP-01…15`. Chi tiết nhất: **Cart & Order** (`CMP-04`), **Payment** (`CMP-11`/`CMP-14`), và mọi thực thể chứa PII (`CMP-02` Identity, `CMP-04` địa chỉ giao hàng, `CMP-05` KYC seller). Các `CMP` còn lại (Catalog, Seller quản trị, Commission, Promotion, Review, Notification, Shipping) ở mức ownership + entity list, không đào sâu schema vật lý (thuộc dev). Đây là hoạt động 5/9 của `sa-2-architecture`. | +| **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`/`FAIL`/`ASR`/`QAS`. AG1 chưa ký thật; AG2 chưa tới hạn; `ADR-005`/`ADR-006`/`ADR-009` (radar ≥8) chưa `Accepted` (chờ `POC-01`/`POC-02`/diễn tập DR); `ADR-008` (PII) chặn hoàn toàn vì chưa có đại diện Pháp chế/Bảo mật (`OQ-007`). Mọi con số retention/index/pool trong tài liệu này là **đề xuất SA**, chưa đo thật. | + +## 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 `dat`) | Bản đầu — hoạt động 5/9 của GĐ2. Bảng ownership D7 cho toàn bộ thực thể của 15 `CMP` (schema-per-module theo `ADR-006`, RDS Payment riêng theo `ADR-002`); mô hình `Order`/`OrderSeller`/`OrderItem` chi tiết theo `ADR-003`, bổ sung `order.payment_init_status` (`PENDING_PAYMENT_INIT`/`PAYMENT_INIT_READY`/`PAYMENT_INIT_FAILED`) theo `ADR-013`, `cart_item.seller_name_snapshot`/`unit_price_snapshot` theo `ICD §3.1.1/§3.7` (`OQ-033`); phân loại dữ liệu PII/Payment/nghiệp vụ kèm đề xuất retention (chờ Legal, `OQ-007`) và whitelist chia sẻ seller theo `ADR-008`; chiến lược đọc/ghi (index cho `QAS-003/004/006`, read replica chỉ dùng cho Catalog, đánh giá cache nội dung Cart cho `OQ-040`); ranh giới transaction + đề xuất outbox pattern cho khoảng trống `FAIL §7` (ADR ứng viên, chưa viết); idempotency store cho `POST /v1/checkout`; backup/PITR đối chiếu `QAS-008`/`ADR-009`; migration/versioning schema (đề xuất Flyway); dữ liệu đối soát (`ReconciliationLog`, `ADR-004`) và job dọn `Order` kẹt (đề xuất ngưỡng cho `OQ-042`). Đối chiếu `docs/sections/05-thiet-ke-du-lieu.md` (P1) — 5 khác biệt chính được ghi nhận. Thêm `OQ-043…047`, cập nhật `OQ-007/040/042`, `ASM-35…38`. Ghi `DEC-24` (tiếp nối `DEC-01…23`, ngoại lệ gate tiếp tục GĐ2 hoạt động `dat`). Không sửa `SAD`/`ICD`/`FAIL`/`ADR`. `Confidence` 🔴 toàn bộ. | `DEC-24` | +| 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 ownership 15 `CMP`, mô hình `Order`/`OrderSeller`/`OrderItem` + `payment_init_status` (`ADR-013`), snapshot giá/`sellerName`, idempotency store, PITR RPO ≤15 phút. Chấp nhận **TẠM** (🔴): `ASM-35` (`OQ-043` giữ mở); chọn Transactional Outbox cho `OQ-044` — yêu cầu `ADR-014` (`Proposed`) ở lượt `adr` kế tiếp; chọn phương án (a) mỗi module tự ghi `audit_log` cho `OQ-047` — không thêm `CMP-16`; ngưỡng job quét 5 phút cho `OQ-042`; polling cho `OQ-041` — cả bốn giữ nguyên mở. `OQ-045`/`OQ-046` giữ mở. **§5 (PII/retention/whitelist) CHƯA CÓ HIỆU LỰC** — chờ Legal/Security phủ quyết (`OQ-007`). Không đổi nội dung chuyên môn. Security/Ops chưa ký; `OQ-004` mở; `Confidence` giữ 🔴; Status giữ 🟡 Draft; AG2 **chưa** ký. Ghi thêm `DEC-25`. | `DEC-25` | +| 1.1 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `adr`) | **Chỉ link ADR, không đổi nội dung.** `ADR-014` (Transactional Outbox, `Proposed`) vừa được viết theo hướng TẠM đã chọn ở `OQ-044`/`DEC-25` — thay các dòng "chưa viết"/"Ứng viên — chưa viết" ở §4.1 bằng đường dẫn `adr/ADR-014_transactional-outbox-publish-su-kien.md`. `OQ-044` giữ nguyên mở (chờ Tech Lead thật xác nhận thiết kế relay, xem `ADR-014 §3`). Không sửa nội dung chuyên môn nào khác của `DAT`. Ghi `DEC-31` (tiếp nối `DEC-01…30`). | `ADR-014`, `DEC-31` | + +> Sơ đồ thắng về **quan hệ và luồng** (ai sở hữu gì, ai đọc/ghi ai). +> Bảng/văn bản thắng về **ràng buộc và con số** (retention, index, TTL, RPO/RTO). +> 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`) và 8 (`FAIL`) đã chạy (`DEC-18…23`), `ADR-001…013` đã viết (tất cả `Proposed`). Điều kiện +đầu vào cho hoạt động 5 (`DAT`) đã đủ. 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-24 (SA)** — Tiếp tục `sa-2-architecture` (hoạt động 5 — `DAT`) 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…23`. +> **Quyết định:** Thiết kế kiến trúc dữ liệu + ownership cho 15 `CMP` dựa trên `SAD v1.3`/`ICD +> v1.0`/`FAIL v1.1`/`ADR-001…013` đã có, giữ `Confidence 🔴` cho tới khi: (a) AG1/AG2 ký thật, +> (b) `POC-02` (tải RDS gộp) chạy xong để xác nhận connection pool/index đề xuất, (c) đại diện +> Pháp chế/Bảo mật xác nhận phân loại PII và retention (`OQ-007`), (d) Tech Lead xác nhận cơ chế +> outbox/idempotency store đề xuất (`OQ-044/045`). +> **Người quyết:** Điều phối dự án (đại diện PO, dự án chạy thử). +> **Radar (ước lượng cho việc tiếp tục dưới ngoại lệ):** ~4 — chi phí đảo ngược thấp (đây là ghi +> tài liệu thiết kế, chưa có dòng code phụ thuộc) · bán kính ảnh hưởng: hoạt động `sec`/`inf` +> kế tiếp và toàn bộ dev BE dùng `DAT` làm nguồn sự thật ownership, nhưng bản thân *việc ghi tài +> liệu dưới ngoại lệ* thì nhỏ · có chạm `QAS-003/004/006/008/011/014` Must trực tiếp (đang hiện +> thực hoá thành index/consistency/retention) nhưng chưa phải cam kết thi công · không ràng buộc +> dài hạn tự thân (văn bản `DAT` sửa được qua version mới) · không tranh cãi mới, tiếp nối tiền lệ +> `DEC-11…23` → **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ệ:** hoạt động `sec`/`inf` (hoạt động 6–7) không có ownership +> dữ liệu/chiến lược consistency để thiết kế threat model dữ liệu và backup/DR theo schema — chậm +> tiến độ chạy thử tương ứng thời gian xử lý các `OQ` đang mở, đặc biệt `OQ-007` (chặn `ADR-008`). + +🔴 **Nhắc quan trọng:** đây là hoạt động 5/9. `SEC`, `INF` (hoạt động 6–7) **chưa được tạo**. +Tài liệu này là input trực tiếp cho cả hai — đặc biệt phân loại PII (§5) cho `sec`, và +backup/RPO-RTO (§9) cho `inf`. + +--- + +## 1. Nguyên tắc: mỗi thực thể có đúng một chủ + +*Quy tắc `D7`. Cột "Schema" theo `ADR-006` (1 cụm RDS chính, schema-per-module) trừ `Payment`/ +`PaymentTransaction`/`PaymentReconciliationLog` nằm ở **RDS Payment hoàn toàn riêng biệt** theo +`ADR-002` — **không module nào khác được join/truy vấn SQL trực tiếp vào RDS Payment**; mọi trao +đổi chỉ qua `IF-006` (sync, khởi tạo), sự kiện `PaymentConfirmed`/`PaymentInitReady`/ +`PaymentInitFailed` (async), hoặc job đối soát nội bộ Payment.* + +### 1.1 Nhóm Giao dịch — `CMP-02` Identity & Access *(schema `identity`)* + +| Thực thể | **SoT** | Bản sao ở đâu | Cập nhật bằng cơ chế gì | Trễ tối đa | Lệch quá thì sao | +|---|---|---|---|---|---| +| `user_account` | `CMP-02` | Cache JWT claims đã xác thực trong Redis (`CMP-15`) | Ghi tại lúc đăng nhập/refresh token | TTL access token (đề xuất 15-60 phút, `ICD §1` mục 9) | Token hết hạn tự nhiên — không phải "lệch", là thiết kế | +| `customer_profile`, `customer_address` | `CMP-02` | Không có bản sao RDS; **`cart_item.seller_name_snapshot`/checkout copy tên người nhận vào `order_seller`** là snapshot một chiều, không phải bản sao đồng bộ | Snapshot tại thời điểm checkout (không cập nhật ngược khi khách đổi địa chỉ sau đó) | N/A — snapshot cố ý, không phải cache | Không áp dụng — đơn đã tạo giữ nguyên địa chỉ tại thời điểm đặt hàng (đúng thông lệ thương mại điện tử) | +| `oauth_identity`, `mfa_device` | `CMP-02` | Không có | — | — | — | +| Session (Guest `X-Guest-Session-Id`, ownership cache) | `CMP-15` (Redis) — **đây là SoT của session, không phải read model** vì session không có bản ghi RDS song song | Không | — | TTL 30 ngày không hoạt động (`ICD §1` mục 10) | Hết TTL → Guest mất phiên, phải tạo giỏ mới (đúng thiết kế `BR-CART §3`) | + +### 1.2 Nhóm Giao dịch — `CMP-03` Catalog & Inventory *(schema `catalog`)* + +| Thực thể | **SoT** | Bản sao ở đâu | Cập nhật bằng cơ chế gì | Trễ tối đa | Lệch quá thì sao | +|---|---|---|---|---|---| +| `category`, `category_i18n`, `product`, `product_i18n` | `CMP-03` | Chỉ mục tìm kiếm — **hoãn dùng OpenSearch ở P2 MVP** (`SAD §10`), dùng Postgres full-text search trực tiếp trên schema `catalog` | N/A (không có read model phái sinh ở MVP) | N/A | N/A | +| `product_variant` (giá `price_amount`) | `CMP-03` | `cart_item.unit_price_snapshot`, `order_item.unit_price_snapshot` (snapshot một chiều, không đồng bộ ngược) | Snapshot lúc thêm giỏ/lúc đặt hàng | N/A — cố ý đóng băng | Khách thấy `priceChanged=true` ở `GET /v1/cart` (`ICD §3.1.1`) nếu giá hiện tại khác snapshot — không tự cập nhật `unit_price_snapshot`, chỉ hiển thị cảnh báo | +| `inventory_stock` (`quantity_available`, `quantity_reserved`) | `CMP-03` | Không có bản sao — mọi kiểm tra/giữ tồn kho gọi trực tiếp `IF-005` (in-process, `ASR-006`) | N/A | 0 (đọc trực tiếp SoT) | N/A — đúng lý do không cache: tồn kho là dữ liệu cần chính xác tức thời (chống oversell, `BR-CART-02`) | +| `wishlist_item`, `language`, `currency`, `exchange_rate` | `CMP-03` | Cache `exchange_rate` ở Redis, TTL 1 giờ (tham khảo `docs/05 §5.3.1`, chỉ hiển thị, không dùng để thanh toán) | Batch job refresh | 1 giờ | Hiển thị quy đổi lệch tạm thời — chấp nhận vì không dùng để tính tiền thật | + +### 1.3 Nhóm Giao dịch — `CMP-04` Cart & Order (+ Dispute) *(schema `cart_order`) — chi tiết nhất* + +| Thực thể | **SoT** | Bản sao ở đâu | Cập nhật bằng cơ chế gì | Trễ tối đa | Lệch quá thì sao | +|---|---|---|---|---|---| +| `cart`, `cart_item` | `CMP-04` | Không có bản sao RDS. Nội dung giỏ **hiện không cache ở Redis** (chỉ session/ownership cache) — xem đánh giá `OQ-040` ở §7.3 | — | — | `QAS-003` không đạt khi RDS chậm và không có fallback (xem `FAIL FM-06`) | +| `order` (đơn cha) | `CMP-04` | Không có | — | — | — | +| `order_seller`, `order_item`, `order_status_history` | `CMP-04` | `commission_transaction.order_seller_id`, `shipment.order_seller_id`, `dispute.order_seller_id` (FK logic, tiêu thụ qua sự kiện `OrderPlaced`/`PaymentConfirmed`, không SQL trực tiếp) | Consume event `OrderPlaced` (per-seller, `ADR-005`) | Fan-out lag ≤5 giây (`QAS-005`) | Vượt 5 giây → cảnh báo lag hàng đợi (`OQ-036`, ứng viên `inf`) | +| `return_request` | `CMP-04` | Không có | — | — | — | +| `dispute` | `CMP-04` | `payout_hold.release_status` (Commission & Payout) tiêu thụ trạng thái `dispute` qua sự kiện (chưa thiết kế tên sự kiện cụ thể — ứng viên module Quản lý đơn hàng, ngoài phạm vi US-002/003) | Sự kiện (chưa đặt tên) | Chưa chốt | Chưa chốt — **ngoài phạm vi module Giỏ hàng & Checkout**, ghi nhận điểm nối cho module kế tiếp | +| `outbox_event` *(mới, đề xuất — xem §4.1)* | `CMP-04` | Không — bảng nội bộ, không phải dữ liệu nghiệp vụ | — | — | — | +| `idempotency_key` *(mới, đề xuất — xem §4.2)* | `CMP-04` | Không | — | — | — | + +### 1.4 Payment — `CMP-11`/`CMP-14` *(RDS Payment riêng, cô lập hoàn toàn theo `ADR-002`)* + +| Thực thể | **SoT** | Bản sao ở đâu | Cập nhật bằng cơ chế gì | Trễ tối đa | Lệch quá thì sao | +|---|---|---|---|---|---| +| `payment` | `CMP-11` | `order.payment_init_status` (Cart & Order, schema `cart_order`) là **read model tối thiểu** — chỉ phản ánh 1 trong 4 trạng thái sơ khởi (`not_applicable`/`pending_payment_init`/`payment_init_ready`/`payment_init_failed`), **không** phải bản sao đầy đủ của `payment` | Consume `PaymentInitReady`/`PaymentInitFailed` (`ADR-013`) | Theo `ADR-013 §3.1`: ngưỡng UX "kẹt" 15 giây | Quá 15 giây chưa cập nhật → coi là bất thường, xem job dọn ở §4.3 | +| `payment_transaction` *(mới, đề xuất — xem §1.4.1)* | `CMP-11` | Không | — | — | — | +| `payment_reconciliation_log` | `CMP-11` | Không | — | — | — | +| `outbox_event` (bản riêng của Payment, khác bảng của `CMP-04` — 2 DB khác nhau) | `CMP-11` | Không | — | — | — | + +#### 1.4.1 Vì sao cần `payment_transaction` tách khỏi `payment` + +`payment` là bản ghi **theo Order** (xem §2.2 — 1 `Order` có 0..1 `payment`). Nhưng `ADR-013` +cho phép khách **thử lại** khởi tạo thanh toán sau `PAYMENT_INIT_FAILED` (§3.3 của `ADR-013`), +và mỗi lần thử là một lời gọi riêng tới VNPay/Momo với `gateway_transaction_ref` riêng (có thể). +Nếu chỉ có 1 dòng `payment`, mỗi lần thử lại phải ghi đè `gateway_transaction_ref` cũ — mất dấu +vết đối soát các lần thử thất bại trước đó (vi phạm `BR-CART-06`/`ADR-004` — "bản ghi thanh toán +không bao giờ bị xoá"). `payment_transaction` ghi **mỗi lần gọi gateway** (init hoặc webhook xác +nhận) như một dòng riêng, `payment.status` là trạng thái **tổng hợp mới nhất** suy ra từ dòng +`payment_transaction` gần nhất thành công. + +### 1.5 Nhóm Hỗ trợ — 6 `CMP` còn lại *(schema-per-module trong cùng RDS chính, `ADR-006`)* + +| `CMP` | Schema | Thực thể chính | SoT | Đối chiếu `docs/05` (P1) | +|---|---|---|---|---| +| `CMP-05` Seller Management | `seller` | `seller`, `kyc_document`, `seller_bank_account` | `CMP-05` | Giữ nguyên tên bảng/cột `docs/05 §5.2.5` — chỉ đổi database-per-service → schema-per-module | +| `CMP-06` Commission & Payout | `commission` | `commission_rule` (gồm `hold_days`), `commission_transaction`, `payout`, `payout_hold` | `CMP-06` | Giữ nguyên `docs/05 §5.2.6`, kể cả trạng thái `payout_hold.release_status` (`holding`/`released`/`disputed_frozen`/`reversed`) | +| `CMP-07` Promotion & Loyalty | `promotion` | `promotion`, `promotion_usage`, `loyalty_account`, `loyalty_transaction`, `membership_tier` | `CMP-07` | Giữ nguyên `docs/05 §5.2.7` | +| `CMP-08` Review | `review` | `review` | `CMP-08` | Giữ nguyên `docs/05 §5.2.8` | +| `CMP-09` Notification | `notification` | `notification_log`, `template` | `CMP-09` | Giữ nguyên `docs/05 §5.2.9` (thêm bảng `template` — không có trong `docs/05`, do `SAD §4.1` liệt kê `CMP-09` sở hữu "Template") | +| `CMP-10` Shipping & Fulfillment | `shipping` | `shipment`, `shipment_event` | `CMP-10` | Giữ nguyên `docs/05 §5.2.10` | + +*Các module này không thuộc phạm vi "chi tiết nhất" của ghi chú người duyệt — chỉ xác nhận +ownership + tên bảng kế thừa từ `docs/05` (điều chỉnh sang schema-per-module). Schema chi tiết +đầy đủ (kiểu dữ liệu, index) thuộc dev khi module đó tới lượt thiết kế chi tiết ở GĐ2 kế tiếp.* + +### 1.6 Hạ tầng dữ liệu dùng chung + +| Hạ tầng | Vai trò | Ai sở hữu | Dữ liệu tồn tại bao lâu | +|---|---|---|---| +| `CMP-13` RDS chính | Physical host cho 8 schema (`identity`/`catalog`/`cart_order`/`seller`/`commission`/`promotion`/`review`/`notification`/`shipping`) | Ops/DBA | Theo backup/PITR §9 | +| `CMP-14` RDS Payment | Physical host riêng cho schema `payment` | Ops/DBA (quyền tách biệt hoàn toàn, `ADR-002`) | Theo backup/PITR §9 | +| `CMP-15` Redis | Cache session/ownership (hiện có); nội dung `Cart` (đề xuất, chưa chốt — `OQ-040`) | Ops/SRE (hạ tầng) + module tương ứng (key schema) | TTL theo loại key (§1.1, §7.3) | +| `CMP-12` Message Backbone (SQS FIFO + EventBridge) | Transit, không phải kho dữ liệu bền vững | Platform/SRE | DLQ giữ 14 ngày (đề xuất TẠM, `OQ-036`) | +| S3 + CloudFront (`SAD §4`) | Ảnh sản phẩm (public), KYC documents (private) | Ops/SRE + `CMP-05`/`CMP-03` | Xem §6 | + +🔴 **15/15 `CMP` đã có bảng ownership ở trên — không `CMP` mồ côi dữ liệu, không thực thể nào có +hai chủ.** `CMP-01` (ALB) và `CMP-12` (Message Backbone) không sở hữu dữ liệu bền vững (đúng theo +`SAD §4.1` "không" ở cột dữ liệu sở hữu). + +--- + +## 2. Mô hình dữ liệu mức khái niệm + +*Thực thể và quan hệ, chưa phải schema vật lý. Chi tiết nhất: Cart & Order + Payment.* + +### 2.1 ERD — Cart & Order + Payment *(chi tiết nhất, theo yêu cầu)* + +```mermaid +erDiagram + CART ||--o{ CART_ITEM : contains + ORDER ||--o{ ORDER_SELLER : "splits_into (ADR-003)" + ORDER ||--o| PAYMENT : "paid_by (1 payment / order — xem OQ-043)" + ORDER_SELLER ||--o{ ORDER_ITEM : contains + ORDER_SELLER ||--o{ ORDER_STATUS_HISTORY : tracks + ORDER_SELLER ||--o{ RETURN_REQUEST : may_have + ORDER_SELLER ||--o{ DISPUTE : may_have + PAYMENT ||--o{ PAYMENT_TRANSACTION : "mỗi lần gọi gateway" + PAYMENT ||--o{ PAYMENT_RECONCILIATION_LOG : reconciled_by + + CART { + uuid id PK + uuid customer_id FK "logic, nullable — Guest" + string session_id "dùng khi Guest" + enum status "active/converted/abandoned — BR-CART §3" + } + CART_ITEM { + uuid id PK + uuid cart_id FK + uuid product_variant_id FK "logic → catalog" + uuid seller_id FK "logic → seller" + string seller_name_snapshot "MỚI — ICD §3.1.1/§3.7, OQ-033 chốt TẠM" + int quantity + numeric unit_price_snapshot "VND, snapshot lúc thêm giỏ" + } + ORDER { + uuid id PK + uuid customer_id FK "logic, nullable — Guest checkout" + string order_number "khoá nghiệp vụ" + numeric total_amount "= Σ order_seller.subtotal_amount" + enum payment_init_status "MỚI — ADR-013: not_applicable/pending_payment_init/payment_init_ready/payment_init_failed" + string idempotency_key "khoá gốc của POST /v1/checkout, ADR-004/013" + timestamp placed_at + } + ORDER_SELLER { + uuid id PK + uuid order_id FK + uuid seller_id FK "logic → seller" + string sub_order_number "khoá nghiệp vụ" + numeric subtotal_amount + enum status "pending/confirmed/cancelled — BR-CART §3 (đoạn khởi tạo)" + } + ORDER_ITEM { + uuid id PK + uuid order_seller_id FK + uuid product_variant_id FK "logic → catalog" + string product_name_snapshot + int quantity + numeric unit_price_snapshot "VND, snapshot lúc đặt hàng — có thể khác cart_item nếu giá đổi giữa 2 mốc" + } + ORDER_STATUS_HISTORY { + bigint id PK + uuid order_seller_id FK + string status + timestamp changed_at + } + RETURN_REQUEST { + uuid id PK + uuid order_seller_id FK + string status + } + DISPUTE { + uuid id PK + uuid order_seller_id FK + uuid assigned_csr_id FK "logic → identity" + string status + } + PAYMENT { + uuid id PK + uuid order_id "logic — KHÔNG FK vật lý, khác RDS (ADR-002)" + enum method "vnpay/momo/cod" + numeric amount + enum status "pending_init/success/failed/refunded" + timestamp paid_at + } + PAYMENT_TRANSACTION { + uuid id PK + uuid payment_id FK + enum direction "init/webhook" + string gateway_transaction_ref + jsonb gateway_response_snapshot "không chứa số thẻ/CVV — BR-CART-05" + string status + timestamp created_at + } + PAYMENT_RECONCILIATION_LOG { + uuid id PK + uuid payment_id FK + string gateway_status + string discrepancy_note + timestamp reconciled_at + } +``` + +**Legend:** `||--o{` một-nhiều · `||--o|` một-không hoặc một · đường nối `PAYMENT`↔`ORDER` là +**FK logic** (khác RDS, không ràng buộc vật lý được — kiểm chứng bằng `IF-006`/sự kiện, không +bằng JOIN SQL). + +🔴 **Khác biệt so với `BR_CartCheckout §4` (BA):** BA chưa biết `ADR-013` khi viết ERD — DAT bổ +sung `order.payment_init_status` và `order.idempotency_key`, `cart_item.seller_name_snapshot`. +Đây là **bổ sung kỹ thuật**, không đổi mô hình nghiệp vụ BA đã chốt (`Order`/`OrderSeller`/ +`OrderItem` giữ nguyên cấu trúc cha-con). Không sửa `BR_CartCheckout` — ghi nhận ở §12 (đối chiếu +BA). + +### 2.2 Bảng thực thể chi tiết (Cart & Order + Payment) + +| Thực thể | Ý nghĩa nghiệp vụ | Khoá nghiệp vụ | Ước lượng số bản ghi (năm 1 / năm 3) | Tăng trưởng | Nguồn | +|---|---|---|---|---|---| +| `cart` | Giỏ hàng | *(id kỹ thuật)* | 🔴 Chưa có số — `TCO §2` chỉ có concurrent user (2.000/10.000), không có số giỏ hàng tuyệt đối | Theo `QAS-009` (×3/2 năm) | `BR_CartCheckout §4.1` | +| `cart_item` | Dòng sản phẩm trong giỏ | `(cart_id, product_variant_id)` | 🔴 Chưa có số | Theo `cart` | `BR_CartCheckout §4.1` | +| `order`/`order_seller`/`order_item` | Đơn hàng cha/con/dòng | `order_number`/`sub_order_number` | Kịch bản A: ~400 đơn/giờ đỉnh · B: ~15.000 đơn/giờ đỉnh (`QAS-002` nguồn) — **chưa có số/ngày hay /năm tuyệt đối**, `Confidence` 🔴 | Theo `QAS-009` | `QAS-002`, `TCO §2` | +| `payment` | Giao dịch thanh toán (1/`order`) | — | ≈ bằng số `order` (trừ đơn hủy trước khi khởi tạo thanh toán) | Theo `order` | Suy từ `order` | +| `payment_transaction` | Mỗi lần gọi gateway (init/webhook) | — | ≥1× số `payment` (có thể nhiều nếu khách thử lại — `ADR-013 §3.3`) | Theo `payment` × tỷ lệ thử lại (chưa đo — `ADR-013 §7`) | §1.4.1 | +| `payment_reconciliation_log` | Log đối soát định kỳ | — | Số `payment` × số chu kỳ đối soát chạy trong đời `payment` (đề xuất ≤15 phút/lần, `QAS-014`) — **có thể lớn hơn nhiều lần số `payment`**, cần retention ngắn (§6) | Cao — cần partition theo tháng (tham khảo `docs/05 §5.3.3`) | `ADR-004` | + +🔴 **`TCO §2`/`QAS-009` chỉ có số concurrent user và đơn/giờ đỉnh, không có ước lượng số bản ghi +tuyệt đối theo năm** — mục "Ước lượng số bản ghi" của template không điền được đầy đủ. Không bịa +con số — đây là khoảng trống thật, ghi `OQ-047` (mới, §11). + +### 2.3 Entity list rút gọn — các module còn lại + +*Không lặp lại `docs/05 §5.2` — chỉ liệt kê để đối chiếu ownership (đã có ở §1.5), tên bảng/cột +đầy đủ xem tài liệu tham khảo đó (điều chỉnh database-per-service → schema-per-module).* + +--- + +## 3. Chọn công nghệ lưu trữ + +| Kho | Loại | Chứa gì | Vì sao loại này | `ADR` | +|---|---|---|---|---| +| RDS PostgreSQL Multi-AZ chính | Quan hệ | 8 schema (Identity, Catalog, Cart&Order, Seller, Commission, Promotion, Review, Notification, Shipping) | Gắn `QAS-006` (p95 write ≤300ms, read ≤200ms, tải gộp); Conway (`CON-05`) — 1 instance thay vì ~9-10 | `ADR-006` | +| RDS PostgreSQL Multi-AZ riêng | Quan hệ | Schema `payment` (`payment`, `payment_transaction`, `payment_reconciliation_log`) | Gắn `ASR-002`/`QAS-011` — cô lập PCI-DSS SAQ A | `ADR-002` | +| ElastiCache Redis | Khoá-giá trị | Session, ownership cache (hiện có); nội dung `Cart` (đề xuất — §7.3) | Gắn `QAS-003`/`QAS-004`/`QAS-010` | `ADR-007` | +| S3 + CloudFront | Object storage | Ảnh sản phẩm (public), KYC documents (private) | Kế thừa `SAD §4`, không đổi | — | +| Postgres full-text search (trong schema `catalog`) | Tìm kiếm (tạm) | Chỉ mục tìm kiếm sản phẩm | `SAD §10`: hoãn OpenSearch ở P2 MVP, dùng FTS Postgres tới khi có bằng chứng tải cần OpenSearch (ngưỡng: traffic thật ≥ kịch bản B ×2, `QAS-009`) | — | +| SQS FIFO + EventBridge | Message queue | Transit sự kiện `OrderPlaced`/`PaymentConfirmed`/`PaymentInitRequested`/`PaymentInitReady`/`PaymentInitFailed` | Gắn `QAS-005` | `ADR-005` | + +**Phương án bị loại** *(kế thừa từ `OPT`/`ADR-001`, không lặp lại chi tiết — quy tắc `D3`)*: + +| Loại | Loại vì | Xét lại khi | +|---|---|---| +| Database-per-service (mỗi `CMP` một RDS riêng, như `docs/05` P1) | Vi phạm Conway với năng lực team hiện tại (`CON-05`), tăng chi phí vận hành ~9-10 instance thay vì 2 | `POC-02` FAIL nghiêm trọng **và** team đủ lớn để vận hành nhiều DB (`ADR-006 §4`) | +| OpenSearch ngay từ đầu | `TCO §3.2`/`OPT §3` P2 hoãn chi phí này ở MVP | Traffic thật ≥ kịch bản B ×2 chưa kiểm chứng (`SAD §10`) | +| Kafka/MSK thay SQS/EventBridge | Đội chưa xác nhận kinh nghiệm production (`CON-05`, `OQ-010`) | `POC-01` FAIL nghiêm trọng (`ADR-005 §4`) | + +--- + +## 4. Consistency + +| Nhánh dữ liệu | Mức nhất quán | Trễ tối đa | Vì sao chấp nhận được | Ai chấp nhận | `ADR`/`QAS` | +|---|---|---|---|---|---| +| Tạo `Order`/`OrderSeller`/`OrderItem` trong 1 lần checkout | **Mạnh** (1 transaction ACID, schema `cart_order`) | 0 | `ASR-003` — cấu trúc cha-con phải tạo trọn vẹn hoặc không tạo gì | SA + Tech Lead | `ADR-003`, `QAS-002` | +| `order.payment_init_status` phản ánh kết quả khởi tạo thanh toán online | **Eventual** | Ngưỡng UX 15 giây (`ADR-013 §3.1`); ngưỡng "kẹt" cần job dọn — đề xuất §4.3 | Khách chấp nhận chờ ngắn để đổi lấy `QAS-002` luôn đạt (`ADR-013`, đã chọn Lựa chọn B) | Tech Lead + PO (đã chốt hướng, chờ ký thật) | `ADR-013`, `QAS-002` | +| `payment.status` (Payment Service) ↔ trạng thái thật ở VNPay/Momo | **Eventual**, có giới hạn thời gian bù bằng job đối soát | ≤15 phút (`QAS-014`, đề xuất — `OQ-021` chưa xác nhận) | Không thể đảm bảo mạnh vì phụ thuộc bên thứ ba (`ASR-004`) — job đối soát bù là biện pháp bắt buộc, không phải "chấp nhận rủi ro" | Tech Lead (kỹ thuật) — **không phải quyết định nghiệp vụ**, vì đây là ràng buộc vật lý (không kiểm soát được uptime đối tác) | `ADR-004`, `QAS-014` | +| `OrderSeller.status` (Cart&Order) ← `PaymentConfirmed` (Payment) | **Eventual** | Fan-out lag ≤5 giây (`QAS-005`) | Người dùng không cần thấy cập nhật tức thời sau khi đã thấy trang xác nhận đặt hàng | PO (đã ngụ ý chấp nhận qua `QAS-005`) | `ADR-005` | +| `CommissionTransaction`/`NotificationLog`/`Review` (eligibility)/`Shipment` ← `OrderPlaced` | **Eventual** | Fan-out lag ≤5 giây (`QAS-005`) + xử lý riêng từng consumer (chưa đo) | Không nằm trên đường găng checkout; nghiệp vụ chấp nhận trễ vài giây tới vài phút | PO | `ADR-005` | +| `inventory_stock.quantity_reserved` khi checkout thất bại/hủy | **Mạnh trong phạm vi 1 transaction** cho bước reserve; **compensation bất đồng bộ** khi `PAYMENT_INIT_FAILED` không được khách xử lý (job dọn, §4.3) giải phóng reserve | Theo ngưỡng job dọn — đề xuất 5 phút (§4.3, `OQ-042`) | `BR-CART-02` yêu cầu không oversell — reserve phải mạnh; nhưng release khi hủy có thể trễ vài phút không gây oversell (chỉ tạm "khoá nhầm" tồn kho) | Tech Lead | `ASR-006`, `BR-CART-02` | + +🔴 **"Eventual" không có con số trễ là câu nói suông** (`D2`/template §4) — mọi dòng trên đều có +con số hoặc tham chiếu tới `OQ` đang chờ con số (`OQ-021` cho tần suất đối soát thật). + +### 4.1 Giao dịch xuyên service — khoảng trống outbox (`FAIL §7`) + +`FAIL_e-commerce_v1.0.md §7` đã ghi nhận khoảng trống: nếu service chết **sau** `COMMIT` transaction +tạo `Order` nhưng **trước** khi publish `OrderPlaced`/`PaymentInitRequested` thành công, sự kiện +bị mất vĩnh viễn — không consumer nào (Commission, Promotion, Notification, Shipping, Payment) +biết `Order` đó tồn tại. Đây là bài toán **dual write** kinh điển (ghi DB + gọi message queue không +nguyên tử). + +**Hai phương án đã cân nhắc** *(quy tắc `D3` — chưa viết `ADR` chính thức, xem cảnh báo dưới)*: + +| Phương án | Mô tả | Ưu | Nhược | +|---|---|---|---| +| **PA-1 — Job quét đối chiếu** | Job định kỳ (đề xuất mỗi 5 phút) quét `order` không có event tương ứng đã publish thành công (dựa cột đánh dấu `event_published_at`), publish lại | Không cần bảng/hạ tầng mới | Cần một cột đánh dấu đủ tin cậy; có race condition giữa "đang xử lý" và "đã mất" nếu không thiết kế cẩn thận; không tổng quát cho các module khác publish event sau này | +| **PA-2 — Transactional Outbox** *(đề xuất SA)* | Ghi một dòng `outbox_event` **trong cùng transaction DB** với việc tạo `Order`/`OrderSeller`/`OrderItem` (cùng schema `cart_order`, cùng ACID). Một relay (poller nội bộ hoặc job định kỳ ngắn, đề xuất mỗi 1-2 giây) đọc `outbox_event` trạng thái `pending`, publish lên SQS/EventBridge, đánh dấu `published` khi thành công | Đảm bảo tính nguyên tử thật sự giữa ghi DB và phát sự kiện (industry-standard, dùng được cho **mọi** module publish event sau này — Payment cũng dùng bảng `outbox_event` riêng trong RDS Payment của nó) | Thêm bảng + một relay process cần giám sát (lag alerting); độ trễ publish tăng nhẹ (1-2 giây thay vì tức thời) | + +**Đề xuất SA: PA-2 (Outbox pattern).** Vì đây là **quyết định thiết lập tiền lệ** cho toàn hệ +thống (mọi module publish event sau này sẽ dùng cùng cơ chế, không chỉ Cart & Order) — +theo `decision-radar.md §4` ("ngoại lệ tiền lệ"), ước lượng radar **~6/10** (đảo ngược trung +bình=1 · bán kính: Cart&Order + Payment (2 CMP publish) + tiền lệ cho các module tương lai=1 · +chạm `QAS-005`/gián tiếp `DRV-08` (không mất giao dịch)=1 · ràng buộc trở thành chuẩn chung ≥1 +năm=2 · chưa tranh cãi=0, +1 vì thiết lập tiền lệ áp dụng toàn hệ thống) → **`ADR` bắt buộc** — +xem [`adr/ADR-014_transactional-outbox-publish-su-kien.md`](adr/ADR-014_transactional-outbox-publish-su-kien.md) +(`Proposed`, viết ở lượt hoạt động `adr` kế tiếp). `OQ-044` **giữ nguyên mở**, chờ Tech Lead thật +xác nhận thiết kế relay (số instance, HA) trước khi `ADR-014` chuyển `Accepted` — xem `ADR-014 §3`. + +**Bù trừ khi lỗi giữa chừng (nếu PA-2 được chọn):** + +| Bước lỗi | Ai phát hiện | Xử lý | +|---|---|---| +| Relay chết trước khi publish | Alerting theo `outbox_event` tuổi > ngưỡng (đề xuất 1 phút, chưa xác nhận) chưa `published` | Restart relay (nhiều instance, không đơn điểm lỗi) — `outbox_event` vẫn còn trong DB, không mất | +| Publish thành công nhưng đánh dấu `published` thất bại (crash giữa hai bước) | Relay quét lại thấy `pending` dù đã publish | Chấp nhận **at-least-once** — consumer đã có dedupe theo `eventId` (`ICD §4`), publish trùng không gây hiệu ứng phụ | +| `outbox_event` tồn đọng số lượng lớn (relay chậm hơn tốc độ ghi) | CloudWatch metric số dòng `pending` | Backpressure — chưa thiết kế cụ thể, ứng viên `inf` | + +**Bảng theo template (`saga`/`outbox`/`2PC`/không có):** + +| Luồng nghiệp vụ | Cơ chế | Bù trừ khi lỗi giữa chừng | Ai phát hiện lệch | `ADR` | +|---|---|---|---|---| +| Checkout → publish `OrderPlaced`/`PaymentInitRequested` | **Outbox** | Xem bảng trên | Alerting lag `outbox_event` (`inf`, chưa thiết kế) | [`ADR-014`](adr/ADR-014_transactional-outbox-publish-su-kien.md) *(`Proposed`, `OQ-044` giữ mở)* | +| Payment Service → publish `PaymentConfirmed`/`PaymentInitReady`/`PaymentInitFailed` | **Outbox** (bảng riêng trong RDS Payment) *(cùng cơ chế)* | Tương tự | Tương tự | [`ADR-014`](adr/ADR-014_transactional-outbox-publish-su-kien.md) | +| Webhook VNPay/Momo → cập nhật `payment.status` | Không saga — xử lý đồng bộ trong 1 transaction schema `payment`, bù bằng job đối soát nếu webhook không tới (`ADR-004`) | Job đối soát ≤15 phút phát hiện lệch, ghi `payment_reconciliation_log`, cảnh báo — **không tự động sửa** | Job đối soát | `ADR-004` | +| Checkout thất bại giữa chừng (VD `IF-005` timeout trước bước ghi `Order`) | Không có gì để bù — transaction chưa `BEGIN`/đã `ROLLBACK`, không có trạng thái nửa vời | N/A | N/A | — | + +### 4.2 Idempotency store cho `POST /v1/checkout` + +*Theo `ADR-004`/`ICD §1` mục 7 — `Idempotency-Key` bắt buộc cho `POST /v1/checkout`.* + +| Thực thể | Cột | Ý nghĩa | +|---|---|---| +| `idempotency_key` *(mới, schema `cart_order`)* | `idempotency_key` (UNIQUE) | Giá trị header `Idempotency-Key` do client gửi | +| | `endpoint` | VD `POST /v1/checkout` — cho phép tái sử dụng bảng này cho các endpoint ghi khác sau này | +| | `request_hash` | Hash body request — phát hiện client gửi lại **cùng key nhưng khác nội dung** (lỗi client, phải từ chối `409`, không âm thầm dùng response cũ) | +| | `response_snapshot` (jsonb) | Response đã trả lần đầu — trả lại nguyên vẹn nếu gọi lại trong TTL | +| | `status` | `processing` (đang xử lý, tránh race hai request đồng thời cùng key) / `completed` | +| | `expires_at` | **Đề xuất TTL 48 giờ** (đủ dài cho khách quay lại thử thanh toán trong ngày, đủ ngắn để không phình bảng vô hạn) — 🔴 chưa xác nhận Tech Lead | + +**Webhook thanh toán KHÔNG dùng bảng này** — dùng khoá nghiệp vụ tự nhiên +`payment_transaction.gateway_transaction_ref` (UNIQUE constraint), đúng theo `ICD §1` mục 7 (đối +tác ngoài không tự đặt `Idempotency-Key`). + +### 4.3 Job dọn `Order` kẹt ở `PENDING_PAYMENT_INIT` — đề xuất cho `OQ-042` + +*`OQ-042` (`00-index/OQ_e-commerce.md`) hỏi ngưỡng thời gian giữ `Order` ở `PENDING_PAYMENT_INIT` +trước khi coi là "kẹt". Đây là đề xuất của `DAT`, **không tự quyết** — Tech Lead xác nhận.* + +| | Đề xuất SA | +|---|---| +| **Ngưỡng quét** | `order.payment_init_status = pending_payment_init` **và** `order.placed_at` cũ hơn **5 phút** (gấp ~2× ngưỡng UX "kẹt" 15 giây × margin an toàn cho retry/hàng đợi chậm — không dùng chung ngưỡng 15 giây của UX vì đó là ngưỡng *hiển thị cho khách*, không phải ngưỡng *hệ thống coi là thất bại vĩnh viễn*) | +| **Tần suất job** | Mỗi 5 phút (tham khảo mẫu tương tự `docs/05 §5.2.6` job quét `payout_hold`) | +| **Hành động khi phát hiện** | (1) Cập nhật `order.payment_init_status = payment_init_failed` (nếu chưa có sự kiện `PaymentInitFailed` nào tới — coi như mất sự kiện); (2) Giải phóng `inventory_stock.quantity_reserved` tương ứng (gọi `IF-005` release, đối xứng với bước reserve ở checkout); (3) Ghi `order_status_history`; (4) Cảnh báo Ops nếu số lượng "kẹt" phát hiện trong 1 lần quét vượt ngưỡng bất thường (đề xuất >5 đơn/lần quét — chưa xác nhận) | +| **Rủi ro ngưỡng quá ngắn** | Hủy nhầm `Order` mà VNPay/Momo chỉ đang xử lý chậm bất thường (chưa timeout thật ở phía Payment Service) | +| **Rủi ro ngưỡng quá dài** | `Order` "ma" tồn đọng lâu, tồn kho reserve bị khoá không cần thiết, nhiễu báo cáo doanh số | + +🔴 Cập nhật `OQ-042` trong sổ `00-index/OQ_e-commerce.md` với đề xuất này (giữ nguyên **mở**, chờ +Tech Lead xác nhận) — xem §11. + +--- + +## 5. Phân loại dữ liệu & tuân thủ + +*🔴 **`ADR-008` (Security/Legal) chưa có người ký** (`OQ-007`) — bảng dưới là đề xuất phân loại + +retention của SA, **không phải quyết định cuối**. Phủ quyết thuộc Pháp chế/Bảo mật.* + +| Nhóm dữ liệu | Mức nhạy cảm | Ví dụ trường | Lưu ở đâu | Mã hoá at-rest | Che khi hiển thị | Retention *(đề xuất, chờ Legal)* | Cách xoá theo yêu cầu | +|---|---|---|---|---|---|---|---| +| Danh tính & liên hệ khách hàng | **PII** | `user_account.email/phone`, `customer_profile.full_name/date_of_birth` | schema `identity` | RDS KMS (mặc định) + mã hoá tầng ứng dụng cho `mfa_device.secret_encrypted` (khuyến nghị, `sec` xác nhận) | Không che với chính chủ; không hiển thị cho seller | Ẩn danh hoá trong **30 ngày** kể từ yêu cầu xoá hợp lệ (NĐ13/2023), giữ `order`/`payment` liên quan ở dạng tách định danh (tham khảo `docs/05 §5.3.6`, **assumption** `ASM-37`) | Ẩn danh hoá (anonymize), không xoá cứng bản ghi tài chính liên quan | +| Địa chỉ giao hàng | **PII** | `customer_address.recipient_name/phone/address_line`, snapshot trong `order_seller` lúc checkout | schema `identity` (SoT) + snapshot trong `cart_order` (một chiều) | RDS KMS | **Whitelist cho seller theo `ADR-008` PA-2** (đề xuất, chờ Security/Legal): chỉ `recipient_name`/`phone`/`address_line` của `OrderSeller` tương ứng — **không** chia sẻ email, lịch sử mua hàng, hay địa chỉ của seller khác trong cùng `Order` | Cùng nhóm với danh tính khách hàng ở trên | Cùng cơ chế trên | +| Tên gian hàng (denormalize) | Nội bộ (không PII) | `cart_item.seller_name_snapshot` | schema `cart_order` | Không cần mã hoá riêng (dữ liệu công khai — tên gian hàng hiển thị công khai trên sàn) | Không cần che | Theo vòng đời `cart` (§6) | Xoá cùng `cart` | +| KYC seller | **PII nhạy cảm** | `kyc_document.file_url_s3` (ảnh CMND/giấy phép kinh doanh), `seller.tax_code/business_license_number` | schema `seller` + S3 bucket riêng (private) | S3 server-side encryption + RDS KMS; đề xuất mã hoá tầng ứng dụng cho object S3 (khuyến nghị `sec` xác nhận) | Chỉ Admin/CSR được duyệt xem (`RBAC` của module Seller, ngoài phạm vi US-002/003) | Tối thiểu **5 năm** sau khi seller ngừng hoạt động (tham khảo `docs/05 §5.3.6`, **assumption** `ASM-37`, chờ Legal) | Không xoá trong thời hạn lưu trữ pháp lý — chỉ ẩn khỏi truy cập vận hành thường ngày sau khi seller đóng | +| Thông tin tài khoản ngân hàng seller | **Payment** | `seller_bank_account.account_number/account_holder_name` | schema `seller` | **Bắt buộc mã hoá tầng ứng dụng** (không chỉ dựa KMS) — đề xuất, `sec` xác nhận | Che một phần khi hiển thị (VD `****1234`) — chi tiết thuộc `sec` | Theo thời hạn hợp đồng seller + tối thiểu 10 năm sau giao dịch cuối (kế toán, tham khảo `docs/05`) | Không xoá trong thời hạn kế toán | +| Dữ liệu thanh toán khách hàng | **Payment — KHÔNG lưu số thẻ/CVV** (`BR-CART-05`, SAQ A) | `payment.amount`, `payment_transaction.gateway_transaction_ref`, `gateway_response_snapshot` (đã lọc, không chứa thẻ) | schema `payment` (RDS riêng, `ADR-002`) | RDS KMS + mã hoá tầng ứng dụng cho `gateway_transaction_ref` (khuyến nghị) | Chỉ hiển thị tham chiếu rút gọn cho khách, không hiển thị `gateway_response_snapshot` thô | Tối thiểu **10 năm** (chứng từ kế toán, tham khảo `docs/05 §5.3.6`, `ASM-37`) | Không xoá — dữ liệu tài chính bắt buộc lưu theo luật kế toán | +| Dữ liệu nghiệp vụ công khai/nội bộ | Công khai/nội bộ | `product`, `category`, `review`, `commission_rule` | Các schema tương ứng | RDS KMS mặc định | Không cần che | Theo vòng đời nghiệp vụ (§6) | Xoá thường theo yêu cầu quản trị (không liên quan NĐ13/2023) | + +### 5.1 Ràng buộc pháp lý + +| Ràng buộc pháp lý | Nguồn | Hệ quả kiến trúc | +|---|---|---| +| Dữ liệu cá nhân phải xác nhận nơi lưu trữ đáp ứng NĐ13/2023 | `CON-06`, `ASM-04` (chưa xác nhận), `ADR-008` | RDS/S3 đặt tại `ap-southeast-1` — **chưa được Legal xác nhận đủ** (`OQ-007`); áp dụng cho cả backup/snapshot, không chỉ dữ liệu online (xem cảnh báo dưới) | +| PCI-DSS SAQ A — không lưu thẻ/CVV | `CON-06`, `BR-CART-05`, `ADR-002` | Không trường nào trong bất kỳ schema nào ngoài `payment` được chứa dữ liệu thẻ; `payment_transaction.gateway_response_snapshot` phải được lọc trước khi ghi (loại bỏ trường thẻ nếu gateway trả về, dù không mong đợi) | +| Quyền được xoá (NĐ13/2023) | `CON-06` | Ẩn danh hoá, không xoá cứng, cho dữ liệu có ràng buộc tài chính/kế toán song song (xem bảng §5) | + +🔴 **Backup và log cũng chứa PII** (`design-rules.md D9`/template §5) — snapshot PITR của schema +`identity`/`cart_order` chứa toàn bộ PII chưa ẩn danh tại thời điểm backup; `payment_transaction. +gateway_response_snapshot` trong backup cũng phải tuân cùng ràng buộc residency. Retention backup +(§9) phải đối chiếu lại với retention dữ liệu ở bảng trên khi Legal xác nhận — hiện **chưa đối +chiếu được vì Legal chưa có** (`OQ-007`). + +### 5.2 Whitelist chia sẻ PII cho seller — hiện thực hoá `ADR-008` PA-2 + +*`ADR-008` (Security/Legal, chưa ký) đề xuất whitelist `recipient_name`/`phone`/`address_line`. +DAT hiện thực hoá thành cơ chế: `order_seller` (schema `cart_order`) chỉ lưu **snapshot đúng 3 +trường này** của địa chỉ giao hàng liên quan tới `OrderSeller` đó — **không** lưu tham chiếu tới +toàn bộ `customer_address`/`user_account` của khách. Bất kỳ API nào trả dữ liệu `OrderSeller` cho +Seller Management (`IF` tương lai, ngoài phạm vi US-002/003) chỉ đọc 3 trường này, không JOIN +ngược sang schema `identity`.* + +🔴 Đây là thiết kế **hiện thực hoá đề xuất PA-2 của `ADR-008`** — không phải quyết định độc lập +của `DAT`. Nếu Security/Legal từ chối PA-2 khi có người ký, thiết kế này phải sửa theo phương án +được chọn (`ADR-008` vẫn `Proposed`, chưa `Accepted`). + +--- + +## 6. Vòng đời & lưu trữ dài hạn + +| Thực thể | Dữ liệu nóng | Chuyển sang lạnh sau | Xoá sau | Ai duyệt | +|---|---|---|---|---| +| `cart` (Guest) | Redis/RDS, hoạt động | — | 7 ngày không hoạt động → `abandoned` (`BR-CART §3`, tham khảo `docs/05 §5.3.1`) | Tech Lead (đã có tiền lệ tham khảo) | +| `cart` (Customer) | RDS, hoạt động | — | 30 ngày không hoạt động → `abandoned` (tham khảo `docs/05`, `BR-CART §3` chưa chốt số chính thức — `OQ` của BA) | PO/Tech Lead | +| `order`/`order_seller`/`order_item` | RDS, 12 tháng gần nhất | Partition theo tháng (tham khảo `docs/05 §5.3.3`), archive sau 12 tháng sang storage rẻ hơn (đề xuất, chưa xác nhận) | Không xoá — dữ liệu tài chính/pháp lý (10 năm, xem §5) | Tech Lead + Kế toán | +| `payment`/`payment_transaction`/`payment_reconciliation_log` | RDS Payment, 12 tháng gần nhất | Partition theo tháng | Không xoá trong 10 năm (§5) | Tech Lead + Kế toán | +| `outbox_event` (cả hai schema) | RDS, vài giờ gần nhất | — | **Xoá sau 7 ngày kể từ `published`** (đề xuất — không cần giữ lâu, chỉ phục vụ relay + debug ngắn hạn) | Tech Lead | +| `idempotency_key` | RDS | — | Xoá khi `expires_at` qua (đề xuất 48 giờ, §4.2) — job dọn định kỳ | Tech Lead | +| `notification_log`, `shipment_event` | RDS | 90 ngày (tham khảo `docs/05 §5.3.6`) | Archive lạnh hoặc xoá sau 90 ngày | Ops | +| `kyc_document` (S3 + metadata) | S3 versioning + cross-region replication | — | Tối thiểu 5 năm sau khi seller ngừng hoạt động (§5, `ASM-37`) | Legal + PO | + +--- + +## 7. Hiệu năng dữ liệu + +### 7.1 Chỉ mục cho `QAS-003`/`QAS-004`/`QAS-006` + +| Truy vấn quan trọng | Tần suất | Khối lượng quét | Chỉ mục cần | `QAS` | +|---|---|---|---|---| +| `GET /v1/cart` — lấy `cart` theo `customer_id`/`session_id` + `cart_item` theo `cart_id` | Đọc nhiều (mỗi lần mở SCR-04) | ≤50 dòng/giỏ (`ASM-16`, `QAS §A3`) | `index(cart.customer_id)`, `index(cart.session_id)`, `index(cart_item.cart_id)` | `QAS-003` | +| `PATCH`/`DELETE /v1/cart/items/{id}` | Ghi đơn lẻ | 1 dòng | PK `cart_item.id` (đủ, không cần thêm) | `QAS-004` | +| `POST /v1/checkout` — ghi `order`+N `order_seller`+N `order_item` | Ghi theo tải đỉnh (`QAS-002`) | N ≤ số seller trong giỏ (thường nhỏ) | PK tự nhiên đủ; cần `index(order.customer_id, placed_at DESC)` cho truy vấn lịch sử đơn sau này | `QAS-002`, `QAS-006` | +| Kiểm tra/giữ tồn kho (`IF-005`) | Đọc+ghi trong mọi checkout | 1 dòng/`product_variant` | PK `inventory_stock.variant_id` (1-1, đã đủ) | `QAS-006` | +| Job đối soát (`payment_reconciliation_log`) | Theo chu kỳ (≤15 phút, `QAS-014`) | Số `payment` đang `pending_init`/`success` gần đây | `index(payment.status, paid_at)` | `QAS-014` | + +### 7.2 Read replica + +| | Quyết định | +|---|---| +| **Có read replica không** | Có — nhưng **chỉ tồn tại ở kịch bản B** (`SAD §7`: "B: r6g.2xlarge + 1 read replica"; kịch bản A không có) | +| **Route cái gì sang replica** | Đề xuất SA: **Catalog & Inventory** (đọc nhiều, phục vụ tìm kiếm/duyệt sản phẩm — không nằm trên đường găng ghi) route sang replica khi có (kịch bản B). **Cart & Order KHÔNG route sang replica** — `GET /v1/cart` cần đọc-ngay-sau-ghi (khách vừa `PATCH` xong phải thấy kết quả ngay), replica lag (`ASM-36`, chưa đo) có thể vi phạm tính đúng đắn cảm nhận được, rủi ro cao hơn lợi ích latency | +| **Vì sao** | Gắn `QAS-003`/`QAS-006` — Catalog chịu tải đọc gấp ~10× tải ghi (`QAS-006` nguồn: "~150.000 truy vấn catalog/giờ so với ~15.000 đơn/giờ"), hưởng lợi rõ từ replica; Cart&Order tải đọc/ghi cân bằng hơn và nhạy cảm với độ tươi dữ liệu | +| **`ADR`** | Không đạt ngưỡng `ADR` (radar ước lượng ~3: đảo ngược thấp, bán kính 1 module, không chạm `QAS` Must trực tiếp theo hướng tiêu cực, có thể đổi routing qua config) — ghi `OQ-046` (§11), không cần `ADR` | + +### 7.3 Cache nội dung `Cart` — đánh giá cho `OQ-040` + +*`OQ-040` (`FAIL §4`) hỏi: có nên thêm cache nội dung `Cart`/`CartItem` vào Redis để `GET +/v1/cart` có fallback thật khi RDS chậm không? Đây là đánh giá của `DAT`, **không tự quyết**.* + +| | Phương án A — Không cache (giữ nguyên) | Phương án B — Thêm cache nội dung `Cart` | +|---|---|---| +| **Mô tả** | `GET /v1/cart` luôn đọc RDS; RDS chậm/lỗi → `503` (timeout 200ms theo `FAIL FM-06`) | Cache-aside: ghi cache khi `PATCH`/`DELETE`/thêm giỏ (write-through), đọc cache trước, fallback RDS nếu miss; TTL đề xuất ngắn (5-10 phút) vì giá/tồn kho có thể đổi | +| **Đạt `QAS-003` khi RDS chậm** | ❌ Không — trả lỗi nhanh hơn, không phải trả đúng | ✅ Có — miễn cache còn dữ liệu | +| **Rủi ro dữ liệu cũ** | Không có (luôn đọc SoT) | Giá/tồn kho hiển thị có thể lệch trong TTL — đã có cơ chế `priceChanged` (`ICD §3.1.1`) giảm nhẹ rủi ro giá, nhưng **không** giảm rủi ro hiển thị sai `quantity` nếu khách sửa giỏ ở tab khác trong TTL | +| **Độ phức tạp thêm** | Không | Cần thiết kế invalidation (write-through khi `PATCH`/`DELETE`), thêm 1 loại key Redis mới, thêm giám sát hit/miss ratio | +| **Chi phí hạ tầng** | Không đổi | Redis hiện tại (`CMP-15`) đã có sẵn — chi phí thêm chủ yếu là dung lượng bộ nhớ (nhỏ, giỏ hàng ≤50 dòng) — không cần instance Redis mới | +| **Khuyến nghị SA** | — | **Nghiêng về B** nếu Tech Lead chấp nhận độ phức tạp invalidation, vì chi phí hạ tầng thấp và cải thiện trực tiếp khả dụng đúng lúc tải cao (flash sale — thời điểm RDS dễ chậm nhất, theo `QAS-006`/`ARISK-02`) | + +🔴 Cập nhật `OQ-040` trong sổ với bảng đánh giá này (giữ nguyên **mở**, chờ Tech Lead quyết định +cuối) — xem §11. + +### 7.4 Bảng quyết định chung + +| Vấn đề | Quyết định | `ADR` | +|---|---|---| +| Phân mảnh (sharding/partitioning) | **Không sharding ở MVP** (kế thừa lý do `docs/05 §5.3.4` — schema-per-module đã là lớp scale đầu tiên); **partitioning theo tháng** cho `order`/`order_seller`/`order_item`, `payment`/`payment_transaction`/`payment_reconciliation_log` (tăng trưởng nhanh nhất, tham khảo `docs/05 §5.3.3`) | Không cần `ADR` riêng (kỹ thuật thi công, radar thấp) | +| Đọc/ghi tách nhau | Có, chỉ Catalog dùng read replica (kịch bản B) — xem §7.2 | Không cần `ADR` (`OQ-046`) | +| Cache: cái gì, invalidate thế nào | Session/ownership (đã có, `ADR-007`); nội dung `Cart` (đề xuất, chưa chốt — `OQ-040`) | `ADR-007` (đã có); cache Cart chưa cần `ADR` nếu chỉ áp dụng 1 module (radar thấp) | + +🔴 **Cache invalidation phải thiết kế cùng lúc với cache** (`D` template) — nếu Phương án B ở +§7.3 được chọn, cơ chế invalidate (write-through khi `PATCH`/`DELETE`) phải triển khai đồng thời, +không được để cache "TTL tự nhiên" là biện pháp duy nhất. + +--- + +## 8. Migration dữ liệu & Versioning schema + +### 8.1 Migration dữ liệu legacy + +**Không áp dụng — dự án greenfield**, theo `CTX`/`docs/05 §5.3.5`: không có hệ thống cũ cần +migrate cho module Giỏ hàng & Checkout. Dữ liệu khởi tạo chỉ gồm cấu hình tĩnh (`language`, +`currency`, `commission_rule` mặc định — thuộc các module khác, ngoài phạm vi chi tiết của +`DAT` lượt này). + +### 8.2 Versioning schema (đề xuất — chưa chốt) + +| | Đề xuất SA | +|---|---| +| **Công cụ** | Flyway (SQL migration thuần, phổ biến với PostgreSQL, không yêu cầu ORM cụ thể) — **đề xuất, chưa xác nhận Tech Lead** (`ICD §2` đã ghi "Flyway/Liquibase chưa chọn"); ghi `OQ-045` | +| **Chính sách thay đổi schema** | Additive trước, breaking sau — khớp `ICD §2 IF-016/017` ("Migration versioned tăng dần, không breaking ngược") | +| **Ranh giới migration theo schema** | Mỗi schema (`identity`/`catalog`/`cart_order`/.../`payment`) có thư mục migration riêng, chạy độc lập — khớp nguyên tắc schema-per-module (`ADR-006`), migration của `payment` chạy trên RDS Payment hoàn toàn tách biệt (không chung pipeline CI/CD deploy với schema khác, để giữ ranh giới cô lập `ADR-002`) | +| **Rollback schema** | Mỗi migration có script `down` tương ứng (Flyway Community không hỗ trợ auto-rollback — cần viết migration bù thủ công nếu cần lùi) — 🔴 đây là giới hạn công cụ cần Tech Lead biết trước khi chọn | + +--- + +## 9. Sao lưu & khôi phục + +*Đối chiếu `QAS-008`/`ADR-009` (RPO ≤15 phút, RTO ≤1 giờ cho Payment, Cart&Order, Identity — +"nhóm giao dịch cốt lõi") và `TCO §3.2` (dòng "Backup & DR" ≈$30/$60/tháng).* + +| | RDS chính (8 schema) | RDS Payment | +|---|---|---| +| Tần suất backup | Automated backup + PITR liên tục (WAL archiving) | Automated backup + PITR liên tục | +| Retention PITR | 🔴 **Đề xuất 35 ngày** (tham khảo `docs/05 §5.3.2` cho nhóm "giao dịch cốt lõi") — chưa xác nhận Ops/SRE | 🔴 Đề xuất 35 ngày (cùng lý do — dữ liệu tài chính) | +| **Lần khôi phục thử gần nhất** | **Chưa từng thử** — `Confidence` 🔴, `ARISK` (đã ghi ở `ADR-009`) | **Chưa từng thử** — cùng `ARISK` | +| RPO | ≤15 phút (mục tiêu `QAS-008`, chưa diễn tập) | ≤15 phút (cùng mục tiêu) | +| RTO | ≤1 giờ (mục tiêu `QAS-008`, chưa diễn tập) | ≤1 giờ (cùng mục tiêu) | + +🔴 **Phát hiện quan trọng — RPO/RTO đồng nhất ngoài ý muốn giữa module lõi và không lõi:** vì +`ADR-006` gộp **8 schema vào 1 RDS instance**, backup/PITR/Multi-AZ failover áp dụng ở **mức +instance**, không phân biệt được schema `cart_order`/`identity` (lõi, cần RPO≤15 phút) với schema +`seller`/`commission`/`promotion`/`review`/`notification`/`shipping` (không lõi, `docs/05 §5.3.2` +P1 đề xuất RPO/RTO lỏng hơn — ví dụ ≤1 giờ/≤4 giờ hoặc ≤24 giờ/≤24 giờ tuỳ nhóm). **Hệ quả:** mọi +schema trong RDS chính **đều được hưởng RPO/RTO chặt của nhóm lõi "miễn phí"** (tốt hơn yêu cầu +tối thiểu cho module không lõi) — không phải lỗi, nhưng khác với giả định phân tầng chi phí của +`docs/05` P1 (vốn tách theo instance để có backup rẻ hơn cho module ít quan trọng). `TCO §3.2` +hiện chỉ có 1 dòng "Backup & DR" chung, khớp với thực tế 1 instance — **không có mâu thuẫn số +liệu**, chỉ ghi nhận đây là đặc điểm của kiến trúc gộp, không phải khác biệt cần sửa. + +| S3 (KYC, ảnh sản phẩm) | Đề xuất | +|---|---| +| Versioning | Bật cho bucket KYC (PII pháp lý) | +| Cross-region replication | Bật cho bucket KYC — tham khảo `docs/05 §5.3.2` | +| Lifecycle | Ảnh sản phẩm ít truy cập → storage rẻ hơn sau 90 ngày (tham khảo `docs/05`) | + +--- + +## 10. Đối chiếu với `docs/sections/05-thiet-ke-du-lieu.md` (P1) — chỉ tham khảo + +*Theo ghi chú người duyệt: tài liệu P1 chỉ dùng để tham khảo tên bảng/cột/số retention đề xuất, +**không** kế thừa kiểu kiến trúc. Danh sách khác biệt chính:* + +| # | P1 (`docs/05`) | P2 (`DAT` này) | Ghi chú | +|---|---|---|---| +| 1 | Database-per-service (mỗi service 1 RDS) | 1 RDS chính schema-per-module + 1 RDS Payment riêng (`ADR-006`/`ADR-002`) | Đã ghi ở §3 | +| 2 | Kafka/MSK cho event | SQS FIFO + EventBridge (`ADR-005`) | Ảnh hưởng cơ chế dedupe/ordering — đã thiết kế lại ở `ICD §4` | +| 3 | Không có trạng thái `PENDING_PAYMENT_INIT`/`PAYMENT_INIT_READY`/`PAYMENT_INIT_FAILED` ở `order` | Có, theo `ADR-013` (bất đồng bộ hoá khởi tạo thanh toán) | P1 không có yêu cầu này vì chưa phát hiện xung đột ngân sách `QAS-002` — đặc thù của P2 | +| 4 | Có service **Audit & Compliance** riêng (`audit_log` tập trung, v3) | **P2 `SAD §4` (15 `CMP`) KHÔNG có `CMP` Audit & Compliance riêng** | 🔴 **Khoảng trống thật** — chưa kiến trúc audit trail xuyên module cho P2 dù `RBAC_CartCheckout §5` (BA) và `ADR-008 §6` (audit định kỳ PII) đều cần. Ghi `OQ-047` (§11), ngoài phạm vi giải quyết đầy đủ ở `DAT` lượt này | +| 5 | `cart_item` không có `seller_name_snapshot`; `order_item.unit_price` không phân biệt snapshot vs giá hiện tại | `cart_item.seller_name_snapshot`, `unit_price_snapshot`; `order_item.unit_price_snapshot` | Bổ sung theo `ICD §3.1.1/§3.7` (`OQ-033` chốt TẠM) | +| 6 | Retention cụ thể theo bảng (`docs/05 §5.3.6`) | Kế thừa làm **đề xuất khởi điểm**, chưa xác nhận Legal (`OQ-007`) | Không copy nguyên trạng làm quyết định — chỉ dùng làm baseline đề xuất | + +--- + +## 11. Giả định & Ngoài phạm vi + +**Giả định** *(tiếp số toàn dự án — `ASM-01…34` đã dùng, bắt đầu `ASM-35`)*: + +| ID | Giả định | Cách xác minh | Nếu sai | +|---|---|---|---| +| `ASM-35` | 1 `Order` (cha) có đúng 1 `Payment` bất kể checkout gồm bao nhiêu seller/phương thức (theo `BR_CartCheckout §4` ERD gốc: `ORDER ||--o| PAYMENT`) | Tech Lead xác nhận qua `OQ-043` | Nếu sai (VD Payment tách theo `OrderSeller`): mô hình `payment.order_id` phải đổi thành `payment.order_seller_id`, ảnh hưởng `IF-006` request/response (`ICD §3.3`, `OQ-030`) và `order.payment_init_status` phải tính lại từ N `Payment` thay vì 1 | +| `ASM-36` | Read replica (kịch bản B) có độ trễ nhân bản đủ thấp (<1 giây) để không ảnh hưởng cảm nhận "mới cập nhật" khi dùng cho Catalog | Đo thật sau khi có replica (`inf`/`POC-02`) | Nếu lag cao hơn: cần điều chỉnh chiến lược cache Catalog (TTL ngắn hơn) hoặc không dùng replica cho các API vừa ghi vừa đọc gần nhau (VD Seller vừa cập nhật giá) | +| `ASM-37` | Số năm retention tham khảo từ `docs/05 §5.3.6` (30 ngày ẩn danh hoá, 5 năm KYC, 10 năm tài chính) là điểm khởi đầu hợp lý cho P2, dù kiến trúc lưu trữ đã đổi (schema-per-module) | Đại diện Pháp chế/Bảo mật xác nhận khi có người (`OQ-007`) | Nếu Legal yêu cầu số khác: sửa bảng §5/§6, có thể ảnh hưởng thiết kế partition (`docs/05 §5.3.3` tham khảo) nếu retention ngắn hơn nhiều | +| `ASM-38` | Outbox relay có thể chạy trong cùng process/task với module publish (Cart & Order, Payment) bằng polling loop 1-2 giây, không cần dịch vụ riêng, ở quy mô kịch bản A/B hiện tại | Đo thật khi có `POC` throughput hoặc sau go-live | Nếu tải cao hơn dự kiến khiến polling loop không theo kịp: cần tách relay thành service riêng hoặc dùng CDC (Debezium) — thay đổi hạ tầng đáng kể | + +**Ngoài phạm vi:** + +- Schema chi tiết đầy đủ (kiểu dữ liệu cột, index đầy đủ, constraint) cho 6 module Nhóm Hỗ trợ + (Seller, Commission, Promotion, Review, Notification, Shipping) — chỉ xác nhận ownership + + entity list (§1.5), kế thừa tên bảng từ `docs/05`; chi tiết hoá đầy đủ thuộc dev khi module đó + tới lượt. +- Kiến trúc audit trail xuyên module (Audit & Compliance Service kiểu P1, hoặc phương án khác) — + khoảng trống ghi nhận ở §10 dòng 4, `OQ-047`, thuộc hoạt động `sec`/`adr` kế tiếp. +- Thiết kế chi tiết OpenSearch (schema chỉ mục, đồng bộ) — hoãn tới khi có bằng chứng tải cần, + theo `SAD §10`. +- `ADR` chính thức cho outbox pattern (§4.1) — chỉ trình bày phân tích + đề xuất, chưa viết + `ADR`, thuộc hoạt động `adr` kế tiếp (`OQ-044`). +- Cấu hình connection pool cụ thể theo module (`OQ-037`, đã có ở `FAIL`) — `DAT` chỉ xác nhận + ranh giới schema cần pool riêng (§1), số cụ thể chờ `POC-02`. +- Chi tiết mã hoá tầng ứng dụng (thuật toán, quản lý khoá) cho các trường đánh dấu "khuyến nghị + mã hoá" ở §5 — thuộc hoạt động `sec` (hoạt động 6, chưa chạy). + +## 12. Open Questions + +*Tiếp số sổ SA (`00-index/OQ_e-commerce.md` đang ở `OQ-042`) — bắt đầu `OQ-043`.* + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược | +|---|---|---|---|---|---| +| `OQ-043` | 1 `Order` (cha) có đúng 1 `Payment` (đa seller, 1 phương thức chung) hay có ngoại lệ tách `Payment` theo `OrderSeller`/phương thức? (nối `OQ-030` của `ICD`) | Tech Lead + PO | 2026-09-15 | Mô hình `payment.order_id`; `IF-006` request/response (`ICD §3.3`); `order.payment_init_status` | Nếu tách theo `OrderSeller`: cần N lời gọi gateway thay vì 1, ảnh hưởng cả `ADR-013` (mỗi `OrderSeller` có trạng thái init riêng, phức tạp hơn UX hiện tại) và chi phí giao dịch (một số gateway tính phí theo giao dịch) | +| `OQ-044` | Chấp nhận **Transactional Outbox pattern** (`outbox_event` + relay poller) làm cơ chế chính thức xử lý khoảng trống "commit `Order` nhưng publish event thất bại" (`FAIL §7`) không, hay dùng job quét đối chiếu đơn giản hơn (PA-1, §4.1)? Radar ước lượng ~6/10 — `ADR` bắt buộc, chưa viết. | Tech Lead | 2026-09-15 | `ADR` mới ở hoạt động `adr` kế tiếp; thiết kế relay ở `inf` | Chọn PA-1 (job quét): tiết kiệm 1 bảng/relay nhưng cần thiết kế cột đánh dấu đủ tin cậy và có race condition tiềm ẩn; không tổng quát cho module publish event sau này — mỗi module tự nghĩ cách riêng | +| `OQ-045` | Công cụ quản lý migration schema — Flyway hay Liquibase (hoặc khác)? | Tech Lead | 2026-09-15 | Quy trình CI/CD; khả năng rollback schema (§8.2) | Flyway: đơn giản, SQL thuần, nhưng Community không auto-rollback (cần viết migration bù thủ công). Liquibase: hỗ trợ rollback tốt hơn nhưng cú pháp XML/YAML phức tạp hơn, đường cong học tập cao hơn cho team chưa dùng | +| `OQ-046` | Đọc `Cart`/`Order` có nên route sang RDS read replica (chỉ có ở kịch bản B) hay luôn đọc primary? SA đề xuất: chỉ Catalog dùng replica, Cart&Order luôn đọc primary (§7.2). | Tech Lead | 2026-09-15 | Cấu hình routing đọc ở `inf`; độ tươi dữ liệu `GET /v1/cart` | Nếu Cart&Order cũng dùng replica để giảm tải primary: có thể vi phạm read-your-write ngay sau `PATCH`, gây bug khó tái hiện ("tôi vừa sửa giỏ mà sao không thấy") | +| `OQ-047` | P2 (`SAD` 15 `CMP`) không có `CMP` Audit & Compliance riêng như P1 (`docs/05` v3) — audit trail xuyên module (`RBAC_CartCheckout §5`, `ADR-008 §6`) nên kiến trúc theo cách nào: (a) mỗi module tự ghi `audit_log` trong schema riêng, hay (b) thêm 1 `CMP` Audit tập trung? | Tech Lead + Security | 2026-09-15 | Danh sách `CMP` (có thể thêm `CMP-16`); `ADR-001` (nếu thêm component mới ảnh hưởng cấu trúc tổng thể) | Chọn (a): đơn giản hơn, không thêm component, nhưng khó tổng hợp audit xuyên module khi CSR/Admin cần tra cứu. Chọn (b): tập trung hoá tra cứu nhưng thêm 1 `CMP`/1 điểm publish event bắt buộc từ mọi module — cần rà lại `SAD §4` | + +**Cập nhật các `OQ` đã mở, không tạo ID mới** *(ghi trong sổ `00-index/OQ_e-commerce.md`, xem §13 +đối chiếu)*: + +- **`OQ-007`** — bổ sung: `DAT §5` đã phân loại PII/Payment/nghiệp vụ + đề xuất retention (30 + ngày ẩn danh hoá PII khách hàng, 5 năm KYC, 10 năm tài chính — tham khảo `docs/05`, `ASM-37`) + và whitelist chia sẻ seller (`recipient_name`/`phone`/`address_line`, hiện thực hoá `ADR-008` + PA-2 ở §5.2) — **vẫn chờ đại diện Pháp chế/Bảo mật phủ quyết**, giữ nguyên **mở**. +- **`OQ-040`** — bổ sung: `DAT §7.3` đánh giá 2 phương án (không cache / cache-aside nội dung + `Cart`) kèm hệ quả — SA nghiêng về Phương án B nếu Tech Lead chấp nhận độ phức tạp invalidation, + giữ nguyên **mở**. +- **`OQ-042`** — bổ sung: `DAT §4.3` đề xuất ngưỡng quét 5 phút + tần suất job 5 phút + hành động + (cập nhật trạng thái, giải phóng tồn kho reserve, cảnh báo Ops) — giữ nguyên **mở**, chờ Tech + Lead xác nhận. + +--- + +## 13. Tự chấm + +### ① Bảng tự chấm Gate AG2 *(`workflow.md §2` — chỉ dòng liên quan tới `DAT`, tự chấm sớm)* + +| # | Tiêu chí | ☐/✅ | Ghi chú | +|---|---|---|---| +| — | `ASR`/`QAS`/`SAD`/`ICD`/`FAIL` | ✅ *(đã đạ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 | 13 `ADR` đã có (`ADR-001…013`); `DAT` phát hiện 1 quyết định mới đạt ngưỡng (outbox pattern, radar ~6) **chưa viết `ADR`** — đúng phạm vi (`dat` không bao gồm viết `ADR`), ghi `OQ-044`, chờ hoạt động `adr` | +| 1 | `DAT` — mỗi thực thể dữ liệu có **đúng một** chủ sở hữu; có phân loại PII và retention | ✅ | §1 (ownership đủ 15 `CMP`, không thực thể mồ côi/hai chủ), §5 (phân loại PII/Payment/nghiệp vụ + retention đề xuất) | +| — | `SEC`/`INF` | ☐ | Chưa tới — hoạt động 6-7 | +| — | `sa-conformance` báo coverage `ASR → ADR/CMP` ≥ 100% | *(không đổi bởi `DAT`)* | `DAT` không tạo `CMP`/`ASR` mới | + +**Kết luận tự chấm (riêng phần `DAT`):** Hoạt động `dat` hoàn tất đúng phạm vi được giao — +ownership đủ 15/15 `CMP` không mồ côi/không hai chủ (`D7`), mô hình `Order`/`OrderSeller`/ +`OrderItem` chi tiết theo `ADR-003`/`ADR-013`, phân loại PII/retention đề xuất (chờ Legal), chiến +lược đọc/ghi/cache/consistency đầy đủ theo `QAS-003/004/006/008/014`, phát hiện 1 khoảng trống cần +`ADR` mới (outbox, chưa viết — đúng phạm vi). AG2 còn thiếu `SEC`/`INF` (hoạt động 6-7) 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 | `DAT` không viết `ADR` mới (outbox là ứng viên, chưa viết — §4.1) | +| D2 | Không NFR định tính | ✅ | Mọi ngưỡng consistency/retention/TTL đều có con số hoặc tham chiếu `OQ` đang chờ số | +| D3 | Nêu phương án bị loại + lý do | ✅ | §3 (database-per-service/OpenSearch/Kafka bị loại, kế thừa `OPT`); §4.1 (PA-1 job quét bị loại thay bằng đề xuất PA-2 outbox, có bảng so sánh) | +| D4 | Sơ đồ khai báo mức + legend | ✅ | §2.1 khai báo "mức khái niệm" + legend; không trộn với mức schema vật lý | +| D5 | Interface có chủ/contract | N/A | Đã xử lý ở `ICD` (hoạt động 4); `DAT` chỉ tham chiếu | +| D6 | Phụ thuộc ngoài process có timeout/retry | N/A | Đã xử lý ở `FAIL` (hoạt động 8); `DAT` chỉ bổ sung khía cạnh dữ liệu (outbox, idempotency store) | +| D7 | Một chủ sở hữu dữ liệu | ✅ | §1 — bảng ownership đầy đủ 15 `CMP`, mỗi thực thể đúng 1 SoT, mọi bản sao ghi rõ cơ chế/độ trễ | +| D8 | Ràng buộc có FIT hoặc nhãn khuyến nghị | 🟡 Một phần | Đề xuất `FIT-26` (schema owner check mở rộng `FIT-09` đã có ở `ADR-006`), `FIT-27` (outbox lag monitor), `FIT-28` (idempotency TTL test) — ứng viên GĐ3, chưa viết thật | +| D9 | Con số hạ tầng quy ra tiền + nguồn | 🟡 Một phần | §9 dùng đúng số `TCO §3.2` (có nguồn); retention/backup cụ thể (35 ngày) là đề xuất tham khảo `docs/05`, chưa có báo giá riêng cho từng mức retention — không ảnh hưởng `TCO` hiện tại (1 dòng chung) | +| D10 | Không quyết định thay người có thẩm quyền | ✅ | §5 (PII/retention — chờ Legal), §7.3 (cache Cart — chờ Tech Lead), §4.1 (outbox — chờ Tech Lead + `adr`) đều trình phương án kèm hệ quả, không tự quyết | +| D11 | Có mục "Ngoài phạm vi" + `ASM-nn` | ✅ | §11 đầy đủ — `ASM-35…38` mớ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 | `DAT` tương ứng | Khớp? | Hành động | +|---|---|---|---|---| +| `BR_CartCheckout §4` (ERD khái niệm) | `Order`/`OrderSeller`/`OrderItem`/`Payment`, không có `payment_init_status` | §2.1 (bổ sung `payment_init_status`, `idempotency_key`, `seller_name_snapshot`) | 🟡 Một phần | Bổ sung kỹ thuật theo `ADR-013`/`ICD`, không đổi mô hình nghiệp vụ BA đã chốt — **BA không cần cập nhật `BR_CartCheckout`** vì đây là chi tiết kỹ thuật (state machine nội bộ), không phải quy tắc nghiệp vụ mới; nếu US-004 (Checkout) được BA viết `SRS` riêng sau này, cần phản ánh 4 trạng thái này ở đó (đã ghi `OQ-038` của `FAIL`) | +| `RBAC_CartCheckout §4` (mức che PII khi hiển thị cho seller — chưa chốt) | Whitelist `recipient_name`/`phone`/`address_line` (§5.2, hiện thực hoá `ADR-008` PA-2) | §5, §5.2 | 🟡 Một phần | `DAT` đề xuất cơ chế kỹ thuật (snapshot 3 trường, không JOIN ngược) — **vẫn chờ Security/Legal chốt chính thức** (`OQ-007`/`RISK-03` của BA), `DAT` không tự đóng câu hỏi này | +| `RBAC_CartCheckout §5` (lưu vết/audit — "chưa chốt thời hạn lưu") | §10 dòng 4 (khoảng trống Audit & Compliance `CMP`) | 🟡 Một phần | `DAT` phát hiện P2 chưa có kiến trúc audit trail xuyên module — **BA cần biết đây là khoảng trống kỹ thuật đang mở (`OQ-047`)**, chưa có nơi lưu vết chi tiết như `RBAC §5` kỳ vọng | +| `BR_CartCheckout §4.3` (thực thể ngoài phạm vi — `CUSTOMER`/`SELLER`/`PRODUCT_VARIANT` tham chiếu qua FK logic, snapshot giá) | §1.1/§1.2 (ownership `CMP-02`/`CMP-05`/`CMP-03`, snapshot `unit_price_snapshot`) | ✅ | Khớp hoàn toàn — `DAT` xác nhận đúng nguyên tắc BA đã nêu (FK logic, snapshot giá) | + +### ④ Danh sách `OQ` mở kèm người phải trả lời, chặn gì + +Xem §12 (`OQ-043…047` mới) cộng cập nhật `OQ-007/040/042`. Ba câu hỏi quan trọng nhất cho `sec`/ +`inf` kế tiếp: **`OQ-007`** (PII/residency, chặn `ADR-008` và toàn bộ §5), **`OQ-044`** (outbox +pattern, chặn `ADR` mới + thiết kế relay ở `inf`), **`OQ-043`** (cardinality `Payment`/`Order`, +chặn thiết kế cuối cùng của `IF-006`). Sổ đầy đủ: `00-index/OQ_e-commerce.md`. + +**Nhắc:** AG2 cần **Tech Lead + Security + Ops/SRE ký** — còn thiếu `SEC`/`INF` (hoạt động 6-7) và +1 `ADR` mới (outbox, `OQ-044`). Hoạt động kế tiếp có thể chạy song song: `sec` (dùng §5 phân loại +PII làm input threat model), `inf` (dùng §9 backup/RPO-RTO, §7.2 read replica, §4.1 relay outbox +nếu được chấp nhận). diff --git a/sa-output/e-commerce/02-architecture/FAIL_e-commerce_v1.0.md b/sa-output/e-commerce/02-architecture/FAIL_e-commerce_v1.0.md new file mode 100644 index 0000000..32f69b4 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/FAIL_e-commerce_v1.0.md @@ -0,0 +1,487 @@ +# 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). diff --git a/sa-output/e-commerce/02-architecture/ICD_e-commerce_v1.0.md b/sa-output/e-commerce/02-architecture/ICD_e-commerce_v1.0.md new file mode 100644 index 0000000..252b1f3 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/ICD_e-commerce_v1.0.md @@ -0,0 +1,600 @@ +# 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)* + +```json +{ + "data": { + "cartId": "cart_123", + "status": "active", + "sellers": [ + { + "sellerId": "seller_11", + "sellerName": "Shop A", + "subtotalVnd": 325000, + "items": [ + { + "cartItemId": "citem_001", + "productVariantId": "variant_789", + "productName": "Áo thun basic", + "variantLabel": "Size M, Đỏ", + "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)** + +```json +{ + "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):** + +```json +{ + "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):** + +```json +{ + "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`). diff --git a/sa-output/e-commerce/02-architecture/INF_e-commerce_v1.0.md b/sa-output/e-commerce/02-architecture/INF_e-commerce_v1.0.md new file mode 100644 index 0000000..fa72e30 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/INF_e-commerce_v1.0.md @@ -0,0 +1,718 @@ +# INF — Infrastructure & Deployment Design — e-commerce + +| | | +|---|---| +| **Version** | 1.1 | +| **Date** | 2026-09-15 | +| **Author** | SA (qua skill `sa-2-architecture`, chế độ `go`, hoạt động `inf`) | +| **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 topology AWS `ap-southeast-1`, bảng đối chiếu `INF↔TCO` (§10), HA/auto-scaling split ECS Nhóm Giao dịch/Nhóm Hỗ trợ A 2/2 – B 6/4 (`ASM-42`, `OQ-055` giữ mở), kế hoạch diễn tập DR 3 kịch bản (ngày thật `OQ-056` chờ Ops/SRE — điều kiện tiên quyết AG2), observability, CI/CD blue-green (`ADR-016` ứng viên), network/egress, IaC Terraform (`ADR-017` ứng viên). Chốt **TẠM** `OQ-058`: giữ nguyên `TCO` — **KHÔNG** thêm replica Redis ở kịch bản A, chấp nhận SPOF với hành vi fail-closed theo `FAIL` — `OQ-058` **giữ nguyên mở**, chờ PO xác nhận cuối. Đồng ý để SA viết `ADR-016`/`ADR-017` (`Proposed`) cùng `ADR-014`/`ADR-015` ở lượt hoạt động `adr` kế tiếp. `OQ-054` (cross-region snapshot Payment vs `ADR-009`) **giữ nguyên mở**. **KHÔNG ký thay Ops/SRE** — header `Approved by → Ops/SRE` giữ `—`. Security: **—** *(chưa ký)* · Ops/SRE: **—** *(chưa ký)*. `Confidence` giữ 🔴; Status giữ 🟡 Draft; AG2 chưa ký. | +| **Source** | `02-architecture/SAD_e-commerce_v1.0.md` v1.3 §4, §7, §10, §11 (`OQ-026/027`, `ASM-22/23`) · `02-architecture/QAS_e-commerce_v1.0.md` §A3 (`QAS-002/005/006/007/008/009/013/014`) · `02-architecture/ASR_e-commerce_v1.0.md` §B2 (`ASR-001/002/005/006/007/009/010/011/012/013/014`) · `02-architecture/FAIL_e-commerce_v1.0.md` v1.1 §1, §3, §7, §10 (`FM-01…13`, `OQ-035/036/037/039`) · `02-architecture/DAT_e-commerce_v1.0.md` §7.2, §8.2, §9, §11 (`OQ-045/046`) · `02-architecture/SEC_e-commerce_v1.0.md` §1, §2.4, §5, §6 (`OQ-048…053`, `DEC-28`) · `02-architecture/adr/ADR-005…006, 009…012_*.md` · `01-context/TCO_e-commerce_v1.0.md` §3.1–§3.2 · `01-context/CTX_e-commerce_v1.0.md` §3 (`CON-04/05/08`) · `01-context/ARISK_e-commerce_v1.0.md` §6 (`POC-01/POC-02`) · `00-index/OQ_e-commerce.md` (`OQ-008/020/022/026/027/036/046/050`) · `00-index/DEC_e-commerce.md` (`DEC-01…28`) · `e-commerce/docs/sections/09-van-hanh-kiem-thu.md` §9.3–§9.5 *(chỉ tái dùng khung CI/CD/rollback/RTO-RPO của tài liệu P1 gốc — điều chỉnh lại cho kiến trúc P2: 2 ECS service + Payment thay vì ~10 microservice, bỏ Kafka/MSK/OpenSearch)* | +| **Scope** | Toàn sàn e-commerce theo P2 (`SAD v1.3 §7` deployment view): hạ tầng AWS `ap-southeast-1`, HA/DR, scale, observability, CI/CD, kế hoạch diễn tập DR trước AG2. Hoạt động 7/9 của `sa-2-architecture` — không sửa `SAD`/`ICD`/`DAT`/`SEC`/`FAIL`/`ADR` đã có | +| **Confidence** | 🔴 Giả định chưa xác minh — theo yêu cầu điều phối, tiếp nối `Confidence` 🔴 của toàn bộ artifact GĐ2 trước đó. AG1 chưa ký thật; AG2 chưa tới hạn; `POC-01`/`POC-02`/diễn tập DR/diễn tập inject lỗi đều **chưa chạy**; mọi con số auto-scaling/pool/timeout hạ tầng 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 `inf`) | Bản đầu — hoạt động 7/9 của `sa-2-architecture`. Topology AWS `ap-southeast-1` (VPC/subnet/AZ, ALB+WAF, 2 ECS Fargate service Nhóm Giao dịch/Nhóm Hỗ trợ + Payment Service tách biệt, RDS chính Multi-AZ + RDS Payment, ElastiCache Redis, SQS FIFO+EventBridge+DLQ, S3+CloudFront, Secrets Manager/KMS, NAT) — đối chiếu từng dòng với `TCO §3.2` (bảng §10), phát hiện 1 điểm chưa khớp bản chất (cross-region snapshot Payment trong `TCO` vs "không multi-region" của `ADR-009`, ghi `OQ-054`), không tự sửa `TCO`/`ADR`. Đề xuất split ECS task Nhóm Giao dịch/Nhóm Hỗ trợ (A: 2/2, B: 6/4) khớp đúng tổng `TCO` (`OQ-055`, nối `OQ-026`). Thiết kế HA (Multi-AZ, health check, auto-scaling A→B theo `QAS-009`), DR (RPO≤15’/RTO≤1h theo `QAS-008`/`ADR-009`, backup/PITR, kế hoạch diễn tập DR 3 kịch bản kèm tiêu chí PASS/FAIL đo thật, đề xuất hạn trước AG2 — `OQ-022` ngày thật chờ Ops/SRE), observability (log/metric/trace/dashboard/alert theo `QAS-013`/`ADR-010`, DLQ 14 ngày + alert lag >5 phút theo `OQ-036`/`DEC-22`, on-call theo `CON-08` + `OQ-008`), CI/CD (pipeline build→test→scan→deploy, blue-green cho 3 ECS service, migration schema trong pipeline theo `OQ-045`), network/security group + egress đối tác ngoài (`OQ-057`), IaC (Terraform, đề xuất) + FIT ứng viên GĐ3 (`FIT-34…38`). Thêm `OQ-054…063`, `ASM-42…46`. Ghi ngoại lệ tiếp tục gate `DEC-29` (nối `DEC-28`). Đề xuất 2 `ADR` ứng viên mới (chiến lược triển khai blue-green, công cụ IaC) cho hoạt động `adr` kế tiếp — **không viết `ADR` ở lượt này** (ngoài phạm vi `inf`). `Confidence` 🔴 toàn bộ. | `DEC-29` | +| 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**: ghi nhận nội dung topology AWS `ap-southeast-1`, bảng đối chiếu `INF↔TCO` (§10), HA/auto-scaling split ECS GD/HT A 2/2 – B 6/4 (`ASM-42`, `OQ-055`), kế hoạch diễn tập DR 3 kịch bản (`OQ-022`/`OQ-056`, ngày thật chờ Ops/SRE — điều kiện tiên quyết AG2), observability, CI/CD blue-green (`ADR-016` ứng viên), network/egress, IaC Terraform (`ADR-017` ứng viên). Chốt **TẠM** `OQ-058`: giữ `TCO`, **KHÔNG** thêm replica Redis ở kịch bản A, chấp nhận SPOF với fail-closed theo `FAIL` — `OQ-058` giữ nguyên mở, chờ PO. Đồng ý viết `ADR-016`/`ADR-017` (`Proposed`) cùng `ADR-014`/`ADR-015` ở lượt `adr` kế tiếp. `OQ-054` (cross-region snapshot vs `ADR-009`) giữ nguyên mở. **KHÔNG ký thay Ops/SRE** — header `Approved by → Ops/SRE` giữ `—`. Security chưa ký. Không đổi nội dung chuyên môn nào của tài liệu. `Confidence` giữ 🔴; Status giữ 🟡 Draft; AG2 chưa ký. Ghi thêm `DEC-30`. | `DEC-30` | +| 1.1 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `adr`) | **Chỉ link ADR, không đổi nội dung.** `ADR-016` (blue-green qua AWS CodeDeploy) và `ADR-017` (IaC Terraform), cả hai `Proposed`, vừa được viết theo đề xuất đã duyệt TẠM ở `DEC-30` — thay các dòng "chưa viết, ngoài phạm vi `inf`" ở §7.2 và §11 bằng đường dẫn thật; cập nhật bảng Truy vết §13. `OQ-056`/`OQ-020` (điều kiện `Accepted` `ADR-016`) và `OQ-060` (điều kiện `Accepted` `ADR-017`) giữ nguyên mở. Không sửa nội dung chuyên môn nào khác của `INF`. Ghi `DEC-31` (tiếp nối `DEC-01…30`). | `ADR-016`, `ADR-017`, `DEC-31` | + +> 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ố** (số task, ngưỡng scale, RTO/RPO, retention). +> 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 phải chọn bên (`D12`). + +--- + +## 0. Ghi chú Preflight & ngoại lệ gate + +AG1 chưa được ký chính thức; AG2 (gate của chính GĐ2) càng 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`); +`ICD`/`DAT`/`SEC`/`FAIL`/`ADR` (hoạt động 4, 5, 6, 8, 9) cũng đã chạy và duyệt từng phần +(`DEC-17…28`) — điều kiện đầu vào cho `inf` đã đủ. + +Người dùng (vai điều phối dự án chạy thử) đã được cảnh báo lại AG1/AG2 chưa qua và **khẳng định +muốn tiếp tục**. Ghi ngoại lệ tại: + +> **DEC-29 (SA)** — Tiếp tục `sa-2-architecture` (hoạt động 7 — `INF`) 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…28`. +> **Quyết định:** Dựng `INF` (topology, HA/DR, scale, observability, CI/CD, network/security, +> IaC) dựa trên `SAD §7` + `TCO §3.2` đã duyệt từng phần, giữ `Confidence 🔴` cho tới khi: (a) +> AG1 ký thật, (b) `POC-01`/`POC-02` chạy xong, (c) diễn tập DR (`QAS-008`/`ADR-009`) và diễn tập +> inject lỗi (`QAS-013`/`ADR-010`) chạy xong PASS, (d) `OQ-010`/`OQ-026`/`OQ-027` (số đội thật, +> khớp `TCO`, vị trí Identity) được Tech Lead/Ops trả lời. +> **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 (tài liệu hạ tầng sửa được qua version mới, +> chưa là Terraform code thật) · bán kính ảnh hưởng: hoạt động `sa-3-enablement` phụ thuộc `INF` +> này, nhưng bản thân *việc ghi tài liệu dưới ngoại lệ* thì nhỏ · chạm `QAS-008/009/013` Must +> trực tiếp (đang thiết kế hạ tầng hiện thực hoá) nhưng chưa cam kết thi công (chưa IaC thật) · +> không ràng buộc dài hạn tự thân · không tranh cãi mới → **ghi `DEC-nn`, không cần `ADR`** +> (`decision-radar.md §1–§2`). +> **Hệ quả nếu không chấp nhận ngoại lệ:** dừng GĐ2 ở hoạt động `fail`, không có `INF` để `AGD`/ +> `FIT` (GĐ3) và Ops dùng làm đầu vào chuẩn bị go-live — chậm tiến độ chạy thử tương ứng thời gian +> xử lý các `OQ` đang mở, đặc biệt `OQ-022` (lịch diễn tập DR, điều kiện tiên quyết AG2). + +🔴 **Nhắc quan trọng:** chưa `POC-01`/`POC-02`, chưa diễn tập DR, chưa diễn tập inject lỗi — mọi +con số auto-scaling/ngưỡng cảnh báo/kích thước instance dưới đây là **mục tiêu thiết kế**, không +phải kết quả đã đo. `AGD`/`FIT`/`IaC` thật (Terraform) là công việc của `sa-3-enablement`, ngoài +phạm vi tài liệu này. + +--- + +## 1. Tóm tắt + +| | | +|---|---| +| **Cloud / vùng** | AWS `ap-southeast-1` (Singapore) — kế thừa `TCO §3` (`ASM-11`); ràng buộc lãnh thổ VN (`CON-06`/NĐ13) chưa xác nhận cần cư trú dữ liệu trong nước (`OQ-007` Pháp chế, `CTX`) | +| **Mô hình chạy** | ECS Fargate — 3 service triển khai: **Nhóm Giao dịch**, **Nhóm Hỗ trợ**, **Payment** (`ADR-001` Proposed, `ADR-012` Proposed) | +| **Chịu được mất gì** | 1 AZ (Multi-AZ toàn bộ compute/data); **không** chịu được mất toàn vùng `ap-southeast-1` ở MVP (`ADR-009` PA-1) | +| **RTO / RPO** | Nhóm giao dịch cốt lõi (Payment/Cart&Order/Identity): **RPO ≤15 phút / RTO ≤1 giờ** (`QAS-008`/`ADR-009`) · **chưa từng diễn tập** — kế hoạch diễn tập ở §5.4, `OQ-022` | +| **Chi phí/tháng ở tải dự kiến** | Kịch bản A: **≈ $2.409/tháng (≈ 60,2 triệu VND)** · Kịch bản B: **≈ $5.862/tháng (≈ 146,6 triệu VND)** — khớp `TCO §3.2`, xem đối chiếu §10 | +| **Điểm chưa khớp `TCO` phát hiện ở lượt này** | 1 điểm bản chất (`OQ-054` — cross-region snapshot Payment trong `TCO` vs quyết định "không multi-region" của `ADR-009`) — không tự sửa, xem §10 | + +--- + +## 2. Môi trường + +| Môi trường | Mục đích | Cấu hình so với prod | Dữ liệu | Ai truy cập được | +|---|---|---|---|---| +| dev | Phát triển, tích hợp nhanh | ~15–20% Production (đề xuất SA, chưa xác nhận — `TCO §3.2` chỉ gộp chung "non-prod ~35%") | Dữ liệu sinh (seed script) | Dev team | +| stg | **Đo `QAS`**, UAT, integration test với sandbox đối tác | ~35% Production theo `TCO §3.2` — **KHÔNG cùng công suất prod** (xem cảnh báo dưới) | Ẩn danh hoá (không PII/KYC thật, theo `SEC §5`) | Dev + QA + Tech Lead; Ops/SRE cho diễn tập DR/chaos | +| prod | Vận hành thật | 100% (§3, §9) | Thật | Ops/SRE + Admin qua IAM role có audit; không ai truy cập DB Production trực tiếp trừ khẩn cấp có phê duyệt (kế thừa `docs/09 §9.3.2`) | + +🔴 **Câu hỏi bắt buộc đã trả lời một phần:** stg chạy ở **~35% công suất** RDS/ECS so với prod +(`r6g.xlarge`/`t4g.medium` giảm size — cụ thể chưa chốt kích cỡ instance stg, `OQ-062`). Điều này +làm sai lệch trực tiếp việc đo `QAS-002` (checkout p95 ≤3s) và `QAS-006` (RDS gộp) nếu chạy thẳng +trên stg với cấu hình thu nhỏ — **`POC-01`/`POC-02` phải chạy trên cấu hình instance PROD thật** +(`ARISK §6` đã ghi rõ "cấu hình instance thật", không phải stg thu nhỏ) để không tự lừa mình theo +đúng cảnh báo `SKILL.md` mục 7. + +| `QAS` cần đo | Đo được trên stg (cấu hình thu nhỏ)? | Nếu không, đo ở đâu | Sai số ước tính | +|---|---|---|---| +| `QAS-002` (checkout p95 ≤3s) | 🟡 Một phần — đo được luồng logic/timeout, nhưng số tuyệt đối không đại diện | Staging với **cấu hình tạm nâng lên bằng prod** trong cửa sổ chạy `POC`/load test, hạ lại sau | Không định lượng được nếu không nâng cấu hình — biên độ RDS nhỏ hơn có thể khiến p95 đo được cao hơn thực tế 20–50% (ước lượng, chưa đo) | +| `QAS-005`/`QAS-006` (`POC-01`/`POC-02`) | ❌ Không — `ARISK §6` đã quy định rõ chạy trên "cấu hình instance thật" | Staging, **nâng tạm** lên đúng cấu hình prod (`r6g.xlarge`, SQS FIFO thật) chỉ trong thời gian chạy POC | N/A — đây chính là lý do `POC` phải chạy đúng cấu hình, không phải trên bản thu nhỏ | +| `QAS-008` (DR drill) | ✅ Có — diễn tập DR chạy trên staging trước, không cần đúng size (đo RTO/RPO theo tỷ lệ, quy trình là chính, không phải hiệu năng tuyệt đối) | — | Thấp — quy trình failover không phụ thuộc kích cỡ instance | +| `QAS-013` (alert ≤1 phút) | ✅ Có — chaos/inject lỗi không phụ thuộc kích cỡ instance | — | Thấp | + +--- + +## 3. Sơ đồ triển khai + +*Mức: **Deployment view**, bổ sung chi tiết VPC/subnet/AZ so với `SAD §7` (SAD chưa thiết kế ranh +giới mạng con chi tiết — ghi rõ ở `SAD §10` "thuộc hoạt động `inf`"). Vùng: AWS `ap-southeast-1`, +2 AZ (`ap-southeast-1a`, `ap-southeast-1b`).* + +```mermaid +flowchart TB + subgraph INTERNET["Internet"] + Users["Guest/Customer/Seller/Admin"] + ExtPay["VNPay · Momo"] + ExtShip["GHN · GHTK"] + ExtNotif["Email/SMS Provider"] + end + + subgraph VPC["VPC — ap-southeast-1 (đề xuất CIDR 10.0.0.0/16, chưa chốt)"] + subgraph AZa["AZ a (ap-southeast-1a)"] + subgraph PubA["Public subnet A"] + WAFa["WAF"] + ALBa["ALB (node A)"] + NATa["NAT Gateway A"] + end + subgraph AppA["Private subnet A — ứng dụng"] + GDa["ECS task — Nhóm Giao dịch"] + HTa["ECS task — Nhóm Hỗ trợ"] + PAYa["ECS task — Payment (SG riêng)"] + end + subgraph DataA["Private subnet A — dữ liệu"] + RDSMa[("RDS chính — writer/AZ a")] + RDSPa[("RDS Payment — writer/AZ a")] + Redisa[("Redis — primary")] + end + end + subgraph AZb["AZ b (ap-southeast-1b)"] + subgraph PubB["Public subnet B"] + ALBb["ALB (node B)"] + NATb["NAT Gateway B"] + end + subgraph AppB["Private subnet B — ứng dụng"] + GDb["ECS task — Nhóm Giao dịch"] + HTb["ECS task — Nhóm Hỗ trợ"] + PAYb["ECS task — Payment (SG riêng)"] + end + subgraph DataB["Private subnet B — dữ liệu"] + RDSMb[("RDS chính — standby/AZ b (+ read replica, chỉ kịch bản B)")] + RDSPb[("RDS Payment — standby/AZ b")] + Redisb[("Redis — replica, chỉ kịch bản B — SPOF ở kịch bản A, §4.3")] + end + end + CM["AWS Cloud Map / ECS Service Connect\n(service discovery GD↔HT nội bộ)"] + SQS[("SQS FIFO + EventBridge + DLQ")] + S3[("S3 (asset/KYC)")] + CF["CloudFront"] + SM["Secrets Manager"] + KMS["KMS (CMK)"] + end + + Users -->|"1 · HTTPS, sync"| WAFa + Users -->|"1 · HTTPS, sync"| ALBb + WAFa -->|"2 · HTTPS, sync"| ALBa + ALBa -->|"3 · HTTP, sync"| GDa + ALBa -->|"3 · HTTP, sync"| HTa + ALBa -->|"3 · HTTP, sync, SG riêng"| PAYa + ALBb -->|"3 · HTTP, sync"| GDb + ALBb -->|"3 · HTTP, sync"| HTb + ALBb -->|"3 · HTTP, sync, SG riêng"| PAYb + + GDa -->|"4 · Service Connect, sync, JWT (SEC PA-3)"| HTa + GDa -.->|"4 · cross-AZ nếu cần"| HTb + CM -.-> GDa + CM -.-> HTa + + GDa -->|"5 · SQL, sync"| RDSMa + HTa -->|"5 · SQL, sync"| RDSMa + PAYa -->|"6 · SQL, sync"| RDSPa + RDSMa -.->|"sync replication, Multi-AZ"| RDSMb + RDSPa -.->|"sync replication, Multi-AZ"| RDSPb + GDa -->|"7 · cache, sync"| Redisa + Redisa -.->|"replication, chỉ kịch bản B"| Redisb + + GDa -->|"8 · publish, async"| SQS + PAYa -->|"8b · publish, async"| SQS + SQS -->|"9 · consume, async"| HTa + SQS -->|"9 · consume, async"| HTb + + GDa -->|"10 · S3 API, sync"| S3 + CF --> S3 + GDa -.->|"secret fetch"| SM + PAYa -.->|"secret fetch"| SM + SM -.-> KMS + RDSMa -.-> KMS + S3 -.-> KMS + + GDa -.->|"egress qua NAT"| NATa --> ExtNotif + HTa -.->|"egress qua NAT"| NATa --> ExtShip + PAYa -.->|"egress qua NAT"| NATa --> ExtPay +``` + +**Legend:** ▭ tài nguyên compute · hình trụ = data store · nét liền = đường gọi đồng bộ hoặc kết +nối trực tiếp có nhãn giao thức · nét đứt = quan hệ hạ tầng (replication, service discovery, lấy +secret, egress qua NAT) · ranh giới `VPC` = ranh giới mạng ngoài cùng · ranh giới `AZ a`/`AZ b` = +ranh giới sẵn sàng · Payment (`PAYa`/`PAYb`) có **security group riêng**, không chung với Nhóm +Giao dịch/Nhóm Hỗ trợ (`ASR-002`). + +🔴 **Quyết định mới của `INF` (giải quyết khoảng trống `SAD §7`/`OQ-028`):** cơ chế kết nối thật +giữa Nhóm Giao dịch ↔ Nhóm Hỗ trợ (`IF-021`/`IF-022`) là **AWS Cloud Map + ECS Service Connect** +(service discovery gốc của ECS, không cần thêm cụm/sidecar mesh) — **không dùng App Mesh** +(đúng lưu ý `SAD §7` v1.2 "không tự thêm hạ tầng mới ngoài phạm vi" và khớp `SEC OQ-050`/`DEC-28` +đã chọn TẠM PA-3 service JWT ở tầng ứng dụng, không cần mTLS hạ tầng). Xác thực giữa 2 service +dùng **service JWT** (`SEC §2.4`, chờ `ADR-015` ở hoạt động `adr` kế tiếp — ngoài phạm vi `inf`). +Đây là quyết định cấu hình mạng (radar ước lượng ~3 — đảo ngược thấp, đổi sang App Mesh sau này +là bổ sung không phải viết lại), **không cần `ADR`**, ghi `DEC-nn` là đủ (`decision-radar.md §2`) +— xem §12 Decisions. + +**Bảng thành phần:** + +| Thành phần | Môi trường | Số bản *(A / B — `TCO §3.2`)* | Cấu hình | Vùng/AZ | Ranh giới tin cậy | +|---|---|---|---|---|---| +| WAF + ALB | Prod | Managed (Multi-AZ, không đếm instance) | OWASP Core Rule Set (`SEC TB1`) | 2 AZ | Internet → VPC | +| **ECS Fargate — Nhóm Giao dịch** *(mới tách khỏi dòng gộp `TCO`, §10)* | Prod | **A: 2 tasks × 1vCPU/2GB · B: 6 tasks × 1vCPU/2GB** *(đề xuất SA — `OQ-055`, chờ Tech Lead/Ops)* | Auto-scaling riêng theo `ASR-014` (§4.2) | Multi-AZ (private subnet ứng dụng) | VPC nội bộ — cùng SG với Nhóm Hỗ trợ trừ port dành cho Service Connect | +| **ECS Fargate — Nhóm Hỗ trợ** | Prod | **A: 2 tasks × 1vCPU/2GB · B: 4 tasks × 1vCPU/2GB** *(đề xuất SA — `OQ-055`)* | Auto-scaling riêng, ngưỡng khác Nhóm Giao dịch (§4.2) | Multi-AZ | VPC nội bộ | +| ECS Fargate — Payment | Prod | A: 2 tasks × 0,5vCPU/1GB · B: 4 tasks × 0,5vCPU/1GB *(khớp `TCO` nguyên trạng, không đổi)* | SG/IAM riêng hoàn toàn | Multi-AZ (private subnet riêng) | Cao nhất — PCI-DSS SAQ A (`ASR-002`) | +| RDS chính | Prod | A: `r6g.xlarge` Multi-AZ · B: `r6g.2xlarge` Multi-AZ + 1 read replica (chỉ Catalog đọc, `DAT §7.2`/`OQ-046`) | schema-per-module (`ADR-006`) | Multi-AZ | Chỉ Nhóm Giao dịch/Nhóm Hỗ trợ | +| RDS Payment | Prod | A: `t4g.medium` Multi-AZ · B: `r6g.large` Multi-AZ | Tách biệt hoàn toàn (`ADR-002`) | Multi-AZ | Chỉ Payment | +| ElastiCache Redis | Prod | **A: `r6g.large` × 1 node — KHÔNG có replica (SPOF, §4.3)** · B: `r6g.xlarge` × 1 + 1 replica (HA) | Session/ownership/giỏ hàng | A: 1 AZ (SPOF) · B: Multi-AZ | Chỉ Nhóm Giao dịch | +| SQS FIFO + EventBridge + DLQ | Prod | Managed | Message group = `seller_id`; DLQ riêng mỗi queue, retention **14 ngày** (`OQ-036`/`DEC-22`, TẠM) | Managed | Publish (GD/Payment) vs consume (HT) | +| S3 + CloudFront | Prod | Managed | KMS SSE, versioning cho bucket KYC | Managed | Public (asset) vs private (KYC) | +| Secrets Manager + KMS | Prod | Managed | DB credentials, API key đối tác, JWT signing key — mỗi module 1 secret riêng (`SEC §6`) | Managed | Theo IAM task role, cô lập theo module | +| NAT Gateway | Prod | 2 (1/AZ) | | 2 AZ | Egress duy nhất cho private subnet ra đối tác ngoài | +| Non-prod (dev/stg) | Dev/Stg | ~35% Production compute/RDS (`TCO §3.2`) | Cấu hình thu nhỏ (§2) — **cần nâng tạm khi chạy `POC`/đo `QAS`** | `ap-southeast-1`, **VPC/account riêng** (đề xuất, `OQ-062`) | Tách biệt hoàn toàn với Production | + +--- + +## 4. Tính sẵn sàng (HA) + +### 4.1 Cơ chế chuyển đổi theo thành phần + +| Thành phần | Chịu được mất | Cơ chế chuyển đổi | Thời gian chuyển *(ước tính, chưa đo)* | Tự động? | Đã thử chưa | +|---|---|---|---|---|---| +| ECS Fargate (GD/HT/Payment) | 1 task, 1 AZ | ALB health check (interval 15s, unhealthy threshold 3 lần) loại task lỗi; ECS scheduler khởi task mới ở AZ còn lại | ~1–3 phút *(`ASM-45`, chưa đo)* | ✅ | ☐ | +| ALB | 1 AZ | Managed Multi-AZ, tự động | N/A (không downtime) | ✅ | N/A (AWS managed) | +| RDS chính / RDS Payment | 1 AZ (mất writer) | RDS Multi-AZ synchronous replication → failover tự động sang standby | Theo SLA AWS công khai ~60–120s *(chưa tự đo)* | ✅ | ☐ — nằm trong kế hoạch diễn tập §5.4 (kịch bản 2) | +| ElastiCache Redis — kịch bản B | 1 node (có replica) | Multi-AZ với automatic failover (ElastiCache) | ~60s theo tài liệu AWS *(`ASM-44`, chưa tự đo)* | ✅ | ☐ | +| **ElastiCache Redis — kịch bản A** | **KHÔNG chịu được mất node — SPOF** | Node mới được ElastiCache tự khởi tạo lại (nếu bật snapshot) hoặc cache rỗng | ~5–10 phút để node mới sẵn sàng *(ước tính, chưa đo)*; dữ liệu cache mất hoàn toàn (không phải source of truth, `D7`) nhưng ownership-check/session Guest phụ thuộc Redis (`ADR-007`) → **có gián đoạn dịch vụ trong lúc chờ**, xem §4.3 | ✅ (tạo lại node) / ❌ (không failover, vì không có replica) | ☐ | +| SQS FIFO + EventBridge | Managed, đa AZ nội tại | AWS quản lý hoàn toàn | N/A | ✅ | N/A | +| NAT Gateway | 1 AZ | 2 NAT Gateway (1/AZ), route table theo AZ | N/A (route riêng theo AZ, không có "chuyển đổi" — mỗi AZ dùng NAT của chính nó) | ✅ (theo thiết kế) | ☐ | + +### 4.2 Auto-scaling — kịch bản A → B (`QAS-009`, `ASR-014`) + +🔴 Toàn bộ ngưỡng dưới đây là **đề xuất SA**, chưa Tech Lead/Ops xác nhận, chưa đo tải thật +(`POC-01`/`POC-02` mới đo throughput SQS/RDS, chưa đo hành vi auto-scaling ECS) — ghi `OQ-055`. + +| Nhóm | Metric | Ngưỡng kích hoạt scale-out | Ngưỡng scale-in | Min task | Max task | Thời gian scale *(ước tính)* | +|---|---|---|---|---|---|---| +| **Nhóm Giao dịch** (Catalog/Cart&Order/Identity) | Target tracking: `ALBRequestCountPerTarget` **và** CPU (lấy giá trị kích hoạt sớm hơn) | CPU > 60% trong 3 phút, hoặc request/target > ngưỡng tương ứng ~2.000 concurrent/task *(suy từ `QAS-009` A=2.000 concurrent/2 task)* | CPU < 30% trong 10 phút | **2** (kịch bản A) | **12** *(2× kịch bản B=6, dự phòng đột biến ×2 chưa kiểm chứng — khớp "Ngoài phạm vi" `SAD §10`)* | Cooldown scale-out 60s, scale-in 300s *(đề xuất, chưa đo)* | +| **Nhóm Hỗ trợ** (Seller/Commission/Promotion/Review/Notification/Shipping) | CPU + độ trễ (age) tin nhắn SQS đang chờ xử lý (consumer lag) | CPU > 70% trong 5 phút, hoặc `ApproximateAgeOfOldestMessage` > 60s | CPU < 30% trong 15 phút | **2** | **8** | Cooldown scale-out 90s, scale-in 300s | +| Payment | CPU (ít nhạy tải hơn vì COD đồng bộ nhẹ, VNPay/Momo đã bất đồng bộ theo `ADR-013`) | CPU > 65% trong 3 phút | CPU < 30% trong 10 phút | **2** (A) | **4** (B, khớp `TCO`, không mở rộng thêm vì PCI-DSS scope hẹp) | Cooldown tương tự Nhóm Giao dịch | + +🔴 **`ASR-014` yêu cầu scale riêng Nhóm Giao dịch** — bảng trên đáp ứng bằng 2 auto-scaling policy +độc lập (2 ECS service riêng, đúng `OQ-026` đã chốt TẠM). Nếu Tech Lead/Ops xác nhận ngược lại ở +`OQ-026` (chỉ 1 service gộp), toàn bộ bảng này phải viết lại thành 1 policy chung. + +**Giới hạn trên và nút thắt kế tiếp** *(kịch bản tải ×3 của `TCO`)* + +| Thứ tự | Thành phần nghẽn trước | Ở mức tải nào | Cách gỡ | Chi phí | +|---|---|---|---|---| +| 1 | RDS chính (đọc + ghi gộp, `ADR-006`) | Khi CPU RDS > 75% liên tục — có thể xảy ra trước khi ECS chạm max task, vì RDS là tài nguyên chung không scale ngang tự động | Tách read replica thêm (đã có 1 ở kịch bản B) hoặc tách Catalog ra RDS riêng (theo điều kiện xét lại `ADR-006 §7`) | Instance lớn hơn hoặc thêm replica — chưa ước tính, ngoài `TCO` hiện tại | +| 2 | Message group SQS FIFO của 1 seller volume cao (`ADR-005 §7`) | Khi 1 seller vượt trần throughput riêng của group đó | Theo dõi/cảnh báo riêng theo seller (chưa thiết kế — việc phát sinh của `ADR-005`, xem §6.4) | Không phát sinh chi phí hạ tầng, chỉ engineering effort | +| 3 | ECS Nhóm Giao dịch chạm max=12 | Tải vượt kịch bản B ×2 (~20.000 concurrent) | Nâng max, đánh giá lại kiến trúc (ngoài phạm vi thiết kế hiện tại theo `SAD §10`) | Cần TCO mới | + +### 4.3 Điểm hỏng đơn (SPOF) còn lại + +| Thành phần | Vì sao chưa dự phòng | Rủi ro | Kế hoạch | +|---|---|---|---| +| **ElastiCache Redis kịch bản A (1 node, không replica)** | `TCO §3.2` kịch bản A chỉ tính 1 node để tiết kiệm chi phí (`ASM-11`) — chưa có yêu cầu HA ở mức tải thấp | Mất node → gián đoạn ownership-check/session Guest (`ADR-007`) cho tới khi node mới sẵn sàng (~5–10 phút ước tính); **không mất dữ liệu nghiệp vụ** (Redis không phải source of truth, `D7`) nhưng có gián đoạn dịch vụ | `OQ-058` — hỏi PO/Ops có chấp nhận rủi ro này ở kịch bản A hay muốn thêm 1 replica ngay (chi phí +~$92/tháng ước tính theo đơn giá `TCO §3.1`, chưa xác nhận) | +| VPC/region `ap-southeast-1` | `ADR-009` chọn PA-1 — không multi-region ở MVP, vì chi phí chưa có trong ngân sách | Mất toàn vùng → toàn hệ thống down, RTO thực tế vượt xa 1 giờ (khôi phục sang region khác là dự án riêng) | Đã ghi trong `ADR-009 §5` "Cái quyết định này khoá lại" — chấp nhận có ý thức, xét lại khi PO duyệt ngân sách multi-region | +| NAT Gateway (theo AZ) | Mỗi AZ có NAT riêng — nếu AZ đó down, task trong AZ đó cũng down theo (không phải NAT là nguyên nhân chính) | Trùng với SPOF "mất 1 AZ" đã có cơ chế chuyển đổi ở §4.1 — không phải SPOF độc lập | Không cần kế hoạch riêng | +| Cấu hình DNS/Route53 (chưa thiết kế) | Chưa có trong phạm vi `SAD`/`INF` lượt này — domain/SSL đã có ở `TCO §4` nhưng cấu hình failover DNS chưa thiết kế | Nếu ALB endpoint đổi mà không có health-check DNS, có thể kéo dài downtime khi có sự cố tầng ngoài ALB (hiếm, vì ALB tự Multi-AZ) | Ghi nhận — mức độ ưu tiên thấp vì ALB đã Multi-AZ, không phải SPOF cấp bách | + +🔴 Hệ thống nào cũng còn SPOF — liệt kê ra là chuyên nghiệp; giả vờ không có mới là vấn đề. + +--- + +## 5. Khôi phục thảm hoạ (DR) + +### 5.1 Mục tiêu và cơ chế khôi phục + +| | | +|---|---| +| **Nhóm phạm vi** | Payment, Cart & Order, Identity & Access — "nhóm giao dịch cốt lõi" (`ASR-010`) | +| **Kịch bản thảm hoạ tính tới** | Mất 1 AZ · hỏng RDS primary (dữ liệu lỗi logic, không phải mất AZ) · xoá nhầm dữ liệu · mất Redis. **Không tính** mất toàn vùng (`ADR-009` PA-1) | +| **RTO mục tiêu** | **≤ 1 giờ** (nguồn: `QAS-008`, kế thừa nguyên trạng từ `SAD.md §5.3.2`/`§9.5.2` gốc — **chưa phải SLA hợp đồng đã ký với PO**, xem `CTX DRV-05`) | +| **RPO mục tiêu** | **≤ 15 phút** (nguồn: `QAS-008`) | +| **Cách khôi phục** | RDS Multi-AZ tự động failover (mất AZ, §4.1) hoặc PITR restore (hỏng dữ liệu logic/xoá nhầm) — xem runbook §5.3 | +| **RTO đo được thực tế** | 🔴 **Chưa đo** — chưa từng diễn tập | +| **Lần diễn tập gần nhất** | 🔴 **Chưa từng** — xem kế hoạch §5.4 | +| **Tần suất diễn tập đề xuất** | 2 lần/năm sau lần đầu (kế thừa đề xuất `ADR-009 §6`), điều chỉnh theo kết quả | + +### 5.2 Backup & PITR + +| Data store | Cơ chế | Tần suất/độ trễ | Retention | Cross-AZ | Cross-region | +|---|---|---|---|---|---| +| RDS chính | Automated Backup + PITR (WAL continuous archiving) | Continuous (đạt RPO ≤15 phút — cần xác nhận tần suất archive log thật đủ nhanh, `OQ-055` mở rộng) | Đề xuất 7 ngày (chưa chốt — khác với con số 35 ngày ở tài liệu P1 gốc `docs/09 §9.5.3`, cần Tech Lead xác nhận số cho P2, `OQ-059-b` gộp vào `OQ-045` phạm vi migration/backup) | ✅ (Multi-AZ synchronous) | ❌ — `TCO §3.2` có dòng "cross-region snapshot (Payment)" nhưng **mâu thuẫn với `ADR-009` PA-1**, xem `OQ-054` | +| RDS Payment | Automated Backup + PITR | Continuous | Đề xuất 7 ngày, riêng biệt khỏi RDS chính (`ADR-002`) | ✅ | ❌ — cùng `OQ-054` | +| ElastiCache Redis | Không PITR (cache, không phải source of truth, `D7`) — chỉ snapshot định kỳ tuỳ chọn để giảm thời gian "cache lạnh" sau sự cố | N/A (không cần RPO cho cache) | N/A | Chỉ kịch bản B (replica) | ❌ | +| S3 (KYC, asset) | Versioning bật cho bucket KYC (khôi phục object bị xoá/ghi đè nhầm) | Continuous (mỗi write là 1 version) | Đề xuất giữ version cũ 90 ngày rồi chuyển lifecycle sang Glacier | N/A (S3 tự đa AZ) | 🔴 Chưa chốt — chỉ cần nếu Pháp chế/Security yêu cầu (`OQ-007`), chưa có trong `TCO` | +| SQS FIFO/EventBridge DLQ | Retention **14 ngày** (`OQ-036`/`DEC-22`, TẠM) | N/A | 14 ngày | Managed | Managed | + +### 5.3 Runbook failover (tóm tắt — chi tiết đầy đủ thuộc tài liệu vận hành `sa-3-enablement`) + +1. **Xác định phạm vi sự cố** — service nào bị ảnh hưởng, dữ liệu mất từ thời điểm nào (dựa trên + CloudWatch alarm đã cấu hình ở §6, đối chiếu `QAS-013`). +2. **Mất 1 AZ:** không can thiệp thủ công cho ECS/ALB/RDS Multi-AZ (tự động, §4.1) — Ops xác + nhận qua dashboard, không chặn nghiệp vụ trừ khi failover RDS vượt ngưỡng bất thường. +3. **Hỏng RDS primary do lỗi dữ liệu logic (không phải mất AZ):** dùng PITR restore về thời điểm + trước sự cố lên instance mới; **không mở lại luồng thanh toán cho tới khi đối soát xong** + (kế thừa nguyên tắc `docs/09 §9.5.3` bước 5 — ưu tiên đúng đắn tài chính hơn tốc độ). +4. **Mất Redis (kịch bản A, không replica):** chấp nhận gián đoạn ownership-check/session Guest + trong lúc ElastiCache tạo node mới; **không cần restore dữ liệu** (cache, không phải nguồn sự + thật) — khi node mới lên, hệ thống tự "làm nóng lại" cache theo truy vấn thực tế. +5. **Xác minh toàn vẹn tài chính** trước khi mở lại Payment (đối chiếu `ReconciliationLog`, kế + thừa nguyên tắc `docs/09 §9.5.3`). +6. **Thông báo & escalation** theo `QAS-013`/`CON-08` — xem §6.5. + +🔴 Runbook đầy đủ (lệnh thao tác cụ thể, ai bấm nút gì) là sản phẩm của `sa-3-enablement` +(`AGD`), tài liệu này chỉ định khung quy trình. + +### 5.4 Kế hoạch diễn tập DR — điều kiện tiên quyết AG2 (`OQ-022`, `DEC-12`) + +🔴 **Đây là mục quan trọng nhất của `INF`** — `ADR-009`/`QAS-008` đều ghi rõ "RTO/RPO chưa diễn +tập là RTO/RPO trên giấy". Ba kịch bản dưới đây **phải chạy trước khi ký AG2**; ngày thật vẫn chờ +Ops/SRE xác nhận (`OQ-022`), nhưng kế hoạch (kịch bản, bước, tiêu chí PASS/FAIL, ai làm, môi +trường) đã đủ chi tiết để lên lịch ngay khi có Ops/SRE. + +| # | Kịch bản | Môi trường | Các bước | Tiêu chí PASS | Tiêu chí FAIL | Ai làm | Công cụ | +|---|---|---|---|---|---|---|---| +| DR-1 | **Mất 1 AZ** (giả lập bằng cách chặn traffic tới AZ đó, không thật sự tắt AZ AWS) | Staging (nâng tạm lên cấu hình gần prod), sau đó lặp lại ở Production giờ thấp điểm nếu DR-1 PASS ở staging | 1) Đo baseline (p95 checkout, uptime) trước khi bắt đầu. 2) Dùng AWS Fault Injection Simulator hoặc chặn route table/SG để cô lập 1 AZ khỏi traffic. 3) Quan sát ALB tự loại AZ lỗi, ECS scheduler khởi task mới ở AZ còn lại, RDS Multi-AZ failover (nếu writer nằm ở AZ bị cô lập). 4) Đo thời gian từ lúc cô lập tới lúc hệ thống phục vụ bình thường trở lại (RTO thực đo). 5) Đo lượng dữ liệu/giao dịch bị ảnh hưởng trong cửa sổ đó (RPO thực đo — kỳ vọng 0 vì đây là mất AZ, không mất dữ liệu, RDS Multi-AZ đồng bộ). 6) Khôi phục traffic bình thường, xác nhận không còn task "mồ côi" | RTO đo được ≤ 1 giờ; RPO đo được = 0 (không mất giao dịch nào vì Multi-AZ đồng bộ); không lỗi 5xx kéo dài > 5 phút liên tục trong lúc chuyển đổi | RTO > 1 giờ, hoặc mất giao dịch, hoặc lỗi 5xx > 5 phút liên tục | Ops/SRE chủ trì, Tech Lead quan sát/xác nhận số liệu | AWS Fault Injection Simulator hoặc thao tác Security Group/Route table thủ công; CloudWatch dashboard đo thời gian thực | +| DR-2 | **Mất RDS primary** (giả lập bằng reboot-with-failover hoặc force failover qua AWS Console/CLI) | Staging trước, Production giờ thấp điểm nếu PASS ở staging (khuyến nghị **không** chạy DR-2 thật trên Production writer chính cho tới khi DR-1 và DR-2 đã PASS ở staging ≥1 lần) | 1) Đo baseline. 2) Trigger `aws rds reboot-db-instance --force-failover` (hoặc tương đương) trên RDS chính (staging trước). 3) Đo thời gian từ lúc trigger tới lúc ứng dụng (Nhóm Giao dịch/Nhóm Hỗ trợ) ghi/đọc thành công trở lại (RTO). 4) Kiểm tra giao dịch đang xử lý tại thời điểm failover có bị mất/trùng không (RPO + kiểm tra idempotency `ADR-004`). 5) Lặp lại riêng cho RDS Payment | RTO đo được ≤ 1 giờ (kỳ vọng thực tế thấp hơn nhiều — Multi-AZ failover thường < 2 phút theo AWS SLA công khai, nhưng phải **đo thật**, không giả định); RPO đo được ≤ 15 phút; không giao dịch nào bị double-write/mất do idempotency đã có (`ADR-004`) | RTO > 1 giờ, RPO > 15 phút, hoặc phát hiện giao dịch bị mất/trùng không được idempotency bắt | Ops/SRE + DBA chủ trì, Tech Lead xác nhận số liệu | AWS CLI/Console, CloudWatch, `ReconciliationLog` (kiểm tra sau) | +| DR-3 | **Mất Redis** (giả lập bằng xoá node hoặc force-failover ElastiCache) | Staging trước | 1) Đo baseline. 2) Xoá/force-failover node Redis. 3) Quan sát hành vi ownership-check/session Guest khi Redis không sẵn sàng (`ADR-007` — có fallback gọi thẳng Identity & Access không, hay lỗi hoàn toàn?). 4) Đo thời gian tới khi node mới sẵn sàng và cache "nóng lại". 5) Với kịch bản A (không replica): đo downtime dịch vụ thực tế trong lúc chờ node mới | Xác nhận có đường fallback (không phải lỗi cứng hoàn toàn) khi Redis mất — nếu không có fallback, đây là **phát hiện quan trọng cần ghi `ARISK` mới**, không phải điều kiện PASS/FAIL đơn thuần | Hệ thống lỗi cứng hoàn toàn (không phục vụ được request nào) khi Redis mất, không có fallback nào | Ops/SRE + Tech Lead (backend module `CMP-02`/`CMP-04`) | Xoá node thủ công qua AWS Console (staging), theo dõi log ứng dụng | + +**Hạn đề xuất:** trong vòng 2 tuần kể từ khi Ops/SRE được xác định (`OQ-008`) và trước khi trình +AG2 — đây là **đề xuất của SA**, ngày thật vẫn là `OQ-022`, chờ Ops/SRE xác nhận lịch cụ thể. + +**Kết quả diễn tập ghi vào:** `ARISK_e-commerce_v1.0.md` (mục mới, theo đúng cách `POC-01`/`POC-02` +đã ghi) — không ghi trực tiếp vào `INF` này để tránh phải bump version mỗi lần có kết quả mới; `INF` +sẽ dẫn chiếu khi có. + +--- + +## 6. Quan sát được (Observability) + +### 6.1 Log / Metric / Trace + +| Loại | Công cụ | Ghi gì | Giữ bao lâu | Ai đọc | Chi phí/tháng | +|---|---|---|---|---|---| +| Log | CloudWatch Logs (managed, khớp `ADR-010` PA-1) | Request log (không PII thô — log-scrubber mask `email`/`phone`/`account_number` theo `SEC §5.1`), application log theo `correlation_id` = header `X-Request-Id` (`ICD OQ-031`, đề xuất Tech Lead xác nhận tên header) | Đề xuất 30 ngày hot (CloudWatch) rồi archive S3 Glacier 90 ngày thêm (🔴 chưa chốt, `OQ-059`) | Dev + Ops/SRE (không unrestricted — theo IAM role) | Trong `TCO §3.2` dòng "Observability" (~$357 A / ~$1.033 B) | +| Metric | CloudWatch Metrics | CPU/memory ECS, connection/CPU RDS, cache hit ratio Redis, SQS `ApproximateAgeOfOldestMessage`/`NumberOfMessagesSent`, ALB 5xx rate, target response time | 15 tháng (CloudWatch mặc định cho metric đã aggregate) | Ops/SRE, dashboard chia sẻ Tech Lead | Trong dòng Observability trên | +| Trace | AWS X-Ray | Luồng checkout xuyên `ALB→GD→(HT/Payment)→RDS/SQS`, tỉ lệ lấy mẫu đề xuất 10% (100% cho request lỗi) — **chưa chốt tỉ lệ**, `OQ-059` | Mặc định X-Ray 30 ngày | Dev + Ops/SRE khi debug latency | Trong dòng Observability trên | +| **Cộng** | | | | | **≈ $357/tháng (A) · ≈ $1.033/tháng (B)** — khớp `TCO §3.2` | + +**Correlation id:** header request `X-Request-Id` (đề xuất SA ở `ICD OQ-031`) — ALB/API Gateway +sinh nếu client không gửi, map 1-1 vào `traceId` (X-Ray) và field `correlation_id` trong mọi dòng +log ứng dụng, xuyên suốt Nhóm Giao dịch → Nhóm Hỗ trợ → Payment → SQS consumer. **Chưa Tech Lead +xác nhận tên header** — nếu đổi, chỉ cần đổi tên field, không ảnh hưởng kiến trúc. + +### 6.2 Dashboard đề xuất + +| Dashboard | Đối tượng xem | Nội dung chính | +|---|---|---| +| "Sức khoẻ giao dịch cốt lõi" | Ops/SRE, Tech Lead | 5xx rate + p95 latency của Payment/Cart&Order/Identity, uptime rolling 30 ngày (đối chiếu ngân sách lỗi `QAS-007`), auto-scaling hiện tại (task count vs max) | +| "Message backbone" | Ops/SRE | SQS lag theo message group (đặc biệt seller volume cao, `ADR-005 §7`), DLQ depth, EventBridge fan-out lag | +| "Chi phí" | PO/Tech Lead | Chi phí AWS thực tế theo dịch vụ, đối chiếu `TCO §3.2` hàng tháng (rà chênh lệch >20% — chuẩn bị cho `CONF` GĐ4) | + +### 6.3 Cảnh báo + +| Cảnh báo | Điều kiện | Mức | Báo cho ai | `QAS` | +|---|---|---|---|---| +| 5xx tăng đột biến — Nhóm giao dịch cốt lõi | Health check fail liên tục **> 1 phút** cho Payment/Cart&Order/Identity | Trang (page) 24/7 | On-call theo `CON-08`/`OQ-008` (§6.5) | `QAS-013` | +| p95 checkout vượt ngưỡng | p95 `POST /v1/checkout` > 3s liên tục 5 phút | Trang giờ hành chính, escalate nếu kéo dài | On-call | `QAS-002` | +| SQS lag / DLQ | `ApproximateAgeOfOldestMessage` > **5 phút** (`OQ-036`/`DEC-22`, TẠM) | Vé giờ hành chính, trang nếu ảnh hưởng nhóm cốt lõi | Ops/SRE theo domain consumer (chưa phân công cụ thể tên người — `OQ-036` phần "ai xử lý" vẫn mở) | `QAS-005`, `FM-09/10` | +| Message group riêng lẻ nghẽn (1 seller volume cao) | Lag riêng 1 message group > 5s kéo dài > 5 phút | Vé giờ hành chính | Ops/SRE | `ADR-005 §7` | +| RDS CPU/connection pool | CPU > 75% > 3 lần/tuần giờ cao điểm, hoặc connection pool exhaust | Trang nếu exhaust, vé nếu CPU cao | DBA/Ops | `ADR-006 §7` | +| Circuit breaker mở (FM-01/02/03/04/12/13) | Bất kỳ lần mở nào (`FAIL §3.1`) | Vé, trang nếu mở > 5 phút liên tục | On-call theo module | `QAS-002` | +| Chi phí AWS bất thường | Chi phí ngày > 150% trung bình 7 ngày trước | Vé giờ hành chính | Ops/PO | `TCO §3.2` | + +🔴 **Cảnh báo không ai xử lý là cảnh báo sẽ bị tắt tiếng.** Mọi cảnh báo trên cần một người nhận +thật (§6.5) — hiện chưa có tên cụ thể vì `OQ-008` (số người Ops) còn mở. + +### 6.4 Error budget (`QAS-007`) + +| | | +|---|---| +| Mục tiêu | 99,9%/tháng cho Catalog/Checkout/Payment/Identity (`QAS-007`) ⇒ ngân sách lỗi **43 phút/tháng** | +| Loại trừ | Bảo trì có báo trước **≤ 2 giờ/tháng** (`OQ-020`/`DEC-12`, TẠM — chưa PO xác nhận số cuối) | +| Theo dõi | Dashboard "Sức khoẻ giao dịch cốt lõi" (§6.2), tính rolling 30 ngày | +| Ràng buộc lên CI/CD | Chiến lược deploy (§7) phải **không** tự tiêu tốn ngân sách lỗi — chọn blue-green/rolling zero-downtime, không chọn "deploy có downtime ngắn" dù chỉ vài giây mỗi lần (tích luỹ nhiều lần release/tháng có thể ăn hết 43 phút) | + +### 6.5 Vận hành thường ngày & on-call + +| Việc | Ai làm | Tần suất | Tài liệu | +|---|---|---|---| +| Trực sự cố (on-call) | Ops/SRE theo `CON-08`: **ca hành chính + escalation 24/7 cho sự cố nghiêm trọng ảnh hưởng nhóm giao dịch cốt lõi** — số người/nội bộ hay thuê ngoài **chưa xác nhận** (`OQ-008`, mở) | Liên tục | Escalation chain: on-call → Tech Lead → PO (thứ tự đề xuất, chưa xác nhận) | +| Vá bảo mật (SCA/dependency) | Dev + Ops (theo cảnh báo Trivy/Snyk ở CI/CD, §7) | Theo phát hiện, ưu tiên Critical/High trong 7 ngày (đề xuất, chưa chốt SLA) | `SEC §7` | +| Kiểm tra backup khôi phục được | Ops/SRE | Theo tần suất diễn tập DR (§5.4) | §5 | +| Rà chi phí | Ops/PO | Hàng tháng, đối chiếu `TCO §3.2` | §10 | + +**Năng lực đội vận hành** *(từ `CON-05`/`CON-08`)*: số người/kỹ năng thật **chưa xác nhận** +(`OQ-008`) — thiết kế trên giả định "đủ người trực ca hành chính + escalation 24/7 khi cần", theo +đúng `CON-08`. Nếu đội thật nhỏ hơn giả định "team MVP chuẩn" (`DEC-02`), khả năng đáp ứng ngưỡng +ack ≤15 phút (`QAS-013`) và tần suất diễn tập DR 2 lần/năm có thể không khả thi — đây là đánh đổi +PO/PM phải quyết (`D10`), không phải SA tự chọn giả định lạc quan hơn thực tế đội. Chi phí đào tạo/ +tuyển dụng nếu thiếu người: xem `TCO §5`/`ASM-14`. + +--- + +## 7. CI/CD + +### 7.1 Pipeline build → test → scan → deploy + +*Điều chỉnh từ khung `docs/09 §9.3.1` (viết cho kiến trúc P1, ~10 microservice + Kafka) sang P2 +(3 đơn vị triển khai: Nhóm Giao dịch, Nhóm Hỗ trợ, Payment) — bỏ bước liên quan Kafka/MSK/ +OpenSearch, thêm bước scan theo `SEC §7`.* + +```mermaid +flowchart LR + Commit["Commit / PR"] --> Build["Build\n(container image/service, tag = commit SHA)"] + Build --> Unit["Unit test\n(coverage gate — ngưỡng chưa chốt, OQ-060)"] + Unit --> SAST["SAST\n(SonarQube/Semgrep)"] + SAST --> SCA["SCA/container scan\n(Trivy image + Snyk dependency)"] + SCA --> Migration["Schema migration dry-run\n(Flyway — OQ-045, mỗi schema module riêng)"] + Migration --> Integration["Integration test\n(Staging, sandbox VNPay/Momo/GHN/GHTK — ARISK-03/04)"] + Integration --> DeployDev["Deploy → Dev\n(auto)"] + DeployDev --> DeployStg["Deploy → Staging\n(auto sau Dev pass)"] + DeployStg --> UAT["UAT + Performance/Security test\n(k6, security regression FIT-29..33)"] + UAT --> Approval["Phê duyệt thủ công\n(Product Owner + Tech Lead — tách vai trò)"] + Approval --> DeployProd["Deploy → Production\n(blue-green, §7.2)"] +``` + +**Ngưỡng chặn:** + +| Bước | Chặn nếu | Nguồn | +|---|---|---| +| Unit test | Coverage giảm so với baseline hoặc test đỏ (ngưỡng % cụ thể chưa chốt cho P2 — `docs/09` đề xuất 70%/50% cho P1, cần Tech Lead xác nhận lại cho P2, `OQ-060`) | `docs/09 §9.1.1` (tham khảo) | +| SAST | Phát hiện lỗ hổng theo policy đã cấu hình (SonarQube quality gate) | `SEC §7` | +| SCA/container scan | **Trivy/Snyk phát hiện Critical/High chưa có ngoại lệ được phê duyệt** — chặn deploy (khớp yêu cầu người duyệt) | `SEC §7`, `docs/09 §9.3.1` | +| Migration dry-run | Migration không tương thích ngược (không theo expand-contract, `DAT §8.2`) — kiểm tra tự động một phần (linter script), phần còn lại cần review thủ công | `DAT §8.2`, `OQ-045` | +| Integration test | Fail idempotency webhook (`ADR-004`), fail contract `ICD` | `ICD`, `ADR-004` | +| UAT/Security regression | FR Must không Pass; `FIT-29…33` (secret scan, service-authn, webhook signature, audit completeness, TLS/HSTS) đỏ | `SEC §11` | +| Deploy Production | Thiếu phê duyệt thủ công (PO + Tech Lead, tách vai trò người phê duyệt/người deploy) | `docs/09 §9.3.2` | + +### 7.2 Chiến lược deploy — zero/low-downtime + +| | Quyết định | Vì sao | +|---|---|---| +| **Chiến lược** | **Blue-green (AWS CodeDeploy cho ECS)** cho cả 3 service (Nhóm Giao dịch, Nhóm Hỗ trợ, Payment) | Tương thích ngân sách lỗi chặt (43 phút/tháng, `QAS-007`) — rolling update vẫn có short window request có thể chạm task đang tắt, blue-green chuyển traffic dứt điểm sau health check pass, rollback tức thời (chuyển lại traffic) nếu phát hiện lỗi sau khi đã live | +| Thời gian downtime cho phép | **0** theo thiết kế (blue-green không có cửa sổ mất traffic nếu health check đúng) — nằm gọn trong ngân sách lỗi `QAS-007` | | +| **Cách rollback** | Chuyển traffic ALB về target group cũ (green→blue) — tức thời (giây), không cần redeploy | CodeDeploy hỗ trợ sẵn | +| Migration schema | **Expand-contract** (thêm cột/bảng trước, xoá sau — kế thừa nguyên tắc `docs/09 §9.5.1`/`DAT §8.2`) — chạy trước bước deploy code mới trong pipeline (§7.1), tương thích ngược để rollback code không gặp schema mới không hiểu | `DAT §8.2`, `OQ-045` (công cụ Flyway/Liquibase chưa chốt) | +| Cờ tính năng (feature flag) | 🔴 Chưa chốt công cụ (LaunchDarkly/tự xây bảng config) — đề xuất SA: bảng config đơn giản trong RDS chính (schema `platform`), không cần SaaS bên thứ ba ở MVP; dùng cho rollout tính năng rủi ro cao (đổi luồng thanh toán/hoa hồng, theo `docs/09 §9.3.2`) | `OQ-060` | +| Ai được bấm deploy Production | Tech Lead (thực hiện) sau khi PO phê duyệt (tách vai trò — segregation of duties) | `docs/09 §9.3.2` | + +🔴 Chiến lược deploy blue-green cho toàn bộ 3 service là quyết định thiết lập tiền lệ (radar ước +lượng ~6 — đảo ngược trung bình, bán kính toàn hệ thống, chạm trực tiếp `QAS-007` Must, ràng buộc +một release, không tranh cãi) — theo `decision-radar.md §2`, đạt ngưỡng `ADR` bắt buộc. Xem +[`adr/ADR-016_blue-green-deploy-aws-codedeploy.md`](adr/ADR-016_blue-green-deploy-aws-codedeploy.md) +(`Proposed`). Điều kiện `Accepted`: Ops/SRE xác nhận năng lực vận hành CodeDeploy + chạy thử +blue-green/rollback thành công ở staging (`OQ-056`), PO xác nhận số cuối `OQ-020`. + +### 7.3 Phân quyền Production & secret trong pipeline + +| Hạng mục | Thiết kế | +|---|---| +| CI/CD → AWS | **OIDC federation** (GitHub Actions/GitLab CI ↔ AWS IAM role tạm thời) — không dùng access key dài hạn nhúng pipeline (kế thừa `docs/09 §9.3.2`) | +| Secret trong pipeline | Lấy từ **AWS Secrets Manager** tại thời điểm chạy (`SEC §6`), không lưu trong biến môi trường CI dạng plaintext lâu dài, không commit vào repo — quét rò rỉ bằng Gitleaks/TruffleHog (`SEC FIT-29`) | +| Audit CI/CD | Log ai trigger deploy, phiên bản nào, thời điểm nào — audit trail hạ tầng, khác `audit_log` nghiệp vụ (`DAT`) | + +--- + +## 8. Network & Security groups + +### 8.1 Security group theo thành phần + +| SG | Áp dụng cho | Inbound | Outbound | +|---|---|---|---| +| `sg-alb` | ALB | 443 từ Internet (0.0.0.0/0, qua WAF) | 80/443 tới `sg-ecs-gd`, `sg-ecs-ht`, `sg-ecs-pay` | +| `sg-ecs-gd` | ECS Nhóm Giao dịch | 80 từ `sg-alb`; port Service Connect từ `sg-ecs-ht` (nội bộ) | 5432 tới `sg-rds-main`; 6379 tới `sg-redis`; 443 tới SQS/EventBridge/S3/Secrets Manager (qua VPC endpoint hoặc NAT); port Service Connect tới `sg-ecs-ht` | +| `sg-ecs-ht` | ECS Nhóm Hỗ trợ | 80 từ `sg-alb`; port Service Connect từ `sg-ecs-gd` | 5432 tới `sg-rds-main`; 443 tới SQS/EventBridge/S3/Secrets Manager; 443 tới NAT (egress GHN/GHTK/Email-SMS) | +| `sg-ecs-pay` | ECS Payment — **cô lập, không chung SG với GD/HT** (`ASR-002`) | 80 từ `sg-alb` **chỉ route Payment** | 5432 tới `sg-rds-payment` (chỉ SG này); 443 tới NAT (egress VNPay/Momo); 443 tới Secrets Manager (chỉ secret của Payment) | +| `sg-rds-main` | RDS chính | 5432 từ `sg-ecs-gd`, `sg-ecs-ht` | — | +| `sg-rds-payment` | RDS Payment | 5432 **chỉ từ** `sg-ecs-pay` | — | +| `sg-redis` | ElastiCache Redis | 6379 **chỉ từ** `sg-ecs-gd` | — | + +🔴 **Không có SG nào cho phép Nhóm Hỗ trợ/Payment kết nối trực tiếp RDS Payment hoặc Redis** — +đúng nguyên tắc cô lập `ASR-002`/`ADR-002` và "chủ duy nhất" `D7`. + +### 8.2 Private subnet cho dữ liệu + +RDS chính, RDS Payment, ElastiCache Redis đặt **hoàn toàn trong private subnet** (không route +public), không có Elastic IP, không truy cập được từ Internet — chỉ qua ECS task trong cùng VPC. +Đúng yêu cầu (f). + +### 8.3 Egress tới đối tác ngoài (VNPay/Momo/GHN/GHTK/Email-SMS) + +| Đối tác | Qua NAT Gateway? | IP allowlist đối tác yêu cầu? | Static outbound IP cần thiết? | +|---|---|---|---| +| VNPay | ✅ (từ `sg-ecs-pay`) | 🔴 **Chưa xác nhận** — chưa có tài liệu tích hợp/sandbox thật (`CON-04`, `ARISK-03`) | Nếu VNPay yêu cầu allowlist IP nguồn: NAT Gateway đã có Elastic IP cố định theo AZ — đủ điều kiện kỹ thuật, chỉ cần đăng ký 2 IP (1/AZ) với VNPay | +| Momo | ✅ (từ `sg-ecs-pay`) | 🔴 Chưa xác nhận | Tương tự — 2 Elastic IP NAT | +| GHN | ✅ (từ `sg-ecs-ht`) | 🔴 Chưa xác nhận (`ARISK-04`) | Tương tự | +| GHTK | ✅ (từ `sg-ecs-ht`) | 🔴 Chưa xác nhận | Tương tự | +| Email/SMS Provider | ✅ (từ `sg-ecs-ht`, qua `CMP-09` Notification) | 🔴 Chưa chọn nhà cung cấp (`TCO OQ-016`) | Chưa xác định | + +🔴 **`OQ-057` (mới):** VNPay/Momo/GHN/GHTK/Email-SMS có yêu cầu IP allowlist cho outbound traffic +từ sàn không? Nếu có, cần đăng ký 2 Elastic IP (1/AZ, gắn NAT Gateway) với từng đối tác trước +go-live — việc này **không phát sinh chi phí thêm** (Elastic IP đã tính trong giá NAT Gateway ở +`TCO §3.1`) nhưng cần thời gian phối hợp hành chính với đối tác. Hỏi: Tech Lead (khi có tài liệu +tích hợp thật từ 4 đối tác, cùng điều kiện với `ARISK-03/04`). + +--- + +## 9. Chi phí — tham chiếu `TCO` + +Toàn bộ con số chi phí trong tài liệu này **tham chiếu nguyên trạng** `TCO_e-commerce_v1.0.md +§3.1–§3.2` — không tính lại, không đổi đơn giá/tỷ giá (`ASM-11`/`ASM-12` vẫn 🔴 chưa xác minh, +thuộc trách nhiệm `TCO`, không phải `INF`). Bảng đối chiếu chi tiết ở §10. + +--- + +## 10. Đối chiếu với `TCO` *(bắt buộc theo `D9` — từng dòng)* + +| Hạng mục | `INF` §3/§4/§6 | `TCO §3.2` | Khớp | +|---|---|---|---| +| Compute — Nhóm Giao dịch + Nhóm Hỗ trợ (tổng) | A: 2+2=4 tasks×1vCPU/2GB · B: 6+4=10 tasks×1vCPU/2GB | A: ~4 tasks×1vCPU/2GB (gộp) · B: ~10 tasks×1vCPU/2GB (gộp) | ✅ **Khớp về tổng số** — split GD/HT là đề xuất mới của `INF` (`OQ-055`), chưa Tech Lead/Ops xác nhận nhưng không đổi tổng cost | +| Compute — Payment | A: 2 tasks×0,5vCPU/1GB · B: 4 tasks×0,5vCPU/1GB | A: 2 tasks×0,5vCPU/1GB · B: 4 tasks×0,5vCPU/1GB | ✅ Khớp hoàn toàn | +| CSDL (RDS chính + Payment) | A: `r6g.xlarge`+`t4g.medium` Multi-AZ · B: `r6g.2xlarge`+1 replica + Payment `r6g.large` | Giống hệt | ✅ Khớp | +| Cache (Redis) | A: `r6g.large`×1 (không replica) · B: `r6g.xlarge`×1+1 replica | Giống hệt | ✅ Khớp — nhưng §4.3 mới **phát hiện và ghi rõ** hệ quả SPOF kịch bản A mà `TCO` không đề cập (không phải lỗi `TCO`, chỉ là `TCO` không có cột "rủi ro HA") | +| Message broker (SQS/EventBridge) | Managed, ~750K msg/tháng (A) / ~2,25M msg/tháng (B) | Giống hệt | ✅ Khớp | +| S3/CloudFront | ~500GB (A) / ~1,5TB (B) | Giống hệt | ✅ Khớp | +| WAF/ALB/NAT | Giống `TCO` | Giống `TCO` | ✅ Khớp | +| **Backup & DR** | Automated backup + PITR, **không cross-region** (theo `ADR-009` PA-1) | Dòng "Backup & DR" ghi **"Automated backup + cross-region snapshot (Payment)"**, ≈$30 (A)/≈$60 (B) | 🔴 **KHÔNG khớp bản chất** — xem `OQ-054` | +| Observability | CloudWatch Logs/Metrics + X-Ray, ~$357 (A)/~$1.033 (B) | Giống hệt | ✅ Khớp | +| Non-prod | ~35% Production | ~35% Production | ✅ Khớp về tỷ lệ; kích cỡ instance cụ thể của non-prod chưa chốt (`OQ-062`) | +| **Tổng/tháng** | ≈ $2.409 (A) / ≈ $5.862 (B) | ≈ $2.409 (A) / ≈ $5.862 (B) | ✅ Khớp | + +🔴 **`OQ-054` (mới) — phát hiện quan trọng nhất của mục đối chiếu này:** `TCO §3.2` tính một +khoản nhỏ (~$30/A, ~$60/B) cho **"cross-region snapshot (Payment)"** trong dòng "Backup & DR", +nhưng `ADR-009` (chiến lược HA/DR cho nhóm giao dịch cốt lõi, bao gồm Payment) đã chọn **PA-1 — +không multi-region ở MVP**, với lý do rõ ràng "chưa có trong ngân sách đã duyệt". Hai khả năng: +(1) khoản chi phí này trong `TCO` chỉ là **bản sao snapshot sang region khác** để phòng thảm hoạ +tối hậu (không kèm hạ tầng compute/failover chủ động ở region đó) — nếu vậy, nó **không mâu +thuẫn** với "không multi-region active-passive" của `ADR-009`, nhưng cần ghi rõ: khôi phục từ +snapshot cross-region này (nếu dùng tới) sẽ **KHÔNG đạt RTO ≤1 giờ** đã cam kết (restore RDS từ +snapshot qua region khác thường mất nhiều giờ) — đây là "van an toàn cuối cùng", không phải một +phần của cam kết RTO/RPO chính; (2) hoặc khoản chi phí này là sai sót/thừa trong `TCO`, nên bỏ +nếu PO/Ops xác nhận không cần. **Không tự sửa `TCO` hay `ADR-009`** — trình cả hai khả năng. +**Hỏi:** Tech Lead + Ops/SRE + PO. **Hệ quả nếu chọn hướng (1):** giữ nguyên chi phí `TCO`, thêm +1 dòng rõ ràng vào `ADR-009`/`INF` rằng cross-region snapshot Payment là biện pháp phụ, không nằm +trong cam kết RTO≤1h. **Hệ quả nếu chọn hướng (2):** `TCO §3.2` giảm ~$30–60/tháng (không đáng kể +so với tổng, không đổi kết luận "P2 rẻ hơn P1"). + +--- + +## 11. Infrastructure as Code (IaC) — đề xuất cho GĐ3 + +*Không viết code Terraform/CDK thật ở lượt này (thuộc `sa-3-enablement`) — chỉ chốt hướng và tiêu +chí FIT ứng viên.* + +| | Đề xuất | Vì sao | +|---|---|---| +| Công cụ | **Terraform** | Đa cloud-agnostic hơn CDK (dù hiện chỉ dùng AWS), cộng đồng module lớn cho ECS/RDS/ElastiCache, không khoá vào 1 ngôn ngữ lập trình cụ thể (CDK cần TypeScript/Python) — phù hợp năng lực team chưa xác nhận rõ (`CON-05`) | +| Cấu trúc state | Tách state theo môi trường (dev/stg/prod) và theo nhóm tài nguyên (network, data, compute) — giảm blast radius khi `terraform apply` | Giảm rủi ro 1 lệnh apply làm hỏng toàn bộ hạ tầng | +| Drift detection | Chạy `terraform plan` định kỳ (đề xuất hàng ngày) trên CI, cảnh báo nếu có drift chưa giải thích | Đúng yêu cầu (h) — fitness function `FIT-34` | +| Tag policy | Bắt buộc tag `Project`, `Environment`, `Owner`, `CostCenter` trên mọi tài nguyên — enforce bằng AWS Config rule hoặc Terraform Sentinel/OPA policy | Phục vụ rà chi phí (§6.2 dashboard "Chi phí") và audit | + +🔴 Chọn Terraform làm công cụ IaC chính là quyết định thiết lập tiền lệ, ràng buộc dài hạn (đảo +ngược tốn nhiều tuần nếu đổi công cụ sau khi đã có code thật) — radar ước lượng ~7, đạt ngưỡng +`ADR` bắt buộc. Xem [`adr/ADR-017_iac-terraform.md`](adr/ADR-017_iac-terraform.md) (`Proposed`). +Điều kiện `Accepted`: Tech Lead + Ops/SRE xác nhận công cụ (`OQ-060`) và năng lực vận hành. + +**`FIT` ứng viên cho GĐ3:** + +| `FIT` | Kiểm tra | Công cụ | Chạy ở đâu | +|---|---|---|---| +| `FIT-34` | Drift detection — hạ tầng thật khớp Terraform state | `terraform plan` định kỳ / driftctl | CI, hàng ngày | +| `FIT-35` | Tag policy — mọi tài nguyên có đủ 4 tag bắt buộc | AWS Config rule / OPA | CI + AWS Config liên tục | +| `FIT-36` | Đúng 2 ECS service (GD/HT) + 1 Payment tồn tại, đúng SG cô lập theo §8.1 | Terraform plan review + AWS Config | CI/CD (trùng `ADR-012 FIT-16`, mở rộng thêm kiểm tra SG) | +| `FIT-37` | Blue-green deploy tự động rollback khi health check fail sau khi chuyển traffic | CodeDeploy hook test | Staging, trước mỗi major release | +| `FIT-38` | Pipeline chặn deploy khi Trivy/Snyk phát hiện Critical/High chưa có ngoại lệ | CI/CD test (giả lập lỗ hổng) | CI, định kỳ kiểm tra pipeline tự nó hoạt động đúng | + +--- + +## 12. Quyết định ghi nhận ở mức `DEC` (không đạt ngưỡng `ADR`) + +| Quyết định | Radar ước lượng | Lý do không cần `ADR` | +|---|---|---| +| Cơ chế service discovery nội bộ GD↔HT: AWS Cloud Map + ECS Service Connect (không App Mesh) | ~3 | Đảo ngược thấp (đổi sang App Mesh sau là bổ sung, không viết lại), bán kính hẹp (chỉ ảnh hưởng cấu hình network nội bộ), không chạm `QAS` Must trực tiếp (latency thêm không đáng kể, kế thừa đường găng đã có timeout ở `FAIL`), không tranh cãi | +| Auto-scaling metric: target tracking CPU + request count (không dùng custom metric phức tạp hơn ở bản đầu) | ~3 | Điều chỉnh được dễ dàng qua console/Terraform, không ràng buộc dài hạn | +| Environment tách VPC/account riêng cho non-prod (đề xuất, `OQ-062`) | ~4 | Đảo ngược trung bình (tách account sau khi đã chạy chung tốn công di chuyển nhưng không phải viết lại code) — ghi `DEC`, không `ADR`, nhưng vẫn cần `OQ-062` xác nhận trước khi triển khai thật | + +--- + +## 13. Truy vết + +| `INF` §/mục | `QAS` | `ASR` | `ADR` | `CMP` | `FM` | +|---|---|---|---|---|---| +| §3 Topology | `QAS-009` | `ASR-001`, `ASR-012`, `ASR-002` | `ADR-001`, `ADR-002`, `ADR-012` | `CMP-01…15` | — | +| §4 HA/auto-scaling | `QAS-002`, `QAS-009` | `ASR-014`, `ASR-007` | `ADR-012` | `CMP-04`, `CMP-15` | — | +| §5 DR | `QAS-008` | `ASR-010` | `ADR-009` | `CMP-02`, `CMP-04`, `CMP-11` | — | +| §6 Observability | `QAS-013`, `QAS-007` | `ASR-011` | `ADR-010` | `CMP-02`, `CMP-04`, `CMP-11` | `FM-09`, `FM-10` | +| §7 CI/CD | `QAS-007` | — | `ADR-016` | Toàn bộ `CMP` triển khai được | — | +| §8 Network/Security | `QAS-010`, `QAS-011` | `ASR-002`, `ASR-007` | `ADR-002` | `CMP-01`, `CMP-11`, `CMP-14`, `CMP-15` | — | +| §11 IaC | — | — | `ADR-017` | — | — | + +--- + +## 14. Giả định & Ngoài phạm vi + +**Giả định** *(tiếp số toàn dự án, bắt đầu `ASM-42`)*: + +| ID | Giả định | Cách xác minh | Nếu sai | +|---|---|---|---| +| `ASM-42` | Split ECS task Nhóm Giao dịch/Nhóm Hỗ trợ đề xuất (A: 2/2, B: 6/4) phản ánh đúng ý `TCO §3.2` khi gộp thành 1 dòng "monolith" — tức là `TCO` đã tính đủ tiền cho *tổng* task bất kể chia thế nào | Tech Lead/Ops xác nhận ở `OQ-026`/`OQ-055` | Nếu `TCO` thực ra chỉ tính đủ cho 1 service duy nhất (không đủ overhead vận hành 2 service riêng — VD 2 load balancer target group, 2 service discovery entry): chi phí thực tế có thể cao hơn `TCO` một khoản nhỏ (không đáng kể theo kinh nghiệm AWS — ECS service không tính phí riêng, chỉ tính theo task) | +| `ASM-43` | Auto-scaling target tracking (CPU 60%/70%, request count) đủ nhanh để bắt kịp tốc độ tăng tải thật của flash sale (chưa biết tốc độ tăng — `QAS-009` chỉ có 2 điểm A/B, không có đường cong tăng) | Đo thật trong `POC-01`/`POC-02` mở rộng hoặc diễn tập tải riêng cho auto-scaling (chưa có kế hoạch, đề xuất bổ sung ở GĐ3 `FIT`) | Nếu tải tăng nhanh hơn tốc độ scale (thường ECS Fargate cần 1-3 phút để task mới sẵn sàng): có thể có cửa sổ ngắn quá tải trước khi auto-scaling bắt kịp — cân nhắc pre-scale thủ công trước sự kiện flash sale đã biết trước lịch | +| `ASM-44` | ElastiCache Multi-AZ (kịch bản B) failover tự động trong ~60 giây theo tài liệu công khai AWS | Diễn tập DR-3 (§5.4) đo thật | Nếu chậm hơn nhiều: tăng thời gian gián đoạn ownership-check, cần xét lại kiến trúc fallback (VD cache-aside với timeout ngắn gọi thẳng DB) | +| `ASM-45` | ECS task thay thế sau khi 1 AZ down mất ~1-3 phút (health check + scheduler + container start) | Diễn tập DR-1 (§5.4) đo thật | Nếu lâu hơn: RTO tổng thể của nhóm giao dịch cốt lõi có nguy cơ tiệm cận giới hạn 1 giờ nhanh hơn dự kiến khi cộng dồn nhiều thành phần phục hồi tuần tự | +| `ASM-46` | Cửa sổ bảo trì ≤2 giờ/tháng (`OQ-020`, TẠM) đủ cho mọi hoạt động deploy/migration định kỳ kể cả nâng cấp minor version RDS | PO xác nhận số cuối ở `OQ-020`; Ops theo dõi thực tế sau go-live | Nếu không đủ: một số bảo trì phải tính vào ngân sách lỗi 43 phút/tháng, giảm biên độ cho sự cố thật | + +**Ngoài phạm vi:** + +- IaC (Terraform) thật, `AGD` runbook chi tiết, `FIT` chạy trên CI thật — thuộc `sa-3-enablement`. +- Multi-region active-passive — đã loại ở `ADR-009`, chỉ xét lại nếu PO duyệt ngân sách bổ sung. +- OpenSearch — P2 hoãn dùng, kế thừa nguyên trạng `SAD §10`/`TCO §3.2` (không có trong `TCO` cho + P2 kịch bản A/B, không thiết kế hạ tầng cho nó ở tài liệu này). +- Cấu hình DNS/Route53 failover chi tiết, chứng chỉ SSL cụ thể — tham chiếu `TCO §4`, chưa thiết + kế chi tiết ở `INF` này (mức độ ưu tiên thấp, ALB đã Multi-AZ). +- Chi tiết connection pool/bulkhead theo con số cụ thể (`OQ-037` của `FAIL`) — chờ kết quả + `POC-02`, `INF` chỉ ghi nhận đây là cấu hình cần thiết lập ở tầng RDS parameter group khi có số. +- Giá cả/đơn giá AWS — không tính lại, tham chiếu nguyên trạng `TCO` (`ASM-11`/`ASM-12`). + +--- + +## 15. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược | +|---|---|---|---|---|---| +| `OQ-054` | `TCO §3.2` tính "cross-region snapshot (Payment)" (~$30/A, ~$60/B) trong dòng Backup & DR — có mâu thuẫn với `ADR-009` (chọn PA-1, không multi-region) không, hay đây chỉ là snapshot phụ không nằm trong cam kết RTO≤1h? | Tech Lead + Ops/SRE + PO | 2026-09-15 | §10 đối chiếu `TCO`; nội dung `ADR-009`/`INF §5.2` | Nếu là (1) snapshot phụ: giữ nguyên, chỉ cần ghi rõ nó không tính vào RTO cam kết. Nếu là (2) sai sót: `TCO` giảm ~$30-60/tháng, không đổi kết luận P2 rẻ hơn P1 | +| `OQ-055` | Xác nhận split ECS task đề xuất giữa Nhóm Giao dịch/Nhóm Hỗ trợ (A: 2/2, B: 6/4) và ngưỡng auto-scaling (CPU 60%/70%, request count) — nối `OQ-026` | Tech Lead + Ops/SRE | 2026-09-15 | §4.2, §10; cấu hình Terraform thật ở GĐ3 | Nếu Tech Lead muốn tỷ lệ khác (VD 3/1 thay vì 2/2 ở kịch bản A): đổi bảng §3/§4, không đổi tổng chi phí `TCO` | +| `OQ-056` | Nối `OQ-022` — lịch diễn tập DR thật (DR-1/2/3 ở §5.4) là ngày nào? SA đề xuất trong vòng 2 tuần kể từ khi xác định Ops/SRE, trước khi trình AG2 | Ops/SRE | 2026-09-15 | Điều kiện tiên quyết ký AG2 (`DEC-12`) | Không diễn tập trước AG2 ⇒ RTO/RPO vẫn "trên giấy", Security/Ops có thể từ chối ký AG2 với lý do chính đáng | +| `OQ-057` | VNPay/Momo/GHN/GHTK/Email-SMS có yêu cầu IP allowlist cho traffic outbound từ sàn không? Nếu có, cần đăng ký 2 Elastic IP NAT với từng đối tác | Tech Lead (khi có tài liệu đối tác thật) | 2026-09-15 | §8.3; thời điểm phối hợp hành chính với đối tác trước go-live | Nếu không xử lý trước go-live và đối tác yêu cầu allowlist: toàn bộ traffic outbound bị chặn ở phía đối tác, phát hiện muộn ngay trước/sau go-live | +| `OQ-058` | Chấp nhận ElastiCache kịch bản A không có replica (SPOF, §4.3) hay muốn thêm 1 replica ngay (chi phí ước tính +~$92/tháng theo đơn giá `TCO §3.1`, chưa xác nhận chính xác)? | PO + Ops/SRE | 2026-09-15 | §4.3; cấu hình ElastiCache thật ở GĐ3 | Giữ nguyên (chấp nhận SPOF): tiết kiệm chi phí nhưng có gián đoạn ownership-check khi mất node Redis (ước 5-10 phút, chưa đo). Thêm replica: tăng chi phí nhỏ, giảm rủi ro gián đoạn | +| `OQ-059` | Xác nhận: (a) retention log CloudWatch/S3 archive, (b) tỉ lệ lấy mẫu X-Ray trace, (c) retention backup RDS (đề xuất 7 ngày, khác 35 ngày ở tài liệu P1 gốc) | Tech Lead + Ops/SRE | 2026-09-15 | §6.1, §5.2; chi phí lưu trữ thực tế | Retention ngắn hơn: giảm chi phí nhưng giảm khả năng điều tra sự cố cũ. Dài hơn: tăng chi phí lưu trữ | +| `OQ-060` | Xác nhận công cụ IaC (Terraform, đề xuất) và ngưỡng coverage unit test cho P2 (đề xuất kế thừa 70%/50% từ tài liệu P1, cần xác nhận lại cho kiến trúc mới) | Tech Lead | 2026-09-15 | §11 (`ADR-017` ứng viên); §7.1 pipeline | Nếu chọn CDK thay Terraform: cần kỹ năng TypeScript/Python cho hạ tầng, ảnh hưởng `CON-05` (năng lực team) | +| `OQ-061` | *(nối `OQ-037` của `FAIL`/`DAT`)* Kích thước connection pool RDS theo module (ghi checkout vs đọc catalog) và pool HTTP theo từng adapter đối tác ngoài — phụ thuộc kết quả `POC-02` chưa chạy | DBA + Tech Lead | 2026-09-15 | Cấu hình RDS parameter group thật ở GĐ3 | Pool sai kích thước: nghẽn checkout (quá nhỏ) hoặc lãng phí connection/cạn tổng pool RDS (quá lớn) | +| `OQ-062` | Non-prod (dev/stg) nên tách VPC riêng trong cùng account hay tách hẳn AWS account riêng (đề xuất SA: account riêng theo AWS Organizations, best practice cô lập blast radius + rà chi phí)? | Tech Lead + Ops/SRE | 2026-09-15 | §2, §3 (bảng thành phần "Non-prod") | Account riêng: cô lập tốt hơn nhưng thêm chi phí quản lý cross-account (IAM, networking). Cùng account khác VPC: đơn giản hơn nhưng rủi ro cấu hình sai lan sang prod cao hơn | +| `OQ-063` | *(nối `OQ-008`, không lặp lại — chỉ nhắc)* Đội Ops/SRE thật (nội bộ/thuê ngoài, quy mô) — chặn trực tiếp khả năng đáp ứng on-call §6.5 và tần suất diễn tập DR §5.4 | PM/SRE | 2026-09-12 *(đã mở từ `CTX`)* | §5.4, §6.5 | Xem `CTX OQ-008` — không lặp lại hệ quả ở đây | + +**Nhắc AG2:** cần **Tech Lead + Security + Ops/SRE ký**. `INF` là artifact cuối cùng cần Ops/SRE +ký trực tiếp (`workflow.md §2`) — hoạt động còn lại của GĐ2 là `fail` (đã xong, `DEC-21/22`) và +`adr` (12+1 ADR đã viết, cộng 2 ADR ứng viên mới từ `INF`: `ADR-016` blue-green, `ADR-017` +Terraform, cộng `ADR-014`/`ADR-015` đang chờ từ `DAT`/`SEC`). + +--- + +## Tự chấm + +### ① Bảng tự chấm Gate AG2 *(`workflow.md §2` — dòng liên quan `INF`)* + +| # | Tiêu chí | ☐/✅ | Ghi chú | +|---|---|---|---| +| — | `ASR`/`QAS`/`SAD`/`ADR`/`ICD`/`DAT`/`SEC`/`FAIL` | ✅ *(đã đạt ở các hoạt động trước, duyệt từng phần)* | Xem artifact tương ứng | +| 1 | `INF` — topology môi trường, HA/DR có **RTO/RPO bằng số**, chiến lược scale, observability | ✅ *(nội dung đầy đủ)* / 🔴 *(chưa đo thật)* | §3–§6: RTO≤1h/RPO≤15’ có số, HA Multi-AZ, scale A→B có ngưỡng, observability có log/metric/trace/dashboard/alert — nhưng **chưa diễn tập** (`OQ-022/056`), `Confidence` giữ 🔴 | +| — | `sa-conformance` báo coverage `ASR → ADR/CMP` ≥ 100% | 🟡 Không đổi bởi `INF` | `INF` không tạo `ASR`/`CMP` mới, chỉ hiện thực hoá — coverage đã đạt 15/15 ở `SAD §4.3` | + +**Kết luận tự chấm (riêng phần `INF`):** Đủ nội dung theo checklist AG2 dòng `INF` — có RTO/RPO +bằng số, kế hoạch diễn tập DR cụ thể (3 kịch bản, tiêu chí PASS/FAIL đo thật), auto-scaling có +ngưỡng, observability đủ 3 trụ (log/metric/trace) + alert + error budget, CI/CD có pipeline đủ +bước + chiến lược deploy zero-downtime, network/security group đầy đủ, đối chiếu `TCO` từng dòng +(1 điểm chưa khớp bản chất đã ghi `OQ-054`, không tự sửa). **Chưa đủ điều kiện ký AG2** vì: (a) +chưa diễn tập DR/inject lỗi thật, (b) `POC-01`/`POC-02` chưa chạy, (c) `OQ-008` (đội Ops thật) +còn mở — ba điều này đều **ngoài khả năng của việc viết tài liệu**, cần hành động thật của +Ops/SRE/Tech Lead. + +### ② Checklist D1–D12 + +| # | Mục | ☐/✅ | Ghi chú | +|---|---|---|---| +| D1 | Một ADR một quyết định | N/A | `INF` không viết `ADR` mới ở lượt này — chỉ đề xuất 2 ứng viên (`ADR-016`, `ADR-017`) cho hoạt động `adr` kế tiếp, mỗi ứng viên đã tách đúng 1 quyết định | +| D2 | Không NFR định tính | ✅ | Mọi ngưỡng (RTO/RPO, auto-scaling, alert, retention) đều có con số hoặc đánh dấu rõ "chưa chốt" kèm `OQ` | +| D3 | Nêu phương án bị loại + lý do gắn `CON`/`QAS` | ✅ *(kế thừa)* | Deploy strategy: nêu rõ vì sao chọn blue-green thay vì rolling (gắn `QAS-007`); Service discovery: nêu rõ vì sao không chọn App Mesh (gắn giới hạn phạm vi đã ghi ở `SAD §7`); các phương án lớn khác (multi-region, message backbone, DB) đã có `ADR` riêng, `INF` chỉ hiện thực hoá | +| D4 | Sơ đồ khai báo mức + legend | ✅ | §3 khai báo "Deployment view", có legend đầy đủ (ranh giới mạng, AZ, loại đường nối); §7.1 khai báo loại (pipeline flowchart) | +| D5 | Interface có chủ/contract | N/A | Không phải phạm vi `INF` — đã có ở `ICD` | +| D6 | Phụ thuộc ngoài process có timeout/retry | N/A | Đã có ở `FAIL` — `INF` chỉ bổ sung network/SG cho phép các phụ thuộc đó chạy được, không thiết kế lại timeout/retry | +| D7 | Một chủ sở hữu dữ liệu | ✅ *(kế thừa)* | §5.2 Backup/PITR tôn trọng đúng ranh giới `ADR-002`/`ADR-006` (RDS chính vs RDS Payment tách biệt) | +| D8 | Ràng buộc có FIT hoặc nhãn khuyến nghị | ✅ | §11 đề xuất `FIT-34…38`; các mục chưa có FIT (VD "ai xử lý DLQ theo domain") đánh dấu rõ "chưa chốt", không giả vờ đã có | +| D9 | Con số hạ tầng quy ra tiền + nguồn; `INF` khớp `TCO` | ✅ *(1 điểm ngoại lệ đã ghi rõ)* | §10 đối chiếu từng dòng — khớp toàn bộ trừ 1 điểm bản chất (`OQ-054`), không tự sửa `TCO` | +| D10 | Không quyết định thay người có thẩm quyền | ✅ | §4.3 (SPOF Redis kịch bản A — trình `OQ-058` kèm chi phí, không tự chọn), §5.2 (`OQ-054` — trình 2 khả năng, không tự sửa `TCO`/`ADR-009`), §7.2 (đề xuất blue-green nhưng đánh dấu cần `ADR-016` — không tự "Accepted") | +| D11 | Có mục "Ngoài phạm vi" + `ASM-nn` | ✅ | §14 đầy đủ — `ASM-42…46` 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 | `INF` tương ứng | Khớp? | Hành động | +|---|---|---|---|---| +| `docs/09 §9.5.2` (RTO/RPO gốc, kiến trúc P1) | Payment/Cart&Order/Identity: RPO≤15’/RTO≤1h; Commission&Payout/Seller: RPO≤1h/RTO≤4h; Catalog/Promotion/Shipping: RPO≤1h/RTO≤8h; Review/Notification/Audit: RPO≤24h/RTO≤24h | `INF §5.1` chỉ thiết kế DR cho nhóm giao dịch cốt lõi (khớp `ASR-010`/`QAS-008`, đúng phạm vi P2 hiện tại) | 🟡 Một phần | `INF` **chưa** thiết kế DR chi tiết cho Nhóm Hỗ trợ (Commission/Seller/Catalog/Promotion/Review/Notification) — ngoài phạm vi yêu cầu người duyệt lượt này (chỉ yêu cầu nhóm giao dịch cốt lõi); ghi nhận là khoảng trống cần bổ sung ở lượt `inf` tiếp theo hoặc trước AG2 nếu Ops/SRE yêu cầu | +| `docs/09 §9.3.1` (CI/CD, kiến trúc P1, 10 microservice) | Pipeline build→test→SAST→SCA→integration→deploy dev/stg/prod, canary rollout | `INF §7.1` — điều chỉnh còn 3 đơn vị triển khai (không phải 10), bỏ Kafka-specific test, đổi canary→blue-green | ✅ Đã điều chỉnh đúng theo P2, không sao chép nguyên trạng P1 | Không cần hành động — đã ghi rõ trong Change Log là "điều chỉnh, không tái dùng nguyên trạng" | +| `docs/09 §9.4.1` (Metrics/alert, kiến trúc P1) | Alert theo NFR-01…08, kênh PagerDuty/OpsGenie | `INF §6.3` — giữ cùng nguyên tắc alert (health check ≤1 phút, escalation 24/7) nhưng bỏ Kafka consumer lag (đổi thành SQS `ApproximateAgeOfOldestMessage`) | ✅ Đã điều chỉnh | Không cần hành động | +| `QAS-008`/`ADR-009` (SA) | RPO≤15’/RTO≤1h, chưa diễn tập | `INF §5.4` — kế hoạch diễn tập cụ thể | ✅ | `INF` là nơi hiện thực hoá điều kiện `ADR-009 §3` đã đặt ra — không lệch | + +### ④ Danh sách `OQ` mở kèm người phải trả lời, chặn gì + +Xem §15 (`OQ-054…063` mới) cộng các `OQ` còn mở từ toàn dự án — sổ đầy đủ tại +`00-index/OQ_e-commerce.md`. Ba câu quan trọng nhất trước khi trình AG2: **`OQ-056`** +(nối `OQ-022`, lịch diễn tập DR — điều kiện tiên quyết `DEC-12`), **`OQ-063`** (nối `OQ-008`, +đội Ops thật — chặn cả on-call §6.5 lẫn khả năng thực hiện diễn tập DR §5.4), **`OQ-054`** +(mâu thuẫn TCO/ADR-009 về cross-region snapshot Payment). + +**Nhắc:** `ADR-014` (outbox, theo `DAT`), `ADR-015` (service JWT, theo `SEC`), `ADR-016` +(blue-green) và `ADR-017` (Terraform, theo `INF`) đã được viết ở lượt hoạt động `adr` kế tiếp — +GĐ2 nay đủ 9/9 hoạt động, 17 `ADR` tổng cộng, tất cả `Proposed`. Cần chạy `sa-conformance` để cập +nhật `DTM`/`ADL` và kiểm coverage trước khi trình AG2 (Tech Lead + Security + Ops/SRE ký). diff --git a/sa-output/e-commerce/02-architecture/QAS_e-commerce_v1.0.md b/sa-output/e-commerce/02-architecture/QAS_e-commerce_v1.0.md new file mode 100644 index 0000000..c131a68 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/QAS_e-commerce_v1.0.md @@ -0,0 +1,283 @@ +# QAS + ASR — Quality Attribute Scenarios & Architecturally Significant Requirements — e-commerce + +| | | +|---|---| +| **Version** | 1.0 | +| **Date** | 2026-09-14 | +| **Author** | SA (skill sa-2-architecture, chế độ `go`, hoạt động `qas`) | +| **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-14: chấp nhận 14 `QAS-001…014` đủ 6 phần và cách đo (Phần A); chấp nhận **TẠM** các số SA tự đề xuất — `QAS-003` p95 ≤500ms, `QAS-004` p95 ≤300ms, `QAS-007` loại trừ bảo trì ≤2 giờ/tháng, `QAS-014` đối soát ≤15 phút — làm baseline tạm để GĐ2 không nghẽn; `OQ-018…021` **giữ nguyên mở**, chờ PO/Tech Lead thật xác nhận số cuối cùng. Chốt thêm điều kiện: diễn tập DR (`QAS-008`) **phải thực hiện trước khi ký AG2** — xem `OQ-022` (đã cập nhật) và ghi làm điều kiện tiên quyết của AG2, cũng là input bắt buộc cho hoạt động `inf` khi tới lượt. Ghi thêm `DEC-12`. · Security: — *(chưa ký)* · Ops/SRE: — *(chưa ký, kể cả điều kiện diễn tập DR ở `OQ-022` cũng do Ops/SRE xác nhận, chưa có)*. `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ệ. | +| **Source** | `sa-output/e-commerce/01-context/CTX_e-commerce_v1.0.md` (v1.2) §2 (`DRV-01…09`), §3 (`CON-nn`) · `01-context/OPT_e-commerce_v1.0.md` §1, §8 (`ASM-07…09`, chọn P2) · `01-context/TCO_e-commerce_v1.0.md` §2 (kịch bản tải A/B, `ASM-10`) · `01-context/ARISK_e-commerce_v1.0.md` §3 (`ARISK-01…10`), §6 (`POC-01`, `POC-02`) · `00-index/OQ_e-commerce.md` v1.7 · `00-index/DEC_e-commerce.md` v1.8 · `ba-output/e-commerce/03-specification/NFR_US002-003_v1.0.md` (`NFR-PERF-01/02`, `NFR-SEC-01…03`, `NFR-AVL-01/02`, `OQ-033`) · `ba-output/e-commerce/03-specification/SRS_US002-003_v1.0.md` · `ba-output/e-commerce/03-specification/API_US002-003_v1.0.md` · `ba-output/e-commerce/01-discovery/BRIEF_CartCheckout_v1.0.md` §4 (`GOAL-01/02`) · `e-commerce/docs/sections/02-phan-tich-yeu-cau.md` (`NFR-01…08`) · `e-commerce/docs/SAD.md` §5.3.2, §9.4.1, §9.5.2 (RTO/RPO, ngưỡng alert — kế thừa, chưa thiết kế lại) | +| **Scope** | Toàn sàn e-commerce theo phương án **P2** (modular monolith + managed AWS, tách riêng Payment — `DEC-06`/`OQ-011`, **chưa** phải `ADR` chính thức). Chi tiết nhất: module **Giỏ hàng & Checkout** (US-002/003, `SCR-04`) — nơi BA đã có `NFR_US002-003`. Chỉ hoạt động 1/9 của `sa-2-architecture` (**QAS**) — không tạo `ASR`/`SAD`/`ADR` ở lượt này (xem Phần B, để trống có chủ đích). | +| **Confidence** | 🔴 Giả định chưa xác minh — AG1 (gate GĐ1 SA) chưa có chữ ký PO/Tech Lead thật (chỉ "PO uỷ quyền — điều phối dự án" ký từng phần dưới ngoại lệ `DEC-01…10`); `POC-01`/`POC-02` (đo throughput SQS/EventBridge, RDS gộp tải) **chưa chạy**; BA chưa ký G1 cho `BRIEF_CartCheckout`. Toàn bộ `QAS` trong tài liệu này giữ mức thấp nhất cho tới khi: (a) PO/Tech Lead ký AG1 thật, (b) `POC-01`/`POC-02` chạy xong, (c) các con số do SA **đề xuất** (chưa có nguồn PO/Tech Lead) ở mục A3 được xác nhận — xem `DEC-11`. | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | ADR/DEC | +|---|---|---|---|---| +| 1.0 | 2026-09-14 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `qas`) | Bản đầu — lượng hoá toàn bộ `NFR-01…08` (SAD/docs) và `NFR-PERF/SEC/AVL` (BA, `NFR_US002-003`) thành 14 `QAS-nnn` đủ sáu phần, rà đủ 7 nhóm thuộc tính (Bảo trì đánh dấu N/A có lý do). Mọi `QAS` truy vết về `DRV`/`ARISK`/`NFR` nguồn. Chạy dưới ngoại lệ gate AG1 chưa qua — ghi `DEC-11` (SA), tiếp nối `DEC-01…10`. Không tạo `ASR`/`SAD`/`ADR` ở lượt này theo yêu cầu điều phối — Phần B để trống có ghi chú. | `DEC-11` | +| 1.0 | 2026-09-14 | Đ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 14 `QAS` đủ 6 phần và cách đo; chấp nhận **TẠM** các số SA đề xuất (`QAS-003` ≤500ms, `QAS-004` ≤300ms, `QAS-007` loại trừ bảo trì ≤2h/tháng, `QAS-014` đối soát ≤15 phút) làm baseline tạm — `OQ-018…021` **giữ nguyên mở** chờ PO/Tech Lead thật. Chốt điều kiện mới: diễn tập DR (`QAS-008`) phải thực hiện **trước khi ký AG2** (cập nhật `OQ-022`, ghi thành điều kiện tiên quyết AG2 và input bắt buộc cho `INF`). Không đổi nội dung chuyên môn. Security/Ops chưa ký; `OQ-004` mở; `Confidence` giữ 🔴; Status giữ 🟡 Draft; AG2 **chưa** ký. Ghi thêm `DEC-12`. | `DEC-12` | + +> Sơ đồ thắng về **quan hệ và luồng** — tài liệu này không có sơ đồ (chỉ bảng lượng hoá). +> Bảng/văn bản thắng về **ràng buộc và con số**. Mâu thuẫn ngoài hai loại này 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 (gate GĐ1 SA) chưa được ký chính thức.** Audit gần nhất (2026-09-12, xem +`ARISK_e-commerce_v1.0.md` §Tự chấm, `DTM_e-commerce.md` §12): AG1 đủ cấu trúc 4/4 artifact +(`CTX`/`OPT`/`TCO`/`ARISK`, mỗi file tự chấm 7/7 tiêu chí **cấu trúc**), nhưng: + +- Mọi phê duyệt đều là **"PO uỷ quyền — Điều phối dự án"**, không phải chữ ký PO/Tech Lead thật + (`OQ-004` còn mở). +- Hai `POC` bắt buộc — `POC-01` (throughput SQS/EventBridge, hạ `ARISK-01`) và `POC-02` (RDS gộp + tải, hạ `ARISK-02`) — **chưa chạy**, chỉ mới có kế hoạch + tiêu chí PASS/FAIL viết trước. +- BA chưa ký G1 chính thức cho `BRIEF_CartCheckout` (`OQ-001` của BA còn mở). + +Người dùng (vai điều phối dự án chạy thử) đã được cảnh báo lại về tình trạng này và **khẳng định +muốn tiếp tục** sang GĐ2 (`sa-2-architecture`), hoạt động 1/9 (`QAS`), tham chiếu mô hình ngoại lệ +đã dùng xuyên suốt GĐ1 (`DEC-01…10`). Quyết định ngoại lệ này được ghi nhận dưới đây và tại sổ +`00-index/DEC_e-commerce.md`. + +> **DEC-11 (SA)** — Bắt đầu `sa-2-architecture` (hoạt động 1 — `QAS`) cho e-commerce trong khi +> AG1 (gate GĐ1 SA) chưa có chữ ký PO/Tech Lead thật (audit 2026-09-12: AG1 🟠 — 4 artifact GĐ1 +> duyệt từng phần bởi PO uỷ quyền, `Confidence` 🔴 toàn bộ; `POC-01`/`POC-02` chưa chạy; BA chưa +> ký G1 cho `BRIEF_CartCheckout`). Tiếp nối `DEC-01…10`. +> **Quyết định:** Tiếp tục lượng hoá `NFR` thành `QAS` dưới ngoại lệ gate. Mọi `QAS` giữ +> `Confidence` 🔴 cho tới khi: (a) PO/Tech Lead ký AG1 thật; (b) `POC-01`/`POC-02` chạy xong và +> kết quả được ghi vào `ARISK`; (c) các con số **SA đề xuất** (chưa có nguồn PO/Tech Lead — +> đánh dấu rõ trong mục A3) được PO/Tech Lead xác nhận qua các `OQ` mới (`OQ-018…023`). +> **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 (sửa lại `QAS` khi có số thật không tốn +> nhiều, đây là tài liệu chưa phải cam kết thi công) · bán kính ảnh hưởng: toàn bộ GĐ2 phụ thuộc +> `QAS` này, nhưng bản thân *việc ghi tài liệu dưới ngoại lệ* thì nhỏ · **có** chạm `QAS` Must +> trực tiếp (đang tạo chính `QAS`, không phải quyết định kiến trúc đã cam kết dựa trên nó) · +> không ràng buộc dài hạn (ngoại lệ tạm thời, tiếp nối tiền lệ) · không tranh cãi mới → **ghi +> `DEC-nn`, không cần `ADR` riêng cho việc chạy dưới ngoại lệ** (`decision-radar.md §1–§2`) — khác +> với `ADR` cho quyết định kiểu kiến trúc P2, việc đó vẫn phải làm ở hoạt động `asr`/`adr` kế tiếp +> (đã cảnh báo ở `DTM §11` "🟠 Nợ #1"). +> **Hệ quả nếu không chấp nhận ngoại lệ:** dừng GĐ2 hoàn toàn cho tới khi AG1 ký thật và +> `POC-01`/`POC-02` chạy xong — chậm tiến độ chạy thử tương ứng thời gian PO/Tech Lead xử lý các +> `OQ` đang mở (`OQ-004/005/006/007/008/010/012` của GĐ1 cộng `OQ-018…023` mới của tài liệu này). + +🔴 **Nhắc quan trọng cho người đọc:** đây **chỉ là hoạt động 1/9** của `sa-2-architecture`. +`ASR` (hoạt động 2), `SAD` (hoạt động 3), `ADR`, `ICD`, `DAT`, `SEC`, `INF`, `FAIL` **chưa được +tạo** — theo đúng yêu cầu điều phối ("Không tạo ASR/SAD/ADR ở lượt này"). Thứ tự bắt buộc của +GĐ2 (`SKILL.md`: 1→2→3 trước khi làm 4–8) vẫn được tôn trọng: đây đúng là bước đầu tiên. + +--- + +# PHẦN A — Quality Attribute Scenarios + +## A1. Tóm tắt + +| Nhóm thuộc tính | Số `QAS` | Must | Đã có cách đo | Đã đo thật | +|---|---|---|---|---| +| Hiệu năng | 4 (`QAS-001…004`) | 4/4 | 4/4 (k6/artillery, kịch bản cụ thể) | 0/4 | +| Thông lượng | 2 (`QAS-005/006`) | 2/2 | 2/2 (`POC-01`/`POC-02`, tiêu chí đã viết trước) | 0/2 | +| Sẵn sàng | 2 (`QAS-007/008`) | 2/2 | 2/2 (uptime monitor · diễn tập DR) | 0/2 | +| Mở rộng | 1 (`QAS-009`) | 1/1 | 1/1 *(một phần — phụ thuộc `POC-01`/`POC-02` + hoạt động `inf` chưa chạy)* | 0/1 | +| Bảo mật | 3 (`QAS-010…012`) | 3/3 | 3/3 | 0/3 | +| Bảo trì | 0 | — | — | — | +| Quan sát được | 2 (`QAS-013/014`) | 2/2 | 2/2 | 0/2 | +| **Tổng** | **14** | **14/14** | **14/14** | **0/14** | + +**Nhóm không áp dụng:** + +- **Bảo trì (Maintainability)** — không áp dụng ở giai đoạn `QAS` này. Lý do: mẫu đo chuẩn của + nhóm này ("một dev mới onboard và sửa được một bug thật trong ≤3 ngày", theo + `templates/quality-scenarios.md` A2) đòi hỏi **một đội thi công thật** đang làm việc trên + codebase thật — dự án chưa có đội thi công thật được xác nhận (`OQ-010` của `OPT` còn mở, + `CON-05` vẫn là giả định "team MVP chuẩn" theo `DEC-02`). Không có bài đo nào chạy được trước + khi có đội thật và có codebase để đo — theo đúng quy tắc "không đo được ⇒ bỏ hẳn, đừng ghi định + tính" (`SKILL.md` mục 1). `NFR-07` (kiến trúc module hoá để các nhóm phát triển độc lập) không + bị bỏ qua — nó là ứng viên `ASR` (ép cấu trúc modular monolith theo domain, xem `OPT §3` P2) sẽ + được xử lý ở hoạt động `asr` kế tiếp, không phải một `QAS` đo bằng con số thời gian. + **Hành động:** đo lại nhóm này trong sprint đầu tiên sau khi có đội thi công thật + codebase đủ + lớn để chọn một bug thật làm bài đo (không phải việc của lượt chạy này). + +--- + +## A2. Mẫu một `QAS` *(tham chiếu — xem cấu trúc đầy đủ ở `templates/quality-scenarios.md`)* + +--- + +## A3. Danh sách `QAS` + +### Hiệu năng + +| ID | Tên | Kích thích + môi trường | Đo lường | Đo bằng cách nào | Ai đo | Mức | Nguồn | +|---|---|---|---|---|---|---|---| +| `QAS-001` | Latency danh mục/tìm kiếm | Guest/Customer gọi `GET /v1/catalog/search`; môi trường giờ cao điểm flash sale, tải kịch bản B (10.000 concurrent user, `TCO §2` `ASM-10`) | **p95 ≤ 2 giây** | k6/artillery, kịch bản `GET /v1/catalog/search` tại 10.000 concurrent user, staging cấu hình giống production, chạy trước mỗi major release | QA + SRE | Must | `DRV-04`, `NFR-01` | +| `QAS-002` | Latency checkout | Customer/Guest gọi `POST /v1/checkout` (giỏ 2–3 seller); môi trường giờ cao điểm, tải kịch bản B | **p95 ≤ 3 giây** (bao gồm tách đơn theo seller + gọi Payment) | k6 kịch bản `POST /v1/checkout` với payload giỏ đa seller mô phỏng, tải đỉnh kịch bản B, staging, trước mỗi release | QA + SRE | Must | `DRV-01`, `DRV-02`, `NFR-01` | +| `QAS-003` | Latency tải giỏ hàng | Customer/Guest mở `SCR-04` → `GET /v1/cart`; giỏ ≤ 50 dòng (đề xuất BA, `ASM-16` mới); tải bình thường lẫn giờ cao điểm | **p95 ≤ 500ms** *(🔴 đề xuất của SA — chưa PO/Tech Lead xác nhận, nối `OQ-033` của BA, xem `OQ-018`)* | k6 kịch bản `GET /v1/cart`, 1 user và tải đồng thời tương ứng kịch bản A/B, staging | QA | Must | `NFR-PERF-01` (BA), `DRV-04` | +| `QAS-004` | Latency sửa/xoá dòng giỏ hàng | Customer/Guest gọi `PATCH`/`DELETE /v1/cart/items`; 1 request ghi đơn lẻ | **p95 ≤ 300ms** *(🔴 đề xuất của SA — chưa xác nhận, nối `OQ-033` của BA, xem `OQ-019`)* | k6 kịch bản `PATCH`/`DELETE /v1/cart/items` đơn lẻ + tải đồng thời tương ứng, staging | QA | Must | `NFR-PERF-02` (BA), `DRV-04` | + +🔴 Mọi ngưỡng trên **kế thừa nguyên trạng "giả định mặc định đã chốt trong brief"** (ghi chú cuối +`docs/sections/02-phan-tich-yeu-cau.md` §2.2) — **chưa phải SLA hợp đồng**. `QAS-003`/`QAS-004` +là số **SA tự đề xuất** (không có trong `NFR_US002-003` của BA, vốn để trống chờ `OQ-033`) — +không bịa, đã gắn `ASM`/`OQ` tương ứng. + +### Thông lượng + +| ID | Tên | Kích thích + môi trường | Đo lường | Đo bằng cách nào | Ai đo | Mức | Nguồn | +|---|---|---|---|---|---|---|---| +| `QAS-005` | Thông lượng message bus `OrderPlaced`/`PaymentConfirmed` | Burst event publish tại đỉnh flash sale — ước ~21 event/giây trung bình (15.000 đơn/giờ × ~5 event/đơn, `TCO` kịch bản B) × biên an toàn ×5; SQS FIFO per-seller message group + EventBridge fan-out ≥ 5 consumer rule, AWS `ap-southeast-1` thật | Thông lượng **sustained ≥ 100 msg/s** trong 30 phút; **p99 độ trễ publish→consume ≤ 2 giây**; **0 message mất**; fan-out lag ≤ 5 giây | **`POC-01`** (đã lập ở `ARISK §6`) — k6/artillery load generator, AWS thật, tối đa 5 ngày làm việc, **chưa chạy** | Tech Lead + 1 DevOps | Must | `DRV-04`, `ARISK-01`, `ASM-07` (OPT) | +| `QAS-006` | Thông lượng RDS gộp (ghi checkout + đọc catalog) | Đồng thời ~15.000 đơn/giờ (ghi) + ~150.000 truy vấn catalog/giờ (đọc, ×10 tải ghi) trên 1 cụm RDS chính (P2, schema-per-module, không tính Payment); staging `db.r6g.xlarge` Multi-AZ, dataset ~50GB/300k SKU (kịch bản A) | **p95 write (checkout) ≤ 300ms**, **p95 read (catalog) ≤ 200ms**, **CPU RDS < 75%**, connection pool không exhaust | **`POC-02`** (đã lập ở `ARISK §6`) — load test staging cấu hình instance thật, tối đa 5 ngày, **chưa chạy** | Tech Lead/DBA | Must | `DRV-04`, `ARISK-02`, `ASM-08` (OPT) | + +🔴 Cả hai `QAS` này **không tạo bài đo mới** — chúng chính là `POC-01`/`POC-02` đã có kế hoạch ở +`ARISK_e-commerce_v1.0.md §6` (theo đúng ghi chú người duyệt: "ARISK-01/02 chính là bài đo"). +Việc còn lại là **chạy POC**, không phải thiết kế lại tiêu chí. + +### Sẵn sàng + +| ID | Mục tiêu | Ngân sách lỗi | Phạm vi tính | Không tính vào | Đo bằng cách nào | Mức | +|---|---|---|---|---|---|---| +| `QAS-007` | 99.9%/tháng cho dịch vụ giao dịch lõi (Catalog, Checkout, Payment, Identity — `SAD §3.1`) | **43 phút/tháng** | API công khai của 4 service trên | Bảo trì có báo trước **≤ 2 giờ/tháng** *(🔴 đề xuất của SA — chưa PO xác nhận, xem `OQ-020`, `ASM-17` mới)* | Uptime/health-check monitor (CloudWatch Synthetics hoặc tương đương), tính theo tháng, báo cáo hàng tháng cho SRE | Must | + +| ID | Nhóm service | RPO | RTO | Đo bằng cách nào | Mức | +|---|---|---|---|---|---| +| `QAS-008` | Payment, Cart & Order, Identity & Access (giao dịch cốt lõi) | **≤ 15 phút** | **≤ 1 giờ** | Diễn tập DR (failover drill) — **CHƯA TỪNG DIỄN TẬP**; con số kế thừa nguyên trạng từ `SAD §5.3.2`/`§9.5.2`, chưa thiết kế lại (thuộc hoạt động `inf`, chưa chạy). Theo `SKILL.md` mục 7: "RTO/RPO chưa diễn tập là RTO/RPO trên giấy" ⇒ `Confidence` 🔴, cần lịch diễn tập trước AG2 (xem `OQ-022`) | Must | + +🔴 **`QAS-008` không phải RTO/RPO mới** — SA **không thiết kế lại** HA/DR ở lượt chạy này (đó là +hoạt động `inf`, chưa chạy); ghi lại đây để `QAS` nhóm Sẵn sàng đầy đủ theo yêu cầu template, +nhưng con số vẫn là **đề xuất kế thừa từ SAD**, chưa qua diễn tập thật — thấp hơn cả mức "ước +lượng có cơ sở". + +### Mở rộng + +| ID | Tải hôm nay | Tải mục tiêu | Trong bao lâu | Scale bằng cách nào | Giới hạn trên | Mức | +|---|---|---|---|---|---|---| +| `QAS-009` | 0 (chưa go-live, greenfield) | Kịch bản A (Năm 1): **2.000 concurrent user**, ~400 đơn/giờ đỉnh · Kịch bản B (đỉnh flash sale): **10.000 concurrent user**, ~15.000 đơn/giờ đỉnh (≈4,2 đơn/giây) — `TCO §2`, `ASM-10` | Từ go-live tới đợt flash sale đầu tiên — **thời điểm cụ thể chưa xác nhận** (🔴 mới, xem `OQ-018`… không, xem ghi chú dưới) | ECS Fargate auto-scaling theo CPU/request count cho nhóm "giao dịch" (Cart/Order/Catalog) — **ngưỡng kích hoạt cụ thể chưa chốt**, thuộc hoạt động `inf` (chưa chạy) | Chưa xác định — đề xuất xét lại kiến trúc nếu tải thật vượt kịch bản B ×2 (~20.000 concurrent) mà chưa kiểm chứng lại (xem "Ngoài phạm vi" §D) | Must | + +*Bài đo cho `QAS-009` tái sử dụng chính `QAS-005`/`QAS-006` (`POC-01`/`POC-02`) chạy lần lượt ở +kịch bản A rồi kịch bản B — không tạo bài đo trùng lặp.* + +### Bảo mật + +| ID | Mối đe doạ | Yêu cầu | Kiểm chứng bằng cách nào | `THR-nn` liên quan | Mức | +|---|---|---|---|---|---| +| `QAS-010` | IDOR — request giả mạo `cartItemId`/`session` không phải chủ sở hữu lên `PATCH`/`DELETE /v1/cart/items` | 100% request phải qua kiểm tra quyền sở hữu (đối chiếu `customerId`/`sellerId` JWT hoặc `session_id` Guest); 0 lượt IDOR thành công | Security test tự động (integration test gọi thẳng API với token/session không phải chủ sở hữu — tương ứng `AC-US003-12/13` của BA) trên staging trước mỗi release | *(chưa có — `THR` thuộc hoạt động `sec`, chưa chạy)* | Must | +| `QAS-011` | Rò rỉ/chia sẻ thừa PII (địa chỉ, SĐT người nhận) cho seller khi tách đơn — vi phạm NĐ13/2023 | 100% trường PII chia sẻ cho seller đã qua rà soát Pháp chế/Security trước go-live (data minimization: chỉ trường cần thiết để giao hàng); 0 trường dư thừa bị lộ qua audit | Review thủ công bởi đại diện Pháp chế/Security (**chưa có người — kế thừa `OQ-007` của `CTX`/`ARISK-06`**) đối chiếu danh sách field SA chuẩn bị, cộng kiểm thử so khớp field thực tế truyền cho seller vs danh sách đã duyệt | *(chưa có — `THR` thuộc hoạt động `sec`)* | Must | +| `QAS-012` | Bypass MFA khi đăng nhập Admin | 100% đăng nhập Admin bắt buộc bước MFA thứ hai, 0 lượt bypass; Seller: khuyến khích (không bắt buộc) | Test tự động: đăng nhập Admin không qua MFA phải bị từ chối; audit log đăng nhập admin rà soát hàng tháng | *(chưa có — `THR` thuộc hoạt động `sec`)* | Must (Admin) / Should (Seller) | + +*Không ghi "bảo mật" như một mục — mỗi dòng trên nêu đúng một mối đe doạ cụ thể. Threat model +STRIDE đầy đủ (`THR-nn`) là hoạt động `sec`, **chưa chạy** ở lượt này; ba `QAS` trên là input đầu +vào cho hoạt động đó, không thay thế nó.* + +### Bảo trì + +*Xem "Nhóm không áp dụng" ở A1 — không có `QAS` nào trong nhóm này ở lượt chạy này.* + +### Quan sát được + +| ID | Kịch bản | Đo lường | Đo bằng cách nào | Mức | +|---|---|---|---|---| +| `QAS-013` | Sự cố tăng đột biến lỗi 5xx ở service giao dịch cốt lõi (Cart & Order, Payment, Identity) | Cảnh báo tự động trong **≤ 1 phút** (health check fail liên tục > 1 phút — kế thừa `SAD §9.4.1`); on-call acknowledge trong **≤ 15 phút** (`NFR-08`), quá hạn thì escalate | Diễn tập inject lỗi (chaos/fault injection thủ công — dừng task ECS) trên staging trước go-live, đo thời gian từ inject tới cảnh báo xuất hiện trên kênh (PagerDuty/OpsGenie) — **chưa từng diễn tập** | Must | +| `QAS-014` | Webhook xác nhận thanh toán VNPay/Momo trễ/lỗi khiến đơn kẹt "chờ thanh toán" dù tiền đã thu (`DRV-08`) | Job đối soát phát hiện lệch trạng thái trong **≤ 15 phút** kể từ khi giao dịch được xác nhận phía cổng thanh toán *(🔴 đề xuất của SA — `SAD §3.4` chưa chốt tần suất job cụ thể, xem `OQ-021`, `ASM-18` mới)* | Test giả lập webhook trễ/mất trên staging — **cần sandbox VNPay/Momo thật, hiện CHƯA có (`ARISK-03`)**; đo thời gian phát hiện qua log job đối soát | Must | + +--- + +## A4. `QAS` xung đột nhau + +| `QAS` A | `QAS` B | Xung đột ở đâu | Phương án cân bằng | Ai quyết | `ADR` | +|---|---|---|---|---|---| +| `QAS-010` (kiểm tra ownership mọi request `PATCH`/`DELETE /v1/cart/items`) | `QAS-003`/`QAS-004` (latency ≤500ms/≤300ms) | Mỗi lần kiểm tra ownership cần đối chiếu JWT/session với chủ sở hữu `CartItem` — nếu tra DB mỗi lần sẽ ăn vào ngân sách latency vốn đã eo hẹp (đề xuất) | Cache thông tin ownership/session trong Redis thay vì query DB mỗi request; đo lại `QAS-003`/`004` sau khi có thiết kế cụ thể | Tech Lead (quyết định thi công, không phải trade-off nghiệp vụ) | *(chưa có — sẽ chốt ở hoạt động `asr`/`adr` kế tiếp nếu cần)* | +| `QAS-005` (SQS FIFO per-seller message group, sustained ≥100 msg/s) | `QAS-009` (mở rộng tới kịch bản B, ~4,2 đơn/giây × ~5 event/đơn) | AWS giới hạn cứng throughput cho **một message group** SQS FIFO (không phải toàn hàng đợi) — nếu một seller có volume rất cao, event của riêng seller đó có thể chạm trần group dù tổng hệ thống chưa chạm 100 msg/s; đảm bảo **thứ tự xử lý đúng theo seller** (liên quan `DRV-06` — tính nhất quán dữ liệu tài chính) buộc serialize trong group đó | Cần quyết định ở `ADR` message backbone: chấp nhận rủi ro cho seller lớn (theo dõi + cảnh báo riêng), hay thiết kế sharding/batching cho seller volume cao | Tech Lead + PO (ảnh hưởng kiến trúc + rủi ro vận hành cho seller lớn) | *(chưa có — `ADR` message backbone thuộc hoạt động `asr`/`adr` kế tiếp, `POC-01` phải chạy trước khi chốt)* | + +--- + +# PHẦN B — Architecturally Significant Requirements + +## Ghi chú phạm vi — KHÔNG thực hiện ở lượt chạy này + +Theo yêu cầu điều phối ("Không tạo ASR/SAD/ADR ở lượt này"), Phần B **để trống có chủ đích**. +`sa-2-architecture` yêu cầu thứ tự bắt buộc 1 (`QAS`) → 2 (`ASR`) → 3 (`SAD`) — tài liệu này đã +hoàn thành đúng bước 1. Hoạt động `--focus asr` kế tiếp phải: + +- Rà toàn bộ 9 `DRV` ở `CTX §2` (chưa `DRV` nào có `ASR`/`QAS` phục vụ, theo `DTM §2` — 0/9, + "kỳ vọng đúng lúc này"). +- Rà 14 `QAS` Must ở Phần A trên — mọi `QAS` Must là ứng viên trực tiếp cho `ASR` (theo tiêu chí + B1 của template: *"có `QAS` mức Must đứng sau"*). +- Ứng viên `ASR` quan sát được trong lúc làm `QAS` (ghi lại để hoạt động `asr` không phải dò lại + từ đầu, **không phải `ASR` chính thức**): + - Ép hàng đợi bền + cơ chế đối soát bù cho xác nhận thanh toán bên thứ ba (`DRV-08`, `QAS-014`). + - Ép biên cô lập Payment Service (network/IAM riêng) cho PCI-DSS SAQ A (`CON-06`, đã có trong + `OPT` P2, chưa phải `ASR` chính thức). + - Ép ranh giới message group theo seller cho thông lượng/thứ tự sự kiện (`DRV-06`, `QAS-005`, + xung đột A4 dòng 2) — cần `ADR` message backbone. + - Ép rà soát PII trước khi chia sẻ cho seller (`DRV-07`, `QAS-011`) — cần người phụ trách + (`OQ-007` còn mở) trước khi có thể "Đã thiết kế". +- `DEC-06` (chọn P2) phải được nâng thành `ADR` chính thức ngay khi hoạt động `asr`/`adr` bắt đầu + (đã cảnh báo ở `DTM §11` "🟠 Nợ #1", radar ước lượng ~7 — **chưa đủ ngưỡng ≥8 bắt buộc POC** + nhưng `POC-01` vẫn cần chạy trước khi `Accepted` vì bản thân `ASM-07` chưa xác minh). + +--- + +## C. Đối chiếu với `NFR` của bộ BA + +| `NFR` của BA/SAD | Nội dung gốc | `QAS` tương ứng | Đã lượng hoá | Hành động | +|---|---|---|---|---| +| `NFR-01` (SAD) | Catalog/search <2s, checkout <3s | `QAS-001`, `QAS-002` | ✅ (số giữ nguyên, `Confidence` 🔴 vì chưa SLA) | Không đổi số — QAS tham chiếu đúng NFR-01, không có lệch | +| `NFR-02` (SAD) | Scale-out ngang, cache/CDN/MQ, hàng nghìn–chục nghìn concurrent | `QAS-005`, `QAS-006`, `QAS-009` | ✅ (cụ thể hoá thành 2 kịch bản A/B với số concurrent/throughput rõ) | Không lệch — là làm rõ thêm, không đổi ý nghĩa | +| `NFR-03` (SAD) | Uptime 99.9% dịch vụ giao dịch lõi | `QAS-007`, `QAS-008` | ✅ (thêm ngân sách lỗi 43 phút/tháng + RTO/RPO kế thừa) | Không lệch | +| `NFR-04` (SAD) | Bảo mật PII, MFA | `QAS-011`, `QAS-012` | ✅ (một phần — `THR` STRIDE đầy đủ chờ hoạt động `sec`) | Hoạt động `sec` kế tiếp bổ sung `THR-nn` | +| `NFR-05` (SAD) | PCI-DSS, NĐ52/85, NĐ13/2023 | `QAS-011` (một phần) | 🟡 Một phần | Phần PCI-DSS (biên cô lập Payment) chưa có `QAS` riêng — thuộc `SEC`/`ADR` hoạt động sau | +| `NFR-06` (SAD) | Đa ngôn ngữ 5 thứ tiếng | *(không có `QAS`)* | ❌ Không lượng hoá thành `QAS` | Đây là yêu cầu chức năng/UI (chiến lược i18n), không phải thuộc tính chất lượng đo bằng con số kiểu latency/throughput — sẽ thành `ASR` (ép chiến lược tách chuỗi hiển thị khỏi code) ở hoạt động `asr`, không phải `QAS` | +| `NFR-07` (SAD) | Bảo trì — kiến trúc module hoá | *(không có `QAS`, xem A1)* | ❌ N/A có lý do | Xem "Nhóm không áp dụng" A1 — chờ đội thi công thật (`OQ-010`) | +| `NFR-08` (SAD) | Vận hành — 3 môi trường, on-call 24/7 sự cố nghiêm trọng | `QAS-013` | ✅ | Không lệch | +| `NFR-PERF-01` (BA, `OQ-033`) | Ngưỡng `GET /v1/cart` — chưa chốt | `QAS-003` | 🟡 SA đề xuất 500ms | **`QAS` thắng `NFR`** — BA nên cập nhật `NFR_US002-003` §1 tham chiếu `QAS-003`, giữ `OQ-033` mở cho tới khi PO/Tech Lead xác nhận qua `OQ-018` | +| `NFR-PERF-02` (BA, `OQ-033`) | Ngưỡng `PATCH`/`DELETE /v1/cart/items` — chưa chốt | `QAS-004` | 🟡 SA đề xuất 300ms | Tương tự — BA cập nhật tham chiếu `QAS-004`, `OQ-019` | +| `NFR-SEC-01` (BA) | IDOR ownership check | `QAS-010` | ✅ Khớp hoàn toàn | Không lệch | +| `NFR-SEC-02` (BA) | Cookie Guest `HttpOnly/Secure/SameSite` | *(không có `QAS` — thuộc mô hình xác thực)* | — | Thuộc hoạt động `sec` (mô hình authn), không phải `QAS` số | +| `NFR-SEC-03` (BA) | Rate limit `PATCH`/`DELETE` Guest — "SAD định nghĩa" nhưng SAD cũng chưa có số cụ thể | *(chưa có `QAS`)* | ❌ Khoảng trống thật | Cần Tech Lead/Security chốt số cụ thể ở hoạt động `sec`/`icd` — ghi `OQ-023` | +| `NFR-AVL-01/02` (BA) | Banner lỗi khi Cart & Order Service lỗi/chậm | *(không có `QAS` — thuộc `FAIL`)* | — | Thuộc hoạt động `fail` (failure mode), không phải `QAS` | +| `NFR-AUD` (BA) | N/A cho `CartItem` | *(không áp dụng)* | ✅ Nhất quán | Không cần `QAS` | + +--- + +## D. Giả định & Ngoài phạm vi + +**Giả định** *(tiếp số toàn dự án — `ASM-01…15` đã dùng ở `CTX`/`OPT`/`TCO`, bắt đầu `ASM-16`)*: + +| ID | Giả định | Cách xác minh | Nếu sai thì `QAS` nào đổi | +|---|---|---|---| +| `ASM-16` | Giỏ hàng có tối đa ~50 dòng/giỏ (đề xuất BA `NFR-PERF-01`) đủ làm baseline đo `GET /v1/cart` | Đo phân phối số dòng/giỏ thật trong 4–6 tuần đầu soft-launch (cùng đợt với `DRV-02` `GOAL-01`) | `QAS-003` — giỏ lớn hơn nhiều lần có thể cần phân trang/lazy-load, đổi cả ngưỡng latency lẫn thiết kế API | +| `ASM-17` | Cửa sổ bảo trì có báo trước ≤ 2 giờ/tháng được loại khỏi ngân sách lỗi 99.9% | PO xác nhận chính sách bảo trì (`OQ-020`) | `QAS-007` — nếu PO không chấp nhận loại trừ, ngân sách lỗi thực tế hẹp hơn 43 phút/tháng | +| `ASM-18` | Job đối soát thanh toán chạy đủ nhanh (đề xuất ≤15 phút) để phát hiện lệch trạng thái trước khi ảnh hưởng đáng kể tới CSKH | Tech Lead xác nhận tần suất job thật (`OQ-021`), đo lại sau khi có sandbox VNPay/Momo | `QAS-014` — tần suất chậm hơn thực tế cần thiết kế lại (webhook + polling kết hợp, hoặc rút ngắn chu kỳ) | + +*`ASM-01…15` của `CTX`/`OPT`/`TCO` (đặc biệt `ASM-07` → `QAS-005`, `ASM-08` → `QAS-006`, +`ASM-10` → `QAS-009`, `ASM-04` → residency liên quan `QAS-011`) vẫn áp dụng nguyên trạng — không +lặp lại nội dung, chỉ tham chiếu theo `artifact-map.md §7`.* + +**Ngoài phạm vi:** + +- `ASR`/`SAD`/`ADR`/`ICD`/`DAT`/`SEC`/`INF`/`FAIL` — chưa thực hiện ở lượt chạy này (chỉ hoạt + động `qas`), theo đúng yêu cầu điều phối. Xem Phần B để biết ứng viên `ASR` đã quan sát được. +- Kiến trúc này (P2, chưa `Accepted` bằng `ADR`) không nhắm tới tải vượt kịch bản B (10.000 + concurrent) **×2** (~20.000 concurrent) mà chưa kiểm chứng lại bằng `POC`/bài đo thật — ngưỡng + phải xét lại nếu traffic thật sau go-live tiệm cận mức này. +- `NFR-06` (i18n)/`NFR-07` (bảo trì qua module hoá) không được lượng hoá thành `QAS` số — xử lý + qua `ASR` (chiến lược i18n) và bằng cách đánh dấu N/A có lý do (bảo trì), không phải bỏ sót. +- `QAS-008` (RTO/RPO) và ngưỡng cảnh báo ở `QAS-013` **kế thừa nguyên trạng** từ `SAD §5.3.2/ + §9.4.1/§9.5.2` — SA **không** thiết kế lại HA/DR/observability ở lượt này (đó là hoạt động + `inf`, chưa chạy); chỉ ghi lại để nhóm Sẵn sàng/Quan sát được của `QAS` đầy đủ theo template. + +## E. Open Questions + +*Tiếp số sổ SA (`00-index/OQ_e-commerce.md` đang ở `OQ-017`) — bắt đầu `OQ-018`.* + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược | +|---|---|---|---|---|---| +| `OQ-018` | Ngưỡng p95 cho `GET /v1/cart` là bao nhiêu? SA đề xuất ≤500ms (nối `OQ-033` của BA). | PO + Tech Lead | 2026-09-14 | `QAS-003` baseline; bài đo `FIT` ở GĐ3 | Nếu PO/Tech Lead muốn ngưỡng chặt hơn (VD ≤200ms): có thể cần thiết kế cache Redis mạnh hơn hoặc bỏ bớt dữ liệu trả về (VD ảnh sản phẩm rút gọn); nếu lỏng hơn (VD ≤1s): giảm áp lực thiết kế cache, nhưng tăng rủi ro trải nghiệm kém ở `DRV-02` (bỏ giỏ) | +| `OQ-019` | Ngưỡng p95 cho `PATCH`/`DELETE /v1/cart/items` là bao nhiêu? SA đề xuất ≤300ms (nối `OQ-033` của BA). | PO + Tech Lead | 2026-09-14 | `QAS-004` baseline; bài đo `FIT` ở GĐ3 | Tương tự `OQ-018` — ngưỡng chặt hơn cần tối ưu ghi (VD giảm số lần round-trip DB); ngưỡng lỏng hơn giảm áp lực thiết kế | +| `OQ-020` | Cửa sổ bảo trì có báo trước (nếu có) được loại trừ khỏi ngân sách lỗi 99.9%/tháng là bao nhiêu giờ? SA đề xuất ≤2 giờ/tháng. | PO | 2026-09-14 | `QAS-007` (ngân sách lỗi thật); chính sách release ở `INF` (chưa chạy) | Nếu PO không chấp nhận loại trừ nào: ngân sách lỗi thực tế thu hẹp còn đúng 43 phút/tháng kể cả bảo trì có kế hoạch — cần chiến lược blue-green/zero-downtime deploy nghiêm ngặt hơn, tăng chi phí vận hành | +| `OQ-021` | Tần suất chạy job đối soát thanh toán (reconciliation) là bao nhiêu? SA đề xuất ≤15 phút/lần. | Tech Lead | 2026-09-14 | `QAS-014`; thiết kế job đối soát ở `DAT`/`INF` (chưa chạy) | Nếu tần suất thật thưa hơn (VD hàng giờ): thời gian phát hiện đơn kẹt "chờ thanh toán" lâu hơn, tăng rủi ro khiếu nại CSKH (`DRV-08`, `RISK-02` của BA) | +| `OQ-022` | Lịch diễn tập DR (failover drill) đầu tiên cho nhóm service giao dịch cốt lõi là khi nào? **Đã chốt điều kiện (sign 2026-09-14, `DEC-12`): phải thực hiện TRƯỚC khi ký AG2** — ngày/lịch cụ thể vẫn chờ Ops/SRE. | Ops/SRE | 2026-09-14 | `QAS-008` (nâng `Confidence` từ 🔴); điều kiện tiên quyết ký AG2 (đã ghi vào điều kiện AG2, xem header) | Nếu không diễn tập trước AG2: Ops/SRE từ chối ký AG2 (theo `workflow.md §2` AG2 — "Chặn: RTO/RPO chưa diễn tập"), phải lùi gate — điều kiện này nay là bắt buộc, không còn là lựa chọn "ký có điều kiện kèm ARISK mới" | +| `OQ-023` | Ngưỡng rate limit cụ thể (số request/phút theo IP) cho `PATCH`/`DELETE /v1/cart/items` của Guest là bao nhiêu? `NFR-SEC-03` của BA ghi "SAD định nghĩa" nhưng SAD cũng chưa có số. | Tech Lead + Security | 2026-09-14 | Hoạt động `sec`/`icd` kế tiếp; `NFR-SEC-03` của BA | Không có ngưỡng ⇒ rủi ro lạm dụng API (spam thêm/xoá giỏ hàng) không bị chặn — cần Security chấp nhận rủi ro tạm thời nếu chưa chốt được số trước go-live | + +**Nhắc:** cộng với `OQ-010` (kinh nghiệm team thật — ảnh hưởng gián tiếp `QAS-005`/`ASM-05` mới +tương tự `ARISK-05`) và `OQ-012` (thời điểm chạy `POC-01`, đã đóng có điều kiện — POC phải chạy +trước `ADR` message backbone) còn mở từ GĐ1, xem sổ đầy đủ `00-index/OQ_e-commerce.md`. diff --git a/sa-output/e-commerce/02-architecture/SAD_e-commerce_v1.0.md b/sa-output/e-commerce/02-architecture/SAD_e-commerce_v1.0.md new file mode 100644 index 0000000..7dbb31c --- /dev/null +++ b/sa-output/e-commerce/02-architecture/SAD_e-commerce_v1.0.md @@ -0,0 +1,705 @@ +# SAD — Solution Architecture Document — e-commerce + +| | | +|---|---| +| **Version** | 1.3 | +| **Date** | 2026-09-15 | +| **Author** | SA (skill sa-2-architecture, chế độ `go`, hoạt động `sad`) | +| **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 C4 Context/Container/Component (Cart & Order), deployment view, bảng `CMP-01…15`, ma trận `ASR→CMP` đủ 15/15, 17 `IF-nn` ứng viên cho `ICD` *(sửa từ số đếm sai "22" ở v1.2 — xem `OQ-029`, `ICD §0.1`, Change Log v1.2)*, 12 chỗ chờ `ADR-001…012` (không `ADR` nào được viết ở lượt này). Chốt **TẠM** `OQ-026` (P2 có 2 ECS Fargate service riêng — Nhóm Giao dịch/Nhóm Hỗ trợ — để scale độc lập, `TCO §3.2` giữ nguyên tới khi hoạt động `inf` xác nhận, theo `ASM-23`) và `OQ-027` (Identity & Access thuộc Nhóm Giao dịch, theo `ASM-22`) làm hướng đi tạm cho hoạt động `icd`/`dat`/`sec`/`inf`/`fail` kế tiếp — **`OQ-026`/`OQ-027` giữ nguyên MỞ**, chờ Tech Lead/Ops thật xác nhận, không coi là đã đóng. Ký thay Tech Lead theo ngoại lệ `DEC-01` (SA) — **không phải chữ ký Tech Lead thật**. · 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ì `ICD`/`DAT`/`SEC`/`INF`/`FAIL` (hoạt động 4–8) và mọi `ADR` (hoạt động 9) chưa chạy. `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-16`. **Lưu ý v1.2 (2026-09-15):** §4/§6/§7 vừa được sửa lỗi nhất quán (phân loại +`IF-021` cross-network, đếm lại `IF-nn` 22→17) theo yêu cầu người duyệt và phát hiện của `ICD` +(`OQ-028`/`OQ-029`) — đây là sửa lỗi tài liệu, **không phải** nội dung kiến trúc mới; chữ ký nêu +trên chỉ áp dụng cho nội dung **trước khi sửa**, §4/§6/§7 bản v1.2 **chưa được Tech Lead/Security/ +Ops ký lại**. **Lưu ý v1.3 (2026-09-15):** §6.1 (sequence checkout) và §8 (bảng ADR) vừa được sửa +theo `ADR-013` (`Proposed`, bất đồng bộ hoá bước khởi tạo thanh toán — quyết định Lựa chọn B của +`OQ-034`/`DEC-22`) — đây **là** nội dung kiến trúc mới (đổi luồng checkout đồng bộ→có nhánh bất +đồng bộ), **không phải** sửa lỗi tài liệu như v1.2; chữ ký nêu trên **không** áp dụng cho §6.1/§8 +bản v1.3 — cần Tech Lead + PO **thật** xác nhận `ADR-013` trước khi coi §6.1/§8 là đã duyệt. | +| **Source** | `02-architecture/ASR_e-commerce_v1.0.md` v1.0 (toàn bộ `ASR-001…015`, §B2, §D) · `02-architecture/QAS_e-commerce_v1.0.md` v1.0 (§A3, §A4 xung đột) · `01-context/OPT_e-commerce_v1.0.md` §1, §3 (P2), §9 · `01-context/CTX_e-commerce_v1.0.md` §2 (`DRV`), §3 (`CON`), §4.2 (đối tác ngoài) · `01-context/TCO_e-commerce_v1.0.md` §3.2 (P2, kịch bản A/B) · `01-context/ARISK_e-commerce_v1.0.md` §3, §6 (`POC-01/02`) · `02-architecture/FAIL_e-commerce_v1.0.md` v1.1 §1.2 (ngân sách timeout, phát hiện vượt `QAS-002`) · `02-architecture/adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md` (mới, `Proposed`) · `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/PROCESS_CartCheckout_v1.0.md` (luồng B1–B9) · `ba-output/e-commerce/02-analysis/IMPACT_CartCheckout_v1.0.md` §1.5 (tích hợp) · `ba-output/e-commerce/03-specification/API_US002-003_v1.0.md` (contract đề xuất Cart) · `e-commerce/docs/sections/03-kien-truc.md` §3.1 (**chỉ tái dùng danh sách module/domain và tích hợp ngoài — KHÔNG kế thừa kiểu kiến trúc ~10 microservices, đó là P1 đã bị loại ở `OPT §5`**) · `e-commerce/docs/sections/04-api-design.md` §4.1 (danh sách endpoint tham khảo) | +| **Scope** | Toàn sàn e-commerce theo phương án **P2** (modular monolith + managed AWS, tách riêng Payment Service — `DEC-06`/`ASR-001`, **chưa** có `ADR-001` chính thức, xem §8). Chi tiết nhất: module **Giỏ hàng & Checkout** (US-002/003, `BR-CART-01…09`, `RBAC` `ROLE-01/02`). Đây là hoạt động 3/9 của `sa-2-architecture` — **không** viết `ADR`/`ICD`/`DAT`/`SEC`/`INF`/`FAIL` ở lượt này; đánh dấu rõ chỗ chờ từng hoạt động đó. | +| **Confidence** | 🔴 Giả định chưa xác minh — theo yêu cầu điều phối, tiếp nối `Confidence` 🔴 của `QAS`/`ASR`. AG1 chưa có chữ ký PO/Tech Lead thật (`OQ-004` mở); `POC-01`/`POC-02` chưa chạy; `ADR-001` (kiểu kiến trúc tổng thể) chưa tồn tại — tài liệu này **giả định trước** kết luận của `ADR-001` (P2) để có thể vẽ C4, đúng theo hướng đã duyệt từng phần ở `DEC-06`/`DEC-14`, nhưng bản thân quyết định đó vẫn `Proposed`, chưa `Accepted`. Mọi con số hạ tầng ở §7 kế thừa `TCO §3.2` nguyên trạng — không tự đổi khi phát hiện lệch (xem `OQ-026`). | + +## Change Log + +| Version | Date | Người sửa | Thay đổi | ADR | +|---|---|---|---|---| +| 1.0 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `sad`) | Bản đầu — hoạt động 3/9 của `sa-2-architecture`. Dựng C4 Context (4 actor + 5 hệ ngoài), C4 Container (Mermaid, legend theo `D4`), C4 Component cho container "Nhóm Giao dịch" (chi tiết Cart & Order — đúng yêu cầu "chi tiết nhất cho Giỏ hàng & Checkout"), 2 sequence diagram (Checkout, Webhook thanh toán + đối soát), deployment view AWS `ap-southeast-1` đối chiếu `TCO §3.2` (phát hiện 1 điểm lệch mức chi tiết — ghi `OQ-026`, không tự đổi số `TCO`). Bảng `CMP-01…15` (15 component, ma trận `ASR-001…015` × `CMP` đủ 15/15, không CMP mồ côi), danh sách 17 `IF-nn` ứng viên cho `ICD` (hoạt động 4) *(số gốc "22" là đếm nhầm — sửa ở v1.2, xem `OQ-029`)*, bảng thực thể dữ liệu sở hữu ứng viên cho `DAT` (hoạt động 5), bảng phụ thuộc vượt ranh giới process ứng viên cho `FAIL` (hoạt động 8). Đánh dấu 12 chỗ chờ `ADR-001…012` (không viết `ADR` nào — đúng yêu cầu điều phối). Không sửa `QAS`/`ASR` đã duyệt từng phần. Thêm `OQ-026/027`, `ASM-22/23`. Ghi `DEC-15` (tiếp nối `DEC-01…14`, ngoại lệ gate tiếp tục GĐ2 hoạt động `sad`). `Confidence` 🔴 toàn bộ. | — *(chưa viết ADR)* | +| 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 C4 Context/Container/Component, deployment view, bảng `CMP-01…15`, ma trận `ASR→CMP` đủ 15/15, 17 `IF-nn` ứng viên *(sửa từ "22" ở v1.2 — xem `OQ-029`)*, 12 chỗ chờ `ADR`. Chốt **TẠM** `OQ-026` (2 ECS Fargate service riêng theo Nhóm Giao dịch/Nhóm Hỗ trợ, `TCO §3.2` giữ nguyên tới khi `inf` xác nhận, `ASM-23`) và `OQ-027` (Identity & Access thuộc Nhóm Giao dịch, `ASM-22`) làm hướng đi tạm — cả hai **giữ nguyên mở**, chờ Tech Lead/Ops thật xác nhận. Không đổi nội dung chuyên môn. Security/Ops chưa ký; `OQ-004` mở; `Confidence` giữ 🔴; Status giữ 🟡 Draft; AG2 **chưa** ký. Ghi thêm `DEC-16`. | `DEC-16` | +| 1.1 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `adr`) | **Chỉ cập nhật §8** (bảng "Quyết định kiến trúc đã ghi") — thay cột "*Chưa viết*" bằng đường dẫn file thật của 12 `ADR-001…012` vừa được viết (tất cả `Status: Proposed`, radar/điều kiện POC giữ nguyên không đổi so với bảng ứng viên đã duyệt từng phần ở `DEC-14`/`DEC-16`). Không sửa bất kỳ nội dung chuyên môn nào khác của `SAD` (C4, `CMP`, deployment view, `OQ`, `ASM` giữ nguyên như v1.0, đã qua duyệt từng phần `DEC-16`). Ghi thêm `DEC-17`. `Confidence` giữ 🔴 — việc link file không phải bằng chứng nguồn mới. | `DEC-17` | +| 1.2 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `sad`) | **Sửa nhất quán theo phát hiện `ICD` (`OQ-028`/`OQ-029`), người duyệt yêu cầu 2026-09-15** — sửa lỗi tài liệu, không tạo nội dung kiến trúc mới, không đổi `CMP`. (1) `IF-021` (Cart&Order → Promotion&Loyalty): sửa mọi mô tả từ "internal call cùng process" thành **cross-network REST giữa 2 ECS Fargate service riêng** (Nhóm Giao dịch ↔ Nhóm Hỗ trợ, theo `OQ-026`/`ASM-23` và `OQ-028`/`ASM-24` đã chốt TẠM ở `ICD`) — sửa ở legend §4, thêm footnote §4.1, bảng bước §6.1, bảng phụ thuộc §6.3, bổ sung cạnh mạng còn thiếu `ECSGD`↔`ECSHT` ở §7 (đánh dấu 🔴 chờ `inf` thiết kế đường kết nối thật). Rà theo cùng nguyên tắc cho mọi `IF` khác: `IF-022` (Cart&Order ↔ Seller Management, cũng GD↔HT) trước đây không có nhãn loại — nay ghi rõ **cũng cross-network** (không phải "đổi loại", chỉ làm rõ vì trước đó chưa từng gán nhãn "internal"); `IF-005` (trong Nhóm Giao dịch) giữ **in-process** (không đổi, đúng từ trước); `IF-006` (Cart&Order→Payment) giữ **cross-network** (không đổi, đúng từ trước). Không `IF` nào khác đổi loại. (2) Đếm lại `IF-nn`: đối chiếu toàn bộ sơ đồ Context/Container/Component (§3/§4/§5) với bảng `CMP-nn` (§4.1) và bảng phụ thuộc (§6.3) — chỉ **17 ID** thực sự xuất hiện (`IF-001…009, 015…022`), không có `IF-010…014` ở bất kỳ đâu, không có mũi tên nào thiếu ID → **kết luận: con số "22" là đếm nhầm ở bản gốc, không phải bỏ sót interface**. Sửa "22"→"17" ở header (`Approved by`), Change Log v1.0/v1.0-sign, `§Tự chấm` (D5, đoạn Nhắc cuối) — nội dung chuyên môn (17 `IF-nn`, `CMP`, ma trận `ASR×CMP`) không đổi, chỉ sửa số đếm sai. Đóng `OQ-029` trong sổ `00-index/OQ_e-commerce.md` với kết luận trên. `OQ-028` **giữ nguyên mở** (SAD nay đã hết mâu thuẫn nội bộ, vẫn chờ Tech Lead thật xác nhận ranh giới mạng). Không sửa §8 (`ADR` links), không sửa `ASR`/`QAS`/`ADR`/`ICD`. Ghi ngoại lệ tiếp tục gate ở `DEC-20` (`00-index/DEC_e-commerce.md`), tiếp nối `DEC-01…19`. `Confidence` giữ 🔴; Status giữ 🟡 Draft; §4/§6/§7 v1.2 **chưa được Tech Lead/Security/Ops ký lại**. | — | +| 1.3 | 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` (bất đồng bộ hoá bước khởi tạo thanh toán VNPay/Momo trong `POST /v1/checkout`). **Đây là nội dung kiến trúc mới, không phải sửa lỗi tài liệu như v1.2.** (1) §6.1: sequence diagram checkout chèn nhánh rẽ theo phương thức thanh toán — COD giữ nguyên luồng đồng bộ cũ; VNPay/Momo dừng đường găng đồng bộ ngay sau khi commit TX Order (bước ghi `Order`/`OrderSeller`/`OrderItem`), trả response `201` với `orderId` + `status: PENDING_PAYMENT_INIT` (chưa có `redirectUrl`), việc gọi VNPay/Momo chuyển thành bất đồng bộ qua message `PaymentInitRequested` (tái dùng message backbone `ADR-005`) — Payment Service consume, gọi gateway, publish `PaymentInitReady`/`PaymentInitFailed`; thêm chú thích tham chiếu `ADR-013` ngay dưới sơ đồ và cập nhật bảng bước kèm theo. (2) §8: thêm dòng `ADR-013` vào bảng "Quyết định kiến trúc đã ghi" (Status `Proposed`, radar 7, không bắt buộc POC vì dưới ngưỡng 8, chờ Tech Lead + PO thật xác nhận). Không sửa nội dung khác của `SAD` (C4 §3–§5, `CMP` §4.1, deployment view §7, §9, §10, §11 giữ nguyên như v1.2) — đúng phạm vi được giao. `OQ-034` cập nhật trạng thái "đã có `ADR-013`, chờ Tech Lead/PO thật xác nhận" trong sổ `00-index/OQ_e-commerce.md`. Thêm `OQ-041`, `OQ-042` (mới, từ `ADR-013`). 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; §6.1/§8 bản v1.3 **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). +> 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 phải 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 được ký chính thức** và **AG2 (gate của chính GĐ2) càng chưa tới hạn** — tài liệu +này là hoạt động 3/9 của `sa-2-architecture`. Theo đúng thứ tự bắt buộc của `SKILL.md` ("1→2→3 +bắt buộc trước; 4–8 chạy song song được"): hoạt động 1 (`QAS`) và hoạt động 2 (`ASR`) đã hoàn tất +và được duyệt từng phần (`DEC-12`, `DEC-14`) — điều kiện đầu vào cho `sad` đã đủ. + +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** +sang hoạt động 3 (`SAD`). Quyết định ngoại lệ này được ghi tại `DEC-15` dưới đây và tại sổ +`00-index/DEC_e-commerce.md`. + +> **DEC-15 (SA)** — Tiếp tục `sa-2-architecture` (hoạt động 3 — `SAD`) cho e-commerce trong khi +> AG1 chưa có chữ ký PO/Tech Lead thật và AG2 (gate của chính GĐ2) chưa tới hạn — tiếp nối +> `DEC-01…14`. +> **Quyết định:** Dựng `SAD` (C4 Context/Container/Component, deployment view, bảng `CMP-nn`, +> ma trận `ASR×CMP`) dựa trên hướng kiến trúc P2 đã duyệt từng phần (`DEC-06`/`DEC-14`), giữ +> `Confidence 🔴` cho tới khi: (a) AG1 ký thật, (b) `ADR-001` (kiểu kiến trúc tổng thể) được viết +> và `Accepted`, (c) `POC-01`/`POC-02` chạy xong, (d) `OQ-010` (số đội thật, ảnh hưởng ranh giới +> nhóm triển khai `ASR-014`) được trả lời. +> **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 (bản vẽ C4 sửa lại khi `ADR-001` đổi hướng +> không tốn nhiều so với đã code) · bán kính ảnh hưởng: hoạt động `icd`/`dat`/`sec`/`inf`/`fail` +> kế tiếp phụ thuộc `SAD` này, nhưng bản thân *việc ghi tài liệu dưới ngoại lệ* thì nhỏ · có chạm +> `QAS`/`ASR` Must trực tiếp (đang hiện thực hoá chúng thành component) nhưng chưa phải cam kết +> thi công (chưa `ADR` nào `Accepted`) · không ràng buộc dài hạn tự thân (văn bản `SAD` sửa được +> qua version mới, khác `ADR` bất biến) · không tranh cãi mới, tiếp nối tiền lệ `DEC-11…14` → +> **ghi `DEC-nn`, không cần `ADR` cho việc chạy dưới ngoại lệ** (`decision-radar.md §1–§2`). +> **Hệ quả nếu không chấp nhận ngoại lệ:** dừng GĐ2 ở hoạt động `asr`, không có `SAD` để hoạt +> động `icd`/`dat`/`sec`/`inf`/`fail` (hoạt động 4–8) dùng làm đầu vào — chậm tiến độ chạy thử +> tương ứng thời gian xử lý các `OQ` đang mở, đặc biệt `OQ-010` (ảnh hưởng trực tiếp §4.1/§7). + +**Cập nhật v1.2 (2026-09-15):** Người duyệt yêu cầu sửa lỗi nhất quán phát hiện bởi hoạt động +`icd` (`OQ-028`/`OQ-029`) — đây là sửa lỗi tài liệu, **không phải** quyết định kiến trúc mới, không +cần `ADR`. Người dùng (vai điều phối dự án chạy thử) đã được cảnh báo lại AG1/AG2 vẫn chưa qua và +**khẳng định muốn tiếp tục**. Ghi ngoại lệ tiếp tục tại `DEC-20` (`00-index/DEC_e-commerce.md`), +tiếp nối `DEC-01…19`. + +🔴 **Nhắc quan trọng:** `ADR`, `ICD`, `DAT`, `SEC`, `INF`, `FAIL` **chưa được tạo**. Tài liệu này +đánh dấu rõ 12 chỗ chờ `ADR-001…012` (§8) và ghi ứng viên `IF-nn` (§4.1, §6.3), thực thể dữ liệu +sở hữu (§4.1, cho `DAT`), phụ thuộc cần `FAIL` (§6.3) — để các hoạt động kế tiếp không phải dò +lại từ đầu, **không thay thế** các hoạt động đó. + +--- + +## 1. Tóm tắt cho người quyết định + +| | | +|---|---| +| **Kiểu kiến trúc** | Modular monolith theo domain, chạy trên AWS managed service (ECS Fargate), **tách riêng duy nhất Payment Service** (mạng/IAM/DB riêng) — phương án **P2** của `OPT`, chưa có `ADR-001` chính thức (vẫn `Proposed`, xem §8) | +| **Quyết định lớn nhất** | `ADR-001` — Modular Monolith P2 thay vì ~10 microservices (P1, đã loại ở `OPT §5`); radar ước lượng ~7, cần `POC-01`/`POC-02` trước khi `Accepted` | +| **Rủi ro kiến trúc lớn nhất** | `ARISK-01`/`ARISK-02` (SQS/EventBridge và RDS gộp chưa đo throughput thật) — chặn trực tiếp `ADR-005`/`ADR-006` (radar ≥8, xem `ASR-005`/`ASR-006`) | +| **Cái này KHÔNG làm được** | Scale-out **độc lập** Catalog/Search khỏi Cart/Checkout ngay từ ngày một (thua P1 đúng 1 bậc ở `OPT §4`); chưa dùng OpenSearch (hoãn, dùng Postgres FTS); chưa tách ranh giới ECS chi tiết theo "Nhóm giao dịch"/"Nhóm hỗ trợ" trong `TCO` (xem `OQ-026`) | + +--- + +## 2. Kiểu kiến trúc và lý do + +Quyết định ở `ADR-001` (chưa viết — xem §8). Tóm tắt lý do gắn với `ASR`/`CON`: + +| Tín hiệu trong dự án này | Nghiêng về | Kết luận | +|---|---|---| +| `CON-05` (số đội thi công chưa xác nhận thật, giả định tạm "team MVP chuẩn" `DEC-02`, hồ sơ thầu BE trung bình ~2,6 FTE/tháng) so với ~10 service độc lập của P1 | Modular monolith — mỗi BE ôm 3–4 service ở P1 vi phạm Conway rõ (`OPT §4` tiêu chí 5: P1=2, P2=5) | Giữ P2 — 2–3 nhóm triển khai thay vì ~10 | +| `ASR-001`/`ASR-014` (tải lệch Catalog/Cart&Order so với nhóm hỗ trợ, cần scale nhanh hơn) | Tách logic thành ≥2 nhóm triển khai trong cùng monolith thay vì 1 khối duy nhất | 2 nhóm container logic: "Nhóm Giao dịch" và "Nhóm Hỗ trợ" (§4.1) + Payment tách biệt | +| `CON-05`/`OQ-010` (chưa xác nhận đội thi công thật từng vận hành Kafka/MSK/OpenSearch/EKS production) | Managed service đơn giản hơn (SQS/EventBridge, ECS Fargate, RDS) thay vì tự vận hành cluster | Loại Kafka/MSK/OpenSearch cho MVP — dùng SQS FIFO + EventBridge (`ASR-005`) và Postgres FTS giai đoạn đầu | +| `CON-06` (PCI-DSS SAQ A, không thương lượng) | Payment phải là ranh giới mạng/IAM/DB riêng bất kể chọn monolith hay microservices | Payment Service tách hoàn toàn (`ASR-002`) — quyết định này **không phụ thuộc** việc chọn P1 hay P2 | + +🔴 **Modular monolith là mặc định hợp lý** cho ≤2 team và ranh giới nghiệp vụ chưa ổn định — ở +đây team thi công thật **chưa được Tech Lead xác nhận** (`OQ-010` còn mở); ranh giới 2 nhóm logic +dưới đây (`ASR-014`) dựa trên giả định team `DEC-02`, phải rà lại khi có số thật. + +--- + +## 3. C4 — Mức 1: System Context + +*Mức: **C4 Context**. Ai dùng hệ thống, hệ thống nói chuyện với cái gì bên ngoài. Không có chi +tiết bên trong.* + +```mermaid +flowchart LR + Guest(["○ Guest\n(chưa đăng nhập)"]) + Customer(["○ Customer"]) + Seller(["○ Seller"]) + Admin(["○ Admin\n(bắt buộc MFA — ASR-009)"]) + + subgraph SYS["▭ Sàn e-commerce — P2: Modular Monolith + managed AWS, Payment tách riêng"] + PLATFORM["Nền tảng e-commerce\n(Identity · Catalog · Cart&Order · Seller · Commission ·\nPromotion&Loyalty · Review · Notification · Shipping · Payment)"] + end + + VNPay["▱ VNPay\n(cổng thanh toán)"] + Momo["▱ Momo\n(cổng thanh toán)"] + GHN["▱ GHN\n(vận chuyển)"] + GHTK["▱ GHTK\n(vận chuyển, fallback GHN)"] + EmailSMS["▱ Email/SMS Provider\n(nhà cung cấp chưa chốt — CTX §4.2)"] + + Guest -->|"1 · HTTPS REST, sync"| PLATFORM + Customer -->|"1 · HTTPS REST, sync"| PLATFORM + Seller -->|"1 · HTTPS REST, sync"| PLATFORM + Admin -->|"1 · HTTPS REST, sync"| PLATFORM + + PLATFORM -->|"2 · REST (init) sync + Webhook IPN async"| VNPay + PLATFORM -->|"2 · REST (init) sync + Webhook IPN async"| Momo + PLATFORM -->|"3 · REST (tạo/tra vận đơn) sync + Webhook async"| GHN + PLATFORM -->|"3 · REST sync + Webhook async, fallback GHN"| GHTK + PLATFORM -->|"4 · REST/SDK qua queue, async"| EmailSMS +``` + +**Legend:** ▭ hệ thống của ta · ▱ hệ thống ngoài · ○ người dùng · ──▶ nhãn số + giao thức + sync/async ghi trên mũi tên. + +| Thực thể ngoài | Vai trò | Ai sở hữu | Giao thức | SLA của họ | `IF-nnn` ứng viên | +|---|---|---|---|---|---| +| VNPay | Cổng thanh toán online (redirect + IPN), không lưu thẻ | VNPay (bên thứ ba) | REST/HTTPS, timeout đề xuất 10s (kế thừa `CTX §4.2`, **chưa kiểm chứng sandbox thật**) | 🔴 Chưa xác nhận (`CON-04`) | `IF-007` | +| Momo | Tương tự VNPay | Momo (bên thứ ba) | REST/HTTPS, timeout đề xuất 10s | 🔴 Chưa xác nhận (`CON-04`) | `IF-008` | +| GHN | Tạo vận đơn, tra cứu trạng thái, webhook | GHN (bên thứ ba) | REST/HTTPS, timeout đề xuất 8s | 🔴 Chưa xác nhận (`CON-04`) | `IF-018` | +| GHTK | Tương tự GHN, fallback chéo khi GHN lỗi (`ASR-013`) | GHTK (bên thứ ba) | REST/HTTPS, timeout đề xuất 8s | 🔴 Chưa xác nhận (`CON-04`) | `IF-019` | +| Email/SMS Provider | Thông báo đơn hàng/giao hàng, đa ngôn ngữ | Chưa chọn (`SAD.md §3.4` tự ghi "chưa chốt"; 🔴🔴 mức chưa sẵn sàng cao nhất theo `CTX §4.2`) | REST/HTTPS hoặc SDK qua queue, timeout đề xuất 5s | Chưa có nhà cung cấp | `IF-020` | + +*Ngoài phạm vi Context này (đã ghi ở `CTX §4.2`, không lặp lại chi tiết): Google/Facebook OAuth +(Should, `DRV` không có — không chặn MVU vì email/password vẫn hoạt động độc lập); ngân hàng +payout (COD/hoa hồng, luồng nội bộ tài chính, không phải điểm tích hợp giao dịch của Cart & +Checkout). Không vẽ vào Context vì không thuộc phạm vi bắt buộc của ghi chú người duyệt.* + +--- + +## 4. C4 — Mức 2: Container + +*Mức: **C4 Container**. Các khối chạy được và triển khai được. Đây là sơ đồ dev dùng nhiều nhất.* + +```mermaid +flowchart TB + WebApp["Web/Mobile Client\n(Guest/Customer/Seller/Admin)"] + + ALB["ALB / API Gateway\n(WAF gắn kèm — TCO §3.2)"] + + subgraph MONO["Modular Monolith — ECS Fargate (P2)"] + GD["Nhóm Giao dịch\n(Identity&Access · Catalog&Inventory ·\nCart&Order + Dispute)"] + HT["Nhóm Hỗ trợ\n(Seller Mgmt · Commission&Payout ·\nPromotion&Loyalty · Review · Notification ·\nShipping&Fulfillment)"] + end + + PAY["Payment Service\n(mạng/IAM riêng — ASR-002)"] + + BUS[("SQS FIFO (group=seller_id)\n+ EventBridge — ASR-005")] + RDS[("RDS PostgreSQL Multi-AZ chính\nschema-per-module — ASR-006")] + RDSPAY[("RDS PostgreSQL riêng\nchỉ Payment — ASR-002")] + REDIS[("ElastiCache Redis\ncache/session/ownership")] + S3CF[("S3 + CloudFront\nasset/ảnh sản phẩm/KYC")] + + VNPay["VNPay"] + Momo["Momo"] + GHN["GHN"] + GHTK["GHTK"] + EmailSMS["Email/SMS Provider"] + + WebApp -->|"1 · HTTPS REST, sync"| ALB + ALB -->|"2 · REST, sync"| GD + ALB -->|"3 · REST, sync"| HT + ALB -->|"4 · REST, sync, cô lập mạng"| PAY + GD -->|"5 · SQL, sync"| RDS + HT -->|"5 · SQL, sync"| RDS + PAY -->|"6 · SQL, sync"| RDSPAY + GD -->|"7 · cache/session, sync"| REDIS + GD -->|"8 · publish OrderPlaced, async"| BUS + PAY -->|"8b · publish PaymentConfirmed, async"| BUS + BUS -->|"9 · consume, async"| HT + GD -->|"10 · asset, sync"| S3CF + GD -->|"11 · REST, sync — áp dụng coupon/điểm (OQ mới BA §OQ-017)"| HT + PAY -->|"12 · REST sync (init) + webhook async"| VNPay + PAY -->|"12 · REST sync (init) + webhook async"| Momo + HT -->|"13 · REST sync + webhook async"| GHN + HT -->|"13 · REST sync + webhook async, fallback"| GHTK + HT -->|"14 · SDK/queue, async"| EmailSMS +``` + +**Legend:** ▭ container ta sở hữu · hình trụ = data store · nhãn số + giao thức + sync/async +bắt buộc trên mọi mũi tên (`D4`) · mũi tên "11" (Cart&Order → Promotion&Loyalty, `IF-021`) **là +cross-network REST** — Nhóm Giao dịch và Nhóm Hỗ trợ là **2 ECS Fargate service riêng** (theo +`OQ-026`/`ASM-23` đã chốt TẠM), không phải cùng process. + +🔴 **Sửa v1.2:** bản trước (v1.0/v1.1) ghi nhầm mũi tên "11" là "internal call trong cùng +process/network boundary" — mâu thuẫn trực tiếp với `OQ-026` (2 nhóm ECS riêng) đã chốt TẠM ngay +trong cùng tài liệu. Phát hiện bởi `ICD §0`/`OQ-028` (`ASM-24`). Timeout/fallback cụ thể **chưa +chốt** — ứng viên `FAIL` có mức ưu tiên cao hơn vì nay là cross-network call nằm trong đường găng +checkout (ngân sách `QAS-002` ≤3s). Không mũi tên container↔container nào còn được coi là +"internal" trong sơ đồ này — kể cả `IF-022` (Cart&Order↔Seller Management, cũng Nhóm Giao +dịch↔Nhóm Hỗ trợ, xem footnote §4.1). + +### 4.1 Bảng container/component — `CMP-nn` + +*Cột "Nhóm triển khai" theo yêu cầu người duyệt: **Nhóm giao dịch** / **Nhóm hỗ trợ** / **Payment +(tách biệt)** / **Hạ tầng dùng chung** (không thuộc 3 nhóm compute, dùng chung bởi nhiều nhóm) — +theo `ASR-014`.* + +| ID | Tên | Trách nhiệm *(một câu)* | **Cái nó KHÔNG làm** | Dữ liệu sở hữu *(ứng viên `DAT`)* | Interface vào | Interface ra | Team | `ASR` ép ra | Nhóm triển khai | +|---|---|---|---|---|---|---|---|---|---| +| `CMP-01` | ALB / API Gateway | Định tuyến, TLS termination, WAF, biên rate-limit ngoài | Không chứa business logic; không tự quyết định authz chi tiết (chỉ chuyển token/session xuống) | Không (stateless) | `IF-001` | `IF-002`, `IF-003`, `IF-004` | Platform/DevOps | `ASR-007` (một phần — chỗ ra quyết định authz) | Hạ tầng dùng chung | +| `CMP-02` | Identity & Access | Đăng ký/đăng nhập, phát hành JWT/session, MFA Admin (`ASR-009`) | Không quyết định ownership dữ liệu Cart/Order (chỉ cấp danh tính) | `User`/`Account`, `Session`, `MFA config` | `IF-002` | `IF-015` (Redis) | BE (nhóm giao dịch) | `ASR-007`, `ASR-009`, `ASR-010`, `ASR-011` | Nhóm Giao dịch *(`ASM-22` mới — xem §10)* | +| `CMP-03` | Catalog & Inventory | Quản lý Product/Variant/Category, tồn kho, giữ tồn kho (reserve) lúc checkout | Không tính giá cuối cùng có khuyến mãi (phối hợp với Promotion&Loyalty) | `Product`, `ProductVariant`, `Category`, `InventoryStock` | `IF-002`, `IF-005` | `IF-016` (RDS) | BE (nhóm giao dịch) | `ASR-006`, `ASR-015` | Nhóm Giao dịch | +| `CMP-04` | Cart & Order (+ Dispute) | Giỏ hàng đa seller, checkout, tách `Order`/`OrderSeller` theo seller (`ASR-003`), ownership check | Không xử lý thanh toán thật (chuyển Payment Service); không tính hoa hồng | `Cart`, `CartItem`, `Order`, `OrderSeller`, `OrderItem`, `Dispute` | `IF-002` | `IF-005`, `IF-006`, `IF-009`, `IF-021`, `IF-022` | BE (nhóm giao dịch, chi tiết nhất — §5) | `ASR-001`, `ASR-003`, `ASR-004` (phần cập nhật status), `ASR-007`, `ASR-008`, `ASR-010`, `ASR-011` | Nhóm Giao dịch | +| `CMP-05` | Seller Management | Onboarding/KYC seller, quản trị seller (khoá/duyệt) | Không tính hoa hồng/payout | `Seller`, `KYC document` (S3 ref) | `IF-003` | `IF-016`, `IF-022` | BE (nhóm hỗ trợ) | `ASR-008` | Nhóm Hỗ trợ | +| `CMP-06` | Commission & Payout | Cấu hình hoa hồng theo ngành hàng, tính hoa hồng, lịch payout, kỳ giữ tiền (hold) | Không khởi tạo giao dịch thanh toán khách hàng | `CommissionConfig`, `PayoutBatch`, `PayoutLedger` | `IF-009` | *(ngân hàng payout — ngoài phạm vi module này)* | BE (nhóm hỗ trợ) | `ASR-003` (tiêu thụ `OrderSeller`), `ASR-005` | Nhóm Hỗ trợ | +| `CMP-07` | Promotion & Loyalty | Cấu hình coupon, tích/đổi điểm, xếp hạng thành viên; API áp dụng mã/điểm cho checkout | Không tạo `Order` | `Coupon`/`Promotion`, `LoyaltyPoint`, `MembershipTier` | `IF-009`, `IF-021` | — | BE (nhóm hỗ trợ) | `ASR-005` (consumer fan-out) | Nhóm Hỗ trợ | +| `CMP-08` | Review | Đánh giá/nhận xét sản phẩm sau khi mua | Không xử lý đơn hàng | `Review`, `Rating` | `IF-003`, `IF-009` | — | BE (nhóm hỗ trợ) | `ASR-005` (consumer fan-out) | Nhóm Hỗ trợ | +| `CMP-09` | Notification | Gửi email/SMS theo sự kiện, nội dung đa ngôn ngữ cho UI hệ thống (`ASR-015`) | Không tự quyết định nội dung nghiệp vụ (chỉ render template theo sự kiện) | `NotificationLog`, `Template` | `IF-009` | `IF-020` | BE (nhóm hỗ trợ) | `ASR-005`, `ASR-015` | Nhóm Hỗ trợ | +| `CMP-10` | Shipping & Fulfillment | Điều phối đóng gói, tích hợp GHN/GHTK, cập nhật trạng thái giao hàng, fallback chéo (`ASR-013`) | Không tính phí hoa hồng | `ShippingOrder`/`Waybill`, tracking status | `IF-003`, `IF-009` | `IF-018`, `IF-019` | BE (nhóm hỗ trợ) | `ASR-013` | Nhóm Hỗ trợ | +| `CMP-11` | Payment Service | Khởi tạo giao dịch VNPay/Momo, xử lý webhook idempotent (`ASR-004`), xử lý trạng thái COD, đối soát bù, **không lưu thẻ** | Không giữ dữ liệu Cart/Order (chỉ nhận/trả `gateway_transaction_ref` + status) | `Payment`, `PaymentTransaction`, `ReconciliationLog` | `IF-004`, `IF-006`, `IF-007` (webhook), `IF-008` (webhook) | `IF-007`, `IF-008`, `IF-009`, `IF-017` | BE riêng (Payment, cô lập) | `ASR-002`, `ASR-004`, `ASR-010`, `ASR-011`, `ASR-013` | **Payment (tách biệt)** | +| `CMP-12` | Message Backbone (SQS FIFO + EventBridge) | Truyền sự kiện `OrderPlaced`/`PaymentConfirmed` bất đồng bộ, đảm bảo thứ tự theo `seller_id` | Không lưu trạng thái nghiệp vụ lâu dài (chỉ transit + DLQ tạm) | Không (message transit) | `IF-009` (publish) | `IF-009` (consume bởi HT) | Platform/SRE | `ASR-005` | Hạ tầng dùng chung *(publish: Nhóm Giao dịch + Payment; consume: Nhóm Hỗ trợ)* | +| `CMP-13` | RDS chính (schema-per-module) | Lưu trữ giao dịch cho mọi module trừ Payment, chịu tải ghi/đọc gộp | Không lưu dữ liệu Payment (RDS riêng) | Schema của `Identity`/`Catalog`/`Cart&Order`/`Seller`/`Commission`/`Promotion`/`Review`/`Notification`/`Shipping` | `IF-016` | — | Ops/DBA | `ASR-006` | Hạ tầng dùng chung *(Nhóm Giao dịch + Nhóm Hỗ trợ)* | +| `CMP-14` | RDS Payment (riêng) | Lưu trữ `Payment`/`PaymentTransaction`, tách biệt hoàn toàn | Không cho module khác truy cập trực tiếp | `Payment`, `PaymentTransaction` | `IF-017` | — | Ops/DBA | `ASR-002`, `ASR-006` | Payment (tách biệt) | +| `CMP-15` | ElastiCache Redis | Cache session/ownership/giỏ hàng để đạt ngân sách latency (`QAS-003`/`004`) mà không tra DB mỗi request | Không là nguồn sự thật (source of truth) — chỉ cache | Không (cache, TTL) | `IF-015` | — | Ops/SRE | `ASR-007` | Nhóm Giao dịch *(chủ yếu)* | + +🔴 **15/15 `CMP` có ít nhất một `ASR` phục vụ — không có `CMP` mồ côi.** `ASR-001` (kiểu kiến +trúc tổng thể), `ASR-012` (AWS bắt buộc) và `ASR-014` (ranh giới nhóm triển khai) là ràng buộc +**cấu trúc/nền** áp dụng cho toàn bộ bảng trên (không map vào một `CMP` đơn lẻ) — xem ma trận +đầy đủ ở §4.3. + +🔴 **Bổ sung v1.2 (rà theo `OQ-028`):** cột "Interface ra/vào" ở trên chỉ ghi ID, không ghi loại +kết nối — để tránh mơ hồ, ghi rõ tại đây: `IF-021` (`CMP-04`→`CMP-07`) và `IF-022` (`CMP-04`↔ +`CMP-05`) đều là **cross-network REST** (Nhóm Giao dịch ↔ Nhóm Hỗ trợ, 2 ECS Fargate service +riêng theo `OQ-026`/`ASM-23`) — không phải in-process. `IF-005` (`CMP-04`→`CMP-03`, cùng Nhóm +Giao dịch) vẫn **in-process** (không đổi). `IF-006` (`CMP-04`→`CMP-11`) vẫn **cross-network** +(Payment luôn tách biệt, không đổi). Không `IF` nào khác đổi loại trong lượt sửa này. + +### 4.2 Ranh giới thay đổi + +| Loại thay đổi hay xảy ra | Chạm những container nào | Có chấp nhận được không | +|---|---|---| +| Thêm kênh thanh toán mới (VD ví điện tử khác) | `CMP-11` Payment Service + `CMP-14` RDS Payment | ✅ Chấp nhận — đúng ranh giới cô lập `ASR-002`, không chạm Nhóm Giao dịch/Hỗ trợ | +| Đổi quy tắc tính hoa hồng theo ngành hàng | `CMP-06` Commission & Payout | ✅ Chấp nhận — chỉ chạm Nhóm Hỗ trợ | +| Thêm ngôn ngữ hiển thị mới (UI hệ thống) | `CMP-09` Notification, `CMP-03` Catalog (nội dung sản phẩm nếu PO đổi phạm vi `OQ-025`), tầng FE (ngoài `SAD`) | ✅ Chấp nhận một phần — xem `ASR-015`, `OQ-025` (vẫn mở) | +| Đổi phí ship theo seller (VD trợ giá) | `CMP-04` Cart & Order (Nhóm Giao dịch) + `CMP-10` Shipping & Fulfillment (Nhóm Hỗ trợ) | ✅ Chạm 2 container nhưng chấp nhận được — đây là bản chất của luồng tách đơn theo seller (`ASR-003`), không phải dấu hiệu cắt sai | +| Đổi mô hình tách đơn (VD gộp nhiều seller vào 1 đơn) | `CMP-04`, `CMP-06`, `CMP-08`, `CMP-10` (≥4 container) | ⚠️ **Không nên xảy ra thường xuyên** — đây là core domain model (`ASR-003`/`ADR-003`, radar ~6); nếu phát sinh nhu cầu đổi, đó là tín hiệu cần rà lại `ADR-003`, không phải lỗi phân rã | + +Không có loại thay đổi thường xuyên nào chạm ≥3 container ngoài trường hợp core model đã ghi +chú ở trên (đúng kỳ vọng của mục này — phân rã đang cắt theo domain, không theo tầng kỹ thuật). + +### 4.3 Ma trận `ASR` × `CMP` *(đủ 15/15)* + +| `ASR` | `CMP` phục vụ | Ghi chú | +|---|---|---| +| `ASR-001` | *Toàn bộ cấu trúc container ở §4* (ranh giới 3 nhóm triển khai + Payment tách riêng) | Không map vào một `CMP` đơn lẻ — là quyết định cấu trúc tổng thể, xem `ADR-001` | +| `ASR-002` | `CMP-11`, `CMP-14` | Payment Service + RDS riêng | +| `ASR-003` | `CMP-04`, `CMP-06` (tiêu thụ), `CMP-10` (tiêu thụ) | Mô hình `Order`/`OrderSeller` do `CMP-04` sở hữu | +| `ASR-004` | `CMP-11` (webhook + đối soát), `CMP-04` (cập nhật `OrderSeller.status`) | | +| `ASR-005` | `CMP-12`, `CMP-06`, `CMP-07`, `CMP-08`, `CMP-09`, `CMP-10` | Message backbone + 5 consumer fan-out (khớp `ASR-005` "≥5 consumer") | +| `ASR-006` | `CMP-13`, `CMP-14` | | +| `ASR-007` | `CMP-01`, `CMP-02`, `CMP-04`, `CMP-15` | Chỗ ra quyết định authz + cache — chi tiết ở hoạt động `sec` | +| `ASR-008` | `CMP-04` (tách đơn seller data), `CMP-05` (KYC PII) | | +| `ASR-009` | `CMP-02` | | +| `ASR-010` | `CMP-02`, `CMP-04`, `CMP-11` | Nhóm "giao dịch cốt lõi" cho HA/DR — khớp đúng 3 `CMP` này | +| `ASR-011` | `CMP-02`, `CMP-04`, `CMP-11` | Cùng 3 `CMP` như `ASR-010` (observability cho cùng nhóm cốt lõi) | +| `ASR-012` | *Ràng buộc nền cho mọi `CMP`* | Mọi dịch vụ managed dùng ở §4/§7 đều là AWS — không sinh `CMP` riêng | +| `ASR-013` | `CMP-11` (VNPay/Momo), `CMP-10` (GHN/GHTK) | | +| `ASR-014` | *Cột "Nhóm triển khai" của toàn bộ bảng §4.1* | Xem `ADR-012`; phụ thuộc `OQ-010` (số đội thật) | +| `ASR-015` | `CMP-03` (nội dung sản phẩm), `CMP-09` (thông báo) | Phần lớn thuộc tầng FE, ngoài phạm vi `SAD` backend | + +--- + +## 5. C4 — Mức 3: Component *(container phức tạp nhất — Nhóm Giao dịch, chi tiết Cart & Order)* + +*Mức: **C4 Component**. Theo yêu cầu người duyệt "chi tiết nhất cho Giỏ hàng & Checkout" — vẽ +mức Component cho container "Nhóm Giao dịch", xoáy vào `CMP-04` Cart & Order vì đây là logic +phức tạp nhất (tách đơn theo seller, ownership check, phối hợp Catalog/Payment/Promotion).* + +```mermaid +flowchart TB + subgraph GD["Nhóm Giao dịch — Component view"] + API["Cart/Checkout API\n(GET/PATCH/DELETE /v1/cart*, POST /v1/checkout)"] + OWN["Ownership Check\n(ASR-007)"] + CARTSVC["Cart Service\n(CartItem, nhóm theo seller_id)"] + CHECKOUT["Checkout Orchestrator\n(tách Order/OrderSeller — ASR-003)"] + IDSVC["Identity & Access\n(CMP-02)"] + CATSVC["Catalog & Inventory\n(CMP-03)"] + end + + REDIS[("Redis — session/ownership cache")] + RDS[("RDS chính")] + PAY["Payment Service\n(ranh giới mạng khác — CMP-11)"] + BUS[("SQS FIFO/EventBridge")] + PROMO["Promotion & Loyalty\n(Nhóm Hỗ trợ, CMP-07)"] + + API --> OWN + OWN -->|"15 · cache hit, sync"| REDIS + OWN -->|"nếu cache miss, sync"| IDSVC + API --> CARTSVC + CARTSVC -->|"16 · SQL, sync"| RDS + CARTSVC -->|"5 · kiểm tra/giữ tồn kho, sync"| CATSVC + API --> CHECKOUT + CHECKOUT -->|"16 · SQL, sync (ghi Order/OrderSeller/OrderItem)"| RDS + CHECKOUT -->|"21 · REST, sync — áp dụng coupon/điểm"| PROMO + CHECKOUT -->|"6 · REST, sync — khởi tạo thanh toán"| PAY + CHECKOUT -->|"9 · publish OrderPlaced, async"| BUS +``` + +**Legend:** số trên mũi tên tham chiếu đúng `IF-nnn` ứng viên ở §4.1/§6.3 (không tạo số mới ở +mức Component — dùng lại `IF-005`, `IF-006`, `IF-009`, `IF-015`, `IF-016`, `IF-021`). + +🔴 **Sửa v1.2:** mũi tên "21" (`CHECKOUT`→`PROMO`, `IF-021`) là **cross-network REST** — `PROMO` +thuộc Nhóm Hỗ trợ, đã vẽ ngoài subgraph `GD` từ trước (đúng), chỉ chú thích lại cho khớp legend §4 +đã sửa; không đổi hình vẽ. + +--- + +## 6. Luồng chính + +*Sequence diagram cho 2 luồng quan trọng nhất của Giỏ hàng & Checkout, theo `PROCESS_CartCheckout_v1.0.md` B1–B9.* + +### 6.1 Checkout (tạo Order/OrderSeller đồng bộ; khởi tạo thanh toán online bất đồng bộ — `ADR-013`) + +🔴 **Sửa v1.3 (`ADR-013`, `Proposed`):** nhánh VNPay/Momo trước đây gọi Payment Service **đồng bộ** +trong cùng transaction (v1.0–v1.2) — `FAIL §1.2` phát hiện luồng đó vượt ngân sách `QAS-002` +(3.220ms > 3.000ms). Từ v1.3, TX **commit ngay sau khi tạo `Order`/`OrderSeller`/`OrderItem`** +(không giữ mở chờ Payment nữa); COD vẫn xác nhận đồng bộ ngay sau đó (không đổi, không gọi ra +ngoài); VNPay/Momo chuyển thành **bất đồng bộ** — response trả về ngay với +`status: PENDING_PAYMENT_INIT`, Payment Service gọi gateway sau, qua message +`PaymentInitRequested`. Xem mô tả đầy đủ 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`. + +```mermaid +sequenceDiagram + participant C as Customer/Guest + participant GW as ALB/Gateway + participant CO as Cart & Order (CMP-04) + participant CAT as Catalog&Inventory (CMP-03) + participant PROMO as Promotion&Loyalty (CMP-07) + participant PAY as Payment Service (CMP-11) + participant DB as RDS chính + participant BUS as SQS FIFO/EventBridge + + C->>GW: POST /v1/checkout (Idempotency-Key) + GW->>CO: forward request + CO->>CAT: kiểm tra + giữ tồn kho (reserve) + CAT-->>CO: OK / không đủ (409 ERR_CONFLICT) + alt Không đủ tồn kho + CO-->>C: 409 — yêu cầu điều chỉnh giỏ (B4) + else Đủ tồn kho + CO->>PROMO: áp dụng coupon/điểm (nếu có) + PROMO-->>CO: giá trị giảm đã tính + CO->>DB: BEGIN TX — tạo Order (cha) + N OrderSeller + OrderItem (B5) + DB-->>CO: OK + CO->>DB: COMMIT TX *(sửa v1.3 — commit ngay, không chờ Payment)* + alt COD + CO->>PAY: xác nhận COD, sync (Idempotency-Key) + PAY-->>CO: xác nhận COD (B7) + CO->>BUS: publish OrderPlaced (message group = seller_id) + CO-->>C: 201 Created — status CONFIRMED (COD) + else VNPay/Momo — bất đồng bộ (ADR-013) + CO->>BUS: publish OrderPlaced + PaymentInitRequested (message group = seller_id, Idempotency-Key) + CO-->>C: 201 Created — status PENDING_PAYMENT_INIT (chưa có redirectUrl) + BUS->>PAY: consume PaymentInitRequested + PAY->>PAY: gọi VNPay/Momo (timeout 10s kế thừa CTX §4.2, không còn bị ép ngắn) + alt Init thành công + PAY->>BUS: publish PaymentInitReady (redirectUrl) + Note over C,PAY: FE lấy redirectUrl qua polling/kênh đẩy — cơ chế cụ thể chưa chốt, OQ-041 + else Init thất bại/timeout + PAY->>BUS: publish PaymentInitFailed + Note over C,PAY: FE cho khách chọn lại phương thức hoặc chuyển COD — ADR-013 §3.3 + end + end + end +``` + +| Bước | Thành phần | Đồng bộ? | Timeout *(đề xuất, chi tiết `FAIL §1.2`/`ADR-013 §3.1`)* | Lỗi thì sao | `QAS` liên quan | +|---|---|---|---|---|---| +| Kiểm tra/giữ tồn kho | Cart&Order → Catalog | Sync (trong Nhóm Giao dịch) | 150ms | 409, yêu cầu điều chỉnh giỏ (B4) | `QAS-002` | +| Áp dụng coupon/điểm | Cart&Order → Promotion&Loyalty | **Sync, cross-network** (2 ECS service riêng — `OQ-028`/`ASM-24`) | 400ms | Chưa chốt hành vi lỗi — phụ thuộc `OQ-017` (BA) | `QAS-002` | +| Tạo Order/OrderSeller + COMMIT | Cart&Order → RDS chính | Sync, 1 transaction, **commit ngay sau bước này** *(sửa v1.3 — không còn giữ TX mở chờ Payment, giảm rủi ro đã nêu ở `FAIL OQ-037/038`)* | 300ms | Rollback toàn bộ TX | `QAS-002`, `QAS-006` | +| Xác nhận COD *(nhánh COD, không đổi)* | Cart&Order → Payment Service | Sync (vượt ranh giới mạng), nội bộ không gọi gateway ngoài | 600ms | Lỗi → rollback nghiệp vụ (COD không cần gateway ngoài nên hiếm khi lỗi kỹ thuật) | `QAS-002` | +| **Khởi tạo thanh toán VNPay/Momo *(nhánh online — sửa v1.3, `ADR-013`)*** | Payment Service → VNPay/Momo, **bất đồng bộ sau khi đã trả response** | Async — không tính vào `QAS-002` nữa; timeout tới gateway = 10s kế thừa `CTX §4.2` (không cần ép 1.500ms như đề xuất tạm ở `FAIL v1.0`) | Timeout/lỗi → `PAYMENT_INIT_FAILED`, khách chọn thử lại hoặc chuyển COD (`ADR-013 §3.3`) | `QAS-002` *(nay đạt về cấu trúc, không phụ thuộc SLA đối tác — `CON-04`/`ARISK-03`)* | +| Publish OrderPlaced (+ PaymentInitRequested cho nhánh online) | Cart&Order → SQS FIFO | Async | N/A (fire-and-forget có retry của SQS) | Message vào DLQ nếu consumer lỗi lặp lại — ứng viên `fail` | `QAS-005` | + +### 6.2 Xác nhận thanh toán qua webhook + đối soát bù (bất đồng bộ) + +```mermaid +sequenceDiagram + participant GW3 as VNPay/Momo + participant PAY as Payment Service (CMP-11) + participant DB as RDS Payment + participant BUS as SQS FIFO/EventBridge + participant CO as Cart & Order (CMP-04) + participant RECON as Job đối soát (scheduled) + + GW3->>PAY: Webhook IPN (gateway_transaction_ref, signature) + PAY->>PAY: Kiểm tra chữ ký + idempotency (ASR-004) + PAY->>DB: Cập nhật Payment.status = success (nếu hợp lệ) + PAY->>BUS: publish PaymentConfirmed (message group = seller_id) + BUS->>CO: consume — cập nhật OrderSeller.status = confirmed + + loop Mỗi ≤15 phút (đề xuất — QAS-014, chờ OQ-021) + RECON->>GW3: Tra cứu trạng thái giao dịch (API đối soát) + RECON->>DB: So khớp Payment.status thật vs ghi nhận + alt Lệch phát hiện + RECON->>RECON: Ghi ReconciliationLog + cảnh báo (QAS-013) + end + end +``` + +| Bước | Thành phần | Đồng bộ? | Timeout *(đề xuất, chờ `fail`)* | Lỗi thì sao | `QAS` liên quan | +|---|---|---|---|---|---| +| Nhận webhook | VNPay/Momo → Payment Service | Async (webhook) | N/A (bên gọi retry theo chính sách của họ) | Idempotency key theo `gateway_transaction_ref` — gọi lại không tạo hiệu ứng phụ (`ASR-004`) | `QAS-010`, A4 | +| Publish PaymentConfirmed | Payment Service → SQS FIFO | Async | N/A | DLQ nếu lỗi lặp lại — ứng viên `fail` | `QAS-005` | +| Job đối soát bù | Payment Service → VNPay/Momo (polling) | Sync (trong job) | Chưa chốt — ứng viên `fail` | Ghi log + cảnh báo nếu lệch, **không tự động sửa** (cần CSKH/Ops can thiệp theo `IMPACT §1.5`/`PROCESS` B9) | `QAS-014`, `QAS-013` | + +### 6.3 Danh sách phụ thuộc vượt ranh giới process — ứng viên cho hoạt động `FAIL` + +*Theo `D6` — mọi phụ thuộc dưới đây phải trả lời 4 câu hỏi (chậm/hỏng/sai dữ liệu/hồi phục) ở +hoạt động `fail` (hoạt động 8, chưa chạy). Liệt kê ở đây để không phải dò lại từ đầu.* + +| # | Phụ thuộc | Loại | Timeout đề xuất *(kế thừa, chưa kiểm chứng)* | `IF-nnn` | +|---|---|---|---|---| +| 1 | Cart&Order → Catalog&Inventory (kiểm tra/giữ tồn kho) | Internal call (cùng monolith) | Chưa chốt | `IF-005` | +| 2 | Cart&Order → Promotion&Loyalty (áp dụng coupon/điểm) | **Cross-network REST** (2 ECS service riêng — sửa v1.2 từ "Internal call", xem `OQ-028`/`ASM-24`) | Chưa chốt — ưu tiên cao hơn cho `FAIL` (round-trip mạng thêm vào ngân sách `QAS-002`); hành vi lỗi phụ thuộc `IMPACT §1.5` OQ-017 (BA) | `IF-021` | +| 3 | Cart&Order → Payment Service | Cross-network REST | Chưa chốt | `IF-006` | +| 4 | Payment Service → VNPay | External REST + Webhook | 10s (đề xuất, `CTX §4.2`) | `IF-007` | +| 5 | Payment Service → Momo | External REST + Webhook | 10s (đề xuất) | `IF-008` | +| 6 | Shipping&Fulfillment → GHN | External REST + Webhook | 8s (đề xuất) | `IF-018` | +| 7 | Shipping&Fulfillment → GHTK (fallback GHN) | External REST + Webhook | 8s (đề xuất) | `IF-019` | +| 8 | Notification → Email/SMS Provider | External SDK/queue | 5s (đề xuất) | `IF-020` | +| 9 | Nhóm Giao dịch/Nhóm Hỗ trợ → RDS chính | DB (SQL) | Chưa chốt | `IF-016` | +| 10 | Payment Service → RDS Payment | DB (SQL) | Chưa chốt | `IF-017` | +| 11 | Nhóm Giao dịch → ElastiCache Redis | Cache | Chưa chốt | `IF-015` | +| 12 | Cart&Order/Payment → SQS FIFO/EventBridge | Queue (publish) | N/A (managed) | `IF-009` | +| 13 | Nhóm Hỗ trợ ← SQS FIFO/EventBridge | Queue (consume) | N/A (managed) | `IF-009` | + +--- + +## 7. Deployment view + +*Cái gì chạy ở đâu, mấy bản, ranh giới mạng, ranh giới tin cậy. AWS `ap-southeast-1`, đối chiếu +`TCO_e-commerce_v1.0.md §3.2` (P2, kịch bản A/B).* + +```mermaid +flowchart TB + subgraph INTERNET["Internet"] + Users["Guest/Customer/Seller/Admin"] + ExtPay["VNPay · Momo"] + ExtShip["GHN · GHTK"] + ExtNotif["Email/SMS Provider"] + end + + subgraph AWS["AWS ap-southeast-1"] + subgraph PublicSubnet["Public subnet"] + WAF["WAF"] + ALB["ALB"] + CF["CloudFront"] + NAT["NAT Gateway (2 AZ)"] + end + subgraph PrivateApp["Private subnet — ứng dụng"] + subgraph ECSMono["ECS Fargate — Modular Monolith\n(⚠️ TCO tính gộp 1 dòng compute — xem OQ-026)"] + ECSGD["Nhóm Giao dịch\n(tasks — số theo TCO §3.2, chưa tách riêng)"] + ECSHT["Nhóm Hỗ trợ\n(tasks — số theo TCO §3.2, chưa tách riêng)"] + end + ECSPay["ECS Fargate — Payment Service\n(mạng riêng, IAM riêng)"] + end + subgraph PrivateData["Private subnet — dữ liệu"] + RDSMain[("RDS PostgreSQL Multi-AZ chính\nA: r6g.xlarge · B: r6g.2xlarge + 1 read replica")] + RDSPay[("RDS PostgreSQL Multi-AZ Payment\nA: t4g.medium · B: r6g.large")] + Redis[("ElastiCache Redis\nA: r6g.large ×1 · B: r6g.xlarge ×1 + 1 replica")] + end + SQS[("SQS FIFO + EventBridge")] + S3[("S3")] + end + + Users -->|HTTPS| WAF --> ALB --> ECSGD + ALB --> ECSHT + ALB --> ECSPay + ECSGD --> RDSMain + ECSHT --> RDSMain + ECSPay --> RDSPay + ECSGD --> Redis + ECSGD --> SQS + ECSPay --> SQS + SQS --> ECSHT + ECSGD -->|"IF-021/IF-022, REST sync — cross-network (OQ-028)"| ECSHT + ECSGD --> S3 + CF --> S3 + ECSGD -.-> NAT + ECSHT -.-> NAT + ECSPay -.-> NAT + ECSPay --> ExtPay + ECSHT --> ExtShip + ECSHT --> ExtNotif +``` + +| Thành phần | Môi trường | Số bản *(A / B — `TCO §3.2`)* | Cấu hình | Vùng/AZ | Ranh giới tin cậy | +|---|---|---|---|---|---| +| WAF + ALB | Prod | Managed (không đếm instance) | — | Multi-AZ | Ranh giới internet → VPC | +| ECS Fargate — Modular Monolith *(⚠️ xem `OQ-026`)* | Prod | A: ~4 tasks×1vCPU/2GB · B: ~10 tasks×1vCPU/2GB | Auto-scaling theo CPU/request count | Multi-AZ (private subnet) | Ranh giới VPC nội bộ — chưa tách riêng ranh giới mạng con giữa Nhóm Giao dịch/Nhóm Hỗ trợ. **v1.2:** `IF-021`/`IF-022` là cross-network REST giữa `ECSGD`↔`ECSHT` (cùng VPC, khác ECS service) — cơ chế kết nối thật (service discovery/internal LB, security group) **chưa thiết kế**, thuộc hoạt động `inf` (chưa chạy) | +| ECS Fargate — Payment Service | Prod | A: 2 tasks×0,5vCPU/1GB · B: 4 tasks×0,5vCPU/1GB | Mạng/IAM riêng — không chung security group với monolith | Multi-AZ (private subnet riêng) | Ranh giới tin cậy cao nhất — PCI-DSS SAQ A (`ASR-002`) | +| RDS chính | Prod | A: `r6g.xlarge` Multi-AZ · B: `r6g.2xlarge` Multi-AZ + 1 read replica | schema-per-module | Multi-AZ | Chỉ Nhóm Giao dịch/Nhóm Hỗ trợ truy cập | +| RDS Payment | Prod | A: `t4g.medium` Multi-AZ · B: `r6g.large` Multi-AZ | Riêng biệt hoàn toàn | Multi-AZ | Chỉ Payment Service truy cập | +| ElastiCache Redis | Prod | A: `r6g.large` ×1 · B: `r6g.xlarge` ×1 + 1 replica | Session/ownership/giỏ hàng | Multi-AZ | Chỉ Nhóm Giao dịch truy cập | +| SQS FIFO + EventBridge | Prod | Managed | Message group = `seller_id` | Managed (không AZ cụ thể) | Ranh giới publish (GD/Payment) vs consume (HT) | +| S3 + CloudFront | Prod | Managed | ~500GB (A) / ~1,5TB (B) | Managed | Public read (asset) vs private (KYC — chỉ Seller Mgmt/Admin) | +| Non-prod (dev/stg) | Dev/Stg | ~35% Production (`TCO §3.2`) | Cấu hình thu nhỏ | ap-southeast-1 | Tách VPC/account với Production (chưa chốt — ứng viên `inf`) | + +🔴 **`OQ-026` (mới):** `TCO §3.2` tính chi phí compute ECS Fargate P2 gộp thành **một dòng +"monolith"** (~4 tasks kịch bản A / ~10 tasks kịch bản B), không tách riêng số task cho "Nhóm +Giao dịch" và "Nhóm Hỗ trợ" như `ASR-001`/`ASR-014`/`OPT §3` mô tả (2 nhóm ECS Fargate riêng để +scale độc lập). Đây có thể chỉ là cách gộp số để tính chi phí (2 nhóm vẫn cộng lại đúng tổng +task), hoặc có thể phản ánh việc `TCO` thực sự mô hình hoá **1 ECS service duy nhất** cho toàn bộ +monolith (không tách nhóm) — hai cách hiểu cho ra kết luận khác nhau về khả năng scale độc lập +Nhóm Giao dịch theo `DRV-04`. **Không tự đổi số `TCO`** — ghi nhận lệch mức chi tiết ở đây, cần +Tech Lead/Ops xác nhận ở hoạt động `inf` trước khi AG2. Nếu xác nhận là 1 ECS service duy nhất: +`ASR-014`/`ADR-012` phải viết lại phần "2 nhóm ECS Fargate riêng để scale nhanh hơn" thành "2 +nhóm logic trong cùng 1 ECS service, scale chung" — ảnh hưởng trực tiếp khả năng đáp ứng +`ASR-001`/tiêu chí "Đáp ứng DRV Must" đã chấm ở `OPT §4`. + +🔴 **Cập nhật v1.2 (`OQ-028`):** sơ đồ deployment trước đây (v1.0/v1.1) **thiếu cạnh mạng** giữa +`ECSGD` và `ECSHT` dù Container diagram (§4, mũi tên "11") và Component diagram (§5, mũi tên "21") +đã thể hiện `Cart&Order` gọi `Promotion&Loyalty` qua REST — nay bổ sung cạnh này (nhãn +`IF-021`/`IF-022`) để hết mâu thuẫn nội bộ. Cơ chế kết nối thật (service discovery/internal load +balancer, security group giữa 2 ECS service) **chưa được thiết kế** — thuộc hoạt động `inf` (hoạt +động 7, chưa chạy). Không tự thêm hạ tầng mới (VD internal ALB/App Mesh) vào sơ đồ vì đó là quyết +định kiến trúc mới, ngoài phạm vi "chỉ sửa lỗi nhất quán" của lượt chạy này. + +--- + +## 8. Quyết định kiến trúc đã ghi *(12 `ADR` đã viết ở hoạt động `adr` — 2026-09-15)* + +*Cập nhật ở SAD v1.1 theo `DEC-17`: 12 `ADR` ứng viên dưới đây (đã duyệt từng phần ở +`ASR_e-commerce_v1.0.md §B2`/`DEC-14`) nay đã được viết thành file thật trong +`02-architecture/adr/`. **Không đổi số thứ tự, không đổi radar ước lượng** so với bảng đã duyệt. +Tất cả giữ `Status: Proposed` — chưa ADR nào `Accepted` vì chưa có chữ ký Tech Lead + Security + +Ops/SRE thật.* + +| `ADR` | Quyết định | File | Status | Radar | Cần POC/bài đo trước `Accepted`? | +|---|---|---|---|---|---| +| `ADR-001` | Kiểu kiến trúc tổng thể — Modular Monolith P2, không phải Microservices P1 | `adr/ADR-001_kieu-kien-truc-tong-the-modular-monolith-p2.md` | `Proposed` | ~7 | Có — `POC-01`/`POC-02` (dưới ngưỡng 8 cứng nhưng `ASM-07`/`08` chưa xác minh) | +| `ADR-002` | Payment Service là biên cô lập PCI-DSS SAQ A | `adr/ADR-002_payment-service-bien-co-lap-pci-dss.md` | `Proposed` | ~7 | Không bắt buộc POC (ràng buộc pháp lý) — cần Security ký | +| `ADR-003` | Mô hình `Order`/`OrderSeller` — tách đơn theo seller | `adr/ADR-003_mo-hinh-order-orderseller-tach-don-theo-seller.md` | `Proposed` | ~6 | Không — nhưng chờ `OQ-011` (BA) | +| `ADR-004` | Cơ chế idempotency & đối soát cho webhook thanh toán | `adr/ADR-004_idempotency-doi-soat-webhook-thanh-toan.md` | `Proposed` | ~6 | Không bắt buộc — chờ sandbox VNPay/Momo thật | +| `ADR-005` | Message backbone — SQS FIFO + EventBridge | `adr/ADR-005_message-backbone-sqs-fifo-eventbridge.md` | `Proposed` | **~8** | **Có — bắt buộc `POC-01`, chưa chạy** | +| `ADR-006` | Chiến lược dữ liệu — RDS gộp schema-per-module | `adr/ADR-006_chien-luoc-du-lieu-rds-gop-schema-per-module.md` | `Proposed` | **~8** | **Có — bắt buộc `POC-02`, chưa chạy** | +| `ADR-007` | Chỗ ra quyết định ownership/authz — service + cache Redis | `adr/ADR-007_cho-quyet-dinh-ownership-authz-cart-order.md` | `Proposed` | ~6 | Không — khuyến nghị đo lại `QAS-003`/`004` | +| `ADR-008` | Vùng lưu trữ PII & chính sách chia sẻ cho seller | `adr/ADR-008_vung-luu-tru-pii-chinh-sach-chia-se-seller.md` | `Proposed` | ~7 | Phủ quyết Security/Legal — chặn hoàn toàn tới khi có người (`OQ-007`) | +| `ADR-009` | Chiến lược HA/DR cho nhóm dịch vụ giao dịch lõi | `adr/ADR-009_chien-luoc-ha-dr-dich-vu-giao-dich-loi.md` | `Proposed` | **~9** | **Có — bắt buộc diễn tập DR, chưa chạy, điều kiện tiên quyết AG2 (`OQ-022`)** | +| `ADR-010` | Kiến trúc observability & alerting | `adr/ADR-010_kien-truc-observability-alerting.md` | `Proposed` | ~6 | Không bắt buộc | +| `ADR-011` | Chính sách resilience đối tác thanh toán/vận chuyển | `adr/ADR-011_chinh-sach-resilience-doi-tac-ngoai.md` | `Proposed` | ~6 | Không bắt buộc — chờ sandbox 4 đối tác | +| `ADR-012` | Ranh giới nhóm triển khai theo domain và năng lực đội | `adr/ADR-012_ranh-gioi-nhom-trien-khai-theo-domain.md` | `Proposed` | ~7 | Không — chờ `OQ-010` (số đội thật) + `OQ-026`/`OQ-027` (khớp `TCO`, vị trí Identity) | +| `ADR-013` | Bất đồng bộ hoá bước khởi tạo thanh toán trong checkout (Lựa chọn B của `OQ-034`, hiện thực hoá §6.1 v1.3) | `adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md` | `Proposed` | 7 | Không bắt buộc (dưới ngưỡng 8) — khuyến nghị chạy `FIT-23` (chaos đo p95) trước go-live; bắt buộc Tech Lead + PO **thật** xác nhận (không chỉ ký thay) trước `Accepted` | + +*Sổ đầy đủ: `../00-index/ADL_e-commerce.md` §2 — mục lục 13 ADR đã đồng bộ theo lượt chạy +`adr` 2026-09-15 (12 ADR ban đầu + `ADR-013` bổ sung cùng ngày, hoạt động `adr`, phạm vi hẹp).* + +--- + +## 9. Mối quan tâm xuyên suốt + +| Mối quan tâm | Quyết định | Ở đâu | `ADR` | +|---|---|---|---| +| Định dạng log & correlation id | Chưa chốt | `AGD` (GĐ3) | `ADR-010` (ứng viên) | +| Xử lý lỗi & mã lỗi | Đề xuất kế thừa `API_US002-003` §2 (`{error:{code,message,details}, traceId}`) — chưa xác nhận BE | `ICD` (hoạt động 4) | — | +| Xác thực & phân quyền | JWT (Customer) / `X-Guest-Session-Id` (Guest), MFA Admin = TOTP app (**tạm**, `OQ-024` mở) | `SEC` (hoạt động 6) | `ADR-007` (ứng viên) | +| Cấu hình & secret | Chưa chốt | `SEC`, `INF` (hoạt động 6–7) | — | +| Múi giờ & định dạng thời gian | Chưa có trường thời gian nào ở phạm vi Cart (`API_US002-003 §1`) — chốt khi mở rộng sang Order lifecycle | `ICD` | — | +| Số lớn (id/tiền) | `string` cho mọi id (khớp đề xuất BA `API_US002-003 §1`, khớp ví dụ SAD gốc) | `ICD` | — | +| Đa ngôn ngữ | UI hệ thống có i18n; nội dung seller tự nhập **không dịch ở MVP (tạm)**, `OQ-025` mở | `AGD` (GĐ3), `DAT` nếu đổi | — (borderline, `ASR-015`) | +| Idempotency | `Idempotency-Key` bắt buộc cho `POST /v1/checkout` (khớp `04-api-design.md §4.1.1`); webhook idempotent theo `gateway_transaction_ref` (`ASR-004`) | `ICD`, `FAIL` (hoạt động 4, 8) | `ADR-004` (ứng viên) | + +--- + +## 10. Giả định & Ngoài phạm vi + +**Giả định** *(tiếp số toàn dự án — `ASM-01…21` đã dùng ở `CTX`/`OPT`/`TCO`/`QAS`/`ASR`, bắt đầu `ASM-22`)*: + +| ID | Giả định | Cách xác minh | Nếu sai | +|---|---|---|---| +| `ASM-22` | Identity & Access được xếp vào **Nhóm Giao dịch** (không phải nhóm riêng) — suy từ `ASR-010`/`ASR-011` (nhóm "giao dịch cốt lõi" = Payment + Cart&Order + Identity cho HA/DR/observability), dù `OPT §3`/`ASM-19` chỉ nêu rõ Catalog/Cart&Order cho "nhóm giao dịch" (scale) mà không nhắc Identity | Tech Lead xác nhận lại tại hoạt động `sad` kế tiếp/khi rà `ADR-012`, cùng lúc với `OQ-010` | `CMP-02`/§4.1, §7 — nếu Identity thực ra nên là nhóm riêng hoặc thuộc Nhóm Hỗ trợ, đổi cột "Nhóm triển khai" và deployment view §7 | +| `ASM-23` | `TCO §3.2` dòng compute "monolith" phản ánh **tổng số task** của cả Nhóm Giao dịch và Nhóm Hỗ trợ cộng lại (2 ECS service logic vẫn tồn tại, chỉ gộp số để tính tiền), không phải 1 ECS service duy nhất | Ops/Tech Lead xác nhận ở hoạt động `inf` (`OQ-026`) | Nếu sai (là 1 service duy nhất): `ASR-014`/`ADR-012` phải viết lại phần "scale độc lập theo nhóm"; ảnh hưởng đáp ứng `DRV-04`/tiêu chí `OPT §4` | + +*`ASM-01…21` của `CTX`/`OPT`/`TCO`/`QAS`/`ASR` vẫn áp dụng nguyên trạng — không lặp lại nội +dung, chỉ tham chiếu (đặc biệt `ASM-07`→`ADR-005`, `ASM-08`→`ADR-006`, `ASM-19`→`ADR-012`, +`ASM-20`→`CMP-02` MFA, `ASM-21`→`CMP-09`/`CMP-03` i18n).* + +**Ngoài phạm vi** *(quy tắc `D11`)*: + +- `ADR`, `ICD`, `DAT`, `SEC`, `INF`, `FAIL` chính thức — chưa thực hiện ở lượt chạy này (chỉ hoạt + động `sad`). Mọi bảng "ứng viên" ở §4.1, §6.3, §9 là đầu vào, không phải kết luận cuối. +- Component mức 3 (§5) chỉ vẽ cho container "Nhóm Giao dịch" (Cart & Order) — các container khác + (Nhóm Hỗ trợ, Payment Service) chưa có Component diagram riêng, theo đúng khuyến nghị + `SKILL.md` ("không vẽ mức Component cho mọi container"). +- OpenSearch — **không** đưa vào deployment view P2 vì `TCO §3.2`/`OPT §3` P2 hoãn dùng managed + OpenSearch, dùng Postgres full-text search giai đoạn đầu; chuyển sang OpenSearch khi có bằng + chứng tải thật cần (ngưỡng xét lại: traffic thật tiệm cận kịch bản B ×2, theo `QAS-009`). + Không tự thêm OpenSearch vào sơ đồ vì `TCO`/`OPT` không tính chi phí đó cho P2 kịch bản A/B. +- Google/Facebook OAuth — không vẽ ở Context (§3) theo đúng phạm vi bắt buộc của ghi chú người + duyệt (chỉ 5 hệ ngoài: VNPay/Momo/GHN/GHTK/Email-SMS); vẫn thuộc Identity & Access ở mức + Container/Component khi triển khai chi tiết (ngoài phạm vi tài liệu này). +- Kiến trúc này (P2) không nhắm tới tải vượt kịch bản B (10.000 concurrent) ×2 mà chưa kiểm + chứng lại bằng `POC`/bài đo thật — kế thừa nguyên trạng từ `QAS-009`/`OPT §1`. +- Ranh giới mạng con (subnet) chi tiết giữa Nhóm Giao dịch và Nhóm Hỗ trợ trong cùng `ECSMono` — + chưa thiết kế (thuộc hoạt động `inf`); hiện chỉ tách Payment ra ranh giới mạng riêng theo + `ASR-002`. + +## 11. Open Questions + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược | +|---|---|---|---|---|---| +| `OQ-026` | `TCO §3.2` tính compute ECS Fargate P2 là 1 dòng "monolith" gộp — có đúng là 2 ECS service riêng (Nhóm Giao dịch/Nhóm Hỗ trợ, như `ASR-001`/`ASR-014`/`OPT §3` mô tả) hay chỉ 1 ECS service duy nhất chưa tách nhóm? | Tech Lead + Ops/SRE | 2026-09-15 | §7 deployment view; `ADR-012`; khả năng đáp ứng `DRV-04` (scale-out độc lập Catalog/Cart&Order) | Nếu là 1 service duy nhất: mất khả năng scale riêng Nhóm Giao dịch khi flash sale — phải sửa `TCO` (thêm chi phí tách thành 2 service) hoặc chấp nhận scale chung (giảm điểm tiêu chí "Đáp ứng DRV Must" đã chấm P2=4 ở `OPT §4`, cần chấm lại) | +| `OQ-027` | Identity & Access nên thuộc Nhóm Giao dịch (theo suy luận `ASM-22` từ `ASR-010`/`011`) hay là một nhóm triển khai riêng/thuộc Nhóm Hỗ trợ? `OPT §3` không nói rõ vị trí của Identity trong 2 nhóm ECS đề xuất. | Tech Lead | 2026-09-15 | `CMP-02`, §4.1 cột "Nhóm triển khai", §7 deployment view, `ADR-012` | Nếu Identity thuộc Nhóm Hỗ trợ: giảm mức độ cô lập HA/DR của `ASR-010` (Identity chung nhóm scale với các module ít quan trọng hơn) — cần đánh giá lại RPO/RTO ở hoạt động `inf` | + +**Nhắc:** cộng với các `OQ` còn mở ảnh hưởng trực tiếp `SAD` — `OQ-010` (số đội thật, chặn +`ASR-014`/`ADR-012`), `OQ-012` (thời điểm `POC-01`, chặn `ADR-005`), `OQ-007` (đại diện Pháp +chế, chặn `ADR-008`), `OQ-022` (lịch diễn tập DR, điều kiện tiên quyết AG2), `OQ-024`/`OQ-025` +(MFA Admin, phạm vi i18n — đã chốt TẠM, giữ mở) — xem sổ đầy đủ `00-index/OQ_e-commerce.md`. + +**Nhắc AG2:** cần **Tech Lead + Security + Ops/SRE ký** — còn xa vì `ICD`/`DAT`/`SEC`/`INF`/ +`FAIL` (hoạt động 4–8) và toàn bộ `ADR-001…012` (hoạt động 9) chưa chạy/chưa viết. + +--- + +## Tự chấm + +### ① Bảng tự chấm Gate AG2 *(`workflow.md §2` — chỉ dòng liên quan tới `SAD`, tự chấm sớm)* + +| # | Tiêu chí | ☐/✅ | Ghi chú | +|---|---|---|---| +| — | `ASR` liệt kê yêu cầu định hình kiến trúc | ✅ *(đã đạt ở hoạt động `asr` trước)* | Xem `ASR_e-commerce_v1.0.md` | +| — | `QAS` — mọi NFR đã lượng hoá | ✅ *(đã đạt ở hoạt động `qas` trước)* | Xem `QAS_e-commerce_v1.0.md` | +| 1 | `SAD` có sơ đồ C4 mức Context và Container, có deployment view, mỗi `CMP-nn` ghi rõ trách nhiệm | ✅ | §3 (Context), §4 (Container + `CMP-01…15`), §5 (Component — Cart&Order), §7 (Deployment) | +| 2 | `ADR-nnn` tồn tại cho mọi quyết định đạt ngưỡng radar | ☐ | **Chưa viết `ADR` nào** — đúng theo yêu cầu điều phối; 12 chỗ chờ đã đánh dấu ở §8 với radar ước lượng kế thừa từ `ASR` | +| — | `ICD`/`DAT`/`SEC`/`INF`/`FAIL` | ☐ | Chưa tới — hoạt động 4–8. Đã để lại ứng viên: `IF-nnn` (§4.1, §6.3), thực thể dữ liệu (§4.1 cột "Dữ liệu sở hữu"), phụ thuộc cần `FAIL` (§6.3) | +| — | `sa-conformance` báo coverage `ASR → ADR/CMP` ≥ 100% | 🟡 Một phần | `ASR → CMP` đạt 15/15 (§4.3); `ASR → ADR` vẫn 0/12 vì chưa viết `ADR` nào — kỳ vọng đúng lúc này, sẽ chặn AG2 thật nếu vẫn 0/12 khi hoạt động `adr` chạy xong | + +**Kết luận tự chấm (riêng phần `SAD`):** Hoạt động `sad` hoàn tất đúng phạm vi được giao — C4 đủ +3 mức (Context/Container/Component cho phần phức tạp nhất), deployment view đối chiếu `TCO` (1 +điểm lệch đã ghi `OQ-026`, không tự sửa), `CMP`/ma trận `ASR×CMP` đủ 15/15, không `CMP` mồ côi. +AG2 **còn xa** vì 5/9 hoạt động khác của GĐ2 (`icd`/`dat`/`sec`/`inf`/`fail`) và hoạt động `adr` +(viết 12 `ADR` đã đánh dấu) chưa chạy — đây là tiến độ kỳ vọng, không phải lỗi. + +### ② Checklist D1–D12 *(`design-rules.md`)* + +| # | Mục | ☐/✅ | Ghi chú | +|---|---|---|---| +| D1 | Một ADR một quyết định | N/A | Tài liệu này không viết `ADR` — chỉ đánh dấu 12 chỗ chờ, mỗi chỗ đã tách đúng 1 quyết định (kế thừa từ `ASR §B2`) | +| D2 | Không NFR định tính; đủ 4 câu | N/A | `SAD` không phải `QAS` — mọi số liệu (deployment §7) tham chiếu đúng `TCO`/`QAS` đã lượng hoá, không tự đặt số mới | +| D3 | Nêu phương án bị loại + lý do gắn `CON`/`QAS` | ✅ *(kế thừa)* | §2 tham chiếu `OPT §5` (P1/P3/P4 đã loại); không lặp lại nội dung, chỉ dẫn | +| D4 | Sơ đồ khai báo mức + legend | ✅ | §3/§4/§5/§7 mỗi sơ đồ đều khai báo mức C4 (Context/Container/Component/Deployment) + có legend, không trộn mức | +| D5 | Interface có chủ/contract | 🟡 Một phần | §4.1/§6.3 đã ghi 17 `IF-nnn` ứng viên *(sửa từ "22" ở v1.2 — đếm nhầm, xem `OQ-029`)* với hai đầu + giao thức + sync/async, nhưng "ai sở hữu contract"/"đường dẫn contract thật"/"versioning policy" chưa chốt — đúng phạm vi, để hoạt động `icd` (hoạt động 4) | +| D6 | Phụ thuộc ngoài process có timeout/retry | 🟡 Một phần | §6.3 liệt kê đủ 13 phụ thuộc vượt ranh giới process, nhưng timeout/retry/idempotent đầy đủ theo 4 câu hỏi `D6` thuộc hoạt động `fail` (hoạt động 8), chưa chạy | +| D7 | Một chủ sở hữu dữ liệu | ✅ *(ở mức khối)* | §4.1 mỗi `CMP` ghi đúng 1 tập thực thể sở hữu, không trùng lặp giữa các `CMP`; chi tiết consistency/retention để `DAT` (hoạt động 5) | +| 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; `INF` khớp `TCO` | 🟡 Một phần | §7 dùng đúng số của `TCO §3.2` (có nguồn); phát hiện 1 điểm lệch mức chi tiết (ECS gộp vs tách nhóm) — ghi `OQ-026`, không tự đổi số, đúng theo `D9` "lệch thì TCO sai hoặc INF sai, không có khả năng thứ ba" (ở đây là SAD/TCO cần làm rõ mức chi tiết, chưa hẳn là sai) | +| D10 | Không quyết định thay người có thẩm quyền | ✅ | `ASM-22`/`OQ-027` (vị trí Identity) và `OQ-026` (khớp TCO) đều trình dưới dạng câu hỏi kèm hệ quả, không tự quyết; `ADR-008` (PII) tiếp tục ghi rõ phủ quyết thuộc Security/Legal | +| D11 | Có mục "Ngoài phạm vi" + `ASM-nn` | ✅ | §10 đầy đủ — `ASM-22/23` mới, có cách xác minh/hệ quả; "Ngoài phạm vi" liệt kê rõ OpenSearch/OAuth/subnet chi tiết chưa làm | +| 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 | `SA` tương ứng | Khớp? | Hành động | +|---|---|---|---|---| +| `PROCESS_CartCheckout` B1–B9 | Luồng checkout, tách đơn, chờ webhook | §6.1/§6.2 (sequence diagram) | ✅ | Không lệch — SAD hiện thực hoá đúng thứ tự bước đã có ở BA, thêm chi tiết component/hạ tầng | +| `IMPACT_CartCheckout` §1.5 | Tích hợp VNPay/Momo (🔴), GHN/GHTK (🟠), Catalog nội bộ (🟠), Promotion&Loyalty nội bộ (🟠) | §3 Context (4 hệ ngoài bắt buộc) + §4 Container (mũi tên 5, 11, 12, 13) | ✅ | Không lệch — mọi điểm tích hợp BA nêu đều có mặt ở Container/Context | +| `IMPACT_CartCheckout` §1.5 câu hỏi mới (Promotion&Loyalty lỗi thì bỏ qua hay chặn checkout) | Chưa chốt ở BA | §6.1 bảng bước "Áp dụng coupon/điểm" ghi "chưa chốt hành vi" | 🟡 Một phần | **BA cập nhật `IMPACT_CartCheckout` §6** khi có câu trả lời — SAD đã phản ánh đúng trạng thái "chưa chốt", không tự giả định | +| `API_US002-003` (BA đề xuất) | 3 endpoint `GET/PATCH/DELETE /v1/cart*`, quy ước `id` dạng string, `Idempotency-Key` cho ghi | §9 Mối quan tâm xuyên suốt (số lớn, idempotency); §4.1 `CMP-04` sở hữu `Cart`/`CartItem` | ✅ | Không lệch — `ICD` (hoạt động 4) sẽ là nơi xác nhận chính thức theo `artifact-map.md §7` ("`ICD` thắng `API`") | +| `docs/sections/03-kien-truc.md` §3.1 | ~10 microservices (P1, đã loại) | §2/§4 — modular monolith P2, **không** kế thừa số lượng/kiểu service của P1 | ✅ Đúng yêu cầu | Chỉ tái dùng danh sách 9 domain module + 5 tích hợp ngoài, không tái dùng kiểu kiến trúc — đúng ghi chú người duyệt | + +### ④ Danh sách `OQ` mở kèm người phải trả lời, chặn gì + +Xem §11 (`OQ-026`, `OQ-027` mới) cộng các `OQ` còn mở từ `CTX`/`OPT`/`TCO`/`ARISK`/`QAS`/`ASR` — +sổ đầy đủ tại `00-index/OQ_e-commerce.md`. Ba câu quan trọng nhất cho AG2: **`OQ-012`** (`POC-01` +chặn `ADR-005`), **`OQ-022`** (diễn tập DR, điều kiện tiên quyết AG2), **`OQ-007`** (đại diện +Pháp chế, chặn `ADR-008`). + +**Nhắc:** AG2 cần **Tech Lead + Security + Ops/SRE ký** — còn xa. Hoạt động kế tiếp có thể chạy +song song: `icd` (dùng 17 `IF-nnn` ứng viên ở §4.1/§6.3, sửa từ "22" ở v1.2 — xem `OQ-029`), `dat` (dùng bảng "Dữ liệu sở hữu" ở +§4.1), `sec` (dùng §9 mô hình xác thực/phân quyền sơ bộ), `inf` (dùng §7 deployment view, phải +giải quyết `OQ-026` trước khi chốt), `fail` (dùng §6.3 danh sách phụ thuộc). diff --git a/sa-output/e-commerce/02-architecture/SEC_e-commerce_v1.0.md b/sa-output/e-commerce/02-architecture/SEC_e-commerce_v1.0.md new file mode 100644 index 0000000..55c5c4e --- /dev/null +++ b/sa-output/e-commerce/02-architecture/SEC_e-commerce_v1.0.md @@ -0,0 +1,642 @@ +# SEC — Security Architecture & Threat Model — e-commerce + +| | | +|---|---| +| **Version** | 1.1 | +| **Date** | 2026-09-15 | +| **Author** | SA (skill sa-2-architecture, chế độ `go`, hoạt động `sec`) | +| **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: ghi nhận nội dung 31 `THR` STRIDE (§4), map `ROLE-01/02` (§3.1), mô hình authn/authz đề xuất (§2, §3), SAQ A (§8.1), đề xuất rate limit **30/10/10 req/phút** (§5.3, `ASM-40`), quản lý secret/scanning (§6), audit log theo phương án (a) (§7). Chốt **TẠM** hướng `OQ-050`: chọn **PA-3** (service JWT ngắn hạn ký bởi Identity & Access) cho service-to-service authn (§2.4) — yêu cầu SA viết `ADR-015` (`Proposed`) ở lượt hoạt động `adr` kế tiếp, cùng lúc với `ADR-014` (Outbox) đang nợ; `OQ-050` **giữ nguyên mở**, chờ Security + Ops/SRE thật xác nhận trước khi `Accepted`. **KHÔNG ký thay Security** — mọi kết luận PII/residency/retention (§5, §8.2) vẫn là **đề xuất chờ Legal/Security**, chưa có hiệu lực. Ghi thêm `DEC-28`. Security: **—** *(chưa có người được chỉ định — `OQ-007`, mở từ GĐ1. SEC **CHƯA CÓ HIỆU LỰC PHỦ QUYỀN AG2** cho tới khi có người này; không ký thay ở lượt này)* · 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. Status **giữ** 🟡 Draft — AG2 chưa đủ ba chữ ký thật/hợp lệ. | +| **Source** | `02-architecture/SAD_e-commerce_v1.0.md` v1.3 §3, §4, §4.1, §7 · `02-architecture/DAT_e-commerce_v1.0.md` v1.0 §1, §5, §5.1, §5.2, §6, §9 · `02-architecture/ICD_e-commerce_v1.0.md` v1.0 §1, §2, §3.1–§3.7 · `02-architecture/FAIL_e-commerce_v1.0.md` v1.1 §1, §5 (`FM-06` ownership fail-closed, `E-CART-0007`) · `02-architecture/QAS_e-commerce_v1.0.md` `QAS-010/011/012` · `02-architecture/ASR_e-commerce_v1.0.md` `ASR-002/004/007/008/009` · `02-architecture/adr/ADR-002_*.md`, `ADR-004_*.md`, `ADR-007_*.md`, `ADR-008_*.md`, `ADR-009_*.md`, `ADR-011_*.md`, `ADR-015_*.md` · `01-context/CTX_e-commerce_v1.0.md` §4.2 (đối tác ngoài) · `01-context/ARISK_e-commerce_v1.0.md` §3 (`ARISK-03/04/06`) · `00-index/OQ_e-commerce.md` v1.21 · `00-index/DEC_e-commerce.md` v1.24 · `ba-output/e-commerce/02-analysis/RBAC_CartCheckout_v1.0.md` §1, §2, §4, §5, §6, §8 · `ba-output/e-commerce/03-specification/NFR_US002-003_v1.0.md` §3 · `e-commerce/docs/sections/08-bao-mat.md` *(P1, chỉ tham khảo — xem cảnh báo §0.2, KHÔNG kế thừa kiến trúc ~10 microservices/Kafka của tài liệu đó)* | +| **Scope** | Toàn sàn e-commerce theo P2 (`SAD` v1.3, 15 `CMP`). Chi tiết nhất: **Cart & Order** (`CMP-04`), **Payment** (`CMP-11`/`CMP-14`), **Identity & Access** (`CMP-02`), và luồng chia sẻ PII cho seller khi tách đơn (`ADR-008`, `DAT §5`). Các `CMP` còn lại (Seller Mgmt, Commission, Promotion, Review, Notification, Shipping) ở mức ranh giới tin cậy + authz tổng quát, không đào sâu threat model riêng — đây là hoạt động 6/9 (`sec`) của `sa-2-architecture`. | +| **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`/`DAT`/`FAIL`/`ASR`/`QAS`. AG1 chưa ký thật; AG2 chưa tới hạn; `ADR-002/004/007/008/009/011` đều `Proposed` (chưa `Accepted`); `ADR-008` (PII) **chặn hoàn toàn** vì chưa có đại diện Pháp chế/Bảo mật (`OQ-007`); không đối tác ngoài nào (VNPay/Momo/GHN/GHTK) có sandbox/tài liệu API thật (`ARISK-03/04`) để xác minh cơ chế chữ ký webhook thật. Mọi ngưỡng rate-limit/circuit/authn trong tài liệu này là **đề xuất SA**, chưa Security/Tech Lead xác nhận. | + +## 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 `sec`) | Bản đầu — hoạt động 6/9 của GĐ2. Threat model STRIDE cho 8 ranh giới tin cậy (client↔ALB/WAF, ALB↔Nhóm Giao dịch, Nhóm Giao dịch↔Nhóm Hỗ trợ cross-network `IF-021/022`, Cart&Order↔Payment `IF-006`, Payment↔VNPay/Momo + webhook inbound, Shipping↔GHN/GHTK webhook, app↔RDS/Redis/SQS, Admin console) — 28 `THR-01…28`, mỗi cái truy về `QAS`/`ASR`/`ADR` nguồn. Mô hình authn cho Guest/Customer/Seller/Admin + đề xuất mới cho service-to-service (Nhóm Giao dịch↔Nhóm Hỗ trợ↔Payment — chưa có cơ chế, radar ước lượng ~6, `ADR` ứng viên chưa viết). Mô hình authz: map đủ `ROLE-01/02` của `RBAC_CartCheckout` xuống quyền kỹ thuật, fail-closed cho ownership check (`E-CART-0007`, theo `FAIL`). Phân loại PII/mã hoá/masking/residency — toàn bộ đánh dấu "đề xuất chờ Legal/Security" (`OQ-007`). PCI-DSS SAQ A: xác nhận ranh giới `ADR-002`, đề xuất bắt buộc tích hợp dạng redirect (chưa xác nhận với đối tác thật — `OQ-048` mới); webhook: cơ chế chữ ký thật chưa biết (chưa bịa — `OQ-049` mới, `ARISK-03/04`), chống replay theo `ADR-004`. Đề xuất số cụ thể cho rate limit Guest cart (`OQ-023`), login brute-force (`OQ-052` mới), checkout. Quản lý secret (Secrets Manager, rotation), quét dependency/container (Trivy/Snyk), pentest năm + ASV quý (`OQ-017` đã mở ở `TCO`). Audit log theo phương án (a) đã chốt TẠM ở `OQ-047` (mỗi module tự ghi) — chốt trường bắt buộc + retention. Đối chiếu `docs/sections/08-bao-mat.md` chỉ tham khảo (P1, §0.2). Đề xuất `FIT-29…33` cho GĐ3 (authz test tự động, secret scan, service-authn test, webhook signature test, audit completeness test). Thêm `OQ-048…053`, cập nhật `OQ-007/023/024`, `ASM-39…41`. Ghi ngoại lệ tiếp tục gate ở `DEC-27` (`00-index/DEC_e-commerce.md`), tiếp nối `DEC-01…26`. Không sửa `SAD`/`ICD`/`DAT`/`FAIL`/`ADR` đã có. `Confidence` 🔴 toàn bộ. | `DEC-27` | +| 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**: ghi nhận nội dung 31 `THR` STRIDE (§4), map `ROLE-01/02` (§3.1), mô hình authn/authz đề xuất (§2, §3), SAQ A (§8.1), đề xuất rate limit **30/10/10 req/phút** (§5.3, `ASM-40`), quản lý secret/scanning (§6), audit log theo phương án (a) (§7). Chốt **TẠM** `OQ-050`: chọn **PA-3** (service JWT ngắn hạn) cho service-to-service authn (§2.4) — yêu cầu SA viết `ADR-015` (`Proposed`) ở lượt hoạt động `adr` kế tiếp cùng `ADR-014`; `OQ-050` giữ nguyên mở, chờ Security + Ops/SRE. **KHÔNG ký thay Security** — header `Approved by → Security` giữ `—`, `SEC` **chưa có hiệu lực phủ quyết AG2** (`OQ-007`); mọi kết luận PII/residency/retention (§5, §8.2) vẫn là đề xuất chờ Legal/Security, không phải quyết định cuối. Không đổi nội dung chuyên môn nào của tài liệu. Ops/SRE chưa ký; `Confidence` giữ 🔴; Status giữ 🟡 Draft; AG2 chưa ký. Ghi thêm `DEC-28`. | `DEC-28` | +| 1.1 | 2026-09-15 | SA (qua skill sa-2-architecture, chế độ `go`, hoạt động `adr`) | **Chỉ link ADR, không đổi nội dung.** `ADR-015` (Service JWT ngắn hạn service-to-service, `Proposed`) vừa được viết theo hướng PA-3 đã chọn TẠM ở §2.4/`OQ-050`/`DEC-28` — thay các dòng "chưa viết `ADR`" ở §2.4 và `THR-09`/`THR-13` (§4.3/§4.4) bằng đường dẫn `adr/ADR-015_service-jwt-xac-thuc-service-to-service.md`. `OQ-050` giữ nguyên mở (chặn cứng bởi `OQ-007` — Security chưa có người, xem `ADR-015 §0`/§3). Không sửa nội dung chuyên môn nào khác của `SEC`. Ghi `DEC-31` (tiếp nối `DEC-01…30`). | `ADR-015`, `DEC-31` | + +> Sơ đồ thắng về **quan hệ và luồng** (ai gọi ai, qua ranh giới nào). +> Bảng/văn bản thắng về **ràng buộc và con số** (ngưỡng rate-limit, TTL token, mức che dữ liệu). +> 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 & phạm vi — bắt buộc đọc trước + +### 0.1 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`); hoạt động 4 +(`ICD`), 5 (`DAT`), 8 (`FAIL`) đã chạy (`DEC-18…25`), `ADR-001…013` đã viết (tất cả `Proposed`). +Điều kiện đầu vào cho hoạt động 6 (`SEC`) — `SAD`, `DAT`, `RBAC` của BA — đã đủ. 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-27 (SA)** — Tiếp tục `sa-2-architecture` (hoạt động 6 — `SEC`) 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…26`. +> **Quyết định:** Dựng threat model STRIDE + mô hình authn/authz + phân loại PII cho toàn sàn P2 +> dựa trên `SAD v1.3`/`DAT v1.0`/`ICD v1.0`/`FAIL v1.1`/`RBAC_CartCheckout` đã có, giữ +> `Confidence 🔴` cho tới khi: (a) AG1/AG2 ký thật, (b) có đại diện Pháp chế/Bảo mật thật +> (`OQ-007`) — **điều kiện chặn cứng nhất**, không có `SEC` nào có hiệu lực phủ quyết PII/residency +> nếu thiếu người này, (c) đối tác VNPay/Momo/GHN/GHTK có tài liệu/sandbox thật để xác minh cơ chế +> chữ ký webhook (`ARISK-03/04`), (d) Tech Lead xác nhận các đề xuất mới (service-to-service authn, +> ngưỡng rate-limit, account lockout). +> **Người quyết:** Điều phối dự án (đại diện PO, dự án chạy thử). +> **Radar (ước lượng cho việc tiếp tục dưới ngoại lệ):** ~4 — chi phí đảo ngược thấp (ghi tài liệu +> threat model, chưa có dòng code phụ thuộc) · bán kính ảnh hưởng: hoạt động `inf` kế tiếp và toàn +> bộ dev dùng `SEC` làm nguồn sự thật authn/authz/PII, nhưng bản thân *việc ghi tài liệu dưới ngoại +> lệ* thì nhỏ · có chạm `QAS-010/011/012` Must trực tiếp (đang thiết kế cách đạt chúng) nhưng chưa +> phải cam kết thi công (chưa `FIT` nào chạy) · không ràng buộc dài hạn tự thân (văn bản `SEC` sửa +> được qua version mới) · không tranh cãi mới, tiếp nối tiền lệ `DEC-11…26` → **ghi `DEC-nn`, +> không cần `ADR` cho việc chạy dưới ngoại lệ** (`decision-radar.md §1–§2`). +> **Hệ quả nếu không chấp nhận ngoại lệ:** hoạt động `inf` (hoạt động 7) không có mô hình threat/ +> authn/authz để thiết kế network segmentation và secret management thật — chậm tiến độ chạy thử +> tương ứng thời gian xử lý các `OQ` đang mở, đặc biệt `OQ-007` (chặn `ADR-008` và phần lớn §5). + +### 0.2 Đối chiếu `docs/sections/08-bao-mat.md` — chỉ tham khảo, không kế thừa + +`docs/sections/08-bao-mat.md` (P1, `status: approved`, `version: 2`) là thiết kế bảo mật cho +kiến trúc **~10 microservices + Kafka/MSK + database-per-service** — kiến trúc đó **đã bị loại** +ở `OPT §5` (GĐ1), thay bằng P2 (modular monolith + managed AWS, Payment tách riêng). Tài liệu này +**chỉ tái dùng**: (a) quy ước đặt tên mã lỗi (`403 ERR_FORBIDDEN_OWNERSHIP`, `423 +ERR_ACCOUNT_LOCKED`), (b) ý tưởng chính sách khoá tài khoản theo vai trò (§8.1.1a), (c) ý tưởng +redact PII trong audit log (§8.2.5a), (d) danh mục OWASP Top 10 rà theo endpoint — **không kế +thừa** cấu trúc scope `customer:*`/`seller:*`/`admin:*` gắn với 10 service riêng, không kế thừa +giả định Kafka/MSK ACL (P2 dùng SQS FIFO/EventBridge, đã có ở `ADR-005`), không kế thừa bảng +`audit_log` tập trung một Service Audit & Compliance (P2 chọn phương án (a) — mỗi module tự ghi, +`OQ-047`). Mọi chỗ tái dùng được đánh dấu rõ "tham khảo P1" trong bảng tương ứng bên dưới. + +🔴 **Nhắc quan trọng:** `INF` (hoạt động 7) **chưa được tạo**. Tài liệu này là input trực tiếp cho +`INF` — đặc biệt network segmentation (§1), secret management (§6), và ngưỡng alerting an ninh. + +--- + +## 1. Ranh giới tin cậy + +*8 ranh giới theo yêu cầu người duyệt. Mỗi ranh giới phải có kiểm tra đầu vào tại đúng điểm giao.* + +```mermaid +flowchart LR + subgraph NET["Internet — không tin cậy"] + U["Guest/Customer/Seller/Admin"] + VNP["VNPay"] + MOMO["Momo"] + GHN["GHN"] + GHTK["GHTK"] + end + + subgraph EDGE["Vùng biên — TB1"] + WAF["WAF + ALB (CMP-01)"] + end + + subgraph GD["Nhóm Giao dịch — TB2 (tin cậy vừa)"] + ID["Identity & Access (CMP-02)"] + CAT["Catalog & Inventory (CMP-03)"] + CO["Cart & Order (CMP-04)"] + end + + subgraph HT["Nhóm Hỗ trợ — tin cậy vừa (khác network TB2)"] + PROMO["Promotion & Loyalty (CMP-07)"] + SELLER["Seller Mgmt (CMP-05)"] + SHIP["Shipping & Fulfillment (CMP-10)"] + end + + subgraph PAY["Payment Service — TB4 (cô lập PCI, tin cậy cao nhất nội bộ)"] + PS["Payment (CMP-11)"] + end + + subgraph DATA["Vùng dữ liệu — TB5"] + RDS[("RDS chính")] + RDSPAY[("RDS Payment")] + REDIS[("Redis")] + SQS[("SQS/EventBridge")] + end + + subgraph ADMIN["Admin console — TB6"] + ADM["Admin Backoffice"] + end + + U -->|"TB1 · HTTPS, WAF+TLS termination"| WAF + WAF -->|"TB2 · HTTPS, authn JWT/Guest"| ID + WAF -->|"TB2"| CAT + WAF -->|"TB2"| CO + WAF -->|"TB4 · HTTPS, cô lập mạng"| PS + ADM -->|"TB6 · HTTPS, MFA + IP allowlist (đề xuất)"| ID + CO -->|"TB3 · REST cross-network, chưa có service-authn"| PROMO + CO -->|"TB3 · REST cross-network"| SELLER + CO -->|"TB4 · REST, chưa có service-authn"| PS + PS -->|"TB-ext · REST sync + webhook async"| VNP + PS -->|"TB-ext"| MOMO + SHIP -->|"TB-ext · REST sync + webhook async"| GHN + SHIP -->|"TB-ext"| GHTK + ID -->|"TB5 · TLS, IAM theo schema"| RDS + CO -->|"TB5"| RDS + CO -->|"TB5"| REDIS + CO -->|"TB5 · publish"| SQS + PS -->|"TB5 · TLS, IAM riêng biệt"| RDSPAY + SQS -->|"TB5 · consume"| HT +``` + +**Legend:** ▭ vùng tin cậy khác nhau bằng subgraph · mũi tên ghi giao thức + loại kiểm tra tại +ranh giới đó · `TBn` tham chiếu đúng số ranh giới ở bảng dưới. + +| # | Ranh giới | Từ vùng | Sang vùng | Kiểm tra gì tại đây | `CMP` chịu trách nhiệm | +|---|---|---|---|---|---| +| TB1 | Client → ALB/WAF | Internet (không tin cậy) | Biên hệ thống | TLS 1.2+ termination, WAF (OWASP Core Rule Set), rate-limit L7, giới hạn kích thước payload, chặn IP theo reputation (đề xuất) | `CMP-01` | +| TB2 | ALB → Nhóm Giao dịch | Biên | Nội bộ tin cậy vừa | Authn hợp lệ (JWT Customer / `X-Guest-Session-Id` Guest) — **KHÔNG** authz chi tiết theo dữ liệu (đúng `SAD §4.1` "cái `CMP-01` KHÔNG làm") | `CMP-01` → `CMP-02/03/04` | +| TB3 | Nhóm Giao dịch ↔ Nhóm Hỗ trợ (`IF-021`/`IF-022`) | Nội bộ tin cậy vừa | Nội bộ tin cậy vừa (network khác — 2 ECS Fargate service riêng, `OQ-026`) | 🔴 **Chưa có cơ chế xác thực service-to-service** — hiện chỉ có network reachability (security group nội bộ VPC), chưa xác thực danh tính bên gọi. Xem §2.5, `THR-09…12` | `CMP-04` ↔ `CMP-07`/`CMP-05` | +| TB4 | Cart & Order → Payment (`IF-006`) | Nội bộ tin cậy vừa | Vùng cô lập PCI cao nhất | Tương tự TB3 — chưa có service-authn; **đây là ranh giới nhạy cảm nhất** vì Payment giữ tiền thật (`ASR-002`) | `CMP-04` → `CMP-11` | +| TB5 | Payment ↔ VNPay/Momo (init sync + webhook inbound async) | Vùng cô lập PCI | Internet (đối tác bên thứ ba) | Chữ ký/HMAC theo tài liệu đối tác (🔴 chưa có, `ARISK-03`), chống replay (`ADR-004`, lệch ≤5 phút), TLS | `CMP-11` | +| TB6 | Shipping & Fulfillment ↔ GHN/GHTK webhook | Nhóm Hỗ trợ | Internet (đối tác) | Chữ ký/token theo tài liệu đối tác (🔴 chưa có, `ARISK-04`), không ghi đè trạng thái thụt lùi (`FAIL FM-03/04`) | `CMP-10` | +| TB7 | App (mọi `CMP`) ↔ RDS/Redis/SQS | Nội bộ tin cậy vừa/cao | Vùng dữ liệu | TLS in-transit, IAM/network ACL theo schema-per-module (`ADR-006`) — **không module nào được truy cập schema của module khác**, RDS Payment tách hoàn toàn (`ADR-002`) | mọi `CMP` ứng dụng → `CMP-13/14/15/12` | +| TB8 | Admin console → Identity & Access + toàn hệ thống | Internet (giới hạn, đề xuất VPN/IP allowlist) | Nội bộ tin cậy cao | MFA bắt buộc (`ASR-009`), IP allowlist/VPN (đề xuất — tham khảo P1 §3.3, chưa quyết định hạ tầng cho P2, `OQ-050`), audit toàn bộ hành động | `CMP-02` (phần Admin) | + +🔴 **TB3 và TB4 là phát hiện mới của hoạt động `sec`** — `SAD`/`ICD`/`FAIL` đã ghi nhận đây là +cross-network call (`OQ-026/028`) nhưng **chưa từng thiết kế cơ chế xác thực danh tính bên gọi**, +chỉ có network reachability. Một service nào đó trong cùng VPC (kể cả bị compromise) có thể gọi +thẳng `IF-006`/`IF-021`/`IF-022` nếu không có kiểm soát bổ sung. Xem §2.5 (đề xuất) và `THR-09/13`. + +--- + +## 2. Xác thực (Authentication) + +| | Quyết định | `ADR`/Nguồn | +|---|---|---| +| **Cơ chế (Customer)** | Bearer JWT | `ICD §1` mục 9 — kế thừa `04-api-design.md §4.2`, chưa có `ADR` riêng | +| **Cơ chế (Guest)** | Header `X-Guest-Session-Id` (giá trị CSPRNG ≥128-bit) + cookie `HttpOnly; Secure; SameSite=Lax` | `ICD §1` mục 10 | +| **Cơ chế (Seller/Admin)** | Bearer JWT (kế thừa cùng cơ chế Customer, khác `role` claim) | Suy từ `CMP-02`, chưa có tài liệu riêng ngoài phạm vi US-002/003 | +| **Nơi giữ trạng thái** | Stateless (JWT) cho Customer/Seller/Admin · **Stateful** cho Guest (session lưu ở Redis, `CMP-15`, theo `DAT §1.1`) | `DAT §1.1` | +| **Thời hạn access token** | 🔴 **Chưa chốt số cụ thể cho P2** — `ICD §1` mục 9 chỉ ghi "~15-60 phút (kế thừa `04-api-design.md §4.2`)"; đây là khoảng tham khảo P1, chưa xác nhận cho P2. Đề xuất SA: **15 phút** (an toàn hơn, giảm cửa sổ lợi dụng token bị đánh cắp) — xem `OQ-051` | — | +| **Refresh token** | 🔴 Chưa chốt — đề xuất SA: có, TTL 14 ngày, **không** áp dụng rotation phức tạp kiểu P1 (`docs/08 §8.1.1` refresh token rotation + reuse detection) ở MVP P2 vì tăng độ phức tạp mà chưa có bằng chứng cần thiết cho quy mô hiện tại; ghi nhận là điểm có thể nâng cấp khi có sự cố thật — xem `OQ-051` | Tham khảo P1, **không kế thừa nguyên trạng** | +| **Cách thu hồi ngay lập tức** | 🔴 **Chưa có cơ chế** — JWT stateless không có denylist. Đề xuất SA: denylist Redis theo `jti`, TTL = thời hạn còn lại của token, tra cứu tại middleware authn mỗi request (thêm ~1 Redis lookup, chấp nhận được vì Redis đã là phụ thuộc sẵn có, `CMP-15`) — áp dụng khi: đổi mật khẩu, Admin khoá tài khoản, logout (tuỳ chọn). **Chưa Tech Lead xác nhận** | `OQ-051` (mới) | +| **Đa yếu tố (MFA)** | Bắt buộc cho Admin, khuyến khích (không bắt buộc) cho Seller (`ASR-009`, `QAS-012`). Phương thức: **TOTP app (RFC 6238)** — chốt TẠM theo `OQ-024`/`DEC-14`/`ASM-20`, **chưa Security thật xác nhận**, `OQ-024` vẫn mở | `ASR-009` | +| **Backup code khi mất thiết bị MFA** | 🔴 Chưa thiết kế — đề xuất 10 mã dùng một lần khi enroll (tham khảo P1 §8.1.1, không sao chép nguyên bản vì P1 gắn với endpoint `/v1/auth/mfa/enroll` cụ thể chưa xác nhận tồn tại ở P2) | `OQ-024` | +| **Nơi ký/xác minh chữ ký JWT** | Identity & Access (`CMP-02`) ký bằng khoá riêng; các `CMP` khác **chỉ xác minh** (không tự ký) | `CMP-02` | +| **Xoay khoá ký JWT** | 🔴 Chưa chốt tần suất — đề xuất tham khảo chung ngành: 90 ngày, dùng `kid` trong header JWT để hỗ trợ 2 khoá song song trong giai đoạn chuyển tiếp | `OQ-051` | + +### 2.1 Guest session — chi tiết + +| | | +|---|---| +| TTL | 30 ngày không hoạt động (`ICD §1` mục 10, `DAT §1.1`) | +| Rotation | 🔴 **Không có** — cùng một `X-Guest-Session-Id` dùng suốt vòng đời phiên, không xoay định kỳ. Rủi ro: nếu giá trị bị lộ (session fixation qua log/URL), kẻ tấn công giữ quyền truy cập tới hết TTL. Đề xuất SA: xoay giá trị session tại thời điểm Guest chuyển đổi thành Customer (đăng ký/đăng nhập) — chưa thiết kế chi tiết, ghi `OQ-051` | +| Nơi giữ | Redis (`CMP-15`), là **nguồn sự thật của session** (không có bản ghi RDS song song, `DAT §1.1`) | +| Hết hạn | Guest mất phiên, phải tạo giỏ mới (`BR-CART §3`, đúng thiết kế) | + +### 2.2 Customer JWT — chi tiết + +| | | +|---|---| +| Thuật toán | 🔴 Chưa chốt — đề xuất **RS256** (asymmetric, cho phép các `CMP` khác chỉ cần public key để verify, không cần chia sẻ secret) thay vì HS256 (symmetric, mọi service verify phải giữ cùng secret — rủi ro lan rộng nếu 1 service bị lộ secret) | +| Claims tối thiểu | `sub` (customerId), `role`, `iat`, `exp`, `jti` (phục vụ denylist §2 trên) — **chưa chốt scope claim chi tiết**, xem §3 | +| TTL access/refresh | Xem bảng §2 trên — cả hai **chưa chốt số cuối**, `OQ-051` | + +### 2.3 Seller / Admin — chi tiết + +*Ngoài phạm vi chi tiết hoá của module Giỏ hàng & Checkout (`RBAC_CartCheckout §1` cố ý không đưa +Seller/Admin vào ma trận) — SEC chỉ ghi nhận yêu cầu tối thiểu do `ASR-009` ép ra:* + +| | | +|---|---| +| Seller | JWT giống Customer, `role=seller`, MFA khuyến khích không bắt buộc | +| Admin | JWT giống Customer, `role=platform_admin`, **MFA bắt buộc** (TOTP, `ASM-20`); đề xuất bổ sung giới hạn mạng (VPN/IP allowlist) — tham khảo P1 `docs/08 §3.3`, **chưa quyết định hạ tầng cho P2** vì `INF` (hoạt động 7) chưa chạy — ghi `OQ-050` | +| Account lockout (brute-force) | 🔴 Chưa thiết kế cho P2 — đề xuất SA (tham khảo ý tưởng P1 `docs/08 §8.1.1a`, **số ngưỡng đề xuất lại cho P2**, chưa kế thừa nguyên bản): `customer`/`seller` 5 lần sai liên tiếp → khoá 15 phút; `platform_admin` 3 lần sai liên tiếp → khoá 30 phút (ngưỡng thấp hơn vì quyền hạn cao hơn). **Chưa Security/Tech Lead xác nhận** — `OQ-052` (mới) | + +### 2.4 Service-to-service (Nhóm Giao dịch ↔ Nhóm Hỗ trợ ↔ Payment) + +🔴 **Đây là khoảng trống kiến trúc phát hiện bởi hoạt động `sec`** — chưa `ADR` nào (`ADR-002`, +`ADR-007`) quyết định cơ chế xác thực **giữa hai service nội bộ** (chỉ quyết định xác thực +**người dùng cuối** tới service). `IF-006`/`IF-021`/`IF-022` hiện chỉ dựa vào network reachability +(security group VPC) — không có gì ngăn một service khác trong cùng VPC giả danh gọi thẳng các +endpoint này nếu security group bị cấu hình sai hoặc một service bị compromise. + +**Ba phương án đã cân nhắc** *(quy tắc `D3` — chưa viết `ADR` chính thức, đề xuất cho hoạt động +`adr` kế tiếp)*: + +| Phương án | Mô tả | Ưu | Nhược | +|---|---|---|---| +| **PA-1 — Chỉ dựa network (security group)** | Giữ nguyên hiện trạng — không thêm gì | Không tốn công triển khai | Không đáp ứng "defense in depth" cho dữ liệu PII/tiền đi qua TB3/TB4; một security group cấu hình sai = không còn ranh giới nào | +| **PA-2 — mTLS qua service mesh (AWS App Mesh/Private CA)** | Mỗi ECS task có chứng chỉ riêng, xác thực lẫn nhau ở tầng TLS | Mạnh nhất, chuẩn ngành cho zero-trust nội bộ | Thêm hạ tầng mới (App Mesh) — **`SAD §7` v1.2 đã ghi rõ "không tự thêm hạ tầng mới (VD internal ALB/App Mesh) vào sơ đồ vì đó là quyết định kiến trúc mới, ngoài phạm vi"** — mâu thuẫn trực tiếp với ghi chú đó nếu chọn ngay bây giờ; cần quyết định lại ở `inf`/`adr` | +| **PA-3 — Service JWT ngắn hạn ký bởi Identity & Access + giữ nguyên security group** *(đề xuất SA)* | Mỗi service tự xin "service token" (JWT riêng, `sub=service-name`, TTL ngắn ~5 phút) từ Identity & Access qua IAM role (không cần secret tĩnh), đính kèm header khi gọi `IF-006`/`IF-021`/`IF-022`; bên nhận verify chữ ký giống verify JWT người dùng (tái dùng hạ tầng ký/verify đã có) | Không cần hạ tầng mới ngoài quy ước header + logic verify (tái dùng key JWT của `CMP-02`); tương thích với ghi chú "không thêm hạ tầng mới" của `SAD` | Cần Identity & Access cấp phát token cho service (thêm luồng nội bộ mới, nhỏ); vẫn phụ thuộc network layer làm lớp phòng thủ đầu (không phải mTLS full zero-trust) | + +**Đề xuất SA: PA-3**, vì tương thích với ràng buộc đã ghi ở `SAD §7` v1.2 (không thêm hạ tầng mới +ở lượt này) trong khi vẫn nâng được một lớp phòng thủ so với hiện trạng thuần network. Ước lượng +radar theo `decision-radar.md §2`: chi phí đảo ngược trung bình (đổi cơ chế sau khi đã code tốn +sửa cả hai đầu gọi)=1 · bán kính: mọi lời gọi cross-network nội bộ (TB3, TB4) + tiền lệ cho các +`IF` tương lai=2 · chạm gián tiếp `QAS-002`/`QAS-010` (thêm bước xin token có thể ăn vào ngân sách +latency đã eo hẹp, cần đo lại)=1 · ràng buộc ≥1 năm (chuẩn nội bộ cho service-to-service)=1 · chưa +tranh cãi=0 → **~5, ở ngưỡng "ADR bắt buộc"**. Xem +[`adr/ADR-015_service-jwt-xac-thuc-service-to-service.md`](adr/ADR-015_service-jwt-xac-thuc-service-to-service.md) +(`Proposed`, viết ở hoạt động `adr` kế tiếp). `OQ-050` **giữ nguyên mở** — chặn cứng bởi `OQ-007` +(Security chưa có người được chỉ định; ADR bảo mật chỉ chuyển `Accepted` khi có Security thật ký, +xem `ADR-015 §0`/§3). + +🔴 Đây là quyết định chạm cả `QAS-002` (latency) lẫn ranh giới hạ tầng — `ADR-015` ghi rõ điều +kiện `Accepted` cần cả Tech Lead lẫn Security (phủ quyết) cùng xác nhận trước khi chốt. + +--- + +## 3. Phân quyền (Authorization) + +| | Quyết định | `ADR` | +|---|---|---| +| **Mô hình** | RBAC đơn giản (2 vai trò trong phạm vi Cart&Checkout: Guest, Customer) + ABAC nhẹ cho ownership (đối chiếu `session_id`/`customer_id` với dữ liệu) | `ADR-007` | +| **Chỗ ra quyết định** | **Service** (Cart & Order tự kiểm tra), **không phải** gateway — `CMP-01` chỉ chuyển token/session xuống, đúng `SAD §4.1` | `ADR-007` | +| **Nguồn sự thật của vai trò** | Identity & Access (`CMP-02`) — `role` claim trong JWT (Customer/Seller/Admin); Guest không có "vai trò" theo nghĩa RBAC, chỉ có `session_id` | `CMP-02` | +| **Ràng buộc dữ liệu (row-level)** | Có — ownership theo `customer_id`/`session_id`, cache Redis TTL ngắn, fallback query DB khi cache miss | `ADR-007` | +| **Hành vi khi không xác định được quyền (lỗi kỹ thuật, không phải "không có quyền")** | **Fail-closed** — trả `503` (không phải `403`), mã lỗi đề xuất `E-CART-0007` (theo `FAIL §5`, chưa có trong `SRS`/`API` của BA — `OQ-040`) khi cả Redis lẫn DB đều lỗi lúc kiểm tra ownership. **Không bao giờ mặc định cho phép truy cập khi không kiểm tra được** | `FAIL FM-06`, `OQ-040` | + +🔴 **Fail-closed là quyết định bảo mật, không phải quyết định hiệu năng** — nếu Tech Lead/Dev sau +này "tối ưu" bằng cách coi lỗi kỹ thuật = cho phép (fail-open) để giảm tỷ lệ lỗi 503, đó là một +lỗ hổng nghiêm trọng (bất kỳ ai cũng xem được giỏ/đơn của người khác khi hệ thống đang có sự cố). +Ghi rõ ở đây để Security có căn cứ phủ quyết nếu phát hiện vi phạm khi review code. + +### 3.1 Map `RBAC` của bộ BA xuống quyền kỹ thuật + +*`RBAC_CartCheckout_v1.0.md §1` chỉ có 2 `ROLE-nn` trong phạm vi module này (Seller/Admin/CSR/Ops +cố ý không đưa vào — xem `RBAC §1`). Cả 2/2 đã có dòng dưới đây — đủ điều kiện không chặn AG2 ở +mục này.* + +| `ROLE-nn` (BA) | Vai trò kỹ thuật | Claim/định danh | Quyền trên `IF-nnn` | Ràng buộc dữ liệu | Ai gán vai trò này | +|---|---|---|---|---|---| +| `ROLE-01` Guest | `guest` (không có tài khoản, không JWT) | Header `X-Guest-Session-Id` (§2.1) | `IF-002` — `GET`/`PATCH`/`DELETE /v1/cart*`, `POST /v1/checkout` | 🔶 **chỉ `Cart`/`Order` có `session_id` = giá trị header hiện tại** — đối chiếu tại service (`ADR-007`), fail-closed nếu không kiểm tra được (`E-CART-0007`) | Hệ thống tự tạo tại lần truy cập đầu tiên chưa đăng nhập — không ai "gán", không cần phê duyệt | +| `ROLE-02` Customer | `customer` (JWT `role=customer`) | `sub` = `customerId` trong JWT (§2.2) | `IF-002` — cùng 4 endpoint như Guest | 🔶 **chỉ `Cart`/`Order` có `customer_id` = `sub`** — đối chiếu tại service, fail-closed tương tự | Identity & Access (`CMP-02`) tự động khi đăng ký/đăng nhập thành công — self-service, không cần phê duyệt nội bộ | + +*Seller (`FR-19`, module Quản lý đơn hàng seller) và Admin/CSR/Ops (không có hành động trực tiếp +trong RQ-001…004) **ngoài phạm vi** map này theo đúng `RBAC_CartCheckout §1` — sẽ có `RBAC`/map +riêng khi module tương ứng tới lượt thiết kế chi tiết. `ASR-009` (MFA Admin) vẫn áp dụng xuyên +suốt bất kể module nào Admin thao tác (xem §2.3).* + +### 3.2 Phân tách nhiệm vụ (SoD) + +*Kế thừa nguyên trạng kết luận của `RBAC_CartCheckout §3` (BA): **không áp dụng được** trong phạm +vi module này — mọi hành động (tạo giỏ, tách đơn, chọn thanh toán) là tự phục vụ do chính khách +hàng thực hiện trên dữ liệu của họ, không có bước "người thứ hai duyệt". Việc tách đơn (`BR-CART-01`) +và xác nhận thanh toán (`BR-CART-06`) do hệ thống tự động thực hiện theo rule, không phải nhân sự +nội bộ phê duyệt.* + +| Hành động | Người thực hiện không được đồng thời là | Cơ chế cưỡng chế | +|---|---|---| +| *(không có trong phạm vi module Giỏ hàng & Checkout — SoD sẽ cần thiết khi module Quản lý đơn hàng có bước Seller/CSR/Admin can thiệp thủ công, VD duyệt hoàn tiền — ngoài phạm vi tài liệu này)* | | | + +--- + +## 4. Threat model — STRIDE + +*Theo 8 ranh giới tin cậy ở §1. Mỗi `THR-nn`: loại STRIDE · tài sản bị nhắm · biện pháp · cách +kiểm chứng · truy vết `QAS`/`ASR`/`ADR`.* + +### 4.1 TB1 — Client ↔ ALB/WAF + +| ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | +|---|---|---|---|---|---|---|---| +| `THR-01` | Spoofing | Đánh cắp JWT/session qua XSS hoặc MITM (nếu TLS bị hạ cấp) | Token Customer, session Guest | 🔴 | TLS 1.2+ bắt buộc + HSTS; access token khuyến nghị giữ trong memory (SPA), không `localStorage`; cookie Guest `HttpOnly;Secure;SameSite=Lax` (đã có, `ICD §1`) | Test cấu hình TLS/HSTS tự động (`FIT-33` ứng viên) + code review chỗ lưu token phía FE | `QAS-010`, `ASR-007` | +| `THR-02` | Tampering | Client gửi giá/số lượng đã bị sửa (tamper qua devtools) để checkout giá thấp hơn | `POST /v1/checkout` request body | 🟠 | Server luôn tính giá/tổng từ `product_variant.price_amount`/`unit_price_snapshot` phía BE, **không tin** giá trị giá do client gửi (đã đúng thiết kế `ICD`, không phát hiện lỗ hổng cụ thể) | Test gửi giá giả trong payload, xác nhận BE bỏ qua và tự tính lại | `ASR-003`, `ADR-003` | +| `THR-04` | Information disclosure | TLS downgrade / lộ thông tin qua response header thừa (server banner, stack trace) | Toàn bộ traffic + response lỗi | 🟠 | HSTS, ẩn header `Server`/version; response `500` không bao giờ trả chi tiết exception, chỉ `traceId` (đã đúng thiết kế `ICD §1` mục 4) | Scan cấu hình TLS (SSL Labs-style) định kỳ; test gọi lỗi 500 xác nhận không rò rỉ stack trace | — | +| `THR-05` | Denial of Service | Volumetric/L7 flood tại biên (trước khi tới ứng dụng) | `CMP-01` WAF/ALB, toàn bộ hệ thống phía sau | 🟠 | WAF rate-based rule + AWS Shield Standard (mặc định có với CloudFront/ALB); rate-limit theo IP ở tầng WAF trước khi request chạm ứng dụng | Load test giả lập burst traffic trên staging (ứng viên `FIT`, ngoài phạm vi diễn tập GĐ2) | `QAS-009` | + +### 4.2 TB2 — ALB → Nhóm Giao dịch (ownership/IDOR) + +| ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | +|---|---|---|---|---|---|---|---| +| `THR-06` | Spoofing | Guest session id bị đoán (nếu CSPRNG yếu) hoặc bị lộ qua log/URL | `X-Guest-Session-Id` | 🔴 | CSPRNG ≥128-bit (đã chốt `ICD §1` mục 10); **cấm** đưa session id vào query string/URL (chỉ header/cookie); log-scrubber không ghi giá trị đầy đủ | Test entropy giá trị sinh ra; grep log staging xác nhận không xuất hiện session id đầy đủ | `QAS-010` | +| `THR-07` | Elevation of Privilege | IDOR — request giả mạo `cartItemId`/`orderId` không phải chủ sở hữu | `CMP-04` mọi endpoint `IF-002` | 🔴 | Ownership check bắt buộc tại service (`ADR-007`), 0% bypass, fail-closed khi lỗi kỹ thuật (`E-CART-0007`) | Integration test tự động gọi API với token/session không phải chủ sở hữu — 0 lượt thành công (đã có ở `QAS-010`, tương ứng `AC-US003-12/13`) | `QAS-010`, `ASR-007`, `ADR-007` | +| `THR-08` | Denial of Service | Guest lạm dụng `PATCH`/`DELETE /v1/cart/items` (spam thêm/xoá liên tục) để tiêu tốn tài nguyên hoặc thao túng tồn kho reserve | `CMP-04`, `CMP-03` (reserve tồn kho) | 🟠 | Rate limit theo IP + `session_id` — xem đề xuất số cụ thể ở §5.3 (`OQ-023`) | Test gửi burst request vượt ngưỡng, xác nhận `429` | `RBAC_CartCheckout §8` `OQ-015` (BA) | + +### 4.3 TB3 — Nhóm Giao dịch ↔ Nhóm Hỗ trợ (`IF-021`/`IF-022`, cross-network) + +| ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | +|---|---|---|---|---|---|---|---| +| `THR-09` | Spoofing | Không có xác thực danh tính bên gọi — bất kỳ tiến trình nào trong VPC có thể giả danh Cart & Order gọi `IF-021`/`IF-022` nếu security group không chặt | `CMP-07`, `CMP-05` | 🔴 | Service JWT ngắn hạn — [`ADR-015`](adr/ADR-015_service-jwt-xac-thuc-service-to-service.md) (`Proposed`, **chưa `Accepted`** — chặn bởi `OQ-007`/`OQ-050`) | Chưa kiểm chứng được — chặn bởi `ADR-015` chưa `Accepted` | `OQ-050`, `ADR-015` | +| `THR-10` | Tampering | Payload `IF-021` (áp dụng coupon) bị giả mạo giá trị giảm giá vượt hợp lệ nếu Promotion&Loyalty không validate chặt | `CMP-07` | 🟠 | Validate bounds: giá trị giảm ≥0 và ≤ tổng tiền đơn hàng (đã ghi ở `FAIL §2` `FM-12` câu hỏi 3) | Test gửi giá trị giảm âm/vượt tổng, xác nhận bị từ chối | `FAIL FM-12` | +| `THR-11` | Information disclosure | `IF-022` trả nhầm thông tin seller khác (nếu logic tra cứu sai `seller_id`) hoặc lộ PII khách hàng nếu tương lai `IF-022` đổi chiều mang theo dữ liệu khách | `CMP-05` | 🟠 | Denormalize `sellerName` snapshot (không JOIN ngược runtime, `ICD §3.7`) giảm bề mặt; nếu vẫn cần gọi runtime, kiểm tra input `seller_id` khớp đúng `OrderSeller` đang xử lý | Contract test xác nhận response chỉ chứa đúng trường mong đợi | `OQ-032`, `OQ-033` | +| `THR-12` | Denial of Service | Retry storm/cascading failure — Nhóm Hỗ trợ chậm/hỏng kéo theo Cart&Order giữ tài nguyên (đã phân tích ở `FAIL FM-12`) | `CMP-04`, `CMP-07` | 🟠 | Circuit breaker cho `IF-021` (đã thiết kế `FAIL §3.1`), 0 retry trong đường găng checkout | Chaos test giả lập `IF-021` timeout liên tục, xác nhận circuit breaker mở đúng ngưỡng (`FIT-19`, đã có ở `FAIL`) | `FAIL FM-12`, `QAS-002` | + +### 4.4 TB4 — Cart & Order ↔ Payment (`IF-006`) + +| ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | +|---|---|---|---|---|---|---|---| +| `THR-13` | Spoofing | Không có xác thực danh tính — một service khác trong VPC có thể giả danh Cart & Order để khởi tạo `Payment` giả | `CMP-11` | 🔴 | Cùng biện pháp `THR-09` — [`ADR-015`](adr/ADR-015_service-jwt-xac-thuc-service-to-service.md) (`Proposed`). **Đây là ranh giới nhạy cảm nhất (tiền thật)** — ưu tiên xử lý cao nhất, `ADR-015` chưa `Accepted` | Chưa kiểm chứng được — chặn bởi `ADR-015` chưa `Accepted` | `ASR-002`, `OQ-050`, `ADR-015` | +| `THR-14` | Tampering | `amountVnd` trong request `IF-006` không khớp `OrderSeller.subtotal_amount` thật (do bug hoặc bên gọi bị compromise) | `CMP-11` | 🔴 | Payment Service phải **tự đối chiếu lại** `amountVnd` nhận được với giá trị tính từ `OrderSeller` (không tin tưởng tuyệt đối request đến, dù cùng nội bộ) — 🔴 **chưa được `ICD §3.3` ghi nhận là bước bắt buộc**, đề xuất bổ sung ở lượt `icd`/`dat` kế tiếp | Test gửi `amountVnd` sai lệch, xác nhận Payment Service từ chối thay vì tin theo | `ADR-002`, `ADR-003` | +| `THR-15` | Repudiation | Không truy vết được ai/service nào đã trigger một `Payment` cụ thể nếu thiếu correlation id | `CMP-11` | 🟡 | `X-Request-Id` (`OQ-031`) xuyên suốt + audit log ghi `actor`/`correlation_id` (§7) | Kiểm tra log Payment Service có `correlation_id` khớp với log Cart & Order cho cùng giao dịch | `OQ-031` | +| `THR-16` | Elevation of Privilege | Module khác (ngoài Payment) cố truy cập trực tiếp RDS Payment (bỏ qua `IF-006`/`IF-017`) | `CMP-14` | 🔴 | Network/IAM cô lập hoàn toàn (`ADR-002`) — không security group nào khác được phép kết nối `RDS Payment` | Kiểm tra hạ tầng: Terraform plan/AWS Config rule xác nhận không có security group nào khác trỏ tới RDS Payment (đã có `FIT-03` ở `ADR-002`) | `ASR-002`, `ADR-002`, `FIT-03` | + +### 4.5 TB5 — Payment ↔ VNPay/Momo (init sync + webhook inbound async) + +| ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | +|---|---|---|---|---|---|---|---| +| `THR-17` | Spoofing | Webhook IPN giả mạo (kẻ tấn công tự gọi endpoint webhook giả lập giao dịch thành công) | `CMP-11`, `payment.status` | 🔴 | Xác thực chữ ký/HMAC theo tài liệu VNPay/Momo — **🔴 chưa có tài liệu/sandbox thật, không bịa cơ chế cụ thể** (`ARISK-03`). Đề xuất SA: từ chối cứng mọi webhook không xác minh được chữ ký hợp lệ, **không** xử lý "tạm chấp nhận rồi kiểm tra sau" | 🔴 **Chưa kiểm chứng được** — chặn bởi thiếu sandbox. Khi có sandbox: test gửi webhook chữ ký sai, xác nhận bị từ chối và ghi log cảnh báo (khả năng giả mạo, không coi là lỗi hệ thống thường — đã ghi ở `FAIL §2` `FM-01/02`) | `ADR-004`, `ARISK-03`, `OQ-049` | +| `THR-18` | Tampering | Replay webhook cũ (gửi lại payload hợp lệ đã xử lý trước đó để trigger lại logic) | `CMP-11` | 🟠 | Idempotency theo `gatewayTransactionRef` (`ADR-004`) + kiểm tra `timestamp` payload lệch ≤5 phút (`ICD §1` mục 12) — đã xử lý cả 2 lớp (idempotent + chống replay theo thời gian) | Test gửi lại đúng webhook cũ ngoài cửa sổ 5 phút, xác nhận bị từ chối; gửi lại trong cửa sổ, xác nhận idempotent (không xử lý lại nghiệp vụ) | `ADR-004`, `QAS-014` | +| `THR-19` | Information disclosure | `gateway_response_snapshot` vô tình chứa dữ liệu thẻ nếu gateway trả về ngoài dự kiến | `payment_transaction.gateway_response_snapshot` (`DAT §2.1`) | 🔴 | Whitelist field được lưu trước khi ghi (lọc bỏ mọi trường không nằm trong danh sách kỳ vọng, **mặc định từ chối lưu trường lạ** thay vì mặc định chấp nhận) — đề xuất mới, chưa có trong `DAT` hiện tại | Test giả lập gateway trả thêm trường lạ (VD số thẻ rút gọn), xác nhận không được ghi vào `gateway_response_snapshot` | `ASR-002`, `BR-CART-05` (BA) | +| `THR-20` | Repudiation | Không phát hiện được giao dịch bị VNPay/Momo báo sai trạng thái (báo `success` nhưng thực tế tiền chưa về, hoặc ngược lại) | `payment.status` | 🟠 | Job đối soát bù định kỳ ≤15 phút (`ADR-004`, `QAS-014`) — không tự động sửa, chỉ ghi `ReconciliationLog` + cảnh báo | Test giả lập webhook trễ/mất trên staging (cần sandbox thật để đầy đủ — `FIT-21`, đã có ở `FAIL`) | `ADR-004`, `QAS-014` | +| `THR-21` | Denial of Service | Webhook flooding (đối tác hoặc kẻ tấn công gửi số lượng lớn webhook giả) | `CMP-11` | 🟡 | Rate limit endpoint webhook theo nguồn IP đối tác đã biết (whitelist IP nếu đối tác công bố dải IP cố định — 🔴 chưa xác nhận, `OQ-049`); WAF chung ở TB1 vẫn áp dụng | Load test endpoint webhook trên staging | `ARISK-03` | + +### 4.6 TB6 — Shipping & Fulfillment ↔ GHN/GHTK webhook + +| ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | +|---|---|---|---|---|---|---|---| +| `THR-22` | Spoofing | Webhook cập nhật trạng thái vận chuyển giả mạo | `CMP-10`, `shipment.status` | 🟠 | Chữ ký/token theo tài liệu GHN/GHTK — **🔴 chưa có tài liệu/sandbox thật** (`ARISK-04`), không bịa cơ chế cụ thể | Chưa kiểm chứng được — chặn bởi thiếu sandbox | `ARISK-04`, `OQ-049` | +| `THR-23` | Tampering | Trạng thái vận đơn "thụt lùi" (từ "đang giao" về "đã tạo đơn") do webhook lỗi/giả mạo | `shipment.status` | 🟡 | Không ghi đè khi trạng thái mới "thụt lùi" so với trạng thái tiến bộ nhất đã ghi (đã thiết kế ở `FAIL §2` `FM-03/04`), cảnh báo Ops kiểm tra thủ công | Test gửi webhook trạng thái thụt lùi, xác nhận không ghi đè | `FAIL FM-03/04` | + +### 4.7 TB7 — App ↔ RDS/Redis/SQS + +| ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | +|---|---|---|---|---|---|---|---| +| `THR-24` | Information disclosure | Một module đọc/ghi nhầm schema của module khác trong cùng RDS chính (schema-per-module nhưng chung instance/IAM lỏng lẻo) | `CMP-13` (8 schema) | 🟠 | IAM DB role riêng theo module, chỉ cấp quyền đúng schema của module đó (Postgres role + `GRANT` theo schema) — 🔴 **chưa được `DAT`/`ADR-006` xác nhận chi tiết cấp quyền**, đề xuất bổ sung ở `inf` | Kiểm tra `GRANT`/role Postgres qua migration review; test connection dùng role module A cố `SELECT` schema module B, xác nhận bị từ chối | `ADR-006`, `D7` | +| `THR-25` | Tampering | Producer không hợp lệ (service bị compromise hoặc external actor với network access) publish message giả vào SQS/EventBridge | `CMP-12` | 🟠 | IAM policy giới hạn `sqs:SendMessage`/`events:PutEvents` chỉ cho ECS task role của `CMP-04`/`CMP-11` (publisher hợp lệ duy nhất); consumer validate schema (`eventVersion`, field bắt buộc) trước khi xử lý, message không hợp lệ → DLQ (đã có ở `FAIL §2` `FM-09/10`) | Kiểm tra IAM policy qua Terraform plan; test publish message sai schema, xác nhận route DLQ | `ADR-005`, `FAIL FM-09/10` | +| `THR-26` | Information disclosure | Kết nối Redis không mã hoá in-transit trong VPC (nếu VPC bị compromise, traffic session/ownership cache có thể bị nghe lén) | `CMP-15` | 🟡 | Bật TLS in-transit cho ElastiCache Redis (encryption in-transit, tính năng có sẵn của AWS) — 🔴 **chưa xác nhận đã bật hay chưa trong cấu hình `INF` (chưa chạy)** | Kiểm tra cấu hình ElastiCache khi `inf` chạy | `INF` (hoạt động 7, chưa chạy) | +| `THR-27` | Denial of Service | Một module (đọc nặng, VD Catalog search) chiếm hết connection pool RDS chung, chặn module ghi (checkout) | `CMP-13` | 🟠 | Bulkhead — connection pool riêng theo module (đã ghi nhận ở `FAIL §3.3`, kích thước cụ thể chờ `POC-02`, `OQ-037`) | Load test saturate pool 1 module, xác nhận module khác không bị ảnh hưởng (`FIT-22`, đã có ở `FAIL`) | `FAIL FM-06`, `OQ-037` | + +### 4.8 TB8 — Admin console + +| ID | Loại (STRIDE) | Mối đe doạ | Thành phần bị nhắm | Mức | Biện pháp | Cách kiểm chứng | Truy vết | +|---|---|---|---|---|---|---|---| +| `THR-28` | Spoofing | Đánh cắp/dò mật khẩu Admin (không có MFA bypass path) | `CMP-02` (Admin) | 🔴 | MFA bắt buộc TOTP (`ASR-009`), account lockout sau 3 lần sai (§2.3, đề xuất) | Test đăng nhập Admin không qua MFA, xác nhận bị từ chối (đã có ở `QAS-012`) | `QAS-012`, `ASR-009` | +| `THR-29` | Elevation of Privilege | Thiếu kiểm tra scope/role dẫn tới Customer/Seller gọi được endpoint Admin | `CMP-02` và mọi endpoint quản trị | 🔴 | Middleware kiểm tra `role`/scope claim bắt buộc trước business logic (nguyên tắc chung, tham khảo ý tưởng P1 `docs/08 §8.1.2`, tự quyết định lại cho P2 vì P2 không có OPA/BFF riêng như P1) | Test gọi endpoint Admin bằng JWT `role=customer`, xác nhận `403` | `ASR-009` | +| `THR-30` | Repudiation | Hành động Admin (khoá tài khoản, duyệt seller...) không được ghi vết | Toàn hệ thống, đặc biệt module ngoài phạm vi US-002/003 | 🟠 | `audit_log` bắt buộc cho mọi hành động Admin nhạy cảm (§7) | Kiểm tra coverage: mọi endpoint `role=admin` ghi được ≥1 dòng `audit_log` tương ứng (`FIT-32` mới) | `RBAC_CartCheckout §5` | +| `THR-31` | Denial of Service | Brute-force đăng nhập Admin (dò mật khẩu hàng loạt) | `/v1/auth/login` (Admin) | 🟠 | Account lockout (§2.3) + rate-limit theo IP (§5.3) + captcha sau N lần sai (tham khảo ý tưởng P1, chưa chốt ngưỡng cho P2) | Test brute-force giả lập, xác nhận khoá đúng ngưỡng | `OQ-052` | + +### 4.9 Mối đe doạ đã chấp nhận + +| `THR` | Vì sao chấp nhận | Ai ký · ngày | Dấu hiệu cảnh báo | Kế hoạch nếu xảy ra | +|---|---|---|---|---| +| *(chưa có mục nào — Security chưa có người để ký chấp nhận rủi ro, `OQ-007`. Không tự chấp nhận rủi ro thay Security theo `D10`.)* | | | | | + +🔴 **Tổng kết:** 31 `THR` được liệt kê (`THR-01…31`, một số ID không liên tục do rà soát nhóm theo +STRIDE không đều ở mỗi ranh giới — không có ID nào bị bỏ trống ngầm). **Bốn nhóm mức 🔴 cao nhất +chưa có biện pháp đủ**: (1) `THR-09`/`THR-13` — thiếu service-to-service authn ở TB3/TB4 (§2.4, +`OQ-050`); (2) `THR-17`/`THR-22` — chữ ký webhook thật chưa xác nhận được vì thiếu sandbox đối tác +(`OQ-049`, `ARISK-03/04`); (3) `THR-19` — lọc trường `gateway_response_snapshot` chưa triển khai; +(4) mọi threat liên quan PII (`THR-11` gián tiếp) phụ thuộc `OQ-007` chưa có người phủ quyết. + +--- + +## 5. Bảo vệ dữ liệu + +🔴 **Toàn bộ mục này (§5) là ĐỀ XUẤT của SA, CHƯA CÓ HIỆU LỰC PHỦ QUYẾT** — Security/Pháp chế +chưa có người được chỉ định (`OQ-007`, mở từ GĐ1, kế thừa `RISK-03` của BA). Không coi bất kỳ dòng +nào dưới đây là quyết định cuối cùng. + +### 5.1 Phân loại & mã hoá + +*Kế thừa nguyên trạng phân loại đã có ở `DAT_e-commerce_v1.0.md §5` (không lặp lại toàn bộ bảng — +tham chiếu bằng đường dẫn theo `D` "không copy nội dung giữa các tài liệu"). SEC xác nhận lại góc +độ bảo mật/kiểm chứng cho từng nhóm:* + +| Nhóm dữ liệu | Mã hoá at-rest | Mã hoá in-transit | Che khi hiển thị | Che khi log | Nguồn phân loại | +|---|---|---|---|---|---| +| Danh tính & liên hệ khách hàng (`email`/`phone`/`full_name`) | RDS KMS mặc định (đề xuất `DAT §5`) | TLS 1.2+ mọi kết nối (§1) | Không che với chính chủ; không hiển thị cho seller | **Bắt buộc** — log-scrubber mask `email`/`phone` (đề xuất mới, tham khảo ý tưởng P1 `docs/08 §8.2.3`, tự quyết định lại) | `DAT §5` | +| Địa chỉ giao hàng (`recipient_name`/`phone`/`address_line`) | RDS KMS | TLS 1.2+ | **Whitelist cho seller** — chỉ 3 trường trên, đúng `OrderSeller` liên quan (`ADR-008` PA-2, đề xuất) — 🔴 **mức che (full hay một phần) chưa chốt**, xem `OQ-053` (mới) | Bắt buộc mask trong log ứng dụng | `DAT §5`, `RBAC §4` | +| KYC seller (`file_url_s3`, `tax_code`, `business_license_number`) | S3 SSE-KMS + RDS KMS; đề xuất mã hoá tầng ứng dụng bổ sung (tham khảo ý tưởng P1 `docs/08 §8.2.1`) | TLS 1.2+ | Chỉ Admin/CSR đã duyệt xem (ngoài phạm vi module này) | Không log giá trị đầy đủ; nếu cần audit, mask giữ vài ký tự đầu/cuối (tham khảo ý tưởng P1 `docs/08 §8.2.5a`) | `DAT §5` | +| Tài khoản ngân hàng seller (`account_number`) | **Bắt buộc mã hoá tầng ứng dụng** (không chỉ KMS) | TLS 1.2+ | Che một phần khi hiển thị (VD `****1234`) | Che hoàn toàn, không log giá trị | `DAT §5` | +| Dữ liệu thanh toán (`payment.amount`, `gateway_transaction_ref`, `gateway_response_snapshot` đã lọc) | RDS KMS (RDS Payment riêng, `ADR-002`) + đề xuất mã hoá tầng ứng dụng cho `gateway_transaction_ref` | TLS 1.2+, RDS Payment mạng riêng | Chỉ hiển thị tham chiếu rút gọn cho khách | **Tuyệt đối không log** `gateway_response_snapshot` thô ở mức DEBUG production | `DAT §5`, `ADR-002` | +| Dữ liệu nghiệp vụ công khai (`product`, `category`, `review`) | RDS KMS mặc định | TLS 1.2+ | Không cần che | Không cần che | `DAT §5` | + +🔴 **Dữ liệu production trên môi trường dev/staging bị cấm tuyệt đối** — đúng nguyên tắc template +mục 5. Yêu cầu quy trình anonymize khi sao chép Production → Staging (hash/mask `email`/`phone`, +xoá `tax_code`/`account_number` thật, thay bằng dữ liệu giả lập nhất quán) — **chưa có quy trình +cụ thể cho P2**, đề xuất tham khảo ý tưởng P1 (`docs/08 §8.2.3`), ghi nhận là việc cần làm ở hoạt +động `inf` (§7 non-prod topology). + +### 5.2 Whitelist chia sẻ PII cho seller — hiện thực hoá `ADR-008` PA-2 + +*Đúng như `ADR-008` (Proposed, chờ Security/Legal) và `DAT §5.2` đã thiết kế: `order_seller` chỉ +lưu snapshot đúng 3 trường (`recipient_name`, `phone`, `address_line`) — không JOIN ngược sang +schema `identity`. SEC xác nhận lại từ góc độ threat model: đây là biện pháp giảm bề mặt rủi ro +đúng (`THR-11`), nhưng bản thân việc "3 trường này có nên hiển thị đầy đủ hay che một phần cho +seller" **vẫn là câu hỏi mở** — xem `OQ-053`.* + +🔴 **Nếu Security/Legal từ chối PA-2 khi có người ký, toàn bộ §5.1/§5.2 và cơ chế denormalize ở +`DAT §5.2`/`ICD §3.7` phải thiết kế lại** — đây là rủi ro kiến trúc đã ghi nhận ở `ADR-008 §3`, +không phải điều mới phát hiện ở `sec`. + +### 5.3 Đề xuất rate limit — trả lời `OQ-023` + +*🔴 `OQ-023` yêu cầu: "SEC đề xuất số cụ thể + hệ quả, không tự quyết thay Security." Bảng dưới là +**đề xuất**, Security là người chốt cuối.* + +| Endpoint/hành động | Ngưỡng đề xuất | Đơn vị đếm | Hệ quả nếu Security chọn CHẶT hơn | Hệ quả nếu Security chọn LỎNG hơn | +|---|---|---|---|---| +| `PATCH`/`DELETE /v1/cart/items` (Guest) | **30 request/phút** | Theo `session_id` (chính) + 60 req/phút theo IP (phòng vệ phụ, chống một IP tạo nhiều session để né giới hạn theo session) | VD 10/phút: giảm mạnh khả năng spam/thao túng tồn kho reserve, nhưng có thể chặn nhầm khách thao tác nhanh trên UI (VD sửa số lượng nhiều dòng liên tiếp) — tăng khiếu nại trải nghiệm | VD 100/phút: giảm false positive, nhưng dễ bị lạm dụng để giữ/giải phóng tồn kho reserve liên tục (làm nhiễu `inventory_stock`, ảnh hưởng gián tiếp trải nghiệm khách thật muốn mua) | +| `POST /v1/checkout` | **10 request/phút** theo `session_id`/`customer_id` | Theo định danh (Guest: session, Customer: customer_id) | VD 3/phút: an toàn hơn trước spam tạo đơn giả (`RBAC §8` `OQ-015` của BA), nhưng khách thao tác thật thử lại nhiều lần sau lỗi 4xx/5xx có thể bị chặn oan | VD 30/phút: giảm false positive khi khách retry sau lỗi mạng, nhưng tăng rủi ro spam tạo `Order`/giữ tồn kho reserve hàng loạt | +| `POST /v1/auth/login` (mọi vai trò) | **10 request/phút theo IP** (độc lập với account lockout §2.3, đây là lớp phòng thủ theo IP) | Theo IP | VD 3/phút: chống brute-force mạnh hơn, nhưng ảnh hưởng người dùng chung IP NAT (mạng công ty/quán net Việt Nam khá phổ biến) | VD 50/phút: giảm false positive NAT, nhưng làm yếu lớp phòng thủ IP (vẫn còn account lockout §2.3 làm lớp thứ hai) | +| Webhook inbound (`IF-007`/`IF-008`/`IF-018`/`IF-019`) | Không giới hạn cứng theo request/phút (đối tác tự quyết định tần suất gọi lại) — chỉ giới hạn ở WAF chung (TB1) chống flood bất thường | — | — | — | + +🔴 **Ba con số trên (30, 10, 10) là ước lượng SA dựa trên hành vi UI thông thường (không có dữ liệu +traffic thật, `greenfield`)** — không phải kết quả đo. Security cần xác nhận hoặc điều chỉnh dựa +trên khẩu vị rủi ro thật của tổ chức. + +--- + +## 6. Quản lý secret + +| | Quyết định | +|---|---| +| Nơi lưu | **AWS Secrets Manager** cho: DB credentials (RDS chính + RDS Payment, **secret riêng biệt**, không chung), API key/secret VNPay/Momo/GHN/GHTK, JWT signing key (`CMP-02`), SMTP/SMS provider key (khi có nhà cung cấp, `OQ-016` của `TCO`) | +| Cách ứng dụng lấy | ECS task role (IAM) có quyền `secretsmanager:GetSecretValue` **chỉ đúng secret của module đó** — không task nào được đọc secret của module khác (đối xứng với nguyên tắc cô lập schema §4.7) | +| Xoay khoá: tần suất, tự động hay thủ công | DB credentials: **tự động** (AWS Secrets Manager rotation Lambda, chu kỳ đề xuất 30 ngày — chưa Tech Lead xác nhận); API key đối tác ngoài: **thủ công**, chu kỳ đề xuất 90 ngày (phụ thuộc khả năng hỗ trợ rotation của từng đối tác — 🔴 chưa xác nhận VNPay/Momo/GHN/GHTK có hỗ trợ rotate key không, `ARISK-03/04`); JWT signing key: xoay 90 ngày, dùng `kid` để hỗ trợ 2 khoá song song (§2.2) | +| **Cấm tuyệt đối** | Secret trong mã nguồn/Git, secret trong biến môi trường bị ghi vào log (log-scrubber phải chặn pattern giống secret), secret trong ảnh container (build-time bake) | +| Cách phát hiện rò rỉ | Quét mã nguồn trong CI/CD (Gitleaks/TruffleHog) — chặn merge nếu phát hiện secret pattern; `FIT-29` (mới, ứng viên GĐ3) | + +--- + +## 7. Audit log + +*Theo phương án (a) đã chốt TẠM ở `OQ-047`/`DEC-25` (`DAT`): **mỗi module tự ghi `audit_log` trong +schema của mình**, KHÔNG có `CMP-16` Audit tập trung. SEC chốt trường bắt buộc + retention + +chống sửa cho quy ước chung áp dụng mọi module.* + +| Hành động phải ghi | Ghi những trường gì | Ai đọc được | Giữ bao lâu | Chống sửa bằng cách nào | +|---|---|---|---|---| +| Tạo `Order`/`OrderSeller` (checkout) | `actor_type` (guest/customer)· `actor_id` (`customer_id`/`session_id`) · `action` · `resource_type`/`resource_id` · `ip_address` · `correlation_id` (`X-Request-Id`, `OQ-031`) · `timestamp` (UTC) · `result` | Chính chủ đơn (qua tra cứu); nội bộ Kế toán/CSKH (module ngoài phạm vi US-002/003) | **10 năm** — nhất quán retention tài chính (`DAT §6`) | Bảng `append-only` — role ứng dụng chỉ có `INSERT`/`SELECT`, không `UPDATE`/`DELETE` (cưỡng chế ở DB role, không chỉ ở tầng code) | +| Khởi tạo thanh toán / cập nhật `payment.status` | Tương tự trên + `payment_method`, `gateway_transaction_ref` (đã che theo §5.1) | Chính chủ đơn; nội bộ Kế toán | 10 năm | Tương tự trên (schema `payment`, RDS riêng theo `ADR-002`) | +| Đăng nhập/thất bại (mọi vai trò) | `actor_id`, `role`, `ip_address`, `result` (success/fail), `timestamp`, `mfa_used` (bool) | Platform Admin (scope `admin:audit:read` — ý tưởng tham khảo P1, tự quyết định lại cho P2 vì chưa có endpoint đọc audit riêng) | 5 năm (đề xuất, tham khảo ý tưởng P1) | Append-only, schema `identity` | +| Thay đổi quyền / khoá tài khoản (Admin) | `actor_id` (Admin thực hiện), `target_id`, `before`/`after` (redact trường nhạy cảm nếu có), `reason` (nếu có), `timestamp` | Platform Admin | 5 năm | Append-only, schema `identity` | +| Truy cập dữ liệu nhạy cảm (VD Admin xem KYC document) | `actor_id`, `resource_type`/`resource_id`, `timestamp` — **không ghi nội dung tài liệu, chỉ ghi hành động xem** | Platform Admin | 5 năm | Append-only (module Seller Mgmt, ngoài phạm vi chi tiết US-002/003) | +| Ownership check thất bại (IDOR bị chặn) | `actor_id`/`session_id`, `resource_type`/`resource_id` bị yêu cầu, `ip_address`, `timestamp` — phục vụ điều tra khi nghi ngờ tấn công hàng loạt | Security (khi có người) | 🔴 chưa chốt — đề xuất 1 năm, thấp hơn nhóm tài chính vì mục đích khác (an ninh vận hành, không phải bằng chứng giao dịch) | Append-only | + +🔴 **Audit log mà người bị audit sửa được thì không phải audit log** — mỗi schema-per-module +(`ADR-006`) phải cưỡng chế `append-only` ở mức DB role của chính schema đó, không có ngoại lệ cho +`platform_admin` (Admin xem được nhưng không sửa/xoá được bản ghi audit). + +🔴 **Khoảng trống đã biết:** không có `CMP` Audit tập trung (phương án (a)) nghĩa là **không có +một nơi duy nhất** để Security truy vấn xuyên toàn sàn khi điều tra sự cố — mỗi module phải được +truy vấn riêng. Đây là đánh đổi đã chấp nhận TẠM ở `DEC-25`, chưa Security thật xác nhận. Nếu +Security khi có người yêu cầu audit tập trung, cần mở lại `OQ-047` và có thể đảo ngược sang +phương án (b) (`CMP-16`) — chi phí đảo ngược: thêm 1 service mới + migrate log lịch sử từ N schema +sang 1 nơi. + +--- + +## 8. Tuân thủ + +### 8.1 PCI-DSS SAQ A + +| Yêu cầu | Nguồn | Cách đáp ứng | Bằng chứng cho kiểm toán | Ai xác nhận | +|---|---|---|---|---| +| Không lưu PAN/CVV ở bất kỳ đâu ngoài Payment Service | `CON-06`, `BR-CART-05` (BA), `ADR-002` | `payment_transaction.gateway_response_snapshot` phải lọc trước khi ghi (`THR-19`); schema linter chặn cột kiểu "card_number"/"cvv" ở mọi schema khác `payment` | `FIT-04` (đã đề xuất ở `ADR-002`) | Security (chưa có người) | +| Ranh giới mạng/IAM/dữ liệu cô lập hoàn toàn | `ASR-002`, `ADR-002` | Network diagram + IAM policy review; không security group nào khác trỏ tới RDS Payment | `FIT-03` (đã đề xuất ở `ADR-002`) | Security | +| **Hình thức tích hợp VNPay/Momo phải là redirect, không nhúng iframe/form nhập thẻ trên domain sàn** *(đề xuất mới)* | Suy luận từ yêu cầu SAQ A (tham khảo `docs/08 §8.4`: "nếu redirect, scope tương ứng SAQ A") | **🔴 Chưa xác nhận được với VNPay/Momo thật** — chưa có tài liệu tích hợp, chưa biết họ có hỗ trợ redirect thuần hay bắt buộc SDK/iframe nào đó. Nếu chỉ hỗ trợ iframe/API pass-through dữ liệu thẻ, **toàn bộ giả định SAQ A của `ASR-002`/`ADR-002` phải xét lại** (có thể cần nâng cấp phạm vi tuân thủ, ảnh hưởng chi phí `TCO`) | — | Tech Lead + Security (`OQ-048`, mới) | +| Webhook: chữ ký/HMAC theo tài liệu đối tác | `ADR-004` | 🔴 **Chưa biết cơ chế cụ thể** (SecureHash/HMAC-SHA256/khác) — không bịa, chờ tài liệu đối tác | `THR-17` | `OQ-049` (mới), `ARISK-03` | +| Chống replay webhook | `ADR-004` | Kiểm tra `timestamp` payload lệch ≤5 phút (đã chốt, `ICD §1` mục 12) | `THR-18` | Đã đủ điều kiện kỹ thuật, chờ sandbox để kiểm chứng thật | +| Quét lỗ hổng ASV hàng quý | `CON-06` | Nhà cung cấp ASV bên ngoài — 🔴 chưa có báo giá | Báo cáo ASV | Security (`OQ-017`, đã mở ở `TCO`) | +| Pentest ứng dụng hàng năm | `CON-06` | Nhà cung cấp pentest bên ngoài — 🔴 chưa có báo giá | Báo cáo pentest | Security (`OQ-017`) | + +### 8.2 NĐ13/2023 (Bảo vệ dữ liệu cá nhân) + +| Yêu cầu | Nguồn | Cách đáp ứng | Bằng chứng | Ai xác nhận | +|---|---|---|---|---| +| Data minimization khi chia sẻ PII cho seller | `ASR-008`, `QAS-011`, `ADR-008` | Whitelist 3 trường (§5.2) — **đề xuất, chưa hiệu lực** | Contract test (`FIT-11`, đã đề xuất ở `ADR-008`) | **Security/Legal — chưa có người (`OQ-007`)** | +| Residency dữ liệu tại `ap-southeast-1` đáp ứng đủ yêu cầu | `CON-06`, `ASM-04` | 🔴 **Chưa xác nhận** — chỉ là giả định (`ASM-04`) | — | Legal (`OQ-007`) | +| Quyền được xoá / ẩn danh hoá | `CON-06` | Đề xuất 30 ngày ẩn danh hoá kể từ yêu cầu hợp lệ (`DAT §5`) — **đề xuất, chờ Legal** | — | Legal (`OQ-007`) | +| Xác thực danh tính người yêu cầu xoá (chống giả mạo yêu cầu xoá tài khoản người khác) | Ý tưởng tham khảo P1 (`docs/08 §8.2.4`), chưa thiết kế cụ thể cho P2 | 🔴 Chưa thiết kế | — | Legal + Tech Lead (mới, ngoài phạm vi US-002/003) | + +### 8.3 NĐ52/85 (thông báo website TMĐT marketplace) + +*Chủ yếu là nghĩa vụ pháp lý/hành chính (đăng ký với Bộ Công Thương), không phải control kỹ thuật +thuộc `SEC`. Yêu cầu kỹ thuật liên quan (hiển thị thông tin đăng ký ở footer) thuộc tầng UI/FE, +ngoài phạm vi tài liệu này.* + +--- + +## 9. Phụ thuộc & chuỗi cung ứng + +| | Quyết định | +|---|---| +| Quét lỗ hổng thư viện (SCA) | Trivy/Snyk/Dependabot trong CI/CD — đề xuất chặn build nếu phát hiện CVE mức **Critical** chưa có bản vá sau **7 ngày**, mức **High** sau **30 ngày** (đề xuất SA, chưa Tech Lead xác nhận) | +| Quét ảnh container | Trivy image scan trước khi push lên ECR — cùng ngưỡng chặn như trên | +| Chính sách vá lỗ hổng nghiêm trọng | Critical: ≤7 ngày · High: ≤30 ngày · Medium/Low: theo chu kỳ release thường | +| Ai duyệt thư viện mới | Tech Lead (theo `decision-radar.md §5` — "Công cụ, thư viện" thuộc Tech Lead, SA chỉ phủ quyết nếu chạm `QAS`) | +| Pentest năm + ASV quý | Xem §8.1 — chi phí chưa có báo giá (`OQ-017`, đã mở ở `TCO`) | + +--- + +## 10. Giả định & Ngoài phạm vi + +**Giả định** *(tiếp số toàn dự án — `ASM-01…38` đã dùng, bắt đầu `ASM-39`)*: + +| ID | Giả định | Cách xác minh | Nếu sai | +|---|---|---|---| +| `ASM-39` | VNPay/Momo hỗ trợ tích hợp dạng redirect thuần (không bắt buộc iframe/SDK truyền dữ liệu thẻ qua domain sàn), đủ điều kiện giữ SAQ A | Tech Lead xác nhận khi có tài liệu/sandbox thật (`OQ-048`, `ARISK-03`) | Nếu sai: phạm vi tuân thủ PCI-DSS phải nâng lên (SAQ A-EP hoặc cao hơn), ảnh hưởng trực tiếp `ASR-002`/`ADR-002`/chi phí `TCO` — cần rà lại toàn bộ `SEC §8.1` | +| `ASM-40` | Chưa có đủ traffic thật để hiệu chỉnh ngưỡng rate-limit (§5.3) — ba con số (30/10/10) là ước lượng dựa trên hành vi UI thông thường, không phải đo | Đo traffic thật 4-6 tuần đầu soft-launch, điều chỉnh lại | Nếu traffic thật khác biệt lớn (VD nhiều khách dùng chung IP NAT hơn dự kiến): cần tách ngưỡng theo `session_id` thuần, giảm phụ thuộc IP | +| `ASM-41` | Đề xuất PA-3 (service JWT) cho service-to-service authn (§2.4) không làm tăng đáng kể latency đường găng checkout (`QAS-002`) | Đo lại `QAS-002` sau khi có thiết kế cụ thể + `POC` nếu Tech Lead chấp nhận hướng này | Nếu tăng latency đáng kể: cần xét lại PA-2 (mTLS, chấp nhận thêm hạ tầng) hoặc thiết kế cache token phía service gọi | + +**Ngoài phạm vi:** + +- Threat model chi tiết cho các `CMP` ngoài "chi tiết nhất" (Seller Mgmt ngoài whitelist PII, + Commission & Payout, Promotion & Loyalty ngoài `IF-021`, Review, Notification) — chỉ có ở mức + ranh giới tin cậy (§1), chưa đào sâu STRIDE riêng. Sẽ bổ sung khi module tương ứng tới lượt + thiết kế chi tiết. +- Cơ chế chữ ký/HMAC cụ thể của VNPay/Momo/GHN/GHTK — **không bịa**, chờ tài liệu/sandbox đối tác + thật (`ARISK-03/04`, `OQ-049`). +- Hạ tầng cụ thể cho VPN/IP allowlist Admin, mã hoá in-transit ElastiCache, cấu hình IAM DB role + chi tiết theo schema — thuộc hoạt động `inf` (hoạt động 7, chưa chạy). +- Endpoint đọc `audit_log` tập trung, DPIA (Data Protection Impact Assessment) — ngoài phạm vi + US-002/003, ghi nhận là việc cần làm trước go-live (tham khảo `docs/08 §8.4`). +- Viết `ADR` chính thức cho service-to-service authn (§2.4) — chỉ đề xuất và ước lượng radar ở + đây, việc viết `ADR` thuộc hoạt động `adr` kế tiếp (ngoài phạm vi hoạt động `sec` được giao). + +--- + +## 11. Open Questions + +*Tiếp số sổ SA (`00-index/OQ_e-commerce.md` đang ở `OQ-047`) — bắt đầu `OQ-048`.* + +| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược | +|---|---|---|---|---|---| +| `OQ-048` | VNPay/Momo có hỗ trợ tích hợp dạng redirect thuần (không iframe/SDK nhập thẻ trên domain sàn) không — điều kiện để giữ phạm vi PCI-DSS SAQ A (`ASM-39`)? | Tech Lead + Security (khi có người) | 2026-09-15 | `SEC §8.1`; giả định nền của `ASR-002`/`ADR-002` | Nếu không hỗ trợ redirect thuần: phạm vi tuân thủ PCI-DSS phải nâng cấp, tăng chi phí audit/kiểm toán và có thể cần thiết kế lại luồng khởi tạo thanh toán | +| `OQ-049` | Cơ chế xác thực chữ ký/HMAC webhook cụ thể của VNPay, Momo, GHN, GHTK là gì (thuật toán, header, cách tính chữ ký)? | Tech Lead (khi có tài liệu đối tác) | 2026-09-15 | `THR-17`/`THR-22`; kiểm chứng `ADR-004` thật | Không có tài liệu: threat model webhook chỉ dừng ở mức nguyên tắc chung ("phải xác thực"), không kiểm chứng được cho tới khi có sandbox — rủi ro triển khai sai cơ chế lúc code | +| `OQ-050` | Chấp nhận đề xuất PA-3 (service JWT ngắn hạn ký bởi Identity & Access) cho service-to-service authn giữa Nhóm Giao dịch ↔ Nhóm Hỗ trợ ↔ Payment không, hay chọn PA-2 (mTLS/App Mesh, cần thêm hạ tầng)? | Tech Lead + Security + Ops/SRE | 2026-09-15 | `ADR` mới ở hoạt động `adr` kế tiếp; thiết kế `inf` cho TB3/TB4 | Chọn PA-3: rủi ro còn lại là chưa đạt mTLS full zero-trust, nhưng không cần hạ tầng mới ngay. Chọn PA-2: cần quyết định lại ràng buộc "không thêm hạ tầng mới" đã ghi ở `SAD §7` v1.2, tăng thời gian/chi phí triển khai | +| `OQ-051` | Xác nhận số cụ thể: TTL access token (đề xuất 15 phút), TTL refresh token (đề xuất 14 ngày), cơ chế thu hồi tức thời (đề xuất denylist Redis theo `jti`), tần suất xoay khoá ký JWT (đề xuất 90 ngày) | Tech Lead | 2026-09-15 | Thiết kế `CMP-02` (Identity & Access) khi tới lượt module đó; toàn bộ luồng authn Customer/Seller/Admin | Số quá ngắn (VD TTL 5 phút): tăng tần suất refresh, tăng tải Identity & Access. Số quá dài (VD TTL 60 phút không denylist): cửa sổ lợi dụng token bị đánh cắp dài hơn | +| `OQ-052` | Xác nhận ngưỡng account lockout theo vai trò (đề xuất: customer/seller 5 lần sai/15 phút; admin 3 lần sai/30 phút) và rate-limit login theo IP (đề xuất 10 request/phút) | Tech Lead + Security | 2026-09-15 | `THR-28/31`; thiết kế `CMP-02` | Ngưỡng quá chặt: tăng khiếu nại khách bị khoá oan (đặc biệt IP NAT dùng chung). Ngưỡng quá lỏng: tăng rủi ro brute-force thành công | +| `OQ-053` | Ba trường whitelist chia sẻ cho seller (`recipient_name`/`phone`/`address_line`, `ADR-008` PA-2) hiển thị đầy đủ hay che một phần (VD số điện thoại che 3-4 số giữa)? | Security/Legal (khi có người) + PO | 2026-09-15 | `DAT §5.2`; UI hiển thị đơn hàng cho Seller (ngoài phạm vi US-002/003) | Hiển thị đầy đủ: seller đủ thông tin giao hàng nhưng tăng bề mặt rủi ro nếu tài khoản seller bị lộ. Che một phần: giảm rủi ro nhưng có thể gây khó khăn thao tác giao hàng thực tế (VD shipper cần gọi điện xác nhận) | + +**Cập nhật cho `OQ` đã mở:** + +- **`OQ-007`** — SEC bổ sung: toàn bộ §5, §8.2 của tài liệu này là **đề xuất chờ phủ quyết**; + không coi bất kỳ phân loại/whitelist/mã hoá nào ở đây là đã "Security xác nhận". **Giữ nguyên + mở.** +- **`OQ-023`** — SEC trả lời bằng đề xuất số cụ thể ở §5.3 (30 req/phút Guest cart, kèm hệ quả cả + hai chiều) — **không tự quyết thay Security**, `OQ-023` **giữ nguyên mở**, chờ Security xác + nhận hoặc điều chỉnh. +- **`OQ-024`** (MFA Admin) — SEC xác nhận lại hướng TẠM TOTP app (`ASM-20`, `DEC-14`) và bổ sung + chi tiết backup code (§2 bảng, chưa thiết kế đầy đủ) — **giữ nguyên mở**, chờ Security thật. + +**Nhắc:** cộng với các `OQ` còn mở ảnh hưởng trực tiếp `SEC` — `OQ-007` (PII/residency, chặn phần +lớn §5/§8.2), `OQ-017` (báo giá pentest/ASV, chặn §8.1/§9), `ARISK-03/04` (sandbox đối tác, chặn +kiểm chứng `THR-17/18/22`) — xem sổ đầy đủ `00-index/OQ_e-commerce.md`. + +**Nhắc AG2:** cần **Tech Lead + Security + Ops/SRE ký** — còn thiếu `INF` (hoạt động 7) và toàn bộ +`ADR` liên quan `SEC` (`ADR-002/004/007/008` vẫn `Proposed`; `ADR` service-to-service authn §2.4 +chưa viết). + +--- + +## Tự chấm + +### ① Bảng tự chấm Gate AG2 *(`workflow.md §2` — chỉ dòng liên quan tới `SEC`, tự chấm sớm)* + +| # | Tiêu chí | ☐/✅ | Ghi chú | +|---|---|---|---| +| — | `ASR`/`QAS`/`SAD`/`ICD`/`DAT`/`FAIL` | ✅ *(đã đạ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 | 13 `ADR` đã viết (bao gồm `ADR-002/004/007/008/011` liên quan bảo mật); `SEC` phát hiện **1 quyết định mới đạt ngưỡng ADR** chưa viết — service-to-service authn (§2.4, radar ~5), ghi `OQ-050` | +| — | `INF` | ☐ | Chưa tới — hoạt động 7 | +| 1 | `SEC` — có threat model STRIDE cho luồng nhạy cảm; mô hình authn/authz đã chốt; **Security ký** | ☐ | Threat model STRIDE đủ 8 ranh giới, 31 `THR` (§4); mô hình authn/authz đã **đề xuất đầy đủ** (§2, §3) nhưng **chưa chốt** ở nhiều điểm (`OQ-050/051/052/053`) và **Security chưa ký** (`OQ-007`, không có người) — đây là điều kiện chặn cứng nhất của AG2 theo `SKILL.md` ("Security có quyền phủ quyết AG2") | +| — | `sa-conformance` báo coverage `ASR → ADR/CMP` ≥ 100% | *(không đổi bởi `SEC`)* | `SEC` không tạo `CMP`/`ASR` mới; có đề xuất 1 `ADR` mới (service-authn) chưa viết | + +**Kết luận tự chấm (riêng phần `SEC`):** Hoạt động `sec` hoàn tất đúng phạm vi được giao — threat +model STRIDE đủ 8 ranh giới tin cậy yêu cầu (31 `THR`), mô hình authn/authz đầy đủ cho Guest/ +Customer/Seller/Admin + phát hiện khoảng trống service-to-service authn (mới, `OQ-050`), map đủ +2/2 `ROLE-nn` của `RBAC_CartCheckout`, PCI-DSS/NĐ13/2023 rà theo yêu cầu (mọi kết luận PII đánh +dấu "đề xuất chờ Legal"), audit log + secret management + chuỗi cung ứng đã chốt trường/chính +sách đề xuất. **AG2 còn xa** vì (a) `INF` (hoạt động 7) chưa chạy, (b) Security **chưa có người** +(`OQ-007`) nên **không ai có quyền phủ quyết/ký** — đây là điều kiện chặn nghiêm trọng nhất, đúng +cảnh báo của `GUIDE.md`: "phát hiện muộn nhất và đau nhất luôn đến từ đây." + +### ② Checklist D1–D12 *(`design-rules.md`)* + +| # | Mục | ☐/✅ | Ghi chú | +|---|---|---|---| +| D1 | Một ADR một quyết định | N/A | `SEC` không viết `ADR` mới ở lượt này — chỉ đề xuất 1 `ADR` ứng viên (service-authn, §2.4) cho hoạt động `adr` kế tiếp | +| D2 | Không NFR định tính | ✅ | Mọi ngưỡng (rate-limit, TTL token, lockout) đều có con số hoặc đánh dấu rõ "chưa chốt" kèm `OQ` — không có mục nào ghi "bảo mật tốt" chung chung | +| D3 | Nêu phương án bị loại + lý do | ✅ | §2.4 (3 phương án service-authn, PA-1/PA-2 bị loại có lý do gắn ràng buộc `SAD §7`) | +| D4 | Sơ đồ khai báo mức + legend | ✅ | §1 khai báo rõ "ranh giới tin cậy" (`flowchart LR` theo `D4`), có legend | +| D5 | Interface có chủ/contract | N/A | Đã xử lý ở `ICD` (hoạt động 4); `SEC` chỉ bổ sung khía cạnh xác thực/authz cho các `IF` đã có | +| D6 | Phụ thuộc ngoài process có timeout/retry | N/A | Đã xử lý ở `FAIL` (hoạt động 8); `SEC` chỉ bổ sung khía cạnh threat/xác thực | +| D7 | Một chủ sở hữu dữ liệu | N/A | Đã xử lý ở `DAT` (hoạt động 5); `SEC` chỉ tham chiếu khi thiết kế IAM theo schema (§4.7) | +| D8 | Ràng buộc có FIT hoặc nhãn khuyến nghị | 🟡 Một phần | Đề xuất `FIT-29` (secret scan), `FIT-30` (service-authn test, chờ `OQ-050`), `FIT-31` (webhook signature test, chặn bởi `ARISK-03/04`), `FIT-32` (audit completeness), `FIT-33` (TLS/HSTS config test) — ứng viên GĐ3, chưa viết thật; các threat chưa có biện pháp đủ (`THR-09/13/17/22`) đánh dấu rõ "chưa kiểm chứng được", không giả vờ đã có `FIT` | +| D9 | Con số hạ tầng quy ra tiền + nguồn | N/A | `SEC` không thêm con số hạ tầng mới (Secrets Manager/WAF đã có trong `TCO`/`SAD` từ trước) | +| D10 | Không quyết định thay người có thẩm quyền | ✅ | Mọi kết luận PII/residency đánh dấu "đề xuất chờ Legal/Security" (§5, §8.2); rate-limit (§5.3), account lockout (§2.3), service-authn (§2.4) đều trình phương án kèm hệ quả hai chiều, không tự quyết; §4.9 để trống vì không tự chấp nhận rủi ro thay Security | +| D11 | Có mục "Ngoài phạm vi" + `ASM-nn` | ✅ | §10 đầy đủ — `ASM-39…41` mớ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 — `RBAC` ↔ `SEC` + +| `RBAC_CartCheckout` (BA) | Nội dung | `SEC` tương ứng | Khớp? | Hành động | +|---|---|---|---|---| +| §1 (2 vai trò: Guest, Customer) | Ma trận vai trò | §3.1 (map đủ `ROLE-01/02`) | ✅ | Không lệch — 2/2 `ROLE-nn` có dòng map, đúng yêu cầu "mỗi `ROLE-nn` phải có đúng một dòng, thiếu ⇒ chặn AG2" | +| §2 (không ai xem giỏ/đơn người khác) | Ranh giới ownership | §3 (fail-closed), `THR-07` | ✅ | Khớp — `ASR-007`/`ADR-007` đã hiện thực hoá đúng | +| §3 (SoD không áp dụng) | Tự phục vụ, không có duyệt kép | §3.2 | ✅ | Kế thừa nguyên trạng kết luận của BA, không lệch | +| §4 (mức che PII cho seller — chưa chốt) | Whitelist chưa quyết định mức che | §5.2, `OQ-053` (mới) | 🟡 Một phần | `SEC` xác nhận whitelist 3 trường (`ADR-008`) nhưng **mức che cụ thể vẫn chưa chốt** như BA đã ghi nhận — **BA không cần sửa `RBAC`**, câu hỏi này tiếp tục do Security/Legal quyết định khi có người | +| §5 (lưu vết — "chưa chốt thời hạn") | Audit log cho `Order`/`Payment` | §7 (10 năm, append-only) | 🟡 Một phần | `SEC` đề xuất retention cụ thể (10 năm) — **BA có thể cập nhật `RBAC_CartCheckout §5`** tham chiếu `SEC §7` khi retention được Security/Tech Lead xác nhận thật | +| §6 (hành vi khi không đủ quyền) | 403/không hiển thị dữ liệu | §3 (fail-closed 503 cho lỗi kỹ thuật, phân biệt với 403 thật) | ✅ Bổ sung | `SEC` làm rõ thêm trường hợp BA chưa phân biệt (lỗi kỹ thuật khi kiểm tra ownership ≠ "không có quyền" thật) — **BA nên bổ sung `AC` mới cho `E-CART-0007`** (đã ghi ở `FAIL`, nhắc lại ở đây) | +| §8 `OQ-012` (Guest OTP đơn giá trị cao) | Chưa chốt | *(ngoài phạm vi `SEC` — thuộc `BR-CART-03`, quyết định PO)* | ➖ N/A | Không hành động — đây là quyết định nghiệp vụ, không phải kiến trúc bảo mật | +| §8 `OQ-015` (chống lạm dụng Guest checkout) | Chưa chốt | §5.3 (đề xuất rate-limit checkout 10/phút) | ✅ Trả lời | `SEC` đã đề xuất số cụ thể — **BA có thể đóng `OQ-015` trong sổ BA**, tham chiếu `SEC §5.3`, với điều kiện Security xác nhận số cuối cùng | +| §8 `OQ-016` (mức che PII cho seller) | Chưa chốt | Trùng với `RBAC §4` ở trên | 🟡 Một phần | Cùng trạng thái — chờ Security/Legal, xem `OQ-053` (SA) | + +### ④ Danh sách `OQ` mở kèm người phải trả lời, chặn gì + +Xem §11 (`OQ-048…053` mới) cộng cập nhật `OQ-007/023/024`. Ba câu hỏi quan trọng nhất cho AG2: +**`OQ-007`** (chưa có người Security/Legal — chặn toàn bộ hiệu lực phủ quyết của `SEC`), +**`OQ-050`** (service-to-service authn — khoảng trống kiến trúc mới phát hiện, ảnh hưởng TB3/TB4 +nơi PII và tiền đi qua), **`OQ-048`/`OQ-049`** (chưa có tài liệu/sandbox đối tác thanh toán/vận +chuyển thật — chặn kiểm chứng phần lớn threat model TB5/TB6). Sổ đầy đủ: `00-index/OQ_e-commerce.md`. + +**Nhắc:** AG2 cần **Tech Lead + Security + Ops/SRE ký** — còn thiếu `INF` (hoạt động 7) và **chưa +có người Security** để ký bất kỳ phần nào của `SEC`. Đây là rủi ro tiến độ nghiêm trọng nhất của +toàn GĐ2: theo `GUIDE.md`, "Bước `sec` cần một người thật từ Security ngồi cùng" — điều này **chưa +xảy ra** trong suốt hoạt động `sec` vừa chạy, toàn bộ nội dung là công việc chuẩn bị một chiều của +SA, chờ người đó xuất hiện. diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-001_kieu-kien-truc-tong-the-modular-monolith-p2.md b/sa-output/e-commerce/02-architecture/adr/ADR-001_kieu-kien-truc-tong-the-modular-monolith-p2.md new file mode 100644 index 0000000..427ded4 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-001_kieu-kien-truc-tong-the-modular-monolith-p2.md @@ -0,0 +1,206 @@ +# ADR-001 — Kiểu kiến trúc tổng thể của sàn e-commerce là Modular Monolith + managed AWS (P2), không phải ~10 Microservices độc lập (P1) + +*Tên file: `adr/ADR-001_kieu-kien-truc-tong-the-modular-monolith-p2.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | SA + Tech Lead (theo `decision-radar.md` §5 — "Cấu trúc hệ thống" đề xuất SA, chốt SA+Tech Lead; EA phủ quyết nếu lệch chuẩn doanh nghiệp). **Chưa ký thật** — chỉ có Điều phối dự án ký thay theo ngoại lệ `DEC-01`/`DEC-17`, xem §Điều kiện chuyển Accepted | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **~7/10** *(chấm lại theo `decision-radar.md §2` — xem §Radar dưới; dưới ngưỡng 8 cứng nhưng vẫn cần POC vì `ASM-07`/`ASM-08` chưa xác minh)* | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-001` · `QAS-005` · `QAS-006` · `QAS-009` · `CON-03` · `CON-05` · `CON-06` · `DRV-04` · `DEC-06` · `POC-01` · `POC-02` · `OQ-010` · `OQ-012` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-001` và đổi trạng thái bản cũ thành `Superseded by`. Không sửa nội dung +> ADR đã Accepted, không xoá ADR đã Rejected. + +--- + +## 1. Bối cảnh + +Sàn e-commerce là dự án greenfield (`CTX §4.1`), quy mô mục tiêu "lớn" (`DRV-04`: hàng trăm +nghìn SKU, hàng trăm nghìn–hàng triệu user, đỉnh hàng nghìn–chục nghìn concurrent user mùa flash +sale — kịch bản A 2.000 CCU/~400 đơn/giờ, kịch bản B 10.000 CCU/~15.000 đơn/giờ, `QAS-009`). +`OPT_e-commerce_v1.0.md` (Bước 4 GĐ1) đã dựng và chấm điểm 3 phương án khả thi (P0/P1/P2) cộng +2 phương án bị loại ở gate cứng (P3/P4) — kết luận khuyến nghị **P2** (modular monolith 2–3 nhóm +ECS Fargate + managed AWS, Payment tách riêng), duyệt từng phần bởi PO uỷ quyền tại `DEC-06`, +nhưng `DEC-06` tự ghi rõ **chưa thay thế** yêu cầu `ADR` chính thức (kiểu kiến trúc tổng thể là +quyết định thuộc danh mục bắt buộc `ADR` theo `decision-radar.md §3`). `ASR-001` (chưng cất từ +`DEC-06`) xác nhận đây là ràng buộc cấu trúc bao trùm toàn bộ hệ thống, ép ra ranh giới container +ở `SAD §4`. ADR này **trả nợ** `DEC-06`/`DTM §11 "🟠 Nợ #1"`/`ADL §8` — không phải quyết định +mới, mà là hình thức hoá quyết định đã có hướng đi tạm. + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `CON-03` | Cloud AWS bắt buộc (cứng) — loại mọi phương án ngoài AWS ngay từ `OPT` | +| `CON-05` | Số đội/số người thi công **chưa xác nhận thật** — giả định tạm "team MVP chuẩn" (`DEC-02`), tham khảo hồ sơ thầu: BE trung bình ~2,6 FTE/tháng trên 7 tháng, đỉnh 10 người toàn dự án | +| `CON-06` | PCI-DSS SAQ A + NĐ13/2023 — Payment phải là biên cô lập bất kể chọn P1 hay P2 (áp dụng độc lập với ADR này, xem `ADR-002`) | +| `ASR-001` | Ép ranh giới triển khai 2–3 nhóm ECS Fargate + 1 nhóm Payment riêng; ép dùng SQS/EventBridge thay Kafka/MSK; ép 1 RDS chính schema-per-module | +| `QAS-005`/`QAS-006`/`QAS-009` | Thông lượng/độ trễ/khả năng mở rộng phải đạt ở kịch bản A/B — input trực tiếp cho `POC-01`/`POC-02` | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| AWS là cloud bắt buộc | 🟢 Đã kiểm chứng | `CON-03`, xác nhận vòng 3 Q&A brief | +| Payment phải cô lập PCI-DSS SAQ A | 🟢 Đã kiểm chứng | `CON-06`, pháp luật/hợp đồng đối tác | +| SQS FIFO + EventBridge đủ throughput cho `OrderPlaced`/`PaymentConfirmed` ở tải đỉnh | 🔴 Giả định (`ASM-07`) | `POC-01` — **chưa chạy** | +| 1 cụm RDS chính đủ tải ghi/đọc gộp | 🔴 Giả định (`ASM-08`) | `POC-02` — **chưa chạy** | +| Team thi công thật khớp giả định "team MVP chuẩn" (`DEC-02`) | 🔴 Giả định | `OQ-010` — Tech Lead chưa xác nhận | +| P2 rẻ hơn P1 ở TCO 3 năm (sơ bộ, số lượng thành phần) | 🟡 Ước lượng có cơ sở | `TCO §3.2` (chưa quy đổi VND đầy đủ, đơn giá AWS chưa xác nhận `OQ-013`) | + +## 2. Phương án đã cân nhắc + +*Tham chiếu đầy đủ bảng chấm điểm và sơ đồ mức khối đã có ở `OPT_e-commerce_v1.0.md §3, §4, §5` +— **không lặp lại** ở đây theo đúng ghi chú người duyệt. Tóm tắt lại đúng mức cần để ra quyết +định.* + +### PA-1 — P1: Modular microservices (~10 service, database-per-service, Kafka/MSK, OpenSearch) + +| | | +|---|---| +| **Mô tả** | ~10 service theo bounded-context, mỗi service 1 RDS logic riêng, Kafka/MSK làm xương sống bất đồng bộ, OpenSearch đa node cho search, ECS/EKS auto-scaling theo domain — theo `SAD.md` v0.2/hồ sơ thầu (`OPT §3` P1) | +| **Ưu** | Đáp ứng `DRV` Must cao nhất (`OPT §4`: điểm 5/5) — scale-out **độc lập** Catalog/Search khỏi Cart/Checkout ngay từ ngày một (`DRV-04`); ranh giới service rõ, dễ thay/rút từng service riêng lẻ về sau | +| **Nhược** | Vi phạm Conway rõ với team giả định hiện tại — mỗi BE ôm trung bình 3–4 service (`CON-05`, `OPT §4` tiêu chí 5: P1=2/5); không có bằng chứng team từng vận hành Kafka/MSK/OpenSearch/EKS production (`CTX §4.4`, `OQ-010` mở); effort dựng nền tảng riêng đã ước 70,2 MD (`WBS-03`, XL, +35% contingency) trước khi làm nghiệp vụ; nhiều thành phần managed độc lập phải vận hành hơn | +| **Chi phí đảo ngược** | Gộp ngược lại thành ít service hơn (nếu team quá nhỏ để vận hành 10 service) tốn công tái cấu trúc network/DB đáng kể — ước > 4 tuần | + +### PA-2 — P2: Modular monolith (2–3 nhóm ECS Fargate) + managed AWS, Payment tách riêng *(chọn)* + +| | | +|---|---| +| **Mô tả** | Modular monolith theo domain, chạy 2–3 nhóm ECS Fargate (Nhóm Giao dịch / Nhóm Hỗ trợ), SQS FIFO + EventBridge thay Kafka/MSK, 1 RDS chính schema-per-module, Postgres FTS giai đoạn đầu (hoãn OpenSearch); Payment tách hoàn toàn (network/IAM/DB riêng) — theo `OPT §3` P2 | +| **Ưu** | Khớp Conway với team giả định (`OPT §4` tiêu chí 5: P2=5/5); effort nền tảng thấp hơn P1 (-70,2 MD, không cần dựng cụm Kafka/MSK); ít thành phần managed độc lập phải vận hành hơn (chi phí vận hành sơ bộ thấp hơn); rủi ro công nghệ thấp hơn (managed service phổ biến hơn) | +| **Nhược** | Thua P1 đúng 1 bậc ở tiêu chí "Đáp ứng `DRV` Must" (4/5 so với 5/5, `OPT §4`) — scale-out **độc lập** Catalog/Search khỏi Cart/Checkout **kém hơn** ở giai đoạn đầu (chung nhóm "Nhóm Giao dịch"); nếu traffic thật vượt xa dự kiến, tách Catalog/Search ra khỏi monolith muộn sẽ tốn hơn tách từ đầu | +| **Chi phí đảo ngược** | Module hoá rõ theo domain trong code giúp tách thành service riêng về sau **có kế hoạch** khi có bằng chứng tải thật — nhưng tốn công tách hạ tầng (network, DB, CI/CD riêng) tại thời điểm tách, không miễn phí; ước > 4 tuần nếu tách toàn diện | + +### PA-0 — Không xây gì (P0, mốc so sánh) + +Vi phạm trực tiếp `DRV-01` (Must, blocker MVP) — không phải phương án khả thi, chỉ giữ làm mốc +so sánh (`OPT §4`). Không xét tiếp. + +### Bảng so sánh *(tóm tắt — chi tiết đầy đủ 6 tiêu chí × trọng số ở `OPT §4`)* + +| Tiêu chí *(trọng số)* | P1 | P2 | +|---|---|---| +| Đáp ứng `DRV` Must (25%) | 5 | 4 | +| Chi phí 3 năm sơ bộ (20%) | 2 | 4 | +| Thời gian tới bản chạy được (15%) | 2 | 4 | +| Rủi ro kỹ thuật (15%) | 2 | 4 | +| Năng lực team & vận hành — Conway (15%) | 2 | 5 | +| Khả năng tiến hoá (10%) | 4 | 3 | +| **Tổng có trọng số** | **2.95** | **4.05** | + +Chênh lệch 1.10 điểm — đủ phân biệt theo `OPT §4` (không rơi vào bẫy "chênh <0.3"). + +## 3. Quyết định + +> **Chọn PA-2 (P2) — Modular monolith + managed AWS, Payment tách riêng.** + +Toàn sàn e-commerce được tổ chức thành 2–3 nhóm triển khai ECS Fargate (modular monolith theo +domain — Nhóm Giao dịch: Identity & Access, Catalog & Inventory, Cart & Order; Nhóm Hỗ trợ: +Seller Management, Commission & Payout, Promotion & Loyalty, Review, Notification, Shipping & +Fulfillment), cộng 1 Payment Service tách hoàn toàn về mạng/IAM/dữ liệu. Dùng SQS FIFO + +EventBridge (không phải Kafka/MSK) và 1 cụm RDS PostgreSQL chính schema-per-module (không phải +database-per-service). + +**Vì sao:** Khớp `CON-05` (Conway — năng lực team giả định hiện tại), giữ nguyên `CON-06` (Payment +cô lập, độc lập với lựa chọn này), và đạt điểm tổng cao nhất trong bộ tiêu chí đã chốt ở `OPT §2` +(4.05 so với 2.95 của P1). + +**Phạm vi áp dụng:** Toàn bộ sàn e-commerce, đến khi traffic thật tiệm cận kịch bản B × 2 +(~20.000 concurrent) mà chưa kiểm chứng lại bằng POC/bài đo thật (xem `QAS-009` "Ngoài phạm vi"). + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| `POC-01` PASS (throughput SQS FIFO/EventBridge ≥100 msg/s sustained, p99 ≤2s, 0 mất message) | Tech Lead + 1 DevOps | **Chưa chạy** (`ARISK-01`, `OQ-012`) | +| `POC-02` PASS (RDS gộp: p95 write ≤300ms, p95 read ≤200ms, CPU <75%) | Tech Lead/DBA | **Chưa chạy** (`ARISK-02`) | +| `OQ-010` — Tech Lead xác nhận team thi công thật khớp (hoặc gần khớp) giả định "team MVP chuẩn" | Tech Lead | Mở | +| AG1 ký thật (PO + Tech Lead, không phải ký thay) | PO + Tech Lead | Mở (`OQ-004`) | + +🔴 Dù radar ước lượng ~7 (< 8 ngưỡng cứng), ADR này **vẫn không được chuyển `Accepted`** cho tới +khi cả hai `POC` chạy xong — vì bản thân `ASM-07`/`ASM-08` (nền tảng của toàn bộ lựa chọn P2) +chưa xác minh; đây là cam kết đã ghi tại `OPT §1` "Điều kiện kèm theo" và `DEC-06`. + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| P0 — Không xây gì | Vi phạm trực tiếp `DRV-01` (Must, blocker MVP) | `DRV-01` | Không xét lại — không phải phương án khả thi cho một sàn giao dịch | +| P1 — Modular microservices (~10 service) | Vi phạm Conway với team giả định hiện tại (`CON-05`, mỗi BE ôm 3–4 service); không có bằng chứng team từng vận hành Kafka/MSK/OpenSearch/EKS production (`CTX §4.4`) | `CON-05`, `OPT §4` tiêu chí 4/5 | Nếu `OQ-010` xác nhận team thật có kinh nghiệm Kafka/MSK/OpenSearch/EKS production **và** team đủ lớn (gần đỉnh 10 người đề xuất hồ sơ thầu) — chấm lại theo `OPT §9 OQ-010` | +| P3 — Mua/tích hợp nền tảng mã nguồn mở | Loại ở gate cứng `OPT §2.1` — không kiểm chứng được cô lập Payment cho PCI-DSS SAQ A (`CON-06`) mà không sửa sâu lõi | `CON-06` | Nếu Tech Lead xác nhận kinh nghiệm sâu với một nền tảng cụ thể **và** POC chứng minh cô lập Payment đạt SAQ A — xét lại cho module không nhạy cảm tài chính (`OPT §5`) | +| P4 — Serverless-first (Lambda/Step Functions/DynamoDB) | Cold-start Lambda ảnh hưởng `DRV-02` (bỏ giỏ) chưa có POC đo trong ngữ cảnh VPC+RDS; chưa có bằng chứng năng lực team serverless-at-scale (`CON-05`) | `DRV-02`, `CON-05` | Nếu có POC đo cold-start đạt yêu cầu và Tech Lead xác nhận năng lực — xét lại cho luồng bất đồng bộ thuần (Notification, Commission batch) như lựa chọn lai, không toàn hệ thống (`OPT §5`) | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Số đơn vị triển khai cần vận hành/on-call giảm từ ~10 (P1) xuống ~3 (2–3 nhóm monolith + + Payment) — khớp trực tiếp FTE DevOps trung bình thấp (~0,7 FTE, `TCO`/hồ sơ thầu) +- Effort tới bản chạy được thấp hơn P1 khoảng 70,2 MD (không cần dựng cụm Kafka/MSK) +- Rủi ro công nghệ thấp hơn — managed service phổ biến hơn (RDS, SQS/EventBridge, ECS Fargate) + +**Hệ quả tiêu cực phải sống chung** + +- Scale-out **độc lập** Catalog/Search khỏi Cart/Checkout kém hơn P1 ngay từ ngày một — nếu flash + sale gây tải lệch mạnh giữa Catalog và Cart&Order, cả hai vẫn scale chung trong "Nhóm Giao dịch" + cho tới khi tách (xem `ASR-014`/`ADR-012`) +- Nếu `POC-01`/`POC-02` FAIL: phải bổ sung kiến trúc lai (Kafka/MSK riêng cho hot-path đặt hàng, + hoặc tách read replica sớm hơn dự kiến) — không quay lại P1 hoàn toàn (`OPT §1`) + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Tách toàn bộ modular monolith thành microservices sau go-live | Tái cấu trúc network/DB/CI-CD riêng biệt cho từng module — ước > 4 tuần, có rủi ro downtime khi tách | +| Đổi lại SQS/EventBridge sang Kafka/MSK sau khi đã có producer/consumer thật | Viết lại toàn bộ tầng tích hợp bất đồng bộ — xem `ADR-005` (quyết định riêng, không lặp ở đây) | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Chạy `POC-01`/`POC-02` theo tiêu chí PASS/FAIL đã viết trước | Tech Lead + DevOps/DBA | Trước khi ADR này chuyển `Accepted` | `ARISK_e-commerce_v1.0.md §6` | +| Xác nhận `OQ-010` (team thật) | Tech Lead | Trước khi `Accepted` | `00-index/OQ_e-commerce.md` | +| Thêm fitness function kiểm tra ranh giới module (không cho import chéo giữa domain package) | SA + Tech Lead | GĐ3 (`AGD`/`FIT`) | `FIT-01` (ứng viên) | +| Kế hoạch tách Catalog/Search nếu traffic vượt ngưỡng B×2 | Tech Lead | Khi có bằng chứng traffic thật | `TDEBT` (GĐ3) | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Không có import chéo trực tiếp DB giữa các domain package trong monolith (chỉ qua API nội bộ/event) | dependency-cruiser hoặc ArchUnit-style rule | CI | `FIT-01` (ứng viên, GĐ3) | +| Số đơn vị triển khai (ECS service) đúng 2–3 nhóm + 1 Payment, không phình thêm không kiểm soát | Kiểm tra hạ tầng (Terraform plan review) | CI/CD pipeline | `FIT-02` (ứng viên) | +| `POC-01`/`POC-02` — bài đo throughput/tải | k6/artillery, load test staging | Trước go-live, lặp lại trước mỗi major release | — (kết quả ghi vào `ARISK §6`) | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Traffic thật tiệm cận kịch bản B × 2 | ~20.000 concurrent user | Tech Lead/SRE | +| `POC-01` hoặc `POC-02` FAIL | Không đạt tiêu chí PASS đã viết trước (`ARISK §6`) | Tech Lead | +| Team thật khác biệt đáng kể so với giả định "team MVP chuẩn" | Số BE thật < 50% giả định `DEC-02`, hoặc > gấp đôi | Tech Lead/PM | + +## 8. Tham chiếu + +- POC: `ARISK_e-commerce_v1.0.md §6 POC-01, POC-02` +- Bài đo: chưa chạy — xem §Điều kiện chuyển Accepted +- Tài liệu ngoài: `OPT_e-commerce_v1.0.md` §1, §3, §4, §5 (bảng chấm điểm đầy đủ, không lặp lại) · + `SAD_e-commerce_v1.0.md §2, §4` (hiện thực hoá quyết định này thành C4 Container) +- Thảo luận: `DEC-06` (00-index/DEC_e-commerce.md), duyệt từng phần 2026-09-12 + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung đủ làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`) | Chưa có chữ ký thật Tech Lead; `POC-01`+`POC-02` chưa chạy; `OQ-010` (team thật) chưa xác nhận | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: 🔴 — +> `AG2` chưa ký. diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-002_payment-service-bien-co-lap-pci-dss.md b/sa-output/e-commerce/02-architecture/adr/ADR-002_payment-service-bien-co-lap-pci-dss.md new file mode 100644 index 0000000..9f709e0 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-002_payment-service-bien-co-lap-pci-dss.md @@ -0,0 +1,167 @@ +# ADR-002 — Payment Service là biên cô lập mạng/IAM/dữ liệu riêng cho PCI-DSS SAQ A + +*Tên file: `adr/ADR-002_payment-service-bien-co-lap-pci-dss.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | **Security** (theo `decision-radar.md §5` — "Bảo mật, quyền riêng tư": đề xuất SA, chốt Security, phủ quyết Security). **Chưa có Security thật ký** — chỉ Điều phối dự án ký thay theo `DEC-01`/`DEC-17` | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **~7/10** | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-002` · `CON-06` · `BR-CART-05` (BA) · `ADR-001` (độc lập với kiểu kiến trúc tổng thể) | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-002` và đổi trạng thái bản cũ thành `Superseded by`. + +--- + +## 1. Bối cảnh + +Sàn phải chấp nhận thanh toán VNPay/Momo/COD **không lưu thông tin thẻ** để giảm phạm vi tuân +thủ PCI-DSS xuống mức SAQ A (`CON-06`, `DRV-03`) — đây là ràng buộc pháp lý/hợp đồng, không +thương lượng được, và **độc lập với việc chọn P1 hay P2** ở `ADR-001`: dù kiểu kiến trúc tổng thể +là gì, Payment vẫn phải là một biên cô lập. `BR-CART-05` (BA) đã ghi phát biểu nghiệp vụ: hệ +thống sàn không được lưu số thẻ/CVV; mọi xử lý thẻ do VNPay/Momo thực hiện, sàn chỉ lưu +`gateway_transaction_ref` + kết quả. + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `CON-06` | PCI-DSS SAQ A (không lưu thẻ) + NĐ13/2023 — cứng, không thương lượng | +| `ASR-002` | Payment phải là ranh giới mạng + IAM + dữ liệu (RDS riêng) hoàn toàn tách biệt | +| `BR-CART-05` (BA) | Không lưu số thẻ/CVV; chỉ lưu `gateway_transaction_ref` + kết quả | +| `QAS-011` | 100% trường PII rà soát trước khi chia sẻ — liên quan gián tiếp (Payment không giữ PII giao hàng) | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| PCI-DSS SAQ A + không lưu thẻ là ràng buộc cứng | 🟢 Đã kiểm chứng | `CON-06`, pháp luật + hợp đồng đối tác | +| Payment cô lập network/IAM/DB là cách duy nhất khả thi để giữ SAQ A trong một kiến trúc chung (monolith/microservices) | 🟡 Ước lượng có cơ sở | Thực hành PCI-DSS phổ biến (segmentation) — chưa có audit chính thức từ QSA/ASV | +| VNPay/Momo có sandbox thật để kiểm chứng luồng redirect+IPN không lưu thẻ | 🔴 Giả định | `CON-04`, chưa có sandbox (`CTX §4.2`) | + +## 2. Phương án đã cân nhắc + +### PA-1 — Payment là module trong monolith, không tách mạng/IAM riêng + +| | | +|---|---| +| **Mô tả** | Payment logic nằm chung namespace/package với Cart & Order trong cùng monolith, chỉ tách bằng ranh giới code (package riêng), dùng chung RDS/network/IAM | +| **Ưu** | Đơn giản triển khai hơn — không cần network segmentation riêng, ít thành phần hạ tầng hơn | +| **Nhược** | **Không kiểm chứng được** phạm vi PCI-DSS thu hẹp — một lỗ hổng ở bất kỳ module nào trong cùng network/IAM có thể mở rộng phạm vi audit PCI-DSS ra toàn bộ hệ thống (vi phạm mục tiêu giảm phạm vi của `DRV-03`) | +| **Chi phí đảo ngược** | Tách ra sau khi đã gộp nhầm cần audit lại toàn bộ luồng thẻ + di chuyển dữ liệu/network — ước > 4 tuần, có rủi ro downtime | + +### PA-2 — Payment Service là container riêng, network + IAM + RDS riêng hoàn toàn *(chọn)* + +| | | +|---|---| +| **Mô tả** | Payment chạy trên ECS Fargate riêng, subnet/security group riêng, IAM role riêng, RDS riêng nhỏ — không service nào khác trong hệ thống truy cập trực tiếp RDS Payment; mọi module khác chỉ nhận `gateway_transaction_ref`/`status` qua API/event | +| **Ưu** | Phạm vi audit PCI-DSS SAQ A thu hẹp rõ ràng, kiểm chứng được bằng network diagram + IAM policy review; độc lập với `ADR-001` (áp dụng dù chọn P1 hay P2) | +| **Nhược** | Thêm một đơn vị triển khai riêng phải vận hành (đã tính vào `ADR-001`/`TCO`); mọi thay đổi cần gọi API/event thay vì truy cập DB trực tiếp — thêm độ trễ mạng cho luồng khởi tạo thanh toán | +| **Chi phí đảo ngược** | Thấp — đây là hướng thắt chặt hơn, gộp lại (nếu muốn) tốn ít hơn tách ra | + +### PA-3 — Uỷ thác hoàn toàn cho VNPay/Momo (tokenization phía đối tác, sàn không giữ Payment Service riêng) + +| | | +|---|---| +| **Mô tả** | Không xây Payment Service nội bộ — mọi trạng thái giao dịch tra cứu trực tiếp qua API đối tác mỗi khi cần, không lưu bản sao nào phía sàn | +| **Ưu** | Phạm vi PCI-DSS nhỏ nhất về lý thuyết | +| **Nhược** | Không đáp ứng `ASR-004` (đối soát bù cần log/trạng thái nội bộ để so khớp); phụ thuộc hoàn toàn uptime của đối tác cho mọi truy vấn trạng thái đơn hàng — vi phạm `QAS-002`/`QAS-014` | +| **Chi phí đảo ngược** | Cao — thiết kế lại toàn bộ luồng đối soát và trạng thái `Order`/`OrderSeller` nếu sau này cần Payment Service nội bộ | + +### Bảng so sánh + +| Tiêu chí | PA-1 | PA-2 | PA-3 | +|---|---|---|---| +| Thu hẹp phạm vi PCI-DSS (`CON-06`) | ❌ Không kiểm chứng được | ✅ Rõ ràng | ✅ Nhỏ nhất về lý thuyết | +| Đáp ứng `ASR-004` (đối soát bù) | ✅ | ✅ | ❌ Không có log nội bộ | +| Chi phí vận hành thêm | Thấp | Trung bình | Thấp | +| Độ trễ khởi tạo thanh toán | Thấp nhất | Trung bình (gọi mạng) | Cao (phụ thuộc đối tác mỗi lần) | + +## 3. Quyết định + +> **Chọn PA-2 — Payment Service là container riêng, cô lập hoàn toàn network + IAM + dữ liệu.** + +**Vì sao:** Đây là cách duy nhất trong 3 phương án vừa thu hẹp được phạm vi PCI-DSS SAQ A +(`CON-06`) vừa đáp ứng được yêu cầu đối soát bù (`ASR-004`). Độc lập với `ADR-001` — áp dụng bất +kể kết luận cuối cùng về kiểu kiến trúc tổng thể là gì. + +**Phạm vi áp dụng:** Toàn bộ luồng xử lý thanh toán VNPay/Momo/COD, không có ngoại lệ. + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| Security xác nhận thiết kế cô lập (network diagram + IAM policy) đạt yêu cầu SAQ A | Security | Chưa có người Security thật (`OQ-004`) | +| Không bắt buộc POC (đây là ràng buộc pháp lý đã có sẵn, không phải con số hiệu năng chưa đo) | — | N/A | + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-1 — Payment chung network/IAM với monolith | Không kiểm chứng được thu hẹp phạm vi PCI-DSS | `CON-06` | Không xét lại — vi phạm ràng buộc pháp lý cứng | +| PA-3 — Uỷ thác hoàn toàn cho đối tác, không Payment Service nội bộ | Không đáp ứng `ASR-004` (đối soát bù); phụ thuộc uptime đối tác cho mọi truy vấn | `ASR-004`, `QAS-002`, `QAS-014` | Chỉ xét lại nếu đối tác cung cấp webhook/API đối soát đủ tin cậy để không cần log nội bộ — chưa có bằng chứng | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Phạm vi audit PCI-DSS SAQ A thu hẹp rõ ràng, kiểm chứng được bằng network diagram +- Payment Service có thể thay đổi độc lập (thêm kênh thanh toán mới) mà không chạm Nhóm Giao + dịch/Nhóm Hỗ trợ (`SAD §4.2` "Ranh giới thay đổi") + +**Hệ quả tiêu cực phải sống chung** + +- Mọi lời gọi từ Cart & Order tới Payment Service phải qua mạng (không còn truy vấn DB trực tiếp) + — thêm độ trễ và cần thiết kế đường lỗi riêng (xem `FAIL`, hoạt động 8) +- Thêm một RDS instance riêng cần patch/backup/monitor độc lập + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Gộp Payment vào chung network/IAM với phần còn lại | Phải làm lại toàn bộ audit PCI-DSS, rủi ro pháp lý cao | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Thiết kế network diagram + IAM policy chi tiết cho Security review | SA + Security | Hoạt động `sec` (GĐ2) | `SEC_e-commerce` §1 | +| Đào tạo team về ranh giới không được vi phạm (không copy code truy cập DB Payment) | Tech Lead | GĐ3 (`AGD`) | `TCO §5` | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Không có security group nào cho phép truy cập trực tiếp từ container khác vào RDS Payment | Kiểm tra hạ tầng (Terraform plan/AWS Config rule) | CI/CD + định kỳ | `FIT-03` (ứng viên GĐ3) | +| Không có trường số thẻ/CVV trong bất kỳ schema nào ngoài Payment | Kiểm tra schema/migration review | CI (schema linter) | `FIT-04` (ứng viên) | +| Pentest/ASV scan hàng quý xác nhận phạm vi SAQ A | Nhà cung cấp pentest bên ngoài | Định kỳ hàng quý | — (thủ công, chưa có báo giá — `OQ-017`) | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Đối tác thanh toán mới yêu cầu mô hình tích hợp khác (không redirect/IPN) | Khi có đối tác mới | Tech Lead | +| Pentest/audit phát hiện lỗ hổng ở ranh giới cô lập | Bất kỳ phát hiện mức Cao | Security | + +## 8. Tham chiếu + +- POC: Không áp dụng (ràng buộc pháp lý, không phải quyết định hiệu năng) +- Bài đo: Pentest/ASV scan hàng quý (chưa có báo giá, `OQ-017`) +- Tài liệu ngoài: `BR_CartCheckout_v1.0.md` (BA) — `BR-CART-05` · `CTX_e-commerce_v1.0.md §3` `CON-06` +- Thảo luận: `ASR_e-commerce_v1.0.md §B2 ASR-002` + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung đủ làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`) | Chưa có người Security để ký (`ADL §8` việc #7) — ngoại lệ dự án chạy thử không thay được chữ ký chuyên môn Security | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: 🔴 — +> `AG2` chưa ký. diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-003_mo-hinh-order-orderseller-tach-don-theo-seller.md b/sa-output/e-commerce/02-architecture/adr/ADR-003_mo-hinh-order-orderseller-tach-don-theo-seller.md new file mode 100644 index 0000000..a005dde --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-003_mo-hinh-order-orderseller-tach-don-theo-seller.md @@ -0,0 +1,167 @@ +# ADR-003 — Mô hình dữ liệu Order (cha) / OrderSeller (con) để tách đơn theo seller khi checkout + +*Tên file: `adr/ADR-003_mo-hinh-order-orderseller-tach-don-theo-seller.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | SA + Tech Lead (cấu trúc dữ liệu — `decision-radar.md §5`) | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **~6/10** | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-003` · `BR-CART-01` (BA) · `DRV-01` · `DRV-02` · `DRV-06` · `OQ-011` (BA, chưa đóng) · `CMP-04` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-003` và đổi trạng thái bản cũ thành `Superseded by`. + +--- + +## 1. Bối cảnh + +Giỏ hàng có thể chứa sản phẩm của nhiều seller. `DRV-01` (blocker MVP) và `DRV-06` (minh bạch +dòng tiền 3 bên khách–sàn–seller) buộc phải có một cách nhất quán để tách trách nhiệm tài chính +và vận chuyển giữa các seller trong cùng một lần đặt hàng. `BR-CART-01` (BA) đã phát biểu quy tắc +nghiệp vụ: nhóm `CartItem` theo `seller_id`, tạo `OrderSeller` riêng cho mỗi nhóm, `Order` là tập +hợp các `OrderSeller`. **Cơ chế tách chi tiết** ("luôn đúng N đơn cho N seller, không gộp") vẫn +phụ thuộc `OQ-011` (BA, `ASM-03` chưa xác minh) — ADR này ghi nhận mô hình cấu trúc, không tự +đóng `OQ-011`. + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `BR-CART-01` (BA) | Tách `CartItem` theo `seller_id`, tạo `OrderSeller` riêng cho mỗi nhóm | +| `ASR-003` | Ép mô hình dữ liệu 1 `Order` — N `OrderSeller` — N `OrderItem`; mỗi `OrderSeller` có vòng đời trạng thái độc lập | +| `DRV-06` | Dòng tiền minh bạch 3 bên, hoa hồng/payout theo từng seller | +| `OQ-011` (BA) | Giỏ N seller luôn tách đúng N đơn, không gộp — **chưa xác nhận bởi PO** | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| Mô hình kinh doanh là marketplace đa seller, cần tách trách nhiệm tài chính/vận chuyển theo seller | 🟢 Đã kiểm chứng | `00-project-brief.md` vòng 1, `BR-CART-01` | +| Không có ngoại lệ gộp nhiều seller vào 1 `OrderSeller` (VD cùng kho vận trung tâm) | 🔴 Giả định — PO chưa xác nhận | `OQ-011` (BA), `ASM-03` | + +## 2. Phương án đã cân nhắc + +### PA-1 — Một `Order` phẳng, không có cấu trúc con theo seller (dùng trường `seller_id` lặp ở từng `OrderItem`) + +| | | +|---|---| +| **Mô tả** | Chỉ có bảng `Order`/`OrderItem`, mỗi `OrderItem` gắn `seller_id` riêng; không có tầng `OrderSeller` trung gian — trạng thái/hoa hồng tính bằng cách nhóm động theo `seller_id` mỗi lần truy vấn | +| **Ưu** | Đơn giản hơn về số bảng, ít JOIN hơn cho các truy vấn không cần phân seller | +| **Nhược** | Không có đơn vị hạch toán/vận chuyển/đối soát độc lập theo seller — mỗi lần cần trạng thái giao hàng hoặc hoa hồng theo seller phải nhóm động, dễ sai lệch khi có seller thay đổi trạng thái không đồng thời; vi phạm `ASR-003` ("mỗi `OrderSeller` có vòng đời trạng thái độc lập") | +| **Chi phí đảo ngược** | Cao — thêm tầng `OrderSeller` sau khi đã có dữ liệu lịch sử cần migrate toàn bộ đơn hàng cũ | + +### PA-2 — `Order` (cha) — N `OrderSeller` (con) — N `OrderItem` *(chọn)* + +| | | +|---|---| +| **Mô tả** | `Order` là tập hợp logic của các `OrderSeller`; mỗi `OrderSeller` có `status` riêng, thuộc về đúng 1 `Order` cha và đúng 1 `seller_id` | +| **Ưu** | Mỗi `OrderSeller` là đơn vị hạch toán/vận chuyển/đối soát độc lập — khớp trực tiếp `BR-CART-01`, `DRV-06`; các module tiêu thụ (Commission & Payout, Shipping & Fulfillment) chỉ cần đọc `OrderSeller`, không phải tự nhóm | +| **Nhược** | Thêm một tầng bảng, thêm JOIN khi cần tổng `Order` (đã có công thức `BR-CART-09` bù); ranh giới sở hữu dữ liệu giữa Cart & Order (tạo) và Commission/Shipping (tiêu thụ) cần rõ ràng | +| **Chi phí đảo ngược** | Trung bình-cao — đổi mô hình sau go-live cần migrate toàn bộ đơn hàng lịch sử + sửa mọi module đọc `Order` | + +### PA-3 — Mỗi seller là một `Order` độc lập, không có `Order` cha chung + +| | | +|---|---| +| **Mô tả** | Bỏ hẳn khái niệm "đơn cha" — khách checkout giỏ 3 seller thì tạo 3 `Order` độc lập hoàn toàn, không có liên kết logic nào | +| **Ưu** | Đơn giản nhất về mặt mô hình — mỗi `Order` tự chứa đủ thông tin | +| **Nhược** | Khách hàng mất khả năng xem "một lần đặt hàng" gồm nhiều seller như một đơn vị trải nghiệm (UX); mất điểm neo cho thanh toán chung 1 lần cho nhiều seller (khởi tạo Payment 1 lần cho N `OrderSeller`) — vi phạm luồng B5-B8 đã có ở `PROCESS_CartCheckout` | +| **Chi phí đảo ngược** | Cao — dựng lại khái niệm "đơn cha" sau này cần thêm bảng liên kết + backfill dữ liệu | + +### Bảng so sánh + +| Tiêu chí | PA-1 | PA-2 | PA-3 | +|---|---|---|---| +| Đơn vị hạch toán/vận chuyển độc lập theo seller (`ASR-003`) | ❌ | ✅ | ✅ | +| Trải nghiệm "một lần đặt hàng" cho nhiều seller (`PROCESS` B5-B8) | 🔶 Nhóm động | ✅ | ❌ | +| Số bảng/độ phức tạp | Thấp | Trung bình | Thấp | +| Khớp `BR-CART-01` (BA) | ❌ | ✅ | 🔶 Một phần | + +## 3. Quyết định + +> **Chọn PA-2 — `Order` (cha) — N `OrderSeller` (con) — N `OrderItem`.** + +**Vì sao:** Đây là mô hình duy nhất khớp trực tiếp `BR-CART-01` (nguồn nghiệp vụ đã chốt), đáp +ứng `ASR-003` (mỗi `OrderSeller` có vòng đời độc lập) và giữ được trải nghiệm "một lần đặt hàng" +theo luồng đã thiết kế ở `PROCESS_CartCheckout` B5-B8. + +**Phạm vi áp dụng:** Toàn bộ luồng checkout và mọi module tiêu thụ `Order`/`OrderSeller` +(Commission & Payout, Shipping & Fulfillment, Review). + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| `OQ-011` (BA) — PO xác nhận không có ngoại lệ gộp seller (VD cùng kho vận trung tâm) | PO | Mở | +| Không bắt buộc POC (đây là quyết định mô hình dữ liệu, không phải con số hiệu năng) | — | N/A | + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-1 — `Order` phẳng, không tầng `OrderSeller` | Vi phạm `ASR-003` (không có vòng đời độc lập theo seller); các module tiêu thụ phải tự nhóm động, dễ sai lệch | `ASR-003`, `BR-CART-01` | Nếu về sau xác nhận không cần vòng đời độc lập theo seller (VD gộp hết trách nhiệm về sàn) — chưa có dấu hiệu | +| PA-3 — Mỗi seller một `Order` độc lập, không cha chung | Phá vỡ trải nghiệm "một lần đặt hàng" đã thiết kế ở `PROCESS` B5-B8; mất điểm neo thanh toán chung | `PROCESS_CartCheckout` B5-B8 | Nếu PO đổi mô hình sản phẩm sang "mỗi seller là một cửa hàng độc lập hoàn toàn, khách checkout riêng từng seller" — thay đổi nghiệp vụ lớn, chưa có dấu hiệu | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Commission & Payout, Shipping & Fulfillment chỉ cần đọc `OrderSeller`, không tự nhóm động — + giảm rủi ro sai lệch đối soát +- Khách hàng có trải nghiệm nhất quán "một lần đặt hàng" dù giỏ có nhiều seller + +**Hệ quả tiêu cực phải sống chung** + +- Thêm JOIN khi cần tổng `Order.total_amount` (đã có công thức bù `BR-CART-09`) +- Nếu `OQ-011` trả lời "có ngoại lệ gộp seller" (VD cùng kho vận), mô hình này phải viết lại một + phần (không phải toàn bộ — vẫn giữ cấu trúc cha-con, chỉ đổi quy tắc nhóm) + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Đổi mô hình tách đơn (VD gộp nhiều seller vào 1 đơn) | Migrate toàn bộ đơn hàng lịch sử + sửa mọi module đọc `Order` — đây là core domain model, `SAD §4.2` đã cảnh báo đây là loại thay đổi "không nên xảy ra thường xuyên" | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| BA xác nhận `OQ-011` với PO | BA + PO | Trước khi `Accepted` | `ba-output/.../00-index/OQ_e-commerce.md` | +| Thiết kế schema chi tiết `Order`/`OrderSeller`/`OrderItem` | SA (hoạt động `dat`) | GĐ2 tiếp theo | `DAT_e-commerce` | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Mọi `OrderSeller` luôn có đúng 1 `seller_id` và thuộc đúng 1 `Order` cha (ràng buộc FK + constraint) | DB schema constraint + migration test | CI | `FIT-05` (ứng viên) | +| Tổng `Order.total_amount` luôn bằng Σ `OrderSeller.subtotal_amount` (`BR-CART-09`) | Unit test / DB trigger kiểm tra | CI | `FIT-06` (ứng viên) | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| PO xác nhận cần ngoại lệ gộp seller (VD cùng kho vận trung tâm) | Khi `OQ-011` trả lời khác giả định hiện tại | PO + BA | +| Phát sinh nhu cầu đổi mô hình tách đơn thường xuyên | ≥ 2 lần yêu cầu thay đổi trong 6 tháng | Tech Lead | + +## 8. Tham chiếu + +- POC: Không áp dụng +- Bài đo: `FIT-05`, `FIT-06` (ứng viên GĐ3) +- Tài liệu ngoài: `BR_CartCheckout_v1.0.md §1 BR-CART-01, §4 ERD` (BA) +- Thảo luận: `ASR_e-commerce_v1.0.md §B2 ASR-003` + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung đủ làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`) | Chờ `OQ-011` — BA + PO xác nhận mô hình `Order`/`OrderSeller` | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: 🔴 — +> `AG2` chưa ký. diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-004_idempotency-doi-soat-webhook-thanh-toan.md b/sa-output/e-commerce/02-architecture/adr/ADR-004_idempotency-doi-soat-webhook-thanh-toan.md new file mode 100644 index 0000000..5a583c6 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-004_idempotency-doi-soat-webhook-thanh-toan.md @@ -0,0 +1,168 @@ +# ADR-004 — Cơ chế idempotency cho webhook thanh toán + job đối soát bù định kỳ + +*Tên file: `adr/ADR-004_idempotency-doi-soat-webhook-thanh-toan.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | SA + Tech Lead (tích hợp/idempotency — `decision-radar.md §5`) | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **~6/10** | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-004` · `QAS-014` · `BR-CART-06` (BA) · `DRV-08` · `ARISK-03` · `CMP-11` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-004` và đổi trạng thái bản cũ thành `Superseded by`. + +--- + +## 1. Bối cảnh + +Xác nhận thanh toán qua webhook VNPay/Momo (bên thứ ba) chưa được xác minh khả thi gần thời gian +thực (`DRV-08`, `ASM-01` của BA chưa xác minh). Nếu webhook trễ/lỗi/gọi lặp, đơn hàng có thể kẹt +"chờ thanh toán" dù tiền đã thu, hoặc bị cập nhật trạng thái sai nếu xử lý webhook không +idempotent. `BR-CART-06` (BA) đã đặt quy tắc nghiệp vụ: chỉ cập nhật `Payment.status = success` +khi webhook có chữ ký hợp lệ và trong thời hạn — nhưng con số thời hạn cụ thể **chưa chốt** +(thuộc phạm vi kỹ thuật của ADR này, không phải quyết định BA). + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `ASR-004` | Webhook phải idempotent + có job đối soát bù | +| `BR-CART-06` (BA) | Chỉ cập nhật `Payment.status=success` khi chữ ký hợp lệ + trong hạn | +| `QAS-014` | Job đối soát phát hiện lệch trong ≤15 phút *(đề xuất SA, `OQ-021` chưa xác nhận)* | +| `ARISK-03` | VNPay/Momo chưa có sandbox thật — thiết kế chưa kiểm chứng | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| Webhook có thể bị gọi lặp lại (retry của VNPay/Momo theo tài liệu công khai) | 🟡 Ước lượng có cơ sở | Thực hành phổ biến của cổng thanh toán, chưa xác nhận với sandbox thật | +| `gateway_transaction_ref` là khoá duy nhất, ổn định qua các lần gọi lặp | 🔴 Giả định | Chưa có tài liệu API/sandbox thật (`CON-04`) | +| Tần suất đối soát ≤15 phút đủ nhanh để tránh khiếu nại CSKH | 🔴 Giả định (`ASM-18`) | `OQ-021` — Tech Lead chưa xác nhận | + +## 2. Phương án đã cân nhắc + +### PA-1 — Chỉ dựa vào webhook, không có job đối soát bù + +| | | +|---|---| +| **Mô tả** | Cập nhật `Payment.status` hoàn toàn dựa vào webhook đến; không có cơ chế nào chủ động kiểm tra lại | +| **Ưu** | Đơn giản nhất, không cần job chạy định kỳ | +| **Nhược** | Nếu webhook mất/trễ vĩnh viễn (lỗi mạng, đối tác không gửi lại), đơn hàng kẹt "chờ thanh toán" vô thời hạn dù tiền đã thu — vi phạm trực tiếp `DRV-08`/`ASR-004` | +| **Chi phí đảo ngược** | Cao — phải xây job đối soát sau khi đã có dữ liệu thật bị kẹt, kèm backfill thủ công cho các đơn đã kẹt | + +### PA-2 — Webhook idempotent (khoá theo `gateway_transaction_ref`) + job đối soát bù định kỳ *(chọn)* + +| | | +|---|---| +| **Mô tả** | Webhook endpoint kiểm tra idempotency key = `gateway_transaction_ref` trước khi ghi; nếu đã xử lý, trả 200 mà không ghi lại. Job đối soát chạy định kỳ (đề xuất ≤15 phút, `OQ-021`), tra cứu API đối tác để so khớp `Payment.status` | +| **Ưu** | Chống hiệu ứng phụ khi webhook gọi lặp; phát hiện được các trường hợp webhook mất hoàn toàn (job chủ động tra cứu, không phụ thuộc webhook đến) | +| **Nhược** | Thêm một job chạy định kỳ cần giám sát riêng (alerting nếu job tự nó lỗi); cần bảng log webhook đã nhận để so khớp | +| **Chi phí đảo ngược** | Trung bình — đổi tần suất/cơ chế đối soát sau khi có dữ liệu thật tốn công viết lại job + backfill, nhưng không ảnh hưởng mô hình dữ liệu cốt lõi | + +### PA-3 — Chỉ dùng job polling, không nhận webhook + +| | | +|---|---| +| **Mô tả** | Bỏ hẳn endpoint webhook, chỉ dựa vào job định kỳ tra cứu API đối tác để cập nhật trạng thái | +| **Ưu** | Không cần lo idempotency cho webhook đến (không có webhook) | +| **Nhược** | Độ trễ xác nhận thanh toán phụ thuộc hoàn toàn chu kỳ polling (tối thiểu bằng tần suất job) — tệ hơn nhiều so với gần thời gian thực; tăng số lượng API call tới đối tác (chi phí + rủi ro rate limit) | +| **Chi phí đảo ngược** | Trung bình — thêm lại webhook sau này không khó, nhưng đã đánh đổi trải nghiệm người dùng trong thời gian dùng PA-3 | + +### Bảng so sánh + +| Tiêu chí | PA-1 | PA-2 | PA-3 | +|---|---|---|---| +| Đáp ứng `ASR-004` (idempotent + đối soát bù) | ❌ | ✅ | 🔶 Có đối soát, không idempotent webhook (không có webhook) | +| Độ trễ xác nhận thanh toán (`QAS-002`) | Nhanh nhất khi webhook tới đúng hạn, nhưng vô hạn khi mất | Nhanh (webhook) + có lưới an toàn (job) | Chậm nhất (phụ thuộc chu kỳ polling) | +| Chi phí vận hành thêm | Thấp nhất | Trung bình (1 job định kỳ) | Trung bình-cao (nhiều API call hơn) | + +## 3. Quyết định + +> **Chọn PA-2 — Webhook idempotent (khoá `gateway_transaction_ref`) + job đối soát bù định kỳ.** + +**Vì sao:** Đây là phương án duy nhất vừa giữ được độ trễ thấp cho trường hợp bình thường (webhook +tới đúng hạn) vừa có lưới an toàn khi webhook trễ/mất — đúng yêu cầu `ASR-004`. + +**Phạm vi áp dụng:** Toàn bộ luồng xác nhận thanh toán VNPay/Momo (không áp dụng cho COD — không +có webhook). + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| Có sandbox VNPay/Momo thật để kiểm chứng hành vi retry webhook | Tech Lead | Chưa có (`ARISK-03`, `CON-04`) | +| `OQ-021` — Tech Lead xác nhận tần suất job đối soát cụ thể | Tech Lead | Mở (đề xuất tạm ≤15 phút) | +| Không bắt buộc POC theo `decision-radar.md §6` (không phải con số hiệu năng lớn, nhưng cần sandbox thật để xác minh hành vi đối tác) | — | Chờ sandbox | + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-1 — Chỉ dựa vào webhook, không đối soát | Không phát hiện được trường hợp webhook mất hoàn toàn — vi phạm `ASR-004` | `ASR-004`, `DRV-08` | Không xét lại trừ khi VNPay/Momo đảm bảo bằng SLA hợp đồng webhook không bao giờ mất — chưa có tiền lệ ngành | +| PA-3 — Chỉ polling, không webhook | Độ trễ xác nhận kém hơn hẳn, tăng API call — vi phạm gián tiếp `QAS-002` (trải nghiệm checkout) | `QAS-002`, `QAS-014` | Nếu VNPay/Momo không hỗ trợ webhook (một số cổng thanh toán khác trong tương lai) — xét lại cho riêng đối tác đó | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Chống được hiệu ứng phụ khi webhook gọi lặp (idempotency key) +- Có lưới an toàn phát hiện đơn kẹt trong thời gian giới hạn (đề xuất ≤15 phút), giảm rủi ro + khiếu nại CSKH (`DRV-08`) + +**Hệ quả tiêu cực phải sống chung** + +- Cần bảng log webhook đã nhận (`ReconciliationLog`) — tăng dung lượng lưu trữ, cần retention + policy (thuộc `DAT`, hoạt động 5) +- Job đối soát tự nó có thể lỗi — cần alerting riêng cho chính job này (không chỉ alerting cho + luồng chính) + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Đổi khoá idempotency từ `gateway_transaction_ref` sang cơ chế khác | Cần migrate log webhook đã có + rà lại toàn bộ giao dịch lịch sử | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Đàm phán sandbox VNPay/Momo | Tech Lead + PO | Trước GĐ2 `ICD` hoàn tất | `ARISK-03` | +| Thiết kế bảng `ReconciliationLog` + retention | SA (hoạt động `dat`) | GĐ2 tiếp theo | `DAT_e-commerce` | +| Thêm alerting cho chính job đối soát (job lỗi/không chạy) | SA (hoạt động `inf`) | GĐ2 tiếp theo | `INF_e-commerce` | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Gọi lặp cùng một webhook payload không tạo hiệu ứng phụ (không nhân đôi trạng thái/log) | Integration test | CI + staging trước mỗi release | `FIT-07` (ứng viên) | +| Job đối soát phát hiện lệch giả lập trong ≤15 phút | Test giả lập webhook trễ/mất trên staging | Trước go-live | — (cần sandbox thật, `ARISK-03`) | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Tần suất job đối soát thật khác đề xuất (`OQ-021` trả lời khác ≤15 phút) | Khi Tech Lead xác nhận số khác | Tech Lead | +| Sandbox thật cho thấy webhook có hành vi khác giả định (VD không gọi lặp, hoặc gọi lặp với `gateway_transaction_ref` khác nhau) | Khi có sandbox | Tech Lead | + +## 8. Tham chiếu + +- POC: Không bắt buộc — nhưng cần sandbox thật (`ARISK-03`) trước khi kiểm chứng đầy đủ +- Bài đo: `FIT-07` (ứng viên GĐ3) +- Tài liệu ngoài: `BR_CartCheckout_v1.0.md §1 BR-CART-06` (BA) +- Thảo luận: `ASR_e-commerce_v1.0.md §B2 ASR-004` + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung đủ làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`) | Chưa có chữ ký thật Tech Lead; cần chạy thử trên sandbox đối tác thanh toán trước khi chốt | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: 🔴 — +> `AG2` chưa ký. diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-005_message-backbone-sqs-fifo-eventbridge.md b/sa-output/e-commerce/02-architecture/adr/ADR-005_message-backbone-sqs-fifo-eventbridge.md new file mode 100644 index 0000000..8475d19 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-005_message-backbone-sqs-fifo-eventbridge.md @@ -0,0 +1,176 @@ +# ADR-005 — Message backbone cho luồng đặt hàng là SQS FIFO (per-seller group) + EventBridge, không phải Kafka/MSK + +*Tên file: `adr/ADR-005_message-backbone-sqs-fifo-eventbridge.md`* + +| | | +|---|---| +| **Status** | `Proposed` *(🔴 radar ≥8 — theo `decision-radar.md §2`/§6, **không được chuyển `Accepted` khi chưa có `POC-01` PASS**)* | +| **Date** | 2026-09-15 | +| **Người quyết** | SA + Tech Lead (tích hợp/hạ tầng — `decision-radar.md §5`) | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **~8/10** — 🔴 bắt buộc POC trước `Accepted` | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-005` · `QAS-005` · `QAS-009` (A4 xung đột dòng 2) · `ARISK-01` · `POC-01` · `ADR-001` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-005` và đổi trạng thái bản cũ thành `Superseded by`. + +--- + +## 1. Bối cảnh + +Luồng sự kiện `OrderPlaced`/`PaymentConfirmed` phải truyền tới ≥5 consumer (Commission & Payout, +Promotion & Loyalty, Review, Notification, Shipping & Fulfillment) sau khi đặt hàng, đồng thời +phải giữ đúng thứ tự xử lý trong cùng một seller (liên quan `DRV-06` — tính nhất quán dữ liệu tài +chính). `ASR-001`/`ADR-001` đã chọn hướng managed service (SQS/EventBridge) thay vì tự vận hành +Kafka/MSK — ADR này hình thức hoá cụ thể lựa chọn message backbone và **là quyết định đạt ngưỡng +radar ≥8** vì chưa có bài đo throughput thật trong ngữ cảnh này (`ASM-07`). + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `ASR-005` | SQS FIFO (message group = `seller_id`) + EventBridge fan-out ≥5 consumer | +| `QAS-005` | Thông lượng sustained ≥100 msg/s, p99 publish→consume ≤2s, 0 mất message, fan-out lag ≤5s | +| `QAS-009` A4 dòng 2 | Xung đột: AWS giới hạn throughput **cứng cho một message group** SQS FIFO — seller volume cao có thể chạm trần group dù tổng hệ thống chưa chạm 100 msg/s | +| `CON-05` | Team chưa xác nhận kinh nghiệm vận hành Kafka/MSK production (`CTX §4.4`) | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| SQS FIFO hỗ trợ message group theo key tuỳ chọn (`seller_id`) | 🟢 Đã kiểm chứng | Tài liệu AWS công khai | +| SQS FIFO + EventBridge đạt ≥100 msg/s sustained, p99 ≤2s trong ngữ cảnh payload `OrderPlaced` ~2KB tại `ap-southeast-1` | 🔴 Giả định (`ASM-07`) | `POC-01` — **chưa chạy** | +| Một seller volume rất cao không làm nghẽn message group riêng của seller đó tới mức ảnh hưởng SLA | 🔴 Giả định | Chưa có POC riêng cho kịch bản seller lệch tải — ghi nhận ở §7 | + +## 2. Phương án đã cân nhắc + +### PA-1 — Kafka / Amazon MSK tự quản lý + +| | | +|---|---| +| **Mô tả** | Cụm Kafka/MSK làm xương sống bất đồng bộ, theo `SAD.md`/hồ sơ thầu (P1) | +| **Ưu** | Throughput cao, kiểm soát partition/consumer group linh hoạt hơn; công nghệ phổ biến cho hệ thống lớn | +| **Nhược** | Không có bằng chứng team từng vận hành Kafka/MSK production (`CTX §4.4`, `OQ-010` mở); effort dựng cụm riêng đã ước 70,2 MD (XL, +35% contingency, `WBS-03`); thêm một cụm phải patch/scale thủ công | +| **Chi phí đảo ngược** | Cao — bỏ Kafka/MSK sau khi đã có producer/consumer thật cần viết lại toàn bộ tầng tích hợp bất đồng bộ | + +### PA-2 — SQS Standard + SNS fan-out (không FIFO) + +| | | +|---|---| +| **Mô tả** | Dùng SQS Standard (at-least-once, không đảm bảo thứ tự) + SNS để fan-out cho nhiều consumer | +| **Ưu** | Throughput lý thuyết cao hơn FIFO (không giới hạn theo message group), chi phí thấp | +| **Nhược** | **Không đảm bảo thứ tự xử lý trong cùng seller** — vi phạm trực tiếp yêu cầu tính nhất quán tài chính của `DRV-06` (VD 2 sự kiện `OrderPlaced`/`PaymentConfirmed` cùng seller có thể xử lý sai thứ tự, gây sai lệch đối soát) | +| **Chi phí đảo ngược** | Trung bình — chuyển sang FIFO sau này cần viết lại consumer để xử lý idempotent/thứ tự, nhưng không cần đổi hạ tầng lớn | + +### PA-3 — SQS FIFO (per-seller message group) + EventBridge fan-out *(chọn)* + +| | | +|---|---| +| **Mô tả** | SQS FIFO với message group key = `seller_id` (đảm bảo thứ tự trong cùng seller), EventBridge rule fan-out tới ≥5 consumer | +| **Ưu** | Managed hoàn toàn (không cụm phải patch/scale thủ công); đảm bảo thứ tự đúng phạm vi cần (trong seller, không cần thứ tự toàn cục); khớp năng lực team hiện tại (không cần kinh nghiệm Kafka) | +| **Nhược** | Giới hạn throughput cứng theo **một** message group — seller volume rất cao có thể chạm trần riêng của seller đó (`QAS-009` A4); FIFO có overhead cao hơn Standard | +| **Chi phí đảo ngược** | Trung bình — nếu cần chuyển sang Kafka/MSK sau này (do `POC-01` fail hoặc traffic vượt xa dự kiến), phải viết lại toàn bộ tầng publish/consume | + +### Bảng so sánh + +| Tiêu chí | PA-1 (Kafka/MSK) | PA-2 (SQS Standard+SNS) | PA-3 (SQS FIFO+EventBridge) | +|---|---|---|---| +| Đảm bảo thứ tự trong seller (`DRV-06`) | ✅ (tự cấu hình partition key) | ❌ | ✅ | +| Rủi ro năng lực team (`CON-05`) | 🔴 Cao — chưa có kinh nghiệm | 🟢 Thấp | 🟢 Thấp | +| Chi phí vận hành (cụm tự quản lý) | 🔴 Cao | 🟢 Thấp | 🟢 Thấp | +| Rủi ro trần throughput 1 seller lớn | 🟢 Thấp (partition linh hoạt) | 🟢 Thấp | 🟠 Có (per-group limit) | + +## 3. Quyết định + +> **Chọn PA-3 — SQS FIFO (message group = `seller_id`) + EventBridge fan-out ≥5 consumer.** + +**Vì sao:** Đây là phương án duy nhất vừa đảm bảo thứ tự trong phạm vi cần (theo seller, khớp +`DRV-06`) vừa khớp năng lực team hiện tại (`CON-05`, không cần vận hành cụm Kafka/MSK) — nhất +quán với hướng đi đã chọn ở `ADR-001`. + +**Phạm vi áp dụng:** Toàn bộ luồng sự kiện `OrderPlaced`/`PaymentConfirmed` và các sự kiện tương +tự phát sinh sau đặt hàng. + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| **`POC-01` PASS** — sustained ≥100 msg/s/30 phút, p99 ≤2s, 0 mất message, fan-out lag ≤5s | Tech Lead + 1 DevOps | 🔴 **Chưa chạy** (`ARISK-01`, `OQ-012`) | +| Có phương án theo dõi/cảnh báo riêng cho seller volume cao (giảm rủi ro trần message group) | Tech Lead | Chưa thiết kế — xem §5 "Việc phát sinh" | + +🔴 **Bắt buộc theo `decision-radar.md §2`/§6** — điểm radar ~8 (≥8) đồng nghĩa ADR này **không +được chuyển `Accepted`** cho tới khi `POC-01` chạy xong và PASS. Nếu `POC-01` FAIL: bổ sung +Kafka/MSK riêng cho hot-path đặt hàng (kiến trúc lai, theo điều kiện đã nêu ở `OPT §1`), không +Supersede toàn bộ `ADR-001`. + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-1 — Kafka/MSK | Không có bằng chứng team vận hành production; effort dựng nền tảng lớn hơn đáng kể | `CON-05`, `OQ-010` | Nếu `POC-01` FAIL **và** `OQ-010` xác nhận team có kinh nghiệm Kafka/MSK — bổ sung Kafka/MSK riêng cho hot-path (kiến trúc lai), không thay thế toàn bộ | +| PA-2 — SQS Standard + SNS | Không đảm bảo thứ tự trong seller — vi phạm `DRV-06` | `DRV-06` | Chỉ xét lại cho các luồng không yêu cầu thứ tự (VD Notification không cần đúng thứ tự tuyệt đối) — không áp dụng cho `OrderPlaced`/`PaymentConfirmed` | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Không cần vận hành cụm message broker riêng — khớp năng lực team, giảm effort nền tảng ~70,2 MD + so với Kafka/MSK +- Đảm bảo đúng thứ tự xử lý trong phạm vi cần (theo seller) + +**Hệ quả tiêu cực phải sống chung** + +- Rủi ro trần throughput cho **một** seller có volume rất cao — cần theo dõi/cảnh báo riêng + (chưa thiết kế, xem việc phát sinh) +- Nếu `POC-01` FAIL, phải bổ sung kiến trúc lai (Kafka/MSK cho riêng hot-path) — tăng độ phức tạp + vận hành so với một giải pháp thuần nhất + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Chuyển từ SQS FIFO/EventBridge sang Kafka/MSK sau khi đã có producer/consumer thật | Viết lại toàn bộ tầng publish/consume, thiết kế lại partition/consumer group | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Chạy `POC-01` theo tiêu chí đã viết trước | Tech Lead + DevOps | Trước khi `Accepted` | `ARISK_e-commerce_v1.0.md §6` | +| Thiết kế cơ chế theo dõi/cảnh báo riêng cho seller volume cao (VD CloudWatch alarm theo group lag) | SA (hoạt động `inf`) + Tech Lead | GĐ2 tiếp theo | `INF_e-commerce` | +| Thêm fitness function kiểm tra publish luôn có `seller_id` làm message group key | Tech Lead | GĐ3 (`AGD`/`FIT`) | `FIT-08` (ứng viên) | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| `POC-01` — throughput/độ trễ/mất message | k6/artillery, AWS `ap-southeast-1` thật | Trước `Accepted`, lặp lại trước mỗi major release | — (ghi vào `ARISK §6`) | +| Mọi message publish `OrderPlaced`/`PaymentConfirmed` có `MessageGroupId = seller_id` | Contract test / lint publish code | CI | `FIT-08` (ứng viên) | +| Cảnh báo khi một message group riêng lẻ có lag > ngưỡng | CloudWatch Alarm | Production, liên tục | — | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| `POC-01` FAIL | Không đạt tiêu chí PASS đã viết trước | Tech Lead | +| Một seller có volume vượt trần message group SQS FIFO trong production | Lag message group > 5 giây kéo dài > 5 phút liên tục | SRE | +| Tổng throughput hệ thống tiệm cận giới hạn đã đo ở `POC-01` | > 80% ngưỡng đã đo | SRE | + +## 8. Tham chiếu + +- POC: `ARISK_e-commerce_v1.0.md §6 POC-01` +- Bài đo: `FIT-08` (ứng viên GĐ3) +- Tài liệu ngoài: `QAS_e-commerce_v1.0.md §A3 QAS-005, §A4 (xung đột dòng 2)` +- Thảo luận: `ASR_e-commerce_v1.0.md §B2 ASR-005`, `OPT_e-commerce_v1.0.md §8 ASM-07` + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung đủ làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`) | Radar 8 — bắt buộc `POC-01` (throughput SQS/EventBridge) PASS trước khi `Accepted`; chưa chạy | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: 🔴 — +> `AG2` chưa ký. diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-006_chien-luoc-du-lieu-rds-gop-schema-per-module.md b/sa-output/e-commerce/02-architecture/adr/ADR-006_chien-luoc-du-lieu-rds-gop-schema-per-module.md new file mode 100644 index 0000000..ca8bdb7 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-006_chien-luoc-du-lieu-rds-gop-schema-per-module.md @@ -0,0 +1,174 @@ +# ADR-006 — Một cụm RDS PostgreSQL chính, schema-per-module, chịu tải ghi/đọc gộp (trừ Payment) + +*Tên file: `adr/ADR-006_chien-luoc-du-lieu-rds-gop-schema-per-module.md`* + +| | | +|---|---| +| **Status** | `Proposed` *(🔴 radar ≥8 — theo `decision-radar.md §2`/§6, **không được chuyển `Accepted` khi chưa có `POC-02` PASS**)* | +| **Date** | 2026-09-15 | +| **Người quyết** | SA + Tech Lead/DBA (dữ liệu — `decision-radar.md §5`) | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **~8/10** — 🔴 bắt buộc POC trước `Accepted` | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-006` · `QAS-006` · `ARISK-02` · `POC-02` · `ADR-001` · `ADR-002` (Payment tách riêng, độc lập) | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-006` và đổi trạng thái bản cũ thành `Superseded by`. + +--- + +## 1. Bối cảnh + +Modular monolith P2 (`ADR-001`) cần một chiến lược dữ liệu nhất quán cho mọi module ngoài +Payment (đã tách riêng theo `ADR-002`). `ASR-006` ép ra một cụm RDS PostgreSQL Multi-AZ chính, +chia theo schema-per-module — chưa đo tải ghi (checkout) + đọc (catalog) gộp ở tải đỉnh flash +sale. Đây là quyết định đạt ngưỡng radar ≥8 vì chưa có bài đo thật trong ngữ cảnh này (`ASM-08`). + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `ASR-006` | 1 RDS chính schema-per-module, chịu tải ghi/đọc gộp cho mọi module trừ Payment | +| `QAS-006` | p95 write (checkout) ≤300ms, p95 read (catalog) ≤200ms, CPU <75%, connection pool không exhaust | +| `ADR-001` | Modular monolith P2 — tiền đề cho việc gộp dữ liệu theo schema thay vì database-per-service | +| `ADR-002` | Payment có RDS riêng — không nằm trong phạm vi cụm RDS chính này | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| Payment có RDS riêng, tách biệt hoàn toàn khỏi cụm chính | 🟢 Đã kiểm chứng | `ADR-002` | +| 1 cụm RDS `db.r6g.xlarge` Multi-AZ đủ chịu tải ghi/đọc gộp cho các module ngoài Payment ở kịch bản A/B | 🔴 Giả định (`ASM-08`) | `POC-02` — **chưa chạy** | +| Connection pool chia theo module đủ tránh một module chiếm hết pool | 🔴 Giả định | Chưa có thiết kế connection pool chi tiết — thuộc `DAT`, hoạt động 5 | + +## 2. Phương án đã cân nhắc + +### PA-1 — Database-per-service (mỗi module 1 RDS logic riêng) + +| | | +|---|---| +| **Mô tả** | Mỗi module (Identity, Catalog, Cart & Order, Seller, Commission, Promotion, Review, Notification, Shipping) có 1 RDS instance/logic DB riêng — theo `SAD.md`/hồ sơ thầu (P1) | +| **Ưu** | Cô lập tải hoàn toàn — một module quá tải không ảnh hưởng module khác; dễ scale/tune riêng từng DB | +| **Nhược** | ~9-10 RDS instance phải patch/backup/monitor độc lập — vi phạm Conway với năng lực team hiện tại (`CON-05`); tăng chi phí vận hành đáng kể so với 1-2 instance | +| **Chi phí đảo ngược** | Cao — gộp lại thành 1 cụm sau này cần migrate dữ liệu qua nhiều DB, đồng bộ schema | + +### PA-2 — 1 cụm RDS chính, schema-per-module (ranh giới logic, chung instance) *(chọn)* + +| | | +|---|---| +| **Mô tả** | 1 cụm RDS PostgreSQL Multi-AZ, mỗi module có schema riêng trong cùng instance (ranh giới logic rõ ràng qua schema + quyền truy cập DB user riêng theo schema) | +| **Ưu** | Ít thành phần phải vận hành hơn (1 instance thay vì ~9-10) — khớp Conway với team hiện tại; vẫn giữ ranh giới logic rõ ràng qua schema (không phải 1 schema dùng chung hỗn loạn) | +| **Nhược** | Một module quá tải (VD Catalog bị truy vấn nặng mùa flash sale) có thể ảnh hưởng module khác dùng chung instance (Cart & Order, Commission…) — chưa đo tải gộp thật | +| **Chi phí đảo ngược** | Trung bình-cao — tách read replica/DB riêng cho từng module sau khi đã gộp là một dự án migration riêng | + +### PA-3 — 1 cụm RDS, 1 schema chung (không phân tách theo module) + +| | | +|---|---| +| **Mô tả** | Tất cả bảng của mọi module nằm chung 1 schema, không phân tách quyền truy cập theo module | +| **Ưu** | Đơn giản nhất về mặt cấu hình DB ban đầu | +| **Nhược** | Không có ranh giới logic nào giữa các module — vi phạm `D7` ("mỗi thực thể có đúng một chủ sở hữu" cần ranh giới rõ để enforce); dễ phát sinh coupling ngầm (module A viết trực tiếp bảng của module B) làm mất tác dụng modular monolith | +| **Chi phí đảo ngược** | Cao — tách schema sau khi code đã coupling chéo là công việc tái cấu trúc lớn | + +### Bảng so sánh + +| Tiêu chí | PA-1 (DB-per-service) | PA-2 (1 cụm, schema-per-module) | PA-3 (1 cụm, 1 schema) | +|---|---|---|---| +| Số thành phần phải vận hành | ~9-10 | 1 | 1 | +| Cô lập tải giữa module | ✅ Hoàn toàn | 🟠 Một phần (chung instance) | ❌ Không | +| Ranh giới logic rõ ràng (`D7`) | ✅ | ✅ (qua schema) | ❌ | +| Khớp Conway (`CON-05`) | ❌ | ✅ | ✅ | + +## 3. Quyết định + +> **Chọn PA-2 — 1 cụm RDS PostgreSQL Multi-AZ chính, schema-per-module, cho mọi module ngoại trừ +> Payment.** + +**Vì sao:** Cân bằng giữa khớp Conway (`CON-05`, ít thành phần vận hành hơn database-per-service) +và vẫn giữ ranh giới logic rõ ràng qua schema (khác PA-3 gộp chung 1 schema mất kiểm soát ranh +giới dữ liệu). + +**Phạm vi áp dụng:** Toàn bộ module ngoại trừ Payment (đã có RDS riêng theo `ADR-002`). + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| **`POC-02` PASS** — p95 write ≤300ms, p95 read ≤200ms, CPU <75%, connection pool không exhaust | Tech Lead/DBA | 🔴 **Chưa chạy** (`ARISK-02`) | +| Thiết kế connection pool theo module (giới hạn để tránh một module chiếm hết pool) | Tech Lead/DBA | Chưa thiết kế — thuộc `DAT` | + +🔴 **Bắt buộc theo `decision-radar.md §2`/§6** — điểm radar ~8 (≥8) đồng nghĩa ADR này **không +được chuyển `Accepted`** cho tới khi `POC-02` chạy xong và PASS. Nếu `POC-02` FAIL: tách read +replica/DB riêng cho Catalog/Search sớm hơn dự kiến, cập nhật `TCO` (chi phí hạ tầng tăng, tiệm +cận P1 cho phần đó — đã cảnh báo ở `TCO §3.3`). + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-1 — Database-per-service | Vi phạm Conway với năng lực team hiện tại; tăng chi phí vận hành đáng kể | `CON-05`, `OPT §4` tiêu chí 5 | Nếu `POC-02` FAIL nghiêm trọng (không thể khắc phục bằng read replica) **và** team đủ lớn để vận hành nhiều DB — xét lại cho riêng module gây nghẽn (VD tách Catalog) | +| PA-3 — 1 cụm, 1 schema chung | Không có ranh giới logic — vi phạm `D7`, dễ coupling chéo giữa module | `D7` (design-rules) | Không xét lại — đây là anti-pattern cho modular monolith, không phải trade-off hợp lý | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Chỉ 1 RDS instance chính phải patch/backup/monitor (ngoài Payment) — khớp năng lực team, giảm + chi phí vận hành đáng kể so với database-per-service +- Ranh giới logic rõ ràng qua schema — enforce được `D7` (mỗi thực thể có đúng một chủ) + +**Hệ quả tiêu cực phải sống chung** + +- Một module quá tải (VD Catalog mùa flash sale) có thể ảnh hưởng module khác dùng chung instance + — cần connection pool giới hạn theo module để giảm thiểu +- Nếu `POC-02` FAIL, phải tách read replica sớm hơn dự kiến — tăng chi phí hạ tầng ngoài kế hoạch + ban đầu + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Tách một module ra RDS riêng sau khi đã gộp | Migration dữ liệu + đồng bộ song song trong thời gian chuyển đổi — dự án riêng, không miễn phí | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Chạy `POC-02` theo tiêu chí đã viết trước | Tech Lead/DBA | Trước khi `Accepted` | `ARISK_e-commerce_v1.0.md §6` | +| Thiết kế connection pool giới hạn theo module | SA (hoạt động `dat`) + DBA | GĐ2 tiếp theo | `DAT_e-commerce` | +| Kế hoạch tách read replica dự phòng nếu `POC-02` FAIL | Tech Lead/DBA | Khi có kết quả `POC-02` | `TDEBT` (GĐ3) hoặc cập nhật `TCO` | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| `POC-02` — tải ghi/đọc gộp | Load test staging, cấu hình instance thật | Trước `Accepted`, lặp lại trước mỗi major release | — (ghi vào `ARISK §6`) | +| Không có bảng nào bị truy cập chéo schema (module A viết trực tiếp bảng module B) | DB user permission theo schema + code review/lint | CI (schema access lint) | `FIT-09` (ứng viên) | +| CPU/connection pool RDS trong ngưỡng ở production | CloudWatch metric + alarm | Production, liên tục | — | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| `POC-02` FAIL | Không đạt tiêu chí PASS đã viết trước | Tech Lead/DBA | +| CPU RDS production vượt 75% thường xuyên | > 3 lần/tuần trong giờ cao điểm | SRE | +| Connection pool exhaust trong production | Bất kỳ lần nào | SRE | + +## 8. Tham chiếu + +- POC: `ARISK_e-commerce_v1.0.md §6 POC-02` +- Bài đo: `FIT-09` (ứng viên GĐ3) +- Tài liệu ngoài: `QAS_e-commerce_v1.0.md §A3 QAS-006` +- Thảo luận: `ASR_e-commerce_v1.0.md §B2 ASR-006`, `OPT_e-commerce_v1.0.md §8 ASM-08` + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung đủ làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`) | Radar 8 — bắt buộc `POC-02` (tải RDS gộp) PASS trước khi `Accepted`; chưa chạy | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: 🔴 — +> `AG2` chưa ký. diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-007_cho-quyet-dinh-ownership-authz-cart-order.md b/sa-output/e-commerce/02-architecture/adr/ADR-007_cho-quyet-dinh-ownership-authz-cart-order.md new file mode 100644 index 0000000..7333857 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-007_cho-quyet-dinh-ownership-authz-cart-order.md @@ -0,0 +1,171 @@ +# ADR-007 — Chỗ ra quyết định ownership/authz cho Cart & Order là service (có cache Redis), không phải gateway + +*Tên file: `adr/ADR-007_cho-quyet-dinh-ownership-authz-cart-order.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | SA + Tech Lead (đề xuất SA, chốt SA+Tech Lead theo `decision-radar.md §5`; Security có quyền phủ quyết vì đây là quyết định authz) | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **~6/10** | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-007` · `QAS-010` · `QAS-003`/`QAS-004` (A4 xung đột dòng 1) · `RBAC_CartCheckout` (BA) §2 · `CMP-02`, `CMP-04`, `CMP-15` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-007` và đổi trạng thái bản cũ thành `Superseded by`. + +--- + +## 1. Bối cảnh + +Mọi thao tác đọc/sửa/xoá `Cart`/`CartItem`/`Order` phải được đối chiếu quyền sở hữu: Guest theo +`session_id` của chính phiên, Customer theo `customer_id` của chính họ — 0% truy cập chéo (IDOR) +thành công (`ASR-007`, `QAS-010`). `RBAC_CartCheckout_v1.0.md §2` (BA) đã xác nhận ma trận: cả +Guest và Customer đều **không** được xem giỏ hàng/đơn hàng của người khác. Vấn đề kỹ thuật cần +chốt: **kiểm tra ownership ở đâu** (gateway hay service) và **có cache không** — vì kiểm tra mỗi +request cạnh tranh trực tiếp với ngân sách latency của `QAS-003`/`QAS-004` (đã ghi nhận xung đột +ở `QAS §A4` dòng 1). + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `ASR-007` | 100% request qua kiểm tra ownership, 0% IDOR thành công | +| `QAS-010` | Test tự động xác nhận 0 lượt IDOR thành công | +| `QAS-003`/`QAS-004` | p95 ≤500ms (`GET /v1/cart`), p95 ≤300ms (`PATCH`/`DELETE /v1/cart/items`) — 🔴 số SA đề xuất, `OQ-018`/`OQ-019` chưa xác nhận | +| `RBAC_CartCheckout §2` (BA) | Guest theo `session_id`, Customer theo `customer_id` — ma trận đã xác nhận | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| Guest/Customer không được xem giỏ/đơn của người khác | 🟢 Đã kiểm chứng | `RBAC_CartCheckout §2` (BA), đã duyệt từng phần | +| Query DB mỗi request để kiểm tra ownership sẽ vi phạm ngân sách latency `QAS-003`/`QAS-004` | 🟡 Ước lượng có cơ sở | Chưa có bài đo thật — cần đo sau khi có thiết kế cụ thể (`QAS §A4`) | +| Redis cache session/ownership đủ nhanh để giữ latency trong ngân sách | 🔴 Giả định | Chưa có POC riêng cho cache ownership | + +## 2. Phương án đã cân nhắc + +### PA-1 — Kiểm tra ownership tại API Gateway/ALB (trước khi vào service) + +| | | +|---|---| +| **Mô tả** | Gateway giải mã JWT/session, đối chiếu ownership ngay tại lớp gateway trước khi forward request vào Cart & Order | +| **Ưu** | Chặn sớm request không hợp lệ, giảm tải cho service phía sau | +| **Nhược** | Gateway (ALB/API Gateway managed) không có quyền truy cập trực tiếp dữ liệu nghiệp vụ (`CartItem` thuộc về ai) — phải gọi ngược lại service hoặc DB để biết ownership, mất lợi thế "chặn sớm"; đặt business logic vào lớp hạ tầng dùng chung vi phạm ranh giới "cái CMP-01 KHÔNG làm" đã ghi ở `SAD §4.1` | +| **Chi phí đảo ngược** | Trung bình — chuyển logic xuống service sau này cần tách lại code đã đặt sai lớp | + +### PA-2 — Kiểm tra ownership tại service (Cart & Order), query DB mỗi request + +| | | +|---|---| +| **Mô tả** | Service tự đối chiếu `session_id`/`customer_id` với DB mỗi request, không cache | +| **Ưu** | Đơn giản, luôn chính xác 100% (không có dữ liệu cache cũ) | +| **Nhược** | Thêm 1 round-trip DB cho mỗi request — cạnh tranh trực tiếp với ngân sách latency `QAS-003`/`QAS-004` (đã ghi xung đột `QAS §A4`) | +| **Chi phí đảo ngược** | Thấp — thêm cache sau này là cải tiến, không phải viết lại | + +### PA-3 — Kiểm tra ownership tại service, cache session/ownership trong Redis *(chọn)* + +| | | +|---|---| +| **Mô tả** | Service tự đối chiếu ownership; thông tin session/ownership được cache trong Redis (TTL ngắn), chỉ query DB khi cache miss | +| **Ưu** | Giữ ranh giới đúng (authz logic ở service sở hữu dữ liệu, không phải gateway); giảm round-trip DB cho phần lớn request — cân bằng được `ASR-007` và `QAS-003`/`004` | +| **Nhược** | Thêm thành phần cache cần vận hành (đã có ElastiCache Redis trong kiến trúc — `CMP-15`); cần xử lý đúng khi cache invalidate (VD khi Guest session hết hạn, khi Customer đổi giỏ hàng) | +| **Chi phí đảo ngược** | Thấp-trung bình — bỏ cache (quay về PA-2) nếu phát hiện vấn đề nhất quán, không cần viết lại toàn bộ | + +### Bảng so sánh + +| Tiêu chí | PA-1 (Gateway) | PA-2 (Service, không cache) | PA-3 (Service + Redis cache) | +|---|---|---|---| +| Đúng ranh giới sở hữu logic (`SAD §4.1` "cái CMP-01 KHÔNG làm") | ❌ | ✅ | ✅ | +| Đáp ứng ngân sách latency `QAS-003`/`004` | 🔶 Chưa rõ (vẫn cần gọi ngược) | ❌ Rủi ro cao | ✅ (kỳ vọng, chưa đo) | +| Độ phức tạp vận hành thêm | Thấp | Thấp nhất | Trung bình (thêm cache) | +| Đảm bảo 0% IDOR (`ASR-007`) | ✅ (nếu gọi ngược đúng) | ✅ | ✅ (cần xử lý invalidate đúng) | + +## 3. Quyết định + +> **Chọn PA-3 — Kiểm tra ownership tại service (Cart & Order), cache session/ownership trong +> Redis, query DB khi cache miss.** + +**Vì sao:** Đây là phương án duy nhất giữ đúng ranh giới sở hữu logic (`CMP-01` API +Gateway/ALB đã ghi rõ "không tự quyết định authz chi tiết" ở `SAD §4.1`) trong khi vẫn có cơ hội +đáp ứng ngân sách latency `QAS-003`/`004` tốt hơn PA-2. + +**Phạm vi áp dụng:** Toàn bộ endpoint `GET`/`PATCH`/`DELETE /v1/cart*` và các endpoint liên quan +`Order` trong phạm vi Cart & Order Service. + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| Đo lại `QAS-003`/`QAS-004` sau khi có thiết kế cache cụ thể (theo `QAS §A4` đã ghi) | QA + Tech Lead | Chưa đo | +| Thiết kế cơ chế invalidate cache đúng khi session hết hạn/giỏ hàng đổi | Tech Lead | Chưa thiết kế | +| Không bắt buộc POC riêng (radar 6, dưới ngưỡng 8) nhưng khuyến nghị đo trước khi `Accepted` | Tech Lead | — | + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-1 — Kiểm tra tại Gateway | Gateway không có quyền truy cập dữ liệu nghiệp vụ, đặt sai ranh giới logic | `SAD §4.1` cột "cái nó KHÔNG làm" của `CMP-01` | Nếu về sau có một BFF (Backend-for-Frontend) layer sở hữu session tập trung — xét lại cho riêng phần xác thực (không phải authz chi tiết theo dữ liệu) | +| PA-2 — Service, không cache | Rủi ro vi phạm ngân sách latency `QAS-003`/`004` do round-trip DB mỗi request | `QAS-003`, `QAS-004`, `QAS §A4` | Nếu đo thực tế cho thấy query DB đơn giản (index tốt) đủ nhanh mà không cần cache — đơn giản hoá bằng cách bỏ Redis, giảm 1 thành phần vận hành | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Giữ đúng ranh giới sở hữu logic theo domain (khớp `SAD §4.1`) +- Có cơ hội đáp ứng ngân sách latency tốt hơn nhờ cache + +**Hệ quả tiêu cực phải sống chung** + +- Redis trở thành một điểm phụ thuộc thêm cho luồng Cart & Order — cần thiết kế đường lỗi khi + Redis chậm/hỏng (thuộc `FAIL`, hoạt động 8): fallback về query DB trực tiếp khi cache miss/lỗi +- Rủi ro dữ liệu cache cũ (stale) nếu invalidate không đúng lúc — cần kiểm thử kỹ + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Chuyển sang kiểm tra tại Gateway sau này | Viết lại toàn bộ luồng xác thực + đặt lại ranh giới logic — không khuyến khích | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Đo `QAS-003`/`QAS-004` với thiết kế cache cụ thể | QA + Tech Lead | GĐ3 (trước go-live) | `FIT`/bài đo GĐ3 | +| Thiết kế cơ chế invalidate cache | SA (hoạt động `sec`) + Tech Lead | GĐ2 tiếp theo | `SEC_e-commerce` §2 | +| Thiết kế fallback khi Redis lỗi/chậm | SA (hoạt động `fail`) | GĐ2 tiếp theo | `FAIL_e-commerce` | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Test IDOR tự động (gọi API với token/session không phải chủ sở hữu) — 0 lượt thành công | Integration test (tương ứng `AC-US003-12/13` BA) | CI + staging trước mỗi release | — (đã có ở `QAS-010`) | +| API Gateway (`CMP-01`) không chứa logic authz chi tiết theo dữ liệu | Code review + kiến trúc lint | CI | `FIT-10` (ứng viên) | +| Latency `GET`/`PATCH`/`DELETE /v1/cart*` đạt ngân sách sau khi có cache | k6 load test | Staging, trước mỗi release | — (đã có ở `QAS-003`/`004`) | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Bài đo `QAS-003`/`004` sau khi có cache vẫn không đạt ngân sách | Vượt p95 đề xuất | Tech Lead | +| Phát hiện lỗi cache invalidate gây IDOR hoặc dữ liệu cũ ảnh hưởng nghiệp vụ | Bất kỳ sự cố production | Security/SRE | + +## 8. Tham chiếu + +- POC: Không bắt buộc — khuyến nghị đo trước `Accepted` +- Bài đo: `QAS-003`, `QAS-004`, `QAS-010` + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung đủ làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`) | Chưa có người Security để ký (`ADL §8` việc #7) — ngoại lệ dự án chạy thử không thay được chữ ký chuyên môn Security | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: 🔴 — +> `AG2` chưa ký. +- Tài liệu ngoài: `RBAC_CartCheckout_v1.0.md §2` (BA) +- Thảo luận: `ASR_e-commerce_v1.0.md §B2 ASR-007`, `QAS_e-commerce_v1.0.md §A4` (xung đột dòng 1) diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-008_vung-luu-tru-pii-chinh-sach-chia-se-seller.md b/sa-output/e-commerce/02-architecture/adr/ADR-008_vung-luu-tru-pii-chinh-sach-chia-se-seller.md new file mode 100644 index 0000000..ba87b1b --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-008_vung-luu-tru-pii-chinh-sach-chia-se-seller.md @@ -0,0 +1,180 @@ +# ADR-008 — Vùng lưu trữ dữ liệu cá nhân (residency) và chính sách chia sẻ PII cho seller khi tách đơn + +*Tên file: `adr/ADR-008_vung-luu-tru-pii-chinh-sach-chia-se-seller.md`* + +| | | +|---|---| +| **Status** | `Proposed` *(🔴 — phủ quyết thuộc Security/Legal, chưa có người, xem `OQ-007`)* | +| **Date** | 2026-09-15 | +| **Người quyết** | **Security/Legal** (theo `decision-radar.md §5` — "Bảo mật, quyền riêng tư": đề xuất SA, chốt Security, phủ quyết Security). **Chưa có đại diện Pháp chế/Bảo mật được chỉ định** — `OQ-007` mở từ GĐ1, kế thừa `RISK-03` của BA | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **~7/10** | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-008` · `QAS-011` · `CON-06` · `ASM-04` · `RBAC_CartCheckout §4` (BA) · `OQ-007` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-008` và đổi trạng thái bản cũ thành `Superseded by`. + +--- + +## 1. Bối cảnh + +Khi tách đơn theo seller (`ADR-003`), hệ thống phải chia sẻ một số trường PII của khách hàng +(địa chỉ giao hàng, số điện thoại người nhận) cho seller tương ứng để họ giao hàng. `DRV-07` ghi +nhận: việc này **chưa được rà soát** theo Nghị định 13/2023 vì dự án chưa có đại diện Pháp +chế/Bảo mật được chỉ định (`OQ-007`, kế thừa `RISK-03` của BA). `RBAC_CartCheckout §4` (BA) đã +đánh dấu "mức che dữ liệu khi hiển thị cho seller — chưa chốt". `ASM-04` (residency +`ap-southeast-1` đủ đáp ứng NĐ13/2023) cũng chưa được xác nhận. + +🔴 **Đây là ADR mà SA KHÔNG có thẩm quyền chốt** — theo `decision-radar.md §5` và `D10`, quyết +định bảo mật/quyền riêng tư thuộc Security, phủ quyết thuộc Security. SA chỉ chuẩn bị phương án +và danh sách trường để người có thẩm quyền quyết. + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `CON-06` | NĐ13/2023 — bảo vệ dữ liệu cá nhân, cứng, không thương lượng | +| `ASR-008` | Data-minimization khi chia sẻ PII cho seller + xác nhận residency trước go-live | +| `QAS-011` | 100% trường PII rà soát trước go-live, 0 trường dư thừa | +| `RBAC_CartCheckout §4` (BA) | Mức che dữ liệu khi hiển thị cho seller — chưa chốt | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| NĐ13/2023 áp dụng cho cả PII khách hàng và giấy tờ KYC seller | 🟢 Đã kiểm chứng | `CON-06`, pháp luật hiện hành | +| Region `ap-southeast-1` (Singapore) đáp ứng đủ yêu cầu residency của NĐ13/2023 | 🔴 Giả định (`ASM-04`) | Chưa có xác nhận Pháp chế — NĐ13/2023 không yêu cầu dữ liệu phải nằm trong lãnh thổ VN tuyệt đối trong mọi trường hợp, nhưng cần đánh giá cụ thể theo loại dữ liệu | +| Danh sách trường PII "cần thiết để giao hàng" đã đầy đủ và không dư thừa | 🔴 Giả định | SA đề xuất ở §2, chưa có Pháp chế/Bảo mật rà soát | + +## 2. Phương án đã cân nhắc + +### PA-1 — Chia sẻ toàn bộ hồ sơ khách hàng cho seller (không data-minimization) + +| | | +|---|---| +| **Mô tả** | Khi tách đơn, gửi toàn bộ thông tin `Customer` (bao gồm email, lịch sử mua hàng…) cho seller tương ứng | +| **Ưu** | Đơn giản nhất về mặt kỹ thuật — không cần lọc trường | +| **Nhược** | Vi phạm rõ nguyên tắc data-minimization của NĐ13/2023; tăng đáng kể bề mặt rủi ro nếu seller bị lộ dữ liệu (seller không có cùng mức kiểm soát bảo mật như sàn) | +| **Chi phí đảo ngược** | Cao — nếu vi phạm bị phát hiện sau go-live, phải thu hồi truy cập + có thể chịu chế tài pháp lý | + +### PA-2 — Whitelist trường tối thiểu cần thiết để giao hàng *(đề xuất, chờ Security/Legal chốt)* + +| | | +|---|---| +| **Mô tả** | Chỉ chia sẻ: `recipient_name`, `phone`, `address_line` cho seller tương ứng với `OrderSeller` của họ — không chia sẻ email, lịch sử mua hàng, hay thông tin của các seller khác trong cùng `Order` | +| **Ưu** | Đáp ứng nguyên tắc data-minimization; giới hạn bề mặt rủi ro đúng phạm vi cần thiết cho nghiệp vụ (giao hàng) | +| **Nhược** | Cần cơ chế lọc trường chính xác ở tầng API (không được lộ nhầm trường khi trả response cho seller); cần review định kỳ khi thêm trường mới vào `Customer`/`Order` | +| **Chi phí đảo ngược** | Thấp — mở rộng whitelist sau này nếu cần thêm trường là thay đổi nhỏ, không phải viết lại | + +### PA-3 — Không chia sẻ trực tiếp, dùng dịch vụ vận chuyển làm trung gian (ẩn danh hoá địa chỉ) + +| | | +|---|---| +| **Mô tả** | Sàn không gửi PII trực tiếp cho seller; địa chỉ giao hàng được gửi thẳng cho GHN/GHTK, seller chỉ nhận mã vận đơn để đóng gói mà không biết địa chỉ cụ thể của khách | +| **Ưu** | Giảm bề mặt rủi ro nhiều nhất — seller không bao giờ thấy PII khách hàng | +| **Nhược** | Không khớp mô hình vận hành thực tế của marketplace VN hiện tại (seller thường tự đóng gói và ghi địa chỉ lên đơn hàng, không phải drop-shipping qua đơn vị vận chuyển trung gian hoàn toàn); cần thay đổi quy trình vận hành seller đáng kể — vượt phạm vi MVP | +| **Chi phí đảo ngược** | Cao — thay đổi mô hình vận hành sau go-live ảnh hưởng trải nghiệm seller đã quen | + +### Bảng so sánh + +| Tiêu chí | PA-1 | PA-2 | PA-3 | +|---|---|---|---| +| Đáp ứng data-minimization (`CON-06`, `QAS-011`) | ❌ | ✅ | ✅ Cao nhất | +| Khớp mô hình vận hành seller hiện tại | ✅ | ✅ | ❌ Cần thay đổi lớn | +| Độ phức tạp kỹ thuật thêm | Thấp | Trung bình (lọc trường) | Cao (tích hợp vận chuyển sâu hơn) | + +## 3. Quyết định + +> **Đề xuất PA-2 — Whitelist trường tối thiểu (`recipient_name`, `phone`, `address_line`) cho +> seller tương ứng với `OrderSeller` của họ.** + +🔴 **Đây là đề xuất của SA, chưa phải quyết định.** Theo `D10`, chấp nhận rủi ro bảo mật/quyền +riêng tư là quyết định của Security/Legal, không phải của SA. ADR này giữ `Proposed` cho tới khi +có đại diện Pháp chế/Bảo mật thật rà soát và ký. + +**Vì sao đề xuất PA-2:** Cân bằng giữa đáp ứng data-minimization (loại PA-1) và khả thi vận hành +trong MVP (loại PA-3, vốn cần thay đổi mô hình vận hành seller ngoài phạm vi hiện tại). + +**Phạm vi áp dụng (nếu được chốt):** Toàn bộ luồng tách đơn theo seller (`ADR-003`) và mọi API +trả dữ liệu `OrderSeller` cho phía Seller Management. + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| PO chỉ định đại diện Pháp chế/Bảo mật | PO | 🔴 **Chưa có người** (`OQ-007`, mở từ GĐ1) | +| Đại diện đó rà soát danh sách trường whitelist ở §2 PA-2 và ký chấp nhận | Security/Legal | Chờ có người | +| Xác nhận `ASM-04` — region `ap-southeast-1` đáp ứng đủ residency NĐ13/2023 | Security/Legal | Chưa xác nhận | + +🔴 **ADR này chặn hoàn toàn cho tới khi có người** — không có ai để ký ngoài SA đề xuất. Đây là +điểm chặn nghiêm trọng nhất trong 12 ADR (theo `GUIDE.md`: "phát hiện muộn nhất và đau nhất luôn +đến từ đây"). + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-1 — Chia sẻ toàn bộ hồ sơ | Vi phạm rõ data-minimization của NĐ13/2023 | `CON-06`, `QAS-011` | Không xét lại — vi phạm pháp luật | +| PA-3 — Ẩn danh hoá qua vận chuyển trung gian | Không khớp mô hình vận hành seller hiện tại; vượt phạm vi MVP | Mô hình vận hành seller đã chốt ở brief | Nếu về sau chuyển sang mô hình fulfillment tập trung (kho sàn quản lý đóng gói) — xét lại, ngoài phạm vi MVP hiện tại | + +## 5. Hệ quả + +**Hệ quả tích cực** *(nếu PA-2 được Security/Legal chấp nhận)* + +- Giới hạn bề mặt rủi ro đúng phạm vi cần thiết cho nghiệp vụ giao hàng +- Có cơ sở whitelist rõ ràng để audit định kỳ + +**Hệ quả tiêu cực phải sống chung** + +- Cần cơ chế lọc trường chính xác ở tầng API — rủi ro lộ nhầm trường nếu code thay đổi không rà + soát lại whitelist +- Chưa có người ký — dự án phải chấp nhận rủi ro pháp lý mở cho tới khi có đại diện Pháp chế + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Mở rộng chia sẻ thêm trường sau khi đã chốt whitelist hẹp | Cần rà soát lại toàn bộ với Pháp chế trước khi thay đổi — không tự ý mở rộng | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| PO chỉ định đại diện Pháp chế/Bảo mật | PO | Trước go-live, càng sớm càng tốt | `OQ-007` | +| Đại diện đó rà soát whitelist + xác nhận residency | Security/Legal | Sau khi có người | — | +| Thiết kế cơ chế lọc trường ở tầng API | SA (hoạt động `sec`/`dat`) | GĐ2 tiếp theo | `SEC_e-commerce`, `DAT_e-commerce` | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Response API trả cho Seller Management chỉ chứa đúng trường whitelist | Contract test / schema validation | CI | `FIT-11` (ứng viên) | +| Audit định kỳ so khớp trường thực tế truyền cho seller vs whitelist đã duyệt | Review thủ công định kỳ bởi Security/Legal | Hàng quý (đề xuất, chưa chốt tần suất) | `⚠️ Khuyến nghị — không tự kiểm được hoàn toàn, cần review thủ công` | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Có đại diện Pháp chế/Bảo mật được chỉ định | Ngay khi có | PO | +| Phát hiện lộ trường PII dư thừa qua audit | Bất kỳ phát hiện nào | Security | +| NĐ13/2023 hoặc quy định liên quan thay đổi | Khi có văn bản pháp luật mới | Legal | + +## 8. Tham chiếu + +- POC: Không áp dụng +- Bài đo: Audit thủ công định kỳ (chưa chốt tần suất) +- Tài liệu ngoài: `RBAC_CartCheckout_v1.0.md §4` (BA), `RISK_CartCheckout_v1.0.md RISK-03` (BA) + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung đủ làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`) | Chặn hoàn toàn — PO chưa chỉ định đại diện Pháp chế/Bảo mật (`OQ-007`); không ai có thẩm quyền ký | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: 🔴 — +> `AG2` chưa ký. +- Thảo luận: `ASR_e-commerce_v1.0.md §B2 ASR-008`, `ARISK_e-commerce_v1.0.md §3 ARISK-06` diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-009_chien-luoc-ha-dr-dich-vu-giao-dich-loi.md b/sa-output/e-commerce/02-architecture/adr/ADR-009_chien-luoc-ha-dr-dich-vu-giao-dich-loi.md new file mode 100644 index 0000000..d5665f4 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-009_chien-luoc-ha-dr-dich-vu-giao-dich-loi.md @@ -0,0 +1,169 @@ +# ADR-009 — Chiến lược HA/DR cho nhóm dịch vụ giao dịch lõi (Payment, Cart & Order, Identity & Access): RPO ≤15 phút, RTO ≤1 giờ + +*Tên file: `adr/ADR-009_chien-luoc-ha-dr-dich-vu-giao-dich-loi.md`* + +| | | +|---|---| +| **Status** | `Proposed` *(🔴 radar ≥8 — theo `decision-radar.md §2`/§6, **không được chuyển `Accepted` khi chưa diễn tập DR**; đây cũng là điều kiện tiên quyết ký AG2, không chỉ điều kiện riêng của ADR này)* | +| **Date** | 2026-09-15 | +| **Người quyết** | SA + Ops/SRE (hạ tầng/HA-DR — `decision-radar.md §5`: đề xuất SA, chốt SA+SRE, phủ quyết PO nếu vượt ngân sách) | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **~9/10** — 🔴 bắt buộc diễn tập DR trước `Accepted` | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-010` · `QAS-008` · `OQ-022` · `DEC-12` · `CMP-02`, `CMP-04`, `CMP-11` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-009` và đổi trạng thái bản cũ thành `Superseded by`. + +--- + +## 1. Bối cảnh + +Payment, Cart & Order, Identity & Access (`ASR-010` gọi là "nhóm giao dịch cốt lõi") phải có khả +năng khôi phục sau sự cố với RPO ≤15 phút và RTO ≤1 giờ. `QAS-008` đã ghi rõ: con số này **kế +thừa nguyên trạng** từ `SAD.md §5.3.2/§9.5.2` (tài liệu trước khi có pipeline `sa-lifecycle`), +**chưa được SA thiết kế lại** ở lượt chạy này, và **chưa từng diễn tập** — theo `SKILL.md` mục 7: +"RTO/RPO chưa diễn tập là RTO/RPO trên giấy". `DEC-12` (duyệt từng phần `QAS`) đã chốt điều kiện: +diễn tập DR phải thực hiện **trước khi ký AG2** — đây không chỉ là điều kiện riêng của ADR này mà +là điều kiện tiên quyết của cả gate AG2. + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `ASR-010` | RPO ≤15 phút, RTO ≤1 giờ cho Payment/Cart&Order/Identity — phải chứng minh bằng diễn tập trước AG2 | +| `QAS-008` | Con số kế thừa từ `SAD.md`, chưa thiết kế lại, chưa diễn tập | +| `OQ-022` | Lịch diễn tập DR đầu tiên — vẫn chờ Ops/SRE, đã chốt là điều kiện bắt buộc AG2 (`DEC-12`) | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| RPO ≤15 phút / RTO ≤1 giờ là mục tiêu đã "chốt" trong tài liệu gốc | 🟡 Ước lượng có cơ sở | `SAD.md §5.3.2/§9.5.2` — nhưng là tài liệu kỹ thuật trước pipeline `sa-*`, chưa qua AG2 | +| Kiến trúc Multi-AZ hiện tại (`SAD §7` deployment view) đủ để đạt RPO/RTO này | 🔴 Giả định | Chưa diễn tập failover thật | +| Đội Ops/SRE sau go-live đủ năng lực thực hiện failover trong 1 giờ | 🔴 Giả định | `OQ-008` (số người/năng lực Ops chưa xác nhận), `CON-08` | + +## 2. Phương án đã cân nhắc + +### PA-1 — Multi-AZ trong 1 region (`ap-southeast-1`), backup point-in-time, không multi-region + +| | | +|---|---| +| **Mô tả** | RDS Multi-AZ (failover tự động trong region), ECS Fargate chạy ≥2 AZ, backup PITR cho RDS (WAL archiving liên tục để đạt RPO ≤15 phút); DR = khôi phục từ backup/failover AZ trong cùng region | +| **Ưu** | Chi phí thấp hơn multi-region đáng kể; đủ chống chịu mất 1 AZ (sự cố phổ biến nhất); khớp `TCO §3.2` hiện tại (không phát sinh chi phí region thứ hai) | +| **Nhược** | Không chống được sự cố toàn bộ region `ap-southeast-1` (hiếm nhưng đã từng xảy ra với các nhà cung cấp cloud); RTO ≤1 giờ cho trường hợp phải khôi phục từ backup (không phải failover AZ) **chưa diễn tập** — có thể lạc quan hơn thực tế | +| **Chi phí đảo ngược** | Trung bình — nâng cấp lên multi-region sau này là dự án hạ tầng riêng, không phải cấu hình nhỏ | + +### PA-2 — Multi-region active-passive (thêm region dự phòng, VD `ap-northeast-1`) + +| | | +|---|---| +| **Mô tả** | Toàn bộ 3 service lõi có bản sao passive ở region thứ hai, đồng bộ liên tục, failover thủ công/tự động sang region đó khi region chính sập | +| **Ưu** | Chống được cả sự cố toàn region — RTO/RPO ổn định hơn trong kịch bản xấu nhất | +| **Nhược** | Tăng chi phí hạ tầng đáng kể (gấp ~1,5-2 lần cho 3 service lõi) — chưa có trong `TCO §3.2` hiện tại, cần PO duyệt ngân sách bổ sung; residency dữ liệu (NĐ13/2023) cần xác nhận lại nếu region thứ hai không phải `ap-southeast-1` (liên quan `ADR-008`) | +| **Chi phí đảo ngược** | Thấp — có multi-region rồi thu hẹp về 1 region dễ hơn chiều ngược lại | + +### Bảng so sánh + +| Tiêu chí | PA-1 (Multi-AZ, 1 region) | PA-2 (Multi-region active-passive) | +|---|---|---| +| Chi phí hạ tầng thêm | Thấp (đã có trong `TCO`) | Cao — cần PO duyệt bổ sung | +| Chống chịu mất 1 AZ | ✅ | ✅ | +| Chống chịu mất toàn region | ❌ | ✅ | +| Khớp ngân sách hiện tại (`CON-01`, `TCO §3.2`) | ✅ | ❌ Chưa có trong ngân sách | +| Rủi ro residency nếu region 2 khác `ap-southeast-1` | N/A | Cần xác nhận lại (`ADR-008`) | + +## 3. Quyết định + +> **Chọn PA-1 — Multi-AZ trong `ap-southeast-1`, backup point-in-time, không multi-region ở +> MVP.** + +**Vì sao:** Khớp ngân sách hiện tại (`TCO §3.2` chưa tính chi phí multi-region) và đủ chống chịu +sự cố phổ biến nhất (mất 1 AZ). Multi-region là đánh đổi ngân sách vs độ sẵn sàng — thuộc thẩm +quyền PO (`D10`), chưa có đề nghị PO tăng ngân sách cho việc này. + +**Phạm vi áp dụng:** Payment, Cart & Order, Identity & Access (nhóm giao dịch cốt lõi theo +`ASR-010`). Không áp dụng cho Nhóm Hỗ trợ (chưa có yêu cầu RPO/RTO tương đương). + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| **Diễn tập DR (failover drill) thật** đạt RPO ≤15 phút, RTO ≤1 giờ | Ops/SRE | 🔴 **Chưa từng diễn tập** (`OQ-022`) | +| Lịch diễn tập đầu tiên được xác nhận | Ops/SRE | Mở | +| Đây là điều kiện tiên quyết ký AG2 (không chỉ điều kiện riêng ADR này) | Tech Lead + Security + Ops/SRE | Theo `DEC-12` | + +🔴 **Bắt buộc theo `decision-radar.md §2`/§6** — điểm radar ~9 (≥8) đồng nghĩa ADR này **không +được chuyển `Accepted`** cho tới khi có diễn tập DR thật. Nếu diễn tập cho kết quả không đạt: ghi +nhận vào `ARISK` mới, đánh giá lại kiến trúc backup/failover trước khi thử lại — không hạ thấp +tiêu chí RPO/RTO để "cho qua". + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-2 — Multi-region active-passive | Chi phí thêm chưa có trong ngân sách đã duyệt (`TCO §3.2`); chưa có nhu cầu nghiệp vụ rõ ràng cho chống chịu mất toàn region ở MVP | `CON-01`, `TCO §3.2` | Nếu PO chấp nhận tăng ngân sách **và** đánh giá rủi ro mất toàn region là không chấp nhận được cho MVP — trình bảng đánh đổi cho PO quyết (`D10`), chưa có yêu cầu này | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Khớp ngân sách hiện tại — không cần PO duyệt thêm chi phí ngoài `TCO §3.2` +- Đủ chống chịu sự cố phổ biến nhất (mất 1 AZ) mà không cần độ phức tạp vận hành của + multi-region + +**Hệ quả tiêu cực phải sống chung** + +- Không chống được sự cố toàn region `ap-southeast-1` — rủi ro đã ghi nhận, chấp nhận có ý thức + cho tới khi PO quyết định khác +- RTO ≤1 giờ cho khôi phục từ backup (không phải failover AZ tự động) phụ thuộc năng lực đội + Ops/SRE thật — chưa xác nhận (`OQ-008`) + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Nâng cấp lên multi-region sau go-live | Dự án hạ tầng riêng — thiết kế đồng bộ dữ liệu xuyên region, xác nhận lại residency, tăng chi phí vận hành liên tục | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Xác nhận lịch diễn tập DR đầu tiên | Ops/SRE | Trước khi ký AG2 | `OQ-022` | +| Chạy diễn tập DR, ghi kết quả | Ops/SRE | Trước khi `Accepted` và trước AG2 | `ARISK_e-commerce_v1.0.md` (kết quả mới) | +| Trình PO bảng đánh đổi multi-region nếu Ops/SRE thấy cần | SA + Ops/SRE | Sau lần diễn tập đầu tiên nếu phát hiện rủi ro cao | `TCO` (cập nhật nếu PO chấp nhận) | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Diễn tập failover AZ (dừng 1 AZ giả lập) đo RTO thật | Chaos engineering thủ công / AWS Fault Injection Simulator | Staging, sau đó production (giờ thấp điểm) | — (kết quả ghi vào `ARISK`) | +| Backup PITR chạy đúng tần suất để đạt RPO ≤15 phút | Kiểm tra cấu hình WAL archiving/backup schedule | CI/CD (kiểm tra hạ tầng) | `FIT-12` (ứng viên) | +| Runbook failover được viết và diễn tập theo đúng bước | Review thủ công + diễn tập | Định kỳ (đề xuất 2 lần/năm, chưa chốt) | `⚠️ Khuyến nghị — không tự kiểm được, cần diễn tập thủ công` | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Diễn tập DR không đạt RPO/RTO | RPO > 15 phút hoặc RTO > 1 giờ | Ops/SRE | +| PO yêu cầu nâng mức sẵn sàng lên multi-region | Khi PO chấp nhận chi phí bổ sung | PO | +| Sự cố production thật cho thấy RTO/RPO thực tế khác đo ở diễn tập | Bất kỳ lần nào | SRE | + +## 8. Tham chiếu + +- POC: Diễn tập DR (chưa chạy) — xem `ARISK_e-commerce_v1.0.md` (kết quả sẽ bổ sung) +- Bài đo: `FIT-12` (ứng viên GĐ3) +- Tài liệu ngoài: `QAS_e-commerce_v1.0.md §A3 QAS-008`, `e-commerce/docs/sections/09-van-hanh-kiem-thu.md §9.5.2` (kế thừa nguyên trạng) +- Thảo luận: `ASR_e-commerce_v1.0.md §B2 ASR-010`, `DEC-12` (00-index/DEC_e-commerce.md) + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung đủ làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`) | Radar 9 — bắt buộc diễn tập DR (failover drill) PASS trước khi `Accepted`, cũng là điều kiện tiên quyết `AG2`; chưa chạy | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: 🔴 — +> `AG2` chưa ký. diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-010_kien-truc-observability-alerting.md b/sa-output/e-commerce/02-architecture/adr/ADR-010_kien-truc-observability-alerting.md new file mode 100644 index 0000000..05bf410 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-010_kien-truc-observability-alerting.md @@ -0,0 +1,166 @@ +# ADR-010 — Kiến trúc observability & alerting cho dịch vụ giao dịch lõi + +*Tên file: `adr/ADR-010_kien-truc-observability-alerting.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | SA + Ops/SRE (hạ tầng — `decision-radar.md §5`) | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **~6/10** | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-011` · `QAS-013` · `CMP-02`, `CMP-04`, `CMP-11` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-010` và đổi trạng thái bản cũ thành `Superseded by`. + +--- + +## 1. Bối cảnh + +Sự cố lỗi 5xx tăng đột biến ở Cart & Order, Payment, Identity & Access phải được cảnh báo tự +động trong ≤1 phút; on-call phải acknowledge trong ≤15 phút (`ASR-011`, `QAS-013`). Cần chuẩn +log/metric/trace thống nhất cho 3 service lõi và pipeline cảnh báo kết nối kênh on-call. +`QAS-013` ghi rõ ngưỡng cảnh báo **kế thừa nguyên trạng** từ `SAD.md §9.4.1`, chưa từng diễn tập +inject lỗi. + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `ASR-011` | Chuẩn log/metric/trace thống nhất, pipeline cảnh báo ≤1 phút, on-call ack ≤15 phút | +| `QAS-013` | Diễn tập inject lỗi đo thời gian từ inject tới cảnh báo — chưa từng diễn tập | +| `CON-08` | Đội Ops trực theo ca + escalation 24/7 — giả định, chưa xác nhận số người thật (`OQ-008`) | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| Cần cảnh báo tự động cho 3 service lõi trong ≤1 phút | 🟢 Đã kiểm chứng | `ASR-011`, yêu cầu doanh thu phụ thuộc trực tiếp | +| CloudWatch Alarms/Synthetics đủ đáp ứng ngưỡng ≤1 phút trong ngữ cảnh này | 🔴 Giả định | Chưa diễn tập inject lỗi | +| Đội Ops đủ người để acknowledge ≤15 phút 24/7 | 🔴 Giả định | `OQ-008` chưa xác nhận | + +## 2. Phương án đã cân nhắc + +### PA-1 — CloudWatch Logs/Metrics/Alarms native (AWS) + PagerDuty/OpsGenie cho on-call + +| | | +|---|---| +| **Mô tả** | Dùng CloudWatch Logs cho log tập trung, CloudWatch Metrics/Alarms cho ngưỡng cảnh báo, X-Ray cho trace, kết nối PagerDuty/OpsGenie cho on-call rotation | +| **Ưu** | Managed hoàn toàn, tích hợp sẵn với ECS Fargate/RDS/SQS — không cần vận hành thêm cluster; chi phí theo mức dùng, dễ ước lượng | +| **Nhược** | CloudWatch Logs Insights có giới hạn về khả năng truy vấn phức tạp so với ELK/Datadog; chi phí có thể tăng nhanh nếu log volume lớn không được kiểm soát retention | +| **Chi phí đảo ngược** | Trung bình — chuyển sang stack khác (Datadog, ELK) sau này cần viết lại instrumentation code | + +### PA-2 — Self-hosted ELK/Grafana stack + +| | | +|---|---| +| **Mô tả** | Tự vận hành Elasticsearch/Logstash/Kibana + Prometheus/Grafana trên ECS/EKS riêng | +| **Ưu** | Khả năng truy vấn/dashboard linh hoạt hơn, không phụ thuộc vendor lock-in AWS | +| **Nhược** | Thêm cụm phải vận hành/patch/scale — vi phạm Conway với năng lực team hiện tại (cùng lý lẽ với việc loại Kafka/MSK ở `ADR-005`); tăng chi phí vận hành đáng kể | +| **Chi phí đảo ngược** | Cao — đã đầu tư vận hành cụm riêng thì chuyển sang managed service sau là bỏ phí đầu tư ban đầu | + +### PA-3 — Datadog/New Relic (SaaS bên thứ ba) + +| | | +|---|---| +| **Mô tả** | Dùng nền tảng observability SaaS thương mại, tích hợp qua agent/SDK | +| **Ưu** | Tính năng phong phú (APM, log correlation, dashboard sẵn), không cần vận hành hạ tầng riêng | +| **Nhược** | Chi phí SaaS theo host/dữ liệu có thể cao hơn CloudWatch ở quy mô lớn (`DRV-04` hàng nghìn–chục nghìn concurrent); thêm một nhà cung cấp bên ngoài cần đánh giá hợp đồng/dữ liệu residency (log có thể chứa thông tin nhạy cảm) | +| **Chi phí đảo ngược** | Trung bình — có thể chuyển sang CloudWatch/khác sau nhưng mất dashboard đã cấu hình | + +### Bảng so sánh + +| Tiêu chí | PA-1 (CloudWatch) | PA-2 (Self-hosted ELK) | PA-3 (Datadog/New Relic) | +|---|---|---|---| +| Khớp năng lực team (`CON-05`) | ✅ | ❌ Thêm cụm phải vận hành | ✅ | +| Chi phí dự đoán được | ✅ | 🔶 Chi phí nhân sự vận hành ẩn | 🔶 Có thể tăng theo scale | +| Tích hợp sẵn với AWS managed service đã chọn | ✅ | 🔶 Cần cấu hình thêm | 🔶 Cần agent riêng | +| Đã có trong `TCO §3.2`/ngân sách hiện tại | ✅ | ❌ Chưa tính | ❌ Chưa tính | + +## 3. Quyết định + +> **Chọn PA-1 — CloudWatch Logs/Metrics/Alarms + X-Ray (trace) + PagerDuty/OpsGenie (on-call).** + +**Vì sao:** Khớp năng lực team hiện tại (không thêm cụm phải vận hành, nhất quán với hướng managed +service đã chọn ở `ADR-001`/`ADR-005`) và đã có trong ước lượng ngân sách hiện tại. + +**Phạm vi áp dụng:** Toàn bộ 3 service lõi (Payment, Cart & Order, Identity & Access) ở giai đoạn +đầu; mở rộng cho Nhóm Hỗ trợ khi cần. + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| Diễn tập inject lỗi đo thời gian từ inject tới cảnh báo ≤1 phút | Ops/SRE | Chưa từng diễn tập (`QAS-013`) | +| Xác nhận công cụ on-call cụ thể (PagerDuty hay OpsGenie) và ngân sách | PO/Ops | Chưa chốt | +| Không bắt buộc POC riêng (radar 6, dưới ngưỡng 8) nhưng khuyến nghị diễn tập trước `Accepted` | Ops/SRE | — | + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-2 — Self-hosted ELK/Grafana | Thêm cụm phải vận hành, vi phạm Conway với năng lực team | `CON-05` | Nếu về sau team có SRE chuyên trách đủ lớn và cần khả năng truy vấn phức tạp hơn CloudWatch cung cấp — xét lại | +| PA-3 — Datadog/New Relic | Chi phí SaaS chưa có trong ngân sách hiện tại; thêm nhà cung cấp bên ngoài cần đánh giá residency dữ liệu log | `TCO §3.2`, `CON-06` | Nếu CloudWatch không đáp ứng đủ nhu cầu (VD thiếu APM sâu) và PO chấp nhận chi phí thêm — trình bảng đánh đổi | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Không thêm thành phần hạ tầng phải vận hành riêng — khớp năng lực team +- Chi phí dự đoán được, đã nằm trong ước lượng `TCO` + +**Hệ quả tiêu cực phải sống chung** + +- Khả năng truy vấn log phức tạp hạn chế hơn ELK/Datadog — có thể cần thêm công cụ bổ sung khi + hệ thống lớn hơn +- Chưa diễn tập inject lỗi — ngưỡng ≤1 phút vẫn là con số trên giấy cho tới khi diễn tập + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Chuyển sang Datadog/ELK sau khi đã cấu hình CloudWatch dashboard | Viết lại instrumentation + dashboard, di chuyển alert đã cấu hình | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Diễn tập inject lỗi đo thời gian cảnh báo | Ops/SRE | Trước go-live | `ARISK`/`QAS-013` (kết quả mới) | +| Chốt công cụ on-call cụ thể (PagerDuty/OpsGenie) | PO/Ops | GĐ2 tiếp theo (`inf`) | `INF_e-commerce` | +| Chuẩn hoá định dạng log + correlation id cho 3 service lõi | Tech Lead | GĐ3 (`AGD`) | `AGD` | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Diễn tập inject lỗi (dừng task ECS) đo thời gian tới cảnh báo | Chaos thủ công | Staging trước go-live, định kỳ sau đó | — (kết quả ghi vào `ARISK`) | +| Mọi service lõi ghi log theo định dạng chuẩn có `correlation_id` | Lint log format trong CI | CI | `FIT-13` (ứng viên) | +| Alert có kết nối kênh on-call thật, test bằng cảnh báo giả lập | Kiểm tra cấu hình PagerDuty/OpsGenie | Định kỳ (đề xuất hàng tháng) | `⚠️ Khuyến nghị — cần kiểm thủ công định kỳ` | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Diễn tập inject lỗi cho thấy thời gian cảnh báo > 1 phút | Bất kỳ lần nào | Ops/SRE | +| Chi phí CloudWatch vượt ngân sách dự kiến đáng kể | > 20% so với `TCO` | SRE/tài chính | + +## 8. Tham chiếu + +- POC: Diễn tập inject lỗi (chưa chạy) +- Bài đo: `FIT-13` (ứng viên GĐ3) +- Tài liệu ngoài: `QAS_e-commerce_v1.0.md §A3 QAS-013` +- Thảo luận: `ASR_e-commerce_v1.0.md §B2 ASR-011` + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung đủ làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`) | Chưa có chữ ký thật Ops/SRE; khuyến nghị diễn tập alerting trước khi chốt | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: 🔴 — +> `AG2` chưa ký. diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-011_chinh-sach-resilience-doi-tac-ngoai.md b/sa-output/e-commerce/02-architecture/adr/ADR-011_chinh-sach-resilience-doi-tac-ngoai.md new file mode 100644 index 0000000..2ae5d6a --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-011_chinh-sach-resilience-doi-tac-ngoai.md @@ -0,0 +1,159 @@ +# ADR-011 — Chính sách resilience chung khi đối tác thanh toán/vận chuyển bên ngoài lỗi (timeout/retry/fallback) + +*Tên file: `adr/ADR-011_chinh-sach-resilience-doi-tac-ngoai.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | SA + Tech Lead (tích hợp — `decision-radar.md §5`) | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **~6/10** | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-013` · `CON-04` · `ARISK-03` · `ARISK-04` · `CMP-10`, `CMP-11` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-011` và đổi trạng thái bản cũ thành `Superseded by`. + +--- + +## 1. Bối cảnh + +Hệ thống phải tích hợp đúng 4 đối tác đã chốt: VNPay, Momo (thanh toán), GHN, GHTK (vận chuyển, +có fallback chéo) — `CON-04`. Không đối tác nào có sandbox/hợp đồng thật tại thời điểm này +(`CTX §4.2`). `ASR-013` yêu cầu một chính sách resilience **chung** cho cả 4 đối tác (timeout, +retry, idempotent) thay vì mỗi đội tự chọn một kiểu khác nhau — đây là quyết định "thiết lập tiền +lệ" theo `decision-radar.md §4` (ngoại lệ để nhỏ thành ADR): áp dụng cho mọi tích hợp đối tác +ngoài tương lai, không chỉ 4 đối tác hiện tại. + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `ASR-013` | Chính sách timeout/retry/idempotent nhất quán cho VNPay/Momo/GHN/GHTK; GHN/GHTK cần fallback chéo | +| `CON-04` | 4 đối tác đã chốt danh tính, chưa có sandbox/hợp đồng thật | +| `ARISK-03` | VNPay/Momo — webhook chưa xác minh khả thi gần thời gian thực | +| `ARISK-04` | GHN/GHTK — cơ chế fallback chéo chưa kiểm chứng hoạt động đúng giữa 2 API khác nhau | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| Danh tính 4 đối tác đã chốt (không phải chờ chọn) | 🟢 Đã kiểm chứng | `CON-04` | +| Timeout đề xuất VNPay/Momo 10s, GHN/GHTK 8s | 🔴 Giả định — kế thừa từ `SAD.md §3.4`, chưa kiểm chứng sandbox thật | `CTX §4.2` | +| Fallback GHN↔GHTK hoạt động đúng khi chuyển đổi API giữa chừng | 🔴 Giả định | `ARISK-04`, chưa có tài liệu API/sandbox thật | + +## 2. Phương án đã cân nhắc + +### PA-1 — Mỗi đội tự thiết kế timeout/retry riêng cho từng đối tác (không có chính sách chung) + +| | | +|---|---| +| **Mô tả** | Không có ADR/chuẩn chung — mỗi dev tích hợp VNPay/Momo/GHN/GHTK tự quyết định timeout/retry theo kinh nghiệm cá nhân | +| **Ưu** | Linh hoạt tối đa cho từng đối tác cụ thể | +| **Nhược** | Không nhất quán — dev khác nhau chọn số khác nhau, khó audit/thay đổi hàng loạt khi cần; đúng bẫy đã cảnh báo ở `GUIDE.md` ("Bỏ qua đường lỗi vì sẽ xử lý lúc code") | +| **Chi phí đảo ngược** | Cao — chuẩn hoá lại sau khi đã có nhiều cách làm khác nhau tốn công rà soát từng điểm tích hợp | + +### PA-2 — Chính sách chung: timeout theo loại đối tác + retry có backoff + idempotency key bắt buộc, adapter riêng mỗi đối tác *(chọn)* + +| | | +|---|---| +| **Mô tả** | Một chuẩn chung áp dụng cho mọi đối tác ngoài: timeout cụ thể theo loại (thanh toán 10s, vận chuyển 8s — đề xuất, chờ kiểm chứng sandbox), retry ≤3 lần với exponential backoff + jitter, idempotency key bắt buộc cho mọi lời gọi ghi; mỗi đối tác có một adapter/anti-corruption layer riêng để cô lập thay đổi API của họ | +| **Ưu** | Nhất quán, dễ audit và thay đổi hàng loạt; adapter riêng giúp thay đổi API một đối tác không ảnh hưởng đối tác khác; đặt tiền lệ cho đối tác tương lai (khớp `decision-radar.md §4`) | +| **Nhược** | Cần thời gian thiết kế chuẩn chung trước khi bắt tay code từng đối tác; timeout cụ thể vẫn là đề xuất chưa kiểm chứng sandbox thật | +| **Chi phí đảo ngược** | Thấp — điều chỉnh số cụ thể (timeout, số lần retry) sau khi có sandbox thật là thay đổi cấu hình, không phải viết lại kiến trúc | + +### Bảng so sánh + +| Tiêu chí | PA-1 (Tự do từng đội) | PA-2 (Chuẩn chung + adapter) | +|---|---|---| +| Nhất quán, dễ audit | ❌ | ✅ | +| Đặt tiền lệ cho đối tác tương lai | ❌ | ✅ | +| Cô lập thay đổi API một đối tác | 🔶 Tuỳ đội | ✅ (adapter riêng) | +| Effort thiết kế trước khi code | Thấp | Trung bình | + +## 3. Quyết định + +> **Chọn PA-2 — Chính sách resilience chung (timeout theo loại đối tác, retry backoff+jitter, +> idempotency key bắt buộc) + adapter riêng cho mỗi đối tác.** + +**Vì sao:** Đây là quyết định thiết lập tiền lệ cho mọi tích hợp đối tác ngoài hiện tại và tương +lai (`decision-radar.md §4`) — không nhất quán ngay từ đầu sẽ tốn công chuẩn hoá lại sau, đúng +bẫy đã cảnh báo ở `GUIDE.md`. + +**Phạm vi áp dụng:** VNPay, Momo, GHN, GHTK, Email/SMS Provider, và mọi đối tác ngoài tương lai. + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| Có sandbox thật của cả 4 đối tác để kiểm chứng timeout cụ thể | Tech Lead | Chưa có (`CON-04`, `ARISK-03`/`04`) | +| Kiểm chứng fallback GHN↔GHTK hoạt động đúng | Tech Lead | Chưa kiểm chứng | +| Không bắt buộc POC theo `decision-radar.md §6` (không phải con số hiệu năng lớn) nhưng cần sandbox thật | — | Chờ sandbox | + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-1 — Mỗi đội tự thiết kế riêng | Không nhất quán, khó audit/thay đổi hàng loạt; vi phạm nguyên tắc "đường lỗi không thể xử lý lúc code" | `GUIDE.md` "Bẫy thường gặp" | Không xét lại — đây là anti-pattern đã có cảnh báo rõ trong bộ SA | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Nhất quán, dễ audit và thay đổi hàng loạt khi cần đổi chính sách retry/timeout +- Adapter riêng cô lập thay đổi API một đối tác, không lan sang đối tác khác + +**Hệ quả tiêu cực phải sống chung** + +- Cần thời gian thiết kế chuẩn chung trước khi từng đội bắt tay code — có thể chậm hơn PA-1 ở + giai đoạn đầu +- Timeout cụ thể (10s/8s) vẫn là đề xuất chưa kiểm chứng, có thể cần điều chỉnh khi có sandbox + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Bỏ chuẩn chung, để từng đối tác tự do sau khi đã có nhiều adapter theo chuẩn | Không tốn nhiều nếu chỉ đổi số cụ thể; tốn nhiều nếu đổi cấu trúc adapter | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Đàm phán sandbox 4 đối tác | Tech Lead + PM | Trước GĐ2 `ICD` hoàn tất | `ARISK-03`, `ARISK-04` | +| Thiết kế chi tiết từng phụ thuộc (4 câu hỏi D6) | SA (hoạt động `fail`) | GĐ2 tiếp theo | `FAIL_e-commerce` | +| Viết integration test cho fallback GHN↔GHTK | Tech Lead | GĐ2/GĐ3 | `FIT` (ứng viên) | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Mọi lời gọi ghi tới đối tác ngoài có idempotency key | Code review/lint + integration test | CI | `FIT-14` (ứng viên) | +| Retry có backoff+jitter, không retry storm khi đối tác hồi phục | Integration test giả lập đối tác chậm/hỏng | CI + staging | `FIT-15` (ứng viên) | +| Fallback GHN→GHTK kích hoạt đúng khi GHN lỗi | Integration test riêng cho luồng fallback | Staging, cần sandbox thật | — | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Sandbox thật cho thấy timeout đề xuất sai lệch nhiều | Timeout thật khác đề xuất > 50% | Tech Lead | +| Fallback GHN↔GHTK thất bại trong kiểm thử/production | Bất kỳ lần nào | Tech Lead/SRE | + +## 8. Tham chiếu + +- POC: Không bắt buộc — cần sandbox thật để kiểm chứng đầy đủ +- Bài đo: `FIT-14`, `FIT-15` (ứng viên GĐ3) +- Tài liệu ngoài: `CTX_e-commerce_v1.0.md §4.2` (trạng thái đối tác), `ARISK_e-commerce_v1.0.md §3 ARISK-03/04` +- Thảo luận: `ASR_e-commerce_v1.0.md §B2 ASR-013` + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung đủ làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`) | Chưa có chữ ký thật Tech Lead; cần chạy thử trên sandbox đối tác ngoài trước khi chốt | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: 🔴 — +> `AG2` chưa ký. diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-012_ranh-gioi-nhom-trien-khai-theo-domain.md b/sa-output/e-commerce/02-architecture/adr/ADR-012_ranh-gioi-nhom-trien-khai-theo-domain.md new file mode 100644 index 0000000..26a1cff --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-012_ranh-gioi-nhom-trien-khai-theo-domain.md @@ -0,0 +1,177 @@ +# ADR-012 — Ranh giới nhóm triển khai (deployment boundary): Nhóm Giao dịch / Nhóm Hỗ trợ / Payment tách biệt + +*Tên file: `adr/ADR-012_ranh-gioi-nhom-trien-khai-theo-domain.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | SA + Tech Lead (cấu trúc/ranh giới service — `decision-radar.md §5`) | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **~7/10** | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-014` · `CON-05` · `OQ-010` · `OQ-026` · `ASM-19` · `ASM-22` · `ASM-23` · `ADR-001` · `SAD §4.1, §7` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-012` và đổi trạng thái bản cũ thành `Superseded by`. + +--- + +## 1. Bối cảnh + +`ADR-001` đã chọn modular monolith (P2) với 2–3 nhóm triển khai ECS Fargate thay vì ~10 service +độc lập. ADR này là **quyết định cụ thể tiếp theo**: module nào nằm nhóm nào — khác `ADR-001` ở +chỗ đó là quyết định "monolith hay không", còn đây là "ranh giới cụ thể bên trong monolith". +`ASR-014` ghi nhận việc gom module vào nhóm phải phản ánh đúng năng lực đội thi công **thật**, +không chỉ theo giả định "team MVP chuẩn" (`DEC-02`). Hai câu hỏi mở trực tiếp ảnh hưởng ADR này: +`OQ-010` (số đội thi công thật) và `OQ-026` (SAD phát hiện lệch mức chi tiết giữa "2 nhóm ECS +service riêng" và cách `TCO §3.2` tính gộp compute thành 1 dòng). + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `ASR-014` | Ranh giới nhóm triển khai phải khớp năng lực đội thi công thật | +| `CON-05` | Team giả định "team MVP chuẩn" (`DEC-02`), chưa xác nhận thật | +| `OQ-010` | Tech Lead chưa xác nhận đội thi công thật | +| `OQ-026` | `TCO §3.2` tính gộp compute — chưa rõ là 1 hay 2 ECS service thật | +| `ASM-22` | Identity & Access xếp vào Nhóm Giao dịch — suy luận từ `ASR-010`/`011`, chưa Tech Lead xác nhận | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| Payment phải tách biệt hoàn toàn khỏi 2 nhóm còn lại | 🟢 Đã kiểm chứng | `ADR-002` (độc lập với ADR này) | +| Nhóm Giao dịch (Catalog & Inventory, Cart & Order) cần scale nhanh hơn Nhóm Hỗ trợ | 🟡 Ước lượng có cơ sở | `DRV-04`, `OPT §3` — chưa có số đo thật sau go-live | +| Identity & Access thuộc Nhóm Giao dịch (không phải nhóm riêng/Nhóm Hỗ trợ) | 🔴 Giả định (`ASM-22`) | Suy từ `ASR-010`/`011` ("nhóm giao dịch cốt lõi" bao gồm Identity cho HA/DR) — `OPT §3` không nói rõ | +| `TCO §3.2` phản ánh đúng 2 ECS service riêng (không phải 1 service gộp) | 🔴 Giả định (`ASM-23`) | `OQ-026` — chưa Tech Lead/Ops xác nhận | + +## 2. Phương án đã cân nhắc + +### PA-1 — 1 nhóm ECS duy nhất cho toàn bộ monolith (không tách Nhóm Giao dịch/Nhóm Hỗ trợ) + +| | | +|---|---| +| **Mô tả** | Toàn bộ 9 module (trừ Payment) chạy trong 1 ECS Fargate service duy nhất, scale chung | +| **Ưu** | Đơn giản nhất — chỉ 2 đơn vị triển khai (1 monolith + 1 Payment); ít cấu hình network/scaling riêng | +| **Nhược** | Không thể scale-out riêng Catalog/Cart&Order khi flash sale mà không kéo theo cả Nhóm Hỗ trợ — lãng phí tài nguyên hoặc thiếu tài nguyên đúng lúc cần; vi phạm `DRV-04` một phần (mục tiêu chịu tải đỉnh của riêng luồng giao dịch) | +| **Chi phí đảo ngược** | Trung bình — tách thành 2 nhóm sau này cần cấu hình lại network/scaling policy, nhưng không cần migrate dữ liệu (cùng schema-per-module) | + +### PA-2 — 2 nhóm ECS: Nhóm Giao dịch (Identity, Catalog, Cart&Order) / Nhóm Hỗ trợ (còn lại) *(chọn tạm)* + +| | | +|---|---| +| **Mô tả** | Theo `OPT §3` P2 — Nhóm Giao dịch gồm Identity & Access, Catalog & Inventory, Cart & Order; Nhóm Hỗ trợ gồm Seller Management, Commission & Payout, Promotion & Loyalty, Review, Notification, Shipping & Fulfillment; mỗi nhóm là 1 ECS Fargate service riêng, scale độc lập | +| **Ưu** | Cho phép scale riêng Nhóm Giao dịch khi flash sale mà không ảnh hưởng Nhóm Hỗ trợ (đáp ứng `DRV-04`); khớp đề xuất đã duyệt từng phần ở `OPT §3`/`DEC-06` | +| **Nhược** | Vị trí Identity & Access trong Nhóm Giao dịch là **suy luận của SA** (`ASM-22`), chưa được Tech Lead xác nhận trực tiếp; `OQ-026` cho thấy `TCO` chưa rõ có tính đúng 2 service riêng hay không — nếu `TCO` thực ra tính 1 service, phương án này phát sinh chi phí chưa được duyệt | +| **Chi phí đảo ngược** | Trung bình — đổi thành viên giữa 2 nhóm (VD chuyển Identity sang Nhóm Hỗ trợ) là thay đổi cấu hình + CI/CD, không phải viết lại code (nhờ ranh giới module đã có ở `ADR-001`) | + +### PA-3 — 3 nhóm ECS: tách riêng Identity & Access thành nhóm thứ ba (ngoài Nhóm Giao dịch/Nhóm Hỗ trợ) + +| | | +|---|---| +| **Mô tả** | Identity & Access là một ECS service riêng biệt, không thuộc Nhóm Giao dịch hay Nhóm Hỗ trợ, vì đây là dịch vụ nền tảng được cả hai nhóm gọi tới | +| **Ưu** | Tách bạch rõ ràng vai trò "hạ tầng xác thực dùng chung" khỏi logic nghiệp vụ Catalog/Cart&Order; có thể scale/HA riêng cho Identity mà không phụ thuộc tải của Catalog | +| **Nhược** | Thêm một đơn vị triển khai thứ 4 (ngoài Payment) — tăng chi phí vận hành so với PA-2; chưa có trong ước lượng `TCO §3.2` nào (chỉ có "monolith" + Payment) | +| **Chi phí đảo ngược** | Thấp — tách Identity ra là thu hẹp phạm vi 1 service, ít rủi ro hơn gộp lại | + +### Bảng so sánh + +| Tiêu chí | PA-1 (1 nhóm) | PA-2 (2 nhóm, Identity ở Nhóm Giao dịch) | PA-3 (3 nhóm, Identity riêng) | +|---|---|---|---| +| Scale riêng Nhóm Giao dịch khi flash sale (`DRV-04`) | ❌ | ✅ | ✅ | +| Khớp `OPT §3`/`DEC-06` đã duyệt từng phần | ❌ | ✅ | 🔶 Gần khớp, thêm 1 nhóm | +| Khớp `TCO §3.2` hiện tại (chưa rõ, `OQ-026`) | ✅ (nếu TCO tính 1 service) | 🔶 Chờ xác nhận | ❌ Chưa có trong TCO | +| Số đơn vị triển khai | 2 | 3 | 4 | + +## 3. Quyết định + +> **Đề xuất PA-2 — 2 nhóm ECS: Nhóm Giao dịch (Identity & Access, Catalog & Inventory, Cart & +> Order) / Nhóm Hỗ trợ (5 module còn lại), cộng Payment tách biệt.** + +🔴 **Đây là quyết định tạm, chưa đủ điều kiện `Accepted`** — theo `ASM-22`/`ASM-23` và `OQ-010`/ +`OQ-026` vẫn mở. Giữ PA-2 làm hướng đi (nhất quán với `OPT §3`/`DEC-06`/`SAD §4.1`) cho tới khi +Tech Lead/Ops xác nhận. + +**Vì sao đề xuất PA-2:** Cân bằng giữa khả năng scale riêng Nhóm Giao dịch (`DRV-04`, loại PA-1) +và không phát sinh thêm chi phí vận hành chưa có trong `TCO` (loại PA-3, chờ xác nhận thêm ngân +sách nếu cần). + +**Phạm vi áp dụng:** Toàn bộ 9 module ngoài Payment. + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| `OQ-010` — Tech Lead xác nhận số đội thật khớp (hoặc đủ để vận hành) 2–3 nhóm triển khai | Tech Lead | Mở | +| `OQ-026` — Tech Lead/Ops xác nhận `TCO §3.2` tính đúng 2 ECS service riêng (không phải 1 gộp) | Tech Lead + Ops/SRE | Mở | +| `OQ-027` — Tech Lead xác nhận vị trí Identity & Access (Nhóm Giao dịch hay riêng/Nhóm Hỗ trợ) | Tech Lead | Mở | + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-1 — 1 nhóm ECS duy nhất | Không đáp ứng nhu cầu scale riêng Nhóm Giao dịch khi flash sale | `DRV-04` | Nếu `OQ-026` xác nhận `TCO` thực ra chỉ tính 1 service (không đủ ngân sách cho 2 nhóm riêng) — quay lại PA-1 và ghi nhận giảm điểm tiêu chí "Đáp ứng DRV Must" đã chấm ở `OPT §4` | +| PA-3 — 3 nhóm, Identity riêng | Chưa có trong `TCO §3.2`, tăng chi phí vận hành chưa được PO duyệt | `TCO §3.2`, `CON-01` | Nếu Tech Lead xác nhận Identity cần HA/scale độc lập khỏi Catalog/Cart&Order (VD do tải xác thực rất khác biệt) **và** PO duyệt thêm chi phí — trình bảng đánh đổi | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Cho phép scale riêng Nhóm Giao dịch khi flash sale mà không lãng phí tài nguyên cho Nhóm Hỗ trợ +- Nhất quán với hướng đi đã duyệt từng phần ở `OPT §3`/`DEC-06` + +**Hệ quả tiêu cực phải sống chung** + +- Vị trí Identity & Access vẫn là giả định (`ASM-22`) — rủi ro phải đổi cấu hình khi Tech Lead xác + nhận khác +- Nếu `OQ-026` xác nhận `TCO` chưa tính đủ chi phí 2 service riêng, cần cập nhật `TCO` trước khi + ADR này có thể `Accepted` + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Đổi thành viên giữa Nhóm Giao dịch/Nhóm Hỗ trợ sau khi team đã quen vận hành theo ranh giới cũ | Tái tổ chức CI/CD + on-call — ước 1-3 tuần tuỳ mức độ đổi | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Tech Lead xác nhận `OQ-010` (số đội thật) | Tech Lead | Trước khi `Accepted` | `00-index/OQ_e-commerce.md` | +| Tech Lead/Ops xác nhận `OQ-026` (khớp TCO) | Tech Lead + Ops/SRE | Trước khi `Accepted`, trước hoạt động `inf` chốt | `00-index/OQ_e-commerce.md` | +| Tech Lead xác nhận `OQ-027` (vị trí Identity) | Tech Lead | Trước khi `Accepted` | `00-index/OQ_e-commerce.md` | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Đúng 2 ECS Fargate service (Nhóm Giao dịch, Nhóm Hỗ trợ) + 1 Payment tồn tại trong hạ tầng | Kiểm tra hạ tầng (Terraform plan review) | CI/CD | `FIT-16` (ứng viên) | +| Module thuộc đúng nhóm theo bảng `CMP-nn` cột "Nhóm triển khai" (`SAD §4.1`) | Review kiến trúc định kỳ | GĐ3 (`DREV`) | — | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| `OQ-010` trả lời team thật khác biệt đáng kể so với giả định | Số BE thật < 50% hoặc > gấp đôi giả định `DEC-02` | Tech Lead | +| `OQ-026` xác nhận `TCO` chỉ tính 1 service (không đủ ngân sách 2 nhóm) | Khi có xác nhận | PO/Tech Lead | +| Tải thật cho thấy Identity cần scale độc lập khỏi Catalog/Cart&Order | Dữ liệu production sau go-live | SRE | + +## 8. Tham chiếu + +- POC: Không áp dụng +- Bài đo: `FIT-16` (ứng viên GĐ3) +- Tài liệu ngoài: `OPT_e-commerce_v1.0.md §3` (P2), `SAD_e-commerce_v1.0.md §4.1, §7, §10 (ASM-22/23), §11 (OQ-026/027)` +- Thảo luận: `ASR_e-commerce_v1.0.md §B2 ASR-014` + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung đủ làm cơ sở thiết kế tiếp (`icd`/`dat`/`sec`/`inf`/`fail`) | Chờ Tech Lead + Ops/SRE xác nhận `OQ-010`/`OQ-026`/`OQ-027` | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: 🔴 — +> `AG2` chưa ký. diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md b/sa-output/e-commerce/02-architecture/adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md new file mode 100644 index 0000000..c2aff8c --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md @@ -0,0 +1,351 @@ +# ADR-013 — Bất đồng bộ hoá bước khởi tạo thanh toán trong checkout + +*Tên file: `adr/ADR-013_bat-dong-bo-hoa-khoi-tao-thanh-toan.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | Tech Lead + PO *(chưa ký thật — xem điều kiện `Accepted` ở §3/§7)* | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **7/10** *(chấm theo `decision-radar.md §2`: Chi phí đảo ngược=2 (>4 tuần — đã lộ ra FE, đổi lại phải thiết kế lại màn hình chờ/polling và state machine) · Bán kính ảnh hưởng=2 (Cart&Order, Payment Service, FE, BA/SRS US-004, ICD) · Chạm `QAS` Must=2 (trực tiếp `QAS-002`) · Ràng buộc dài hạn=1 (ràng trong phạm vi thiết kế hiện tại, xét lại được khi có sandbox thật) · Tranh cãi=0 (lần đầu đề xuất, chưa tranh luận nhiều vòng) → **5–7 ⇒ ADR bắt buộc**, dưới ngưỡng 8 nên không bắt buộc POC trước khi `Accepted`, nhưng vẫn cần bài đo xác nhận theo §6)* | +| **Supersedes** | — *(không supersede ADR nào — luồng đồng bộ trước đó là một phần `SAD §6.1` "duyệt từng phần" dưới ngoại lệ gate, chưa từng là một `ADR` riêng, nên không có ADR nguồn để supersede; `SAD §6.1` được sửa trực tiếp kèm dẫn chiếu `ADR-013`, xem `SAD_e-commerce_v1.0.md` v1.3 Change Log)* | +| **Superseded by** | — | +| **Liên quan** | `ASR-004` · `QAS-002` · `DRV-02` · `CON-04` · `ARISK-03` · `ADR-004` (idempotency/đối soát webhook) · `ADR-005` (SQS FIFO/EventBridge) · `ADR-011` (chính sách resilience đối tác ngoài) · `OQ-034` (đã chọn hướng B, `DEC-22`) | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-013` và đổi trạng thái bản cũ thành `Superseded by`. Không sửa nội dung ADR +> đã `Accepted`, không xoá ADR đã `Rejected`. + +--- + +## 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 từ trước (`DEC-12/14/16`); hoạt động 4 +(`ICD`) và 8 (`FAIL`) đã chạy (`DEC-18…22`). Điều kiện đầu vào cho việc viết `ADR-013` (kết luận +của `FAIL §1.2`, đã được điều phối dự án chọn Lựa chọn B qua `OQ-034`/`DEC-22`) đã đủ. 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-23 (SA)** — Viết `ADR-013` và sửa nhất quán tối thiểu `SAD §6.1`/`§8` + `FAIL §1.2` 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…22`. +> **Quyết định:** Hiện thực hoá Lựa chọn B đã chọn ở `OQ-034` (`DEC-22`) thành một `ADR` chính +> thức, mô tả đầy đủ luồng bất đồng bộ hoá khởi tạo thanh toán, và sửa `SAD §6.1` (sequence +> diagram checkout) + `SAD §8` (bảng ADR) + `FAIL §1.2` (ngân sách timeout cộng dồn) cho khớp với +> quyết định này. Không sửa nội dung khác của `SAD`/`FAIL` ngoài phạm vi được giao. Giữ +> `Confidence 🔴` cho tới khi: (a) AG1/AG2 ký thật, (b) Tech Lead + PO thật xác nhận `ADR-013` +> (không chỉ điều phối dự án ký thay), (c) BA cập nhật `SRS`/`AC` cho US-004 Checkout theo trạng +> thái mới, (d) `ICD` lượt sau chốt endpoint/cơ chế FE lấy `redirectUrl` (polling hay SSE — +> `OQ-041` mới). +> **Người quyết:** Điều phối dự án (đại diện PO, dự án chạy thử) — tiếp tục hoạt động dưới ngoại +> lệ; bản thân nội dung `ADR-013` vẫn cần Tech Lead + PO **thật** ký trước khi `Accepted`. +> **Radar (ước lượng cho việc tiếp tục dưới ngoại lệ, khác điểm radar 7/10 của chính `ADR-013` +> ở trên):** ~4 — chi phí đảo ngược thấp (đây là việc ghi tài liệu, không phải thi công) · bán +> kính ảnh hưởng: `SAD`/`FAIL` đã tồn tại, chỉ sửa đúng 2 mục theo yêu cầu người duyệt · chạm +> `QAS-002` Must gián tiếp (đang sửa lại cách đạt nó, không phải hạ chuẩn) · không ràng buộc dài +> hạn tự thân (khác `ADR-013` — bản thân *việc chạy dưới ngoại lệ* thì sửa được) · không tranh +> cãi mới, tiếp nối tiền lệ `DEC-11…22` → **ghi `DEC-nn`, không cần `ADR` riêng cho việc chạy dưới +> ngoại lệ**. +> **Hệ quả nếu không chấp nhận ngoại lệ:** `OQ-034` tiếp tục treo ở trạng thái "đã chọn hướng B +> nhưng chưa có ADR" — Dev không có tài liệu để thi công lại luồng checkout, `SAD §6.1` và +> `FAIL §1.2` tiếp tục mô tả một luồng đã biết là vượt ngân sách `QAS-002` (~7%) mà không có +> phương án sửa chính thức. + +--- + +## 1. Bối cảnh + +`FAIL_e-commerce_v1.0.md §1.2` (bảng ngân sách timeout cộng dồn đường găng checkout) phát hiện: +ngay cả sau khi siết timeout VNPay/Momo xuống 1.500ms (thay 10s kế thừa `CTX §4.2`), tổng thời +gian phản hồi `POST /v1/checkout` ở kịch bản worst-case cộng dồn đạt **3.220ms — vượt `QAS-002` +(≤3.000ms, mức Must) khoảng 7%**. Nguyên nhân gốc: một mình bước "Payment Service gọi VNPay/Momo" +(bước 8 trong bảng ngân sách) đã chiếm phần lớn ngân sách còn lại, trong khi ta **không kiểm soát +được SLA thật của đối tác ngoài** (`CON-04` — SLA VNPay/Momo/GHN/GHTK chưa xác nhận; `ARISK-03` — +chưa có sandbox thật để đo). Đây đúng là tình huống vi phạm `D6`: "timeout tầng ngoài phải lớn +hơn timeout tầng trong" — ở luồng đồng bộ hiện tại, timeout tầng trong (đối tác thanh toán) đang +lớn hơn timeout tầng ngoài (toàn bộ checkout). + +`DRV-02` (giỏ hàng ≥2 seller có nguy cơ tỷ lệ bỏ giỏ cao hơn ở bước checkout) là driver kinh doanh +đứng sau — nếu checkout thường xuyên chậm hoặc timeout do đối tác thanh toán, rủi ro bỏ giỏ càng +tăng đúng ở bước cuối cùng, nơi thiệt hại kinh doanh là lớn nhất (khách đã hoàn tất chọn hàng và +tách đơn theo seller). + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `QAS-002` | Latency checkout `POST /v1/checkout`: **p95 ≤ 3 giây**, mức **Must** — không đạt thì không được go-live theo định nghĩa `Must` của `sa-2-architecture/SKILL.md` | +| `ASR-004` | Webhook xác nhận thanh toán phải idempotent + có job đối soát bù — ép kiến trúc chấp nhận eventual consistency có giới hạn thời gian cho trạng thái thanh toán; `ADR-013` mở rộng đúng tinh thần này sang cả **bước khởi tạo** thanh toán, không chỉ bước xác nhận | +| `CON-04` | SLA thật của đối tác thanh toán/vận chuyển ngoài chưa được xác nhận bằng hợp đồng | +| `ARISK-03` | Chưa có sandbox thật VNPay/Momo để đo latency init thật — mọi con số timeout hiện tại là đề xuất SA | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| Tổng ngân sách worst-case cộng dồn của luồng đồng bộ hiện tại = 3.220ms > 3.000ms | 🟢 Đã kiểm chứng *(bằng tính toán cộng dồn, không phải đo thật)* | `FAIL_e-commerce_v1.0.md §1.2` bảng 10 bước | +| Tách đường găng đồng bộ (bước 1–7, 10) khỏi bước khởi tạo thanh toán (bước 8) đưa tổng thời gian phản hồi xuống ≤3.000ms bất kể VNPay/Momo chậm bao lâu | 🟢 Đã kiểm chứng bằng tính toán (1.670ms + 50ms = 1.720ms, còn dư ~1.280ms so với ngân sách) | Xem bảng §2.3 dưới | +| VNPay/Momo hoàn tất init trong ≤10s ở phần lớn trường hợp khi không còn bị ép timeout ngắn | 🔴 Giả định mới — `ASM-34` | Cần sandbox thật (`ARISK-03`) để xác minh; nếu sai, cửa sổ chờ của FE (§2.2) cần tăng hoặc coi thất bại sớm hơn | +| FE có thể triển khai polling hoặc kênh đẩy (SSE/WebSocket) để lấy `redirectUrl` sau khi có | 🔴 Giả định — chưa có xác nhận năng lực FE hiện tại | Cần Tech Lead FE xác nhận — xem `OQ-041` | + +--- + +## 2. Phương án đã cân nhắc + +### PA-A — Giữ đồng bộ, siết timeout hơn nữa + +| | | +|---|---| +| **Mô tả** | Giảm timeout gọi VNPay/Momo trong nhánh đồng bộ xuống 1.200ms (thay vì 1.500ms đã đề xuất ở `FAIL v1.0`), đưa tổng ngân sách cộng dồn còn ~2.920ms, có margin ~80ms | +| **Ưu** | Không đổi cấu trúc luồng, không đổi UX FE, không cần state machine mới, không cần BA viết lại `SRS` US-004 | +| **Nhược** | Chỉ là "ép con số" chứ không giải quyết nguyên nhân gốc — ta vẫn không kiểm soát được SLA thật của VNPay/Momo (`CON-04`/`ARISK-03` chưa có sandbox). Nếu đối tác thật cần >1.200ms để phản hồi (rất có thể, vì 10s là con số kế thừa từ hợp đồng gốc, không phải p95 thật đo được), tỷ lệ timeout/thất bại init tăng, khách phải tự bấm "Thử lại" nhiều lần — đúng lúc rủi ro bỏ giỏ hàng cao nhất (`DRV-02`). Margin 80ms cũng rất mỏng, một dao động nhỏ ở bước 1 (network client→ALB, hiện đề xuất 150ms, `ASM-31` chưa đo thật) đã có thể lại vượt ngân sách | +| **Chi phí đảo ngược** | Thấp về mặt kỹ thuật (chỉ đổi số cấu hình) — nhưng rủi ro kinh doanh (bỏ giỏ hàng) không định lượng được trước và có thể đã gây thiệt hại trước khi phát hiện | + +### PA-B — Bất đồng bộ hoá bước khởi tạo thanh toán *(chọn)* + +| | | +|---|---| +| **Mô tả** | Tách bước gọi VNPay/Momo ra khỏi đường găng đồng bộ của `POST /v1/checkout`. `Order`/`OrderSeller` được tạo và commit ở trạng thái chờ, response trả về ngay cho client trong ngân sách đồng bộ (~1.720ms, xem §2.3); việc gọi VNPay/Momo và lấy `redirectUrl` diễn ra sau, bất đồng bộ. FE lấy `redirectUrl` qua một cơ chế riêng (polling hoặc kênh đẩy — `OQ-041`). COD không đổi (không phụ thuộc bước này) | +| **Ưu** | `QAS-002` được đảm bảo về mặt cấu trúc — không còn phụ thuộc vào SLA của bên thứ ba ta không kiểm soát được, đúng tinh thần `D6`. Hệ quả phụ tích cực: TX DB không còn phải giữ mở xuyên qua lời gọi mạng tới Payment Service (giải quyết một phần mối lo bulkhead đã nêu ở `OQ-037`/`OQ-038` của `FAIL`) | +| **Nhược** | Đổi UX checkout đáng kể (khách không nhận `redirectUrl` ngay, cần chờ/poll); thêm độ phức tạp state machine cho `Order`; cần BA viết lại `SRS`/`AC` cho US-004; cần `ICD` lượt sau chốt endpoint mới; cần xử lý "Order kẹt ở trạng thái chờ" nếu bước async không bao giờ hoàn tất (tương tự khoảng trống outbox đã ghi ở `FAIL §7`) | +| **Chi phí đảo ngược** | Cao — >4 tuần nếu phải quay lại đồng bộ sau khi FE đã triển khai polling/kênh đẩy và BA đã cập nhật `SRS` theo trạng thái mới | + +### PA-C — Giữ đồng bộ, chấp nhận vượt ngân sách `QAS-002` + +| | | +|---|---| +| **Mô tả** | Không sửa gì, chấp nhận p95 lý thuyết worst-case 3.220ms, coi đây là biên an toàn hiếm khi chạm tới trong thực tế (đa số request sẽ nhanh hơn nhiều vì không phải mọi bước đều đồng thời chạm timeout tối đa) | +| **Ưu** | Không tốn công sức thiết kế lại, không đổi UX, không đổi tài liệu | +| **Nhược** | Vi phạm trực tiếp một `QAS` mức **Must** — theo định nghĩa `Must` ("không đạt thì không được go-live") và tiêu chí chặn của `AG2` ("còn interface/QAS nào không đạt mà không có phương án"), đây không phải lựa chọn SA có thẩm quyền tự chấp nhận (`D10`) — chấp nhận rủi ro vi phạm một ràng buộc chất lượng đã cam kết là quyết định của PO/Tech Lead, không phải mặc định giữ nguyên trong im lặng | +| **Chi phí đảo ngược** | Thấp về kỹ thuật, nhưng **không phải là một quyết định** — đây là không quyết định gì cả và để lại một `QAS` Must đã biết là không đạt trôi tới go-live | + +### Bảng so sánh + +| Tiêu chí *(sinh từ `QAS-002`/`CON-04`/`DRV-02`)* | PA-A | PA-B | PA-C | +|---|---|---|---| +| Đảm bảo `QAS-002` (Must) bất kể SLA đối tác | 🟡 Không chắc chắn (margin mỏng, phụ thuộc giả định 1.200ms) | 🟢 Có (về mặt cấu trúc) | 🔴 Không | +| Không phụ thuộc SLA đối tác ngoài chưa xác nhận (`CON-04`) | 🔴 Vẫn phụ thuộc | 🟢 Độc lập | 🔴 Vẫn phụ thuộc | +| Chi phí thay đổi FE/BA | 🟢 Không đổi | 🔴 Đổi đáng kể | 🟢 Không đổi | +| Rủi ro bỏ giỏ hàng do timeout init (`DRV-02`) | 🟡 Có thể tăng, không định lượng được | 🟢 Loại bỏ nguyên nhân này | 🔴 Không xử lý | +| Đúng thẩm quyền quyết định (`D10`) | ✅ SA có thể đề xuất, PO/Tech Lead chọn | ✅ SA có thể đề xuất, PO/Tech Lead chọn | ❌ Vi phạm Must trong im lặng, không phải lựa chọn hợp lệ để "không làm gì" | + +--- + +## 3. Quyết định + +> **Chọn PA-B — Bất đồng bộ hoá bước khởi tạo thanh toán online (VNPay/Momo) trong `POST +> /v1/checkout`.** + +**Vì sao:** Đây là cách duy nhất trong ba phương án đảm bảo `QAS-002` (Must) đạt được **về mặt +cấu trúc**, không phụ thuộc vào một SLA đối tác ngoài mà `CON-04`/`ARISK-03` xác nhận là chưa +kiểm chứng được. PA-A chỉ giảm nhẹ rủi ro mà không loại bỏ nguyên nhân gốc; PA-C vi phạm trực +tiếp một ràng buộc Must mà SA không có thẩm quyền tự chấp nhận thay Tech Lead/PO (`D10`). + +**Phạm vi áp dụng:** Chỉ áp dụng cho phương thức thanh toán **online qua cổng bên thứ ba** (VNPay, +Momo). **COD không đổi** — vì COD không gọi ra ngoài, xác nhận ngay trong luồng đồng bộ hiện có +(bước 7 cũ), không có nguyên nhân gây vượt ngân sách. Áp dụng cho `POST /v1/checkout` (US-004, +chưa có `SRS`/`AC` chính thức từ BA — xem §5 Việc phát sinh). + +### 3.1 Mô tả luồng mới + +**Đường găng đồng bộ (không đổi thứ tự, chỉ dừng lại sớm hơn):** + +| Bước | Thành phần | Timeout đề xuất *(kế thừa `FAIL §1.2`)* | Cộng dồn | +|---|---|---|---| +| 1 | Client → ALB | 150ms | 150ms | +| 2 | ALB → Cart & Order | 20ms | 170ms | +| 3 | Xác thực/ownership (cache hit) | 50ms | 220ms | +| 4 | Kiểm tra/giữ tồn kho (in-process) | 150ms | 370ms | +| 5 | Áp dụng coupon/điểm (`IF-021`) | 400ms | 770ms | +| 6 | Ghi `Order`/`OrderSeller`/`OrderItem` (TX) — **COMMIT ngay sau bước này**, không giữ TX mở chờ Payment nữa | 300ms | 1.070ms | +| 7 | *(chỉ áp dụng cho COD)* Payment Service xác nhận COD, đồng bộ | 600ms | 1.670ms *(nhánh COD)* | +| 10 | Response serialization + trả về client | 50ms | **1.720ms (nhánh COD)** | + +*(nhánh VNPay/Momo dừng đường găng đồng bộ ngay sau bước 6 + bước 10, không đi qua bước 7 đồng +bộ nữa — xem bảng dưới)* + +| Bước | Thành phần | Timeout | Cộng dồn (nhánh VNPay/Momo) | +|---|---|---|---| +| 1–6 | *(giống bảng trên)* | — | 1.070ms | +| 10 | Response serialization + trả về client — trả `orderId` + `status: PENDING_PAYMENT_INIT`, **chưa có `redirectUrl`** | 50ms | **1.120ms** | + +**Kết luận:** cả hai nhánh đều nằm sâu dưới `QAS-002` (≤3.000ms) — nhánh VNPay/Momo còn dư +~1.880ms margin so với ngân sách, đủ bù đắp mọi sai lệch chưa đo thật ở bước 1/3/4/5 (`ASM-27`, +`ASM-28`, `ASM-31`). + +**Bất đồng bộ (sau khi đã trả response, không tính vào `QAS-002`):** + +```mermaid +stateDiagram-v2 + [*] --> PENDING_PAYMENT_INIT: TX commit (bước 6), response 201 trả về (bước 10) + PENDING_PAYMENT_INIT --> PAYMENT_INIT_READY: Payment Service gọi VNPay/Momo thành công, có redirectUrl + PENDING_PAYMENT_INIT --> PAYMENT_INIT_FAILED: Hết retry / timeout / lỗi từ VNPay/Momo + PAYMENT_INIT_FAILED --> PENDING_PAYMENT_INIT: Khách chọn "thử lại" (retry init, cùng Idempotency-Key) + PAYMENT_INIT_FAILED --> COD: Khách chọn chuyển sang COD (nếu seller/sản phẩm hỗ trợ) + PAYMENT_INIT_READY --> [*]: Khách hoàn tất thanh toán trên trang VNPay/Momo (luồng webhook — ADR-004, không đổi) +``` + +**Cơ chế trigger bước async:** Cart & Order publish message `PaymentInitRequested` (message group += `seller_id`, dedupe theo `eventId`, cùng cơ chế SQS FIFO đã có — `ADR-005`) ngay sau khi commit +TX (bước 6), **cùng lúc** với việc publish `OrderPlaced` đã có sẵn (không phải luồng mới hoàn +toàn, tái dùng hạ tầng message backbone hiện có). Payment Service (`CMP-11`) consume message này, +gọi VNPay/Momo với timeout **10s kế thừa nguyên trạng `CTX §4.2`** (không cần ép ngắn nữa, vì +không còn nằm trên đường găng phản hồi người dùng), cập nhật trạng thái, publish +`PaymentInitReady`/`PaymentInitFailed`. + +**Idempotency của bước async:** `Idempotency-Key` gốc của `POST /v1/checkout` (`ICD §3.3`, +`ADR-004`) được truyền kèm message `PaymentInitRequested` — nếu Payment Service consume message +này nhiều lần (redelivery do visibility timeout, `ASM-29`), lời gọi VNPay/Momo không bị lặp lại +sau khi đã có `gatewayTransactionRef` (kiểm tra trạng thái hiện tại trước khi gọi lại — check- +then-act, cùng nguyên tắc đã áp dụng cho GHN/GHTK ở `FAIL FM-03/04`). + +**Timeout tổng thể của giai đoạn async (góc nhìn UX, không phải ràng buộc kiến trúc cứng):** đề +xuất coi là "quá lâu, cần hành động" nếu sau **15 giây** kể từ khi tạo `Order` mà vẫn ở +`PENDING_PAYMENT_INIT` (10s timeout đối tác + margin xử lý/hàng đợi) — khi đó FE nên chuyển sang +trạng thái cho phép khách chủ động thao tác (xem §3.2) thay vì chờ vô thời hạn. Đây là con số đề +xuất SA, gắn `OQ-042` (thời gian giữ `Order` ở `PENDING_PAYMENT_INIT` trước khi coi là "kẹt" và +cần job dọn dẹp/hủy tự động). + +### 3.2 Cơ chế FE lấy `redirectUrl` — đề xuất, chưa chốt + +Hai lựa chọn kỹ thuật cho FE nhận biết khi `PAYMENT_INIT_READY` sẵn sàng: + +| Cơ chế | Mô tả | Đánh đổi | +|---|---|---| +| **Polling** *(đề xuất mặc định)* | FE gọi lặp lại một endpoint trạng thái (đề xuất `GET /v1/orders/{orderId}/payment-init-status`, chưa chốt tên — `ICD` lượt sau) mỗi ~1 giây, tối đa ~15 giây | Đơn giản, không cần hạ tầng mới (WebSocket/SSE), hoạt động tốt qua mọi proxy/CDN hiện có; tốn thêm request lặp lại (tải nhỏ, ngắn hạn, không đáng kể so với `QAS-009`) | +| **SSE / WebSocket** | Server đẩy sự kiện khi trạng thái đổi | Trải nghiệm mượt hơn (không có độ trễ polling interval), nhưng cần thêm thành phần hạ tầng (kết nối lâu dài, cân bằng tải phù hợp), tăng độ phức tạp vận hành mà đội chưa xác nhận có kinh nghiệm (`OQ-010` vẫn mở) | + +🔴 **Đây là đề xuất, không phải quyết định cuối** — `ADR-013` chỉ chốt việc **bất đồng bộ hoá**, +không chốt cơ chế truyền tải cụ thể. Ghi `OQ-041` (mới), chờ Tech Lead (kèm ý kiến FE) xác nhận; +hệ quả phương án ngược: chọn polling mà tải cao bất thường có thể tăng số request nhỏ không cần +thiết (giảm thiểu bằng interval hợp lý + dừng poll sau 15s hoặc khi có kết quả); chọn SSE/WebSocket +mà đội chưa có kinh nghiệm vận hành production kênh kết nối lâu dài có thể phát sinh sự cố khó +chẩn đoán đúng lúc ra mắt. + +### 3.3 Hành vi khi khởi tạo thất bại (`PAYMENT_INIT_FAILED`) + +Khi hết retry / timeout ở bước async (VNPay/Momo không phản hồi được trong 10s, hoặc trả lỗi): +`Order` chuyển `PAYMENT_INIT_FAILED`. FE (qua polling/kênh đẩy) nhận trạng thái này và cho khách +hai lựa chọn, **không tự động rollback/huỷ `Order`**: + +1. **Thử lại cùng phương thức** — gọi lại endpoint khởi tạo (đề xuất tái dùng cùng + `Idempotency-Key`, `ICD` lượt sau chốt contract cụ thể) → quay lại `PENDING_PAYMENT_INIT`. +2. **Chuyển sang COD** (nếu seller/sản phẩm trong đơn hỗ trợ COD) hoặc **chọn phương thức online + khác** (VNPay ⇄ Momo) — tái sử dụng cùng `Order`/`OrderSeller` đã tạo, chỉ đổi phương thức + thanh toán, không tạo `Order` mới (tránh trùng đơn, giữ đúng ownership tồn kho đã reserve ở + bước 4). + +🔴 Chi tiết endpoint/contract cho hai thao tác trên **chưa chốt** — thuộc hoạt động `icd` lượt +sau (xem §5 Việc phát sinh). + +--- + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-A (siết timeout xuống 1.200ms, giữ đồng bộ) | Không loại bỏ nguyên nhân gốc (phụ thuộc SLA đối tác chưa xác nhận, `CON-04`); margin còn lại (~80ms) quá mỏng so với các con số chưa đo thật khác trong cùng ngân sách (`ASM-27/28/31`) | `CON-04`, `ARISK-03` | Nếu có sandbox thật và VNPay/Momo xác nhận SLA hợp đồng ≤1.000ms p99, có thể xét lại PA-A như một tối ưu bổ sung (không nhất thiết thay thế PA-B, có thể kết hợp: PA-B đã chọn + timeout đối tác chặt hơn nếu SLA cho phép) | +| PA-C (giữ đồng bộ, chấp nhận vượt `QAS-002`) | Vi phạm trực tiếp một `QAS` mức Must mà SA không có thẩm quyền tự chấp nhận thay Tech Lead/PO (`D10`); không phải "không làm gì" là an toàn — đây là để một rủi ro đã biết trôi tới go-live trong im lặng | `QAS-002` (Must) | Chỉ xét lại nếu PO/Tech Lead **chính thức** hạ mức `QAS-002` từ Must xuống Should/Could kèm lý do nghiệp vụ — đây là quyết định PO, không phải kỹ thuật | + +*"Giữ đồng bộ vì đơn giản hơn cho FE" là lý do có thật (chi phí thi công thấp hơn) — nhưng không +đủ để thắng một ràng buộc Must đã lượng hoá; ghi nhận ở đây để không ai đề xuất lại PA-C mà không +đọc lý do đã bị loại.* + +--- + +## 5. Hệ quả + +**Hệ quả tích cực** + +- `QAS-002` (Must) được đảm bảo về mặt cấu trúc cho mọi request VNPay/Momo — không còn phụ thuộc + SLA đối tác ngoài mà ta không kiểm soát (`CON-04`/`ARISK-03`), đúng nguyên tắc `D6`. +- Loại bỏ hoàn toàn tình huống giữ transaction DB mở xuyên qua một lời gọi mạng ra ngoài container + (TX nay commit ngay sau bước 6) — giảm trực tiếp rủi ro cạn connection pool đã nêu ở `FAIL + OQ-037`/`OQ-038`, dù không đóng hẳn hai `OQ` đó (bulkhead vẫn cần cho các phụ thuộc khác). +- Payment Service có thể dùng lại nguyên trạng timeout 10s kế thừa `CTX §4.2` cho VNPay/Momo mà + không cần "ép" xuống 1.500ms như đề xuất tạm ở `FAIL v1.0` — giảm rủi ro timeout giả (false + timeout) khi đối tác chỉ chậm tạm thời. + +**Hệ quả tiêu cực phải sống chung** + +- UX checkout đổi đáng kể: khách không nhận `redirectUrl` ngay trong response đầu tiên, cần chờ + một khoảng thời gian ngắn (kỳ vọng thường vài trăm ms tới vài giây, tối đa đề xuất 15s trước khi + coi là bất thường) — cần màn hình chờ/trạng thái mới ở FE, chưa thiết kế ở lượt này. +- Thêm độ phức tạp: state machine 4 trạng thái mới cho `Order` (`PENDING_PAYMENT_INIT` → + `PAYMENT_INIT_READY` / `PAYMENT_INIT_FAILED` → …), thêm 1 loại message + (`PaymentInitRequested`) cần DLQ/retry riêng (tương tự các message khác đã có ở `ADR-005`). +- Khoảng trống chưa xử lý: nếu message `PaymentInitRequested` bị mất hoặc Payment Service không + bao giờ xử lý (sự cố), `Order` kẹt vĩnh viễn ở `PENDING_PAYMENT_INIT` — cần job quét dọn (cùng + bản chất với khoảng trống outbox đã ghi ở `FAIL §7`, chưa thiết kế chi tiết, thuộc hoạt động + `dat`/`inf` sắp tới). Ghi `OQ-042`. + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Quay lại luồng đồng bộ hoàn toàn (bỏ polling/kênh đẩy) | Thiết kế lại FE (bỏ màn hình chờ), viết `ADR` mới `Supersedes: ADR-013`, cập nhật lại `SRS` US-004 lần nữa, và **chỉ khả thi nếu** có sandbox thật chứng minh SLA đối tác đủ nhanh (`ARISK-03` đã đóng) | +| Đổi cơ chế polling ↔ SSE/WebSocket (sau khi đã chọn một trong hai ở `OQ-041`) | Đổi tầng truyền tải FE↔BE, không đổi state machine `Order` — chi phí trung bình, không cần `ADR` mới (thuộc `ICD`, không phải quyết định kiến trúc cấu trúc) | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Cập nhật `SAD §6.1` (sequence diagram checkout) + `§8` (bảng ADR) theo `ADR-013` | SA | Đã làm cùng lượt (`SAD` v1.3) | `SAD_e-commerce_v1.0.md` | +| Cập nhật `FAIL §1.2` (ngân sách timeout cộng dồn, tách đường găng đồng bộ khỏi bước async) | SA | Đã làm cùng lượt (`FAIL` v1.1) | `FAIL_e-commerce_v1.0.md` | +| Chốt endpoint/contract: trạng thái polling, retry init, chuyển COD | SA (hoạt động `icd` lượt sau) | Trước khi Dev thi công US-004 | `ICD_e-commerce_v1.0.md` (bổ sung `IF` mới) | +| Viết/cập nhật `SRS`/`AC` cho US-004 Checkout với trạng thái `PENDING_PAYMENT_INIT`/`PAYMENT_INIT_READY`/`PAYMENT_INIT_FAILED` | BA | Trước khi Dev thi công | `ba-output/e-commerce/03-specification/SRS_US004_*.md` (chưa tồn tại) | +| Thiết kế job quét `Order` kẹt ở `PENDING_PAYMENT_INIT` quá hạn (`OQ-042`) | SA (hoạt động `dat`/`inf` lượt sau) | Trước AG2 | `DAT_e-commerce_v1.0.md` (chưa tồn tại) | +| Thêm fitness function đo p95 checkout thật ≤3s bất kể VNPay/Momo chậm | SA/QA (GĐ3) | GĐ3 | `FIT-23` (mới, xem §6) | + +--- + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Đo p95 `POST /v1/checkout` (nhánh VNPay/Momo) ≤3.000ms **ngay cả khi** giả lập VNPay/Momo phản hồi chậm (chaos, ép độ trễ 9–10s ở bước async) — xác nhận response không bị ảnh hưởng | k6 + chaos injection (giả lập độ trễ đối tác) | Staging | `FIT-23` *(mới, cộng thêm vào danh sách `FIT-16…22` đã đề xuất ở `FAIL §8`)* | +| Xác nhận không có `Order` nào giữ TX DB mở quá bước 6 (kiểm tra thời lượng transaction qua log/APM) | Kiểm tra APM/log transaction duration | Staging + production sau go-live | `FIT-24` *(mới)* | +| Xác nhận message `PaymentInitRequested` idempotent — gửi trùng không gọi lại VNPay/Momo khi đã có `gatewayTransactionRef` | Test tích hợp: publish trùng message, xác nhận chỉ 1 lời gọi gateway | Staging | `FIT-25` *(mới)* | + +Cả ba `FIT-23/24/25` là **ứng viên**, chưa viết thật (thuộc GĐ3 `sa-3-enablement`, cùng nhóm với +`FIT-16…22` đã đề xuất ở `FAIL §8`) — không giả vờ đã kiểm chứng. + +--- + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Tỷ lệ `Order` rơi vào `PAYMENT_INIT_FAILED` sau go-live | > 5% tổng số checkout VNPay/Momo trong 1 tuần (đề xuất, chưa xác nhận — cần baseline thật sau go-live) | Tech Lead + PO | +| Thời gian trung bình từ `PENDING_PAYMENT_INIT` → `PAYMENT_INIT_READY` | > 5 giây p95 (gần chạm ngưỡng "kẹt" 15s ở §3.1) | SRE | +| Sandbox VNPay/Momo thật cho thấy SLA p99 ổn định ≤ 1.000ms | Có báo cáo SLA chính thức từ đối tác | Tech Lead (đóng `ARISK-03`) | +| Phản hồi người dùng về UX chờ/poll (khảo sát/CSKH) cho thấy trải nghiệm xấu đáng kể | Ngưỡng định tính, cần PO đánh giá | PO | + +**Điều kiện chuyển `Accepted`:** Tech Lead + PO **thật** (không phải ký thay dưới ngoại lệ +`DEC-01`) xác nhận nội dung §3 (mô tả luồng), đồng thời BA xác nhận đã cập nhật `SRS`/`AC` cho +US-004 theo trạng thái mới. Radar 7/10 (dưới ngưỡng 8) nên không bắt buộc POC trước `Accepted`, +nhưng khuyến nghị mạnh chạy `FIT-23` (chaos đo p95) ít nhất một lần ở staging trước khi go-live, +vì đây là ràng buộc chất lượng mức Must. + +--- + +## 8. Tham chiếu + +- POC: *(không bắt buộc — radar 7/10, dưới ngưỡng 8)* +- Bài đo: `FIT-23/24/25` (ứng viên, chưa chạy — xem §6) +- Tài liệu ngoài: `CTX_e-commerce_v1.0.md §4.2` (timeout đối tác kế thừa 10s) +- Thảo luận: `FAIL_e-commerce_v1.0.md §1.2` (phát hiện xung đột ngân sách), `OQ-034`/`DEC-22` + (quyết định chọn Lựa chọn B, 2026-09-15, điều phối dự án thay mặt Tech Lead/PO) + +--- + +## 9. Review log (không đổi Status) + +| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển `Accepted` | +|---|---|---|---|---| +| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ `DEC-01`) | `Reviewed (Proposed giữ nguyên)` — nội dung §3 (state machine `PENDING_PAYMENT_INIT`/`PAYMENT_INIT_READY`/`PAYMENT_INIT_FAILED`, timeout async 10s, idempotency, hành vi thất bại) đủ làm cơ sở thiết kế tiếp (`ICD`/`DAT`/FE) | Chưa có chữ ký thật Tech Lead + PO (`§7` điều kiện `Accepted`); BA chưa viết `SRS`/`AC` cho US-004 (`OQ-034`) | + +> Đây là ghi nhận **review nội dung**, không phải "sign" theo nghĩa gate: `Status` giữ nguyên +> `Proposed`. Xem `00-index/ADL_e-commerce.md` (Change Log — Review 2026-09-15) và `ADL §8` +> "Việc phải làm" (mục #9) cho điều kiện chuyển `Accepted`. Confidence tổng thể của lượt review: +> 🔴 — `AG2` chưa ký. diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-014_transactional-outbox-publish-su-kien.md b/sa-output/e-commerce/02-architecture/adr/ADR-014_transactional-outbox-publish-su-kien.md new file mode 100644 index 0000000..1b96f34 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-014_transactional-outbox-publish-su-kien.md @@ -0,0 +1,207 @@ +# ADR-014 — Transactional Outbox cho publish sự kiện Cart & Order / Payment + +*Tên file: `adr/ADR-014_transactional-outbox-publish-su-kien.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | SA + Tech Lead (cấu trúc/tích hợp — `decision-radar.md §5`) — chưa ký thật | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **6/10** *(chấm theo `decision-radar.md §2`, kế thừa nguyên ước lượng đã ghi ở `DAT_e-commerce_v1.0.md §4.1`: Chi phí đảo ngược=1 (1–3 tuần — `outbox_event` là bảng nội bộ, không phải dữ liệu nghiệp vụ, chưa tới mức "phải migrate dữ liệu") · Bán kính ảnh hưởng=1 (Cart&Order + Payment, 2 `CMP` publish, cộng tiền lệ cho các module tương lai) · Chạm `QAS` Must=1 (gián tiếp `QAS-005`/`DRV-08` — không mất giao dịch, không phải chính nó là con số `QAS`) · Ràng buộc dài hạn=2 (trở thành chuẩn chung cho mọi module publish sự kiện, ≥1 năm) · Tranh cãi=0, cộng +1 vì đây là quyết định **thiết lập tiền lệ** áp dụng toàn hệ thống (`decision-radar.md §4`) → **5–7 ⇒ `ADR` bắt buộc**, dưới ngưỡng 8 nên không bắt buộc POC trước khi `Accepted`, nhưng cần bài đo/`FIT` xác nhận trước khi chuyển `Accepted` theo §6)* | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-004` · `ASR-005` · `QAS-005` · `DRV-08` · `ADR-004` · `ADR-005` · `ADR-013` · `DAT_e-commerce_v1.0.md §1.3, §1.4, §4.1` · `FAIL_e-commerce_v1.0.md §7` · `OQ-044` · `DEC-25` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-014` và đổi trạng thái bản cũ thành `Superseded by`. Không sửa nội dung ADR +> đã `Accepted`, không xoá ADR đã `Rejected`. + +--- + +## 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 từ trước; hoạt động 4–8 (`ICD`/`DAT`/ +`SEC`/`INF`/`FAIL`) đã chạy và duyệt từng phần (`DEC-18…30`). `ADR-001…013` đã viết (`Proposed`). +`DAT_e-commerce_v1.0.md §4.1` (duyệt từng phần, `DEC-25`) đã chọn **TẠM** hướng Transactional +Outbox cho khoảng trống dual-write phát hiện ở `FAIL §7`, và yêu cầu SA viết `ADR-014` chính thức +ở lượt hoạt động `adr` này. 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-31 (SA)** — Viết `ADR-014`/`ADR-015`/`ADR-016`/`ADR-017` (`Proposed`) 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…30`. Hiện thực hoá 4 hướng đã chọn +> TẠM qua `OQ-044`/`DEC-25` (outbox), `OQ-050`/`DEC-28` (service JWT), và 2 ứng viên mới của `INF` +> (`DEC-30`: blue-green, Terraform). Tất cả 4 `ADR` giữ `Status Proposed` — không `Accepted`. Chỉ +> link 4 `ADR` này vào `DAT §4.1`, `SEC §2.4`/§4 (TB3/TB4), `INF §7.2`/§11 (thay "ứng viên"/"chưa +> viết" bằng đường dẫn thật), không đổi nội dung chuyên môn khác của ba tài liệu đó — mỗi file +> chạm tới bump `+0.1` kèm Change Log "chỉ link ADR, không đổi nội dung". Cập nhật `ADL`/`DTM`. +> **Người quyết:** Điều phối dự án (đại diện PO, dự án chạy thử). +> **Radar (ước lượng cho việc tiếp tục dưới ngoại lệ, khác điểm radar riêng của từng ADR):** ~4 — +> chi phí đảo ngược thấp (ghi 4 ADR + link tài liệu, chưa có dòng code phụ thuộc) · bán kính ảnh +> hưởng: AG2 phụ thuộc nhưng bản thân *việc ghi dưới ngoại lệ* thì nhỏ · chạm gián tiếp `QAS-005`/ +> `QAS-007`/`QAS-002`/`QAS-010` Must (đang hiện thực hoá các cơ chế đạt chúng) nhưng chưa cam kết +> thi công (không `ADR` nào `Accepted`) · không ràng buộc dài hạn tự thân (nội dung từng `ADR` đã +> được chấm radar riêng, 5–7, không cái nào ≥8) · không tranh cãi mới, tiếp nối tiền lệ `DEC-17/23` +> → **ghi `DEC-nn`, không cần thêm `ADR` cho chính việc chạy dưới ngoại lệ**. +> **Hệ quả nếu không chấp nhận ngoại lệ:** `OQ-044`/`OQ-050` tiếp tục treo ở trạng thái "đã chọn +> hướng nhưng chưa có `ADR`" — Dev không có tài liệu chính thức để thi công outbox/service-authn; +> `INF §7.2`/§11 tiếp tục ghi "đề xuất ADR mới, chưa viết", để lộ khoảng trống ở tiêu chí AG2 +> "`ADR` tồn tại cho mọi quyết định đạt ngưỡng radar". + +--- + +## 1. Bối cảnh + +`FAIL_e-commerce_v1.0.md §7` phát hiện một khoảng trống: nếu service chết **sau** `COMMIT` +transaction tạo `Order` nhưng **trước** khi publish `OrderPlaced`/`PaymentInitRequested` thành +công, sự kiện bị mất vĩnh viễn — không consumer nào (Commission, Promotion, Notification, +Shipping, Payment) biết `Order` đó tồn tại. Đây là bài toán **dual write** kinh điển (ghi DB + gọi +message queue không nguyên tử). `DAT_e-commerce_v1.0.md §4.1` đã phân tích khoảng trống này và đề +xuất Transactional Outbox, được duyệt **TẠM** qua `DEC-25` với yêu cầu SA viết `ADR` chính thức. + +`ADR-005` đã chốt message backbone (SQS FIFO + EventBridge); `ADR-013` bổ sung một sự kiện mới +(`PaymentInitRequested`) publish **cùng lúc** với `OrderPlaced` ngay sau khi commit — càng làm +tăng tầm quan trọng của việc publish nguyên tử, vì nay có ≥2 sự kiện phải cùng "sống hay chết" +với transaction ghi `Order`. + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `ASR-004` | Webhook + xác nhận thanh toán phải idempotent + có cơ chế bù — mở rộng tinh thần sang cả bước publish sự kiện tạo đơn | +| `ASR-005` | Message backbone SQS FIFO + EventBridge đã chọn (`ADR-005`) — outbox là cơ chế publish nguyên tử **lên trên** backbone đó, không thay thế nó | +| `QAS-005` | Fan-out lag ≤5 giây từ `OrderPlaced` tới consumer — outbox relay (đề xuất 1–2 giây) phải nằm trong ngân sách này | +| `DRV-08` | Xác nhận thanh toán/giao dịch không được mất — outbox là biện pháp trực tiếp chống mất sự kiện `OrderPlaced`/`PaymentInitRequested` | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| Dual-write (ghi DB + gọi queue không cùng transaction) có thể mất sự kiện nếu service chết giữa hai bước | 🟢 Đã kiểm chứng — đây là vấn đề đã biết rộng rãi trong kiến trúc phân tán, không cần đo riêng cho dự án này | `FAIL §7` | +| Relay poller in-process (đọc `outbox_event` mỗi 1–2 giây) đủ nhanh để không ăn hết ngân sách `QAS-005` (≤5 giây) | 🔴 Giả định (`ASM-38`, `DAT §4.1`) | Chưa đo — cần bài đo GĐ3 | +| Consumer đã có dedupe theo `eventId` (chống publish trùng khi relay publish thành công nhưng đánh dấu `published` thất bại — at-least-once) | 🟢 Đã kiểm chứng — đã thiết kế ở `ICD §4` | `ICD_e-commerce_v1.0.md §4` | + +## 2. Phương án đã cân nhắc + +### PA-1 — Job quét đối chiếu định kỳ + +| | | +|---|---| +| **Mô tả** | Job định kỳ (đề xuất mỗi 5 phút) quét `order` không có sự kiện tương ứng đã publish thành công (dựa cột đánh dấu `event_published_at`), publish lại | +| **Ưu** | Không cần bảng/hạ tầng mới, chỉ thêm 1 cột đánh dấu | +| **Nhược** | Không giải quyết nguyên nhân gốc — luồng publish "bình thường" (ngay sau commit) vẫn là dual-write không nguyên tử, job chỉ là lưới vá muộn; có race condition giữa "đang xử lý" và "đã mất" nếu không thiết kế cẩn thận cột đánh dấu; độ trễ phát hiện tối đa bằng chu kỳ job (5 phút) — vượt xa ngân sách `QAS-005` (≤5 giây) cho trường hợp cần vá; không tổng quát — mỗi module publish event sau này phải tự cài lại logic quét riêng | +| **Chi phí đảo ngược** | Trung bình — đổi sang cơ chế khác sau khi nhiều module đã cài job quét riêng tốn công dọn dẹp từng nơi | + +### PA-2 — Transactional Outbox *(chọn)* + +| | | +|---|---| +| **Mô tả** | Ghi một dòng `outbox_event` **trong cùng transaction DB** với việc tạo `Order`/`OrderSeller`/`OrderItem` (cùng schema `cart_order`, cùng ACID). Một relay (poller in-process, đề xuất chu kỳ 1–2 giây, `ASM-38`) đọc `outbox_event` trạng thái `pending`, publish lên SQS/EventBridge, đánh dấu `published` khi thành công. Payment Service dùng bảng `outbox_event` riêng trong RDS Payment của nó (2 DB khác nhau, không chia sẻ bảng) | +| **Ưu** | Đảm bảo tính nguyên tử thật sự giữa ghi DB và phát sự kiện (industry-standard); dùng được cho **mọi** module publish event sau này, không chỉ Cart & Order; độ trễ phát hiện/publish thấp (1–2 giây), nằm gọn trong ngân sách `QAS-005` (≤5 giây) | +| **Nhược** | Thêm bảng `outbox_event` mỗi module publish + một relay process cần giám sát riêng (lag alerting); độ trễ publish tăng nhẹ (1–2 giây thay vì tức thời) | +| **Chi phí đảo ngược** | Trung bình (1–3 tuần) — sau khi Cart&Order + Payment đã tích hợp, đổi sang cơ chế khác cần sửa lại relay + rà lại mọi module đã dùng, nhưng `outbox_event` là bảng nội bộ kỹ thuật, không phải dữ liệu nghiệp vụ, nên chưa tới mức "phải migrate dữ liệu" | + +### PA-3 — 2PC (Distributed transaction giữa DB và message broker) + +| | | +|---|---| +| **Mô tả** | Dùng giao thức 2-phase commit (XA transaction) trải rộng cả việc ghi DB lẫn publish message, đảm bảo cả hai cùng commit hoặc cùng rollback | +| **Ưu** | Về lý thuyết là đảm bảo nhất quán mạnh nhất giữa hai hệ thống | +| **Nhược** | **Không khả thi kỹ thuật** — SQS FIFO và EventBridge (đã chốt ở `ADR-005`) là dịch vụ managed của AWS, **không hỗ trợ tham gia giao thức XA/2PC**; ngay cả nếu đổi sang một message broker hỗ trợ 2PC, cơ chế này làm giảm throughput đáng kể (transaction coordinator là điểm nghẽn tập trung) và đội chưa có kinh nghiệm vận hành (`CON-05`) | +| **Chi phí đảo ngược** | Không áp dụng — loại ngay từ đầu vì không khả thi kỹ thuật với hạ tầng đã chọn | + +### Bảng so sánh + +| Tiêu chí | PA-1 | PA-2 | PA-3 | +|---|---|---|---| +| Đảm bảo nguyên tử ghi DB + publish | ❌ Không (chỉ vá muộn) | ✅ Có | ✅ Về lý thuyết | +| Khả thi với SQS FIFO/EventBridge (`ADR-005`) | ✅ | ✅ | ❌ Không hỗ trợ XA | +| Độ trễ phát hiện/publish khi lỗi | Tối đa chu kỳ job (5 phút) — vượt `QAS-005` | 1–2 giây (`ASM-38`) — trong ngân sách `QAS-005` | N/A (không khả thi) | +| Tổng quát cho mọi module tương lai | 🔶 Phải cài riêng từng nơi | ✅ Một chuẩn chung | N/A | + +## 3. Quyết định + +> **Chọn PA-2 — Transactional Outbox (bảng `outbox_event` + relay poller in-process chu kỳ +> 1–2 giây).** + +**Vì sao:** Đây là phương án duy nhất vừa giải quyết đúng nguyên nhân gốc (dual-write không +nguyên tử) vừa khả thi với message backbone đã chọn (`ADR-005`), và tổng quát hoá được cho mọi +module publish sự kiện trong tương lai — đúng tinh thần `DRV-08` (không mất giao dịch). + +**Phạm vi áp dụng:** Toàn hệ thống — mọi module publish sự kiện qua SQS FIFO/EventBridge (bắt đầu +với Cart & Order publish `OrderPlaced`/`PaymentInitRequested`, và Payment Service publish +`PaymentConfirmed`/`PaymentInitReady`/`PaymentInitFailed` qua bảng `outbox_event` riêng trong RDS +Payment của nó). Module nào publish sự kiện mới sau này (Commission, Shipping, …) dùng cùng mẫu. + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| Tech Lead xác nhận thiết kế relay (poller in-process, chu kỳ 1–2 giây, số instance/HA của relay) | Tech Lead | Mở (`OQ-044` chưa đóng) | +| Bài đo xác nhận relay lag thật không ăn quá nhiều vào ngân sách `QAS-005` (≤5 giây) | Tech Lead + QA | Chưa chạy — GĐ3 | +| `FIT` §6 dưới đây chạy PASS ít nhất 1 lần ở staging | Tech Lead/SRE | Chưa chạy | + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-1 — Job quét đối chiếu định kỳ | Không giải quyết nguyên nhân gốc (vẫn dual-write ở luồng bình thường), độ trễ phát hiện tối đa 5 phút vượt xa ngân sách `QAS-005` (≤5 giây), không tổng quát cho module tương lai | `QAS-005`, `DRV-08` | Chỉ xét lại như biện pháp bổ sung (không thay thế outbox) nếu cần một lớp giám sát "vá muộn" cho các dòng `outbox_event` bị kẹt bất thường — bản thân outbox relay đã đóng vai trò chính | +| PA-3 — 2PC (XA transaction) | Không khả thi kỹ thuật — SQS FIFO/EventBridge không hỗ trợ XA/2PC (`ADR-005`); ngay cả đổi broker, giảm throughput đáng kể và đội chưa có kinh nghiệm (`CON-05`) | `ADR-005`, `CON-05` | Chỉ xét lại nếu đổi hẳn message backbone sang một hệ có hỗ trợ 2PC **và** có bằng chứng throughput đáp ứng — chưa có tiền lệ ở dự án này | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Đảm bảo tính nguyên tử thật sự giữa ghi `Order` và phát sự kiện — đóng khoảng trống `FAIL §7` +- Một chuẩn chung dùng được cho mọi module publish sự kiện sau này (Commission, Shipping, + Notification, …), không phải thiết kế lại từ đầu mỗi lần +- Cho phép `ADR-013` publish đồng thời `OrderPlaced` + `PaymentInitRequested` một cách an toàn + +**Hệ quả tiêu cực phải sống chung** + +- Thêm bảng `outbox_event` ở mỗi module publish (Cart & Order, Payment Service — đã thiết kế ở + `DAT §1.3`/§1.4) — tăng độ phức tạp schema +- Relay process là một thành phần mới cần giám sát riêng (lag alerting theo tuổi dòng `pending`, + chưa thiết kế ngưỡng cụ thể — thuộc `inf`) +- Độ trễ publish tăng nhẹ (1–2 giây thay vì tức thời) — cần xác nhận không ăn quá nhiều vào ngân + sách `QAS-005` (≤5 giây) khi cộng cả thời gian consumer xử lý + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Đổi khỏi Outbox sang cơ chế khác (VD CDC — Change Data Capture) sau khi mọi module đã tích hợp | Cần thay relay + rà lại từng module đã dùng — nhiều tuần, dù không phải migrate dữ liệu nghiệp vụ | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Thiết kế chi tiết relay (số instance, HA, cơ chế lock tránh 2 relay cùng publish 1 dòng) | Tech Lead + SA (hoạt động `inf` lượt sau) | Trước khi Dev thi công | `INF_e-commerce_v1.0.md` (bổ sung) | +| Thêm alerting lag `outbox_event` (tuổi dòng `pending` vượt ngưỡng) | SA (hoạt động `inf`)/Ops | Trước AG2 | `INF_e-commerce_v1.0.md` | +| Viết `FIT-26`/`FIT-27` thật | QA/Dev (GĐ3) | GĐ3 | `03-enablement/FIT_e-commerce.md` | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Không có publish nào đi thẳng SQS/EventBridge mà bỏ qua ghi `outbox_event` trong cùng transaction ("không publish ngoài outbox") | Static analysis (lint rule cấm gọi trực tiếp SDK publish ngoài lớp outbox) + integration test kiểm tra mọi `Order` tạo ra đều có dòng `outbox_event` tương ứng trong cùng transaction | CI + staging | `FIT-26` *(ứng viên GĐ3)* | +| Chaos: kill relay process giữa lúc có tải, xác nhận `outbox_event` tồn đọng không mất; khi relay phục hồi (restart), toàn bộ dòng `pending` được publish, không mất và không publish thiếu | Chaos test — dừng relay, tạo N `Order`, khởi động lại relay, đếm số sự kiện consumer nhận được so với N | Staging | `FIT-27` *(ứng viên GĐ3)* | + +Cả `FIT-26`/`FIT-27` là **ứng viên**, chưa viết thật (thuộc GĐ3 `sa-3-enablement`). + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Relay lag thật (từ lúc `outbox_event` ghi tới lúc publish) thường xuyên vượt ngưỡng, ăn quá nhiều vào ngân sách `QAS-005` | p95 lag > 3 giây (margin còn lại quá mỏng so với ngân sách 5 giây) | Tech Lead + SRE | +| Số dòng `outbox_event` tồn đọng (`pending`) tăng liên tục, không giảm | Tồn đọng > vài phút liên tục theo dõi qua CloudWatch (ngưỡng cụ thể chưa chốt — thuộc `inf`) | Ops/SRE | + +## 8. Tham chiếu + +- POC: Không bắt buộc (radar 6/10, dưới ngưỡng 8) — nhưng khuyến nghị bài đo relay lag trước khi + `Accepted` +- Bài đo: `FIT-26`/`FIT-27` (ứng viên GĐ3) +- Tài liệu ngoài: — +- Thảo luận: `DAT_e-commerce_v1.0.md §4.1` (phát hiện + đề xuất), `FAIL_e-commerce_v1.0.md §7` + (khoảng trống gốc), `OQ-044`/`DEC-25` (chọn hướng TẠM) diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-015_service-jwt-xac-thuc-service-to-service.md b/sa-output/e-commerce/02-architecture/adr/ADR-015_service-jwt-xac-thuc-service-to-service.md new file mode 100644 index 0000000..94343d8 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-015_service-jwt-xac-thuc-service-to-service.md @@ -0,0 +1,185 @@ +# ADR-015 — Xác thực service-to-service bằng Service JWT ngắn hạn + +*Tên file: `adr/ADR-015_service-jwt-xac-thuc-service-to-service.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | Security (chưa có người — `OQ-007`) + Tech Lead (bảo mật — `decision-radar.md §5`; Security có quyền phủ quyết cuối cùng) — chưa ký thật | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **5/10** *(chấm theo `decision-radar.md §2`, kế thừa nguyên ước lượng đã ghi ở `SEC_e-commerce_v1.0.md §2.4`: Chi phí đảo ngược=1 (1–3 tuần — đổi cơ chế sau khi đã code tốn sửa cả hai đầu gọi) · Bán kính ảnh hưởng=2 (mọi lời gọi cross-network nội bộ TB3/TB4 + tiền lệ cho các `IF` tương lai) · Chạm `QAS` Must=1 (gián tiếp `QAS-002`/`QAS-010` — thêm bước xin token có thể ăn vào ngân sách latency đã eo hẹp, cần đo lại) · Ràng buộc dài hạn=1 (chuẩn nội bộ cho service-to-service, trong một release) · Tranh cãi=0 → **5 ⇒ `ADR` bắt buộc** (5–7), dưới ngưỡng 8 nên không bắt buộc POC, nhưng cần đo lại latency overhead trước khi `Accepted`)* | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `ASR-002` · `ASR-007` · `QAS-002` · `QAS-010` · `THR-09` · `THR-13` · `SEC_e-commerce_v1.0.md §1 (TB3/TB4)`, `§2.4` · `SAD_e-commerce_v1.0.md §7` (ràng buộc không thêm hạ tầng mới) · `ADR-002` · `ADR-007` · `ADR-012` · `OQ-050` · `DEC-28` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-015` và đổi trạng thái bản cũ thành `Superseded by`. Không sửa nội dung ADR +> đã `Accepted`, không xoá ADR đã `Rejected`. + +--- + +## 0. Ghi chú Preflight & ngoại lệ gate + +Viết cùng lượt với `ADR-014`/`ADR-016`/`ADR-017` dưới ngoại lệ gate ghi ở `DEC-31` (tiếp nối +`DEC-01…30`) — xem `ADR-014 §0` cho bối cảnh đầy đủ. Riêng `ADR-015`: hiện thực hoá hướng **PA-3** +đã chọn TẠM ở `SEC_e-commerce_v1.0.md §2.4` (duyệt từng phần, `DEC-28`). + +🔴 **Lưu ý quan trọng nhất của ADR này:** đây là quyết định **bảo mật** — theo `decision-radar.md +§5`, loại quyết định này do **Security chốt**, không phải Tech Lead hay SA. Security **hiện chưa +có người được chỉ định** (`OQ-007`, mở từ GĐ1). ADR này **không thể chuyển `Accepted`** cho tới +khi có đại diện Security thật ký — bất kể Tech Lead có đồng ý nội dung hay không, đúng nguyên tắc +"Security có quyền phủ quyết AG2" (`sa-2-architecture/SKILL.md`, hoạt động 6). 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** dưới ngoại lệ. + +--- + +## 1. Bối cảnh + +`SEC_e-commerce_v1.0.md §1`/`§2.4` phát hiện một khoảng trống: hai ranh giới cross-network nội bộ +— TB3 (Nhóm Giao dịch ↔ Nhóm Hỗ trợ, `IF-021`/`IF-022`) và TB4 (Cart & Order → Payment, `IF-006`, +**ranh giới nhạy cảm nhất vì Payment giữ tiền thật**, `ASR-002`) — hiện **chỉ dựa vào network +reachability** (security group VPC), không có cơ chế xác thực danh tính bên gọi. `THR-09` và +`THR-13` (Spoofing, mức 🔴) ghi rõ: một service khác trong cùng VPC (kể cả bị compromise) có thể +giả danh gọi thẳng các endpoint này nếu security group cấu hình sai. + +`SAD_e-commerce_v1.0.md §7` (v1.2) đã đặt một ràng buộc rõ ràng: **không tự thêm hạ tầng mới** +(VD internal ALB/App Mesh) vào sơ đồ ở lượt thiết kế này — mọi hạ tầng mới là một quyết định kiến +trúc riêng, ngoài phạm vi. Điều này loại trực tiếp phương án service mesh/mTLS đầy đủ trừ khi có +một `ADR` riêng chấp nhận thêm hạ tầng. + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `ASR-002` | Payment Service cô lập PCI-DSS SAQ A — TB4 là ranh giới nhạy cảm nhất | +| `ASR-007` | Chỗ ra quyết định ownership/authz — mở rộng tinh thần sang cả xác thực giữa các service nội bộ | +| `SAD §7` (v1.2) | Không tự thêm hạ tầng mới ngoài phạm vi thiết kế hiện tại | +| `CON-05` | Đội vận hành chưa xác nhận có kinh nghiệm vận hành hạ tầng phân tán phức tạp (service mesh) | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| Hạ tầng ký/verify JWT của Identity & Access (`CMP-02`) đã tồn tại cho xác thực người dùng cuối | 🟢 Đã kiểm chứng | `SEC §2` | +| Thêm 1 bước xin/verify service token không ăn quá nhiều vào ngân sách latency `QAS-002`/`QAS-010` | 🔴 Giả định mới — cần đo lại | Chưa đo — GĐ3 | +| AWS Cloud Map + ECS Service Connect (đã chốt ở `INF §3`, mức `DEC`, không `ADR`) tương thích với việc đính kèm header service JWT ở tầng ứng dụng | 🟢 Đã kiểm chứng (đây là 2 lớp độc lập — network discovery vs application-layer auth) | `INF §3` | + +## 2. Phương án đã cân nhắc + +### PA-1 — Chỉ dựa network (security group) + +| | | +|---|---| +| **Mô tả** | Giữ nguyên hiện trạng — không thêm cơ chế xác thực nào giữa các service nội bộ | +| **Ưu** | Không tốn công triển khai | +| **Nhược** | Không đáp ứng "defense in depth" cho dữ liệu PII/tiền đi qua TB3/TB4; một security group cấu hình sai = không còn ranh giới nào; không giảm thiểu `THR-09`/`THR-13` | +| **Chi phí đảo ngược** | Thấp về kỹ thuật, nhưng để lại `THR-09`/`THR-13` ở mức 🔴 không giảm thiểu — rủi ro bảo mật tồn đọng | + +### PA-2 — mTLS qua service mesh (AWS App Mesh/Private CA) + +| | | +|---|---| +| **Mô tả** | Mỗi ECS task có chứng chỉ riêng, xác thực lẫn nhau ở tầng TLS | +| **Ưu** | Mạnh nhất, chuẩn ngành cho zero-trust nội bộ | +| **Nhược** | Thêm hạ tầng mới (App Mesh) — **mâu thuẫn trực tiếp** với ràng buộc đã ghi ở `SAD §7` v1.2 ("không tự thêm hạ tầng mới ngoài phạm vi"); đội chưa xác nhận có kinh nghiệm vận hành mesh (`CON-05`) | +| **Chi phí đảo ngược** | Cao — triển khai rồi tháo dỡ mesh tốn nhiều tuần, ảnh hưởng mọi service | + +### PA-3 — Service JWT ngắn hạn ký bởi Identity & Access *(chọn)* + +| | | +|---|---| +| **Mô tả** | Mỗi service tự xin "service token" (JWT riêng, `sub=service-name`, TTL ngắn ~5 phút, đề xuất) từ Identity & Access qua IAM role (không cần secret tĩnh), đính kèm header khi gọi `IF-006`/`IF-021`/`IF-022`; bên nhận verify chữ ký giống verify JWT người dùng (tái dùng hạ tầng ký/verify đã có) | +| **Ưu** | Không cần hạ tầng mới ngoài quy ước header + logic verify (tái dùng key JWT của `CMP-02`); tương thích với ràng buộc "không thêm hạ tầng mới" của `SAD §7`; nâng được một lớp phòng thủ so với hiện trạng thuần network | +| **Nhược** | Cần Identity & Access cấp phát token cho service (thêm luồng nội bộ mới, nhỏ); vẫn phụ thuộc network layer làm lớp phòng thủ đầu (không phải mTLS zero-trust đầy đủ); thêm 1 round-trip xin token có thể ăn vào ngân sách latency (cần đo lại) | +| **Chi phí đảo ngược** | Trung bình (1–3 tuần) — đổi cơ chế sau khi đã code cả hai đầu gọi (bên gửi xin token, bên nhận verify) tốn sửa cả hai phía | + +### Bảng so sánh + +| Tiêu chí | PA-1 | PA-2 | PA-3 | +|---|---|---|---| +| Giảm thiểu `THR-09`/`THR-13` (Spoofing) | ❌ Không | ✅ Mạnh nhất | ✅ Có (một lớp phòng thủ bổ sung) | +| Tương thích ràng buộc `SAD §7` (không thêm hạ tầng mới) | ✅ | ❌ Vi phạm trực tiếp | ✅ | +| Tương thích năng lực đội hiện tại (`CON-05`) | ✅ | 🔴 Chưa xác nhận có kinh nghiệm | ✅ Tái dùng hạ tầng JWT sẵn có | +| Chi phí đảo ngược | Thấp (nhưng để lại rủi ro) | Cao | Trung bình | + +## 3. Quyết định + +> **Chọn PA-3 — Service JWT ngắn hạn ký bởi Identity & Access, giữ nguyên security group làm lớp +> phòng thủ đầu.** + +**Vì sao:** Đây là phương án duy nhất vừa nâng được một lớp phòng thủ thật sự (giảm thiểu +`THR-09`/`THR-13`) vừa **không vi phạm** ràng buộc đã ghi ở `SAD §7` v1.2 ("không tự thêm hạ tầng +mới ngoài phạm vi") và không đòi hỏi năng lực vận hành mesh mà đội chưa xác nhận có (`CON-05`). + +**Phạm vi áp dụng:** Mọi lời gọi cross-network nội bộ giữa các nhóm triển khai — hiện tại là TB3 +(`IF-021`/`IF-022`) và TB4 (`IF-006`); áp dụng cho mọi `IF` cross-network tương lai theo cùng +chuẩn (thiết lập tiền lệ). + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| **Có đại diện Security thật ký** — đây là quyết định bảo mật, Security có quyền phủ quyết | Security | 🔴 **Chặn cứng — chưa có người** (`OQ-007`, mở từ GĐ1) | +| Tech Lead xác nhận hướng PA-3 (không đổi sang PA-2 mTLS) | Tech Lead | Mở (`OQ-050` chưa đóng) | +| Đo lại latency overhead của bước xin/verify token, xác nhận không ăn quá nhiều vào ngân sách `QAS-002`/`QAS-010` | Tech Lead + QA | Chưa chạy — GĐ3 | + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-1 — Chỉ dựa network | Không giảm thiểu `THR-09`/`THR-13` (Spoofing mức 🔴) — để lại rủi ro bảo mật đã biết mà không có biện pháp bổ sung | `ASR-002`, `THR-13` | Không xét lại — đây là hiện trạng đã bị đánh giá không đủ | +| PA-2 — mTLS/App Mesh | Vi phạm trực tiếp ràng buộc `SAD §7` v1.2 ("không tự thêm hạ tầng mới ngoài phạm vi"); đội chưa xác nhận có kinh nghiệm vận hành mesh (`CON-05`) | `SAD §7`, `CON-05` | Xét lại nếu tổ chức cần zero-trust đầy đủ hơn (VD mở rộng nhiều team/service hơn đáng kể) **và** có `ADR` riêng chấp nhận thêm hạ tầng mesh, **và** đội xác nhận đủ năng lực vận hành | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Nâng một lớp phòng thủ thật sự cho TB3/TB4 (giảm thiểu `THR-09`/`THR-13`), thay vì chỉ dựa + network reachability +- Không cần hạ tầng mới — tái dùng hạ tầng ký/verify JWT sẵn có của Identity & Access +- Thiết lập một chuẩn chung cho mọi `IF` cross-network tương lai + +**Hệ quả tiêu cực phải sống chung** + +- Identity & Access cần thêm luồng cấp phát service token (endpoint/logic mới, dù nhỏ) +- Thêm 1 round-trip mạng (xin token) có thể ăn vào ngân sách latency vốn đã eo hẹp + (`QAS-002`/`QAS-010`) — cần đo lại trước khi `Accepted` +- Vẫn phụ thuộc network layer làm lớp phòng thủ đầu — không phải zero-trust đầy đủ như mTLS + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Đổi sang mTLS/App Mesh sau này | Cần viết `ADR` mới chấp nhận thêm hạ tầng, triển khai mesh, đào tạo đội vận hành — nhiều tuần | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Identity & Access thiết kế endpoint/logic cấp service token | Dev (Identity & Access) | Trước khi Dev thi công TB3/TB4 | Thiết kế chi tiết thuộc GĐ3 | +| Đo lại latency overhead trên đường găng checkout | SA/QA (GĐ3) | Trước go-live | `FAIL`/`FIT` GĐ3 | +| Viết `FIT-31` thật (service-authn test) | QA/Dev (GĐ3) | GĐ3 | `03-enablement/FIT_e-commerce.md` | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Gọi `IF-006`/`IF-021`/`IF-022` không có service JWT hợp lệ (thiếu, hết hạn, hoặc sai chữ ký) bị từ chối | Integration test | CI + staging | `FIT-31` *(ứng viên, đã đề xuất ở `SEC §11`)* | +| Đo p95 latency đường găng checkout với bước xin/verify token, xác nhận vẫn ≤ ngân sách `QAS-002` | Load test (k6) | Staging | Ứng viên bổ sung — cùng nhóm `FIT-23/24/25` của `ADR-013` | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Latency overhead đo được ăn quá nhiều vào margin `QAS-002` (margin còn lại theo `ADR-013` ~1.280–1.880ms) | Overhead > 100ms p95 (đề xuất, chưa xác nhận) | Tech Lead | +| Tổ chức mở rộng nhiều team/service hơn đáng kể, cần zero-trust đầy đủ | Số service cross-network > gấp đôi hiện tại (2 ranh giới TB3/TB4) | Tech Lead + Security | + +## 8. Tham chiếu + +- POC: Không bắt buộc (radar 5/10, dưới ngưỡng 8) — nhưng khuyến nghị đo lại latency trước khi + `Accepted` +- Bài đo: `FIT-31` (ứng viên GĐ3) +- Tài liệu ngoài: — +- Thảo luận: `SEC_e-commerce_v1.0.md §2.4` (phát hiện + đề xuất), `THR-09`/`THR-13`, + `OQ-050`/`DEC-28` (chọn hướng TẠM) diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-016_blue-green-deploy-aws-codedeploy.md b/sa-output/e-commerce/02-architecture/adr/ADR-016_blue-green-deploy-aws-codedeploy.md new file mode 100644 index 0000000..436f897 --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-016_blue-green-deploy-aws-codedeploy.md @@ -0,0 +1,168 @@ +# ADR-016 — Chiến lược triển khai Blue-Green qua AWS CodeDeploy cho 3 dịch vụ ECS + +*Tên file: `adr/ADR-016_blue-green-deploy-aws-codedeploy.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | SA + Ops/SRE (hạ tầng/HA/DR/chi phí vận hành — `decision-radar.md §5`; PO phủ quyết nếu vượt ngân sách) — chưa ký thật | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **6/10** *(chấm theo `decision-radar.md §2`, kế thừa nguyên ước lượng đã ghi ở `INF_e-commerce_v1.0.md §7.2`: Chi phí đảo ngược=1 (đổi chiến lược deploy sau khi đã cấu hình CodeDeploy cho 3 service tốn vài tuần, không phải migrate dữ liệu) · Bán kính ảnh hưởng=2 (toàn bộ 3 đơn vị triển khai — Nhóm Giao dịch, Nhóm Hỗ trợ, Payment) · Chạm `QAS` Must=2 (trực tiếp `QAS-007`, ngân sách lỗi 43 phút/tháng) · Ràng buộc dài hạn=1 (ràng buộc trong phạm vi chiến lược release hiện tại, đổi được qua `ADR` mới) · Tranh cãi=0 → **6 ⇒ `ADR` bắt buộc**, dưới ngưỡng 8, không bắt buộc POC)* | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `QAS-007` · `ASR-011` · `OQ-020` · `OQ-056` · `ADR-010` · `ADR-012` · `INF_e-commerce_v1.0.md §6.4, §7` · `DEC-30` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-016` và đổi trạng thái bản cũ thành `Superseded by`. Không sửa nội dung ADR +> đã `Accepted`, không xoá ADR đã `Rejected`. + +--- + +## 0. Ghi chú Preflight & ngoại lệ gate + +Viết cùng lượt với `ADR-014`/`ADR-015`/`ADR-017` dưới ngoại lệ gate ghi ở `DEC-31` (tiếp nối +`DEC-01…30`) — xem `ADR-014 §0` cho bối cảnh đầy đủ. Riêng `ADR-016`: hiện thực hoá đề xuất đã ghi +ở `INF_e-commerce_v1.0.md §7.2` (duyệt từng phần, `DEC-30`). + +--- + +## 1. Bối cảnh + +`QAS-007` (error budget) đặt ngân sách lỗi **43 phút/tháng** cho Catalog/Checkout/Payment/Identity +(99,9%/tháng), loại trừ bảo trì có báo trước ≤2 giờ/tháng (`OQ-020`, TẠM — chưa PO xác nhận số +cuối). `INF §6.4` ghi rõ ràng buộc: chiến lược deploy **không được tự tiêu tốn ngân sách lỗi này** +— chọn sai chiến lược release (VD rolling update có cửa sổ mất traffic ngắn mỗi lần) tích luỹ +qua nhiều lần release/tháng có thể ăn hết 43 phút mà không liên quan gì tới sự cố thật. + +`ADR-012` đã chốt 3 đơn vị triển khai độc lập: Nhóm Giao dịch, Nhóm Hỗ trợ, Payment (ECS Fargate). +Mỗi service cần một chiến lược release nhất quán, không phải mỗi module một kiểu. + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `QAS-007` | Ngân sách lỗi 43 phút/tháng, loại trừ bảo trì ≤2h/tháng (`OQ-020`, TẠM) | +| `ASR-011` | Observability & alerting — cần phát hiện lỗi sau deploy nhanh để rollback kịp thời | +| `CON-08` | Năng lực đội vận hành chưa xác nhận đầy đủ — chọn chiến lược không quá phức tạp để đội vận hành được | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| AWS CodeDeploy hỗ trợ blue-green cho ECS như một tính năng managed sẵn có | 🟢 Đã kiểm chứng — theo tài liệu AWS công khai | `INF §7.2` | +| Đội chưa từng vận hành CodeDeploy blue-green trong production | 🔴 Giả định — chưa xác nhận | `CON-05`/`CON-08`, `OQ-008` | +| Rollback bằng chuyển traffic ALB (green→blue) là tức thời (giây), không cần redeploy | 🟢 Đã kiểm chứng — tính năng CodeDeploy | `INF §7.2` | + +## 2. Phương án đã cân nhắc + +### PA-1 — Rolling update + +| | | +|---|---| +| **Mô tả** | Thay thế dần từng task cũ bằng task mới, giữ một phần traffic route tới task đang tắt trong thời gian ngắn | +| **Ưu** | Đơn giản, là chế độ mặc định của ECS, không cần cấu hình CodeDeploy thêm | +| **Nhược** | Có cửa sổ ngắn (vài giây) mỗi lần deploy mà request có thể chạm task đang tắt (draining) — tích luỹ nhiều lần release/tháng có nguy cơ ăn vào ngân sách lỗi 43 phút/tháng (`QAS-007`); rollback chậm hơn (phải redeploy version cũ, không phải chuyển traffic tức thời) | +| **Chi phí đảo ngược** | Thấp — đổi sang blue-green sau vẫn khả thi, không tốn nhiều | + +### PA-2 — Blue-green qua AWS CodeDeploy *(chọn)* + +| | | +|---|---| +| **Mô tả** | Deploy phiên bản mới sang một target group "green" song song với "blue" đang chạy; sau khi health check pass, chuyển toàn bộ traffic ALB sang "green" dứt điểm; giữ "blue" một thời gian để rollback tức thời nếu phát hiện lỗi | +| **Ưu** | Tương thích ngân sách lỗi chặt (`QAS-007`) — 0 downtime theo thiết kế nếu health check đúng; rollback tức thời (chuyển traffic lại, không cần redeploy) | +| **Nhược** | Cần double capacity tạm thời trong cửa sổ chuyển đổi (cả blue lẫn green cùng chạy) — tăng chi phí nhỏ trong thời gian ngắn; đội cần học vận hành CodeDeploy (chưa có kinh nghiệm, `CON-05`/`CON-08`) | +| **Chi phí đảo ngược** | Trung bình — đổi sang canary sau này là bổ sung, không phải viết lại từ đầu | + +### PA-3 — Canary (progressive traffic shifting) + +| | | +|---|---| +| **Mô tả** | Chuyển traffic dần theo tỷ lệ % (VD 10% → 50% → 100%) sang phiên bản mới, theo dõi metrics ở mỗi bước | +| **Ưu** | Phát hiện lỗi sớm hơn với blast radius nhỏ hơn (chỉ % nhỏ traffic chạm phiên bản lỗi) | +| **Nhược** | Thêm độ phức tạp giám sát (theo dõi metrics theo từng bước %, quyết định tự động/thủ công tiếp tục hay rollback ở mỗi bước) mà đội chưa có kinh nghiệm (`CON-05`); lợi ích thêm (phát hiện sớm hơn blue-green) chưa cần thiết ở quy mô tải hiện tại (kịch bản A/B của `TCO`) | +| **Chi phí đảo ngược** | Trung bình-cao — cấu hình canary phức tạp hơn, tháo dỡ cũng tốn công hơn | + +### Bảng so sánh + +| Tiêu chí | PA-1 | PA-2 | PA-3 | +|---|---|---|---| +| Downtime mỗi lần deploy | Cửa sổ ngắn (vài giây) | 0 theo thiết kế | 0 theo thiết kế | +| Tương thích `QAS-007` (ngân sách lỗi chặt) | 🔴 Rủi ro tích luỹ | ✅ | ✅ | +| Tốc độ rollback | Chậm (redeploy) | Tức thời (chuyển traffic) | Tức thời từng bước | +| Độ phức tạp vận hành so với năng lực đội hiện tại (`CON-05`) | Thấp | Trung bình | Cao | + +## 3. Quyết định + +> **Chọn PA-2 — Blue-green qua AWS CodeDeploy cho cả 3 dịch vụ ECS (Nhóm Giao dịch, Nhóm Hỗ trợ, +> Payment).** + +**Vì sao:** Đây là phương án cân bằng tốt nhất giữa việc bảo vệ ngân sách lỗi chặt (`QAS-007`) và +độ phức tạp vận hành phù hợp với năng lực đội hiện tại (`CON-05`) — mạnh hơn rolling (không có +cửa sổ mất traffic), đơn giản hơn canary (không cần giám sát theo từng bước %). + +**Phạm vi áp dụng:** Cả 3 dịch vụ ECS triển khai (Nhóm Giao dịch, Nhóm Hỗ trợ, Payment) — thống +nhất một chiến lược, không mỗi module một kiểu. + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| Ops/SRE xác nhận năng lực vận hành CodeDeploy (đào tạo nếu cần) | Ops/SRE | Mở (`OQ-008` đội Ops thật chưa xác nhận) | +| Chạy thử blue-green + rollback thành công ít nhất 1 lần ở staging | Ops/SRE | Chưa chạy | +| PO xác nhận số cuối cửa sổ bảo trì loại trừ ngân sách lỗi (`OQ-020`) | PO | Mở | + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-1 — Rolling update | Cửa sổ mất traffic ngắn mỗi lần deploy tích luỹ có nguy cơ ăn vào ngân sách lỗi chặt `QAS-007` (43 phút/tháng); rollback chậm hơn | `QAS-007` | Không xét lại trừ khi `QAS-007` được PO hạ mức (nới ngân sách lỗi) — quyết định nghiệp vụ, không phải kỹ thuật | +| PA-3 — Canary | Thêm độ phức tạp giám sát/vận hành mà đội chưa có kinh nghiệm (`CON-05`); lợi ích thêm (blast radius nhỏ hơn) chưa cần thiết ở quy mô tải hiện tại | `CON-05` | Xét lại khi tải tăng đáng kể (vượt kịch bản B ×2 theo `SAD §10`) hoặc đội xác nhận đủ năng lực vận hành canary | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Bảo vệ ngân sách lỗi `QAS-007` — 0 downtime theo thiết kế nếu health check đúng +- Rollback tức thời (giây) khi phát hiện lỗi sau khi đã chuyển traffic + +**Hệ quả tiêu cực phải sống chung** + +- Cần double capacity tạm thời trong cửa sổ chuyển đổi (cả blue lẫn green) — tăng chi phí nhỏ, + ngắn hạn, cần xác nhận không đáng kể so với `TCO` +- Đội cần đào tạo vận hành CodeDeploy nếu chưa có kinh nghiệm (`TCO §5`) + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Đổi sang canary sau này | Bổ sung cấu hình giám sát theo bước %, không phải viết lại toàn bộ pipeline — chi phí trung bình | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Cấu hình CodeDeploy thật cho cả 3 service | Ops/SRE (GĐ3) | Trước go-live | `03-enablement/AGD_e-commerce.md` (chưa tồn tại) | +| Viết runbook rollback chi tiết | Ops/SRE (GĐ3) | Trước go-live | `03-enablement/AGD_e-commerce.md` | +| Chạy thử blue-green + rollback ở staging | Ops/SRE | Trước AG2 | `INF §11 FIT-37` | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Blue-green deploy tự động rollback khi health check fail sau khi chuyển traffic | CodeDeploy hook test | Staging, trước mỗi major release | `FIT-37` *(đã đề xuất ở `INF §11`)* | +| Đo downtime thực tế trong 1 lần deploy blue-green, xác nhận = 0 (hoặc dưới ngưỡng nhỏ chấp nhận được) | Load test liên tục trong lúc deploy | Staging | Ứng viên bổ sung, cùng nhóm `FIT-37` | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Tần suất release tăng đáng kể, cần giảm blast radius hơn nữa | Release > vài lần/tuần với rủi ro cao (đề xuất, chưa xác nhận) | Tech Lead | +| Chi phí double-capacity trong cửa sổ deploy vượt ngân sách đáng kể | Vượt >5% chi phí compute hàng tháng (đề xuất, chưa xác nhận) | Ops/PO | + +## 8. Tham chiếu + +- POC: Không bắt buộc (radar 6/10, dưới ngưỡng 8) +- Bài đo: `FIT-37` (ứng viên GĐ3, đã đề xuất ở `INF §11`) +- Tài liệu ngoài: — +- Thảo luận: `INF_e-commerce_v1.0.md §6.4, §7.2` (phát hiện + đề xuất), `DEC-30` (duyệt từng phần) diff --git a/sa-output/e-commerce/02-architecture/adr/ADR-017_iac-terraform.md b/sa-output/e-commerce/02-architecture/adr/ADR-017_iac-terraform.md new file mode 100644 index 0000000..dbe178b --- /dev/null +++ b/sa-output/e-commerce/02-architecture/adr/ADR-017_iac-terraform.md @@ -0,0 +1,167 @@ +# ADR-017 — Công cụ Infrastructure as Code — Terraform + +*Tên file: `adr/ADR-017_iac-terraform.md`* + +| | | +|---|---| +| **Status** | `Proposed` | +| **Date** | 2026-09-15 | +| **Người quyết** | Tech Lead + Ops/SRE (hạ tầng — `decision-radar.md §5`) — chưa ký thật | +| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | +| **Điểm radar** | **7/10** *(chấm theo `decision-radar.md §2`, kế thừa nguyên ước lượng đã ghi ở `INF_e-commerce_v1.0.md §11`: Chi phí đảo ngược=2 (>4 tuần — đổi công cụ sau khi đã có code Terraform thật cho toàn bộ hạ tầng tốn nhiều tuần viết lại + rủi ro thao tác chuyển đổi state) · Bán kính ảnh hưởng=2 (toàn bộ tài nguyên AWS của dự án) · Chạm `QAS` Must=1 (gián tiếp — nền tảng hiện thực hoá mọi `QAS` hạ tầng, không phải chính nó là một `QAS`) · Ràng buộc dài hạn=2 (chuẩn IaC nội bộ ≥1 năm) · Tranh cãi=0 → **7 ⇒ `ADR` bắt buộc**, dưới ngưỡng 8, không bắt buộc POC)* | +| **Supersedes** | — | +| **Superseded by** | — | +| **Liên quan** | `CON-05` · `INF_e-commerce_v1.0.md §11` · `OQ-060` · `DEC-30` | + +> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có +> `Supersedes: ADR-017` và đổi trạng thái bản cũ thành `Superseded by`. Không sửa nội dung ADR +> đã `Accepted`, không xoá ADR đã `Rejected`. + +--- + +## 0. Ghi chú Preflight & ngoại lệ gate + +Viết cùng lượt với `ADR-014`/`ADR-015`/`ADR-016` dưới ngoại lệ gate ghi ở `DEC-31` (tiếp nối +`DEC-01…30`) — xem `ADR-014 §0` cho bối cảnh đầy đủ. Riêng `ADR-017`: hiện thực hoá đề xuất đã ghi +ở `INF_e-commerce_v1.0.md §11` (duyệt từng phần, `DEC-30`). + +--- + +## 1. Bối cảnh + +Trước khi `sa-3-enablement` (GĐ3) viết code hạ tầng thật, cần chốt công cụ Infrastructure as Code +(IaC) chính cho toàn dự án — tránh tình trạng mỗi thành phần hạ tầng dùng một công cụ khác nhau, +không ai review/audit được nhất quán. `INF_e-commerce_v1.0.md §11` đã đề xuất Terraform và đánh +dấu đây là quyết định thiết lập tiền lệ (radar ước lượng ~7, đạt ngưỡng `ADR` bắt buộc), yêu cầu +SA viết `ADR` chính thức ở hoạt động `adr`. + +**Ràng buộc đang chi phối:** + +| Nguồn | Nội dung | +|---|---| +| `CON-05` | Năng lực đội (kỹ năng lập trình cho hạ tầng — TypeScript/Python cho CDK, hay chỉ cần HCL của Terraform) chưa xác nhận rõ | +| `D9` (`design-rules.md`) | Mọi con số hạ tầng phải quy ra tiền, có nguồn, và cấu hình phải tái lập được — công cụ IaC là nền tảng để đạt điều này | + +**Cái đã biết chắc / cái còn là giả định:** + +| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | +|---|---|---| +| Terraform có cộng đồng module lớn cho ECS/RDS/ElastiCache (AWS) | 🟢 Đã kiểm chứng — thực tế công khai của hệ sinh thái Terraform | `INF §11` | +| Đội có đủ kỹ năng TypeScript/Python để dùng AWS CDK hiệu quả | 🔴 Giả định chưa xác nhận | `CON-05`, `OQ-060` | +| Đội có đủ kỹ năng HCL (ngôn ngữ cấu hình của Terraform) hoặc học được nhanh hơn một ngôn ngữ lập trình đầy đủ | 🔴 Giả định — Terraform HCL thường được coi là dễ tiếp cận hơn với đội chưa quen lập trình hạ tầng, nhưng chưa xác nhận với đội thật | `OQ-060` | + +## 2. Phương án đã cân nhắc + +### PA-1 — Terraform *(chọn)* + +| | | +|---|---| +| **Mô tả** | HashiCorp Terraform, dùng HCL để định nghĩa hạ tầng, quản lý state qua backend (đề xuất S3 + DynamoDB lock) | +| **Ưu** | Đa cloud-agnostic hơn CDK (dù hiện chỉ dùng AWS — giữ tuỳ chọn mở cho tương lai); cộng đồng module lớn cho ECS/RDS/ElastiCache; không khoá vào một ngôn ngữ lập trình cụ thể (HCL là ngôn ngữ khai báo riêng, không cần biết TypeScript/Python) | +| **Nhược** | HCL là một ngôn ngữ riêng cần học, dù thường được coi là dễ tiếp cận hơn ngôn ngữ lập trình đầy đủ; cần thiết lập backend state (S3 + DynamoDB lock) — thêm một phần hạ tầng nhỏ | +| **Chi phí đảo ngược** | Cao (>4 tuần) nếu đổi công cụ sau khi đã có code Terraform thật cho toàn bộ hạ tầng — viết lại + rủi ro thao tác trong lúc chuyển đổi state | + +### PA-2 — AWS CDK + +| | | +|---|---| +| **Mô tả** | Định nghĩa hạ tầng bằng ngôn ngữ lập trình đầy đủ (TypeScript/Python), compile ra CloudFormation | +| **Ưu** | Tích hợp sâu với AWS, cho phép dùng logic lập trình (vòng lặp, hàm) trực tiếp khi định nghĩa hạ tầng | +| **Nhược** | Cần kỹ năng TypeScript/Python cho hạ tầng — `CON-05` chưa xác nhận đội có; khoá vào AWS (dù hiện tại dự án chỉ dùng AWS, việc khoá vào một hãng làm giảm tuỳ chọn multi-cloud tương lai nếu cần) | +| **Chi phí đảo ngược** | Cao — tương tự PA-1, đổi sau khi đã có code thật tốn nhiều tuần | + +### PA-3 — AWS CloudFormation (native) + +| | | +|---|---| +| **Mô tả** | Dùng trực tiếp CloudFormation (JSON/YAML), không qua công cụ trung gian | +| **Ưu** | Không cần công cụ bên thứ ba, tích hợp gốc với AWS Console/CLI | +| **Nhược** | Cú pháp JSON/YAML kém module hoá hơn Terraform/CDK; cộng đồng module tái sử dụng nhỏ hơn; quản lý state kém linh hoạt hơn (CloudFormation tự quản lý state, không có backend tách rời như Terraform S3+DynamoDB, khó tách theo môi trường/nhóm tài nguyên để giảm blast radius) | +| **Chi phí đảo ngược** | Trung bình-cao — viết lại theo cấu trúc module hoá tốt hơn sau này | + +### Bảng so sánh + +| Tiêu chí | PA-1 (Terraform) | PA-2 (CDK) | PA-3 (CloudFormation) | +|---|---|---|---| +| Phù hợp năng lực đội hiện tại (`CON-05`, chưa xác nhận kỹ năng lập trình) | 🟡 Cần học HCL (thường dễ hơn) | 🔴 Cần TypeScript/Python | 🟡 Cần học JSON/YAML CloudFormation | +| Đa cloud-agnostic (giữ tuỳ chọn tương lai) | ✅ | ❌ Khoá vào AWS | ❌ Khoá vào AWS | +| Cộng đồng module tái sử dụng (ECS/RDS/ElastiCache) | ✅ Lớn | 🟡 Trung bình | 🔴 Nhỏ hơn | +| Tách state theo môi trường/nhóm tài nguyên (giảm blast radius) | ✅ Linh hoạt (backend riêng) | 🟡 Qua CDK stack | 🔴 Kém linh hoạt hơn | + +## 3. Quyết định + +> **Chọn PA-1 — Terraform làm công cụ Infrastructure as Code chính cho toàn dự án.** + +**Vì sao:** Cân bằng tốt nhất giữa năng lực đội chưa xác nhận rõ (`CON-05`, không đòi hỏi kỹ năng +lập trình đầy đủ như CDK), hệ sinh thái module tái sử dụng lớn cho đúng các dịch vụ AWS đã chọn +(ECS/RDS/ElastiCache), và khả năng tách state để giảm blast radius (yêu cầu (h) của `INF §11`). + +**Phạm vi áp dụng:** Toàn bộ hạ tầng AWS của dự án — network, data, compute — trong mọi môi trường +(dev/stg/prod). + +### Điều kiện chuyển `Proposed → Accepted` + +| Điều kiện | Ai xác nhận | Trạng thái hiện tại | +|---|---|---| +| Tech Lead xác nhận công cụ IaC (Terraform) cho P2 | Tech Lead | Mở (`OQ-060` chưa đóng) | +| Ops/SRE xác nhận năng lực vận hành Terraform (đào tạo nếu cần) | Ops/SRE | Mở | +| Thiết lập backend state (S3 + DynamoDB lock) thành công ở dev/stg | Ops/SRE | Chưa chạy — GĐ3 | + +## 4. Phương án bị loại và lý do + +| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | +|---|---|---|---| +| PA-2 — AWS CDK | Cần kỹ năng TypeScript/Python cho hạ tầng mà `CON-05` chưa xác nhận đội có; khoá vào AWS làm giảm tuỳ chọn multi-cloud tương lai dù hiện chưa cần | `CON-05` | Xét lại nếu đội xác nhận có kỹ năng lập trình mạnh (TypeScript/Python) và muốn tích hợp logic lập trình phức tạp trực tiếp vào định nghĩa hạ tầng | +| PA-3 — CloudFormation | Cộng đồng module nhỏ hơn, kém tái sử dụng, quản lý state kém linh hoạt hơn so với Terraform (backend S3+DynamoDB tách rời) | `INF §11` (yêu cầu tách state theo môi trường/nhóm) | Xét lại nếu tổ chức có chính sách bắt buộc chỉ dùng công cụ AWS gốc (không có ở dự án này hiện tại) | + +## 5. Hệ quả + +**Hệ quả tích cực** + +- Module hoá tốt, tách state theo môi trường/nhóm tài nguyên — giảm blast radius khi + `terraform apply` +- Drift detection dễ tích hợp CI (`terraform plan` định kỳ, `FIT-34`) +- Không khoá vào một ngôn ngữ lập trình cụ thể — giảm rào cản với đội chưa xác nhận kỹ năng + TypeScript/Python + +**Hệ quả tiêu cực phải sống chung** + +- Cần đào tạo Terraform/HCL cho đội nếu chưa quen (`TCO §5`) +- Cần thiết lập và vận hành backend state riêng (S3 + DynamoDB lock) — thêm một phần hạ tầng nhỏ + cần quản lý (quyền truy cập, backup state) + +**Cái quyết định này khoá lại** + +| Muốn đổi về sau thì | Tốn | +|---|---| +| Đổi công cụ IaC sau khi đã có code Terraform thật cho toàn bộ hạ tầng | Viết lại toàn bộ + rủi ro thao tác trong lúc migrate state — nhiều tuần | + +**Việc phát sinh** + +| Việc | Chủ | Hạn | Ghi ở đâu | +|---|---|---|---| +| Viết Terraform module thật cho network/data/compute | Ops/SRE + Dev (GĐ3) | Trước go-live | `03-enablement/AGD_e-commerce.md` (chưa tồn tại) | +| Thiết lập backend state (S3 + DynamoDB lock) | Ops/SRE | Trước khi viết module thật | GĐ3 | +| Viết `FIT-34`/`FIT-35`/`FIT-36` thật | Ops/SRE (GĐ3) | GĐ3 | `03-enablement/FIT_e-commerce.md` | + +## 6. Cách kiểm chứng quyết định này được tuân thủ + +| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | +|---|---|---|---| +| Drift detection — hạ tầng thật khớp Terraform state | `terraform plan` định kỳ / driftctl | CI, hàng ngày | `FIT-34` *(đã đề xuất ở `INF §11`)* | +| Tag policy — mọi tài nguyên có đủ 4 tag bắt buộc | AWS Config rule / OPA | CI + AWS Config liên tục | `FIT-35` *(đã đề xuất ở `INF §11`)* | +| Đúng cấu trúc hạ tầng (2 ECS service GD/HT + 1 Payment, đúng SG cô lập) | Terraform plan review + AWS Config | CI/CD | `FIT-36` *(đã đề xuất ở `INF §11`)* | + +## 7. Điều kiện xét lại + +| Dấu hiệu | Ngưỡng | Ai theo dõi | +|---|---|---| +| Đội xác nhận có kỹ năng TypeScript/Python mạnh và muốn logic lập trình phức tạp trong định nghĩa hạ tầng | Ý kiến chính thức từ Tech Lead sau khi đội đã dùng Terraform một thời gian | Tech Lead | +| Nhu cầu multi-cloud thật sự phát sinh | Có quyết định kinh doanh mở rộng ngoài AWS | PO + Tech Lead | + +## 8. Tham chiếu + +- POC: Không bắt buộc (radar 7/10, dưới ngưỡng 8) +- Bài đo: `FIT-34`/`FIT-35`/`FIT-36` (ứng viên GĐ3, đã đề xuất ở `INF §11`) +- Tài liệu ngoài: — +- Thảo luận: `INF_e-commerce_v1.0.md §11` (phát hiện + đề xuất), `OQ-060`, `DEC-30`