Skip to content

Indicator Notifications System

Overview

The Indicator Notifications System provides a comprehensive, customizable notification framework for indicator-related events in the FlowCode application. This system allows administrators to manage email and in-app notification templates through a centralized interface in the Envoy dashboard (landlord only), while providing dynamic content merging and intelligent batching of new indicator notifications.

Key Features

  • Centralized Template Management: Envoy dashboard interface for managing notification templates (landlord tenant only)
  • Dynamic Content Merging: Template variables that are replaced with contextual data
  • Multi-channel Notifications: Support for both email and in-app notifications
  • Intelligent Batching: Groups new indicator tasks created within a 30-minute window into single notifications
  • Test Functionality: Built-in test notifications for each notification
  • Conditional Display: Smart table columns based on user context

Architecture Components

The system consists of several interconnected components:

  1. GlobalSettings Filament Page - Administrative interface for template management
  2. Notification Classes - Laravel notification classes for each event type
  3. Merging Service - Handles dynamic content replacement and table generation
  4. Background Job - Batches and sends notifications asynchronously
  5. Global Settings Model - Stores notification templates and configuration

Core Components

Global Settings Management

The GlobalSettings Filament page (app/Filament/Pages/GlobalSettings.php) provides the administrative interface for managing notification templates. This page is only available in the Envoy dashboard on the landlord tenant and requires the MANAGE_GLOBAL_SETTINGS permission. This page features:

Template Configuration Sections

  • New Indicator Tasks Ready: Notification sent when indicators are assigned
  • Submission Ready for Review: Notification sent to reviewers when submissions are ready
  • Submission Rejected: Notification sent when submissions are rejected
  • Submission Approved: Notification sent when submissions are fully approved

Template Fields

Each notification type includes:

  • Email Subject: Customizable subject line with merge variable support
  • Email Content: Rich text email body content
  • In-App Content: Optional in-app notification content

Testing Functionality

  • Send Test Email buttons for each notification type
  • Unsaved Changes Detection: Prompts users to save changes before testing
  • Mock Data Generation: Creates realistic test data using factories (does not save them to the database)

Notification Merging Service

The IndicatorNotificationMergingService (app/Services/Indicators/IndicatorNotificationMergingService.php) handles:

Dynamic Content Replacement

Replaces template variables (format: *|variable_name|*) with contextual data:

  • User information (names, roles)
  • Indicator details (title, description, dates)
  • Submission data (values, comments, status)
  • Programme and organization information

Intelligent Table Generation

The buildIndicatorsTable() method creates HTML tables for new indicator notifications with:

  • Conditional Columns: Shows entrepreneur/organization columns only when relevant
  • Responsive Design: Styled tables that work across email clients
  • Data Safety: Proper escaping of user-generated content
  • Contextual Information: Due dates, programme months, and descriptions

Merge Variable Types

Different notification types use specific variable sets defined in NotificationMergeVariables enum:

  • newIndicatorVars(): User info and indicators table
  • reviewReadyVars(): Reviewer and submission details
  • submissionRejectedVars(): User, indicator, and rejection information
  • submissionApprovedVars(): User and indicator information

Background Job Processing

The SendNewIndicatorTasksNotificationJob (app/Jobs/Indicators/SendNewIndicatorTasksNotificationJob.php) handles only new indicator task notifications and provides:

Intelligent Batching for New Indicator Tasks

  • Unique Job IDs: Prevents duplicate notifications using entrepreneur ID and time window (hourly grouping)
  • 30-Minute Delay: Jobs are delayed by 30 minutes to allow batching of multiple new tasks
  • Collection Window: Collects all new indicator tasks created for the same entrepreneur within a 1-hour window before task creation
  • Hourly Uniqueness: Job uniqueness is based on entrepreneur ID and hour of creation to prevent duplicate batched notifications

Performance Optimization

  • Selective Data Loading: Maps only necessary task data to reduce memory usage
  • Eager Loading: Loads relationships efficiently to prevent N+1 queries
  • Logging: Comprehensive logging for debugging and monitoring

Error Handling

  • Retry Logic: 3 attempts with exponential backoff (5s, 30s, 60s)
  • Graceful Failures: Handles missing users and empty task sets
  • Queue Integration: Implements ShouldQueue for background processing

Notification Classes

Each notification event has a dedicated class extending Laravel's Notification class:

  • NewIndicatorTasksReadyNotification
  • IndicatorVerificationAwaitingNotification
  • IndicatorSubmissionRejectedNotification
  • IndicatorSubmissionApprovedNotification

Template-Driven Content

All notification classes follow the same pattern:

  • Template Retrieval: Retrieve templates from GlobalSetting model
  • Merge Variable Application: Apply merge variables through the merging service
  • Multi-channel Support: Email and database notifications
  • Conditional Channels: Only sends via channels with configured content
  • Action URLs: Provide appropriate action URLs based on user context
  • Smart Routing: Different URLs for entrepreneurs vs. administrators

Configuration and Setup

Global Settings Storage

Templates are stored in the global_settings table with:

  • Structured Data: JSON arrays containing email_subject, email_content, and inapp_content
  • Slugified Keys: Consistent naming for easy retrieval
  • Active Status: Enable/disable notifications without losing templates

Merge Variable System

The NotificationMergeVariables enum provides:

  • Type Safety: Strongly typed variable definitions
  • Descriptions: Human-readable descriptions for the admin interface
  • Grouped Variables: Different variable sets for different notification types
  • Consistent Formatting: Standardized *|variable_name|* format

Permission Integration

Access to the Global Settings page is controlled through:

  • Landlord Tenant Only: Available exclusively in the Envoy dashboard on the landlord tenant
  • Permission Required: UserPermissions::MANAGE_GLOBAL_SETTINGS permission check
  • Role-based Access: Integration with the application's role-based access control system
  • Secure Modifications: Template modification restrictions prevent unauthorized changes

Notification Dispatch Points

This section documents where each notification type is dispatched from in the application, providing developers with clear understanding of the trigger points and event flow.

New Indicator Tasks Ready Notification

Dispatched from: IndicatorTaskReadyForSubmissionListener (app/Listeners/Indicator/IndicatorTaskReadyForSubmissionListener.php)

Trigger Event: IndicatorTaskReadyForSubmission

Dispatch Logic:

  • Validates that the task is a user task with a responsible user
  • Creates a 1-hour collection window (1 hour before the task creation time)
  • Dispatches SendNewIndicatorTasksNotificationJob with a 30-minute delay
  • Job collects all new indicator tasks created for the same entrepreneur within the collection window
  • Sends a single batched notification with all collected tasks

Key Details:

  • Delay: 30 minutes (->delay(now()->addMinutes(30)))
  • Collection Window: 1 hour before task creation ($task->created_at->copy()->subHour())
  • Batching: Multiple tasks for the same entrepreneur are grouped into one notification

Indicator Verification Awaiting Notification

Dispatched from: IndicatorSubmissionAwaitingVerificationListener (app/Listeners/Indicator/IndicatorSubmissionAwaitingVerificationListener.php)

Trigger Event: IndicatorSubmissionAwaitingVerification

Dispatch Logic:

  • Triggered when a submission requires verification
  • Event is fired from IndicatorVerificationService::initiateVerificationForLevel()
  • Directly notifies the assigned verifier
  • Includes submission details, verifier level, and verifier information

Key Details:

  • Immediate Dispatch: No delay, sent immediately
  • Target: Specific verifier assigned to review the submission
  • Context: Includes verifier level (1 or 2) and submission data

Indicator Submission Rejected Notification

Dispatched from: IndicatorSubmissionRejectedListener (app/Listeners/Indicator/IndicatorSubmissionRejectedListener.php)

Trigger Event: IndicatorSubmissionRejected

Dispatch Logic:

  • Triggered when a reviewer rejects a submission in the Filament interface
  • Event is fired from IndicatorVerificationsResource action
  • Notifies the original submitter of the rejection
  • Includes rejection reason and reviewer information

Key Details:

  • Immediate Dispatch: No delay, sent immediately upon rejection
  • Target: Original submitter of the indicator
  • Context: Includes reviewer details and rejection reason

Indicator Submission Approved Notification

Dispatched from: IndicatorTaskCompletedListener (app/Listeners/Indicator/IndicatorTaskCompletedListener.php)

Trigger Event: IndicatorTaskCompleted

Dispatch Logic:

  • Triggered only when all required verifications are complete
  • Event is fired after the verification service completes the task and submission
  • Notifies the original submitter of the final approval
  • Only sent when the task is fully completed (not for intermediate approvals)

Key Details:

  • Immediate Dispatch: No delay, sent immediately upon final completion
  • Target: Original submitter of the indicator
  • Context: Final approval notification (not sent for intermediate verification levels)

Important Note: The IndicatorSubmissionApprovedListener does not send notifications, as noted in its comments: "No notification is sent here, as it may only be the first level of verification (so approval is not final)". Notifications are only sent when the task is fully completed through the IndicatorTaskCompletedListener.

Usage Examples

Triggering New Indicator Notifications

When new indicator tasks are created, the system:

  1. Event Listener captures the indicator creation
  2. Job Dispatch schedules SendNewIndicatorTasksNotificationJob with 30-minute delay
  3. Batching Logic collects all new tasks created for the same entrepreneur within the 1-hour window before task creation
  4. Notification Sending creates and sends a single notification with all batched tasks and merged content

Customizing Templates

Administrators with the MANAGE_GLOBAL_SETTINGS permission can:

  1. Access the Envoy dashboard on the landlord tenant
  2. Navigate to Settings > Global Settings
  3. Select the Indicator Notifications tab
  4. Modify email subjects, content, and in-app messages
  5. Use merge variables from the provided reference panel
  6. Test changes using the Send test email buttons

Adding New Merge Variables

To add new variables:

  1. Add enum case to NotificationMergeVariables
  2. Update appropriate variable group methods
  3. Implement variable resolution in merging service
  4. Update template documentation

Maintenance and Troubleshooting

Common Issues

  • Missing Templates: Check global_settings table for required entries
  • Failed Jobs: Review queue worker logs and retry failed jobs
  • Email Delivery: Verify SMTP configuration and email queue processing

Monitoring Points

  • Job Success Rates: Monitor notification job completion
  • Template Usage: Track which templates are being used
  • User Engagement: Monitor email open rates and in-app notification interactions