Four questions, four layers, each enforced in a different place - and none of them in the interface.
| Question | Layer | Enforced |
|---|---|---|
| Which organisation is this? | Schema-per-organisation | At the connection, per transaction |
| Who is the caller? | Sessions and tokens | At the identity service |
| May they see this object at all? | Object grants | Before a query is planned |
| Which rows? | Row policies | As a filter injected into the query plan |
| Which values in those rows? | Column masks | As a mask expression on the plan's output columns |
The important structural property: rows and columns are decided inside the query plan, not filtered afterwards by whatever asked. A dashboard, a page of an application, a workflow, an MCP client and an AI agent all get the same answer, because none of them is the thing applying the rule.
The pages
- Sign-in and identity - sessions, tokens, and why there are no static API keys.
- Roles and grants - functional roles, resource grants, application-declared roles.
- Row-level security - policies, attributes and value sets, and what an empty allow-list means.
- Column masking - the mask expressions and how conflicts resolve.
- Tenant isolation - schema-per-organisation, and why it is not a discriminator column.