Joy Loyalty · Notification Email · Email Editor v1

Email V2 — trình soạn email kéo-thả trực quan

Thay form soạn email cũ bằng một editor block trực quan ngay trong Joy admin: kéo-thả, xem trước đúng như khi gửi, và gửi email thật — bật dần theo từng shop, không ảnh hưởng khách đang dùng bản cũ.

Implemented · verified on dev Sau flag shop.useEmailEditorV2 · pending QA 2026-06-01

1Vấn đề

Email thông báo (earn points, tier achieved, milestone, referral…) ở bản V1 soạn bằng form cứng.

Merchant chỉ có 1 ô subject + 1 ô nội dung + template cố định: không kéo-thả khối, không đổi bố cục, khó thêm nhiều nút/ảnh/section, và không xem trước đúng — phải gửi thử mới biết email ra sao. Muốn email "đẹp & đúng brand" thì gần như phải nhờ dev sửa HTML.

2Giải pháp

Một trình soạn email trực quan dạng block, nhúng thẳng vào trang Notifications của Joy admin.

🧱 Editor kéo-thả

17 loại block (Heading, Text, Image, Button, Banner, Footer, Divider, Spacer, Social, HTML + khối động Joy: Loyalty Card, Product, Coupon). Kéo-thả, sửa trực tiếp trên canvas, 4 theme màu, nội dung theo từng ngôn ngữ (EN/VI…), khung mô phỏng hộp thư (inbox) để xem y như khách thấy.

🔁 Một nguồn render cho cả xem trước & gửi

Cùng một bộ máy dựng email (block → MJML → HTML) chạy cho cả preview lẫn gửi thật → "xem sao gửi vậy". Merge-tag ({{shop_name}}…) và điều kiện Liquid ({% if %}) được thay giá trị đúng lúc gửi. Bật theo từng shop qua flag, khách V1 không đổi gì.

3Cách hoạt động

Luồng A — Soạn & lưu:

Kéo block vào canvas
Merchant dựng email bằng block, sửa trực tiếp, đổi theme/ngôn ngữ.
Xem trước đúng-như-gửi
Canvas hiện email với giá trị mẫu + điều kiện Liquid đã giải.
Lưu
Bản thiết kế lưu vào notification (emailDocV2) — save bar + ⌘S, không đụng bản V1.

Luồng B — Gửi email thật cho khách:

Sự kiện kích hoạt
Khách earn points / lên tier / tới milestone… → Joy chuẩn bị gửi email.
Cổng an toàn (flag)
Shop bật V2 & có bản thiết kế → dựng theo V2; nếu không → giữ nguyên đường V1.
Dựng + thay biến
block → MJML → HTML; Liquid thay {{tag}} + điều kiện bằng dữ liệu thật.
Gửi (Mailgun)
Email tới hộp thư khách.

4Trải nghiệm trong app

Merchant vào Settings → Notifications → chọn 1 email (shop đã bật flag) là thấy editor: cây block bên trái, canvas (khung inbox) ở giữa, thư viện block + thuộc tính bên phải, panel Settings (Performance · Trigger · Subject & Preview · Sender · Send test).

📧 Inbox · Customer — Avada Store: You've reached $500 Club!

Congratulations!

Hi Lan Nguyen,

Great news! You've officially leveled up to $500 Club 🎉

Next milestone: Platinum Club — You need 200 points more to get there.

View My Benefits
Avada Store · You receive this email as a member of our loyalty program · Unsubscribe

Demo trực tiếp: editor trên dev shop (Settings → Notifications, flag shop.useEmailEditorV2 bật) — dev route /dev_zone/email_editor_v2.

5Bằng chứng

Hạng mụcTrạng tháiKết quả thật
Gửi email V2 thật✓ verified on devBấm "Send test" → email V2 tới inbox thật (Mailgun), render đúng block + biến đã thay.
Xem trước khớp gửiCanvas giải cả {% if next_milestone_name %} → hiện "Next milestone: Platinum Club", không lộ chữ {% %}.
Khách V1 không bị ảnh hưởngKhi flag tắt / chưa có bản V2 → email đi đúng đường V1 cũ, không đổi 1 ký tự.
Chuyển nội dung V1 → V2Mở lần đầu tự chuyển nội dung V1 sang block (không mất chữ), hoặc dùng 1 trong 17 template mẫu.

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

✅ Đã làm xong

  • Editor block đầy đủ: 17 block, kéo-thả, resize, sửa rich-text, 4 theme, undo/redo
  • Nội dung theo từng ngôn ngữ + khung inbox xem trước
  • Panel Email Settings: Performance · Trigger · Subject & Preheader · Sender (From/Reply-to)
  • Lưu/đọc bản thiết kế (emailDocV2) + chuyển V1→V2 + 17 template mẫu
  • Gửi email V2 thật (gate an toàn khách V1) + "Send test"
  • Xem trước khớp gửi (giải Liquid trong canvas)

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

  • Khớp khoảng cách canvas ↔ email chính xác từng px đang làm
  • Preheader vào lúc gửi · cảnh báo email > 90KB
  • Khối động lấy dữ liệu thật lúc gửi (Loyalty Card / Product / Coupon)
  • Gửi theo ngôn ngữ của từng khách chờ task locale

7Ghi chú cho BA

• Tính năng bật/tắt theo từng shop qua flag shop.useEmailEditorV2 — rollout dần, an toàn (khách chưa bật giữ nguyên bản V1).
• Biến (merge-tag) lấy từ chính dữ liệu Joy đang dùng cho email V1 → giá trị nhất quán giữa V1 và V2.
• "Gửi theo ngôn ngữ khách" chờ task locale chung của Joy; hiện gửi theo ngôn ngữ chính của shop.
• Khối động (sản phẩm / thẻ thành viên / coupon) đang ở mức bố cục; phần bind dữ liệu-thật-lúc-gửi là follow-up.