---
name: project_auth_email
description: "Vérification email, mot de passe oublié, pages auth — architecture complète"
metadata: 
  node_type: memory
  type: project
  originSessionId: e9aff1a4-9c1c-4cab-b7ec-90146b832fb0
---

Fonctionnalités auth ajoutées (session juin 2026, avant le 2FA).

**DB** — migrations dans `db/index.js` :
- `users.email_verified INTEGER NOT NULL DEFAULT 1` (DEFAULT 1 pour ne pas bloquer les comptes existants ; 0 pour les nouveaux si SMTP actif)
- Table `email_verification_tokens` (token, expires_at 24h, used)
- Table `password_reset_tokens` (token, expires_at 1h, used)
- Table `smtp_config` (id=1, enabled, host, port, secure, email, username, password, allow_unauth, app_name, app_url)

**Backend (auth.js)** — routes :
- `POST /register` : premier user auto-vérifié ; si SMTP actif → envoie email bienvenue + `{ requiresVerification: true }`
- `POST /login` : bloque si `email_verified=0`, code `EMAIL_NOT_VERIFIED`
- `GET /verify-email?token=` : valide le token, set `email_verified=1`
- `POST /resend-verification` : invalide anciens tokens, envoie nouveau (toujours 200 pour éviter enumeration)
- `PUT /me` : si email change → `email_verified=0` + envoie nouveau lien de vérification
- `POST /forgot-password` / `POST /reset-password` : tokens 1h, toujours 200

**Backend (admin.js)** :
- `GET /admin/users` retourne `email_verified`
- `PATCH /admin/users/:id/verify-email` : vérification manuelle par admin

**Pages frontend** :
- `Login.jsx` : gère `EMAIL_NOT_VERIFIED` → bouton "Renvoyer l'email"
- `Register.jsx` : état `verifyEmail` si `requiresVerification`
- `ForgotPassword.jsx` : layout 2 colonnes, état idle → sent
- `ResetPassword.jsx` : layout 2 colonnes, lit `?token=`, redirect /login après 3s
- `VerifyEmail.jsx` : layout 2 colonnes, appel GET au montage, états loading/ok/error
- `MonCompte.jsx` : badge vérifié/non-vérifié sur email, `EmailChangeForm`, `EmailResendBlock`
- `App.jsx` : routes `/forgot-password`, `/reset-password`, `/verify-email`

**Why:** Sécurité compte, demande utilisateur.
**How to apply:** `getSmtpConfig()` est la source de vérité SMTP. `smtpReady = cfg.enabled && cfg.host && cfg.email`. Toujours wrap les `sendMail` dans try/catch pour ne pas bloquer l'inscription.
