Saltar al contenido principal
Versión: 1.2

Módulo: Roles y Permisos

Scope​

Tipo de organizaciónAcceso
Empresa✅
Agencia✅
Reclutador independiente❌

Permisos por rol​

Empresa (COMPANY)​

AcciónDisponiblePermiso
Ver lista de roles✅roles:read
Ver detalle de rol✅roles:read
Ver permisos disponibles✅roles:read
Crear rol personalizado✅roles:create
Editar rol personalizado✅roles:update
Eliminar rol personalizado✅roles:delete
Ver miembros de un rol✅roles:read + memberships:read

Agencia (AGENCY)​

AcciónDisponiblePermiso
Ver lista de roles✅roles:read
Ver detalle de rol✅roles:read
Ver permisos disponibles✅roles:read
Crear rol personalizado✅roles:create
Editar rol personalizado✅roles:update
Eliminar rol personalizado✅roles:delete
Ver miembros de un rol✅roles:read + memberships:read

Reclutador independiente (RECRUITER)​

AcciónDisponiblePermiso
Ver roles❌—
Crear/editar/eliminar roles❌—

¿Qué es?​

El módulo de Roles permite a las organizaciones (empresas y agencias) crear roles personalizados con permisos granulares para sus miembros. Los roles son plantillas de acceso que se asignan a los usuarios a través de membresías.

Existen dos tipos de roles:

  • Globales (sistema): Roles predefinidos por la plataforma según tipo de organización (ej. company_admin, agency_admin, recruiter). No se pueden modificar ni eliminar.
  • Personalizados (tenant): Roles creados por la organización con permisos seleccionados del catálogo disponible para su tipo.

¿Qué puede hacer el usuario?​

Admin de organización​

  • Ver lista paginada de roles con búsqueda
  • Ver detalle de un rol con permisos agrupados por recurso y conteo de miembros
  • Crear roles personalizados con nombre, key auto-generado, descripción y permisos seleccionados
  • Editar nombre, descripción y permisos de roles personalizados
  • Eliminar roles personalizados (solo si no tienen miembros activos asignados)
  • Ver qué usuarios tienen un rol específico

Flujo del usuario​

Listar y gestionar roles​

1. Abre "Equipo" desde la navegación
2. Selecciona el tab "Roles"
3. Ve la lista paginada con scroll infinito
4. Usa el buscador para filtrar roles por nombre/key
5. Puede ver detalle, editar o eliminar roles desde el menú contextual

Crear un rol​

1. En el tab "Roles", presiona "Crear rol"
2. Se abre el modal bottom sheet
3. Ingresa nombre (la key se auto-genera)
4. Opcionalmente agrega descripción
5. Selecciona permisos del catálogo agrupado por recurso
6. Confirma la creación
7. El rol aparece en la lista

Editar un rol​

1. Desde la lista o el detalle, presiona "Editar"
2. Se abre el modal con datos actuales pre-cargados
3. Modifica nombre, descripción o permisos
4. Confirma los cambios
5. El rol se actualiza

Eliminar un rol​

1. Desde el menú contextual de la card, presiona "Eliminar"
2. Se muestra diálogo de confirmación
3. Confirma → el rol se elimina (soft-delete)
4. Si tiene miembros activos, el API rechaza con ROLE_IN_USE

Ver miembros de un rol​

1. En el detalle del rol, presiona "Ver usuarios (N)"
2. Se abre la página con lista paginada de miembros asignados
3. Muestra avatar, nombre, email y estado de cada miembro

Reglas de negocio​

  • Los roles del sistema (globales) no se pueden crear, editar ni eliminar desde el tenant
  • Un rol personalizado requiere al menos 1 permiso
  • La key del rol se auto-genera del nombre, debe ser única dentro del tenant
  • Las keys de roles globales están reservadas y no se pueden usar para roles personalizados
  • Los permisos asignables están filtrados por tipo de organización y por los permisos que tiene el usuario activo
  • Permisos internos (system:access, admin:override) nunca son asignables a roles personalizados
  • No se puede eliminar un rol que tiene membresías activas asignadas
  • La eliminación es soft-delete con auditoría
  • Toda operación de CRUD invalida el cache de auth del tenant en Redis

Arquitectura​

lib/features/team/
├── application/
│ ├── roles_cubit.dart # CRUD + paginación + permisos
│ └── roles_state.dart # Equatable, enum status, selectedRole
├── data/
│ ├── datasources/
│ │ └── team_remote_datasource.dart # 6 métodos CRUD
│ ├── models/
│ │ └── role_model.dart # RoleModel, RolePermissionModel, RolesResponseModel
│ └── repositories/
│ └── team_repository_impl.dart # Error handling tipado
├── domain/
│ ├── entities/
│ │ ├── role.dart # Role (Equatable), RolePermission (Equatable)
│ │ ├── available_permission.dart
│ │ └── membership.dart
│ └── repositories/
│ └── team_repository.dart # Contrato abstracto CRUD
└── presentation/
├── pages/
│ ├── role_detail_page.dart # Detalle con BlocProvider
│ └── role_members_page.dart # Miembros de un rol
├── tabs/
│ └── roles_tab.dart # Lista con BlocProvider + scroll infinito
└── widgets/
├── create_role_modal.dart # Bottom sheet con permisos
├── edit_role_modal.dart # Bottom sheet con permisos pre-seleccionados
└── role_card.dart # Card reutilizable

Endpoints API (sin prefijo /api)​

MétodoEndpointPermisoDescripción
GET/rolesroles:readLista roles personalizados del tenant (paginado, search, sort)
GET/roles/:roleIdroles:readDetalle del rol con conteo de miembros
GET/roles/available-permissionsroles:readPermisos asignables para el tipo de organización
GET/roles/assignableroles:readRoles asignables (globales + custom) para invitaciones
GET/roles/:roleId/membersroles:read + memberships:readMiembros asignados al rol (paginado)
POST/rolesroles:createCrear rol personalizado
PATCH/roles/:roleIdroles:updateActualizar rol personalizado
DELETE/roles/:roleIdroles:deleteSoft-delete rol personalizado

Respuesta paginada​

{
"data": [...],
"meta": {
"page": 1,
"pageSize": 20,
"total": 5,
"totalPages": 1,
"hasNextPage": false,
"hasPreviousPage": false
}
}

Estructura de un rol (response)​

{
"id": "uuid",
"organizationId": "uuid | null",
"key": "senior_recruiter",
"name": "Senior Recruiter",
"description": "Can manage candidates and take vacancies.",
"scope": "TENANT",
"isSystem": false,
"permissions": [
{
"key": "vacancies:read",
"resource": "vacancies",
"action": "read",
"description": "Read visible vacancies under tenant scope."
}
],
"createdAt": "2026-05-11T16:00:00.000Z",
"updatedAt": "2026-05-11T16:00:00.000Z",
"membersCount": 3
}

Permisos asignables por tipo de organización​

COMPANY​

companies:read, companies:update, vacancies:read, vacancies:create, vacancies:publish, candidates:read, candidates:update-stage, disputes:read, disputes:create, wallet:read, billing:read, notifications:read, support:read, support:manage, ai:use-guide, y permisos de recruiting.

AGENCY​

agencies:read, agencies:update, recruiters:read, recruiters:update, vacancies:read, vacancies:take, candidates:read, candidates:create, candidates:update-stage, disputes:read, disputes:create, wallet:read, notifications:read, support:read, support:manage, ai:use-guide, y permisos de recruiting.

RECRUITER​

recruiters:read, recruiters:update, vacancies:read, vacancies:take, candidates:read, candidates:create, candidates:update-stage, disputes:read, disputes:create, wallet:read, notifications:read, support:read, ai:use-guide.

Registro DI​

  • Datasource: LazySingleton
  • Repository: LazySingleton
  • Cubit: Factory (nueva instancia por pantalla)
getIt<RolesCubit>()

Localización​

Usa claves l10n para labels del UI:

  • rolesDeleteConfirmTitle, rolesDeleteConfirmMessage, rolesDeleted, rolesDeleteError
  • rolesLoadError, rolesEmpty, rolesManageDescription, rolesCount, rolesSearchHint, rolesCreateButton
  • retry, cancel, delete, close