Trigger Name: UserChangeEventTrigger¶
Last Updated: 2025-10-22 Source Code: https://github.com/AANP-IT/I2C.Salesforce.Metadata/blob/STAGING/force-app/main/default/triggers/UserChangeEventTrigger.trigger
API Name: UserChangeEventTrigger Object: UserChangeEvent (Change Data Capture Event) Pattern: Handler Pattern with Static Method
Business Purpose¶
This trigger uses Change Data Capture to monitor User email changes and automatically synchronize email updates to the Username field and related Person Account email addresses. Since User triggers have limitations (mixed DML), CDC provides async processing to update both User.Username and Account.PersonEmail fields when User.Email changes.
Trigger Events¶
This trigger fires on the following events: - ☐ Before Insert - ☐ Before Update - ☐ Before Delete - ☑️ After Insert (CDC events only support after insert) - ☐ After Update - ☐ After Delete - ☐ After Undelete
Trigger Handler¶
Handler Class: UserChangeEventTriggerHandler.cls Pattern: Static Handler Method Entry Point: Static method call from trigger
trigger UserChangeEventTrigger on UserChangeEvent (after insert) {
UserChangeEventTriggerHandler.handleAfterInsert(Trigger.New);
}
Process Flow by Event¶
After Insert¶
Purpose: Synchronize email changes from User to Username and Person Account
Business Logic: 1. Extract Email values from UserChangeEvent records 2. Get User IDs from change event headers (multiple IDs possible per event) 3. Create User update records with new Username (set to Email value) 4. Query User records to get AccountId values 5. Filter for portal users only (non-portal users removed from update list) 6. Update User.Username records (with allOrNone=false for error handling) 7. Call UserTriggerHandler.updateAccountEmailsAsync() to update Person Accounts
Methods Called:
- UserChangeEventTriggerHandler.handleAfterInsert(List<UserChangeEvent> uces)
- UserTriggerHandler.updateAccountEmailsAsync(Map<Id, String> accountsToUpdate, Boolean byPassUpdate)
Field Updates:
- User.Username: Set to new Email value (for portal users)
- Account.PersonEmail: Updated via future method
Related Records Updated: - User records (Username field) - Account records (PersonEmail field, via future method)
Key Business Rules¶
Validation Rules¶
- Only processes UserChangeEvent records with Email field changes
- Only updates Username for portal users (User.AccountId != null)
- Username set equal to Email value
- Account.PersonEmail synchronized asynchronously
Field Updates¶
User.Username: Set to User.EmailAccount.PersonEmail: Set to User.Email (via future method)
Related Record Operations¶
- User records updated synchronously
- Account records updated asynchronously via @future method
- Mixed DML handled via CDC async processing
Bulkification & Governor Limits¶
Bulkified: Yes (CDC) Max Records Handled: CDC event batching SOQL Queries: 1 (query Users for AccountId) DML Operations: 1 (Database.update Users with allOrNone=false)
Bulkification Strategy¶
- CDC batches multiple User changes into single event
- Single change event can contain multiple User IDs
- Single SOQL query for all User records
- Single DML operation with Database.update
- Future method handles Account updates separately
Governor Limit Considerations¶
- CDC Limits: Subject to org CDC allocations
- SOQL: 1 query per event batch
- DML: 1 DML statement (with allOrNone=false)
- Future Method: 1 future method call per execution
Recursion Prevention¶
Strategy: CDC events cannot trigger themselves + Future method isolation
Implementation: - CDC events fire after committed transactions - Future method runs in separate transaction - Natural recursion protection via CDC and async processing
Scenarios: - No recursion risk with CDC events - Username update doesn't create new CDC events in same transaction - Future method isolation prevents User->Account->User loops
Execution Order & Dependencies¶
Order of Execution Impact¶
- CDC events fire after source transaction commits
- User.Username updated synchronously in CDC transaction
- Account.PersonEmail updated asynchronously in future method
Dependent Triggers¶
- UserTrigger: Direct trigger on User object (may interact)
- AccountTrigger: Could be impacted by Person Account updates
Dependent Processes¶
- UserTriggerHandler.updateAccountEmailsAsync: Future method for Account updates
- Person Account management
- Email synchronization across objects
Error Handling¶
Strategy: Database.update with allOrNone=false + error logging
User Experience: - Success: Email change captured, Username and Account updated - Event Delivery Failure: Salesforce automatically retries - User Update Error: Logged to debug logs, other records still processed - Account Update Error: Handled in future method
Logging: - Error logging in handler using System.debug - Database.SaveResult errors logged for each failed User update - CDC built-in monitoring
Rollback Behavior: - Partial success allowed (allOrNone=false) - Failed User updates logged but don't stop processing - Future method failures isolated
Dependencies¶
Apex Classes¶
UserChangeEventTriggerHandler: Handler with static methodUserTriggerHandler: Contains updateAccountEmailsAsync future method
Salesforce Objects¶
UserChangeEvent: CDC event objectUser: Standard object (Username field updated)Account: Standard object (PersonEmail updated)
Custom Settings/Metadata¶
- CDC entity settings (Salesforce managed)
External Systems¶
- None directly
Testing¶
Test Class: UserChangeEventTriggerHandlerTest.cls (likely) Coverage: Unknown
Test Scenarios: - Single User email change - Bulk User email changes - Portal vs non-portal users - Users with and without AccountId - CDC event delivery testing - Future method execution - Error handling with invalid email formats
Performance Considerations¶
Average Execution Time: Fast (CDC routing) Max Records Processed: CDC batch sizes Async Processing: Yes - CDC + Future method
Optimization Opportunities: - Already optimized with CDC and future method - Monitor future method queue - Consider Queueable instead of future for better monitoring
Changes & History¶
- Author: Original implementation (team maintained)
- Pattern: CDC with future method for mixed DML handling
- Rationale: User object has mixed DML limitations, CDC + future method solves this
Pre-Go-Live Concerns¶
CRITICAL - Fix Before Go-Live¶
- CDC Configuration: Verify User CDC properly enabled with Email field
- Username Validation: No validation that Email is valid Username format
- Duplicate Username Risk: Could create duplicate Username if Email not unique
- Mixed DML: Verify future method properly handles mixed DML scenarios
HIGH - Address Soon After Go-Live¶
- Error Handling: System.debug errors not persisted, need custom object logging
- Future Method Limits: Only 50 future methods per transaction
- Account Update Bypass: byPassUpdate parameter always passed as false, may need true scenario
- Non-Portal User Handling: Users removed from update silently, should log
MEDIUM - Future Enhancement¶
- Replace Future with Queueable: Better monitoring and chaining capability
- Event Replay: Document CDC replay procedures
- Trigger Settings: Custom metadata to enable/disable
- Username Validation: Add validation before Username update
LOW - Monitor¶
- CDC Limits: Monitor org-wide CDC allocations
- Future Method Queue: Track future method execution times
- Username Conflicts: Monitor for duplicate Username errors
Maintenance Notes¶
Complexity: Medium-High Recommended Review Schedule: Quarterly
Key Maintainer Notes: - Uses CDC because User triggers have mixed DML limitations - Username always set equal to Email (no transformation) - Only portal users (with AccountId) get Username updates - Account.PersonEmail updated via future method (mixed DML workaround) - Database.update with allOrNone=false allows partial success - Errors logged but not persisted (System.debug only) - Always test with portal and non-portal users - CDC events can batch multiple User changes
Deactivation Instructions: Add custom metadata check:
trigger UserChangeEventTrigger on UserChangeEvent (after insert) {
if (TriggerSettings__mdt.getInstance('UserChangeEvent')?.Disabled__c == true) {
return;
}
UserChangeEventTriggerHandler.handleAfterInsert(Trigger.New);
}
CDC Considerations: - User CDC must be enabled in Setup - Select Email field for CDC tracking - CDC events have 3-day retention - Test thoroughly with portal users in sandbox - Monitor CDC allocations (varies by edition)