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