resources/views/pages/frontend/docs/lost-password.md
Última modificación: 24 Oct, 2026

Recuperación Relacional de Acceso

Mañuti reemplaza el mecanismo por defecto de contraseñas olvidadas de Laravel (password_reset_tokens basado en cadenas de correo electrónico planas) por una arquitectura relacional normalizada y auditada centrada en la entidad lost_password.


1. Esquema Relacional de lost_password

CREATE TABLE `lost_password` (
    `id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    `usuario_id` BIGINT UNSIGNED NOT NULL,
    `token` VARCHAR(255) NOT NULL,
    `cat_status` BIGINT UNSIGNED NOT NULL,
    `created_at` TIMESTAMP NULL,
    `updated_at` TIMESTAMP NULL,
    `deleted_at` TIMESTAMP NULL,
    FOREIGN KEY (`usuario_id`) REFERENCES `usuarios`(`id`) ON DELETE CASCADE,
    FOREIGN KEY (`cat_status`) REFERENCES `catalogos`(`id`)
);

Ventajas del Esquema Relacional

  • Integridad Referencial: Vinculado al id del usuario. Si el usuario actualiza su correo corporativo, no se rompe el rastro de recuperación.
  • Estatus por Catálogo: Los estados del ciclo de vida del token no son cadenas de texto sueltas; apuntan a la tabla de Catálogos (LP_PENDIENTE, LP_USADO, LP_EXPIRADO).
  • Caducidad Automática: Se calcula contra created_at permitiendo ventanas dinámicas (default: 60 minutos).

2. Flujo Criptográfico Transaccional

flowchart TD
    REQ["[Solicitud /forgot-password]"]
    
    STEPS1["1. Valida existencia del correo en tabla 'usuarios'<br/>2. Genera token criptográfico de 64 caracteres: Str::random(64)<br/>3. Obtiene ID de 'LP_PENDIENTE' en 'catalogos'<br/>4. Inserta registro en 'lost_password'<br/>5. Despacha ResetPasswordMail vía SMTP"]
    
    CLICK["[Usuario hace clic en el enlace del correo: /reset-password/{token}]"]
    
    VALIDATE{"Valida simultáneamente:<br/>* Existencia del token en 'lost_password'<br/>* cat_status == LP_PENDIENTE<br/>* created_at < 60 minutos"}
    
    SUCCESS["1. Actualiza password en 'usuarios' (Bcrypt)<br/>2. Actualiza cat_status a LP_USADO<br/>3. Invalida token para futuros accesos"]
    
    FAIL["Retorna error amigable<br/>y audita intento en Mongo"]

    REQ --> STEPS1
    STEPS1 --> CLICK
    CLICK --> VALIDATE
    
    VALIDATE -->|"Válido"| SUCCESS
    VALIDATE -->|"Inválido / Expirado"| FAIL

3. Notificación Desacoplada (ResetPasswordMail)

El correo no se renderiza dentro del controlador; utiliza clases Mailable con soporte para encolamiento asíncrono en Redis:

// app/Mail/ResetPasswordMail.php
class ResetPasswordMail extends Mailable
{
    use Queueable, SerializesModels;

    public function __construct(public string $token, public string $nombres) {}

    public function build()
    {
        return $this->subject('Recuperación de Contraseña')
            ->view('emails.reset_password');
    }
}

Enlaces Relacionados

Edita este documento en >> lost-password.md
← Volver a la Landing Page