Aadhib

Case study · In development

Architecting multi-tenant legal AI with isolation, roles and audit

When the data is privileged, tenant isolation is a database property rather than a query filter. How the platform is structured, without describing anything that should stay private.

Role
Founder · Architecture · Engineering
Published
Reading time
1 min
PostgreSQLRow-level securityRBAC
01

Context

A legal AI platform holds some of the most sensitive material a firm has: matters, contracts, due-diligence documents, and the questions lawyers ask when they are unsure. Multiple firms use the same deployment. A leak across that boundary is not a bug, it is an existential event for the product.

02

Problem

Application-level tenant filtering is one forgotten WHERE clause away from a cross-tenant disclosure. Every developer knows this and every codebase has the near-miss. Relying on discipline at the query layer is relying on nobody ever making an ordinary mistake.

03

Constraints

01
Isolation must not be optional
It has to hold even when application code is wrong, because application code is eventually wrong.
02
Roles are not uniform
A partner, an associate and an administrator have genuinely different access needs within the same firm.
03
Actions must be attributable
In a professional context, who did what and when is not a nice-to-have.
04
Authentication is a target
The account is the perimeter, so it needs to be defended accordingly.
04

Approach

I pushed isolation down to the database with row-level security enforced rather than advisory, so a query that forgets its tenant returns nothing instead of returning someone else's matter. Above that I layered role and attribute-based access for in-firm permissions, kept an append-only audit trail so history cannot be quietly rewritten, and required multi-factor authentication on the accounts that hold all of it.

05

Architecture

AuthenticationAccount security with multi-factor authentication.
Role and attribute checksIn-firm permissions — who may see which matters and take which actions.
Database-enforced tenant isolationRow-level security enforced at the database, so isolation survives application error.
Append-only auditA record of actions that can be added to but not rewritten.
06

Solution

Isolation is a property of the data layer, not a convention in the query layer. Access control sits above it for the finer-grained in-firm decisions. The audit trail is append-only so the history of access is itself trustworthy. Together these mean a mistake in application code degrades to "no results" rather than to a disclosure.

What I have deliberately left out

No configuration, no policy definitions, no schema detail, no authentication implementation specifics. I think describing the shape of a security architecture is useful to other engineers. Describing its implementation is useful to someone else entirely.

The principle underneath

I design so that the most likely mistake is the least damaging one. A developer forgetting a tenant filter is not a hypothetical — it is a Tuesday. The architecture's job is to make that Tuesday boring.

07

Lessons

  1. 01Put the boundary where a mistake is survivable. Isolation enforced by the database fails closed; isolation enforced by convention fails open, and fails silently.
  2. 02Audit trails that can be edited are documentation, not evidence. Append-only is what makes them worth having.
  3. 03Security architecture is easiest to add before the product has users and nearly impossible to retrofit afterwards without a migration nobody wants to run.

Stack

What it runs on

Isolation
PostgreSQL row-level securityTenant scoping
Access
RBAC / ABACMFA
Accountability
Append-only audit trail

The project

01MyAdvisor.ai
All case studies