Files
sys-analysis-design/sa-output/e-commerce/02-architecture/adr/ADR-007_cho-quyet-dinh-ownership-authz-cart-order.md
Canhchimlac 343ad8bbbc save
2026-09-15 16:02:30 +07:00

11 KiB

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)