--- section: "09" title: Kế hoạch vận hành & Kiểm thử status: approved version: 1 reviewer_notes: "" --- # 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.md` v3 (backup/RTO-RPO 5.3.2, retention 5.3.6); `06-luong-xu-ly.md` v2 (Business Rules BR-01..BR-15, sequence checkout/payout/KYC/dispute/login); `08-bao-mat.md` v2 (§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-xx` gắn đúng **1** `FR-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 sang `openQuestions`. ### 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 ```mermaid 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 log `password`/`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_event` 90 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** — xem `assumptions`). - **`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 theo `resource_type`, chỉ scope `admin: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) 1. **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). 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. 3. **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. 4. **Đồ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. 5. **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). 6. **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 `Order` cha hay từng `OrderSeller`, 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 đọc `audit_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ở `Dispute` từ một `ReturnRequest` bị 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 |