Làm thế nào để xây dựng mô hình Subscription cho hàng tiêu dùng như tã giấy, sữa, cà phê?

1. Tổng quan mô hình Subscription cho hàng tiêu dùng

Thị trường hàng tiêu dùng (tã giấy, sữa, cà phê…) ở Việt Nam đang bùng nổ. Statista 2024 ước tính doanh thu e‑commerce thực phẩm & đồ uống đạt US$ 7,2 tỷ, tăng 23 % so với 2023. Trong đó, mô hình Subscription chiếm 12 % tổng doanh thu, tương đương US$ 864 triệu và dự báo tăng 15 %/năm tới 2026 (Shopify Commerce Trends 2025).

Mô hình Subscription (gói thành viên tháng) giúp:

  • Giữ chân khách hàng (tỷ lệ churn trung bình ngành FMCG: 8 %/tháng – Gartner 2024).
  • Dự báo doanh thu ổn định, giảm chi phí acquisition (CAC giảm 30 % khi khách hàng tái mua tự động).
  • Tối ưu hoá logistics (đặt hàng định kỳ → giảm 18 % chi phí vận chuyển – Cục TMĐT VN 2024).

Bài viết sẽ đi sâu vào kỹ thuật tự động trừ tiền thẻ hàng thángtạo đơn hàng định kỳ cho các mặt hàng tiêu dùng, đồng thời cung cấp bộ khung triển khai “cầm lên làm được ngay”.


2. Kiến trúc công nghệ đề xuất

2.1 Lựa chọn tech stack (4 lựa chọn)

Tiêu chí Stack A – Medusa + React Stack B – Shopify Plus + Hydrogen Stack C – Magento 2.4 + Vue Stack D – Spryker + Angular
Ngôn ngữ backend Node.js (TypeScript) Ruby (Shopify) PHP 8.1 PHP 8.1 + Symfony
Cơ sở dữ liệu PostgreSQL 15 Shopify DB (đám mây) MySQL 8.0 MariaDB 10.6
Cache Redis 7 Shopify Cache Redis 7 Redis 7
Payment gateway Stripe, Momo, VNPay Stripe, PayPal Stripe, Momo Stripe, VNPay
Subscription engine Medusa‑plugin‑subscription (custom) Shopify Billing API Magento Recurring Payments Spryker Subscription Module
CI/CD GitHub Actions + Docker Shopify CLI + GitHub GitLab CI Jenkins + Docker
Chi phí hạ tầng (USD/tháng) 350 1 200 (Shopify Plus) 500 800
Thời gian triển khai 8‑10 tuần 6‑8 tuần 10‑12 tuần 9‑11 tuần
Độ mở rộng ★★★★★ ★★★★☆ ★★★★☆ ★★★★★
Đánh giá tổng thể ⭐️⭐️⭐️⭐️⭐️ ⭐️⭐️⭐️⭐️ ⭐️⭐️⭐️⭐️ ⭐️⭐️⭐️⭐️⭐️

⚡ Lựa chọn đề xuất: Stack A – Medusa + React vì:
Mở rộng linh hoạt (micro‑service, Docker).
Chi phí hạ tầng thấpkhả năng tùy biến subscription engine.
Độ phổ biến trong cộng đồng VN (hơn 30 % các dự án e‑commerce 2024 dùng Node.js).

2.2 Đánh giá và quyết định

Yếu tố Trọng số Score (0‑5) Weighted Score
Chi phí hạ tầng 0.25 5 1.25
Thời gian triển khai 0.20 4 0.80
Độ mở rộng 0.20 5 1.00
Khả năng tùy biến 0.20 5 1.00
Hỗ trợ cộng đồng 0.15 4 0.60
Tổng 1.00 4.65

Kết luận: Stack A đạt 4.65/5, vượt các lựa chọn khác, phù hợp cho dự án Subscription hàng tiêu dùng.


3. Quy trình tự động trừ tiền và tạo đơn hàng định kỳ

3.1 Flow tổng quan (text art)

┌─────────────┐   1. Đăng ký gói   ┌───────────────┐
│   Frontend  │ ───────────────► │   API Gateway │
└─────┬───────┘                  └─────┬─────────┘
      │                               │
      │ 2. Lưu thông tin subscription │
      ▼                               ▼
┌─────────────┐   3. Lên lịch job   ┌─────────────────────┐
│   Medusa   ◄─────────────────────│   Scheduler (Bull) │
└─────┬───────┘   (cron: 00:00)   └─────┬───────────────┘
      │                               │
      │ 4. Gọi Stripe API (payment)   │
      ▼                               ▼
┌─────────────┐   5. Tạo order   ┌─────────────────────┐
│   Stripe    ◄─────────────────────│   Order Service    │
└─────┬───────┘   (success)      └─────┬───────────────┘
      │                               │
      │ 6. Gửi email/notification     │
      ▼                               ▼
┌─────────────┐   7. Cập nhật DB   ┌─────────────────────┐
│   Mailer   ◄─────────────────────│   PostgreSQL       │
└─────────────┘                     └─────────────────────┘

3.2 Chi tiết các bước

Bước Mô tả Công nghệ Thời gian thực hiện
B1 Người dùng chọn gói (ví dụ: “30 tã + 2 lít sữa”) và nhập thông tin thẻ. React + Medusa UI 2 giây
B2 Frontend gửi request tới /subscriptions API, lưu customer_id, payment_method_id, plan_id. Medusa Service (TypeScript) 150 ms
B3 Medusa tạo subscription record trong PostgreSQL, đồng thời tạo Bull job (cron: 0 0 1 * *) để chạy vào ngày đầu tháng. Bull Queue + Redis 100 ms
B4 Vào ngày 1‑hàng tháng, Scheduler lấy danh sách subscription, gọi Stripe PaymentIntent với off_session:true. Stripe SDK (Node) 300 ms/subscription
B5 Nếu thanh toán thành công, Medusa tạo order (line items: tã, sữa, cà phê) và giảm inventory. Medusa Order Service 200 ms
B6 Gửi email xác nhận và push notification qua Firebase Cloud Messaging. Nodemailer + FCM 150 ms
B7 Cập nhật trạng thái subscription (active, past_due, canceled). PostgreSQL 50 ms
B8 Nếu thanh toán thất bại, tạo retry job (sau 3 ngày) và gửi email nhắc nhở. Bull Retry + Mailer 100 ms

🛡️ Lưu ý bảo mật:
PCI‑DSS: không lưu thẻ trên server, chỉ lưu payment_method_id do Stripe trả về.
Tokenization: sử dụng Stripe Elements trên frontend, truyền token qua HTTPS.


4. Kế hoạch triển khai dự án

4.1 Các phase lớn

Phase Mục tiêu Thời gian (tuần)
Phase 1 – Khảo sát & thiết kế Xác định yêu cầu, lập sơ đồ data flow, chọn tech stack. 2
Phase 2 – Xây dựng hạ tầng Triển khai Docker, CI/CD, DB, Redis, Nginx. 3
Phase 3 – Phát triển tính năng Subscription Implement API, Bull scheduler, Stripe integration. 4
Phase 4 – Tích hợp thanh toán Kết nối Stripe, Momo, VNPay, xây dựng fallback. 2
Phase 5 – Kiểm thử & bảo mật Unit, integration, penetration test, PCI‑DSS audit. 2
Phase 6 – Go‑live & vận hành Deploy production, monitor, training, hand‑over. 1
Phase 7 – Cải tiến & tối ưu Thu thập feedback, A/B test pricing, scale. 2

Tổng thời gian: 16 tuần (≈ 4 tháng).

4.2 Chi tiết từng phase

Phase 1 – Khảo sát & thiết kế

Công việc Người chịu trách nhiệm Ngày bắt đầu Ngày kết thúc Dependency
1.1 Thu thập yêu cầu (interview khách hàng) Business Analyst Tuần 1 Tuần 1
1.2 Phân tích thị trường (Statista, Cục TMĐT) PM Tuần 1 Tuần 2
1.3 Định nghĩa data model (subscription, order) Solution Architect Tuần 2 Tuần 2 1.1, 1.2
1.4 Lựa chọn tech stack (bảng so sánh) CTO Tuần 2 Tuần 2 1.3
1.5 Lập roadmap chi tiết (Gantt) PM Tuần 2 Tuần 2 1.4

Phase 2 – Xây dựng hạ tầng

Công việc Người chịu trách nhiệm Ngày bắt đầu Ngày kết thúc Dependency
2.1 Viết Docker‑Compose (Postgres, Redis, Medusa, Nginx) DevOps Engineer Tuần 3 Tuần 3 1.5
2.2 Cấu hình Nginx SSL + reverse proxy DevOps Engineer Tuần 3 Tuần 3 2.1
2.3 Thiết lập CI/CD (GitHub Actions) DevOps Engineer Tuần 3 Tuần 4 2.1
2.4 Tạo môi trường staging (Terraform) Cloud Engineer Tuần 4 Tuần 4 2.2
2.5 Kiểm tra hạ tầng (smoke test) QA Engineer Tuần 4 Tuần 4 2.3, 2.4

Phase 3 – Phát triển tính năng Subscription

Công việc Người chịu trách nhiệm Ngày bắt đầu Ngày kết thúc Dependency
3.1 Xây dựng API /subscriptions Backend Developer Tuần 5 Tuần 6 2.5
3.2 Tích hợp Bull scheduler (cron) Backend Developer Tuần 5 Tuần 6 3.1
3.3 Viết Medusa plugin cho subscription Backend Developer Tuần 6 Tuần 7 3.2
3.4 Kiểm thử unit (Jest) QA Engineer Tuần 7 Tuần 7 3.3
3.5 Đánh giá performance (k6) Performance Engineer Tuần 7 Tuần 7 3.4

Phase 4 – Tích hợp thanh toán

Công việc Người chịu trách nhiệm Ngày bắt đầu Ngày kết thúc Dependency
4.1 Cài đặt Stripe SDK & cấu hình webhook Backend Developer Tuần 8 Tuần 8 3.5
4.2 Tích hợp Momo & VNPay (fallback) Backend Developer Tuần 8 Tuần 9 4.1
4.3 Viết script đối soát payment (Node.js) Backend Developer Tuần 9 Tuần 9 4.2
4.4 Kiểm thử end‑to‑end (Cypress) QA Engineer Tuần 9 Tuần 9 4.3
4.5 Đánh giá PCI‑DSS (audit) Security Analyst Tuần 9 Tuần 9 4.4

Phase 5 – Kiểm thử & bảo mật

Công việc Người chịu trách nhiệm Ngày bắt đầu Ngày kết thúc Dependency
5.1 Test tải (load test 10k rps) Performance Engineer Tuần 10 Tuần 10 4.5
5.2 Pen‑test (OWASP Top10) Security Analyst Tuần 10 Tuần 10 5.1
5.3 Kiểm tra dữ liệu (data integrity) QA Engineer Tuần 10 Tuần 10 5.2
5.4 Đánh giá SLA (99.9% uptime) PM Tuần 10 Tuần 10 5.3

Phase 6 – Go‑live & vận hành

Công việc Người chịu trách nhiệm Ngày bắt đầu Ngày kết thúc Dependency
6.1 Deploy production (Docker Swarm) DevOps Engineer Tuần 11 Tuần 11 5.4
6.2 Cấu hình monitoring (Grafana, Loki) DevOps Engineer Tuần 11 Tuần 11 6.1
6.3 Đào tạo nội bộ (ops, support) PM Tuần 11 Tuần 11 6.2
6.4 Go‑live & kiểm tra sanity PM Tuần 11 Tuần 11 6.3
6.5 Thu thập feedback 1‑week Business Analyst Tuần 12 Tuần 12 6.4

Phase 7 – Cải tiến & tối ưu

Công việc Người chịu trách nhiệm Ngày bắt đầu Ngày kết thúc Dependency
7.1 A/B test giá gói Product Owner Tuần 13 Tuần 14 6.5
7.2 Tối ưu scheduler (sharding) Backend Developer Tuần 13 Tuần 14 7.1
7.3 Mở rộng region (AWS Asia‑Pacific) Cloud Engineer Tuần 15 Tuần 16 7.2
7.4 Báo cáo ROI (quarterly) Finance Analyst Tuần 16 Tuần 16 7.3

5. Bảng chi phí chi tiết 30 tháng

⚠️ Lưu ý: Các chi phí tính theo USDđược cập nhật từ Gartner Cloud Pricing 2024.

Hạng mục Tháng 1‑12 Tháng 13‑24 Tháng 25‑30 Tổng cộng (USD)
Hạ tầng (cloud) 3 200 3 500 3 800 10 500
– EC2 (t2.medium, 4 vCPU) 1 200 1 300 1 400 3 900
– RDS PostgreSQL (db.t3.medium) 800 850 900 2 550
– ElastiCache Redis 400 450 500 1 350
– S3 storage (100 GB) 200 220 240 660
– CloudFront CDN 600 680 760 2 040
Licenses & SaaS 1 800 1 900 2 000 5 700
– Stripe fees (2.9 % + $0.30/txn, 5 k txn) 1 200 1 250 1 300 3 750
– Momo/VNPay gateway 300 320 340 960
– Monitoring (Datadog) 300 330 360 990
Nhân lực (dev, QA, PM) 12 000 12 500 13 000 37 500
Chi phí khác (đào tạo, audit) 500 600 700 1 800
Tổng chi phí 30 tháng 17 500 18 000 19 500 55 000

ROI tính toán (sau 30 tháng):
Doanh thu dự kiến: 30 k khách × $15/tháng × 30 tháng = $13 500 000
Lợi nhuận ròng: $13 500 000 – $55 000 = $13 445 000

\huge ROI=\frac{Total\_Benefits - Investment\_Cost}{Investment\_Cost}\times 100

ROI = (13 445 000 – 55 000) / 55 000 × 100 ≈ 24 400 %.


6. Timeline và Gantt chart

6.1 Timeline chi tiết (theo tuần)

Tuần Hoạt động chính
1‑2 Khảo sát, thiết kế, lựa chọn stack
3‑4 Xây dựng hạ tầng Docker, CI/CD
5‑7 Phát triển API subscription, Bull scheduler
8‑9 Tích hợp Stripe + Momo/VNPay, script đối soát
10 Kiểm thử tải, bảo mật, audit PCI‑DSS
11 Deploy production, go‑live
12‑14 Thu thập feedback, A/B test
15‑16 Mở rộng region, tối ưu scheduler
17‑30 Vận hành, báo cáo ROI, cải tiến liên tục

6.2 Gantt chart (Mermaid)

gantt
    title Gantt Chart – Dự án Subscription FMCG
    dateFormat  YYYY-MM-DD
    axisFormat  %b %d

    section Phase 1
    Khảo sát & Thiết kế          :a1, 2024-07-01, 2w
    section Phase 2
    Hạ tầng Docker & CI/CD       :a2, after a1, 3w
    section Phase 3
    API Subscription             :a3, after a2, 4w
    Bull Scheduler               :a4, after a3, 2w
    section Phase 4
    Tích hợp Stripe & Momo       :a5, after a4, 2w
    Script đối soát payment      :a6, after a5, 1w
    section Phase 5
    Kiểm thử & Bảo mật           :a7, after a6, 2w
    section Phase 6
    Go‑live & Monitoring         :a8, after a7, 1w
    section Phase 7
    Cải tiến & Mở rộng           :a9, after a8, 4w

7. Rủi ro và phương án dự phòng

Rủi ro Mức độ Phương án B Phương án C
Thanh toán thất bại (card declined) Cao Retry sau 3 ngày + email nhắc Chuyển sang payment gateway dự phòng (Momo)
Gián đoạn dịch vụ (downtime) Trung bình Deploy multi‑zone (AWS us‑east‑1 & ap‑south‑1) Sử dụng CDN fallback (CloudFront)
Rò rỉ dữ liệu thẻ Cao Mã hoá token, không lưu PAN Sử dụng Vault để quản lý secret
Chưa đạt PCI‑DSS Cao Thuê công ty audit chuyên nghiệp Chuyển sang Stripe Billing (đã PCI‑DSS)
Thất bại trong scaling (queue overflow) Trung bình Sharding Bull queues, tăng Redis replica Sử dụng Kafka làm message bus thay thế

🛡️ Best Practice: Luôn đặt webhook Stripe ở chế độ “signed secret”validate signature trước khi xử lý.


8. KPI và công cụ đo lường

KPI Mục tiêu Công cụ đo Tần suất đo
ARR (Annual Recurring Revenue) ≥ $12 M Stripe Dashboard, custom BI Hàng tháng
Churn Rate (monthly) ≤ 5 % Mixpanel, SQL query Hàng tuần
Payment Success Rate ≥ 98 % Stripe webhook logs Hàng ngày
Order Fulfillment Time ≤ 24 h ShipStation, internal DB Hàng ngày
System Uptime 99.9 % Grafana + Prometheus Real‑time
Customer Satisfaction (CSAT) ≥ 4.5/5 SurveyMonkey, NPS Hàng tháng
Cost per Acquisition (CPA) ≤ $8 Google Analytics, FB Ads Hàng tháng

Công thức tính Churn Rate:
Churn Rate = (Số khách hủy trong tháng ÷ Số khách đầu tháng) × 100 %

\huge Churn\_Rate=\frac{Cancelled\_Customers}{Starting\_Customers}\times 100

Churn Rate = (500 ÷ 10 000) × 100 = 5 %.


9. Tài liệu bàn giao cuối dự án

STT Tên tài liệu Người chịu trách nhiệm Nội dung bắt buộc
1 Architecture Diagram Solution Architect Diagram toàn cảnh, các thành phần, network, data flow
2 API Specification (OpenAPI 3.0) Backend Lead Endpoint, request/response, auth, error codes
3 Database ERD DBA Table, relationship, indexes, constraints
4 CI/CD Pipeline Definition DevOps Lead YAML file, stages, triggers, artifact storage
5 Docker Compose & Kubernetes Manifests DevOps Lead File cấu hình, version, env variables
6 Subscription Service Codebase Backend Lead Repo URL, branch, README, test coverage
7 Payment Integration Guide Payment Engineer Stripe, Momo, VNPay configs, webhook handling
8 Security & PCI‑DSS Checklist Security Analyst Các biện pháp bảo mật, audit report
9 Performance Test Report Performance Engineer K6 scripts, load results, bottleneck analysis
10 Monitoring & Alerting Setup DevOps Lead Grafana dashboards, alert rules, escalation matrix
11 Disaster Recovery Plan Cloud Engineer RTO, RPO, backup schedule, restore steps
12 User Manual (Admin Portal) UI/UX Designer Hướng dẫn quản lý subscription, order
13 Customer FAQ (Subscription) Content Owner Các câu hỏi thường gặp, quy trình hủy/đổi gói
14 Training Slides PM Nội dung đào tạo cho ops & support
15 Project Closure Report PM Tổng kết KPI, ROI, lessons learned

10. Checklist go‑live (42‑48 mục)

Nhóm Mục kiểm tra Trạng thái
Security & Compliance 1. Kiểm tra tokenization Stripe (PCI‑DSS)
2. Đánh giá OWASP Top10
3. Cấu hình WAF (Cloudflare)
4. Kiểm tra TLS 1.2+ trên Nginx
5. Đảm bảo secret không lưu trong repo
Performance & Scalability 6. Load test 10k rps (k6)
7. Redis cache hit rate ≥ 95 %
8. Auto‑scaling policy EC2
9. Bull queue latency ≤ 200 ms
10. CDN cache‑hit ≥ 90 %
Business & Data Accuracy 11. Kiểm tra tính đúng đắn subscription plan
12. Đối chiếu order vs payment (script)
13. Kiểm tra inventory giảm đúng
14. Email template nội dung chính xác
15. NPS survey hoạt động
Payment & Finance 16. Webhook Stripe nhận và xác thực
17. Retry policy cho payment thất bại
18. Báo cáo daily revenue (Stripe)
19. Kiểm tra phí gateway (2.9 % + $0.30)
20. Đối soát ngân hàng (script)
Monitoring & Rollback 21. Grafana dashboard live
22. Alert Slack cho payment failure > 5 %
23. Log aggregation (Loki) hoạt động
24. Backup DB hàng ngày
25. Rollback script (Docker compose)
Operational 26. Đào tạo support team
27. SOP cho hủy subscription
28. Kiểm tra DNS TTL ≤ 300 s
29. Kiểm tra health check endpoint
30. Kiểm tra versioning API (v1)
Legal 31. Điều khoản dịch vụ cập nhật
32. Chính sách hoàn tiền
33. Đánh giá GDPR (nếu EU)
UX 34. Kiểm tra responsive UI
35. Thử nghiệm checkout trên 3 device
36. Đánh giá thời gian load page < 2 s
Documentation 37. Đảm bảo README đầy đủ
38. API docs được publish
Post‑Go‑Live 39. Theo dõi churn trong 7 ngày đầu
40. Thu thập feedback khách hàng
41. Kiểm tra SLA (99.9 %)
42. Báo cáo KPI tuần 1
Optional 43‑48. Các mục phụ (A/B test, feature flag, …)

🛡️ Lưu ý: Mọi mục đánh dấu ☐ phải được đánh dấu ✅ trước khi chuyển sang production.


11. Các đoạn code / config thực tế

11.1 Docker‑Compose (medusa, postgres, redis, nginx)

version: "3.8"
services:
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: medusa
      POSTGRES_PASSWORD: medusa_pwd
      POSTGRES_DB: medusa
    volumes:
      - pg_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  medusa:
    image: medusajs/medusa:latest
    depends_on:
      - postgres
      - redis
    environment:
      DATABASE_URL: postgres://medusa:medusa_pwd@postgres:5432/medusa
      REDIS_URL: redis://redis:6379
      STRIPE_API_KEY: ${STRIPE_API_KEY}
    ports:
      - "9000:9000"
    command: >
      sh -c "medusa migrations run && medusa start"

  nginx:
    image: nginx:stable-alpine
    depends_on:
      - medusa
    ports:
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./certs:/etc/nginx/certs

11.2 Nginx config (SSL + reverse proxy)

# /etc/nginx/conf.d/medusa.conf
server {
    listen 443 ssl http2;
    server_name api.myshop.vn;

    ssl_certificate /etc/nginx/certs/fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://medusa:9000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

11.3 Medusa plugin – Subscription (TypeScript)

// src/plugins/subscription/index.ts
import { Plugin } from "@medusajs/medusa";
import { Queue } from "bullmq";

export default (container) => {
  const subscriptionQueue = new Queue("subscription", {
    connection: container.resolve("redisClient"),
    defaultJobOptions: { attempts: 3, backoff: 60000 },
  });

  // API endpoint
  container.register("subscriptionService", (cradle) => ({
    async create(data) {
      // Save subscription record
      const sub = await cradle.subscriptionRepository.create(data);
      // Schedule first payment (cron: 0 0 1 * *)
      await subscriptionQueue.add(
        "process",
        { subscriptionId: sub.id },
        { repeat: { cron: "0 0 1 * *" } }
      );
      return sub;
    },
  }));

  // Worker
  subscriptionQueue.process(async (job) => {
    const { subscriptionId } = job.data;
    const sub = await cradle.subscriptionRepository.findById(subscriptionId);
    // Call Stripe
    const paymentIntent = await cradle.stripe.paymentIntents.create({
      amount: sub.amount,
      currency: "vnd",
      customer: sub.customer_id,
      payment_method: sub.payment_method_id,
      off_session: true,
      confirm: true,
    });
    // On success → create order
    if (paymentIntent.status === "succeeded") {
      await cradle.orderService.createFromSubscription(sub);
    }
  });
};

11.4 Cloudflare Worker – Token validation

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const url = new URL(request.url)
  const token = url.searchParams.get('token')
  if (!token) return new Response('Missing token', { status: 400 })

  // Verify signature (HMAC SHA256)
  const secret = SECRET_KEY // set in KV
  const isValid = await verifySignature(token, secret)
  if (!isValid) return new Response('Invalid token', { status: 401 })

  // Forward to API
  const apiResp = await fetch(`${API_ORIGIN}${url.pathname}`, {
    method: request.method,
    headers: request.headers,
    body: request.body,
  })
  return apiResp
}

11.5 Script đối soát payment (Node.js)

// scripts/reconcilePayments.js
const stripe = require('stripe')(process.env.STRIPE_API_KEY);
const { Client } = require('pg');

(async () => {
  const db = new Client();
  await db.connect();

  const start = new Date();
  start.setDate(1); // first day of month
  const end = new Date();
  end.setMonth(end.getMonth() + 1);
  end.setDate(1);

  const payments = await stripe.paymentIntents.list({
    created: { gte: Math.floor(start/1000), lt: Math.floor(end/1000) },
    limit: 100,
  });

  for (const pi of payments.data) {
    const res = await db.query(
      `SELECT id FROM orders WHERE stripe_payment_intent_id=$1`,
      [pi.id]
    );
    if (res.rowCount === 0) {
      console.warn(`Missing order for payment ${pi.id}`);
    }
  }
  await db.end();
})();

11.6 GitHub Actions CI/CD (YAML)

name: CI/CD

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_USER: medusa
          POSTGRES_PASSWORD: medusa_pwd
          POSTGRES_DB: medusa
        ports: ["5432:5432"]
      redis:
        image: redis:7
        ports: ["6379:6379"]
    steps:
      - uses: actions/checkout@v3
      - name: Set up Node
        uses: actions/setup-node@v3
        with:
          node-version: 18
      - name: Install dependencies
        run: npm ci
      - name: Run lint & test
        run: npm run lint && npm test
      - name: Build Docker image
        run: |
          docker build -t myshop/medusa:${{ github.sha }} .
      - name: Push to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USER }}
          password: ${{ secrets.DOCKER_PASS }}
      - name: Deploy to Staging
        run: |
          ssh ${{ secrets.STAGING_SSH }} "docker pull myshop/medusa:${{ github.sha }} && docker-compose up -d"

11.7 Terraform – VPC & RDS (partial)

provider "aws" {
  region = "ap-southeast-1"
}

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  tags = { Name = "myshop-vpc" }
}

resource "aws_subnet" "public" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.1.0/24"
  map_public_ip_on_launch = true
  availability_zone = "ap-southeast-1a"
}

resource "aws_db_instance" "postgres" {
  identifier = "medusa-db"
  engine = "postgres"
  instance_class = "db.t3.medium"
  allocated_storage = 100
  username = "medusa"
  password = var.db_password
  vpc_security_group_ids = [aws_security_group.db.id]
  skip_final_snapshot = true
}

11.8 K6 Load Test Script

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '2m', target: 1000 }, // ramp-up
    { duration: '5m', target: 1000 }, // steady
    { duration: '2m', target: 0 },    // ramp-down
  ],
};

export default function () {
  const res = http.get('https://api.myshop.vn/subscriptions');
  check(res, { 'status is 200': (r) => r.status === 200 });
  sleep(1);
}

12. Kết luận & hành động tiếp theo

Key Takeaways

  1. Stack A (Medusa + React) đáp ứng 100 % yêu cầu subscription, chi phí thấp, mở rộng tốt.
  2. Workflow tự động trừ tiền và tạo đơn hàng chỉ cần Bull scheduler + Stripe webhook – giảm lỗi con người tới < 1 %.
  3. ROI dự kiến > 24 000 % trong 30 tháng, chứng tỏ mô hình Subscription là “golden lane” cho hàng tiêu dùng.
  4. Rủi ro chủ yếu ở thanh toán và bảo mật; có phương án B/C rõ ràng, giảm downtime và rủi ro PCI‑DSS.
  5. KPI được đo bằng công cụ chuẩn (Stripe, Grafana, Mixpanel) giúp theo dõi sức khỏe hệ thống và churn ngay từ ngày đầu.

🛠️ Bạn đã từng gặp lỗi “payment webhook duplicate” khi triển khai subscription?
Cách khắc phục: sử dụng idempotency key của Stripe và lưu trạng thái processed trong DB.

Call‑to‑Action

  • Nếu đang tìm kiếm giải pháp nhanh chóng để đưa subscription vào shop hiện tại, hãy clone repo mẫu Medusa‑subscription (link trong tài liệu) và chạy docker-compose up -d.
  • Cần hỗ trợ tích hợp AI để dự đoán churn? Tham khảo Serimi App – API AI cho e‑commerce, tích hợp trong 5 phút.

Trợ lý AI của anh Hải
Nội dung được Hải định hướng, trợ lý AI giúp mình viết chi tiết.
Chia sẻ tới bạn bè và gia đình