Joy Loyalty · Membership · Plan V2 · SB-12028 / MR !4396

Plan V2 — Migrate tích hợp Membership sang API thế hệ mới của Joy Subscription

App Joy Subscription đã chuyển từ API product-based (V1) sang plan-based (V2). Joy Loyalty tích hợp với Joy Subscription để gán VIP tier cho người subscribe — nên phải migrate tích hợp theo để tính năng tiếp tục chạy: hỗ trợ nhiều sản phẩm/plan, đồng bộ admin UX với app JS mới, và đồng bộ dữ liệu chủ động khi merchant xoá plan. Kèm sửa lỗi xử lý webhook tồn tại sẵn.

Implemented · verified on dev Pending QA + đấu staging với Joy Sub + deploy 29/05/2026

1Vấn đề

Joy Subscription nâng cấp API, Joy Loyalty phải migrate tích hợp theo — nếu không, người subscribe trên plan kiểu mới sẽ không được gán VIP tier.

Joy Subscription đổi mô hình dữ liệu. Trước đây một subscription chỉ gắn 1 sản phẩm (product-based, V1). API mới (plan-based, V2) cho phép nhiều sản phẩm trong cùng một plan. Joy Loyalty đang gọi API cũ — không theo kịp mô hình mới sẽ hỏng tích hợp.

Admin chuyển sang app Joy Subscription. Bản mới merchant tạo/sửa/xoá plan ngay trong app Joy Subscription (UI giàu hơn). Hệ quả: merchant xoá plan bên đó thường xuyên hơn → cách Joy dọn dữ liệu cũ (chỉ dọn khi mở trang) không bắt kịp → cần đồng bộ chủ động qua webhook.

Lỗi webhook có sẵn (ảnh hưởng cả bản cũ). Khi khách subscribe/huỷ, Joy Subscription bắn webhook sang Joy để gán/gỡ tier. Phát hiện: cửa sổ kích hoạt (Activation window) bị bỏ qua hoàn toàn — plan hết hạn vẫn promote, plan chưa tới ngày cũng promote luôn. Ngoài ra mọi thay đổi tier qua webhook không ghi activity log → CS/admin không truy được lịch sử.

Lưu ý quan trọng (tránh hiểu nhầm): gắn VIP tier theo từng chu kỳ (yearly = Gold, monthly = Silver trong cùng plan) không phải tính năng mới — bản V1 đã chạy ≥18 tháng. V2 giữ nguyên khả năng này; thay đổi thật nằm ở số sản phẩm/plan, vị trí màn admin, và cách đồng bộ dữ liệu.

2Giải pháp

Migrate tích hợp sang API plan-based + admin V2 đồng bộ với app JS + đồng bộ dữ liệu chủ động + sửa lỗi webhook.

Tích hợp + Admin V2

Đổi tích hợp Joy ↔ Joy Subscription sang API plan-based (hỗ trợ nhiều sản phẩm/plan). Màn admin V2 trong Joy: chọn nhiều sản phẩm, cấu hình từng frequency (tier · ưu tiên · cửa sổ ngày · auto-tag · giảm giá), preview storefront real-time, widget settings gương từ app JS. Router tự tách shop V1 ↔ V2 — không phá bản cũ.

Webhook backend (đúng & đồng bộ)

Sửa cửa sổ kích hoạt (đọc ngày từ chính dữ liệu Joy, không phụ thuộc payload), ghi activity log mỗi lần đổi tier (kèm tên plan + contract), và xoá sạch dữ liệu loyalty khi Joy Subscription xoá plan (cascade delete) — thay cho cơ chế dọn-khi-mở-trang vốn không kịp với admin flow mới.

3Cách hoạt động

Luồng A — Merchant tạo/sửa plan trong Joy admin

Chọn sản phẩm
Browse modal: lọc theo collection, chọn nhiều sản phẩm/biến thể
Cấu hình frequency
Mỗi chu kỳ: tier · ưu tiên · cửa sổ ngày · auto-tag · giảm giá
Lưu
Joy đẩy cấu trúc plan sang Joy Subscription, lưu phần loyalty riêng

Luồng B — Khách subscribe / huỷ → tier tự đổi

Khách subscribe
Joy Subscription bắn webhook sang Joy Loyalty
Joy kiểm tra
Plan hợp lệ? Trong cửa sổ kích hoạt? Ưu tiên cao hơn tier hiện tại?
Gán tier + ghi log
Đổi VIP tier của khách, gắn tag, ghi activity feed

4Trải nghiệm trong app

Màn sửa frequency: form bên trái, preview storefront real-time bên phải, nút chuyển nhanh giữa các frequency ở góc trên.

Các điểm UX đáng chú ý (đã verify trên dev, ảnh chụp sẽ bổ sung khi tunnel chạy lại):

5Bằng chứng demo

Test backend webhook trên dev shop dopd-joy-dev.myshopify.com (Firebase emulator → staging Firestore). Phase N chạy trên 3 khách hàng thật, kiểm tra cả dữ liệu Firestore lẫn activity feed UI.

KháchKịch bảnKết quả render thật
C1 — dopdtestrefund@Subscribe plan có tier SilverVIP Tier → Silver; activity: "User joined a membership plan — tier moved from Bronze to Silver"; tag c1-vip được gắn
C2 — maint@Huỷ subscription (đang ở Subscriber)VIP Tier → Bronze (fallback); activity: "Membership ended — tier moved from Subscriber to Bronze"; tag được gỡ
C3 — dopd@Đổi từ plan Silver (ưu tiên thấp) sang plan Subscriber (ưu tiên cao)VIP Tier → Subscriber; activity: "User joined a membership plan — tier moved from Silver to Subscriber"

Tổng cộng 61 kịch bản backend webhook PASS (Phase A–O), 0 fail — phủ middleware, dispatch, lọc plan, validation, ưu tiên, đổi tier, gắn/gỡ tag, xoá plan.

6Phạm vi & trạng thái

✅ Đã làm xong

  • Migrate tích hợp Joy ↔ Joy Subscription sang API plan-based (V2)
  • Màn admin V2: list / tạo / sửa / orphan; router tự tách V1 ↔ V2
  • Hỗ trợ nhiều sản phẩm/plan; browse (lọc collection) + preview real-time
  • Cấu hình tier per-frequency (giữ từ V1) · ưu tiên · cửa sổ ngày · auto-tag
  • Widget settings gương từ Joy Subscription
  • Sửa lỗi cửa sổ kích hoạt (webhook) + thêm activity log cho tier change
  • Handler xoá plan (cascade) khi Joy Sub xoá selling plan
  • 61 kịch bản auto-test backend + 3 khách thật verified trên dev
  • Dịch i18n 10 ngôn ngữ

🔜 Follow-up (không chặn)

  • Đấu staging Joy Loyalty ↔ Joy Subscription để test E2E thật cần JS team
  • Verify save Widget Settings end-to-end (sau khi đấu staging) pending
  • QA full + deploy production QA
  • Sau khi webhook delete chạy ổn định: có thể giảm bớt code orphan-detection (giữ làm safety net) tech debt

7Ghi chú cho BA / Tester