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 rolesroles:read
Ver detalle de rolroles:read
Ver permisos disponiblesroles:read
Crear rol personalizadoroles:create
Editar rol personalizadoroles:update
Eliminar rol personalizadoroles:delete
Ver miembros de un rolroles:read + memberships:read

Agencia (AGENCY)

AcciónDisponiblePermiso
Ver lista de rolesroles:read
Ver detalle de rolroles:read
Ver permisos disponiblesroles:read
Crear rol personalizadoroles:create
Editar rol personalizadoroles:update
Eliminar rol personalizadoroles:delete
Ver miembros de un rolroles: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