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)