Overview
PROD-SYS implements a role-based access control (RBAC) system where:
Users are assigned System Roles (Administrador, Inspector, Supervisor, etc.)
Roles have Permissions (MANAGE_STAFF, VIEW_PRODUCTION, etc.)
Permissions gate access to API endpoints and system features
Authorization checks occur on every authenticated request
Permission Model
Permission Categories
Permissions are organized by functional domain:
Personnel & Users
Permission Description Grants Access To VIEW_STAFFView personnel information GET /api/personnel/personal, GET /api/personnel/personal/:id MANAGE_STAFFFull personnel management POST /api/personnel/personal, PUT /api/personnel/personal/:id, password reset, role assignment
Production
Permission Description Grants Access To VIEW_PRODUCTIONView production data GET production orders, shift logs, work records MANAGE_PRODUCTIONCreate/edit production records POST/PUT production data, register work ASSIGN_OPERATIONSAssign personnel to machines POST /api/personnel/personal/:id/asignar-operacion
Quality
Permission Description Grants Access To VIEW_QUALITYView quality data GET samples, defects, quality inspections MANAGE_QUALITYRecord quality data POST/PUT quality records, sample results
Machines
Permission Description Grants Access To VIEW_MACHINESView machine information GET /api/maquinas MANAGE_MACHINESManage machine configuration POST/PUT machine status, configuration
System
Permission Description Grants Access To VIEW_AUDITAccess audit logs GET /api/auditoria VIEW_PROCESSESView process definitions GET process catalogs
Location : backend/shared/auth/permissions.js:1-22
System Roles
Role Definitions
Administrador
Access Level : Full system access
Permissions : All permissions (wildcard)
Use Cases :
System configuration
User account management
Access to all modules
Audit log review
Emergency overrides
Assignment : Only for IT staff and executive management
'Administrador' : Object . values ( PERMISSIONS )
Location : backend/shared/auth/permissions.js:25
Inspector
Access Level : Full operational access (except system config)
Permissions :
VIEW_STAFF, MANAGE_STAFF
VIEW_PRODUCTION, MANAGE_PRODUCTION
VIEW_QUALITY, MANAGE_QUALITY
VIEW_MACHINES, MANAGE_MACHINES
VIEW_PROCESSES
VIEW_AUDIT
Use Cases :
Quality department supervisors
Shift inspectors with full authority
Production coordinators
Personnel management for their area
Cannot :
Modify system configuration
Create/delete roles
Access low-level system settings
Location : backend/shared/auth/permissions.js:26-37
Supervisor
Access Level : Production oversight and personnel assignment
Permissions :
VIEW_STAFF
VIEW_PRODUCTION
ASSIGN_OPERATIONS
VIEW_QUALITY
VIEW_MACHINES
VIEW_PROCESSES
Use Cases :
Shift supervisors
Team leaders
Assigning operators to machines
Monitoring production progress
Cannot :
Register or modify personnel data
Edit quality records
Change machine configuration
Access audit logs
Location : backend/shared/auth/permissions.js:38-45
Jefe de Operaciones
Access Level : Operations management
Permissions :
VIEW_STAFF, MANAGE_STAFF
VIEW_PRODUCTION
VIEW_QUALITY
VIEW_MACHINES, MANAGE_MACHINES
VIEW_PROCESSES
Use Cases :
Operations managers
Plant engineers
Maintenance coordinators
Machine configuration
Cannot :
Assign day-to-day operations
Edit production or quality records directly
Access audit logs
Location : backend/shared/auth/permissions.js:46-54
Gerencia
Access Level : Executive read-only access
Permissions :
VIEW_STAFF
VIEW_PRODUCTION
VIEW_QUALITY
VIEW_MACHINES
VIEW_AUDIT
VIEW_PROCESSES
Use Cases :
Executive management
Business intelligence access
Compliance review
Strategic planning
Cannot :
Make any system changes
Create or edit any records
Manage personnel or operations
Location : backend/shared/auth/permissions.js:55-62
Operario
Access Level : Production floor operators
Permissions :
VIEW_PRODUCTION
MANAGE_PRODUCTION
Use Cases :
Machine operators
Production line workers
Recording work output
Shift data entry
Cannot :
View or manage personnel
Configure machines
Assign operations
Access quality module (except recording during production)
Location : backend/shared/auth/permissions.js:63-66
Authorization Flow
Middleware Stack
Every protected endpoint uses this middleware chain:
router . get ( '/api/personnel/personal' ,
authMiddleware , // 1. Verify JWT and session
authorize ( PERMISSIONS . VIEW_STAFF ), // 2. Check permission
controller . getAllStaff // 3. Execute handler
);
1. Authentication Middleware
File : backend/middlewares/auth.middleware.js
Process :
Development Bypass (if DISABLE_AUTH_CHECKS=true):
if ( process . env . DISABLE_AUTH_CHECKS === 'true' ) {
req . user = { id: 1 , usuario_id: 1 , username: 'admin' , rol: 'Administrador' };
return next ();
}
Token Extraction :
Check Authorization: Bearer <token> header
Fallback to token cookie
Token Verification :
Verify JWT signature with JWT_SECRET
Extract user payload (id, username, role)
Real-time Status Check :
const user = await sqlite . get (
'SELECT estado_usuario FROM usuarios WHERE id = ?' ,
[ decoded . usuario_id ]
);
if ( ! user || user . estado_usuario !== 'Activo' ) {
return next ( new ForbiddenError ( 'Su cuenta ha sido desactivada' ));
}
Attach to Request :
req . user = decoded ; // Available in all downstream handlers
Location : backend/middlewares/auth.middleware.js:8-53
2. Authorization Middleware
File : backend/middlewares/authorize.js
Function Signature :
const authorize = ( ... requirements ) => {
return ( req , res , next ) => {
// Authorization logic
};
};
Process :
Verify Authentication :
if ( ! req . user ) {
return next ( new UnauthorizedError ( 'Usuario no autenticado' ));
}
Development Bypass (if DISABLE_AUTH_CHECKS=true):
if ( process . env . DISABLE_AUTH_CHECKS === 'true' ) {
return next (); // Skip permission checks
}
Permission Check :
const userRole = req . user . rol ;
const isAuthorized = requirements . some ( reqmt => {
// Direct role match
if ( reqmt === userRole ) return true ;
// Admin alias
if ( reqmt === 'ADMIN' && userRole === 'Administrador' ) return true ;
// Permission check via role mapping
if ( hasPermission ( userRole , reqmt )) return true ;
return false ;
});
Enforce or Deny :
if ( ! isAuthorized ) {
return next ( new ForbiddenError ( 'No tiene permisos para realizar esta acción' ));
}
next (); // Authorized, proceed to handler
Location : backend/middlewares/authorize.js:9-41
Permission Resolution
Helper Function : hasPermission(role, permission)
const hasPermission = ( role , permission ) => {
if ( ! role || ! permission ) return false ;
const permissions = ROLE_PERMISSIONS [ role ] || [];
return permissions . includes ( permission );
};
Lookup : ROLE_PERMISSIONS object maps role names to permission arrays
Location : backend/shared/auth/permissions.js:69-73
Development Mode
Disabling Authorization
Environment Variable : DISABLE_AUTH_CHECKS=true
Effect :
Authentication middleware injects admin user automatically
Authorization middleware always grants access
All users effectively have Administrador role
Use Cases :
Local development (faster iteration)
Integration testing (avoid auth setup)
System bootstrapping (first-time setup)
Location :
backend/middlewares/auth.middleware.js:9-12
backend/middlewares/authorize.js:21-23
NEVER deploy to production with DISABLE_AUTH_CHECKS=true. This completely bypasses all security controls.
Enabling Authorization
In Production :
# .env
DISABLE_AUTH_CHECKS = false
NODE_ENV = production
Effect :
Full RBAC enforcement
Real user authentication required
Permission checks active on every request
API Protection Examples
Personnel Management
// backend/domains/personal/personal.routes.js
// View personnel list - requires VIEW_STAFF
router . get ( '/' ,
authMiddleware ,
authorize ( PERMISSIONS . VIEW_STAFF ),
controller . getAllStaff
);
// Register new personnel - requires MANAGE_STAFF
router . post ( '/' ,
authMiddleware ,
authorize ( PERMISSIONS . MANAGE_STAFF ),
controller . registerStaff
);
// Assign role - requires MANAGE_STAFF
router . post ( '/:id/asignar-rol' ,
authMiddleware ,
authorize ( PERMISSIONS . MANAGE_STAFF ),
controller . assignRole
);
// Assign to operation - requires ASSIGN_OPERATIONS
router . post ( '/:id/asignar-operacion' ,
authMiddleware ,
authorize ( PERMISSIONS . ASSIGN_OPERATIONS ),
controller . assignOperation
);
Audit Logs
// backend/shared/audit/audit.routes.js
router . get ( '/' ,
authMiddleware ,
authorize ( PERMISSIONS . VIEW_AUDIT ), // Only Administrador, Inspector, Gerencia
async ( req , res , next ) => {
const { usuario , entidad , fecha } = req . query ;
const logs = await auditService . getAll ({ usuario , entidad , fecha });
return sendSuccess ( res , logs );
}
);
Location : backend/shared/audit/audit.routes.js:14-26
Authentication Endpoints
// backend/domains/auth/auth.routes.js
// Login - no authentication required (public)
router . post ( '/login' , controller . login );
// Change password - authentication required, no specific permission
router . post ( '/change-password' ,
authMiddleware , // Only verify user is logged in
controller . changePassword
);
Role Management
Viewing Roles
Endpoint : GET /api/personnel/personal/catalogos
Permission : VIEW_STAFF
Returns :
{
"success" : true ,
"data" : {
"areas" : [
{ "id" : 1 , "nombre" : "Producción" },
{ "id" : 2 , "nombre" : "Departamento de Calidad" }
],
"roles" : [
{ "id" : 1 , "nombre" : "Inspector" },
{ "id" : 2 , "nombre" : "Supervisor" },
{ "id" : 6 , "nombre" : "Administrador" }
]
}
}
Location : backend/domains/personal/personal.service.js:235-239
Assigning Roles
Endpoint : POST /api/personnel/personal/:id/asignar-rol
Permission : MANAGE_STAFF
Request :
{
"rol_id" : 2 ,
"motivo_cambio" : "Promoción a Supervisor de Turno" ,
"es_correccion" : false
}
Process :
Updates usuarios.rol_id
Creates history entry in persona_roles table
Logs to audit trail with ROLE_CHANGE action
New permissions take effect on user’s next request
Location : backend/domains/personal/personal.service.js:241-270
Role History
Role assignments are tracked in persona_roles table:
CREATE TABLE persona_roles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
persona_id INTEGER NOT NULL ,
rol_id INTEGER NOT NULL ,
fecha_asignacion DATETIME DEFAULT CURRENT_TIMESTAMP,
asignado_por INTEGER ,
activo BOOLEAN DEFAULT 1 ,
motivo_cambio TEXT ,
FOREIGN KEY (persona_id) REFERENCES personas(id),
FOREIGN KEY (rol_id) REFERENCES roles(id),
FOREIGN KEY (asignado_por) REFERENCES personas(id)
);
Location : backend/database/sqlite.js:1115-1126
Adding New Permissions
1. Define Permission Constant
// backend/shared/auth/permissions.js
const PERMISSIONS = {
// Existing permissions...
// New permission
MANAGE_REPORTS: 'MANAGE_REPORTS' ,
};
2. Assign to Roles
const ROLE_PERMISSIONS = {
'Administrador' : Object . values ( PERMISSIONS ), // Gets it automatically
'Inspector' : [
// Existing permissions...
PERMISSIONS . MANAGE_REPORTS , // Add explicitly
],
'Gerencia' : [
// Gerencia only views
]
};
3. Protect Endpoints
// In your route file
const { PERMISSIONS } = require ( '../../shared/auth/permissions' );
const authorize = require ( '../../middlewares/authorize' );
router . post ( '/api/reports/generate' ,
authMiddleware ,
authorize ( PERMISSIONS . MANAGE_REPORTS ),
controller . generateReport
);
Adding New Roles
1. Add to Database
INSERT INTO roles (nombre) VALUES ( 'Analista de Datos' );
2. Define Permissions
// backend/shared/auth/permissions.js
const ROLE_PERMISSIONS = {
// Existing roles...
'Analista de Datos' : [
PERMISSIONS . VIEW_STAFF ,
PERMISSIONS . VIEW_PRODUCTION ,
PERMISSIONS . VIEW_QUALITY ,
PERMISSIONS . VIEW_AUDIT ,
PERMISSIONS . MANAGE_REPORTS
]
};
3. Assign to Users
Use the standard role assignment endpoint:
curl -X POST http://localhost:3000/api/personnel/personal/5/asignar-rol \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{
"rol_id": 7,
"motivo_cambio": "Asignación a nuevo rol de Analista de Datos"
}'
Security Best Practices
Principle of Least Privilege
Separation of Duties
Role Assignment Hygiene
Development vs Production
Troubleshooting
403 Forbidden Errors
Symptoms : User is authenticated but cannot access endpoint
Check :
User’s Current Role :
SELECT u . username , r . nombre as rol
FROM usuarios u
JOIN roles r ON u . rol_id = r . id
WHERE u . username = 'username' ;
Required Permission :
Check route definition for authorize(...) parameter
Example: authorize(PERMISSIONS.MANAGE_STAFF)
Role Permission Mapping :
// In backend/shared/auth/permissions.js
console . log ( ROLE_PERMISSIONS [ 'Inspector' ]);
// Should include required permission
Development Mode :
# Check .env
DISABLE_AUTH_CHECKS = true # Should be false in production
Permission Changes Not Taking Effect
Cause : User’s JWT token contains cached role information
Solution :
User must log out and log back in
New JWT will contain updated role
Permissions checked fresh on each request
Alternative : Implement token revocation mechanism (not currently in system)
Unauthorized Despite Correct Role
Check :
Token Validity :
Verify JWT_SECRET hasn’t changed
Check token expiration (8 hours)
Inspect token payload: jwt.io
Account Status :
SELECT estado_usuario FROM usuarios WHERE id = ?;
Persona Status :
SELECT estado_laboral FROM personas WHERE id = ?;
Must be Activo (not Incapacitado, Inactivo, or Baja)
User Management Creating and managing user accounts
Audit Logs Tracking role assignments and access
Configuration Security settings and environment variables