npm package: @haykal/rbac-backend
Description: > Role-Based Access Control with hierarchy, permission caching, guard decorators, and configurable role seeding.
Latest version: 1.0.0

# @haykal/rbac-backend

> Role-Based Access Control with hierarchy, permission caching, guard decorators, and configurable role seeding.

## Installation

```bash
pnpm add @haykal/rbac-backend
```

## Configuration

### `forRoot()` Options

```typescript
import { RbacModule } from '@haykal/rbac-backend';

@Module({
  imports: [
    RbacModule.forRoot({
      defaultRoles: [
        {
          name: 'admin',
          displayName: 'Administrator',
          permissions: ['*'],
          isSystem: true,
        },
        {
          name: 'user',
          displayName: 'Regular User',
          permissions: ['profile.read', 'profile.update'],
          isSystem: true,
          isDefault: true,
        },
      ],
      superAdminRole: 'superadmin',
      permissionCacheTtlSeconds: 300,
    }),
  ],
})
export class AppModule {}
```

| Property                    | Type               | Default        | Description                                   |
| --------------------------- | ------------------ | -------------- | --------------------------------------------- |
| `defaultRoles`              | `RoleDefinition[]` | `[]`           | Roles to seed on startup                      |
| `superAdminRole`            | `string`           | `'superadmin'` | Role name that bypasses all permission checks |
| `permissionCacheTtlSeconds` | `number`           | `300`          | Redis cache TTL for user permissions          |

**`RoleDefinition`:**

| Property      | Type       | Description                           |
| ------------- | ---------- | ------------------------------------- |
| `name`        | `string`   | Unique role identifier                |
| `displayName` | `string`   | Human-readable name                   |
| `description` | `string?`  | Optional description                  |
| `permissions` | `string[]` | Permission keys (`['*']` = all)       |
| `isSystem`    | `boolean?` | Cannot be modified/deleted            |
| `isDefault`   | `boolean?` | Auto-assigned to new users            |
| `parentRole`  | `string?`  | Parent role for hierarchy/inheritance |

## Key Exports

| Export                  | Type          | Description                                                 |
| ----------------------- | ------------- | ----------------------------------------------------------- |
| `RbacModule`            | NestJS Module | Main module with `forRoot()` / `forRootAsync()`             |
| `RBAC_CONFIG`           | Symbol        | Inject the config object                                    |
| `RbacService`           | Service       | Full RBAC management (roles, permissions, user assignments) |
| `PermissionsGuard`      | Guard         | Check route-level permission requirements                   |
| `RolesGuard`            | Guard         | Check route-level role requirements                         |
| `@RequirePermissions()` | Decorator     | Declare permission requirements on a route                  |
| `@RequireRoles()`       | Decorator     | Declare role requirements on a route                        |
| `RBAC_ENTITIES`         | Array         | Entities for migration discovery                            |

### Entities

| Entity                 | Table                   | Description                          |
| ---------------------- | ----------------------- | ------------------------------------ |
| `RoleEntity`           | `rbac_roles`            | Role definitions with hierarchy      |
| `PermissionEntity`     | `rbac_permissions`      | Permission definitions with grouping |
| `RolePermissionEntity` | `rbac_role_permissions` | Role-to-permission join table        |
| `UserRoleEntity`       | `rbac_user_roles`       | User-to-role assignments with audit  |

### Domain Errors

| Error                          | Code                              | Status | Description               |
| ------------------------------ | --------------------------------- | ------ | ------------------------- |
| `RoleNotFoundError`            | `RBAC_ROLE_NOT_FOUND`             | 404    | Role not found            |
| `RoleAlreadyExistsError`       | `RBAC_ROLE_ALREADY_EXISTS`        | 409    | Duplicate role name       |
| `SystemRoleError`              | `RBAC_SYSTEM_ROLE_IMMUTABLE`      | 403    | Cannot modify system role |
| `PermissionNotFoundError`      | `RBAC_PERMISSION_NOT_FOUND`       | 404    | Permission not found      |
| `InsufficientPermissionsError` | `RBAC_INSUFFICIENT_PERMISSIONS`   | 403    | Missing permissions       |
| `InsufficientRolesError`       | `RBAC_INSUFFICIENT_ROLES`         | 403    | Missing roles             |
| `CircularRoleHierarchyError`   | `RBAC_CIRCULAR_HIERARCHY`         | 422    | Circular parent chain     |
| `UserRoleAlreadyAssignedError` | `RBAC_USER_ROLE_ALREADY_ASSIGNED` | 409    | Duplicate role assignment |

### Domain Events

| Event                         | Payload                                                        |
| ----------------------------- | -------------------------------------------------------------- |
| `RoleCreatedEvent`            | `roleId`, `roleName`                                           |
| `RoleUpdatedEvent`            | `roleId`, `roleName`, `changes`                                |
| `RoleDeletedEvent`            | `roleId`, `roleName`                                           |
| `RolePermissionsChangedEvent` | `roleId`, `roleName`, `addedPermissions`, `removedPermissions` |
| `UserRoleAssignedEvent`       | `userId`, `roleId`, `roleName`, `assignedBy`                   |
| `UserRoleRemovedEvent`        | `userId`, `roleId`, `roleName`                                 |

## API Endpoints

All endpoints require JWT authentication. Grouped under `/api/rbac`.

### Roles (`/rbac/roles`)

| Method   | Path                          | Description                        |
| -------- | ----------------------------- | ---------------------------------- |
| `GET`    | `/rbac/roles`                 | List all roles                     |
| `POST`   | `/rbac/roles`                 | Create a new role                  |
| `GET`    | `/rbac/roles/:id`             | Get role details                   |
| `PATCH`  | `/rbac/roles/:id`             | Update a role                      |
| `DELETE` | `/rbac/roles/:id`             | Delete a non-system role           |
| `GET`    | `/rbac/roles/:id/permissions` | Get role permissions               |
| `PUT`    | `/rbac/roles/:id/permissions` | Set role permissions (replace all) |
| `POST`   | `/rbac/roles/:id/permissions` | Add permissions to role            |
| `DELETE` | `/rbac/roles/:id/permissions` | Remove permissions from role       |

### Permissions (`/rbac/permissions`)

| Method | Path                | Description                                        |
| ------ | ------------------- | -------------------------------------------------- |
| `GET`  | `/rbac/permissions` | List all permissions (`?grouped=true` for grouped) |

### User Roles (`/rbac/users`)

| Method   | Path                                | Description                    |
| -------- | ----------------------------------- | ------------------------------ |
| `GET`    | `/rbac/users/:userId/roles`         | Get user's roles               |
| `PUT`    | `/rbac/users/:userId/roles`         | Set user's roles (replace all) |
| `POST`   | `/rbac/users/:userId/roles`         | Add role(s) to user            |
| `DELETE` | `/rbac/users/:userId/roles/:roleId` | Remove role from user          |

### My RBAC (`/rbac/me`)

| Method | Path                   | Description                                  |
| ------ | ---------------------- | -------------------------------------------- |
| `GET`  | `/rbac/me/permissions` | Current user's effective permissions         |
| `GET`  | `/rbac/me/roles`       | Current user's roles                         |
| `GET`  | `/rbac/me/check`       | Check permissions (`?permissions=key1,key2`) |

## Usage Examples

### Protecting Routes with Permissions

```typescript
import { RequirePermissions, RequireRoles } from '@haykal/rbac-backend';

@Controller('orders')
export class OrdersController {
  @RequirePermissions('orders.create')
  @Post()
  async create() {
    /* ... */
  }

  @RequireRoles('admin')
  @Delete(':id')
  async delete() {
    /* ... */
  }
}
```

### Registering Domain Permissions

```typescript
import { RbacService } from '@haykal/rbac-backend';

@Module({})
export class OrdersModule implements OnModuleInit {
  constructor(private rbacService: RbacService) {}

  async onModuleInit() {
    await this.rbacService.registerPermissions([
      { key: 'orders.create', displayName: 'Create Orders', group: 'orders' },
      { key: 'orders.read', displayName: 'Read Orders', group: 'orders' },
      { key: 'orders.update', displayName: 'Update Orders', group: 'orders' },
      { key: 'orders.delete', displayName: 'Delete Orders', group: 'orders' },
    ]);
  }
}
```

## Related Packages

- `@haykal/rbac-client` — React Query hooks for RBAC
- `@haykal/auth-backend` — JWT auth (RBAC guards layer on top)
- `@haykal/core-backend` — Base infrastructure

## Further Reading

- [API Reference](../../../docs/api-reference.md) — Full endpoint listing
- [Architecture Overview](../../../docs/architecture.md) — System design and module composition
- [Backend Style Guide](../../../docs/backend-styleguide.md) — Coding conventions