Document Expiration Notifications
1. What does this feature do? (High-Level Overview)
Section titled “1. What does this feature do? (High-Level Overview)”Document Expiration Notifications automatically alert employees about upcoming expiration dates for their licenses, certifications, and required documents. The system sends email reminders at strategic intervals (60 days, 45 days, and weekly for critical < 30 days) to ensure compliance and prevent lapses in required credentials. Each location can configure which document types trigger notifications.
2. Who is this for? (Roles & Permissions)
Section titled “2. Who is this for? (Roles & Permissions)”- Superadmin: Can configure document notification settings for any location.
- Admin: Can configure document notification settings for locations they manage.
- Owner: Can configure document notification settings for their own locations.
- Employees (Recipients): All active staff members with expiring licenses or certifications receive email notifications based on their location’s configuration.
Required Permission: Access to location settings for configuration
3. Business Rules & Enforcements
Section titled “3. Business Rules & Enforcements”- Rule 1: Notifications are configured per location - each location can choose which document types trigger alerts.
- Rule 2: Notifications are sent via email only (no SMS option for document expirations).
- Rule 3: Three notification windows are enforced:
- Exactly 60 days before expiration - First reminder
- Exactly 45 days before expiration - Second reminder
- Less than 30 days before expiration - Critical alerts (sent weekly maximum)
- Rule 4: Critical notifications (< 30 days) are sent only once per week per location to avoid notification fatigue.
- Rule 5: All document types default to enabled unless explicitly disabled in location settings.
- Rule 6: Only active employees with active access to the location receive notifications.
- Rule 7: Disabled document types in location settings will NOT trigger email alerts or appear on employee dashboards.
- Rule 8: The system tracks
last_critical_notification_sent_atper employee per location to enforce weekly limits for critical alerts. - Rule 9: Expired tokens and historical notifications remain in the database for audit purposes.
4. UI Placement
Section titled “4. UI Placement”Configuration Interface
Section titled “Configuration Interface”Location: Admin View > Locations > Edit Location
Route: /location/list/edit/:id
Section: “Document Notification Settings”
Position: Appears in the location edit form, only in edit mode when document fields exist
Condition: Only visible when isEditMode && documentNotificationFields.length > 0
Configuration Display
Section titled “Configuration Display”Table Layout:
- Column 1: Document name (e.g., “Driver License”, “BACB License”, “CPR Certification”)
- Column 2: Toggle checkbox to enable/disable notifications for that document
Description Text:
“Configure which document expiration notifications are sent to employees at this location. Disabled documents will not trigger email alerts or appear on the employee dashboard widget.”
Available Document Types
Section titled “Available Document Types”The following document types can be configured (sourced from ExpirationField enum):
| Field Name | Display Label |
|---|---|
driver_license_expiration | Driver License |
bacb_license_expiration | BACB License |
cpr_every_2_years | CPR Certification |
background_every_5_years | Background Check |
liability_insurance_annually | Liability Insurance |
local_police_rec_every_5_years | Local Police Record |
ceu_hippa_annually | CEU HIPAA |
ceu_security_awareness_annually | CEU Security Awareness |
ceu_zero_tolerance_every_3_years | CEU Zero Tolerance |
wc | WC |
medicaid_provider_expiration | Medicaid Provider |
national_sex_offender_registry | National Sex Offender Registry |
employment_auth_card_expiration | Employment Authorization Card |
auth_permanent_res_expiration | Auth Permanent Res Expiration |
5. How-To Guide (Step-by-Step)
Section titled “5. How-To Guide (Step-by-Step)”Scenario A: Configuring which documents trigger notifications
- Navigate to Admin View > Locations
- Find the location and click Edit
- Scroll to the Document Notification Settings section (only visible in edit mode)
- You’ll see a table listing all document types with toggle checkboxes
- Enable (check) the documents that should trigger expiration notifications
- Disable (uncheck) any documents you don’t want to monitor at this location
- Click Save to apply the changes
- Employees will receive notifications only for enabled document types at this location
Scenario B: Disabling all document notifications for a location
- Navigate to the location edit page
- In the Document Notification Settings table
- Uncheck all document type checkboxes
- Click Save
- No document expiration notifications will be sent for this location
Scenario C: Understanding the notification schedule
60-Day Reminder:
- Sent exactly 60 days before expiration
- Subject: “Reminder: Licenses Expiring in 60 Days”
- One-time notification
45-Day Reminder:
- Sent exactly 45 days before expiration
- Subject: “Important: Licenses Expiring in 45 Days”
- One-time notification
- More urgent tone
Critical Alert (< 30 days):
- Sent weekly for documents expiring in less than 30 days
- Subject: “URGENT: Your Licenses Are Expiring Soon”
- Maximum of one critical alert per week per location
- Tracked via
last_critical_notification_sent_atin the database
Scenario D: Understanding the email content
The notification email includes:
- Personalized greeting with employee name
- Grouped by location (if employee works in multiple locations)
- For each location:
- Location name
- List of expiring documents sorted by urgency:
- Document name (e.g., “BACB License”)
- Expiration date (formatted: “Jan 15, 2026”)
- Days until expiration
- Urgency level (Critical, 45-day, 60-day)
- Visual styling with urgency-based colors:
- Red for critical (< 30 days)
- Orange for 45-day notices
- Blue for 60-day notices
6. What happens if…? (Edge Cases / FAQ)
Section titled “6. What happens if…? (Edge Cases / FAQ)”-
Q: What happens if an employee has no email address on file?
- A: The employee is skipped during processing and no notification is sent. The command continues processing other employees.
-
Q: What happens if an employee works in multiple locations with different notification settings?
- A: The employee receives a single email containing expiring documents from all locations, but only for document types enabled in each respective location’s settings.
-
Q: How does the weekly limit work for critical notifications?
- A: The system tracks the last time a critical notification was sent per employee per location. If a critical notification was sent less than 7 days ago, the location is skipped for that employee in the current run.
-
Q: What happens if I disable a document type after notifications have already been sent?
- A: Future notifications for that document type will not be sent for this location. Past notifications cannot be recalled, but new checks will skip disabled document types.
-
Q: Are historical expiration dates included in notifications?
- A: No, the system only checks documents based on the reference date (typically today). Already-expired documents are not included unless they’re within the notification windows relative to the command’s run date.
-
Q: What happens if an expiration date is invalid or malformed?
- A: The system logs a warning for that specific field and skips it, continuing to process other valid fields for the employee. Check logs for details: “Invalid date format for user X, field Y.”
-
Q: Can I test document notifications before enabling them?
- A: Yes, use the
--dry-runflag to see what would be sent without actually sending emails:php artisan licenses:send-expiration-notifications --dry-run
- A: Yes, use the
-
Q: What happens if the email sending service is down?
- A: The system will attempt to send via the Resend batch API first. If that fails, it falls back to individual Laravel Mail sending. All failures are logged with error details, and the command reports how many emails failed.
-
Q: Are there any database fields that are always excluded from notifications?
- A: No, all fields defined in the
ExpirationFieldenum are included by default. However, each location can disable specific fields in their notification settings.
- A: No, all fields defined in the
-
Q: How long are expired notification records kept?
- A: Old notification records remain in the database indefinitely for audit purposes. A cleanup command can be configured if needed.
Technical Details
Section titled “Technical Details”Backend Command
Section titled “Backend Command”Command: php artisan licenses:send-expiration-notifications
Available Options:
--date=YYYY-MM-DD- Reference date for expiration checks (defaults to today)--dry-run- Preview what would be sent without actually sending--chunk-size=N- Number of users to process per chunk (default: 100)--batch-size=N- Number of emails per batch to Resend API (default: 50)--force-critical- Force sending critical notifications even if sent recently (bypasses 7-day limit)
Example Usage:
# Check today's expiring documents for all locationsphp artisan licenses:send-expiration-notifications
# Check specific datephp artisan licenses:send-expiration-notifications --date=2026-04-15
# Dry run to previewphp artisan licenses:send-expiration-notifications --dry-run
# Force critical notifications (bypass 7-day limit)php artisan licenses:send-expiration-notifications --force-critical
# Custom chunk and batch sizesphp artisan licenses:send-expiration-notifications --chunk-size=50 --batch-size=25How It Works
Section titled “How It Works”- Query Active Employees: The command queries all active users who have active access to at least one active location
- Process in Chunks: Users are processed in chunks (default: 100) to manage memory efficiently
- For Each Employee:
- Load all active locations with their
document_notification_settings - For each location:
- Loop through all expiration fields defined in
ExpirationFieldenum - Check if the location has notifications enabled for that field
- Parse the expiration date from the employee-location pivot
- Calculate days until expiration
- Determine urgency level (60-day, 45-day, or critical)
- Skip if outside notification windows
- Loop through all expiration fields defined in
- Load all active locations with their
- Group by Location: Expiring documents are grouped by location for each employee
- Check Critical Limits: For locations with critical documents, check if notification was sent in the last 7 days
- Buffer and Batch: Notifications are buffered and sent in batches to the Resend API for efficiency
- Update Tracking: After successful send, update
last_critical_notification_sent_atfor locations with critical documents - Logging: All processing steps, successes, and failures are logged
Data Model
Section titled “Data Model”Location Model Fields:
document_notification_settings: array|null// Structure:[ 'driver_license_expiration' => true, 'bacb_license_expiration' => true, 'cpr_every_2_years' => false, 'background_every_5_years' => true, ...]User-Location Pivot Fields:
// Expiration date fields (from ExpirationField enum)driver_license_expiration: date|nullbacb_license_expiration: date|nullcpr_every_2_years: date|null...
// Notification trackinglast_critical_notification_sent_at: datetime|nullHelper Methods:
// Check if specific field notifications are enabled$location->isDocumentNotificationEnabled('driver_license_expiration'): bool
// Get all settings with defaults (fills missing keys with true)$location->getDocumentNotificationSettingsWithDefaults(): arrayUrgency Calculation
Section titled “Urgency Calculation”The system determines urgency based on days until expiration:
if ($daysUntilExpiration === 60) { $urgency = '60_days';} elseif ($daysUntilExpiration === 45) { $urgency = '45_days';} elseif ($daysUntilExpiration < 30) { $urgency = 'critical';}Urgency Sorting: Documents in the email are sorted by urgency (critical first, then 45-day, then 60-day) to highlight the most urgent items.
Email Sending Strategy
Section titled “Email Sending Strategy”Batch API (Preferred):
- Uses Resend batch API when available and sending to 2+ employees
- More efficient for large batches
- Single HTTP request for multiple emails
- Falls back to individual sending if batch fails
Individual Sending (Fallback):
- Uses Laravel’s Mail facade
- Sends one email at a time
- Used when Resend API key is not configured or batch size is 1
- More reliable for small volumes
Email Template
Section titled “Email Template”Uses LicenseExpirationNotificationMail:
- Professional HTML email format
- Personalized with employee name
- Grouped by location
- Color-coded urgency indicators
- Formatted expiration dates
- Clear call to action to renew documents
Logs and Audit Trail
Section titled “Logs and Audit Trail”Success Logs:
License expiration notifications completed- users_processed- employees_notified- critical_skipped (due to recent notification)- total_licenses- emails_sent- emails_failedError Logs:
Failed to send license expiration notification- employee_id- email- error message
Invalid date format for user X- user_id- location_id (if applicable)- field name- field value- error detailsSecurity and Production Safeguards
Section titled “Security and Production Safeguards”- Environment Check: Automatically forces
--dry-runif not in production or ifAPP_URLis nothttps://backend.pmc-app.com - Data Validation: All dates are validated and parsed safely with exception handling
- Error Isolation: Errors for individual employees don’t stop the entire process
- Batch Fallback: Automatic fallback to individual sending if batch API fails
- Audit Trail: All notification sends are logged with timestamps and employee details
Performance Optimization
Section titled “Performance Optimization”- Chunked Processing: Users are processed in configurable chunks to manage memory
- Eager Loading: Locations and pivot data are eager-loaded to minimize database queries
- Batch API: Multiple emails sent in single API requests when possible
- Skip Early: Locations with recently-sent critical notifications are skipped early to save processing
Configuration Defaults
Section titled “Configuration Defaults”If document_notification_settings is null or a specific field is not present:
- Default Behavior: Notifications are enabled (opt-out model)
- Rationale: Ensures compliance by default - locations must explicitly disable unwanted notifications