# Access and isolation

> Four layers that decide what a caller sees - organisation isolation by schema, object grants, row policies and column masks - evaluated per query and injected into the plan instead of applied by the client

Source: https://aipril.dev/docs/platform/access

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](https://aipril.dev/docs/platform/access/sso.md) - sessions, tokens, and why there are no static
  API keys.
- [Roles and grants](https://aipril.dev/docs/platform/access/roles.md) - functional roles, resource grants,
  application-declared roles.
- [Row-level security](https://aipril.dev/docs/platform/access/row-level-security.md) - policies, attributes and value sets, and what an
  empty allow-list means.
- [Column masking](https://aipril.dev/docs/platform/access/column-masking.md) - the mask expressions and how conflicts
  resolve.
- [Tenant isolation](https://aipril.dev/docs/platform/access/tenant-isolation.md) - schema-per-organisation, and why it is
  not a discriminator column.
