Notification
Data Entity
Description
Persisted notification records delivered to users via push, email, or SMS channels. Stores delivery status, read state, and scenario-driven content for the Notifications area.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key | PKrequiredunique |
user_id |
uuid |
Recipient user. Foreign key to users.id | required |
organization_id |
uuid |
Tenant scope. Foreign key to organizations.id. NULL for platform-level system notifications | - |
type |
enum |
High-level notification category used for routing and filtering | required |
channel |
enum |
Delivery channel used for this notification record | required |
title |
string |
Short notification title shown in push banners and inbox headers. Max 120 chars | required |
body |
text |
Full notification body text. May contain rendered template variables | required |
data |
json |
Arbitrary payload for deep-link routing and action context (e.g. {screen, entity_id, entity_type}) | - |
scenario_template_id |
uuid |
Reference to the notification_scenario_templates row that triggered this notification. NULL for manual or system-generated notifications | - |
is_read |
boolean |
Whether the recipient has viewed the notification in the inbox | required |
read_at |
datetime |
Timestamp when is_read was set to true. NULL until read | - |
delivery_status |
enum |
Current delivery state of the notification | required |
delivery_attempted_at |
datetime |
Timestamp of the last delivery attempt | - |
delivery_error |
text |
Error message from the last failed delivery attempt. NULL on success | - |
retry_count |
integer |
Number of delivery retry attempts made | required |
expires_at |
datetime |
Optional expiry timestamp after which the notification is no longer surfaced in inbox or retried | - |
created_at |
datetime |
Row creation timestamp | required |
updated_at |
datetime |
Row last-updated timestamp | required |
Database Indexes
idx_notifications_user_id
Columns: user_id
idx_notifications_user_is_read
Columns: user_id, is_read
idx_notifications_user_created
Columns: user_id, created_at
idx_notifications_delivery_status
Columns: delivery_status, created_at
idx_notifications_scenario_template_id
Columns: scenario_template_id
idx_notifications_organization_id
Columns: organization_id
Validation Rules
title_max_length
error
Validation failed
body_non_empty
error
Validation failed
valid_type_enum
error
Validation failed
valid_channel_enum
error
Validation failed
read_at_requires_is_read
error
Validation failed
retry_count_non_negative
error
Validation failed
expires_at_in_future_on_create
error
Validation failed
Business Rules
respect_user_notification_settings
Before creating a notification row, check notification_settings for the user and type. If the user has disabled that notification type or channel, set delivery_status=suppressed instead of pending
channel_requires_address
email channel requires user to have a verified email address; sms channel requires a verified phone number. If address is missing, downgrade to in_app and log a warning
max_retry_limit
Delivery retries are capped at 5. After the 5th failed attempt, delivery_status is set to failed and no further retries are scheduled
read_at_set_on_mark_read
When is_read is flipped from false to true, read_at must be set to the current timestamp atomically in the same update
expired_notifications_suppressed
Notifications past expires_at must not be surfaced in the inbox or retried for delivery. A scheduled job marks them suppressed
tenant_isolation
Notifications with an organization_id may only be read by users belonging to that organization. Platform-level notifications (organization_id IS NULL) are visible to all authenticated users