Skip to content

Commit 4709679

Browse files
rafiki270claude
andcommitted
docs(requirements): update roles-and-acl with clarified decisions
- UOA system roles simplified to owner + admin only - No cap on custom roles per team/org - Custom roles are labels only; consuming app owns all gating - Custom roles are orthogonal to UOA system roles - Owner non-removable, transferable; admin has full power - Reduced outstanding decisions to 3 open items Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 48fe773 commit 4709679

File tree

1 file changed

+67
-70
lines changed

1 file changed

+67
-70
lines changed

Docs/Requirements/roles-and-acl.md

Lines changed: 67 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6,69 +6,70 @@ There are two completely separate concepts that must not be conflated.
66

77
### 1. UOA system roles (internal)
88

9-
These control who can administer the UOA backend itself. They are fixed and managed only by system admins via the admin panel. End users and developers never see or configure these.
9+
These control who can administer the UOA backend itself — the org and team structure, billing, membership. There are exactly two UOA system roles:
1010

11-
| Role | Scope | Can do |
11+
| Role | Scope | Rules |
1212
|---|---|---|
13-
| `system_admin` | Global | Full admin panel access, all orgs/teams/domains |
14-
| `org_owner` | Organisation | Manage their org, teams, members, domains |
15-
| `org_admin` | Organisation | Manage teams and members, not delete org |
16-
| `org_member` | Organisation | Read-only on org structure |
17-
| `team_owner` | Team | Manage team members and domain rules for that team |
18-
| `team_admin` | Team | Manage team members |
19-
| `team_member` | Team | Basic membership |
13+
| `owner` | Org or Team | Created with the org/team. Cannot be removed. Can transfer ownership to any other user. Implicitly has all admin capabilities. |
14+
| `admin` | Org or Team | Full power: delete teams, manage billing, manage members, manage domains. Multiple admins allowed. Any user can be granted or revoked admin. |
2015

21-
These roles are stored and managed by UOA. They drive access to the UOA admin panel and to management API endpoints (`/internal/...`).
16+
Users who are neither `owner` nor `admin` have no named UOA system role — they are plain members whose significance is defined entirely by their custom role.
17+
18+
`system_admin` is a separate global role for UOA's own admin panel operators and is not visible to org/team users.
2219

2320
### 2. Consumer-defined roles (external, custom)
2421

25-
These are the roles that a developer registering a domain/team defines for their own product. UOA does not know or care what they mean — it stores and returns them. The developer decides what `editor`, `viewer`, `staff`, `bartender`, or anything else means inside their own application.
22+
These are roles that a developer or org defines for their own product. UOA stores only the **label** — a string reference. UOA has no opinion on what the role permits. The consuming application owns all gating logic.
2623

27-
UOA's responsibility:
28-
- Store the custom role definitions per team
29-
- Assign custom roles to users per team
30-
- Return the user's custom roles in the access token and via API
31-
- Enforce nothing — the consuming app enforces meaning
24+
- Any number of custom roles per team or organisation — no cap, no gating
25+
- Custom roles can share names with UOA system roles (different namespaces, no conflict)
26+
- A user's UOA role and their custom role are completely orthogonal: an `owner` in UOA can be a `viewer` in the app; a plain user in UOA can be a `superadmin` in the app
3227

33-
These are entirely separate from UOA system roles.
28+
UOA's only responsibilities for custom roles:
29+
- Store the role definitions per team/org
30+
- Validate that a role assigned to a user exists in the team/org's defined list
31+
- Return the role label in the access token and via API
32+
- Enforce nothing beyond that
3433

3534
---
3635

3736
## Hierarchy model
3837

3938
```
4039
Organisation
41-
├── has many Domains (multiple — one org may run hundreds of services)
42-
├── has many Teams
43-
│ ├── Team has one or more Domains
44-
│ ├── Team has custom Role definitions
45-
│ └── Team has Members (with custom roles assigned)
46-
└── has system-level role assignments per member
40+
├── has many Domains (multiple — one org can serve hundreds of services)
41+
├── has UOA role assignments (owner, admin) per member
42+
├── has custom role definitions
43+
└── has many Teams
44+
├── references one or more Domains from the org's domain pool
45+
├── has UOA role assignments (owner, admin) per member
46+
├── has custom role definitions (can differ from org-level)
47+
└── has Members with assigned custom roles
4748
```
4849

4950
### Auto-organisation rule
5051

51-
Not every user of UOA needs an enterprise org setup. Teams are the primary registration unit for simpler setups.
52+
Teams are the primary registration unit. Not every setup needs a full enterprise org structure.
5253

53-
**Rule:** When a team is created and no organisation is specified, an organisation is automatically created with the same name/slug and the team placed under it. That org is allowed to contain only one team (the simple/non-enterprise case). If the org later needs to expand to multiple teams, it is promoted to a full enterprise org by adding a second team.
54+
**Rule:** When a team is created without specifying an organisation, UOA automatically creates an organisation with the same name and slug and places the team under it. That org starts in single-team mode.
5455

55-
This means:
56-
- Teams are always under an org, but the org can be implicit/auto-created
57-
- Single-team orgs are the default, lightweight path
58-
- Multi-team orgs are the enterprise path
56+
- Single-team org = the default, lightweight path (most small integrations)
57+
- Multi-team org = enterprise path, unlocked simply by adding a second team
58+
- Teams are always under an org — the org may just be implicit and auto-created
5959

6060
### Domain assignment
6161

62-
- Domains live at **organisation level** — an org can have multiple domains (e.g. `api.acme.com`, `app.acme.com`, `admin.acme.com`, `mobile.acme.com`, ...)
63-
- A **team** references one or more domains from its org's domain pool — this is what gets registered; the team is the entity that "uses" a domain
64-
- A domain can only belong to one organisation
65-
- Authentication requests come in on a domain → resolve to the org → resolve to the team registered for that domain → determine user's membership and roles for that team
62+
- Domains are registered at **organisation level**
63+
- An org can have any number of domains (`api.acme.com`, `app.acme.com`, `admin.acme.com`, etc.)
64+
- A domain belongs to exactly one organisation
65+
- Teams reference domains from their org's pool — the team is what gets registered against a domain
66+
- Inbound auth request flow: domain → org → team registered for that domain → user's membership and roles for that team
6667

6768
---
6869

6970
## Custom role definitions
7071

71-
Each team defines its own set of role names. These are free-form strings stored per team.
72+
Each team (and optionally org) defines its own role names as a simple list of strings:
7273

7374
```json
7475
{
@@ -77,17 +78,13 @@ Each team defines its own set of role names. These are free-form strings stored
7778
}
7879
```
7980

80-
When a user is added to a team, they are assigned one of those custom roles.
81-
82-
UOA validates only:
83-
- The role name assigned to a user must exist in the team's `customRoles` list
84-
- Role names must be non-empty strings, no spaces, reasonable length
81+
No limit on the number of roles. Role names are validated only for being non-empty strings. Format is up to the defining org — UOA imposes no casing or character rules beyond that.
8582

86-
UOA does **not** validate meaning or enforce permissions based on custom roles — that is the consuming app's responsibility.
83+
What a role *permits* inside the consuming application is entirely that application's concern. UOA returns only the label.
8784

88-
### Token output
85+
---
8986

90-
The access token issued by UOA includes:
87+
## Token output
9188

9289
```json
9390
{
@@ -97,60 +94,60 @@ The access token issued by UOA includes:
9794
{
9895
"id": "org_abc",
9996
"slug": "acme",
100-
"uoaRole": "org_member",
97+
"uoaRole": "admin",
98+
"customRoles": ["manager"],
10199
"teams": [
102100
{
103101
"id": "team_xyz",
104102
"name": "Backend",
105103
"domain": "api.acme.com",
106-
"customRole": "editor",
107-
"uoaRole": "team_member",
108-
"uoaRoleInherited": true
104+
"uoaRole": "admin",
105+
"uoaRoleInherited": true,
106+
"customRoles": ["editor"]
109107
}
110108
]
111109
}
112110
]
113111
}
114112
```
115113

116-
`uoaRole` = UOA system role (internal, for UOA management use)
117-
`customRole` = developer-defined role (for the consuming app to use)
118-
`uoaRoleInherited` = true if the team-level UOA role was not set explicitly but inherited from the org
114+
- `uoaRole` `owner`, `admin`, or omitted if neither. For UOA management use only.
115+
- `uoaRoleInherited` — true if the team-level UOA role was derived from the org-level role, not set explicitly
116+
- `customRoles` — array of the consuming app's role labels for that scope. UOA stores and returns them; the app interprets them.
119117

120-
---
118+
Note: `customRoles` is an array because a user may hold multiple custom roles at the same scope (e.g. `["editor", "billing"]`).
121119

122-
## Inheritance rules (UOA system roles only)
120+
---
123121

124-
Custom roles do not inherit — the consuming app defines its own hierarchy if it wants one.
122+
## UOA system role inheritance
125123

126-
UOA system role inheritance:
124+
Inheritance applies only to UOA system roles, not to custom roles.
127125

128-
1. `org_owner` → effective `team_owner` on every team in the org
129-
2. `org_admin` → effective `team_admin` on every team in the org
130-
3. `org_member` → effective `team_member` on every team (read access only)
131-
4. A user with an explicit team role at a higher level than their org role keeps the higher team role
126+
1. Org `owner` → effective `owner` on every team in the org
127+
2. Org `admin` → effective `admin` on every team in the org
128+
3. A user with an explicitly higher team role than their org role keeps the higher team role
129+
4. Inheritance is computed at request time — not stored as duplicate records
132130

133-
Inheritance is computed at access time, not stored as duplicate records.
131+
Custom roles do not inherit. If a consuming app wants role inheritance, it implements that in its own gating layer.
134132

135133
---
136134

137135
## Email domain auto-enrolment
138136

139-
Orgs (and by extension teams) can define rules: any user who authenticates with a verified email from `@acme.com` is automatically added to the org as `org_member` and to the default team with a specified custom role.
137+
Orgs can define rules so that any user who authenticates with a verified email from a given domain is automatically granted membership on first login.
140138

141-
Rules are per-org and specify:
139+
Each rule specifies:
142140
- Email domain (e.g. `acme.com`)
143-
- UOA role granted (`org_member` or `org_admin` — never `org_owner`)
144-
- Custom role granted on the default team (must exist in that team's `customRoles`)
145-
- Verification method required (`ANY`, `EMAIL`, `GOOGLE`, `GITHUB`)
141+
- UOA role to grant — `admin` only, or neither (plain member with no UOA role)
142+
- Custom role(s) to assign on the default team — must exist in the team's defined list
143+
- Verification method required: `ANY`, `EMAIL`, `GOOGLE`, `GITHUB`
144+
145+
`owner` can never be granted via auto-enrolment — ownership is always explicit.
146146

147147
---
148148

149-
## Outstanding decisions needed
149+
## Outstanding decisions
150150

151-
1. **Can a custom role be the same string as a UOA system role?** (e.g. can a developer name a role `admin`?) — recommend: yes, no conflict since they live in different namespaces
152-
2. **Role name format** — allow any string, or enforce lowercase/alphanumeric/hyphen?
153-
3. **Max custom roles per team** — suggest: 20
154-
4. **Who can manage custom role definitions?** — suggest: `team_owner` and `org_owner` only
155-
5. **Default custom role on auto-enrolment** — must be pre-configured per rule, or fallback to first role in the list?
156-
6. **SCIM provisioning** — out of scope for now but the custom role model needs to be SCIM-group-compatible for future enterprise IdP sync
151+
1. **Default custom role on auto-enrolment** — must the rule explicitly name a custom role, or fall back to the first role in the team's list if none specified?
152+
2. **Multiple custom roles per user per team** — the token uses an array; confirm this is intentional (a user can hold `editor` and `billing` simultaneously at the same team scope)
153+
3. **SCIM** — confirmed out of scope for now

0 commit comments

Comments
 (0)