Apariencia
Registro y aprobación
Los reclutadores HUMAE pueden registrarse por su cuenta desde la web pública. Para evitar que cualquier persona acceda al directorio de candidatos, el alta queda en revisión hasta que un administrador la apruebe.
El recorrido en una imagen
1. Usuario llena form → 2. Backend crea User en pending_approval
+ Notificación a TODOS los admins
+ Correo de verify-email al usuario
↓
3. Usuario verifica el correo (signed URL, 60 min)
email_verified_at = now()
↓
4. Admin entra a /admin/usuarios?status=pending_approval
Ve la solicitud → Aprobar / Rechazar
↓
5a. Aprobar → status = active → Notificación al usuario → Login OK
5b. Rechazar → status = inactive → Notificación con motivo → Login bloqueadoMientras la cuenta no esté verificada y aprobada, el login devuelve 403 con un mensaje específico.
Paso 1 · Formulario público
URL: /register → tarjeta "Soy reclutador" → /register/reclutador
Campos (schema Zod en src/schemas/auth.ts → registerRecruiterSchema):
| Campo | Validación |
|---|---|
name | Requerido, 2–120 caracteres |
email | Requerido, formato email, único en users |
phone | Opcional, máx. 30 caracteres |
password | Requerido, 8+ caracteres con al menos 1 letra y 1 número |
password_confirmation | Debe coincidir con password |
accept_terms | Checkbox obligatorio |
motivo | Opcional, máx. 500 caracteres — texto libre que el admin verá al revisar |
Endpoint: POST /api/v1/auth/register/recruiterRate limit: 5 por minuto por IP.
El motivo no es validación de negocio
Es un campo de cortesía para que el admin tenga contexto sin tener que escribir al solicitante. Ejemplo: "Trabajo en una agencia de selección y necesitamos talento evaluado por psicométricos".
Paso 2 · Pantalla de éxito (sin token)
A diferencia del registro de candidato, este flujo NO devuelve token. Tras el 201 el frontend muestra una pantalla con:
- Ícono de correo (Lucide
MailCheck). - Título: "¡Recibimos tu solicitud!".
- Mensaje: "Te enviamos un correo para verificar tu email. Después, un administrador de HUMAE revisará tu cuenta y te avisará por correo cuando esté aprobada.".
- Aviso: "Mientras tanto, no podrás iniciar sesión.".
- Link "Volver al login".
El backend creó:
Userconstatus = 'pending_approval', password hasheada,email_verified_at = NULL.- Asignó el rol Spatie
recruiter. - Disparó
Registered(que envía la URL firmada de verificación al solicitante). - Mandó
PendingUserRegistrationNotification(mail + database) a todos los users con roladmin.
Paso 3 · El admin recibe el aviso
El correo a admins llega con asunto "Solicitud de registro pendiente: Reclutador" e incluye:
- Nombre y email del solicitante.
- Motivo declarado (si llenó ese campo).
- CTA "Ir a usuarios pendientes" → abre
https://app.humae.com.mx/admin/usuarios?status=pending_approval.
Llega a TODOS los admins
El servicio recorre User::role('admin')->get() y hace Notification::send(). Si tu instancia tiene 3 admins, los 3 reciben copia. La notificación también se persiste en notifications (DB) para verla en la campanita.
Paso 4 · Verificación de email
Independientemente de la aprobación, el usuario debe verificar su correo. La URL del correo es la misma que para candidatos: /verify-email?id=...&hash=...&signature=....
- Si la firma es válida y no expiró:
email_verified_at = now(). El status no cambia — sigue enpending_approvalhasta que el admin actúe. - Si expira (60 min): el usuario puede pedir reenvío en
/verify-email.
Paso 5 · Login bloqueado mientras espera
POST /api/v1/auth/login con la cuenta del reclutador devuelve 403 con un código que el frontend usa para mostrar el toast adecuado:
| Estado de la cuenta | errors.code | Mensaje al usuario |
|---|---|---|
email_verified_at = NULL | email_unverified | "Verifica tu correo antes de iniciar sesión" + acción "Reenviar correo" |
Verificado pero status = pending_approval | pending_approval | "Tu cuenta está en revisión por un administrador de HUMAE. Te avisaremos por correo cuando esté aprobada." |
status = active | — | 200 con {user, token} y redirige a /recruiter/directorio |
status = suspended o inactive | account_inactive | "Tu cuenta está inactiva. Contacta a soporte." |
El login devuelve sólo después de validar credenciales
La compuerta de email/aprobación corre después de Hash::check(). Si las credenciales son malas, el response es 422 "Las credenciales no coinciden" — para no filtrar si una cuenta existe o no.
Paso 6 · Aprobación o rechazo del admin
Ver el detalle operativo en Gestión de usuarios y aprobaciones (admin). Resumen rápido:
- Aprobar →
status = active+AccountApprovedNotification(mail). El usuario puede iniciar sesión. - Rechazar (con motivo opcional) →
status = inactive+AccountRejectedNotification(motivo). El login queda bloqueado conaccount_inactive.
Notificaciones relacionadas
| Evento | Destinatario | Plantilla |
|---|---|---|
| Solicitud creada | Reclutador | VerifyEmail (URL firmada) |
| Solicitud creada | Cada admin | PendingUserRegistrationNotification |
| Aprobación | Reclutador | AccountApprovedNotification |
| Rechazo | Reclutador | AccountRejectedNotification(reason) |
Todas vía mail; las dos últimas también van al canal database para mostrar en la campanita.
Errores comunes
| Síntoma | Causa | Solución |
|---|---|---|
422 errors.email "Este correo ya está registrado" | Email ya existe | Usar Recuperar contraseña o registrarse con otro |
403 errors.code = email_unverified al login | No clickeó el link del correo | Reenviar desde /verify-email |
403 errors.code = pending_approval al login | Admin aún no revisa | Esperar correo de aprobación |
403 errors.code = account_inactive al login | Admin rechazó / suspendió | Contactar soporte; si fue rechazo, el motivo está en el correo |
Siguiente
Una vez aprobado, el reclutador entra al Directorio de talento →.

