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; mỗi tab unread riêng từ server breakdown. - Badge unread: tổng + từng loại hiện ở entrypoint khi render (chưa mở panel cũng thấy); tin archived không tính; tab không unread → không badge. Panel prefetch trang đầu khi mở, giữ mounted trong session.
- 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.
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 |
| 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.