75 KiB
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ốiDEC-01…23. Quyết định: Thiết kế kiến trúc dữ liệu + ownership cho 15CMPdựa trênSAD 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 độngsec/infkế tiếp và toàn bộ dev BE dùngDATlà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ạmQAS-003/004/006/008/011/014Must 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ảnDATsửa được qua version mới) · không tranh cãi mới, tiếp nối tiền lệDEC-11…23→ ghiDEC-nn, không cầnADRcho việc chạy dưới ngoại lệ. Hệ quả nếu không chấp nhận ngoại lệ: hoạt độngsec/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ácOQđang mở, đặc biệtOQ-007(chặnADR-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)
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
(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 (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 |
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 | |
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 độngsec/adrkế 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. ADRchính thức cho outbox pattern (§4.1) — chỉ trình bày phân tích + đề xuất, chưa viếtADR, thuộc hoạt độngadrkế tiếp (OQ-044).- Cấu hình connection pool cụ thể theo module (
OQ-037, đã có ởFAIL) —DATchỉ 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ảodocs/05,ASM-37) và whitelist chia sẻ seller (recipient_name/phone/address_line, hiện thực hoáADR-008PA-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 dungCart) 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).