3.3 KiB
title, tags, aliases
| title | tags | aliases | ||||
|---|---|---|---|---|---|---|
| Notification |
|
|
Notification
Per-user notification entry. Each row binds to one userId (stored as a string rather than ObjectId), carries a typed severity (info / success / warning / error) and a domain category, optionally references another entity via relatedId, and supports an actionUrl for deep-linking. Old notifications are auto-purged by a 90-day TTL index.
[!note] Source
backend/src/models/Notification.ts:18— schema definitionbackend/src/models/Notification.ts:79— model export
[!warning] String userId
userIdis a String, not an ObjectId, and is not declared withref. Consumers must cast toObjectIdif they want topopulate()it as a User.
Schema
| Field | Type | Required | Default | Validation | Index | Description |
|---|---|---|---|---|---|---|
userId |
String | yes | — | — | yes (single + compound) | Owner of the notification. |
title |
String | yes | — | maxlength 200 | — | Headline. |
message |
String | yes | — | maxlength 1000 | — | Body. |
type |
String | yes | info |
enum: info / success / warning / error |
— | Severity. |
category |
String | yes | — | enum: purchase_request / offer / payment / delivery / system |
yes (compound) | Domain bucket. |
relatedId |
String | no | — | — | yes | Id of the related entity (e.g. PurchaseRequest). |
metadata |
Mixed | no | — | — | — | Arbitrary payload. |
actionUrl |
String | no | — | maxlength 500 | — | Deep link. |
isRead |
Boolean | no | false |
— | yes (compound) | Read flag. |
readAt |
Date | no | — | — | — | When read. |
createdAt |
Date | auto | — | — | yes (compound + TTL) | Mongoose timestamp. |
updatedAt |
Date | auto | — | — | — | Mongoose timestamp. |
The collection name is overridden to notifications via collection: 'notifications'.
Virtuals
None defined.
Indexes
Defined at backend/src/models/Notification.ts:71-77:
{ userId: 1, createdAt: -1 }— user feed.{ userId: 1, isRead: 1 }— unread badge.{ userId: 1, category: 1 }— category filter.{ relatedId: 1 }— lookup by linked entity.{ createdAt: 1 }withexpireAfterSeconds: 60 * 60 * 24 * 90— auto-delete after 90 days.
Plus the implicit index from userId having index: true at the field level.
Pre/Post Hooks
None declared.
Instance Methods
None defined.
Static Methods
None defined.
Relationships
- References: User indirectly through
userId(string); arbitrary entity viarelatedId. - Referenced by: none.
State Transitions
stateDiagram-v2
[*] --> unread
unread --> read : user opens
read --> [*] : TTL purge (90d)
unread --> [*] : TTL purge (90d)
Common Queries
// User feed
Notification.find({ userId }).sort({ createdAt: -1 }).limit(50);
// Unread badge count
Notification.countDocuments({ userId, isRead: false });
// Mark all read
Notification.updateMany(
{ userId, isRead: false },
{ $set: { isRead: true, readAt: new Date() } }
);
// All notifications about a request
Notification.find({ relatedId: purchaseRequestId.toString() });
Related: User, PurchaseRequest, SellerOffer, Payment.