This is a rate-limit pattern translated into Apex. The basic answer uses LastModifiedDate. The senior answer uses a per-user history object and acknowledges the subtle gap: LastModifiedDate is “any user” and “any field,” so it can’t distinguish “this user touched this Account 30 minutes ago” from “another user touched it.” Interviewers want both layers.
The 60-second answer
In a before-update trigger on Account, compare the in-flight record’s LastModifiedDate to Datetime.now(). If less than 60 minutes have passed AND LastModifiedById = UserInfo.getUserId(), block with addError('You can update this account again at HH:MM'). The senior version uses a custom Account_Update_Audit__c child object so the rate-limit is per-user-per-record, immune to other users updating the same record in between, and survives recursive same-transaction updates.
Basic answer — using LastModifiedDate
trigger AccountTrigger on Account (before update) {
Datetime cutoff = Datetime.now().addMinutes(-60);
Id me = UserInfo.getUserId();
for (Account a : Trigger.new) {
Account oldA = Trigger.oldMap.get(a.Id);
Boolean recentBySameUser =
oldA.LastModifiedById == me &&
oldA.LastModifiedDate > cutoff;
if (recentBySameUser) {
Long minsRemaining =
(oldA.LastModifiedDate.addMinutes(60).getTime()
- Datetime.now().getTime()) / 60000L;
a.addError(
'You can only update this Account once per hour. ' +
'Try again in ' + minsRemaining + ' minute(s).'
);
}
}
}
Key choices:
before update—addError()aborts the save before the data hits the database. After-update is too late (the row is already saved).Trigger.oldMap—Trigger.newalready has the incomingLastModifiedDate(some platforms auto-populate during save). The reliable value is onoldMap.- Per-user check — without
LastModifiedById == me, you’d block a manager from approving a record a rep just edited.
Why the basic answer breaks
Three failure modes the senior answer addresses:
- Apex automation: An after-update trigger or scheduled job that updates the Account counts as a “recent update.” The user gets blocked because the platform updated the record on their behalf 5 minutes ago. Fix: filter automation users out via a Custom Setting or a
User.Profile.Name = 'Integration'check. - Field history is field-agnostic:
LastModifiedDateupdates when any field changes. If you only care about specific fields, the basic answer over-restricts. - No durable audit: If a manager needs to know “did this user actually attempt 3 updates in the last hour?”,
LastModifiedDateshows only the most recent. Use a child audit object.
Senior answer — custom audit object
Custom object: Account_Update_Audit__c
Account__c (Lookup → Account, required)
Updated_By__c (Lookup → User, required, default = $User.Id)
Updated_At__c (Datetime, required, default = NOW())
public class AccountUpdateRateLimit {
/** Returns the records that violate the 1-update-per-user-per-hour rule. */
public static Set<Id> findViolations(List<Account> incoming) {
Id me = UserInfo.getUserId();
Datetime cutoff = Datetime.now().addMinutes(-60);
Set<Id> acctIds = new Map<Id, Account>(incoming).keySet();
Set<Id> violations = new Set<Id>();
for (Account_Update_Audit__c audit : [
SELECT Account__c, Updated_At__c
FROM Account_Update_Audit__c
WHERE Account__c IN :acctIds
AND Updated_By__c = :me
AND Updated_At__c > :cutoff
]) {
violations.add(audit.Account__c);
}
return violations;
}
}
trigger AccountTrigger on Account (before update, after update) {
if (Trigger.isBefore) {
Set<Id> violations = AccountUpdateRateLimit.findViolations(Trigger.new);
for (Account a : Trigger.new) {
if (violations.contains(a.Id)) {
a.addError('You can only update this Account once per hour.');
}
}
}
if (Trigger.isAfter) {
// Write audit row for the successful update
List<Account_Update_Audit__c> rows = new List<Account_Update_Audit__c>();
for (Account a : Trigger.new) {
rows.add(new Account_Update_Audit__c(
Account__c = a.Id,
Updated_By__c = UserInfo.getUserId(),
Updated_At__c = Datetime.now()
));
}
insert rows;
}
}
The custom object makes the constraint provable (every blocked attempt has a row), per-user by construction, and filterable (“ignore system users” is just a WHERE Updated_By__c.Profile.Name != 'Integration').
Edge cases the interview wants you to mention
- Bulk update of 200 Accounts — one user, 200 records, one transaction. Should all 200 succeed or all fail? Answer depends on business — usually allow the bulk update because it’s a single user action.
- Sandbox seed data — turn the rule off (Custom Setting bypass) for the data migration user.
- Approval Process auto-updates — when an approval approves, Salesforce updates the record as the approver. Don’t block this.
- Scheduled batch jobs — same as integration user; filter by Profile or User ID.
- Time-zone gotcha —
Datetime.now()is server time (GMT). Display the “try again at HH:MM” in the user’s locale by passing throughDatetime.formatGmt()or letting the UI handle it.
Anti-patterns
- After-update with rollback —
Database.rollback(sp)works but the user gets a confusing error.before update+addError()is the clean answer. - Comparing
LastModifiedDatefromTrigger.new— during save, the runtime may have already updated it. UseTrigger.oldMap. - Storing the constraint in a custom setting — fine for the value (60 minutes), wrong as the enforcement mechanism. Use a trigger.
- Blocking all updates regardless of user — managers, system processes, and integrations break.
How to answer in 30 seconds
“Before-update trigger on Account. Read Trigger.oldMap’s LastModifiedDate and LastModifiedById. If the modifier was the current user AND less than an hour ago, addError(). For a production-grade version, keep a custom Account_Update_Audit__c child object so the rate-limit is per-user-per-record and auditable.”
How to answer in 2 minutes
Show the basic LastModifiedDate version, then explain its three limitations (any field counts, no per-user accuracy when other users touch the record, no audit trail). Show the custom audit-object version. Mention the edge cases: bypass for integration users, approval-process updates, bulk updates by one user. End with the trade-off: a custom child object adds storage and a SOQL per save — fine for a low-volume object like Account, wasteful for high-throughput objects.
Likely follow-up questions
- What if multiple users need different limits?
- How would you bypass this for integration users?
- What happens if a workflow rule or process builder updates the Account?
- Could you do this in a Validation Rule instead?
- How would you handle this in a Flow if there were no Apex?
Verified against: Apex Triggers — addError, UserInfo class, Datetime class. Last reviewed 2026-05-19.