core PK: id 10 required 1 unique

Description

Persisted notification records for each user, covering all channels (push, email, SMS, in-app). Stores delivery status, read state, scenario origin, and a deep-link payload so the inbox screen and badge widget can reconstruct context without additional queries.

18
Attributes
5
Indexes
9
Validation Rules
15
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Primary key, generated server-side on creation.
PKrequiredunique
user_id uuid Owner of this notification. Foreign key to users.
required
channel enum Delivery channel used for this notification record.
required
scenario string Identifier of the notification scenario that triggered this record (e.g. 'assignment_received', 'activity_approved', 'certificate_expiring'). Matches the scenario registry.
required
title string Short notification title shown in the inbox and push alert.
required
body text Full notification body text. Supports line breaks; rendered as plain text in push and SMS.
required
data json Structured deep-link payload. Keys: route (string), reference_type (string), reference_id (uuid). Used by the notification message handler to navigate on tap.
-
priority enum Dispatch priority affecting FCM/APNs urgency and inbox sort order.
required
status enum Lifecycle state of the notification.
required
failure_reason string Human-readable reason when status = failed (e.g. 'invalid_push_token', 'email_bounce'). Null otherwise.
-
reference_type string Entity type that this notification relates to (e.g. 'assignment', 'activity', 'event', 'expense_claim', 'certificate'). Null for system-wide notifications.
-
reference_id uuid ID of the referenced entity. Used together with reference_type for deep linking.
-
sent_at datetime Timestamp when the notification was handed off to FCM, email provider, or SMS gateway. Null until dispatched.
-
delivered_at datetime Timestamp confirmed by FCM delivery receipt or email open pixel. Null until confirmed.
-
read_at datetime Timestamp when the user tapped or dismissed the notification in the inbox. Null until read.
-
expires_at datetime Optional expiry after which the notification is no longer actionable (e.g. event sign-up deadline passed). Null = no expiry.
-
created_at datetime Server-side creation timestamp.
required
updated_at datetime Last status update timestamp. Updated on every status transition.
required

Database Indexes

idx_notifications_user_created
btree

Columns: user_id, created_at

idx_notifications_user_status
btree

Columns: user_id, status

idx_notifications_reference
btree

Columns: reference_type, reference_id

idx_notifications_scenario
btree

Columns: scenario, user_id

idx_notifications_expires_at
btree

Columns: expires_at

Validation Rules

title_not_empty error

Validation failed

body_not_empty error

Validation failed

user_id_exists error

Validation failed

channel_enum_valid error

Validation failed

scenario_registered error

Validation failed

reference_pair_complete error

Validation failed

data_payload_schema error

Validation failed

expires_at_in_future error

Validation failed

read_at_requires_delivered_status error

Validation failed

Business Rules

quiet_hours_enforcement
on_create

Push notifications must not be dispatched during a user's configured quiet hours. The scenario evaluation job checks the user's notification_settings row before dispatching. If within quiet hours, dispatch is deferred to the next allowed window unless priority = high (e.g. encrypted assignment received).

channel_opt_out_respected
on_create

If the user has disabled a channel (push/email/sms) for a given scenario in notification_settings, no record is created for that channel. The scenario dispatcher checks enabled channels before writing.

deduplication_cooldown
on_create

The dispatch deduplication guard blocks creation of a duplicate notification for the same (user_id, scenario, reference_id) within the cooldown window defined in notification_cooldown_log_table. Prevents alert storms from repeated triggers.

status_transition_monotonic
on_update

Status transitions follow a strict sequence: pending → sent → delivered → read. A notification already in delivered state cannot be set back to sent. failed is a terminal state for the dispatch attempt; the record may be retried by creating a new record.

user_scoped_access
always

A user may only read or update their own notifications. API endpoints enforce user_id = authenticated user. Coordinators and admins do not have access to another user's notification inbox.

expired_notifications_hidden
always

Notifications past expires_at are excluded from inbox queries and badge counts even if status != read. They are retained in the table for audit but not surfaced in the UI.

high_priority_bypass_quiet_hours
on_create

Notifications with priority = high (e.g. encrypted assignment dispatch, threshold alert) bypass quiet hours and are delivered immediately regardless of user preference.

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
by_user
Retention
archive_after_1year