A multi-customer system has one rule everyone agrees on: you can only see your own company’s records. The interesting question is where the rule lives, and the answer decides whether the next feature can leak.
The system: a support desk serving many client companies. Staff need a board showing everything. Each client needs a portal showing only their own tickets.
The obvious place
The obvious place is the code that handles each request. Every screen, every report, every export, checks “is this the caller’s company?” before showing anything. The system I was replacing did exactly that, in roughly forty places. It worked, in the sense that nobody had yet found the place where the check was missing.
That is not the same as being correct. And with an AI tool generating new screens on request, the number of places to forget the check was only going to grow. Each new feature was a chance to leak one client’s tickets to another, and the review process was the only thing standing in the way.
The better place
Modern databases can hold the rule themselves. You state it once, as a policy on the data, and the database applies it to every query, from every screen, every report and every live update, whether or not the code that asked remembered to.
That changes what the code is for. It stops being a bouncer at forty doors and becomes a set of screens that ask for data and get only what the caller is allowed. New features inherit the rule for free. The tool can generate a new report tomorrow and it cannot leak, because the leak would have to happen below the code it wrote.
Three things followed that I did not expect to get for free:
- anything that changes several records at once runs inside the database as the caller, so a client physically cannot move another client’s record even by naming its id
- activity logging became automatic rather than something each feature had to remember to do
- live updates, which would normally need their own copy of the rule, simply obeyed the same one, so the portal shipped with them in the first version rather than “later”
What the database cannot do
It is not magic. Some things stay in the code: cleaning up rich text before it is stored, so that one client cannot plant something that runs in another’s browser. And any part of the system that connects with a privileged account bypasses the rule entirely. One privileged query in a system that believes “the policies protect us” is a hole, not a backstop. Checking for that is now a standard line in my security review.
How you know it is true
Rules in a database are code, and code can be loosened by accident. I found that out from a failing test: a narrower permission I added had no effect at all, because the database’s default permissions were broader and sat alongside it. A test caught it. That is the only acceptable way to find out.
So the rule ships with tests that prove each isolation case and fail when one is loosened. That test suite is the reason I can say “new features inherit the isolation” and mean it.
What to take from this if you run a company
You do not need to know how policies are written. You need to ask one question of whoever builds or sells you a multi-customer system: where does the rule about who can see what live, and what happens when someone adds a new screen? If the answer is “each screen checks”, ask what checks the screens.