PRD: Activity notifications & websocket push
| Module | Nền tảng (CORE-16) | PRD ID | PRD-ACT-001 |
| Status | Shipped | Owner | Platform / Signal squad |
| Date | 2026-06-15 | Version | v1.0 |
| Packages | @nx/signal · @nx/core | URD | ACT · WSS |
TL;DR
Biến một hoạt động nghiệp vụ đáng chú ý thành thông báo đến đúng người, tức thì. Một activity event (ví dụ thanh toán thành công) rơi vào luồng hoạt động của nền tảng; một worker phân giải ai cần được biết - tất cả trong một tổ chức, tất cả trong một merchant, hoặc một danh sách user cụ thể - render một thông điệp bản địa hóa, lưu một bản ghi thông báo cho mỗi recipient, rồi đẩy từng bản ghi trực tiếp tới chủ sở hữu qua WebSocket được xác thực và mã hóa đầu-cuối. Mỗi user đọc, đếm và xóa chỉ thông báo của riêng mình qua một API tự-giới-hạn; nếu kênh real-time tạm thời không khả dụng thì các bản ghi vẫn được lưu, nên không mất gì. Người vận hành có một nhóm điều khiển transport tinh gọn để kiểm tra và điều phối các kết nối live.
1. Bối cảnh & Vấn đề
KICKO tạo ra một dòng liên tục các khoảnh khắc đáng chú ý - một thanh toán hoàn tất, một đơn hàng xong - nhưng cho đến nay những khoảnh khắc đó vẫn bị chôn trong service đã tạo ra chúng. Không có cách nào ở tầm nền tảng để biến một hoạt động thành một thông báo bền vững theo từng người, quyết định ai cần thấy, và đưa nó lên một màn hình live ngay khi nó xảy ra. Nhân viên phải refresh và truy vấn lại để biết có chuyện gì đã xảy ra.
Cái còn thiếu là một backbone duy nhất tách rời việc tạo ra một hoạt động với việc gửi nó: một seam sự kiện mà bất kỳ service nào cũng phát lên được, một worker fan-out một hoạt động tới đúng recipient trong đúng phạm vi tenant, một bản ghi bền vững để thông báo sống sót qua mất kết nối, và một transport live đẩy nó tới chủ sở hữu - và chỉ chủ sở hữu - theo thời gian thực.
Increment này cung cấp backbone đó như một năng lực nền tảng hạng nhất: pipeline activity-notification (ACT) và luồng WebSocket real-time (WSS) mà nó vận hành trên đó, kèm read API tự-giới-hạn và một hợp đồng gửi mã hóa, ổn định.
2. Mục tiêu & Không-mục-tiêu
Mục tiêu
- Một pipeline hướng sự kiện: tiêu thụ activity event → phân giải recipient → render nội dung → lưu một bản ghi cho mỗi recipient → đẩy live.
- Phân giải recipient theo phạm vi - fan một hoạt động ra một tổ chức, một merchant, hoặc một danh sách user, fallback về actor khi không có audience nào.
- Một read API tự-giới-hạn bền vững - mỗi user list, đếm (kể cả chưa đọc), đánh dấu-đọc-một và đánh dấu-đọc-tất-cả chỉ thông báo của riêng mình.
- Một push WebSocket live, được xác thực và mã hóa đầu-cuối tới kênh riêng của từng recipient, theo hợp đồng room/topic cố định.
- Khả năng phục hồi - lưu trữ luôn thành công; kênh real-time thiếu hoặc lỗi không bao giờ làm hỏng pipeline và không bao giờ chặn các recipient khác.
- Các điều khiển transport quản trị tinh gọn - trạng thái kết nối, liệt kê client, gửi có đích, broadcast và ngắt kết nối, sau permission.
Không-mục-tiêu
- Kênh email / SMS / push-notification - increment này chỉ cung cấp kênh real-time trong ứng dụng.
- Mô hình tùy chọn / tắt / đăng ký thông báo theo từng user.
- Logic của chính các service tạo sự kiện - phát activity event là trách nhiệm của producer; năng lực này tiêu thụ nó.
- Tăng cường ủy quyền room chống xuyên-tenant trên transport (một follow-up đã biết, xem §11).
- Tạo kiểu UI chuông / activity-feed phía tiêu thụ - PRD này đặc tả API và hợp đồng gửi mà client render.
3. Chỉ số thành công
| Chỉ số | Mục tiêu / tín hiệu |
|---|---|
| Độ trễ gửi | Activity event → push live tới recipient gần như tức thời (dưới một giây ở tải bình thường) |
| Độ chính xác recipient | Một thông báo đến đúng các user trong phạm vi của hoạt động; không rò rỉ xuyên-tenant |
| Độ bền | Mỗi recipient có một bản ghi được lưu kể cả khi socket của họ chết; read-state sống sót qua reconnect |
| Tự-giới-hạn | Một user chỉ có thể đọc hoặc thay đổi thông báo của chính mình |
| Khả năng phục hồi | Một sự cố real-time hoặc một push lỗi đơn lẻ tụt xuống chế độ chỉ-lưu, với zero pipeline lỗi |
4. Personas & Use Cases
| Persona | Mục tiêu trong tính năng này |
|---|---|
| Chủ / Quản lý | Thấy hoạt động của tổ chức hoặc merchant hiện live, không cần refresh |
| Nhân viên / Thu ngân | Nhận các thông báo gửi tới mình và xóa chúng khi đã đọc |
| Client kết nối (web / POS) | Giữ một socket live và phản ánh thông báo mới + read-state tức thì |
| Người vận hành nền tảng | Kiểm tra các kết nối live và điều phối hoặc cắt một phiên khi cần |
Kịch bản cốt lõi: một thanh toán thành công và service thanh toán phát một hoạt động PAYMENT_SUCCESS mang theo actor và subject của đơn. Worker phân giải recipient cho phạm vi của hoạt động đó, render một thông điệp dễ đọc, và ghi một thông báo cho mỗi recipient. Mỗi recipient đang giữ một socket live thấy thông báo xuất hiện tức thì trên kênh riêng của mình; một recipient đang offline sẽ thấy nó chờ sẵn ở lần list thông báo tiếp theo. Recipient nào cũng đánh dấu đã đọc - hoặc xóa tất cả trong một thao tác - và read-state giữ nguyên qua các phiên của họ.
5. User Stories
- Là một chủ, tôi muốn hoạt động xuất hiện ngay khi nó xảy ra, để tôi theo dõi việc kinh doanh mà không refresh.
- Là nhân viên, tôi chỉ muốn các thông báo gửi cho tôi, để feed của tôi liên quan và không bao giờ hiện hoạt động của người khác.
- Là một client kết nối, tôi muốn thông báo qua một socket live, được mã hóa, để cập nhật tức thì và riêng tư khi truyền.
- Là một user, tôi muốn đếm thông báo chưa đọc và đánh dấu đã đọc - một hoặc tất cả, để feed phản ánh những gì tôi đã thấy.
- Là nền tảng, tôi muốn một thông báo sống sót qua một kết nối bị rớt, để một user offline không bao giờ bỏ lỡ nó.
- Là một người vận hành, tôi muốn thấy và điều phối các kết nối live, để chẩn đoán hoặc cắt một phiên.
6. Yêu cầu chức năng
| # | Yêu cầu | URD ref |
|---|---|---|
| FR-1 | Một activity event trên luồng nền tảng được tiêu thụ và biến thành một thông báo cho mỗi recipient được phân giải | URD-ACT-001 |
| FR-2 | Recipient được phân giải theo phạm vi - cả tổ chức, cả merchant, hoặc một danh sách user cụ thể - fallback về actor khi không có ai | URD-ACT-002 |
| FR-3 | Mỗi thông báo lưu recipient, type, organizer, nội dung text + HTML đã render, action URL tùy chọn, dữ liệu có cấu trúc (kể cả actor), và cờ đọc + timestamp | URD-ACT-003 |
| FR-4 | Nội dung được render từ event type thành một thông điệp bản địa hóa, dễ đọc; chỉ các event type được nhận diện mới tạo thông báo, type lạ bị bỏ qua không lỗi | URD-ACT-004 · URD-ACT-005 |
| FR-5 | Một user đã đăng nhập list thông báo của riêng mình (phân trang / lọc) với tổng số và số chưa đọc | URD-ACT-006 |
| FR-6 | Một user có thể đếm thông báo của mình (ví dụ chưa đọc) và đánh dấu đọc một hoặc đọc tất cả, mỗi cái mang một timestamp đọc | URD-ACT-007 · URD-ACT-008 |
| FR-7 | Mọi đọc và ghi đều giới hạn theo recipient đã xác thực - một user không bao giờ thấy hoặc thay đổi thông báo của người khác | URD-ACT-009 |
| FR-8 | Khi tạo, mỗi thông báo được đẩy live tới kênh riêng của recipient qua WebSocket | URD-WSS-001 |
| FR-9 | Client kết nối qua một socket được xác thực (JWT bearer) với handshake ECDH; payload sau handshake được mã hóa đầu-cuối | URD-WSS-002 |
| FR-10 | Gửi dùng một hợp đồng room/topic cố định và fan-out giữa các instance; kênh thiếu hoặc một push lỗi tụt xuống chế độ chỉ-lưu mà không chặn các recipient khác | URD-WSS-003 · URD-WSS-004 · URD-WSS-005 |
| FR-11 | Các điều khiển transport quản trị - trạng thái, list client, get client, broadcast, send-to-room, send-to-client, disconnect - có sẵn sau permission | URD-WSS-006 |
Toàn văn yêu cầu và tiêu chí chấp nhận nằm trong Platform URD - ACT và WSS. PRD này tham chiếu chúng thay vì lặp lại.
7. Yêu cầu phi chức năng
| Lĩnh vực | Yêu cầu |
|---|---|
| Tenancy & cô lập | Phân giải recipient giới hạn theo tổ chức / merchant; read API của user giới hạn theo user ID của chính họ - không rò rỉ xuyên-tenant hay xuyên-user |
| Độ bền | Mỗi push được hậu thuẫn bởi một bản ghi đã lưu; read-state truy được sau reconnect |
| Tách rời & quy mô | Seam sự kiện tách producer khỏi fan-out; một worker hấp thụ các đợt bùng mà không chặn producer |
| Khả năng phục hồi | Lưu trữ độc lập với kênh real-time; push theo từng recipient được settle độc lập nên một lỗi không bao giờ chặn phần còn lại |
| Bảo mật | Kênh live được xác thực (JWT) và mã hóa đầu-cuối (AES dẫn xuất từ ECDH) sau handshake |
| Ổn định transport | Đặt tên room (theo từng recipient) và topic (observation.signal.notification.created) cố định để client đăng ký theo một hợp đồng ổn định |
| Gửi xuyên-instance | Fan-out hậu thuẫn bởi Redis gửi tới một recipient bất kể socket của họ kết nối ở đâu |
| i18n | Nội dung thông báo hướng người dùng được render theo ngôn ngữ của user |
8. UX & Luồng
Client giữ một socket được xác thực, được mã hóa và đăng ký kênh-theo-từng-recipient của riêng mình; trên observation.signal.notification.created nó hiện thông báo mới ở chuông hoạt động. Một recipient đang offline lúc emit sẽ thấy thông báo chờ sẵn qua read API ở lần tải tiếp theo. Đánh dấu một - hoặc tất cả - đã đọc làm số chưa đọc nhất quán qua các phiên.
9. Dữ liệu & Miền
| Thực thể | Vai trò |
|---|---|
ActivityNotification | Bản ghi theo từng recipient được lưu - recipient, type, organizer, nội dung (text + HTML), action URL, dữ liệu có cấu trúc, cờ đọc + timestamp |
| Activity event | Thông điệp đầu vào trên luồng hoạt động - event type, recipient scope, actor, organizer / merchant, recipient cụ thể tùy chọn, payload |
| Phân giải recipient | Tra cứu các user ID trong phạm vi tổ chức hoặc merchant của hoạt động; danh sách cụ thể và actor-fallback được tôn trọng |
| Kênh + topic theo từng recipient | Room WebSocket riêng của recipient và topic notification-created - hợp đồng gửi live |
Chỉ mang tính khái niệm - schema và bất biến đầy đủ nằm trong developer domain model.
10. Phụ thuộc & Giả định
Phụ thuộc vào
@nx/core- sở hữu schema / model / repository củaActivityNotification, registry event-type được nhận diện, topic + message types của luồng hoạt động, và phân giải recipient qua policy/membership repository.- Activity stream (Kafka) - seam ingest giữa producer hoạt động và notification worker.
- WebSocket transport + Redis - kênh gửi live được xác thực, mã hóa, xuyên-instance.
- Các service tạo sự kiện - phát activity event (ví dụ luồng thanh toán phát
PAYMENT_SUCCESS).
Giả định
- Producer phát các activity event đúng định dạng lên topic luồng đã thỏa thuận.
- Dữ liệu membership tổ chức / merchant có sẵn cho phân giải recipient.
- Client duy trì một kết nối WebSocket và đăng ký kênh-theo-từng-recipient của riêng mình.
11. Rủi ro & Câu hỏi mở
| Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|
| Một recipient đang offline khi hoạt động phát | Bản ghi vẫn được lưu bất kể; client đọc lại nó qua API tự-giới-hạn ở lần tải tiếp theo |
| Kênh real-time không khả dụng hoặc một push lỗi | Pipeline tụt xuống chỉ-lưu; push theo từng recipient được settle độc lập nên một lỗi không bao giờ chặn phần khác |
| Rò rỉ xuyên-user trong read API | Mọi đọc / ghi giới hạn theo user ID đã xác thực - một user không thể chạm tới thông báo của người khác |
| Đăng ký room xuyên-tenant trên transport | Follow-up tăng cường đã biết - ủy quyền room hiện đang dễ dãi; room admin / global không được emit tới |
| Trôi tên room / topic giữa producer và client | Cố định theo room-theo-từng-recipient và topic observation.signal.notification.created như một hợp đồng ổn định |
Hôm nay chỉ một event type live (PAYMENT_SUCCESS) | Pipeline hướng-type và tái dùng được; event type mới chỉ thêm một renderer mà không làm lại backbone |
12. Kế hoạch phát hành & Tiêu chí ra mắt
| Khía cạnh | Kế hoạch |
|---|---|
| Phase | P2 - ACT và WSS trong URD feature catalog |
| Triển khai | Tất cả merchant; không feature flag |
| Di trú | Thực thể ActivityNotification mới; không di trú dữ liệu |
| Tiêu chí ra mắt | Activity event → phân giải recipient → bản ghi đã lưu → push live được kiểm chứng end-to-end; list / count / mark-read / mark-all-read tự-giới-hạn hoạt động; một sự cố real-time tụt xuống chỉ-lưu; điều khiển transport quản trị bị permission gate |
| Giám sát | Lượng thông báo, độ trễ gửi, sức khỏe kết nối WebSocket, độ đúng phân giải recipient, tỷ lệ push lỗi |
13. FAQ
Audience cho một thông báo được chọn thế nào? Theo recipient scope của hoạt động - cả tổ chức, cả merchant, hoặc một danh sách user cụ thể. Nếu không cái nào phân giải ra ai, thì actor của hoạt động nhận nó.
Điều gì xảy ra nếu recipient offline? Thông báo vẫn được lưu. Client thấy nó qua read API tự-giới-hạn ở lần tải tiếp theo, và read-state giữ nguyên qua các phiên.
Kênh live có an toàn không? Có - client xác thực bằng JWT bearer qua socket và hoàn tất một trao đổi khóa ECDH; tất cả payload sau handshake được mã hóa đầu-cuối.
Một user có thể thấy thông báo của người khác không? Không - mọi list, count và mark-read giới hạn theo user đã xác thực; read API không bao giờ trả về bản ghi của user khác.
Nếu push real-time lỗi thì sao? Việc gửi tụt xuống chỉ-lưu một cách mượt mà - bản ghi đã được ghi rồi, và một lỗi cho một recipient không bao giờ chặn các recipient khác.
Hôm nay chỉ thanh toán? Pipeline hướng event-type. PAYMENT_SUCCESS là type live đầu tiên; các loại hoạt động mới cắm vào một content renderer và tái dùng toàn bộ backbone.
Tham khảo
- URD: Platform - ACT · WSS
- PRD liên quan: Device signal & notifications - increment giám sát thiết bị chạy trên cùng backbone này
- Module: Nền tảng - tổng quan + traceability
- Developer: @nx/signal · @nx/core