At Talentera (the Bayt.com B2B recruitment platform) I spent a couple of years architecting multi-tenant workflows serving enterprises and governments on one codebase. The data model looked fine on day one and — more surprisingly — it survived years of tenancy-specific demands. The trick was treating identity + access control as a first-class design axis, not a middleware concern bolted on after the business logic was written. This post is the short version of what I’d recommend to any engineer building a multi-tenant platform in 2026.

The shape of the problem

Multi-tenant recruitment is almost a worst-case for access control:

  • Multiple classes of tenant. Enterprises, small businesses, government ministries — same platform, wildly different expectations about what “isolation” means.
  • Shared staff. Recruiters who work for one agency this quarter and a different one next quarter. Their history can’t leak. Their credentials should be portable.
  • Candidates are a cross-tenant primitive. A candidate applies to roles at ten companies. Those companies should not see each other’s interactions with that candidate.
  • Government contracts come with audit requirements. Not “we log things.” Formal requirements, with periodic audits, with legal consequences for misses.

Every one of those bullets is an identity / access-control problem first. The rest of the platform is a thin layer on top.

The model that worked

The model that shipped and survived was built around four primitives:

1. Tenant as a first-class, non-nullable entity

Every row in the database had a tenant column, enforced by database-level constraints. Not an app-level filter. Not a “we’ll remember to add it.” Row-level security in Postgres (or equivalent in other stores). If an engineer wrote a query that didn’t include the tenant filter, the database raised an error.

The trade-off was that every query looked slightly more verbose. The win was that a bug in the app could never cause a cross-tenant leak, because the database refused to serve the request.

2. Subject / relationship / resource, not user / role

The off-the-shelf model — users have roles, roles have permissions, permissions protect resources — is fine for simple apps. It breaks in a multi-tenant recruitment context because a user’s role depends on which tenant they’re operating in. A recruiter who is “admin” at Agency A is “guest” at Agency B, and “nothing” at Agency C.

The model we used was closer to the Zanzibar style (before Zanzibar was a household name in the engineering community): subject has a relationship to a resource, mediated by the current tenant context. A single query answered “can this subject do this action on this resource in this context?” and the answer was computed from the relationship graph, not a role enum.

That single change unlocked dozens of product features that would have required bespoke permission code in the role-enum model.

3. Shared identity, scoped session

Users had one identity — their login. When they authenticated, they got a session token scoped to a specific tenant. Switching tenants meant issuing a new session, not mutating the existing one. The session carried the tenant ID, the subject’s relationships relevant to that tenant, and the session’s own audit-visible identifier.

This meant that every audited action was trivially traceable to (subject, tenant, session, timestamp) — and “who did what for whom” questions from auditors became a one-query answer.

4. Audit as an append-only domain event

Every mutation in the system emitted a domain event to an append-only audit log. The audit log was a first-class part of the application schema, not an ops afterthought. When a government auditor asked “show me all resume views by this recruiter in March,” the answer was a query, not a multi-week exercise in log correlation.

Building this from day one is 3x cheaper than retrofitting it later. I know because I did both.

The failures

Two things I got wrong:

1. The first version of role inheritance was too flat. We had an admin-user-contributor tier and that was that. Enterprises wanted sub-admins. We had to add role composition after the fact, which meant untangling a bunch of assumptions that “admin means all these things.” The right move would have been to build composition from day one — but I didn’t see the need until customer #20.

2. The multi-tenancy model didn’t extend cleanly to analytics. For transactional queries, row-level tenant scoping was bulletproof. For BI / reporting workloads, it got expensive fast. We ended up with a separate analytics pipeline that enforced the tenant boundary at the pipeline level, not the query level. That worked — but it was a lot of plumbing to build twice, and I’d do it differently if I started again.

What I’d do differently in 2026

Four years later, starting from scratch, I would:

  • Reach for OPA (Open Policy Agent) or a similar policy engine from day one, rather than building the permission-evaluation engine myself. Cheaper, audited, well-tested, and the conceptual model is the same.
  • Use Postgres row-level security or an equivalent hard boundary. Not “we’ll filter in the app.” The perimeter has to be at the database layer.
  • Pick a structured audit-event schema before writing the first mutation endpoint. Every event is (actor, subject, action, resource, tenant, timestamp, outcome, diff). If a new feature needs an event shape the schema doesn’t support, that’s a schema conversation, not a “just log something.”
  • Use Open ID Connect + a dedicated identity provider rather than rolling auth. Pocket ID, Keycloak, Auth0, Ory — the good options are cheaper than the DIY cost.

The pattern that generalises

None of this is recruitment-specific. Every B2B SaaS, every multi-tenant platform, every government-adjacent system has the same shape. The reason most of them are a mess is that identity and access control are treated as middleware — bolted on, underspecified, never-the-priority. The ones that age well treat identity as a product dimension: part of the domain model, part of the design reviews, part of the roadmap.

If you’re building a multi-tenant platform right now: the identity model is the most load-bearing design choice you will make in the first year. You cannot retrofit it cheaply. Get it right. Spend the time. Read the Zanzibar paper. Talk to people who’ve done it. It compounds.