Saltar al contenido principal
Versión: 1.2

Módulo: Invitaciones

Scope

Tipo de organizaciónAcceso
Empresa
Agencia
Reclutador independiente

Permisos por rol

AcciónDisponiblePermiso
Ver invitacionesmemberships:read
Crear invitaciónmemberships:invite
Revocar invitaciónmemberships:revoke-invite
Reenviar invitaciónmemberships:invite

¿Qué es?

Gestión de invitaciones pendientes de la organización. Permite ver todas las invitaciones enviadas, filtrar por estado, revocar invitaciones pendientes, y reenviar el email de invitación.

¿Qué puede hacer el usuario?

  • Ver lista de invitaciones con filtro por estado (chips)
  • Filtrar: Todas, Pendientes, Aceptadas, Revocadas, Expiradas
  • Revocar invitaciones pendientes (con motivo opcional)
  • Reenviar invitaciones pendientes (genera nuevo token + email)
  • Pull-to-refresh para actualizar la lista

Flujo del usuario

Listar invitaciones

1. Abre "Equipo" → tab "Invitaciones"
2. Ve lista con email, rol, estado y fechas
3. Filtra con chips de estado
4. Pull-to-refresh para actualizar

Revocar invitación

1. En una invitación PENDIENTE, presiona menú ⋮
2. Selecciona "Revocar"
3. Se muestra diálogo con campo de motivo (opcional)
4. Confirma → invitación revocada, enlace deja de funcionar
5. Lista se recarga automáticamente

Reenviar invitación

1. En una invitación PENDIENTE, presiona menú ⋮
2. Selecciona "Reenviar"
3. El API genera nuevo token, actualiza expiración, y envía nuevo email
4. Snackbar confirma el reenvío

Reglas de negocio

  • Solo invitaciones con status PENDING pueden revocarse o reenviarse
  • Revocar requiere confirmación con motivo opcional
  • Reenviar genera un token completamente nuevo (el anterior se invalida)
  • La expiración se renueva al reenviar (7 días desde el momento)
  • Las invitaciones EXPIRED se marcan automáticamente por el backend
  • El token de invitación nunca se almacena en texto plano (solo hash SHA-256)
  • El email de invitación incluye un link con el token para aceptar

Estados de invitación

EstadoDescripciónAcciones disponibles
PENDINGEsperando aceptaciónRevocar, Reenviar
ACCEPTEDMiembro creadoNinguna
REVOKEDEnlace invalidadoNinguna
EXPIREDPasó fecha de expiraciónNinguna

Arquitectura

lib/features/team/
├── application/
│ ├── invitations_cubit.dart # loadInvitations, createInvitation, revokeInvitation, resendInvitation
│ └── invitations_state.dart # InvitationsStatus enum, invitations list, statusFilter
├── data/
│ ├── datasources/
│ │ └── team_remote_datasource.dart # listInvitations, createInvitation, revokeInvitation, resendInvitation
│ ├── models/
│ │ └── invitation_model.dart # InvitationModel, InvitationsResponseModel
│ └── repositories/
│ └── team_repository_impl.dart
├── domain/
│ ├── entities/
│ │ └── invitation.dart # Invitation (Equatable) con helpers isPending, isAccepted, etc.
│ └── repositories/
│ └── team_repository.dart
└── presentation/
└── tabs/
└── invitations_tab.dart # BlocProvider + BlocBuilder, filter chips, revoke dialog

Endpoints API

MétodoEndpointPermisoDescripción
GET/memberships/invitationsmemberships:readLista invitaciones (paginado, status filter)
POST/memberships/invitationsmemberships:inviteCrear invitación (email + roleId)
PATCH/memberships/invitations/:id/revokememberships:revoke-inviteRevocar invitación (reason?)
POST/memberships/invitations/:id/resendmemberships:inviteReenviar invitación

Respuesta de invitación

{
"id": "uuid",
"organizationId": "uuid",
"email": "ana@example.com",
"status": "PENDING",
"role": { "id": "uuid", "key": "recruiter", "name": "Recruiter", ... },
"invitedByUserId": "uuid",
"expiresAt": "2026-05-18T16:00:00.000Z",
"acceptUrl": "https://portal.contratta.mx/es/invitations/accept?token=...",
"createdAt": "2026-05-11T16:00:00.000Z"
}

Registro DI

  • Cubit: Factory (nueva instancia por pantalla)
getIt<InvitationsCubit>()

Localización

✅ Completa — claves con prefijo invitations en ambos ARB:

  • Filtros: invitationsFilterAll, invitationsFilterPending, invitationsFilterAccepted, invitationsFilterRevoked, invitationsFilterExpired
  • Status: invitationsStatusPending, invitationsStatusAccepted, invitationsStatusExpired, invitationsStatusRevoked
  • Acciones: invitationsResendButton, invitationsRevokeButton, invitationsRevoked, invitationsResent
  • Diálogo: invitationsRevokeTitle, invitationsRevokeMessage, invitationsRevokeReasonHint
  • Empty states: invitationsEmpty, invitationsEmptyMessage, invitationsNoResults, invitationsNoFilterResults
  • Parametrizado: invitationsExpires({date})