| title | Role Management System |
|---|---|
| description | Developer guide for managing roles and permissions in DeployStack Backend. |
This guide explains how to manage roles and permissions in the DeployStack backend for developers.
DeployStack uses a centralized role-based access control (RBAC) system with automatic synchronization between code definitions and database storage.
All roles and permissions are defined in a single file:
services/backend/src/permissions/index.ts
This is the single source of truth for all role definitions. To see current roles and their permissions, check this file.
The system supports two types of roles:
- Global Roles: System-wide roles (
global_admin,global_user) - Team Roles: Team-specific roles (
team_admin,team_user)
Team roles are assigned within team contexts and work alongside global roles to provide fine-grained access control for team-based resources.
Roles are stored in the roles table with the following structure:
id- Role identifier (e.g., 'global_admin')name- Display name (e.g., 'Global Administrator')description- Role descriptionpermissions- JSON array of permission stringsis_system_role- Boolean flag for core system rolescreated_at/updated_at- Timestamps
User role assignments are stored in the authUser.role_id column.
The system automatically syncs role permissions from code to database on server startup. The RoleSyncService compares the definitions in permissions/index.ts with the database and updates any differences. This ensures the database always matches your code definitions without manual intervention.
Add your new role to services/backend/src/permissions/index.ts:
export const ROLE_DEFINITIONS = {
// ... existing roles
content_moderator: [
'users.view',
'content.moderate',
'reports.view',
],
} as const;If you want the role available immediately in existing databases, create a migration:
-- Add new role to existing databases
INSERT OR IGNORE INTO `roles` (`id`, `name`, `description`, `permissions`, `is_system_role`, `created_at`, `updated_at`) VALUES
('content_moderator', 'Content Moderator', 'Manages user content', '[]', 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000);The RoleSyncService will automatically populate the role's permissions from your code definition on the next server startup.
All permissions are auto-generated from role definitions. The AVAILABLE_PERMISSIONS array in permissions/index.ts contains all unique permissions across all roles, sorted alphabetically.
Use the middleware functions for route protection:
import { requirePermission } from '../middleware/roleMiddleware';
// Require specific permission
fastify.get('/admin-endpoint', {
preValidation: requirePermission('system.admin')
}, handler);For team-based resources, use team-aware permissions:
import { requireTeamPermission } from '../middleware/roleMiddleware';
// Team-specific permission checking
fastify.post('/teams/:teamId/resources', {
preValidation: requireTeamPermission('resources.create')
}, handler);See API Security Best Practices for detailed information about team-aware permissions and security patterns.
import { checkUserPermission } from '../middleware/roleMiddleware';
const hasPermission = await checkUserPermission(userId, 'users.edit');GET /api/roles- List all rolesPOST /api/roles- Create new rolePUT /api/roles/:id- Update roleDELETE /api/roles/:id- Delete role
PUT /api/users/:id/role- Assign role to userGET /api/users/me- Get current user with role info
- Single Source: Always define roles in
permissions/index.ts - Descriptive Names: Use clear permission names with dot notation (
users.edit,content.moderate) - Minimal Permissions: Give roles only the permissions they need
- System Roles: Mark core roles as
is_system_role: trueto prevent deletion - Testing: Test permission changes in development before deploying
- System roles cannot be modified or deleted via API
- Users cannot change their own roles
- The last global administrator cannot be deleted
- All permission checks happen server-side