Persons, user accounts and role assignments. Core.
identity is who a tenant knows and who can sign in: three tables in a chain, person to user to role.
| Table | Holds |
|---|---|
persons | The minimal identity record, keyed on email. A person can exist with no user. |
users | Links a person to a role and an auth identity. One per person. |
roles | Tenant-authored roles, hierarchical. |
permissions and role_permissions | The permission vocabulary and each role's set. |
organization_persons | A person's placement on an organization node: their territory. |
The split exists for the pre-onboarding state: an email is known before a role is. Onboarding upserts the person by email and creates the user with the default role, idempotently on every sign-in. A user holds one role; the role holds many permissions, each <resource>.<verb>, and the admin role holds every one. Only a holder of the provisioning permission can create a user.
A person placed on a node covers that node and everything beneath it. Territory is data, not a role: a national and an area manager share one role and differ only in where they are placed. Every private table's policy admits a person's own rows, and admits the rows within their territory when they hold the resource's read permission.
| Route | Surface |
|---|---|
/users | User accounts, their role and status. |
/persons | People, with or without an account. |
/roles | Roles and their permission sets. |
identity.
download_table, propose_import and commit_import: people arrive by spreadsheet through the same contract products use, upserting on email.
identity.read, identity.manage, identity.provision. A person's own row is always theirs to read and update.
Never. Every project links it at provisioning.