Roles & access control
Pier’s authorization model has two scopes. Every user carries one global role, and a user can additionally hold a project role on each project they’re a member of. Most endpoints check one or the other; a few high-impact ones are reserved for the Owner.
Global roles
Section titled “Global roles”A global role is stored on the user record and travels with every authenticated request. There are three, ordered from most to least privileged.
| Role | What it can do |
|---|---|
Owner | Everything Admin can, plus the Owner-only knobs: changing other users’ global roles, deleting/promoting Admins, federation grants, and the WireGuard mesh. The first user created at setup is the Owner. At least one active Owner is always required. |
Admin | Manage users (invite, edit, remove non-Owners), manage servers, view system metrics and the audit log, create projects, and operate Docker-level resources (containers, images, compose stacks, networks, registries). Bypasses project membership — an Admin reaches every project. |
User | A regular member. Sees only the projects they’re an explicit member of, plus read-only global endpoints (server list, system metrics). Cannot create projects or manage users. |
Global
OwnerandAdminboth bypass project-membership checks — they’re treated as projectAdminon every project.
Project roles
Section titled “Project roles”A project role is granted via project membership (the project_members table) and scopes a User’s reach to a single project without giving them global power. There are three.
| Role | What it can do within the project |
|---|---|
Admin | Everything Editor can, plus manage the project’s membership (add/remove members, change their roles). |
Editor | Deploy and redeploy services, change env vars, domains and settings, restart. |
Viewer | Read-only: configs, logs, metrics, and deployment history. |
Each project keeps at least one project Admin: Pier refuses to demote or remove the last one.
How endpoints are gated
Section titled “How endpoints are gated”Two mechanisms enforce roles:
- Router-level global guards. Whole groups of routes sit behind a middleware layer.
require_global_admingates user management, Docker daemon ops, compose stacks, registries, the audit log, and server mutations.require_global_ownergates global-role changes (PUT /users/{id}/role), the mesh, and federation grants. - In-handler project checks. Project-scoped routes (resources, deployments, env, backups) call
enforce_project_role/enforce_resource_roleat the top of the handler, resolving the resource to its project and requiring a minimum project role.
A concise map of common actions:
| Action | Minimum role |
|---|---|
| Browse the catalog / view a project’s services | Viewer (project) |
| Deploy or redeploy a service, edit env/domains | Editor (project) |
| Add or remove a project member | Admin (project) |
| Create a new project | Admin (global) |
| Invite or remove users, view audit log | Admin (global) |
Promote a user to Admin, or change any global role | Owner (global) |
| Manage federation grants or the WireGuard mesh | Owner (global) |