# RBAC & Permissions

## Model

- **Roles** contain a set of permissions
- **Users** are assigned one or more roles
- A user's effective permissions are the union of all permissions from all their roles
- Permissions are checked on every GraphQL query and mutation

## Permission Keys

Permissions follow the pattern `domain.action`. Current registry:

| Key | Description |
|-----|-------------|
| `users.read` | View user list and user details |
| `users.create` | Invite new users to the system |
| `users.update` | Edit user details and activation status |
| `users.delete` | Remove users from the system |
| `roles.read` | View roles and their permissions |
| `roles.create` | Create new roles |
| `roles.update` | Edit role details and assigned permissions |
| `roles.delete` | Delete non-system roles |
| `permissions.read` | View all available permissions |
| `invitations.read` | View pending and past invitations |
| `invitations.create` | Send invitations to new users |
| `invitations.revoke` | Revoke pending invitations |
| `audit.read` | View the audit log |

## Superadmin Role

- Name: `Superadmin`
- `isSystem: true` — this flag protects it from modification and deletion
- Always has **all** permissions. When new permissions are added to the registry and the seed runs, they are automatically bound to Superadmin.
- Cannot be renamed, deleted, or have permissions removed via the API
- The `updateRole` and `deleteRole` mutations reject operations on system roles

## Authorization Enforcement

Every resolver calls one of:

- `requireAuth(ctx)` — ensures the user is logged in
- `requirePerm(ctx, "domain.action")` — ensures the user is logged in AND has the specified permission

These are centralized in `src/graphql/context.ts`. Do **not** add ad-hoc permission checks in service layers — all authorization goes through the GraphQL context guards.

## Creating a New Role (Frontend)

```graphql
mutation {
  createRole(input: {
    name: "Warehouse Manager"
    description: "Can manage inventory operations"
    permissionKeys: ["users.read", "roles.read"]
  }) {
    id
    name
    permissions { key description }
  }
}
```

## Assigning Roles

Roles are assigned to users through the invitation flow. When an admin creates an invitation, they specify which role the user should receive. The role is assigned when the user activates their account via OAuth login.
