Overview
Trazea implements a comprehensive role-based access control (RBAC) system where permissions are stored as JSON objects in the roles table. Each role defines granular permissions across different areas of the application.
Role Structure
Role Interface
src/entities/user/model/useUserStore.ts:62-67
interface Role {
id_rol : string ;
nombre : string ;
descripcion : string ;
permissions : AppPermissions ;
}
Available Roles
src/entities/user/model/types.ts:6-10
export enum ROLES {
ADMIN = 'admin' ,
TECNICO = 'tecnico' ,
SUPERVISOR = 'superuser' ,
}
Admin Full Access Complete system control including user management, configuration, and all operational features.
Técnico Operational Access Technical staff access to inventory, spare parts, service requests, and assigned work.
Supervisor Enhanced Access Elevated permissions for oversight, approvals, and cross-location visibility.
Permissions Structure
AppPermissions Interface
Permissions are organized into functional domains:
src/entities/user/model/useUserStore.ts:19-60
export interface AppPermissions {
menu : {
registros : MenuPermissions ;
repuestos : MenuPermissions ;
solicitudes : MenuPermissions ;
inventario : MenuPermissions ;
[ key : string ] : MenuPermissions ;
};
dashboard ?: {
view_global_stats : boolean ;
view_financial_data : boolean ;
};
inventory ?: {
edit_product : boolean ;
create_product : boolean ;
delete_product : boolean ;
view_cost_price : boolean ;
view_all_locations : boolean ;
adjust_stock_manual : boolean ;
view_assigned_location_only : boolean ;
};
logistics ?: {
reject_transfer : boolean ;
view_all_orders : boolean ;
approve_transfer_in : boolean ;
approve_transfer_out : boolean ;
create_transfer_order : boolean ;
};
technical_ops ?: {
assign_to_tech : boolean ;
create_tech_user : boolean ;
receive_from_tech : boolean ;
view_tech_history : boolean ;
};
users_and_access ?: {
create_user : boolean ;
edit_user_roles : boolean ;
view_audit_logs : boolean ;
assign_locations : boolean ;
};
[ key : string ] : unknown ;
}
Permission Domains
Control access to main navigation sections:
src/entities/user/model/useUserStore.ts:7-17
export interface MenuPermissions {
show_view : boolean ;
edit_register ?: boolean ;
show_form_register ?: boolean ;
get_action ?: boolean ;
discontinue ?: boolean ;
send_action ?: boolean ;
button_actions ?: boolean ;
create_register ?: boolean ;
[ key : string ] : boolean | undefined ;
}
Whether the menu item is visible and accessible
Permission to edit existing records in this section
Permission to create new records in this section
Permission to view the registration form
Access to action buttons within this section
Dashboard Permissions
View statistics across all locations
Access to financial reports and cost data
Inventory Permissions
Inventory permissions directly affect what users can do with stock levels and pricing information.
Edit spare part details in the catalog
Add new spare parts to the catalog
Remove spare parts from the catalog
View cost prices and margins
See inventory across all locations (overrides location assignment)
Manually adjust stock levels
view_assigned_location_only
Restrict view to only assigned locations
Logistics Permissions
Create transfer orders between locations
Approve incoming transfers to location
Approve outgoing transfers from location
View transfer orders across all locations
Technical Operations Permissions
Assign work orders to technicians
Receive completed work from technicians
Create new technician accounts
View technician work history and performance
Users & Access Permissions
Critical Security Permissions : These permissions control who can manage users and access controls.
Assign and modify user roles
Assign users to locations via usuarios_localizacion table
Access system audit logs and user activity
Checking Permissions
Using the User Store
The user store provides helper methods for permission checks:
src/entities/user/model/useUserStore.ts:139-148
checkMenuPermission : ( menu : string , permission : string ) => {
const state = get ();
const menuPermissions = state . sessionData ?. user . role ?. permissions ?. menu ;
if ( ! menuPermissions || ! menuPermissions [ menu ]) {
return false ;
}
return !! menuPermissions [ menu ][ permission ];
},
Route-Level Checks
src/entities/user/model/useUserStore.ts:150-160
canViewRoute : ( routeKey : string ) => {
const state = get ();
const menuPermissions = state . sessionData ?. user . role ?. permissions ?. menu ;
if ( ! menuPermissions ) {
return false ;
}
const routePermission = menuPermissions [ routeKey ];
return routePermission ?. show_view === true ;
},
Role Checks
src/entities/user/model/useUserStore.ts:132-137
hasRole : ( roleName : string ) => {
const state = get ();
const userRole = state . sessionData ?. user . role ?. nombre ;
if ( ! userRole ) return false ;
return userRole . toLowerCase (). trim () === roleName . toLowerCase (). trim ();
},
Using Permissions in Components
import { useUserStore } from '@/entities/user' ;
function InventoryActions () {
const { checkMenuPermission } = useUserStore ();
const canEdit = checkMenuPermission ( 'inventario' , 'edit_register' );
const canCreate = checkMenuPermission ( 'inventario' , 'create_register' );
return (
< div >
{ canCreate && (
< Button onClick = { handleCreate } > Add New Part </ Button >
)}
{ canEdit && (
< Button onClick = { handleEdit } > Edit Part </ Button >
)}
</ div >
);
}
Check Domain Permission
import { useUserStore } from '@/entities/user' ;
function PricingDisplay ({ cost } : { cost : number }) {
const { sessionData } = useUserStore ();
const permissions = sessionData ?. user . role ?. permissions ;
const canViewCost = permissions ?. inventory ?. view_cost_price ;
return (
< div >
{ canViewCost ? (
< span > Cost : $ { cost }</ span >
) : (
< span > Cost : Hidden </ span >
)}
</ div >
);
}
Route Protection
import { useUserStore } from '@/entities/user' ;
import { Navigate } from 'react-router-dom' ;
function ProtectedRoute ({ children , requiredRoute } : ProtectedRouteProps ) {
const { canViewRoute } = useUserStore ();
if ( ! canViewRoute ( requiredRoute )) {
return < Navigate to = "/unauthorized" replace />;
}
return <>{ children } </> ;
}
// Usage
< ProtectedRoute requiredRoute = "inventario" >
< InventoryPage />
</ ProtectedRoute >
Configuring Role Permissions
Creating a Role
Define Role Details
Choose a unique nombre and write a clear descripcion.
Build Permissions Object
Create the JSON permissions structure with appropriate access levels.
Insert into Database
Add the role to the roles table with the permissions JSON.
Assign to Users
Update users’ id_rol field to assign the new role.
Example: Creating a Technician Role
{
"menu" : {
"registros" : {
"show_view" : true ,
"edit_register" : false ,
"create_register" : false
},
"repuestos" : {
"show_view" : true ,
"edit_register" : false ,
"create_register" : false
},
"solicitudes" : {
"show_view" : true ,
"edit_register" : true ,
"create_register" : true
},
"inventario" : {
"show_view" : true ,
"edit_register" : false ,
"create_register" : false
}
},
"dashboard" : {
"view_global_stats" : false ,
"view_financial_data" : false
},
"inventory" : {
"edit_product" : false ,
"create_product" : false ,
"delete_product" : false ,
"view_cost_price" : false ,
"view_all_locations" : false ,
"adjust_stock_manual" : false ,
"view_assigned_location_only" : true
},
"technical_ops" : {
"assign_to_tech" : false ,
"create_tech_user" : false ,
"receive_from_tech" : true ,
"view_tech_history" : false
},
"users_and_access" : {
"create_user" : false ,
"edit_user_roles" : false ,
"view_audit_logs" : false ,
"assign_locations" : false
}
}
Example: Creating an Admin Role
{
"menu" : {
"registros" : {
"show_view" : true ,
"edit_register" : true ,
"create_register" : true ,
"button_actions" : true
},
"repuestos" : {
"show_view" : true ,
"edit_register" : true ,
"create_register" : true ,
"discontinue" : true
},
"solicitudes" : {
"show_view" : true ,
"edit_register" : true ,
"create_register" : true ,
"button_actions" : true
},
"inventario" : {
"show_view" : true ,
"edit_register" : true ,
"create_register" : true ,
"button_actions" : true
}
},
"dashboard" : {
"view_global_stats" : true ,
"view_financial_data" : true
},
"inventory" : {
"edit_product" : true ,
"create_product" : true ,
"delete_product" : true ,
"view_cost_price" : true ,
"view_all_locations" : true ,
"adjust_stock_manual" : true ,
"view_assigned_location_only" : false
},
"logistics" : {
"reject_transfer" : true ,
"view_all_orders" : true ,
"approve_transfer_in" : true ,
"approve_transfer_out" : true ,
"create_transfer_order" : true
},
"technical_ops" : {
"assign_to_tech" : true ,
"create_tech_user" : true ,
"receive_from_tech" : true ,
"view_tech_history" : true
},
"users_and_access" : {
"create_user" : true ,
"edit_user_roles" : true ,
"view_audit_logs" : true ,
"assign_locations" : true
}
}
Permissions JSON Storage
Permissions are stored as JSONB in PostgreSQL, allowing flexible querying and indexing.
Database Storage
The roles table structure:
CREATE TABLE roles (
id_rol UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
nombre TEXT NOT NULL UNIQUE ,
descripcion TEXT ,
permissions JSONB NOT NULL ,
created_at TIMESTAMP DEFAULT NOW ()
);
Updating Permissions
To update role permissions:
UPDATE roles
SET permissions = '{
"menu": { ... },
"inventory": { ... },
...
}' ::jsonb
WHERE nombre = 'tecnico' ;
Critical Configuration Step : Always test permission changes in a development environment first. Users must log out and back in for permission changes to take effect.
Best Practices
Principle of Least Privilege
Grant users only the permissions they need to perform their job:
Start with minimal permissions
Add permissions as needed
Regularly review and audit permissions
Remove unused permissions
Create roles based on job functions:
Define clear role boundaries
Avoid too many similar roles
Document what each role can do
Use descriptive role names
Always test permission changes:
Create test users for each role
Verify UI elements show/hide correctly
Test API access restrictions
Check cross-location permissions
Keep your permission structure documented:
List all available permissions
Document what each permission controls
Maintain a permission matrix
Update docs when adding new features
Session Management
Permissions are loaded when users log in:
src/shared/api/fetchUserSessionData.ts:20-24
const { data : rol } = await supabase
. from ( 'roles' )
. select ( '*' )
. eq ( 'id_rol' , user ?. id_rol )
. single ();
The role object (including permissions) is stored in the user session and persisted to localStorage for quick access.
User Management Learn about user creation, approval, and role assignment
Multi-Location Setup Configure location-based access controls