section: Feature Auth — Session | prio: P0 | est: 4h | deps: FE-A-01
Pourquoi
À 2M users, des milliers donglets ouverts simultanément. Sans BroadcastChannel, un logout dans un onglet laisse les autres onglets avec des tokens actifs.
Acceptance Criteria
- Session Manager
src/features/auth/lib/session.manager.ts : au démarrage app → refresh silencieux si cookie présent → isInitializing=true pendant ce temps → splash screen Quantify (logo hexagonal animé)
- Proactive refresh : timer déclenché 2 min avant expiration JWT (
sessionExpiresAt - Date.now() < 120_000), refresh en background sans bloquer lUX, toast warning si < 5min et tab active
- BroadcastChannel
src/features/auth/lib/session.broadcast.ts : canal "qfy_auth", logout dans un onglet → message broadcast → tous les autres onglets clearSession() + redirect /login, login dans un onglet → broadcast du nouveau token (sync état)
- Offline : si app lancée offline et token en mémoire → accès lecture de lapp, actions auth nécessitent le réseau → message "Connexion requise", event
window.ononline → retry refresh automatique
- Guards :
ProtectedRoute (redirect /login si !isAuthenticated), GuestRoute (redirect /app si isAuthenticated), PhoneCompletionGuard (redirect /profile/complete-phone si requires_phone_completion), isInitializing → splash screen
- Service Worker : routes
/api/v1/auth/* en network-only (jamais cachées)
Fichiers
src/features/auth/lib/
├── session.manager.ts
├── session.broadcast.ts
└── useSessionInit.ts
src/app/router/guards/
├── ProtectedRoute.tsx
├── GuestRoute.tsx
└── PhoneCompletionGuard.tsx
Scale
BroadcastChannel = synchronisation instantanée entre onglets sans serveur. Proactive refresh = zéro expiration inattendue.
section: Feature Auth — Session | prio: P0 | est: 4h | deps: FE-A-01
Pourquoi
À 2M users, des milliers donglets ouverts simultanément. Sans BroadcastChannel, un logout dans un onglet laisse les autres onglets avec des tokens actifs.
Acceptance Criteria
src/features/auth/lib/session.manager.ts: au démarrage app → refresh silencieux si cookie présent →isInitializing=truependant ce temps → splash screen Quantify (logo hexagonal animé)sessionExpiresAt - Date.now() < 120_000), refresh en background sans bloquer lUX, toast warning si < 5min et tab activesrc/features/auth/lib/session.broadcast.ts: canal"qfy_auth", logout dans un onglet → message broadcast → tous les autres onglets clearSession() + redirect /login, login dans un onglet → broadcast du nouveau token (sync état)window.ononline→ retry refresh automatiqueProtectedRoute(redirect /login si !isAuthenticated),GuestRoute(redirect /app si isAuthenticated),PhoneCompletionGuard(redirect /profile/complete-phone si requires_phone_completion),isInitializing→ splash screen/api/v1/auth/*en network-only (jamais cachées)Fichiers
Scale
BroadcastChannel = synchronisation instantanée entre onglets sans serveur. Proactive refresh = zéro expiration inattendue.