A permission model that works fine for a single location business almost always breaks the first time a customer opens a second branch. The break is rarely visible in the role names themselves. It shows up in the data, a manager at one branch can suddenly see, or worse, edit, records belonging to a completely different branch, because "manager" was defined as a capability with no sense of place attached to it at all. We learned this the hard way on an early project, and it changed how we design every permission model since.
The actual fix is structural. Every permission check we write now looks at two things together, does this role have the capability, and does the reach of that capability actually cover this particular record's location. A branch manager role should be something you can assign per branch, so the exact same role definition can go to five different people at five different branches, without giving any of them sight of branches that are not theirs. Treating location as a setting on the role assignment, rather than baking a brand new role for every branch, is what kept our role list from spiralling out of control as customers opened more locations.
Some users genuinely need to see across every location, regional managers, finance staff pulling company wide numbers. We treat this as a clearly named, deliberately granted capability, something like "all branch visibility," never something that falls out of a role simply because nobody scoped it properly. Every grant like this is something we can list and explain in a security review, because we made a point of being able to.
Checks on individual records were always well tested in our work. The actual leaks showed up in reporting, where a report pulling totals across all stores quietly skipped the very same per record checks the rest of the application enforced everywhere else. We now make sure every reporting screen applies the exact same location based rule as the normal transaction screens, not a second, separately maintained copy of that rule that can drift out of step over time.
When a record, a transfer, a referral, a customer moving branches, crosses from one location to another, both the sending and the receiving location's staff genuinely need to see it for a period of time. We learned to decide this on purpose, since it is one of the most common gaps in this kind of design. Most models simply assume every record belongs to exactly one place, and ours did too, until an actual case proved otherwise.
A test setup with only two locations hides bugs that only show up with three or more, especially around rules like "see everything except my own" and grouping by region. If your test data only ever has one location, or two, your testing has not actually exercised the actual scoping logic the way an actual multi branch customer eventually will.
Maybeach Tech designs access control systems for multi branch and multi location organisations. Get in touch and let us review your scoping model.