PRD: Tín hiệu & thông báo thiết bị
| Module | Thiết bị (CORE-04) | PRD ID | PRD-MON-001 |
| Status | In-progress | Owner | Đội Device / Signal |
| Date | 2026-05-21 | Version | v0.1 |
| Packages | @nx/signal · @nx/outreach · @nx/core | URD | MON |
TL;DR
Mang đến cho KICKO một nền tảng activity-notification phía server: một Kafka consumer thu nhận các sự kiện hoạt động, một worker xác định đúng những người dùng nhận trong scope organizer/merchant, lưu một bản ghi notification, rồi đẩy trực tiếp tới các client đang kết nối qua WebSocket. Kết quả - quản trị viên thấy hoạt động thiết bị và nền tảng hiển thị gần như tức thời thay vì phải polling, và use case trực tiếp đầu tiên (inquiry-submitted) chạy thông suốt từ đầu đến cuối.
1. Context & Problem
Định danh & Giám sát Tình trạng Thiết bị (MON) cần nền tảng ghi nhận hoạt động và hiển thị cho quản trị viên gần như tức thời. Hiện chưa có nền tảng thông báo phía server: sự kiện xảy ra ở commerce/outreach nhưng không có gì phát chúng tới đúng người dùng hay đẩy lên giao diện trực tiếp, nên quản trị viên không thể theo dõi hoạt động ngay khi nó diễn ra.
Increment này xây dựng nền tảng đó trong @nx/signal - một pipeline activity-notification trọn vẹn (Kafka consumer → worker → bản ghi được lưu → WebSocket emit) - cùng với việc xác định người nhận theo scope organizer/merchant và một WebSocket transport ổn định. Đây là kênh truyền thời gian thực mà việc giám sát và hiển thị hoạt động dựa vào; phần báo cáo heartbeat/tình trạng (URD-MON-001/002) và các thao tác thiết bị từ xa (URD-MON-004/005) được theo dõi riêng.
2. Goals & Non-Goals
Goals
- Một pipeline activity-notification chạy bằng Kafka trong
@nx/signal: consumer → worker → bản ghi được lưu → WebSocket emit. - Xác định người nhận - thông báo được phát tới đúng người dùng trong scope organizer/merchant.
- Một WebSocket transport ổn định (room + topic + socket-event service) với cách đặt tên room/topic cố định (
signal/notification,NOTIFICATION_CREATED). - Trạng thái đã đọc của notification: các endpoint REST để lấy notification và đánh dấu đã đọc.
- Use case thời gian thực đầu tiên trọn vẹn: thông báo WebSocket inquiry-submitted trong
@nx/outreach.
Non-Goals
- Phát heartbeat và ngưỡng offline 15 phút (URD-MON-001/002).
- Hủy kích hoạt từ xa / xóa dữ liệu từ xa (URD-MON-004/005).
- Giao diện dashboard tình trạng theo từng thiết bị (bề mặt client tiêu thụ).
- Tách bộ công cụ notification khỏi
@nx/signalsang một package dùng chung.
3. Success Metrics
| Metric | Target / signal |
|---|---|
| Độ trễ phát | Sự kiện hoạt động → WebSocket emit tới client gần như tức thời (dưới một giây ở tải thông thường) |
| Độ chính xác người nhận | Thông báo tới đúng người dùng trong scope organizer/merchant; không rò rỉ chéo tenant |
| Độ bền | Mọi notification được phát đều có bản ghi được lưu; trạng thái đã đọc tồn tại qua lần kết nối lại |
| Phạm vi | Đường đi trực tiếp đầu tiên (inquiry-submitted) được kiểm chứng trọn vẹn; pipeline tái dùng cho các loại sự kiện sau |
4. Personas & Use Cases
| Persona | Mục tiêu trong tính năng này |
|---|---|
| Quản trị viên / Chủ sở hữu | Thấy hoạt động nền tảng & thiết bị hiển thị trực tiếp không cần polling |
| Client đang kết nối (web/app) | Nhận thông báo qua WebSocket trực tiếp và phản ánh trạng thái đã đọc |
| Người xử lý outreach | Được báo ngay khi có inquiry được gửi |
Core scenarios: một sự kiện hoạt động đến Kafka → worker xác định người nhận trong scope organizer/merchant và lưu một notification → bản ghi được đẩy qua WebSocket tới các client đang kết nối → một client lấy notification của mình và đánh dấu đã đọc; việc gửi inquiry phát một thông báo WebSocket trực tiếp qua cùng transport này.
5. User Stories
- Là một quản trị viên, tôi muốn hoạt động xuất hiện trên giao diện ngay khi nó diễn ra, để tôi giám sát nền tảng mà không cần làm mới.
- Là một client đang kết nối, tôi muốn nhận thông báo qua WebSocket trực tiếp, để thấy cập nhật ngay khoảnh khắc nó xảy ra.
- Là một client đang kết nối, tôi muốn lấy notification của mình và đánh dấu đã đọc, để trạng thái đã đọc nhất quán qua các phiên.
- Là một người xử lý outreach, tôi muốn có thông báo trực tiếp khi một inquiry được gửi, để tôi phản hồi kịp thời.
- Là nền tảng, tôi muốn thông báo chỉ phát tới người dùng trong đúng scope organizer/merchant, để không tenant nào thấy hoạt động của tenant khác.
6. Functional Requirements
| # | Requirement | URD ref |
|---|---|---|
| FR-1 | Một Kafka consumer thu nhận các sự kiện hoạt động vào pipeline notification | URD-MON-003 |
| FR-2 | Một worker xác định các user ID người nhận trong scope organizer/merchant | URD-MON-003 |
| FR-3 | Mỗi notification được lưu thành một bản ghi activity-notification trong @nx/core | URD-MON-003 |
| FR-4 | Một WebSocket transport (room + topic + socket-event service) đẩy notification tới các client đang kết nối trực tiếp, trên room signal/notification / topic NOTIFICATION_CREATED | URD-MON-003 |
| FR-5 | Các endpoint REST lấy notification của một người dùng và đánh dấu đã đọc | URD-MON-003 |
| FR-6 | Việc gửi inquiry trong @nx/outreach phát một thông báo WebSocket tới các client quan tâm | URD-MON-003 |
Toàn bộ nội dung requirement và tiêu chí nghiệm thu nằm trong Device URD. PRD này tham chiếu chúng thay vì lặp lại.
7. Non-Functional Requirements
| Area | Requirement |
|---|---|
| Tenancy & authz | Việc xác định người nhận theo scope organizer/merchant; thông báo không bao giờ vượt ranh giới tenant |
| Độ bền | Mọi WebSocket emit đều được bảo chứng bằng một bản ghi notification được lưu; trạng thái đã đọc lấy lại được sau khi kết nối lại |
| Performance / scale | Kafka tách rời việc thu nhận khỏi việc phát; worker xử lý các đợt dồn dập mà không chặn producer |
| Độ ổn định transport | Cách đặt tên room/topic cố định (signal/notification, NOTIFICATION_CREATED) để client đăng ký theo một hợp đồng ổn định |
| i18n | Nhãn notification hiển thị cho người dùng dùng song ngữ ({ en, vi }) khi xuất hiện |
8. UX & Flows
Các bề mặt chính: notification component nằm trong @nx/signal (components/notification - consumer, worker, socket-event service, rooms, topics) với REST trong controllers/activity-notifications; đường đi inquiry nằm trong @nx/outreach (components/websocket, controllers/inquiry). Giao diện dashboard tiêu thụ nằm ngoài phạm vi của increment này.
9. Data & Domain
| Entity | Vai trò |
|---|---|
activity-notification | Bản ghi notification được lưu (người nhận, payload, trạng thái đã đọc) trong @nx/core |
| Notification component | Kafka consumer, worker, socket-event service, rooms, topics của @nx/signal |
| WebSocket room / topic | Room signal/notification và topic NOTIFICATION_CREATED - kênh phát trực tiếp |
| Xác định người nhận | Tra cứu của PolicyDefinitionRepository các user ID trong một organizer/merchant |
Chỉ ở mức khái niệm - schema đầy đủ nằm trong developer domain model.
10. Dependencies & Assumptions
Depends on
@nx/core- sở hữu schema/model/repositoryactivity-notification, Kafka topic + types, và việc xác định người nhận quaPolicyDefinitionRepository.- Kafka - đường nối thu nhận giữa các nguồn hoạt động và notification worker.
- WebSocket transport - kênh phát trực tiếp tới các client đang kết nối.
@nx/outreach- producer sự kiện đầu tiên (gửi inquiry).
Assumptions
- Các nguồn hoạt động đẩy sự kiện lên Kafka topic đã thống nhất.
- Dữ liệu thành viên organizer/merchant sẵn sàng cho việc xác định người nhận.
- Client duy trì một kết nối WebSocket và đăng ký room
signal/notification.
11. Risks & Open Questions
| Risk / question | Mitigation / status |
|---|---|
| Việc xác định người nhận có thể rò rỉ chéo tenant | Việc xác định theo scope organizer/merchant; kiểm chứng dựa trên tra cứu thành viên |
| Mất kết nối WebSocket có thể làm rơi thông báo trực tiếp | Mọi emit đều được bảo chứng bằng một bản ghi được lưu; client lấy lại trạng thái đã đọc khi kết nối lại |
| Tên room/topic lệch nhau giữa producer và client | Tên được cố định thành signal/notification / NOTIFICATION_CREATED như một hợp đồng ổn định |
Bộ công cụ notification nằm trong @nx/signal, chưa dùng chung | Chấp nhận cho increment này; việc tách sang package dùng chung là một cân nhắc tương lai |
Heartbeat/tình trạng của MON vẫn còn chờ | Ngoài phạm vi tại đây; increment này chỉ giao transport (xem §2) |
12. Release Plan & Launch Criteria
| Aspect | Plan |
|---|---|
| Phase | P2 (MON là một tính năng P2, In-progress) |
| Rollout | Tất cả merchant; không feature flag |
| Migration | Entity activity-notification mới; không cần migration dữ liệu |
| Launch criteria | Sự kiện hoạt động → xác định người nhận → bản ghi được lưu → WebSocket emit được kiểm chứng trọn vẹn; đường đi inquiry-submitted được kiểm chứng; trạng thái đã đọc tồn tại qua kết nối lại |
| Monitoring | Lượng notification, độ trễ phát, tình trạng kết nối WebSocket, độ đúng của việc xác định người nhận |
13. FAQ
Cái này có giao heartbeat / tình trạng thiết bị không? Không - increment này giao kênh truyền thông báo thời gian thực mà việc giám sát dựa vào. Phát heartbeat và ngưỡng offline (URD-MON-001/002) được theo dõi riêng.
Người nhận được chọn thế nào? Worker xác định các user ID trong scope organizer/merchant liên quan qua PolicyDefinitionRepository; thông báo không bao giờ vượt ranh giới tenant.
Điều gì xảy ra nếu một client bị mất kết nối khi sự kiện xảy ra? Notification vẫn được lưu; client lấy lại notification và trạng thái đã đọc qua REST khi kết nối lại.
Client đăng ký room/topic nào? Room signal/notification, topic NOTIFICATION_CREATED - một hợp đồng cố định, ổn định.
Vì sao đường đi inquiry-submitted nằm ở đây? Đây là use case thời gian thực đầu tiên chứng minh transport trọn vẹn, phát từ @nx/outreach qua cùng nền tảng WebSocket.
References
- URD: Thiết bị - Định danh & Giám sát Tình trạng Thiết bị - requirements (mảng
MON) - Module: Thiết bị - tổng quan + traceability
- Developer: @nx/signal · @nx/outreach · @nx/core