Skip to main content

Notification System — Implementation Plan

Gap analysis and phased implementation plan for completing the Tellus EHS notification system.

Table of Contents

  1. Current State Summary
  2. Gap Analysis
  3. Phase 1: Unify & Fix Foundations — COMPLETED
  4. Phase 2: Email Delivery — COMPLETED
  5. Phase 3: Scheduled Notifications
  6. Phase 4: General Notification Preferences
  7. Phase 5: Webhook Delivery (Pro Tier)
  8. Phase 6: Future Module Notifications
  9. File Change Summary

Current State Summary

Updated: 2026-02-24 after Phase 1 and Phase 2 completion.

What Works

FeatureStatusNotes
Unified in-app notifications (32 types)WorkingSingle notifications table with 7 categories
General notification types (25)WorkingDB + SSE + REST API
Training notification types (7)WorkingMerged from SafePath in Phase 1
SSE real-time pushWorkingTraining notifications flow through general system
NotificationBell frontendWorking7 category icons, polling + SSE
Category filteringWorking?category=training on /api/v1/notifications
SafePath schedulerWorkingUses general NotificationService + UnitOfWork
Background notification creationWorkinghandle_notification_send() SQS handler
Auto-assignment notificationsWorkingBackground handlers create training_assigned notifications
Notification deduplicationWorkingNotificationRepository.has_recent_notification()
90-day auto-expiryWorkingexpires_at + delete_expired()
Email delivery (15 types)WorkingVia Mailgun through background service (SQS + direct)
Email opt-outWorkingemail_notifications_enabled boolean on core_data_users
Email preference APIWorkingGET/PUT /api/v1/notifications/email-preference

What Doesn't Work / Is Missing

GapImpactPriority
Two separate notification systemsRESOLVED in Phase 1HIGH
No email delivery for notificationsRESOLVED in Phase 2HIGH
Scheduler not running on cronOverdue/reminder/cert checks never actually executeHIGH
No per-category notification preferencesUsers can only toggle ALL emails, not per-categoryMEDIUM
No webhook deliveryPro tier feature not implementedLOW
Missing notification typessds_expiring, compliance_*, quantity_threshold not triggeredLOW
No notification center pageUsers only see notifications in dropdown bellLOW
Background notifications miss SSEAsync notifications only appear on next pollMEDIUM

Gap Analysis

Gap 1: Two Separate Notification Systems — RESOLVED

Resolved in Phase 1 (2026-02-24). The safepath_notifications and safepath_notification_preferences tables were dropped. All training notifications now flow through the unified notifications table with category='training'.

Gap 2: No Email Delivery — RESOLVED

Resolved in Phase 2 (2026-02-24). Email delivery implemented for 15 email-worthy notification types via Mailgun through the background service. Two dispatch paths: (1) Main service -> SQS EMAIL_SEND -> background handler for API-originated notifications, (2) Background handlers send directly via helper function for background-originated notifications.

Gap 3: SafePath SSE Gap — RESOLVED

Resolved in Phase 1 (2026-02-24). Training notifications now use the general NotificationService which integrates with the SSE push system.

Gap 4: Scheduler Not Running — OPEN

Problem: SafePathScheduler has methods for overdue checks, reminders, and cert expiry, but there's no cron job or background task that actually calls run_all_scheduled_tasks().

Impact: Overdue assignments are never flagged, reminders are never sent, cert expiry alerts are never generated.

Solution: Add a scheduled task in the background service. See Phase 3.

Gap 5: Auto-Assignment Notification Gap — RESOLVED

Resolved in Phase 1 (2026-02-24). Both handle_safepath_rule_evaluate() and handle_safepath_plan_retraining() now INSERT a training_assigned notification into the general notifications table after creating each assignment.


Phase 1: Unify & Fix Foundations — COMPLETED

Completed: 2026-02-24. All steps implemented and migration applied to dev database.

Goal: Merge SafePath notifications into the general system, fix auto-assignment notifications, remove separate SafePath notification tables.

What Was Done

StepFileActionDescription
1service/alembic/versions/...-dr0pn0t1f_drop_safepath_notification_tables.pyCREATEDrop safepath_notifications + safepath_notification_preferences tables
2service/app/db/models/safepath.pyEDITRemoved 2 notification model classes
3service/app/db/models/notification.pyEDITAdded 7 training types + category map
4service/app/services/safepath/notification_service.pyDELETERemoved SafePath-specific NotificationService
5service/app/services/notification_service.pyEDITAdded training templates + category filter
6service/app/db/repositories/notification_repository.pyEDITAdded category filter to queries
7service/app/api/v1/notifications.pyEDITAdded category query parameter
8service/app/services/safepath/scheduler.pyEDITUses general NotificationService + UnitOfWork
9service/app/api/v1/safepath/automation.pyEDITRefactored notification endpoints, removed preferences
10service/app/schemas/safepath/automation.pyEDITRemoved preference schemas
11bg-service/app/services/sqs_consumer/handlers.pyEDITAdded notification INSERTs after auto-assignment
12ui/src/pages/safepath/automation/index.tsxEDITUses general notification API
13ui/src/services/api/notification.api.tsEDITAdded category parameter
14ui/src/services/api/safepath.api.tsEDITRemoved 5 notification/preference functions
15ui/src/pages/safepath/automation/notifications.tsxDELETERemoved preferences page
15bui/src/App.tsxEDITRemoved notification settings route
16ui/src/types/safepath.tsEDITRemoved 4 notification interfaces

Total: 3 new/deleted files, 13 modified files


Phase 2: Email Delivery — COMPLETED

Completed: 2026-02-24. All 10 steps implemented. Migration applied to dev database. TypeScript clean.

Goal: Implement email notification delivery for critical notification types via Mailgun through the background service (async via SQS).

Architecture

Main Service (API)                    SQS Queue                Background Service
+--------------------+ +--------------------+
| NotificationSvc | | |
| .notify_user() |--creates in-app notification-->DB | |
| | | |
| if email-worthy: |--dispatch_email()-->[EMAIL_SEND]--> | handle_email_send |
| | | -> check opt-out |
| | | -> render HTML |
| | | -> Mailgun API |
+--------------------+ +--------------------+

Background handlers also send emails directly after creating notifications
(no re-queue through SQS).

What Was Done

StepFileActionDescription
1service/alembic/versions/...-em41ln0t1f_add_email_notifications_enabled.pyCREATEAdd email_notifications_enabled BOOLEAN DEFAULT TRUE to core_data_users
1bservice/app/db/models/user.pyEDITAdd email_notifications_enabled column to User model
2service/app/db/models/notification.pyEDITAdd EMAIL_WORTHY_TYPES constant (15 types)
3service/app/services/notification_service.pyEDITWire email dispatch into notify_user() and _create_for_recipients()
4bg-service/app/core/config.pyEDITAdd Mailgun config + FRONTEND_URL
5bg-service/app/services/email/__init__.pyCREATEPackage init, exports mailgun_client
5bbg-service/app/services/email/mailgun_client.pyCREATEAsync Mailgun HTTP client using httpx
6bg-service/app/services/email/templates.pyCREATESubject lines + HTML/text templates with urgency styling
7bg-service/app/services/sqs_consumer/handlers.pyEDITImplement handle_email_send() (replaced stub)
8bg-service/app/services/email/send_notification_email.pyCREATEHelper for background handlers to send emails directly
8bbg-service/app/services/sqs_consumer/handlers.pyEDITAdd email calls to 4 handlers: handle_notification_send, _dispatch_ai_notification, handle_safepath_rule_evaluate, handle_safepath_plan_retraining
9service/app/api/v1/notifications.pyEDITAdd GET/PUT /email-preference endpoints
10ui/src/services/api/notification.api.tsEDITAdd getEmailPreference() + updateEmailPreference()

Total: 5 new files, 7 modified files

Email-Worthy Types (15)

EMAIL_WORTHY_TYPES = {
# Workflow - major events
"plan_approved", "plan_rejected", "plan_published",
# Inventory - bulk operations
"chemical_bulk_imported", "sds_expiring",
# Compliance - safety critical
"quantity_threshold_exceeded", "plan_review_due", "plan_overdue",
# AI - user waiting
"ai_generation_completed", "ai_generation_failed",
# Training - action required / safety
"training_assigned", "training_reminder", "training_overdue",
"cert_expiring", "cert_expired",
}

Email Template Urgency Styling

UrgencyBanner ColorTypes
UrgentRed (#dc2626)training_overdue, cert_expired, plan_overdue, ai_generation_failed, quantity_threshold_exceeded
WarningAmber (#d97706)training_reminder, cert_expiring, sds_expiring, plan_review_due, plan_rejected
NormalBlue (#2563eb)All other email-worthy types

Phase 3: Scheduled Notifications

Goal: Wire up SafePath scheduler to actually run in the background service.

Status: OPEN — Next priority

3.1 New SQS Message Type

Add SAFEPATH_SCHEDULED_CHECK message type.

3.2 New Background Handler

Implement handle_safepath_scheduled_check() that runs overdue checks, reminders, and cert expiry checks for a company.

3.3 Cron Trigger

Option A (Recommended for production): CloudWatch Events / EventBridge rule that sends an SQS message every 6 hours.

Option B (For local dev): apscheduler inside the background service.


Phase 4: General Notification Preferences

Goal: Allow users to control per-category notification preferences with frequency options.

Status: OPEN — Detailed plan at Notification Preferences Plan

Key features:

  • Per-category preferences (7 categories) with three-tier resolution (user -> company -> system)
  • Three frequency options: immediate, daily_digest, off
  • Always-immediate override for 5 safety-critical types
  • Daily digest batching via pending_digest_emails staging table
  • Frontend settings page at /settings/notification-preferences

Phase 5: Webhook Delivery (Pro Tier)

Goal: Allow enterprise customers to receive notifications via webhook (Slack, Teams, custom).

Status: OPEN — Low priority

Key features:

  • notification_webhooks table with URL, secret, category filter
  • Webhook dispatcher via SQS WEBHOOK_SEND message type
  • Admin UI for webhook configuration
  • HMAC signature verification for security

Phase 6: Future Module Notifications

Goal: Add notification support for planned modules (AdminHQ, Inspections, Incidents).

Status: OPEN — Triggered when each module is implemented

Pattern for Adding New Module Notifications

  1. Define types in NotificationType class and NOTIFICATION_CATEGORY_MAP
  2. Add title/message templates in NotificationService
  3. If email-worthy, add to EMAIL_WORTHY_TYPES and create email subject template
  4. Wire triggers in the module's API/service layer
  5. Frontend category icon handled automatically if reusing existing categories

File Change Summary

Phase 1 (Unify & Fix) — COMPLETED 2026-02-24

3 new/deleted files, 13 modified files — See Phase 1 section above.

Phase 2 (Email Delivery) — COMPLETED 2026-02-24

5 new files, 7 modified files — See Phase 2 section above.

Phase 3 (Scheduler) — TODO

#FileActionDescription
1service/app/core/sqs_config.pyEDITAdd SAFEPATH_SCHEDULED_CHECK
2bg-service/app/services/sqs_consumer/handlers.pyEDITAdd handle_safepath_scheduled_check()
3bg-service/app/services/sqs_consumer/service.pyEDITRegister handler

Phase 4 (General Preferences) — TODO

See Notification Preferences Plan6 new files, 13 modified files

Phase 5 (Webhooks) — TODO

#FileActionDescription
1service/alembic/versions/..._notification_webhooks.pyCREATEnotification_webhooks table
2service/app/db/models/notification.pyEDITAdd NotificationWebhook model
3service/app/services/webhook_service.pyCREATEWebhook dispatch logic
4service/app/core/sqs_config.pyEDITAdd WEBHOOK_SEND
5bg-service/app/services/sqs_consumer/handlers.pyEDITAdd handle_webhook_send()
6service/app/api/v1/webhooks.pyCREATEWebhook CRUD API
7ui/src/pages/settings/webhooks.tsxCREATEWebhook management UI

Priority & Dependencies

Phase 1 (Unify)  <-- COMPLETED 2026-02-24
|
Phase 2 (Email) <-- COMPLETED 2026-02-24
|
Phase 3 (Scheduler) <-- NEXT (enables overdue/reminder/cert notifications)
|
Phase 4 (Preferences) <-- Per-category prefs with daily digest
|
Phase 5 (Webhooks) <-- Pro tier, lowest priority
|
Phase 6 (New Modules) <-- As modules are built