Skip to main content

SF-9269 · Scenario · Easy

Restrict users from updating Account records more than once within 1 hour

✓ Verified by Vikas Singhal · Last reviewed 5/19/2026 · Updated for Spring '26

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 updateaddError() aborts the save before the data hits the database. After-update is too late (the row is already saved).
  • Trigger.oldMapTrigger.new already has the incoming LastModifiedDate (some platforms auto-populate during save). The reliable value is on oldMap.
  • 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:

  1. 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.
  2. Field history is field-agnostic: LastModifiedDate updates when any field changes. If you only care about specific fields, the basic answer over-restricts.
  3. No durable audit: If a manager needs to know “did this user actually attempt 3 updates in the last hour?”, LastModifiedDate shows 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 gotchaDatetime.now() is server time (GMT). Display the “try again at HH:MM” in the user’s locale by passing through Datetime.formatGmt() or letting the UI handle it.

Anti-patterns

  • After-update with rollbackDatabase.rollback(sp) works but the user gets a confusing error. before update + addError() is the clean answer.
  • Comparing LastModifiedDate from Trigger.new — during save, the runtime may have already updated it. Use Trigger.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.