Skip to content

Runtime And Delivery — Business Rules

Tổng quan

Domain này gom phần notification chạy thật khi hệ thống đang hoạt động:

  • inbox cá nhân của user
  • web push listener trên FE
  • vendor delivery cho push/email/SMS
  • queue/scheduler cho ZNS và deferred tasks
  • log/read model như notification_user, message_user_view, sms_user, zns_user

Khác với config surface, domain này trả lời câu hỏi: "message được giao, đọc, log và reconcile như thế nào?"

Scope nghiệp vụ

NhómVai tròSurface chính
Personal inboxBadge unread, notification list, mark read / read allNotificationButton, NotificationList
Web push listenerLắng nghe push hiện popup trong appNotificationListener, useOneSignal, boot/onesignal.ts
Push deliveryGửi notification qua vendor fcm / onesignal / nonenotification-api/messenger
Email/SMS deliverySave request hoặc send-now, log responsesendEmails, sendSMS, email_request_insert, sms_request_insert
ZNS + deferred tasksImmediate send hoặc persist future taskzns_request_insert, scheduled_tasks, message scheduler

Luồng chính

text
App boot
  -> init OneSignal
  -> nếu browser support push:
      -> register push
      -> bind externalUserId = account.id
      -> attach notificationDisplay listener

User mở notification bell
  -> query unread aggregate
  -> load notification_personal(args)
  -> xem item
  -> upsert notification_user(read = true)
  -> refresh badge count

Backend delivery
  -> notification/email/sms/zns request vào DB hoặc action trực tiếp
  -> service tương ứng chọn vendor / template / variables
  -> send
  -> update response + sent_at + success/failure stats
  -> log user-level result vào các bảng/view phụ

Quy tắc nghiệp vụ

Quy tắc
BR-NRT-001Inbox cá nhân không đọc trực tiếp từ bảng notification; nó đi qua function notification_personal(args) và stats function notification_personal_stats(args).
BR-NRT-002Badge unread count được tính bằng total_count - read_count, sau đó cache vào Pinia store + localStorage.
BR-NRT-003Mark-as-read không mutate bản ghi notification gốc; hệ thống upsert notification_user để lưu trạng thái đọc/xóa theo từng user.
BR-NRT-004Đọc tất cả là flow 2 bước: lấy toàn bộ unread IDs rồi bulk upsert notification_user(read = true).
BR-NRT-005FE web push hiện chỉ bind runtime service qua OneSignal; app khởi tạo listener từ boot/onesignal.ts.
BR-NRT-006Khi subscribe thành công, FE gắn externalUserId = account.id để map thiết bị/vendor user với account trong hệ thống.
BR-NRT-007Push payload runtime dùng subject_type + subject_id + data để resolve deep-link sang module đích; notification domain không tự sở hữu màn hình detail đích.
BR-NRT-008Backend notification-api chịu trách nhiệm cho push/email/SMS kiểu v1; notification-v2-api chịu ZNS, messenger integrations và scheduler runtime.
BR-NRT-009ZNS request có hai nhánh: gửi ngay nếu đến hạn gần, hoặc persist sang scheduled_tasks nếu còn xa.
BR-NRT-010scheduled_tasks không chỉ là DB queue; nhánh v2 còn có in-memory scheduler để hot-load task trong ngày và hỗ trợ hủy task khi status chuyển canceled.
BR-NRT-011Runtime log không thống nhất về một bảng duy nhất: push dùng notification_user, SMS dùng sms_user, ZNS dùng zns_user, view tổng hợp dùng message_user_view.

Boundary

BoundaryGhi chú
authruntime bind theo account/session/logout
user / crm / ecommerce / wallet / projectsdeep-link đích của notification nằm ở các module này
settingstemplate/config quyết định runtime output nhưng không chạy delivery tại đây
notification-api vs notification-v2-apiruntime bị chia thành hai thế hệ service song song

Rủi ro / Findings

MứcFinding
P1Routing trong NotificationList dùng switch lớn trên NOTIFICATION_TYPE; đây là coupling trực tiếp từ notification runtime sang nhiều module khác.
P1Runtime status của admin UI đang nhìn theo send_after, trong khi delivery result thật lại nằm ở sent_at/response.
P1message_user_view chỉ là read model; muốn debug delivery phải lần ngược về từng bảng request/log family khác nhau.
P2notification runtime hiện song song 2 model recipient identity: notification_user trong DB và externalUserId bên OneSignal.