Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.novacula.io/llms.txt

Use this file to discover all available pages before exploring further.

Novacula has two layers of access control: organization roles for tenant-scoped work, and a separate system role for platform operators. CASL evaluates the active session against both layers on every request.

Organization roles

Every member of an organization holds exactly one role. Roles live on the Member row and follow better-auth’s organization plugin.
RoleWhat they can do
ownerEverything in the org. Manage members (including admins), rotate API keys, deactivate the org, every action below.
adminManage members below their level, manage executors and nodes, configure notifications, create/rotate API keys. Cannot remove or demote the owner.
memberRead-only access to all org-scoped resources: executors, nodes, events, alert incidents, webhook deliveries, notification settings.
Roles are mutually exclusive within an org. A user who needs different permissions for different orgs needs separate org memberships.

System role

A separate role field on the User row controls platform-level access:
  • admin (system admin) — sees all orgs, can impersonate any user, can deactivate organizations, can publish executor releases. Granted exclusively by other system admins.
  • (unset) — default; behavior is controlled entirely by org membership.
System admin is independent of org membership. A system admin who is not a member of org X has admin powers there too, by virtue of the system role.

What requires which role

ActionRequired role
View executors, nodes, events, incidentsAny org role
Create / rotate / revoke API keysowner, admin
Connect a new executorowner, admin
Deploy a node, edit config, lifecycle actions, deleteowner, admin
Request executor / node upgradesowner, admin
Configure org-wide notifications + webhookowner, admin
Invite a member, change member roleowner (for any role); admin (for member ↔ admin only)
Remove a memberowner; admin (cannot remove owner or other admins)
Deactivate the orgowner
Publish executor releasessystem admin
Impersonate a usersystem admin
Deactivate any org from the admin consolesystem admin

How the platform enforces it

  • Authentication. All sessions go through better-auth. UI sessions are cookie-based; executors authenticate with org-scoped API keys (see API keys).
  • Authorization. A CASL ability is built per request from (user.role, session.activeOrganizationId). Repos AND-merge accessibleBy filters into every Prisma query, so a query you’re not allowed to run returns nothing instead of leaking rows.
  • Tenant scope. A non-system-admin user belongs to exactly one organization at a time. activeOrganizationId on the session is the single source of truth — set by login, lifted out of API key metadata for the polling client.

Inviting members

Owners and admins invite members from MembersInvite member. The invitee gets an email; on accept, a Member row is created with the role chosen at invite time. See Members and invitations for the full flow.