Permissions
This guide explains how to add new permissions to the application. We use spatie/laravel-permission for role/permission management.Key Concepts
- We use both roles and permissions, but always check against permissions, never roles
- Roles are just containers for permissions
- We use one permission per model (e.g., “manage_users”) rather than CRUD-level permissions
- Permissions are defined as enums and synced to TypeScript via
composer generate-ts - Permissions are automatically synced from both
CorePermissionandapp/Enums/Permissionenums - Role permissions are defined declaratively in the
permissions()method on the Role enum
Adding a New Permission
-
Add the permission to
app/Enums/Permission.php: -
Add the permission label in the same file:
-
Map the model to its permission if applicable:
-
Update role permissions in
app/Enums/Role.phpby adding them to the appropriate role’spermissions()method: -
Generate TypeScript types:
-
Run the permissions command to sync to database:
permissions:generate command will automatically:
- Create/update all permissions from both
CorePermissionandapp/Enums/Permission - Delete permissions that no longer exist in either enum
- Create all roles from
app/Enums/Role - Sync permissions to roles based on their
permissions()method
Usage
Backend
Frontend
AI Instruction
Follow this step-by-step guide if you’re an AI that has been asked to add a new permission for a model:-
Add the permission case to
app/Enums/Permission.php:- Add the case constant (e.g.,
case MANAGE_ORDERS = 'manage_orders';) - Add the label in the
label()method (e.g.,self::MANAGE_ORDERS => __('Manage orders'),)
- Add the case constant (e.g.,
-
Update
app/Enums/Role.phpto grant the permission to appropriate roles:- Edit the
permissions()method - Add the permission to the relevant role(s) (e.g.,
self::STAFF => [Permission::MANAGE_ORDERS]) - ADMIN and DEVELOPER roles typically have
'*'(all permissions)
- Edit the
-
Generate TypeScript types and sync permissions:
-
Implement the permission checks:
- Backend: Add
$this->authorize(Permission::YOUR_PERMISSION->value)to relevant controllers - Frontend: Use
usePermissionhook component where needed - Remember to check permissions in both API endpoints and UI components
- Backend: Add