Overview
Luis IT Repair uses a role-based permission system to control access to different features and workflows. Each user is assigned a role, and each role has specific permissions that determine what actions they can perform.
Role Hierarchy
The system includes three predefined roles:
const ROLES = {
Administrador: "Full system access" ,
Tecnico: "Service and client management" ,
Cajero: "Sales and inventory management"
};
Permission Catalog
All available permissions are defined in a central catalog:
export const PERMISOS_CATALOGO = [
{
key: "servicios.crear" ,
label: "Dar de alta servicios" ,
description: "Permite abrir y usar la pantalla de hoja de servicio."
},
{
key: "servicios.ver" ,
label: "Ver servicios" ,
description: "Permite acceder al listado y detalle de servicios."
},
{
key: "clientes.ver" ,
label: "Ver clientes" ,
description: "Permite entrar a clientes y su detalle."
},
{
key: "ventas.pos" ,
label: "Usar POS" ,
description: "Permite entrar a Punto de Venta y cobrar."
},
{
key: "productos.ver" ,
label: "Ver productos" ,
description: "Permite abrir y gestionar productos."
},
{
key: "reportes.ver" ,
label: "Ver reportes" ,
description: "Permite acceder al apartado de reportes."
},
{
key: "configuracion.ver" ,
label: "Entrar a configuracion" ,
description: "Permite entrar al modulo de configuracion."
},
{
key: "empleados.gestionar" ,
label: "Gestionar empleados" ,
description: "Permite crear, editar y eliminar empleados."
}
];
See: src/js/services/permisos.js:2-43
Default Role Permissions
Administrador
Full access to all system features:
Administrador : {
"servicios.crear" : true ,
"servicios.ver" : true ,
"clientes.ver" : true ,
"ventas.pos" : true ,
"productos.ver" : true ,
"reportes.ver" : true ,
"configuracion.ver" : true ,
"empleados.gestionar" : true
}
Administrador Role
Create and manage service tickets
View all services and clients
Access POS for sales
Manage product inventory
View all reports
Configure system settings
Manage employee accounts and permissions
Técnico (Technician)
Focused on service and repair workflows:
Tecnico : {
"servicios.crear" : true ,
"servicios.ver" : true ,
"clientes.ver" : true ,
"ventas.pos" : false ,
"productos.ver" : false ,
"reportes.ver" : false ,
"configuracion.ver" : false ,
"empleados.gestionar" : false
}
Técnico Role
Create service tickets (Hoja de Servicio)
View and update service status
View client information
Cannot access POS or process sales
Cannot view inventory or reports
Cannot modify system configuration
Technicians can see client data to create services but cannot manage the client records directly or access sales features.
Cajero (Cashier)
Focused on sales and inventory:
Cajero : {
"servicios.crear" : false ,
"servicios.ver" : false ,
"clientes.ver" : true ,
"ventas.pos" : true ,
"productos.ver" : true ,
"reportes.ver" : true ,
"configuracion.ver" : false ,
"empleados.gestionar" : false
}
Cajero Role
Process sales in POS
Manage product inventory
View sales reports
Lookup client information for sales
Cannot create service tickets
Cannot view service details
Cannot modify system configuration
Cashiers can charge for completed services in POS but cannot view service details or create new service tickets.
Permission Checking
The system provides utility functions for permission validation:
Basic Permission Check
export function tienePermiso ( rol = "" , permisos = {}, key = "" ) {
// Administrators always have access
if ( normalizarRol ( rol ) === "Administrador" ) return true ;
// Check normalized permissions
const normalized = normalizarPermisos ( rol , permisos );
return bool ( normalized [ key ]);
}
Usage:
if ( tienePermiso ( userRole , userPermisos , "servicios.crear" )) {
// Show "Create Service" button
}
Role Normalization
Handles text variations and accents:
function normalizarRol ( raw = "" ) {
const key = String ( raw || "" )
. toLowerCase ()
. normalize ( "NFD" )
. replace ( / [ \u0300 - \u036f ] / g , "" ) // Remove accents
. trim ();
if ( key === "administrador" ) return "Administrador" ;
if ( key === "tecnico" ) return "Tecnico" ; // Works with or without accent
if ( key === "cajero" ) return "Cajero" ;
return "" ;
}
This ensures “Técnico” and “Tecnico” are treated identically.
See: src/js/services/permisos.js:86-97
Route Protection
Routes are protected using the PermissionRoute component:
import PermissionRoute from "../components/PermissionRoute" ;
< Route
path = "/hoja-servicio"
element = {
< PermissionRoute
permission = "servicios.crear"
fallbackPath = "/home"
>
< HojaServicio />
</ PermissionRoute >
}
/>
Component Implementation:
export default function PermissionRoute ({
permission = "" ,
fallbackPath = "/home" ,
children
}) {
const { loading , activo , puede } = useAutorizacionActual ();
if ( loading ) return < div > Cargando... </ div > ;
if ( ! activo ) return < Navigate to = "/login" replace /> ;
if ( permission && ! puede ( permission )) {
return < Navigate to = { fallbackPath } replace /> ;
}
return children ;
}
See: src/components/PermissionRoute.jsx
Flow:
Check if user authorization is still loading
Redirect to login if user is not active
Check if user has required permission
Redirect to fallback path if permission denied
Render protected content if authorized
User Authorization Hook
The useAutorizacionActual hook provides current user’s permissions:
const { loading , activo , puede , autorizacion } = useAutorizacionActual ();
// Check specific permission
if ( puede ( "ventas.pos" )) {
// Show POS menu item
}
Hook provides:
loading: Boolean indicating if auth is still loading
activo: Boolean if user account is active
puede(permission): Function to check specific permission
autorizacion: Full authorization object with role and permissions
See: src/hooks/useAutorizacionActual.js
Custom Permission Overrides
Administrators can customize permissions per user:
export function normalizarPermisos ( rol = "" , raw = {}) {
const base = permisosBasePorRol ( rol ); // Get role defaults
const result = { ... base };
// Apply custom overrides
PERMISOS_CATALOGO . forEach (( p ) => {
if ( Object . prototype . hasOwnProperty . call ( raw || {}, p . key )) {
result [ p . key ] = bool ( raw [ p . key ]);
}
});
return result ;
}
Example: Custom Technician with POS Access
{
uid : "user-123" ,
rol : "Tecnico" ,
permisos : {
"ventas.pos" : true // Override: this technician can use POS
}
}
The normalized permissions will merge:
Base “Tecnico” permissions
Plus the custom ventas.pos: true override
Permission-Based UI Rendering
import { useAutorizacionActual } from "../hooks/useAutorizacionActual" ;
function Navigation () {
const { puede } = useAutorizacionActual ();
return (
< nav >
{ puede ( "servicios.crear" ) && (
< NavLink to = "/hoja-servicio" > Nuevo Servicio </ NavLink >
) }
{ puede ( "servicios.ver" ) && (
< NavLink to = "/servicios" > Ver Servicios </ NavLink >
) }
{ puede ( "ventas.pos" ) && (
< NavLink to = "/pos" > Punto de Venta </ NavLink >
) }
{ puede ( "reportes.ver" ) && (
< NavLink to = "/reportes" > Reportes </ NavLink >
) }
{ puede ( "configuracion.ver" ) && (
< NavLink to = "/configuracion" > Configuración </ NavLink >
) }
</ nav >
);
}
Common Permission Scenarios
Scenario 1: Technician Needs POS Access
Administrator opens employee management
Edits the technician’s user record
Toggles custom permission: ventas.pos: true
Saves changes
Technician can now access POS while keeping service creation access
Scenario 2: Cashier Needs Service View
Edit cashier user record
Enable custom permission: servicios.ver: true
Cashier can now view service details when processing payments
Still cannot create new service tickets
Scenario 3: Limited Administrator
Create user with “Administrador” role
Add custom restriction: empleados.gestionar: false
User has full access except employee management
Useful for trusted senior staff without HR access
Best Practices
Principle of Least Privilege Grant only the permissions necessary for each user’s job function.
Review Regularly Periodically audit user permissions, especially after role changes.
Document Overrides Keep notes on why custom permissions were granted to specific users.
Test Permission Changes After modifying permissions, have the user test all affected features.
Administrator Bypass
Users with “Administrador” role ALWAYS have all permissions, regardless of custom overrides. The permission check short-circuits: if ( normalizarRol ( rol ) === "Administrador" ) return true ;
You cannot restrict administrator access through the permission system.
Security Considerations
Client-Side vs Server-Side
The permission checks shown here are client-side (UI hiding). For true security, implement matching server-side validation in Firebase Security Rules or Cloud Functions.
Example Firebase Security Rule:
match / servicios / { servicioId } {
allow create : if request . auth != null
&& get ( / databases / $ ( database ) / documents / empleados / $ ( request . auth . uid ))
. data . permisos [ "servicios.crear" ] == true ;
}
Permission Validation in API
For Cloud Functions:
const { rol , permisos } = await getEmpleadoData ( context . auth . uid );
if ( ! tienePermiso ( rol , permisos , "ventas.pos" )) {
throw new functions . https . HttpsError (
'permission-denied' ,
'No tienes permiso para procesar ventas'
);
}
Troubleshooting
User can’t access a feature they should have access to?
Verify their role is spelled correctly (case-sensitive)
Check for custom permission overrides blocking access
Ensure user account is activo: true
Have user log out and log back in to refresh permissions
Check browser console for PermissionRoute redirect logs
Administrador can’t access employee management?
Should never happen with default role
Check if custom override empleados.gestionar: false exists
Remember: admin role bypasses most checks, but UI may respect overrides
Permission changes not taking effect?
User needs to refresh their session
Clear browser localStorage
Check if autorizacion hook is using cached data
Verify Firestore empleados collection was updated
Navigation shows links but routes redirect?
UI check (puede()) and route protection may use different data sources
Ensure both useAutorizacionActual and PermissionRoute are consistent
Check for race conditions in loading states