User Management
User management is where you add people to your workspace, set what they can do by assigning a role, and remove them when they leave. Each person's access to a workspace is a membership: a link between a user and a workspace that carries exactly one role. A single user can hold memberships in several workspaces (for example a parent workspace and its children), each with its own role.
The membership list lives at /admin/members. Inviting, changing roles, and revoking all happen here.
Who can manage users. Managing users requires user-management capabilities (user.invite, user.view, user.assign_role, user.revoke_membership). These belong to the user_admin, builder_admin, and system_admin roles. See Governance and permissions.
The members page
Open /admin/members to see everyone with a membership in the current workspace. The table shows each member's name and email, their role (as an inline dropdown), whether this workspace is their home workspace, and when the membership was created. The list is paginated and searchable: typing in the search box filters by name or email across the whole workspace, not just the current page.
A member's home workspace is the one their account is anchored to. It matters when revoking — see Revoking a membership.
Inviting a user
Select Invite to open the invite dialog. Enter the person's email address; as you type, Ema looks up whether that email already exists in your workspace subtree and adapts the form:
- Already in your workspace tree. If the email belongs to a user who already has a membership somewhere in your workspace or its children, Ema only needs to create the membership here. You pick a role and send (name and password are ignored because the identity already exists).
- New to your workspace tree. If the email is unknown, the form asks for a display name. When the workspace uses password sign-in (rather than SSO), it also asks for an initial password. Ema creates the user account and a home membership in your workspace in one step.
- Already a member of this workspace. If the user already has a membership in this exact workspace, the invite is rejected with an
already_memberconflict.
Pick a role from the dropdown (only roles you are allowed to assign are selectable; see role assignment rules). Each assignable role shows a short description of what it can do, so the picker doubles as a reference. Confirm when ready.
Email domain gate
The invitee's email domain must be claimed by your workspace or one of its ancestor workspaces. If it isn't, the invite is rejected with invitee_domain_not_allowed. This gate applies to everyone, with no role-based bypass. Claim the domain first under email domains, then retry the invite.
Inviting into a child workspace
If you administer a parent workspace, you can add a user to one of its child workspaces without switching context. The same dialog is used; the membership is created in the child workspace instead of your current one. This requires the tenant.view_children capability.
How invited users sign in
How a new user first signs in depends on the workspace's sign-in method:
- SSO workspaces. The user signs in through your identity provider; their role on first sign-in comes from the SSO default role unless you invited them with an explicit role. See Tenant management and SSO.
- Password workspaces. The user signs in with the email and initial password set at invite time.
Bulk invite via CSV
Select Bulk invite members in the invite dialog to import users from a CSV file. The flow runs in two steps, with a step counter (for example, "Step 1 of 2") in the footer:
- Upload. Drop or select a CSV file (1 MB limit). Download the template from the link on this step if you need the column format. The upload step shows how many unique email addresses were parsed from the file.
- Review. Each row is shown with an editable email field and a Role selector. You can correct email addresses and set a role per row before sending. An info banner shows how many of the total rows will be sent. Rows with validation errors are highlighted; fix them inline and the list rechecks automatically. Select Send invitations to submit.
Assigning and changing roles
A member's role is shown as a dropdown directly in the members table. Pick a new role to change it immediately (there is no separate save step). Ema records the change in the audit log as user.role_changed.
You can also change a role from the actions menu on a member's row: open the menu and select Edit role. A modal opens showing the member's name and a role selector; save to apply the change.
Each membership carries one role. Changing a role replaces it; roles are not additive.
Role assignment rules
You can only assign a role whose capabilities are a subset of your own. The platform enforces this on both invite and role change: if the target role includes any capability you do not hold, the assignment is rejected. In practice:
- A
user_admincan assignuser,user_admin,builder(only if they also hold builder capabilities), andno_access, but notbuilder_adminorsystem_admin. - A
builder_admincan assign anything up tobuilder_admin. - A
system_admincan assign any role.
In the role dropdown, roles you cannot assign are disabled. This prevents privilege escalation: no admin can grant access beyond their own.
Revoking a membership
To remove someone from a workspace, open the actions menu on their row and select Revoke. The revoke dialog adapts to the member's situation:
- Cascade. If the user also holds memberships in child workspaces below the current one, you can check cascade to revoke those in the same operation. The dialog lists which child workspaces would be affected.
- Home-workspace warning. If you are revoking the user's home membership, the dialog warns you. When the user has other memberships, one is promoted to home automatically.
- Last membership. If this is the user's only membership anywhere, revoking it deactivates their account. The dialog warns you before you confirm.
The result reported back is authoritative: the success message reflects what actually happened (revoked, home changed, or account deactivated), which can differ from the prediction when the user holds memberships in ancestor workspaces the dialog can't see.
You cannot revoke your own home membership in the workspace you are currently in; revoking another user's home is always allowed.
Teams
The Teams tab lists all teams in the workspace, including archived ones, as cards. Each card shows the team name, description, and member count. Clicking a card opens a members drawer showing everyone in that team.
- All Employees is pinned to the top. It contains every workspace member automatically; membership is implicit and cannot be managed here.
- Live teams are sorted by name below All Employees. Clicking a card opens the members drawer, where you can invite users or manage the team.
- Archived teams appear grayed out at the bottom with an archive date. They are not clickable; select Restore on the card to bring a team back with its members and nesting intact.
A search field above the list filters by team name across all three groups.
Creating a team
Select Create team to open the team creation wizard. The wizard runs in two steps (the footer shows "Step 1 of 2"):
- Details. Enter a team name (required) and an optional description. Select Continue.
- Members. Type one or more email addresses (press Enter or comma between addresses, or paste a comma-separated list) and select a role to apply to everyone in this batch. Select Create to create the team and add the listed members in one step.
If any email addresses cannot be added (for example, the address is unknown to the system), a warning toast reports the count; invite those members individually from the team page afterward.
Inviting users and teams into a team
From the members drawer or the team detail page, select Invite to add people or nest other teams:
- Invite users. Search the workspace directory, select one or more people, pick a role that applies to the whole batch, and confirm.
- Invite teams. Select one or more teams from the picker (built-in search, with a member count shown per option), pick a role that applies to all selected teams, and confirm. The role is a bulk setting for this batch, not a per-team choice. Teams that are already nested, or that would create a cycle, are excluded from the picker automatically.
Editing a role in a team
To change a member's or nested team's role, open the actions menu on their row and select Edit role. A modal opens with the identity field (read-only) and a role selector. The Role column in the table is sortable: click the column header to sort by role label.
Reference: endpoints
User management is backed by the auth service. The capability that gates each route is noted.
| Action | Endpoint | Capability |
|---|---|---|
| List memberships (with search) | GET /memberships?q= | user.view |
| Invite a user into the current workspace | POST /memberships | user.invite |
| Invite a user into a child workspace | POST /tenants/{id}/memberships | user.invite + tenant.view_children |
| Look up an email in the subtree | GET /memberships/lookup-email | user.invite |
| Change a membership's role | PUT /memberships/{id} | user.assign_role |
| Revoke a membership | DELETE /memberships/{id} | user.revoke_membership |
| List a user's memberships in your subtree | GET /users/{id}/memberships | user.view |
A membership returned by these endpoints looks like this:
{
"id": "8b1f...",
"user_id": "3c92...",
"tenant_id": "a07d...",
"role_id": "1f44...",
"role_name": "builder",
"is_home": true,
"created_at": "2026-05-30T14:22:10Z",
"updated_at": "2026-05-30T14:22:10Z"
}
What's next
- Governance and permissions — what each role can do.
- Tenant management and SSO — configure sign-in and claim email domains.
- Audit log — review invites, role changes, and revocations.