Skip to content

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.

  • 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

  • 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_at per employee per location to enforce weekly limits for critical alerts.
  • Rule 9: Expired tokens and historical notifications remain in the database for audit purposes.

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

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.”

The following document types can be configured (sourced from ExpirationField enum):

Field NameDisplay Label
driver_license_expirationDriver License
bacb_license_expirationBACB License
cpr_every_2_yearsCPR Certification
background_every_5_yearsBackground Check
liability_insurance_annuallyLiability Insurance
local_police_rec_every_5_yearsLocal Police Record
ceu_hippa_annuallyCEU HIPAA
ceu_security_awareness_annuallyCEU Security Awareness
ceu_zero_tolerance_every_3_yearsCEU Zero Tolerance
wcWC
medicaid_provider_expirationMedicaid Provider
national_sex_offender_registryNational Sex Offender Registry
employment_auth_card_expirationEmployment Authorization Card
auth_permanent_res_expirationAuth Permanent Res Expiration

Scenario A: Configuring which documents trigger notifications

  1. Navigate to Admin View > Locations
  2. Find the location and click Edit
  3. Scroll to the Document Notification Settings section (only visible in edit mode)
  4. You’ll see a table listing all document types with toggle checkboxes
  5. Enable (check) the documents that should trigger expiration notifications
  6. Disable (uncheck) any documents you don’t want to monitor at this location
  7. Click Save to apply the changes
  8. Employees will receive notifications only for enabled document types at this location

Scenario B: Disabling all document notifications for a location

  1. Navigate to the location edit page
  2. In the Document Notification Settings table
  3. Uncheck all document type checkboxes
  4. Click Save
  5. 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_at in 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
  • 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-run flag to see what would be sent without actually sending emails: php artisan licenses:send-expiration-notifications --dry-run
  • 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 ExpirationField enum are included by default. However, each location can disable specific fields in their notification settings.
  • 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.

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:

Terminal window
# Check today's expiring documents for all locations
php artisan licenses:send-expiration-notifications
# Check specific date
php artisan licenses:send-expiration-notifications --date=2026-04-15
# Dry run to preview
php 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 sizes
php artisan licenses:send-expiration-notifications --chunk-size=50 --batch-size=25
  1. Query Active Employees: The command queries all active users who have active access to at least one active location
  2. Process in Chunks: Users are processed in chunks (default: 100) to manage memory efficiently
  3. For Each Employee:
    • Load all active locations with their document_notification_settings
    • For each location:
      • Loop through all expiration fields defined in ExpirationField enum
      • 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
  4. Group by Location: Expiring documents are grouped by location for each employee
  5. Check Critical Limits: For locations with critical documents, check if notification was sent in the last 7 days
  6. Buffer and Batch: Notifications are buffered and sent in batches to the Resend API for efficiency
  7. Update Tracking: After successful send, update last_critical_notification_sent_at for locations with critical documents
  8. Logging: All processing steps, successes, and failures are logged

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|null
bacb_license_expiration: date|null
cpr_every_2_years: date|null
...
// Notification tracking
last_critical_notification_sent_at: datetime|null

Helper 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(): array

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.

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

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

Success Logs:

License expiration notifications completed
- users_processed
- employees_notified
- critical_skipped (due to recent notification)
- total_licenses
- emails_sent
- emails_failed

Error 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 details
  • Environment Check: Automatically forces --dry-run if not in production or if APP_URL is not https://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
  • 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

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