Communication — Góc nhìn end-user
Phần người dùng cảm nhận trực tiếp nhất: họ nhận email, push, tin trong app. Dưới đây là các trải nghiệm quen thuộc và điều gì đứng sau.
1. Nhận tin qua nhiều kênh
"Tôi nhận email xác nhận booking, đồng thời thấy một thông báo trong app."
Một sự việc gửi qua nhiều kênh cùng lúc: email, push, SMS, in-app. Mỗi người nhận / kênh là một OutgoingMessage riêng — hệ thống biết chính xác từng kênh đã tới chưa.
2. Nội dung tự điền đúng thông tin
"Email gọi đúng tên tôi, đúng mã booking, đúng ngày."
Nội dung tin dựa trên template có placeholder như {{TÊN}}, {{MÃ_BOOKING}}. Lúc gửi, hệ thống điền dữ liệu thật — mỗi người nhận một nội dung cá nhân hóa, không phải soạn tay.
3. Không nhận tin trùng
"Hệ thống có vẻ xử lý lại đơn của tôi, nhưng tôi chỉ nhận đúng một email."
Trước khi gửi thật, hệ thống "claim" (giành quyền gửi) mỗi tin. Tin đã "đang gửi/đã gửi" → các lần xử lý lặp thoát, không gọi provider lần nữa. Kết quả: không nhận email đôi.
4. Hộp thư trong ứng dụng (in-app)
"Tôi mở app và thấy danh sách thông báo của mình; phụ huynh thấy gộp tin của các con."
Tin in-app lưu dưới dạng UserMessage — mỗi người nhận một hàng. Phụ huynh thấy hộp thư gộp các thông báo liên quan tới con mình.
Thao tác trong hộp thư
- Hộp thư read-only: chỉ read, archive, save/unsave; không reply, thread, compose,
New message, tìm kiếm người nhận — nội dung do producer sinh, không có endpoint tạo tin từ inbox. - Tin phân loại theo
UserMessageCategory(Reminder/Notification/Message); lọc là server-side filter, không scan phía client. Badge là một tổng unread authoritative; tin archived không tính. Panel prefetch trang đầu khi mở, giữ mounted trong session. - Khi có tin mới, badge và Inbox đang mở được cập nhật gần realtime qua SSE; SSE chỉ báo có thay đổi, còn dữ liệu vẫn được tải bằng REST. Mất SSE không chặn Inbox vì focus/visibility refresh và polling vẫn hoạt động.
- Retention: tin chưa save bị xóa sau 3 tháng từ
CreatedOn(không kể đọc/archive); tin đã save miễn trừ; save/unsave idempotent, không đụng state khác. - Authorization theo portal: Admin Portal =
EnterpriseUser+Employeehiện tại; Enterprise Portal =EnterpriseUser+ mọi Employee profile được link; Customer Portal / AimyMe mini-app = Account hiện tại; AimyMe Global View = mọi Account được link (không cần chọn). Tin ngoài scope → not-found (như tin không tồn tại). - Riêng tư: list chỉ trả preview an toàn có giới hạn; body stream sau khi authorize; không lộ URL Blob vĩnh viễn; log/metrics không chứa body hay recipient data.
Ví dụ thực tế: Phụ huynh đọc tin nhắc
StaffFirstAidExpiration, save tin campaign nghỉ lễ, rồi producer retry cả hai. → Inbox không đổi: tin nhắc vẫn read, tin nghỉ lễ vẫn saved, không dòng trùng.
5. Chiến dịch & báo cáo định kỳ
"Trung tâm gửi thông báo nghỉ lễ tới tất cả phụ huynh." / "Mỗi tuần tôi nhận một báo cáo."
- Campaign: gửi hàng loạt tới nhiều người nhận cùng lúc.
- Report subscription: báo cáo tự động theo lịch.
Cả hai dùng MessagingJob + Blob để xử lý lượng dữ liệu lớn rồi đi qua cùng pipeline gửi.
Notification Settings và trace
- Admin tìm notification theo nhóm Customers, Staff, Staff (Subscribers Only); có thể bật/tắt notification và copy tới Site contact hoặc Business Unit contact ngay ở list, kể cả batch.
- Khi có copy ở cả Site và BU, địa chỉ trùng chỉ nhận một bản. Default recipient được chỉnh ở modal riêng.
- Delivery lưu source-keyed message khi nguồn đã resolve, giúp support tra theo invoice/account/attendee; provider status vẫn là trạng thái gửi thật.
Ví dụ thực tế: Admin chọn 6 notification và bật copy BU contact. → Không phải mở từng site. → Batch áp dụng một lần cho BU; nếu Site contact trùng BU contact, delivery dedupe người nhận.
Report Subscription
Roll Sheet có thể gửi theo lịch hoặc Run Now. Mỗi run luôn lưu file và email dùng secure view/download link; attachment là tùy chọn, quá lớn thì tự chuyển sang link-only. Pause dừng run tương lai nhưng Run Now vẫn được phép nếu subscription còn hợp lệ.
Ví dụ thực tế: Report tuần vượt giới hạn attachment. → Không làm run fail. → File vẫn lưu, email chỉ chứa link bảo mật và run history ghi trạng thái link-only.
Tóm lại với end-user
| Trải nghiệm | Nhờ phần nào |
|---|---|
| Nhận tin qua email/push/SMS/in-app | Nhiều OutgoingMessage / UserMessage theo kênh |
| Nội dung đúng tên, đúng dữ liệu | Template + render ở Generator |
| Không nhận trùng | Claim trước khi gửi (send claim) |
| Hộp thư in-app, gộp cho phụ huynh | UserMessage với partition theo người nhận |
| Hộp thư read-only: read/archive/save, retention 3 tháng | UserMessage + inbox API authorize theo portal scope |
| Badge/list cập nhật gần realtime | SSE invalidation + REST revalidation; polling là fallback |
| Nhận thông báo hàng loạt / báo cáo | Campaign / Report subscription |
Muốn hiểu cơ chế bên dưới? Đọc Khái niệm cốt lõi.