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:
- GlobalSettings Filament Page - Administrative interface for template management
- Notification Classes - Laravel notification classes for each event type
- Merging Service - Handles dynamic content replacement and table generation
- Background Job - Batches and sends notifications asynchronously
- 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 tablereviewReadyVars(): Reviewer and submission detailssubmissionRejectedVars(): User, indicator, and rejection informationsubmissionApprovedVars(): 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
ShouldQueuefor background processing
Notification Classes
Each notification event has a dedicated class extending Laravel's Notification class:
NewIndicatorTasksReadyNotificationIndicatorVerificationAwaitingNotificationIndicatorSubmissionRejectedNotificationIndicatorSubmissionApprovedNotification
Template-Driven Content
All notification classes follow the same pattern:
- Template Retrieval: Retrieve templates from
GlobalSettingmodel - 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_SETTINGSpermission 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
SendNewIndicatorTasksNotificationJobwith 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
IndicatorVerificationsResourceaction - 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:
- Event Listener captures the indicator creation
- Job Dispatch schedules
SendNewIndicatorTasksNotificationJobwith 30-minute delay - Batching Logic collects all new tasks created for the same entrepreneur within the 1-hour window before task creation
- 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:
- Access the Envoy dashboard on the landlord tenant
- Navigate to Settings > Global Settings
- Select the Indicator Notifications tab
- Modify email subjects, content, and in-app messages
- Use merge variables from the provided reference panel
- Test changes using the Send test email buttons
Adding New Merge Variables
To add new variables:
- Add enum case to
NotificationMergeVariables - Update appropriate variable group methods
- Implement variable resolution in merging service
- 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