39 KiB
section, title, status, version, reviewer_notes
| section | title | status | version | reviewer_notes |
|---|---|---|---|---|
| 09 | Kế hoạch vận hành & Kiểm thử | approved | 1 |
9. Kế hoạch vận hành & Kiểm thử (Testing & Deployment)
Đầu vào:
00-project-brief.md(profile:scale=large,hasPayment=true,hasPII=true, cloud AWS, Dev/Staging/Production, on-call giờ hành chính + escalation 24/7);02-phan-tich-yeu-cau.md(FR-01..FR-27, NFR-01..NFR-08);03-kien-truc.md(11 service, môi trường 3.3, tích hợp bên thứ ba 3.4);05-thiet-ke-du-lieu.mdv3 (backup/RTO-RPO 5.3.2, retention 5.3.6);06-luong-xu-ly.mdv2 (Business Rules BR-01..BR-15, sequence checkout/payout/KYC/dispute/login);08-bao-mat.mdv2 (§8.1–8.5, OWASP, findings F10/F11/F12/F14 tồn đọng).Right-sizing:
scale=large+hasPayment=true+hasPII=true→ áp dụng đầy đủ pipeline CI/CD nhiều bước (build → test → scan → deploy theo môi trường), monitoring/alerting chi tiết theo NFR, và kế hoạch DR có RTO/RPO phân nhóm theo mức độ nghiêm trọng của service — không có mục nào được rút gọn thành "không áp dụng" ở phần này.
9.1 Chiến lược kiểm thử (Test Strategy)
9.1.1 Unit Testing
| Hạng mục | Nội dung |
|---|---|
| Phạm vi | Business logic thuần trong từng service — đặc biệt các công thức/quy tắc phức tạp: BR-01 (tách đơn theo seller), BR-02 (giữ tồn kho), BR-03 (tính hoa hồng), BR-04/BR-05 (kỳ giữ tiền/điều kiện release payout), BR-06/BR-07/BR-08 (loyalty), BR-09 (điều kiện coupon), BR-10 (điều kiện huỷ đơn), BR-11 (điều kiện review), BR-12 (chính sách MFA/lockout — §8.1.1a), BR-13 (duyệt KYC), BR-14 (dispute), BR-15 (fallback vận chuyển) |
| Trách nhiệm | Đội phát triển sở hữu từng service (Identity, Catalog, Cart & Order, Payment, Seller Management, Commission & Payout, Promotion & Loyalty, Review, Notification, Shipping & Fulfillment, Audit & Compliance) — mỗi PR bắt buộc kèm unit test cho logic mới/sửa |
| Công cụ | JUnit/Jest/PyTest tuỳ stack thực thi (kiến trúc sư chưa ràng buộc ngôn ngữ cụ thể ở mục 3 — giả định stack backend phổ biến cho microservices, VD Node.js/Java/Go); coverage tối thiểu khuyến nghị 70% cho module business logic của Cart & Order, Payment, Commission & Payout (service tài chính/giao dịch cốt lõi); 50% cho service ít rủi ro hơn (Review, Notification) |
| Ngưỡng chặn merge | Build fail nếu coverage giảm so với baseline hoặc unit test đỏ — enforce ở bước "test" của pipeline CI/CD (9.3) |
9.1.2 Integration Testing
| Hạng mục | Nội dung |
|---|---|
| Phạm vi | (a) Giao tiếp đồng bộ REST giữa BFF ↔ service nội bộ (VD Cart & Order ↔ Catalog khi reserve tồn kho — BR-02); (b) luồng bất đồng bộ qua Message Broker (Kafka/MSK) — OrderPlaced, PaymentConfirmed, OrderDelivered, CommissionCalculated, PayoutScheduled, SellerApproved, các domain event ghi audit_log; (c) tích hợp bên thứ ba ở môi trường Staging dùng sandbox: VNPay/Momo (sandbox), GHN/GHTK (sandbox), Google/Facebook OAuth (test app), email/SMS provider (test mode) |
| Trách nhiệm | QA + đội backend liên quan; test theo ranh giới bounded-context (mục 3.1) — không kiểm thử xuyên transaction DB vật lý (vì database-per-service, chỉ có FK logic qua event) |
| Công cụ | Postman/Newman hoặc REST-assured cho API; Testcontainers (Kafka, PostgreSQL) hoặc môi trường Staging thực để test contract giữa producer/consumer event; contract testing (Pact) khuyến nghị cho các cặp service có API nội bộ thay đổi thường xuyên (VD Cart & Order ↔ Commission & Payout) |
| Trọng tâm rủi ro cao | Idempotency của webhook thanh toán (chống replay, mục 4/8 v3), saga đặt hàng → thanh toán → trừ kho → hoa hồng (BR-01/02/03), fallback vận chuyển GHN→GHTK (BR-15) |
9.1.3 UAT (User Acceptance Testing)
| Hạng mục | Nội dung |
|---|---|
| Phạm vi | Toàn bộ FR Must (FR-01, 03–09, 12, 17–19, 21–26) theo kịch bản nghiệp vụ đầu-cuối trên môi trường Staging (dữ liệu ẩn danh hoá, không PII/KYC thật — theo mục 3.3); FR Should/Could (FR-02, 10, 11, 13–16, 20, 27) kiểm thử nếu đã hoàn thành trong phạm vi release |
| Trách nhiệm | Product Owner + đại diện nghiệp vụ (vận hành sàn, CSR, đại diện seller nếu có) xác nhận; QA chuẩn bị kịch bản, môi trường, dữ liệu test |
| Kịch bản tiêu biểu | Checkout đa seller trọn vẹn (duyệt → giỏ hàng → thanh toán → theo dõi đơn → nhận hàng → đánh giá); seller onboarding từ đăng ký đến payout đầu tiên; CSR xử lý một khiếu nại từ đầu đến khi payout bị loại/được release |
| Điều kiện thoát (exit criteria) | 100% kịch bản UAT cho FR Must đạt "Pass"; các FR Should/Could không đạt được ghi nhận là known-issue có kế hoạch khắc phục trước go-live hoặc lùi sau go-live theo quyết định Product Owner |
9.1.4 Performance Testing (gắn NFR cụ thể)
| NFR | Kịch bản tải | Ngưỡng chấp nhận | Công cụ |
|---|---|---|---|
| NFR-01 | Duyệt catalog/tìm kiếm sản phẩm (FR-04) ở tải bình thường và tải đỉnh mô phỏng flash sale | p95 response time < 2 giây | k6/JMeter/Gatling, chạy trên môi trường Staging có cấu hình gần Production (mục 3.3) |
| NFR-01 | Checkout & thanh toán (FR-06, FR-07) ở tải đỉnh | p95 hoàn tất checkout < 3 giây, kể cả khi Catalog/Search đang chịu tải đỉnh song song | k6/JMeter, kịch bản kết hợp đồng thời checkout + browse |
| NFR-02 | Load test mô phỏng flash sale: tăng dần từ tải bình thường lên hàng chục nghìn concurrent users, đo khả năng cache (Redis)/CDN hấp thụ tải đọc và message queue hấp thụ đột biến ghi (đặt hàng) | Không tăng lỗi 5xx đáng kể; queue lag (thời gian xử lý event OrderPlaced→PaymentConfirmed→CommissionCalculated) không vượt ngưỡng cảnh báo (xem 9.4); không xảy ra oversell (BR-02) dưới tải đồng thời cao |
k6 (ramping-arrival-rate), theo dõi qua APM/dashboard mục 9.4 |
| NFR-03 | Chaos/failover test: chủ động tắt 1 instance của service giao dịch cốt lõi (Cart & Order, Payment, Identity) trong lúc có tải | Auto-scaling/Multi-AZ tự phục hồi, downtime cảm nhận bởi client tối thiểu, không vi phạm mục tiêu uptime 99.9% trong cửa sổ kiểm thử | AWS Fault Injection Simulator hoặc kịch bản thủ công (dừng task ECS) |
| Trách nhiệm | Đội DevOps/SRE chủ trì kịch bản và hạ tầng đo; đội backend hỗ trợ phân tích bottleneck theo service | ||
| Tần suất | Trước mỗi lần go-live/major release, và định kỳ trước mùa cao điểm (VD trước các đợt khuyến mãi lớn dự kiến) |
Ghi chú: NFR-01/NFR-03 là giả định mặc định đã chốt ở brief (chưa có SLA hợp đồng thực tế xác nhận) — nếu số liệu tải thực tế sau go-live khác biệt đáng kể so với giả định "large" ở mục 1/5, cần điều chỉnh lại kịch bản/ngưỡng performance test (đã ghi trong
openQuestions).
9.1.5 Security Testing (dựa trên findings mục 8)
| Hạng mục | Nội dung | Nguồn |
|---|---|---|
| SAST (Static Application Security Testing) | Quét mã nguồn mỗi lần build trong CI/CD (SonarQube hoặc Semgrep) — tập trung vào các endpoint ghi dữ liệu (checkout, KYC upload, commission rule) theo rủi ro A03 Injection đã nêu ở mục 8.3 | §8.3 A03 |
| SCA/Dependency scanning | Snyk/Trivy/Dependabot quét lỗ hổng thư viện của mọi service (container ECS Fargate/EKS) — chặn build nếu phát hiện lỗ hổng mức Critical/High chưa có bản vá | §8.3 A06 |
| DAST/Penetration test | Pentest ứng dụng hàng năm + ASV scan hàng quý nếu phạm vi PCI-DSS SAQ A yêu cầu (mục 8.4) — ưu tiên các luồng thanh toán, KYC upload, webhook | §8.4 |
| Kiểm thử theo finding tồn đọng mục 8 | F10 (MSK ACL/TLS — kiểm tra service không liên quan không subscribe được topic PII/tài chính); F11 (khi endpoint pre-signed URL KYC được bổ sung ở mục 4 — kiểm tra TTL ≤5 phút, không lộ file_url_s3 trực tiếp); F12 (khi mã lỗi 423 ERR_ACCOUNT_LOCKED được bổ sung — kiểm tra hành vi khoá/mở khoá đúng theo bảng §8.1.1a); F13 (khi endpoint GET /v1/admin/audit-logs được bổ sung — kiểm tra chỉ scope admin:audit:read truy cập được, dữ liệu nhạy cảm đã redact theo §8.2.5a) |
§8.5 F10, F11, F12, F13 |
| Account lockout / brute-force | Test chủ động: đăng nhập sai liên tiếp theo ngưỡng từng vai trò (Customer/Seller 5 lần → khoá 15 phút; Platform Admin 3 lần → khoá 30 phút — §8.1.1a); xác minh không lộ "email có tồn tại hay không" ở thông báo lỗi thông thường | §8.1.1a |
| OAuth/social login | Test giả mạo state (kỳ vọng 400 ERR_OAUTH_STATE_INVALID), test email trùng tài khoản có sẵn (kỳ vọng 409 ERR_ACCOUNT_LINK_REQUIRED, không auto-merge) |
§8.1.1, §8.3 |
| Webhook replay/idempotency | Gửi lại IPN VNPay/Momo với timestamp quá hạn hoặc gatewayTransactionRef trùng lặp — kỳ vọng bị từ chối/không lặp side-effect |
§8.3 A08 |
| PII masking trong log | Kiểm tra log CloudWatch/APM không lộ email/phone/account_number đầy đủ ở môi trường Production |
§8.2.3 |
| Trách nhiệm | Security champion trong mỗi đội (do chưa có đội Security/Compliance Officer riêng theo brief) phối hợp DevOps chạy scan tự động trong pipeline; pentest/ASV scan thuê ngoài định kỳ |
9.2 Kịch bản kiểm thử (Test Cases)
Quy ước: mỗi
TC-xxgắn đúng 1FR-xx. Chỉ viết test case khi FR có acceptance criteria đủ rõ để suy ra Given-When-Then; trường hợp FR/BR còn thiếu số liệu cụ thể (VD ngưỡng VND hạng thành viên, công thức hoàn tiền dispute), test case nêu rõ phần chưa kiểm thử được và dẫn sangopenQuestions.
9.2.1 Khách hàng & tài khoản
| TC | FR | Priority | Given | When | Then |
|---|---|---|---|---|---|
| TC-01 | FR-01 | Must | Guest chưa có tài khoản, nhập email hợp lệ chưa tồn tại | Gửi POST /v1/auth/register với email/mật khẩu hợp lệ (≥10 ký tự) |
Tài khoản Customer được tạo, password_hash lưu bằng bcrypt/argon2id, trả 201 |
| TC-02 | FR-01 | Must | Tài khoản Customer tồn tại, nhập sai mật khẩu 5 lần liên tiếp trong thời gian ngắn | Gửi POST /v1/auth/login lần thứ 6 |
user_account.locked_until = now + 15 phút (§8.1.1a); phản hồi không tiết lộ email có tồn tại hay không; lần đăng nhập tiếp theo trong 15 phút bị từ chối ngay không so khớp mật khẩu |
| TC-03 | FR-02 | Could | Email a@x.com đã có tài khoản email/password, chưa liên kết OAuth |
Đăng nhập Google bằng cùng email a@x.com |
Hệ thống không tự merge tài khoản; trả 409 ERR_ACCOUNT_LINK_REQUIRED, yêu cầu xác minh sở hữu email trước khi liên kết |
| TC-04 | FR-03 | Must | Customer đã đăng nhập, có 1 địa chỉ mặc định | Thêm địa chỉ giao hàng mới và đặt làm mặc định | Địa chỉ mới được lưu với is_default=true; địa chỉ cũ tự động chuyển is_default=false |
9.2.2 Catalog, giỏ hàng & checkout
| TC | FR | Priority | Given | When | Then |
|---|---|---|---|---|---|
| TC-05 | FR-04 | Must | Catalog có sản phẩm thuộc nhiều seller/category | Guest tìm kiếm theo từ khoá + lọc theo category | Kết quả trả về đúng sản phẩm khớp bộ lọc, thời gian phản hồi p95 < 2s (NFR-01) |
| TC-06 | FR-05 | Must | Giỏ hàng trống của Guest (theo session_id) |
Thêm sản phẩm từ Seller A và Seller B vào cùng giỏ hàng | Cart chứa CartItem với seller_id khác nhau trong cùng một Cart |
| TC-07 | FR-06 | Must | Giỏ hàng có sản phẩm từ 2 seller, đủ tồn kho | Gọi POST /v1/checkout |
Hệ thống tạo 1 Order cha và 2 OrderSeller con tương ứng 2 seller (BR-01); Order.totalAmount = tổng OrderSeller.subtotalAmount |
| TC-08 | FR-06 | Must | Sản phẩm trong giỏ hàng có quantity_available - quantity_reserved < quantity yêu cầu |
Gọi POST /v1/checkout |
Trả 409 ERR_CONFLICT, không tạo Order, không tăng quantity_reserved (BR-02) |
| TC-09 | FR-07 | Must | Đơn hàng ở trạng thái pending_payment, khởi tạo thanh toán VNPay |
VNPay gửi IPN với chữ ký hợp lệ, timestamp trong 5 phút | Payment.status=success; event PaymentConfirmed được publish; Order/OrderSeller.status=confirmed |
| TC-10 | FR-07 | Must | Một giao dịch VNPay đã được xác nhận thành công (gatewayTransactionRef đã ghi nhận) |
VNPay gửi lại IPN trùng gatewayTransactionRef (retry tự nhiên của gateway) hoặc timestamp lệch > 5 phút |
Hệ thống trả 200 OK không lặp side-effect (idempotent) cho retry hợp lệ; từ chối 400 ERR_VALIDATION cho timestamp quá hạn — không tạo PaymentConfirmed lần 2 |
| TC-11 | FR-08 | Must | OrderSeller.status=pending |
Customer gọi huỷ đơn | Đơn chuyển cancelled (BR-10) |
| TC-11b | FR-08 | Must | OrderSeller.status=packed |
Customer gọi huỷ đơn | Bị từ chối — Customer phải dùng luồng đổi trả/khiếu nại (FR-09) thay vì huỷ trực tiếp (BR-10) |
| TC-12 | FR-09 | Must | OrderSeller.status=delivered |
Customer gửi POST /v1/orders/{orderId}/return-requests |
Tạo ReturnRequest(status=requested); nếu PayoutHold liên quan đang holding, chuyển disputed_frozen (BR-14a) |
| TC-13 | FR-10 | Should | Customer đã đăng nhập | Thêm sản phẩm vào wishlist, sau đó xoá | WishlistItem được tạo rồi xoá; không cho trùng lặp (UNIQUE customer_id, product_id) |
| TC-14 | FR-11 | Should | Customer đã mua order_item X, OrderSeller.status=delivered |
Gửi đánh giá rating 5 sao cho sản phẩm trong order_item X |
Review được tạo thành công (BR-11) |
| TC-14b | FR-11 | Should | OrderSeller.status=confirmed (chưa giao hàng) |
Gửi đánh giá cho sản phẩm chưa nhận | Bị từ chối — không cho phép đánh giá trước khi delivered (BR-11) |
| TC-15 | FR-12 | Must | Đơn hàng vừa chuyển PaymentConfirmed |
Notification Service consume event | Email/SMS xác nhận đơn hàng được gửi tới Customer trong thời gian hợp lý (không chặn luồng checkout chính) |
| TC-16 | FR-13 | Should | Coupon SALE10 đang active, còn lượt dùng, đơn hàng đạt min_order_amount |
Áp coupon tại checkout | Giảm giá đúng theo type/value (BR-09); ghi PromotionUsage UNIQUE theo (promotion_id, order_id) |
| TC-16b | FR-13 | Should | Coupon đã hết usage_limit |
Áp coupon tại checkout | Bị từ chối, không áp dụng giảm giá (BR-09) |
9.2.3 Loyalty, đa ngôn ngữ/tiền tệ
| TC | FR | Priority | Given | When | Then |
|---|---|---|---|---|---|
| TC-17 | FR-14 | Should | OrderSeller với subtotalAmount = 250,000đ chuyển delivered |
Loyalty Service consume event OrderDelivered |
LoyaltyTransaction(type=earn, points=25) theo BR-06 (floor(250000/10000)=25) — lưu ý: cách tính trên subtotalAmount từng OrderSeller là giả định của mục 6, cần xác nhận chủ dự án trước go-live (xem openQuestions) |
| TC-17b | FR-14 | Should | LoyaltyAccount.points_balance = 500 |
Customer đổi 300 điểm lấy giảm giá | Giảm giá 30,000đ được áp dụng, points_balance còn 200, ghi LoyaltyTransaction(type=redeem, points=-300) theo bội số 100 (BR-08) |
| TC-18 | FR-15 | Should | Sản phẩm có product_i18n cho vi, en, ja |
Customer chuyển ngôn ngữ hiển thị sang en rồi ja |
Tên/mô tả sản phẩm hiển thị đúng bản dịch tương ứng; ngôn ngữ chưa có bản dịch fallback về vi (mặc định) |
| TC-19 | FR-16 | Could | Sản phẩm giá 500,000 VND, exchange_rate USD đã cấu hình |
Customer xem trang sản phẩm với hiển thị tiền tệ USD |
Giá quy đổi tham khảo hiển thị đúng theo rate_to_vnd; giao dịch checkout vẫn thực hiện bằng VND (không thanh toán trực tiếp ngoại tệ) |
9.2.4 Seller, KYC, commission & payout
| TC | FR | Priority | Given | When | Then |
|---|---|---|---|---|---|
| TC-20 | FR-17 | Must | Seller mới đăng ký, upload đủ 3 tài liệu bắt buộc (business_license, id_card_front, id_card_back) |
Admin duyệt verified cho cả 3 tài liệu |
Seller.status=active, event SellerApproved publish (BR-13) |
| TC-20b | FR-17 | Must | Seller đã upload đủ tài liệu | Admin từ chối 1 tài liệu (rejected) |
Seller.status=rejected kèm reason; Seller có thể nộp lại (quay về pending_kyc) |
| TC-21 | FR-18 | Must | Seller sở hữu ProductVariant với quantity_available=10 |
Seller cập nhật tồn kho thành 20 và đổi giá bán |
inventory_stock.quantity_available=20, product_variant.price_amount cập nhật; sản phẩm khác của seller khác không bị ảnh hưởng |
| TC-22 | FR-19 | Must | Seller A có đơn order_seller X; Seller B không liên quan tới X |
Seller B gọi GET /v1/seller/orders/{X} |
Trả 403 ERR_FORBIDDEN_OWNERSHIP (kiểm soát ownership §8.1.2); Seller A gọi cùng endpoint → trả dữ liệu thành công |
| TC-23 | FR-20 | Should | Seller có CommissionTransaction và Payout trong kỳ gần nhất |
Seller xem GET /v1/seller/payouts |
Hiển thị đúng doanh thu, hoa hồng, trạng thái payout (scheduled/processing/paid/failed) chỉ của chính seller đó |
| TC-24 | FR-21 | Must | Category "Điện tử" chưa có CommissionRule hiệu lực |
Admin cấu hình commission_percent=8%, effective_from=hôm nay |
CommissionRule mới được tạo, có hiệu lực từ ngày chỉ định; đơn hàng phát sinh sau đó tính hoa hồng theo BR-03; action ghi audit_log (CommissionRuleUpdated) |
| TC-25 | FR-22 | Must | PayoutHold.hold_until_date đã qua, không có Dispute mở cho order_seller liên quan |
Job payout hàng tuần chạy | PayoutHold.release_status=released, CommissionTransaction.net_amount được gộp vào Payout mới của seller (BR-04/BR-05) |
| TC-25b | FR-22 | Must | Payout.status=processing được gửi ngân hàng |
Ngân hàng từ chối batch (lỗi định dạng) | Payout.status=failed; hệ thống không tự động thử lại; Admin gọi POST /v1/admin/payouts/{payoutId}/retry thủ công sau xác minh; hành động ghi audit_log |
| TC-26 | FR-23 | Must | Seller đang active, bị phát hiện vi phạm |
Admin khoá seller (PATCH /v1/admin/sellers/{sellerId}/status) |
Seller.status=suspended; seller không thể đăng sản phẩm/nhận đơn mới cho tới khi được Admin mở khoá lại; action ghi audit_log |
| TC-27 | FR-24 | Must | Sản phẩm đang active, bị báo cáo vi phạm |
Admin ẩn sản phẩm toàn sàn | Product.status=hidden_by_admin; sản phẩm không còn hiển thị ở Catalog/Search (kể cả khi seller vẫn active) |
9.2.5 Tranh chấp, vận chuyển, MFA
| TC | FR | Priority | Given | When | Then |
|---|---|---|---|---|---|
| TC-28 | FR-25 | Must | Dispute.status=investigating, CSR đã được gán |
CSR quyết định refund qua PATCH /v1/admin/disputes/{disputeId} |
Dispute.status=resolved; Payment.status=refunded; PayoutHold liên quan chuyển reversed (loại vĩnh viễn khỏi payout, không bao giờ released — BR-14); action ghi audit_log |
| TC-28b | FR-25 | Must | Dispute.status=investigating |
CSR quyết định reject |
ReturnRequest.status=rejected; PayoutHold quay lại holding, chờ hold_until_date release bình thường |
| TC-29 | FR-26 | Must | OrderSeller.status=confirmed, Ops đóng gói xong |
Shipping Service gọi GHN tạo vận đơn thành công | Shipment tạo với tracking_number; OrderSeller.status=shipped; webhook GHN cập nhật delivered → publish OrderDelivered |
| TC-29b | FR-26 | Must | GHN timeout sau 3 lần retry, khu vực giao hàng được GHTK hỗ trợ | Shipping Service fallback | Vận đơn được tạo qua GHTK thay thế (BR-15); nếu cả hai lỗi, đưa vào hàng đợi Ops xử lý thủ công, OrderSeller.status không bị chặn |
| TC-30 | FR-27 | Should | role=platform_admin, mfa_enabled=false |
Đăng nhập bằng email/password đúng | Đăng nhập thành công nhưng bị chặn hoàn toàn scope admin:* cho tới khi hoàn tất mfa/enroll (BR-12) |
| TC-30b | FR-27 | Should | role=platform_admin, mfa_enabled=true |
Đăng nhập đúng mật khẩu | Hệ thống yêu cầu OTP (mfaRequired:true); nhập đúng OTP → nhận accessToken; nhập sai OTP quá 5 lần → challenge token bị vô hiệu |
9.2.6 Bảng tổng hợp Test Case → FR (dùng để điền Traceability Matrix mục 2.4)
| FR | Test Case |
|---|---|
| FR-01 | TC-01, TC-02 |
| FR-02 | TC-03 |
| FR-03 | TC-04 |
| FR-04 | TC-05 |
| FR-05 | TC-06 |
| FR-06 | TC-07, TC-08 |
| FR-07 | TC-09, TC-10 |
| FR-08 | TC-11, TC-11b |
| FR-09 | TC-12 |
| FR-10 | TC-13 |
| FR-11 | TC-14, TC-14b |
| FR-12 | TC-15 |
| FR-13 | TC-16, TC-16b |
| FR-14 | TC-17, TC-17b |
| FR-15 | TC-18 |
| FR-16 | TC-19 |
| FR-17 | TC-20, TC-20b |
| FR-18 | TC-21 |
| FR-19 | TC-22 |
| FR-20 | TC-23 |
| FR-21 | TC-24 |
| FR-22 | TC-25, TC-25b |
| FR-23 | TC-26 |
| FR-24 | TC-27 |
| FR-25 | TC-28, TC-28b |
| FR-26 | TC-29, TC-29b |
| FR-27 | TC-30, TC-30b |
Toàn bộ FR-01..FR-27 đều có ít nhất 1 test case. Một số test case (TC-17, TC-25) có phần "chưa kiểm thử được đầy đủ" vì thiếu số liệu chốt (ngưỡng VND hạng thành viên, công thức hoàn tiền dispute, ngân hàng đối tác cụ thể) — xem
openQuestions/findings.
9.3 CI/CD & Bảo mật pipeline
9.3.1 Pipeline build → test → scan → deploy
flowchart LR
Commit["Commit / Pull Request"] --> Build["Build\n(container image per service)"]
Build --> UnitTest["Unit Test\n(coverage gate 9.1.1)"]
UnitTest --> SAST["SAST\n(SonarQube/Semgrep)"]
SAST --> SCA["Dependency scan\n(Snyk/Trivy/Dependabot)"]
SCA --> Integration["Integration Test\n(Staging sandbox 9.1.2)"]
Integration --> DeployDev["Deploy → Dev\n(auto, mọi merge vào nhánh dev)"]
DeployDev --> DeployStaging["Deploy → Staging\n(auto sau QA sign-off)"]
DeployStaging --> UAT["UAT + Performance/Security test\n(9.1.3, 9.1.4, 9.1.5)"]
UAT --> Approval["Phê duyệt thủ công\n(Product Owner + Kiến trúc sư trưởng)"]
Approval --> DeployProd["Deploy → Production\n(canary/phần trăm rollout — theo feature flag mục 3.3)"]
- Build: mỗi service đóng gói container riêng (khớp mục 3.2 — ECS Fargate/EKS), gắn tag theo commit SHA + semantic version cho release chính thức.
- Test: unit test bắt buộc pass + coverage gate (9.1.1); build fail nếu không đạt.
- Scan: SAST (SonarQube/Semgrep) + SCA (Snyk/Trivy/Dependabot) chạy trên mọi image trước khi cho phép deploy; chặn deploy nếu phát hiện lỗ hổng Critical/High chưa có ngoại lệ được phê duyệt.
- Deploy theo môi trường (khớp mục 3.3):
- Dev: tự động sau mỗi merge vào nhánh phát triển; feature flag mặc định bật.
- Staging: tự động sau khi Dev pass, dùng dữ liệu ẩn danh hoá/giả lập (không PII/KYC thật) để chạy Integration/UAT/Performance/Security test.
- Production: chỉ deploy sau khi UAT pass và có phê duyệt thủ công (Product Owner + Kiến trúc sư trưởng); rollout theo canary/phần trăm người dùng cho tính năng rủi ro cao (thay đổi luồng thanh toán/commission — đã chốt ở mục 3.3).
9.3.2 Phân quyền Production & quản lý secret trong pipeline
| Hạng mục | Thiết kế |
|---|---|
| Truy cập hạ tầng Production | Chỉ đội Ops và Admin được cấp quyền qua IAM role có audit log (đã chốt mục 3.3); không truy cập DB Production trực tiếp trừ khẩn cấp có phê duyệt |
| CI/CD → AWS | Ưu tiên OIDC federation (GitHub Actions/GitLab CI ↔ AWS IAM role tạm thời) thay vì access key/secret key dài hạn nhúng trong pipeline — giảm rủi ro lộ credential vĩnh viễn |
| Secret trong pipeline | Toàn bộ secret (DB credentials, API key VNPay/Momo/GHN/GHTK, OAuth client secret) lấy từ AWS Secrets Manager tại thời điểm chạy, không lưu trong biến môi trường CI dạng plaintext lâu dài, không commit vào repository (đã chốt mục 8.2.2) |
| Phê duyệt deploy Production | Bắt buộc bước phê duyệt thủ công (manual gate) trong pipeline trước khi deploy Production, tách biệt người phê duyệt và người thực hiện deploy (tách vai trò — segregation of duties) |
| Rollout rủi ro cao | Thay đổi luồng thanh toán/commission bắt buộc dùng canary/feature flag rollout theo phần trăm người dùng tăng dần (đã chốt mục 3.3), không deploy 100% ngay lập tức |
| Audit CI/CD | Log lại ai trigger deploy, phiên bản nào, thời điểm nào — phục vụ điều tra sự cố; không bắt buộc ghi vào bảng audit_log nghiệp vụ (mục 5.2.11) vì đây là audit trail hạ tầng/vận hành, khác phạm vi audit nghiệp vụ |
9.4 Giám sát & Nhật ký (Monitoring & Logging)
9.4.1 Metrics theo NFR
| NFR | Metric | Ngưỡng cảnh báo (alert threshold) | Kênh cảnh báo |
|---|---|---|---|
| NFR-01 | p95 latency GET /v1/catalog/search, POST /v1/checkout |
Cảnh báo khi p95 > 2s (catalog/search) hoặc > 3s (checkout) liên tục 5 phút | PagerDuty/OpsGenie → on-call giờ hành chính, escalation nếu ảnh hưởng giao dịch (mục 3.3/NFR-08) |
| NFR-02 | Concurrent connections, Redis cache hit ratio, Kafka/MSK consumer lag theo topic (OrderPlaced, PaymentConfirmed...) |
Cảnh báo khi cache hit ratio < 80% mùa cao điểm, hoặc consumer lag > ngưỡng xử lý trong 2 phút (VD > 1000 message chưa xử lý) | Cảnh báo đội vận hành domain tương ứng (Catalog/Search, Cart & Order) |
| NFR-03 | Uptime/health check theo service (đặc biệt Cart & Order, Payment, Identity — service giao dịch cốt lõi mục 3.1) | Cảnh báo ngay khi health check fail liên tục > 1 phút cho service cốt lõi; escalation 24/7 nếu ảnh hưởng checkout/thanh toán (NFR-08) | Escalation 24/7 cho sự cố nghiêm trọng, giờ hành chính cho sự cố thường |
| NFR-04 | Số lần đăng nhập sai/khoá tài khoản bất thường (failed_login_count tăng đột biến theo IP/khoảng thời gian), số request bị WAF chặn |
Cảnh báo khi phát hiện pattern brute-force/credential stuffing (nhiều tài khoản bị khoá cùng lúc từ cùng dải IP) | Security alert riêng, không lẫn với alert vận hành thông thường |
| NFR-05 | Tỷ lệ ghi audit_log thành công cho hành động nhạy cảm (KYC review, commission update, dispute resolve, payout retry, khoá/mở seller — mục 5.2.11) |
Cảnh báo nếu phát hiện hành động nhạy cảm không có bản ghi audit_log tương ứng (event bị mất/consumer lỗi) |
Cảnh báo đội vận hành Audit & Compliance Service |
| NFR-08 | SLA phản hồi on-call (thời gian từ alert đến acknowledge) | Cảnh báo leo thang (escalate) nếu on-call không acknowledge trong 15 phút cho sự cố nghiêm trọng ảnh hưởng giao dịch | PagerDuty/OpsGenie escalation chain |
9.4.2 Log tập trung & masking PII
- Log tập trung: toàn bộ service ghi log qua CloudWatch Logs (hoặc ELK/OpenSearch dùng chung cluster đã có ở mục 3.2 cho search subsystem, cân nhắc tách index riêng cho log vận hành để không ảnh hưởng hiệu năng search nghiệp vụ); tracing phân tán (distributed tracing, VD AWS X-Ray/OpenTelemetry) cho các luồng xuyên nhiều service (checkout, payout) để debug latency.
- Masking PII trong log (khớp mục 8.2.3): bắt buộc log-scrubber middleware ở tầng ứng dụng trước khi ghi log Production — mask
email,phone,account_number, không logpassword/secret_encrypted/gateway_transaction_refđầy đủ. Áp dụng đồng nhất cho mọi service, kiểm tra lại bằng security test định kỳ (9.1.5). - Retention log vận hành: khớp mục 5.3.6 —
notification_log/shipment_event90 ngày trước khi archive lạnh; log APM/tracing đề xuất giữ 30-90 ngày (không quy định trong brief, đây là giả định — xemassumptions). audit_log(mục 5.2.11/§8.2.5): không thuộc phạm vi log kỹ thuật ở đây — là dữ liệu nghiệp vụ có retention/kiểm soát truy cập riêng (5 năm/10 năm theoresource_type, chỉ scopeadmin:audit:read).
9.5 Kế hoạch rollback & khôi phục thảm hoạ (Rollback & DR)
9.5.1 Điều kiện rollback
| Điều kiện | Hành động |
|---|---|
| Tỷ lệ lỗi 5xx tăng vượt ngưỡng (VD > 1% request) ngay sau khi rollout canary tính năng mới | Tự động dừng rollout, revert về phiên bản trước đó qua feature flag (không cần rollback toàn bộ deploy nếu tính năng được cô lập bằng flag — mục 3.3) |
| Phát hiện lỗi nghiêm trọng ảnh hưởng thanh toán/commission sau khi deploy Production | Rollback thủ công ngay lập tức (revert image về version trước), thông báo escalation 24/7 (NFR-08); không rollback dữ liệu tài chính đã ghi nhận — xử lý bằng nghiệp vụ điều chỉnh (adjustment) nếu cần, không xoá/sửa trực tiếp bản ghi payment/payout đã hoàn tất |
| Job payout hàng tuần thất bại hàng loạt (VD lỗi kết nối ngân hàng) | Không rollback dữ liệu — giữ nguyên Payout.status=failed, cảnh báo Admin, retry thủ công qua endpoint đã có (mục 6.1.4), không tự động replay để tránh double-payout (đã chốt ở mục 3.4/6.1.4) |
| Migration schema DB gây lỗi ở Staging/Production | Áp dụng chiến lược migration tương thích ngược (backward-compatible, VD expand-contract pattern) cho mọi thay đổi schema service tài chính/PII; rollback code trước, rollback schema sau nếu bắt buộc (tránh mất dữ liệu mới ghi trong lúc rollback) |
9.5.2 RTO/RPO (kế thừa từ mục 5.3.2, không thiết kế lại)
| Nhóm service | RPO | RTO | Ghi chú |
|---|---|---|---|
| Payment, Cart & Order, Identity & Access (giao dịch cốt lõi) | ≤ 15 phút | ≤ 1 giờ | Ưu tiên phục hồi đầu tiên — ảnh hưởng trực tiếp doanh thu/uptime NFR-03 |
| Commission & Payout, Seller Management (tài chính nhạy cảm) | ≤ 1 giờ | ≤ 4 giờ | Payout không realtime nhưng cần audit trail đầy đủ khi khôi phục |
| Catalog & Inventory, Promotion & Loyalty, Shipping & Fulfillment | ≤ 1 giờ | ≤ 8 giờ | |
| Review, Notification, Audit & Compliance | ≤ 24 giờ | ≤ 24 giờ | Không ảnh hưởng giao dịch trực tiếp |
Các con số RTO/RPO trên là giả định đã chốt ở mục 5.3.2 (brief không có SLA hợp đồng cụ thể) — mục 9 kế thừa nguyên trạng, không thay đổi.
9.5.3 Quy trình khôi phục (tham chiếu mục 5 — Backup & Recovery)
- Xác định phạm vi sự cố: service nào bị ảnh hưởng, dữ liệu mất từ thời điểm nào (dựa trên PITR — Point-in-Time Recovery đã bật cho toàn bộ RDS theo mục 5.3.2).
- Khôi phục RDS: dùng Automated Backup + PITR (retention 35 ngày cho service tài chính/PII cốt lõi, 14 ngày cho service ít quan trọng — mục 5.3.2) để restore về thời điểm trước sự cố; với sự cố quy mô lớn (mất cả region), dùng snapshot cross-region đã cấu hình cho Payment/Commission & Payout/Seller Management.
- Khôi phục S3 (KYC, ảnh sản phẩm): dùng versioning + cross-region replication đã bật cho bucket KYC (mục 5.3.2) để khôi phục object bị xoá/ghi đè ngoài ý muốn.
- Đồng bộ lại dữ liệu phái sinh: sau khi RDS của Catalog & Inventory được khôi phục, replay lại event
ProductUpdated/ProductCreated(nếu còn lưu trong Kafka/MSK retention window) để đồng bộ lại chỉ mục OpenSearch; nếu event đã hết retention, chạy job re-index toàn bộ từ RDS. - Xác minh tính toàn vẹn tài chính: với Payment/Commission & Payout, đối chiếu (reconciliation) dữ liệu khôi phục với
payment_reconciliation_log/log đối soát VNPay/Momo trước khi mở lại giao dịch cho service đó — không mở lại luồng thanh toán cho tới khi xác minh xong (ưu tiên đúng đắn dữ liệu tài chính hơn tốc độ khôi phục). - Thông báo & escalation: theo NFR-08 — escalation 24/7 cho sự cố nghiêm trọng, cập nhật trạng thái cho stakeholder (Product Owner, Admin) theo chu kỳ đã thống nhất trong runbook vận hành (runbook chi tiết theo từng service là tài liệu vận hành riêng, ngoài phạm vi SAD).
9.6 Assumptions
- Đội phát triển dùng stack ngôn ngữ phổ biến cho microservices (Node.js/Java/Go...) chưa được chốt cụ thể ở mục 3 — công cụ unit test (9.1.1) là ví dụ minh hoạ, cần điều chỉnh theo stack thực tế khi chọn.
- Ngưỡng coverage unit test (70%/50%) là đề xuất của mục 9, không có trong brief/mục 2 — cần đội kỹ thuật xác nhận khi thiết lập pipeline thực tế.
- Ngưỡng cảnh báo cache hit ratio, consumer lag, tỷ lệ lỗi 5xx cho rollback (9.4, 9.5.1) là giá trị đề xuất dựa trên thông lệ vận hành hệ thống quy mô lớn, chưa được xác nhận bởi SLA/KPI cụ thể của chủ dự án.
- Retention log APM/tracing (30-90 ngày) là giả định của mục 9, không có trong brief.
- Công cụ SAST/SCA/APM cụ thể (SonarQube/Semgrep, Snyk/Trivy, X-Ray/OpenTelemetry, PagerDuty/OpsGenie) là đề xuất minh hoạ theo best practice AWS — không phải ràng buộc bắt buộc từ brief (brief không chỉ định công cụ cụ thể).
9.7 Open Questions
- FR-14 (loyalty): điểm thưởng tính trên
Ordercha hay từngOrderSeller, có gồm phí vận chuyển/thuế hay không (đã nêu ở mục 6.8) — ảnh hưởng trực tiếp kỳ vọng kết quả của TC-17; ngưỡng chi tiêu VND cho từng hạng Bạc/Vàng/Kim Cương chưa có số liệu (ảnh hưởng test hạng thành viên chưa được viết ở mục 9.2 vì thiếu acceptance criteria). - FR-25/BR-14 (dispute): công thức/mức hoàn tiền (toàn phần hay theo tỷ lệ), ai chịu phí vận chuyển hoàn trả — TC-28 chỉ kiểm thử được luồng trạng thái (refund/reject), chưa kiểm thử được số tiền hoàn cụ thể vì chưa có công thức.
- FR-22/BR-04: số ngày hold payout mặc định (5 ngày) và giới hạn cấu hình theo category (có cho phép Admin đặt ngoài khoảng 3-7 ngày hay không) cần chủ dự án xác nhận trước khi chốt bộ test case performance/payout đầy đủ; ngân hàng đối tác và chuẩn kết nối batch file (SFTP+PGP hay API HTTPS) chưa chốt — ảnh hưởng khả năng viết integration test thực tế cho luồng payout (TC-25b hiện chỉ kiểm thử được nhánh "thất bại + retry thủ công", chưa kiểm thử được kết nối ngân hàng thật).
- Mục 4 (API design) đã "hết vòng sửa" theo ghi chú mục 8 — các finding F11 (endpoint pre-signed URL KYC), F12 (mã lỗi
423 ERR_ACCOUNT_LOCKED), F13 (endpoint đọcaudit_log) chưa có endpoint chính thức ở mục 4; test case liên quan (phần trong 9.1.5) chỉ mô tả kỳ vọng khi được bổ sung, chưa thể viết test case thực thi được cho tới khi mục 4 cập nhật. - SLA phản hồi của Seller trước khi hệ thống tự động mở
Disputetừ mộtReturnRequestbị từ chối/không phản hồi chưa có số ngày cụ thể (mục 6.8) — chưa thể viết test case timeout cho luồng leo thang tự động. - Ngân sách/công cụ monitoring cụ thể (PagerDuty/OpsGenie hay giải pháp nội bộ) chưa được xác nhận — ảnh hưởng chi tiết runbook escalation thực tế.
9.8 Findings
| targetSection | issue | severity | suggestion |
|---|---|---|---|
| 02-phan-tich-yeu-cau (FR-14) | FR-14 không có acceptance criteria đủ chi tiết để viết test case xác nhận số điểm/ngưỡng hạng thành viên chính xác (chỉ kiểm thử được công thức giả định của BR-06/BR-07) | medium | Bổ sung acceptance criteria cụ thể (cách tính trên Order hay OrderSeller, ngưỡng VND từng hạng) ở mục 2 sau khi chủ dự án xác nhận |
| 06-luong-xu-ly (BR-14) | Không có công thức hoàn tiền dispute cụ thể → test case TC-28 chỉ xác minh được chuyển trạng thái, không xác minh được số tiền hoàn đúng/sai | medium | Bổ sung công thức hoàn tiền (toàn phần/theo tỷ lệ) ở mục 6 sau khi có quyết định nghiệp vụ |
| 04-api-design | 3 finding bảo mật (F11, F12, F13 — mục 8) chưa có endpoint tương ứng vì mục 4 đã ở trạng thái approved/hết vòng sửa | low | Cần một vòng cập nhật mục 4 (bổ sung endpoint pre-signed URL KYC, mã lỗi 423, endpoint đọc audit_log) trước khi có thể viết security test case thực thi được cho các finding này |
| 08-bao-mat (F10) | ACL/mã hoá theo topic cho Kafka/MSK chưa được cập nhật ở mục 3 (kiến trúc) — chưa thể viết test case xác minh cụ thể ACL nào áp dụng cho topic nào | low | Cần mục 3 bổ sung chi tiết ACL trước khi security test (9.1.5) có thể specify chính xác kịch bản kiểm tra |
| 09 (mục này) | NFR-01/NFR-02/NFR-03 dùng số liệu "giả định mặc định đã chốt" từ brief (chưa có SLA hợp đồng thực tế) — ngưỡng performance test có thể cần điều chỉnh sau go-live | low | Rà soát lại ngưỡng performance/alert sau khi có dữ liệu tải thực tế 1-3 tháng đầu vận hành |