Users & permissions
Pragma CMS uses a simple and explicit Role-Based Access Control (RBAC) system.
No magic. No hidden rules. Everything is transparent.
Core Concept
A Role is just a collection of Permissions.
A Permission is a string key representing a single action:
product_create
product_read
product_update
product_delete
When you create a Content Type, Pragma automatically generates these four permissions.
How it works
The system is intentionally simple:
- Permissions are stored in the
permissionstable - Roles are stored in the
rolestable - A pivot table
role_permissionslinks roles to permissions - A user is assigned a role
- At runtime, the system checks if the user has a given permission
Runtime Security (Critical)
Permissions are checked at the beginning of every controller and API endpoint:
if (!UserManager::userHasPermission('product_update')) {
displayError(statusCode: 403);
exit();
}
This is not optional.
Security Model Philosophy
Pragma CMS keeps authorization logic explicit and local.
There are no hidden layers between a request and its permission check.
This means:
- no middleware chains
- no implicit rule systems
- no runtime magic
Each controller is responsible for its own security check.
This makes the system:
- predictable at runtime
- easy to debug
- trivial to audit
If you can read the code, you can understand the security model.
UI vs Real Security
The UI in Pragma CMS is not a security layer.
It is only a representation layer.
Permission checks always happen at the server level, inside controllers and API endpoints.
The UI may hide or disable actions for usability, but it never defines access rules.
All access control decisions are enforced independently of the interface.
Permission Design Philosophy
Permissions are:
- granular → one action = one permission
- predictable →
{entity}_{action} - generated automatically → no manual setup needed
This ensures:
- consistency across the system
- zero configuration friction
- no forgotten permissions
Example
A "Shop Manager" role might have:
product_create
product_read
product_update
But not:
product_delete
Result:
- can manage products
- cannot delete them