Skip to content

Runtime And Delivery — Technical Map

FE runtime map

SurfaceFileVai trò
Bell + badgeNotificationButton.tsxLoad unread aggregate, cache count, mở drawer
Personal listNotificationList.tsxQuery notification_personal, mark read / read all, route resolve
Runtime popupNotificationListener.tsxSubcribe onMessage() rồi bắn QNotify
Vendor wrapperuseOneSignal.tsinit, subscribe, unsubscribe, sendTags, getTags, deleteTags
Boot entrysrc/boot/onesignal.tsInit OneSignal khi app khởi động
Local cacheuseNotificationStore.tsPersist unreadCount, lastRequest vào localStorage

Backend runtime map

LayerFile / objectVai trò
Push deliverynotification-api/messenger/messenger.goApply template, chọn vendor, send/update
Push insert eventnotification-api/event/message.gonotification_send trên insert bảng notification
Push cronnotification-api/scheduler/notification_send.goQuét notification chưa sent_at
Cleanup cronnotification-api/scheduler/notification_cleanup.goXóa notification cũ theo batch
Email immediate/savenotification-api/action/send_email.goLoad template, apply vars, insert/send
SMS immediate/savenotification-api/action/send_sms.goLoad template, apply vars, insert/send
ZNS insert eventnotification-v2-api/event/zns_request_insert.goQuyết định gửi ngay hay schedule
Deferred queuescheduled_tasks + message_scheduler/*.goHeap-based in-memory scheduler cho task trong ngày

Data / read model map

ObjectVai trò
notification_personalFunction lấy inbox cá nhân theo session
notification_personal_statsAggregate unread/read stats
notification_userRead/delete state per user cho push/in-app
message_user_viewUnified read model cho message logs
notification_queueQueue metadata-driven cho một số SMS/ZNS flows
device_tokenDevice token DB-side, có event device_token_register
scheduled_tasksPersisted future task store cho v2 scheduler
zns_request, zns_userZNS request + recipient logs
sms_request, sms_userSMS request + recipient logs
Kỹ thuậtGhi chú
NOTIFICATION_TYPEMap subject_type -> route template cho customer, appointment, order, ticket, approval, project task, inventory transfer...
NotificationList.handleView()Switch lớn để build RouteLocationRaw từ payload data
Payload fieldsMột số route cần thêm order_kind, customer_id, project_id, task_id, recordId ngoài subject_id

Rủi ro / Findings kỹ thuật

MứcFinding
Caonotification_send event trigger chạy trên mọi insert của notification, và sendNotification() gọi Messenger.SendAndUpdate() ngay lập tức. Scheduler notification_send cũng tồn tại cho bản ghi sent_at IS NULL. Điều này xác nhận runtime có hai cơ chế send chồng nhau, trong đó insert-event path đang bypass semantics send_after.
CaoNotificationButton.reloadCount() throttling cứng 60 giây bằng localStorage; unread badge có thể stale ngắn hạn nếu cùng user thao tác trên tab/session khác.
CaoNotificationList.handleView() là switch cross-module rất lớn; chỉ cần route constant đổi ở module khác là notification runtime có thể điều hướng sai mà không có compiler boundary rõ.
Trung bìnhdevice_token và OneSignal external user binding là hai lớp identity/runtime khác nhau; source hiện không cho thấy một abstraction thống nhất giữa web push vendor và DB token registry.
Trung bìnhscheduled_task_insert chỉ hot-load task trong ngày; task xa hơn được để lại cho lần day rollover, nên debugging deferred send phải nhìn cả DB lẫn in-memory queue.