Role and permission matrix
Every DeployMill organisation has three roles, scoped per organisation. A user can be an owner in one org and a member in another.
| Role | Description |
|---|---|
| owner | Full control. Can do everything an admin can, plus transfer or delete the org and change other members' roles (including granting/revoking owner). There must always be at least one owner. |
| admin | Manages members, invites, and SSO, and can view billing (only an owner manages billing). Can drive all deploy-lifecycle actions. Cannot demote or remove an owner. |
| member | Deploys and operates apps. Cannot manage membership or access workspace-administration pages. |
Deploy lifecycle (MCP tools + API)
Any role can authenticate an MCP client (or /api/v1) and drive the deploy lifecycle. The first unit of access control is which org the token belongs to. Within that, most deploy-lifecycle actions are open to every role, but a few privileged ones are gated to admin/owner: managing the org secret vault, deleting an app, and deleting a preview. A member calling one of those gets a not_authorized error (HTTP 403 over /api/v1).
| Capability | owner | admin | member |
|---|---|---|---|
| Deploy, redeploy, rollback | ✓ | ✓ | ✓ |
| Create apps | ✓ | ✓ | ✓ |
| Delete apps | ✓ | ✓ | — |
| Create / redeploy previews | ✓ | ✓ | ✓ |
| Delete previews | ✓ | ✓ | — |
| Set / delete env vars | ✓ | ✓ | ✓ |
| Request / bind / delete org secrets | ✓ | ✓ | — |
| List org secrets (names only) | ✓ | ✓ | ✓ |
| Attach / detach domains | ✓ | ✓ | ✓ |
| Set app protection | ✓ | ✓ | — |
| Set app resources / sleep policy | ✓ | ✓ | — |
| Start / stop apps | ✓ | ✓ | ✓ |
| Push files / get clone credentials | ✓ | ✓ | ✓ |
Workspace administration (dashboard + API)
These are workspace-management capabilities, not deploy-lifecycle capabilities. They live primarily in the dashboard (/account/org) and are gated to admin/owner.
| Capability | owner | admin | member |
|---|---|---|---|
| View org member list | ✓ | ✓ | ✓ |
| Invite members | ✓ | ✓ | — |
| Remove members | ✓ | ✓ | — |
| Change a member's role | ✓ | ✓¹ | — |
| Transfer / delete org | ✓ | — | — |
| View audit log | ✓ | ✓ | — |
| Export audit log (CSV/JSON) | ✓ | ✓ | — |
| Configure SIEM webhook | ✓ | ✓ | — |
| View backup evidence | ✓ | ✓ | — |
| View / manage SSO | ✓ | ✓ | — |
| Require organization protection (org-wide) | ✓ | ✓ | — |
| View billing & plan | ✓ | ✓ | — |
¹ Admins can change roles for members only. Only an owner can grant or revoke the owner role.
The Require organization protection mandate is gated by its own org.protection capability (owner/admin by default). When on, every app is force-gated behind organization sign-in on its next reconcile and protection can't be removed per-app. See the site-protection guide.
Per-member permission overrides
The role columns above are defaults, not hard limits. On top of a member's role bundle, anyone holding the member.manage permission can grant or revoke individual capabilities per member, so two admins can differ (revoke secret.write from one), or a single member can be trusted with app.delete without being promoted to admin.
Capabilities come from a fixed catalog: app.deploy, app.stop, app.manage, app.delete, preview.delete, domain.attach, secret.read, secret.write, code.export, backup.download, member.manage, org.settings, org.protection, org.billing.
A member's effective permissions are (role bundle ∪ grant) ∖ revoke, where a revoke always wins over a grant. Two guardrails apply: you can only grant a capability you hold yourself (no privilege escalation), and ownership changes stay owner-only (overrides never change who is an owner). get_account returns the caller's effective permission set, so an agent can see what it may do before it tries.
Last-owner guard
DeployMill enforces that every org always has at least one owner. An owner cannot demote themselves or be removed if they are the last owner. This prevents orgs from becoming ownerless.
Role assignment API
Roles are managed through the Better Auth organisation API:
POST /api/auth/organization/update-member-role: change a member's role (owner-only for owner role changes)POST /api/auth/organization/remove-member: remove a memberPOST /api/auth/organization/invite-member: invite with a role (admin/owner only)
Per-member permission overrides and the per-member app cap are managed through the dashboard API:
PATCH /api/ui/org/members/:id/permissions: set a member's grant/revoke overrides (member.manage-gated, escalation-guarded, audit-logged)PATCH /api/ui/org/members/:id/limits: set or clear a member's active-app cap ({ maxActiveApps: number | null })GET /api/ui/permissions/catalog: the capability catalog (labels + descriptions) the dashboard renders its toggles from
See also: Subprocessors for the data flows relevant to compliance.