Notification System
Overview
Multi-channel notification system for event changes, reminders, and announcements. Supports SMS and Push notifications with priority-based delivery and user preferences.
Key Features
Channels
- SMS - Sent via BulkSMSBD provider
- Push - Firebase Cloud Messaging (FCM)
Notification Types
schedule_reminder- Daily/weekly schedule remindersschedule_change- Room/time changescancellation- Event cancellationsexam_alert- Exam notificationsseminar_announcement- Seminar announcementsgeneral- General notifications
Priority Levels
Urgent (exams, cancellations):
- SMS + Push immediately
- High visibility
Normal (lectures, room changes):
- Push preferred, SMS fallback
- Standard delivery
Low (seminars, announcements):
- Push only
- Batched delivery
Database Schema
notification.notification
Main notification records.
notification.notification_recipient
Individual delivery tracking per user per channel.
notification.device_token
FCM/APNS tokens for push notifications.
notification.notification_template
Reusable templates for common notifications.
notification.user_preference
User opt-in/opt-out preferences.
See Database Schema for complete table definitions.
Automatic Triggers
Event Change Notification
Trigger: INSERT on event.event_change
Webhook: /webhooks/event-change-notification
Logic:
- Detect change type (room, time, etc.)
- Resolve recipients from
event_target - Determine priority based on event.priority and change_type
- Create notification record
- Create recipient records for all students
- Send via configured channels
- Update
notification_sent = true
Example:
-- Room change triggers notification
INSERT INTO event.event_change (
event_id, change_type, old_value, new_value, reason
) VALUES (...);
-- Trigger automatically creates notificationCancellation Notification
Trigger: INSERT on event.event_cancellation
Webhook: /webhooks/event-cancellation-notification
Logic:
- Get cancellation details
- Resolve recipients from
event_target - Create urgent notification (SMS + Push)
- Include rescheduled event info if available
- Send to all recipients
- Update
notification_sent = true
Manual Notifications
Send Schedule Reminder
mutation SendReminder {
sendNotification(input: {
title: "Tomorrow's Schedule"
message: "You have 3 classes tomorrow"
notification_type: schedule_reminder
priority: normal
target_type: batch
target_id: "batch-uuid"
channels: ["push"]
}) {
id
status
}
}Device Token Management
Register Device (Mobile App)
mutation RegisterDevice {
registerDeviceToken(input: {
token: "fcm-token-xyz123"
platform: android
device_info: {model: "Samsung S21", os: "Android 12"}
}) {
success
}
}Backend: Creates or updates notification.device_token record.
Unregister Device
mutation UnregisterDevice {
unregisterDeviceToken(token: "fcm-token-xyz123") {
success
}
}Delivery Flow
Notification Created
- Via trigger or manual
- Targets defined (batch/section/course)
Recipients Resolved
- Fetch users from target
- Check user preferences
- Filter by enabled channels
Recipient Records Created
- One per user
- Status: pending
Channels Executed
- SMS: Send via BulkSMSBD
- Push: Send via FCM
- Update recipient status
Delivery Tracking
- SMS: sent → delivered
- Push: sent → delivered
- Track read status
User Preferences
Update Preferences
mutation UpdatePreferences {
updateNotificationPreferences(
preferences: [
{event_type: lecture, notification_type: change, channel: sms, enabled: false},
{event_type: exam, notification_type: alert, channel: sms, enabled: true}
]
) {
success
}
}Effect: User receives only enabled notifications via enabled channels.
Notification Templates
Predefined Templates
Room Change
- Title: "Room Change: "
- Message: "Your event has been moved from to "
Cancellation
- Title: "Event Cancelled: "
- Message: ". Rescheduled to at "
Exam Alert
- Title: "Upcoming Exam: "
- Message: "Room , Seat . Starts at "
Use Template
mutation SendFromTemplate {
sendNotificationFromTemplate(
template_name: "exam_room_change"
variables: {
event_title: "CSE 301 Midterm"
old_room: "Room 201"
new_room: "Room 305"
date: "2025-02-15"
time: "14:00"
}
target_type: course_offering
target_id: "course-uuid"
) {
id
}
}Query Patterns
Get User Notifications
query GetMyNotifications($user_id: uuid!, $limit: Int, $offset: Int) {
notification_recipient(
where: {user_id: {_eq: $user_id}}
order_by: {created_at: desc}
limit: $limit
offset: $offset
) {
notification {
title
message
notification_type
priority
created_at
}
read_at
push_status
sms_status
}
}Unread Count
query GetUnreadCount($user_id: uuid!) {
notification_recipient_aggregate(
where: {user_id: {_eq: $user_id}, read_at: {_is_null: true}}
) {
aggregate { count }
}
}Mark as Read
mutation MarkAsRead($notification_recipient_id: uuid!) {
update_notification_recipient_by_pk(
pk_columns: {id: $notification_recipient_id}
_set: {read_at: "now()"}
) {
id
}
}Configuration
Environment Variables
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_PRIVATE_KEY=your-private-key
FIREBASE_CLIENT_EMAIL=your-client-email
BULK_SMS_API_KEY=your-api-key
BULK_SMS_SECRET_KEY=your-secret-key
BULK_SMS_CALLER_ID=your-sender-idSettings
-- Configure default channels per priority
INSERT INTO settings.config (identifier, value) VALUES (
'notification_channels',
'{
"urgent": ["sms", "push"],
"normal": ["push"],
"low": ["push"]
}'::jsonb
);Testing
Test Notification
mutation TestNotification {
sendTestNotification(
user_id: "test-user-uuid"
channel: push
) {
success
}
}Best Practices
- Use appropriate priority - Urgent for time-sensitive, normal for updates
- Respect user preferences - Check before sending
- Batch low-priority - Group multiple notifications
- Log all deliveries - Track in recipient records
- Handle failures gracefully - Retry logic for SMS
- Monitor delivery rates - Track SMS/push success
- Clean old tokens - Remove inactive device tokens
- Test templates - Verify variable substitution
Integration with Event System
Event changes automatically trigger notifications via Hasura event triggers. See Event Management System for details.