Tag: Apex Sharing

  • Designing a Salesforce solution around one metric leadership will actually track

    Ask most delivery teams what a Salesforce enhancement is meant to achieve and you’ll get a feature description back. “We’re adding a custom object for renewals.” “We’re building an approval process for discounts over 15%.” Ask what number on a leadership dashboard is supposed to move because of it, and you’ll usually get a pause.

    That pause is the problem. A solution built without a target metric gets evaluated on whether it shipped, not whether it worked. Six months later nobody can say if the renewals object actually reduced churn, or if the approval process actually cut discount leakage, because nobody wired the build to a number in the first place.

    Why “it works” isn’t the same as “it moved something”

    I’ve sat in enough steering committees to know the difference between a project that’s technically complete and one that’s actually earning its budget. The first gets a green status and a demo. The second gets renewed funding next year because someone can point at a chart and say “that’s us.”

    Most orgs I’ve reviewed have dozens of automations, reports and custom fields that were built for a stakeholder request, went live, and then quietly stopped being anyone’s responsibility. Nobody’s watching whether they’re doing anything. The gap isn’t in testing. It sits earlier, at the requirements stage, long before a single flow gets built.

    Pick the metric before you open the object manager

    Before any real design work starts, force one question: what single number does this need to move, and who already looks at that number every week? Not a KPI you’ll invent for the project. One that already exists on someone’s dashboard, in someone’s board pack, or in someone’s head when they walk into a Monday meeting.

    For a contact-centre client I worked with, that number was average handle time on a specific case type. Not “improve agent efficiency.” Not “modernise the case workflow.” Handle time, on that case type, measured weekly, already tracked by the operations lead before we touched anything. Every design decision after that got tested against one question: does this reduce handle time on that case type, or doesn’t it?

    That constraint kills a lot of scope creep on its own. A nice-to-have field that doesn’t touch the metric gets deprioritised without an argument. A workaround that adds three clicks but saves the agent from a phone call gets fast-tracked, because someone can show the maths.

    What changes in the technical design

    Once you know the metric, it should show up in three places in the build, not just the final report.

    • The data model needs a field or relationship that captures the event driving the metric, at the point it happens, not reconstructed later from case comments or a separate spreadsheet.
    • The automation needs to fire close enough to that event that the data is accurate. A nightly batch job that recalculates handle time after the fact is a different design than a trigger or flow that stamps timestamps as the case moves through statuses.
    • The reporting layer needs to expose the metric in a way the person who owns it can actually check without asking IT for a custom report every Friday.

    Skip any of those three and you end up with a metric that technically exists but nobody trusts, because getting to it takes fifteen minutes and a pivot table.

    A composite example: the discount approval that didn’t cut leakage

    A typical enterprise org I’ve seen runs something like this. Finance flags discount leakage as a problem. The response is an approval process: discounts above a threshold route to a manager before the quote goes out. It ships. Everyone moves on.

    Eighteen months later, leakage hasn’t moved. The approval process captured whether a discount was approved, not what happened to margin as a result. Nobody built a field for the original list price versus the approved price at the line-item level. Nobody reported on override frequency by manager. The process existed, the metric didn’t, and finance is back asking for the same fix under a different name.

    More approval steps won’t fix that. Going back to the one number that actually matters, margin retained per deal, and checking whether the data model can produce it today, will. Usually it can’t, because the build was scoped around the workflow rather than the measurement.

    The scoping conversation this forces

    When a stakeholder brings a request, I ask them to finish this sentence: “I’ll know this worked when [metric] moves by [amount] by [date].” If they can’t finish it, the request isn’t ready for a solution design session yet. It’s a blunt filter, and a genuinely useful one for separating a real business problem from a feature someone saw in a demo.

    It also changes who signs off. A feature list gets approved by whoever asked for it. A metric commitment gets approved by whoever owns that number, and that person has a much stronger incentive to push back on scope that won’t move it.

    What this looks like in a solution design document

    Practically, add one section before the requirements table: the target metric, its current baseline, who owns it, and how the proposed build is expected to shift it. Keep it to a few lines. If you can’t fill it in, that’s the signal to go back and ask better questions before committing engineering time.

    I’ve started refusing to take a build past discovery without this filled in. It’s cut the number of “why did we build this again” conversations down to almost none, mostly because writing the metric down forces a conversation that usually gets skipped entirely.

    Where this earns its keep

    The payoff isn’t just cleaner requirements. It’s a much easier renewal conversation for whoever’s paying for the work. “We shipped the feature” competes for budget every year. “We moved handle time by 22% on the highest-volume case type” doesn’t need to compete. It gets funded again without a fight.

    That’s the actual argument for doing this on every enhancement, not just the big ones. Small requests accumulate into an org nobody can explain the value of. One metric, tracked from design through to the dashboard, is what turns a backlog of tickets into a track record.

  • A security review checklist before any Salesforce release

    Every Salesforce team I’ve worked with has a release checklist. Most of them cover deployment steps, test coverage, and rollback plans. Security review is often the item that gets a tick box with nobody actually looking. That’s how a permission set built for a pilot ends up granting “Modify All” to a profile with 200 users, three releases after anyone remembers why it was created.

    I’ve sat in enough post-incident reviews to know the pattern. Nobody set out to expose sensitive fields to the wrong profile. It happened because a change that looked small in isolation, a new field, a cloned permission set, a flow running in system context, never got checked against what it actually opened up once it hit production.

    Why security review keeps getting skipped

    There are a few reasons, and they compound. It takes real judgment, not a script you run and read a green tick from. It doesn’t map neatly to a single owner either: the admin who built the permission set isn’t necessarily the person who understands the object’s data sensitivity, and the developer writing the Apex trigger isn’t necessarily thinking about who can invoke it. And it’s the easiest checklist item to defer when a release date is fixed and something else broke in UAT.

    None of that makes it optional. It just means it needs a checklist specific enough to run in twenty minutes, not a vague instruction to “review security.”

    What to actually check before you ship

    Field-level security and object permissions

    Any new or changed field needs an explicit answer to who can see it and who can edit it, not an assumption that the default profile settings are fine. Check every profile and permission set that touches the object, not just the ones you edited. It’s common for a field to get correctly locked down on the profile you were focused on and left wide open on three others nobody thought to check.

    Sharing model changes

    Organisation-wide defaults, sharing rules, and role hierarchy changes have a habit of solving one visibility problem while quietly creating another. If you’re moving an object from Public Read/Write to Private, walk through every automation, report, and integration that assumes broader visibility. I’ve seen a tightened sharing rule silently break an integration user’s access to records it needed to update, and the failure didn’t surface until a batch job started throwing errors two days later.

    Apex running without sharing

    Classes declared without sharing bypass the sharing model entirely, and that’s sometimes the right call. The problem is when it’s the default because nobody thought about it, not a decision. Same with SOQL and DML: check whether CRUD and field-level security are actually enforced in the code path, especially in anything invoked from a Lightning component or an exposed Apex REST endpoint. Security enforcement should show up somewhere in any query that touches user-facing data, not just the queries someone remembered to protect.

    Integration and API surface

    Every new connected app, named credential, and integration user is a new door into the org. Check the OAuth scopes granted are the minimum the integration actually needs, not whatever was easiest to get working in a sandbox. Check the integration user’s profile and permission sets against what the integration touches today, because it’s common for an integration user to accumulate access over eighteen months that has nothing to do with its current job.

    Guest user access

    If the release touches an Experience Cloud site, the guest user profile deserves its own pass, separate from everything else. Guest users are the one profile in most orgs where broad object access is a genuine security incident waiting to be reported, not a hypothetical. Salesforce has tightened defaults here over the last few releases, but a cloned profile or an older site can still be sitting on access nobody would approve if they saw it written down.

    Flows and automation running in system context

    A flow set to run in system context without sharing ignores both field-level security and the running user’s record access. That’s frequently the right choice for something like a data cleanup job. It’s the wrong choice, more often than teams expect, for a flow triggered from a screen a regular user interacts with, because it means the automation can read and write things that user couldn’t touch directly.

    Where this actually goes wrong in practice

    The releases that cause problems are rarely the big ones. Big releases get scrutiny by default: more eyes, more testing, a slower pace that leaves room to notice things. It’s the small release that skips review, the one field addition or the permission set clone done at 4pm on a Thursday to unblock a stakeholder, because it feels too minor to need it. Those are exactly the changes worth running through a fixed checklist, since a fixed checklist doesn’t care how small the change felt at the time.

    Making this part of the release process, not an extra step

    The checklist above works because it’s specific enough to run against a change in minutes, and specific enough that two different reviewers reach the same conclusion. Put it in the pull request template or the release notes, right next to test coverage. Assign it to whoever owns the release, not “the security team” as an abstract entity, because unowned checklist items are the ones that get skipped first when time runs short.

    None of this needs new tooling. It’s a short, fixed set of questions applied consistently, every release, on every object and permission set the release touches. The org that does this quietly avoids the incident the org that doesn’t ends up explaining after the fact.