Files
whatsapp/modules/soporte/docs/arquitectura/30-roles-y-permisos.md
Lizandro GuarnizoandClaude Opus 5 fe96e5b60d Documentación en usted, y panel de LIA con el mismo diseño del dashboard
Toda la documentación pasa de voseo a tratamiento de usted, incluidos los
diagramas y los textos de la interfaz. Los prompts de ambos asistentes lo
piden explícitamente, para que las respuestas generadas también lo respeten.

El panel de LIA en la página de documentación adopta el diseño del dashboard
del turnero: mismo botón circular, mismo panel deslizante con encabezado en
degradado y logo LIA, mismos chips de atajo, burbujas y campo de entrada.
Los atajos se arman con los documentos que ese usuario puede ver.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 10:57:28 -05:00

4.3 KiB

Roles y permisos

Quién puede ver y hacer qué. Es el punto donde más seguido se cometen errores, así que conviene entenderlo completo.

Las dos columnas de un usuario

En admin_users conviven dos campos que parecen redundantes y no lo son:

Columna Para qué se usa
role Texto del rol (admin, bacteriologo, …). Lo consultan las vistas para decidir qué mostrar
role_id Apunta a roles.id. Es de donde se cargan los módulos al iniciar sesión

Hay que mantener las dos sincronizadas. Cambiar solo role deja al usuario con los permisos viejos, porque el acceso real sale de role_id. Este error ya ocurrió: un usuario cambió de rol, la interfaz mostraba el rol nuevo y los módulos seguían siendo los anteriores.

Al cambiar el rol de alguien, actualice las dos a la vez:

UPDATE admin_users
   SET role = 'lab_recepcion',
       role_id = (SELECT id FROM roles WHERE slug = 'lab_recepcion')
 WHERE id = 12;

Cómo se arma el acceso al iniciar sesión

authenticateUser() (config/config.php) valida la contraseña y arma la sesión:

admin_users.role_id
   └── role_modules  →  lista de module_slug + permission
         └── $_SESSION['admin_user']['modules']              (qué módulos ve)
             $_SESSION['admin_user']['module_permissions']   (read o write en cada uno)

Esto ocurre una sola vez, al entrar. Cualquier cambio en role_modules no afecta a las sesiones abiertas: el usuario tiene que cerrar sesión y volver a entrar.

Las dos preguntas del control de acceso

hasModule('lab_domicilios')       // ¿puede entrar al módulo?
hasModuleWrite('lab_domicilios')  // ¿puede modificar, o solo mirar?
  • hasModule() mira si el slug está en la lista de módulos de la sesión.
  • hasModuleWrite() mira module_permissions[slug] === 'write'. Los administradores siempre pueden escribir.

Una vista típica lo usa así:

$puedeEscribir = hasModuleWrite('lab_domicilios');
...
<?php if ($puedeEscribir): ?><button>Nuevo domicilio</button><?php endif; ?>

La columna que manda es permission

role_modules tiene dos formas de expresar lo mismo, y solo una se usa:

Columnas ¿Se usan?
permission (read / write) Sí. Es lo que lee hasModuleWrite()
can_view, can_create, can_edit, can_delete, can_export No las lee el control de acceso

Poner can_edit = 0 no impide editar. Para dejar un módulo en solo lectura hay que fijar permission = 'read'. Las columnas can_* quedaron de un diseño anterior; conviene mantenerlas coherentes por prolijidad, pero no protegen nada.

Solo lectura de verdad:

UPDATE role_modules SET permission = 'read'
 WHERE role_id = 1030 AND module_slug IN ('lab_domicilios', 'lab_ordenes');

Roles actuales

{{roles}}

Sesiones sin role_id

Hay dos casos heredados que siguen contemplados en el código:

  • modules nulo y rol admin → acceso total. Cubre usuarios anteriores al sistema de roles.
  • Rol enfermero sin role_id → recibe enfermero_portal y lab_formularios de forma fija.

Verificaciones adicionales

El control por módulo no siempre alcanza. Varias pantallas agregan sus propias reglas:

Dónde Regla
enfermero_portal.php Solo admin, superadmin y enfermero
api/lab/save_domicilio.php Un enfermero solo edita domicilios que creó o que tiene asignados
api/lab/firmar_profesional.php Un enfermero solo firma envíos propios
modules/turnero/api/_helpers.php requireTurnero() en todos los endpoints del turnero
modules/turnero/module.php El menú cambia según rol y según la IP del equipo

Al agregar un endpoint que modifica datos, no alcanza con confiar en que la vista ocultó el botón: el endpoint tiene que verificar por su cuenta.

Diagnóstico rápido

Alguien reporta que no ve un módulo o que puede editar lo que no debería:

-- Qué rol tiene realmente y si las dos columnas coinciden
SELECT u.id, u.username, u.role, u.role_id, r.slug AS rol_real
  FROM admin_users u LEFT JOIN roles r ON r.id = u.role_id
 WHERE u.username = 'usuario';

-- Qué módulos le da ese rol
SELECT module_slug, permission FROM role_modules WHERE role_id = <role_id>;

Si los datos se ven bien y el usuario sigue sin acceso: no ha vuelto a iniciar sesión.