Domain Model
Signal không định nghĩa schema riêng. Entity được lưu duy nhất của nó là
ActivityNotification, mà bảng, model, và repository đều nằm trong@nx/core. Trạng thái kết nối và khoá AES được giữ in-memory theo từng instance và không được mô hình hoá ở đây.
1. ERD đầy đủ
ActivityNotification không có relation foreign-key nào trong schema — recipientId và organizerId là soft reference tới ID user / organizer được giải lúc ghi.
2. Entities
ActivityNotification
| Thuộc tính | Giá trị |
|---|---|
| Table | ActivityNotification |
| Source | packages/core/src/models/schemas/public/activity-notification/schema.ts |
| Model | packages/core/src/models/schemas/public/activity-notification/model.ts |
| Repository | ActivityNotificationRepository (@nx/core) |
| Soft-delete | có (SoftDeletableRepository, deletedAt) |
| Owner ID column | recipientId (theo từng user) |
Trường:
| Trường | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
id | text | ✓ | Snowflake | Primary key |
recipientId | text | ✓ | — | User đích; một hàng mỗi người nhận |
type | varchar(80) | ✓ | — | TActivityNotificationTypes (xem enum) |
organizerId | text | null | Organizer sở hữu, nếu có phạm vi | |
content | text | ✓ | — | Nội dung plain-text đã render |
html | text | ✓ | — | Nội dung HTML đã render |
actionUrl | text | null | Đích deep-link | |
data | jsonb | ✓ | {} | Snapshot payload actor + sự kiện |
isRead | boolean | ✓ | false | Cờ đã đọc |
readAt | timestamptz | null | Đặt khi đánh dấu đã đọc |
Enum type (ActivityNotificationTypes):
| Giá trị | Mô tả |
|---|---|
PAYMENT_SUCCESS | Loại duy nhất hiện thực hôm nay; render từ payload actor + payment |
Worker từ chối bất kỳ
eventTypenào không trongActivityNotificationTypes.SCHEME_SET(log cảnh báo và bỏ qua).
Index:
| Tên | Cột | Mục đích |
|---|---|---|
IDX_ActivityNotification_recipientId_isDeleted_createdAt | recipient_id, deleted_at, created_at | Query chuông — notification của người nhận, mới nhất trước |
IDX_ActivityNotification_recipientId_isRead | recipient_id, is_read | Đếm chưa đọc |
IDX_ActivityNotification_organizerId_type_createdAt | organizer_id, type, created_at | Lọc theo organizer + type |
Relations: không khai báo trong schema (recipientId / organizerId là soft reference).
3. Bất biến xuyên entity
| Bất biến | Cách thực thi |
|---|---|
| Một hàng mỗi người nhận mỗi fan-out | Worker lặp qua người nhận đã giải và createAll một hàng mỗi cái |
readAt đặt ⇔ isRead = true | ActivityNotificationService.markAsRead / markAllAsRead đặt cả hai cùng nhau |
| Người nhận chỉ đọc/sửa hàng của chính họ | Controller scope mọi query theo recipientId = subject JWT |
4. Hành vi Soft-delete
| Hành vi | Chi tiết |
|---|---|
| Mặc định đọc | deletedAt IS NULL (defaultFilter của model) |
| Hard-delete | signal không dùng |
| Restore | không expose |