# 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ý.