Trigger Name: UserTrigger¶
Last Updated: 2025-10-22 Source Code: https://github.com/AANP-IT/I2C.Salesforce.Metadata/blob/STAGING/force-app/main/default/triggers/UserTrigger.trigger
API Name: UserTrigger Object: User (Standard Salesforce Object) Pattern: Handler Pattern with Switch Statement
Business Purpose¶
This trigger monitors User email changes and synchronizes them to Person Account email addresses. When a User's email is updated, it automatically updates the associated Person Account's PersonEmail field via future method to avoid mixed DML errors, ensuring email consistency across User and Account objects.
Trigger Events¶
This trigger fires on the following events: - ☐ Before Insert - ☐ Before Update - ☐ Before Delete - ☐ After Insert - ☑️ After Update - ☐ After Delete - ☐ After Undelete
Trigger Handler¶
Handler Class: UserTriggerHandler.cls Pattern: Handler with Static Methods and Switch Statement Entry Point: Switch statement calls static handler method
trigger UserTrigger on User (after update) {
switch on Trigger.operationType {
when AFTER_UPDATE {
UserTriggerHandler.handleAfterUpdate(Trigger.oldMap, Trigger.newMap);
}
}
}
Process Flow by Event¶
After Update¶
Purpose: Synchronize User email changes to Person Account email
Conditional Logic: - Fires When: User.Email field value changes - Example: If Email changes from 'old@email.com' to 'new@email.com'
Business Logic: 1. Compare old and new User records 2. Detect Email field changes 3. Collect AccountId and new Email for users with email changes 4. Call updateAccountEmailsAsync future method with Account updates 5. Future method updates Account.PersonEmail asynchronously
Methods Called:
- UserTriggerHandler.handleAfterUpdate(Map<Id, User> oldUsers, Map<Id, User> newUsers)
- UserTriggerHandler.updateAccountEmailsAsync(Map<Id, String> accountsToUpdate, Boolean byPassUpdate) @future
Field Updates:
- Account.PersonEmail: Updated to match User.Email (via future method)
Related Records Updated: - Account records (PersonEmail field, asynchronous)
Key Business Rules¶
Validation Rules¶
- Only processes User records with Email field changes
- Only updates Accounts for Users with AccountId populated
- Future method allows bypass via byPassUpdate parameter (default: true in trigger)
Field Updates¶
User.Username: Commented out (not currently updated)Account.PersonEmail: Updated via future method
Related Record Operations¶
- Person Account email synchronized
- Mixed DML handled via future method
Bulkification & Governor Limits¶
Bulkified: Partial Max Records Handled: Limited by future method limits SOQL Queries: 0 in trigger DML Operations: 0 in trigger (DML in future method)
Bulkification Strategy¶
- Trigger collects all email changes in bulk
- Single future method call with all Account updates
- Future method performs bulk DML on Accounts
Governor Limit Considerations¶
- Future Method Limit: 50 future method calls per transaction
- DML: All DML in future method (separate limits)
- Mixed DML: Future method avoids mixed DML errors
Recursion Prevention¶
Strategy: Future method runs in separate transaction
Implementation: - Future method isolation prevents recursion - AccountTrigger updates don't re-trigger UserTrigger in same transaction - No explicit recursion flags
Scenarios: - User update -> Account update (via future) -> separate transaction - AccountTrigger can safely update Users without recursion risk
Execution Order & Dependencies¶
Order of Execution Impact¶
- After Update: Runs after validation rules
- Future method executes asynchronously after transaction commits
Dependent Triggers¶
- AccountTrigger: May update Users, creating potential circular dependency
- UserChangeEventTrigger: Handles same sync via CDC
- Risk: Two triggers (UserTrigger + UserChangeEventTrigger) doing similar work
Dependent Processes¶
- updateAccountEmailsAsync: Future method for Account updates
- Person Account management
- Email synchronization
Error Handling¶
Strategy: Future method with byPassUpdate parameter
User Experience: - Success: User saves, Account updated asynchronously - Validation Error: Standard Salesforce errors - Future Method Error: Account update fails silently (no user notification)
Logging: - No explicit logging in trigger or handler - Future method errors not captured
Rollback Behavior: - User update commits regardless of future method outcome - Future method failures don't rollback User changes
Dependencies¶
Apex Classes¶
UserTriggerHandler: Handler with static methods and future method
Salesforce Objects¶
User: Standard object (primary)Account: Standard object (PersonEmail updated)
Custom Settings/Metadata¶
- None visible
External Systems¶
- None
Testing¶
Test Class: UserTriggerHandlerTest.cls (likely) Coverage: Unknown
Test Scenarios: - Single User email update - Bulk User email updates (200 records) - User with AccountId vs without - Email change vs other field changes - Future method execution - byPassUpdate scenarios
Performance Considerations¶
Average Execution Time: Fast (triggers future method) Max Records Processed: Limited by future method limits (50 per transaction) Async Processing: Yes - Future method for Account updates
Optimization Opportunities: - Replace future with Queueable for better monitoring - Consider Platform Events for complete decoupling - Add logging for future method outcomes - Optimize byPassUpdate parameter usage
Changes & History¶
- Author: Original implementation (team maintained)
- Pattern: Switch statement with future method for mixed DML
- Note: Username update logic commented out (lines 26-28)
Pre-Go-Live Concerns¶
CRITICAL - Fix Before Go-Live¶
- Duplicate Logic: UserChangeEventTrigger does same thing via CDC. Which one should be primary?
- Future Method Limit: Only 50 future methods per transaction. Bulk user updates could fail
- Username Update Commented: Lines 26-28 commented out but left in code
- No Error Handling: Future method failures not handled or logged
HIGH - Address Soon After Go-Live¶
- byPassUpdate Parameter: Always passed as true in trigger, but checked as false in future method
- No Logging: No audit trail of email synchronization
- Silent Failures: Account update errors not surfaced to users
- Mixed DML Documentation: Needs documentation about mixed DML handling strategy
MEDIUM - Future Enhancement¶
- Replace Future with Queueable: Better monitoring and error handling
- Consolidate with CDC Trigger: Choose one approach (trigger or CDC)
- Add Trigger Settings: Custom metadata to enable/disable
- Error Notifications: Alert users when Account update fails
LOW - Monitor¶
- Future Method Queue: Monitor future method execution times
- Account Update Success Rate: Track failures
- Performance: Monitor with bulk user updates
Maintenance Notes¶
Complexity: Medium Recommended Review Schedule: Quarterly
Key Maintainer Notes: - IMPORTANT: UserChangeEventTrigger does similar work via CDC. Potential duplication! - Username update logic commented out (was it intentional?) - byPassUpdate parameter logic seems inverted (passed as true, checked as false) - Future method isolates Account updates to avoid mixed DML - Always test with bulk user updates (200 records) - Future method has 50 call limit per transaction - AccountTrigger may create circular dependencies - test carefully
Deactivation Instructions: Add custom metadata check in trigger:
trigger UserTrigger on User (after update) {
if (TriggerSettings__mdt.getInstance('UserTrigger')?.Disabled__c == true) {
return;
}
switch on Trigger.operationType {
when AFTER_UPDATE {
UserTriggerHandler.handleAfterUpdate(Trigger.oldMap, Trigger.newMap);
}
}
}
Critical Questions for Team: 1. Should UserTrigger or UserChangeEventTrigger be the primary sync mechanism? 2. Was Username update intentionally commented out? 3. Is byPassUpdate parameter logic correct (passed true, used as false)? 4. How to handle duplicate triggers doing same work?