Organizations and members
The scope everything belongs to, the three roles, and the one-user-one-organization rule.
Every project, application, deployment, server, service, alert, and token belongs to an organization. Every read and write is scoped to the organization on your session.
The first organization is created by first-run setup, alongside the first user and their membership.
Roles
| Role | Can |
|---|---|
OWNER | Everything, including renaming the organization, inviting, changing a member's role, and removing a member. |
ADMIN | Everything an owner can do except the organization mutations above. Can list and revoke another member's sessions. |
MEMBER | Read and act on the organization's resources. |
Mutations on the organization itself — rename, member role change, member removal, invite,
cancel invitation — require OWNER. Reading the organization, its members, and its
invitations requires only a session scoped to it.
Roles are not a security boundary against the machine
Anyone with admin access to the portal has root on the server, because the control plane holds the Docker socket. The roles divide responsibility among people you already trust with the box — they do not contain someone you do not.
One user, one organization
A user belongs to exactly one organization. This is enforced at every path that can create a membership rather than by a database constraint, and both signup and invitation acceptance refuse to give a second one to a user who already has one.
Why it is enforced this way
The schema is many-to-many and stays that way — a @@unique([userId]) would foreclose
multi-organization membership forever. What is not built is the switching concept: a session
carries exactly one organizationId, and every organization-scoped route trusts it as the
scope.
A user with two memberships would silently resolve to their earliest one, on every
session and every request, and the second organization would be invisible through that session
with no error and no 403. Refusing to create the second membership is what keeps that from
happening.
Multi-organization support — the "active organization" a consultant working across several customers would need — is deferred work, not a decision against it.
Members and sessions
GET /users lists the organization's members. GET /users/:id/sessions lists one member's
sessions; an owner or admin can list and revoke someone else's, and anyone can manage their
own.
Revoking a session ends it server-side rather than only clearing a cookie.
Removing a member
An owner can remove a member. Anything that member created stays with the organization — an API token they left behind stops working, because a token's organization is re-validated against membership on every use.