Skip to content
All writing

Multi-tier access is harder than it looks

Restricting a manager to their own territory sounds like a filter on a list. It reaches every export, aggregate, notification and search index, and retrofitting it is expensive.

Engineering practice3 min read

The requirement arrives as one line in a backlog. Regional managers should only see their own territory. It gets estimated at a couple of days, because it sounds like a filter on a list.

On the Würth CRM, where regional managers see only their own territory across a platform carrying the whole field sales force, that decision shaped almost everything built after it. We made it early, which is the only reason it stayed cheap. On systems where the decision was made late, we have priced retrofits that came to more work than the reporting layer they had to be applied to.

Where the rule leaks

A territory restriction belongs to the data rather than to any screen. It applies to every path by which data leaves the system, and an enterprise system has more of those than anybody lists at the start.

  • Every list endpoint, including the ones added eighteen months later by a different team who read the existing code and copied the wrong example.
  • Search. If the index is built once for everyone, the filter has to be applied at query time, and the result count leaks information even when the rows themselves do not.
  • Exports. A CSV download is the most common leak we find, because it is usually built by somebody treating it as a reporting feature rather than as a read path.
  • Aggregates. A regional total is safe. A national total displayed next to it, with two of three regions visible, hands the manager the third region's number by subtraction.
  • Notifications and scheduled emails. A digest generated by a batch job runs without a user session, and therefore without the filter a request would have applied automatically.
  • Audit logs, which are the awkward case, because the people who need to read them are often the people the restriction was written for.

The aggregate problem is the one that surprises teams. Row-level filtering is a solved problem in every serious framework, and a competent engineer will get it right. Deciding which totals a regional manager is permitted to see is a business question, and in our experience it has usually never been asked before the demonstration where somebody notices.

Territories move

The second surprise is time. Territories get reorganised, sometimes annually, and the reorganisation is announced with a slide rather than a data migration plan. When a region splits, somebody has to decide what happens to the historical records: whether the incoming manager can see last year's visits in the area they now own, and whether the outgoing manager keeps them.

There is no technically correct answer here. There is a business answer, and it differs depending on whether the record is being read for reporting, for commission or for audit. The same visit can need three different visibility rules depending on why somebody is looking at it. A system that stores a single owner column on a row cannot express that, and discovering it in year two means a data migration on live records with money attached to them.

Making it cheap

Three decisions do most of the work, and all three are close to free in the first week of a build.

  1. 01Decide the scoping unit before the first table exists. Territory, legal entity, business unit, or some combination. Put it on the rows that need it and resolve it through one function, so that a query written later cannot quietly forget.
  2. 02Make the unfiltered query the awkward one. If reading data requires passing a scope, an engineer who genuinely needs everything has to write something that looks unusual and gets noticed in review. Where the unfiltered read is the default, the omission is invisible on the page.
  3. 03Test with a user who should see nothing. Realistic fixtures hide leaks, because every number looks plausible. A user assigned to an empty territory should get empty lists, zero counts, a search with no results and an export containing a header row. Any screen that shows them a figure is a bug found for free.

Access tiers look like a permissions feature and behave like a data model decision. They are worth an hour in the first week, with the person who actually owns the territory structure in the room rather than a proxy. The alternative is finding out during a reorganisation that the system holds an opinion about the org chart, and that the opinion is now out of date.

Talk to our engineering team

Tell us what you need built, modernised or maintained. We will tell you whether we are the right firm for it and what it costs.