iKonekt

For groups and several brands

Several companies,
one install, no shared customers

Groups usually solve this twice badly: either five separate installs and five separate everything, or one install and a solemn promise that the application always filters correctly. The first is expensive. The second is a promise, and promises are not a security model.

If you run more than one company — a holding with subsidiaries, a franchise, two brands aimed at different markets, an agency and the thing the agency spun out — you already know the shape of the problem. The brands share people, tooling and a finance department. They do not share customers, and they must not appear to.

iKonekt runs all of them from one install, and the separation between them is kept by the database rather than by the code. That distinction sounds academic until the day it isn't.

Why the layer matters

An application-level filter is a sentence in a query. It works as long as every query that will ever be written contains it — including the one written in a hurry, the one written by the new developer, and the one written for a report that was only ever going to be used once.

Push the boundary into the database and the arithmetic inverts. The policy runs on every read and every write, underneath everything. A query that forgets the company does not return the wrong rows; it returns none. The failure mode becomes an empty screen and a confused developer, which is the correct failure mode.

Empty screens are a feature. We would rather explain an empty screen to one of our own engineers than explain a customer list to two clients who were not expecting to meet.

One installPer company
  • 1Customers & threadsScoped. A seller in brand A cannot reach brand B's, by construction rather than by configuration.
  • 2Claims on a customer"We already have this account" is a lock held per company — so two brands can both work the same market without colliding.
  • 3Prompts & settingsEach company edits its own. The one place this was ever shared was a bug, and it is the bug this system is proudest of having found.
  • 4Partner programmesA module per company, not a global one that everyone inherits.

Boundary enforced below the application

What a group actually gets to share

Separation is not isolation for its own sake. The things worth sharing across a group are shared deliberately, and they are mostly the boring ones — which is exactly right, because the boring ones are where the duplicated cost lives:

  • One install to run and update. One deployment, one set of credentials to look after, one thing to keep patched.
  • One team of people, wearing different hats. A person can work in more than one company; what they cannot do is see both at once through a query that forgot to ask.
  • One set of habits. The way a lead is assigned, the way a note is written, the way a job reaches an invoice — learned once, applied everywhere, which shortens onboarding to about a morning.
  • One relationship with the rest of the family. castomAPI underneath, the same account, the same connectors — configured per company where it matters.

The question a group always asks second

"Can we report across all of them?" Yes — from the group's own vantage point, deliberately and explicitly, rather than as a side effect of a leaky boundary. The distinction is the whole design: crossing the line has to be an act somebody performed on purpose, with the authority to do it. It must never be something a stray identifier can accomplish by accident.

And the question they ask third: "what happens if we sell one of the brands?" A boundary that the database keeps is also a boundary you can lift a clean copy out of. That is not a coincidence — separation and portability are the same property viewed from two different meetings.

Under the floor

What is holding the line, specifically

Not a claim, a list. If a supplier cannot produce this list about their own product, that is worth noticing.

26

Tables carrying their company, with the check forced on rather than merely available.

72

Policies, written out one at a time so each has been read by a person, not generated in a loop.

942

Tests, run against a database rebuilt from zero every time anything changes.

0

Default companies. A request with no scope throws before it reaches the data — there is no fallback to forget to disable.

How separation is built

“Five companies, five installs, five invoices from you.”

One install. Five boundaries the database keeps.

Shared people, shared habits, shared platform — and not one shared customer. Crossing that line has to be something a person did on purpose, never something an identifier managed by accident.

How separation is built →