14 KiB
🔔 Analyse Approfondie du Système de Notifications
📋 Vue d'ensemble
Le système de notifications est un système multi-sources qui agrège les notifications de plusieurs services externes (Leantime, RocketChat, Email) et les affiche dans un badge clignotant rouge dans la navbar.
Architecture actuelle :
- Service Pattern : Singleton avec adapter pattern
- 3 Adapters implémentés : Leantime, RocketChat, Email
- Cache : Redis avec TTL de 30 secondes
- Polling : 30 secondes via
useUnifiedRefresh - Temps réel : Système hybride avec event-driven triggers
🏗️ Architecture Actuelle
1. Composants Frontend
components/notification-badge.tsx
- Rôle : Affiche le badge de notification et le dropdown
- Problèmes identifiés :
- ❌ Logs de debug excessifs : 6
console.logau render - ❌ Double fetch :
manualFetch()appelé à la fois dansuseEffectethandleOpenChange - ❌ Pas de fonctionnalité "Mark as read" : Les notifications ne peuvent pas être marquées comme lues depuis le dropdown
- ❌ Pas de pagination : Limite fixe à 10 notifications
- ❌ Pas de tri/filtre : Toutes les notifications mélangées
- ❌ Pas d'actions : Impossible d'interagir avec les notifications (ouvrir, marquer lu, supprimer)
- ❌ Logs de debug excessifs : 6
hooks/use-notifications.ts
- Rôle : Hook principal pour gérer les notifications
- Problèmes identifiés :
- ⚠️ Force refresh par défaut :
fetchNotificationCount(true)au mount - ⚠️ Pas de fonction markAsRead : Aucune méthode pour marquer comme lu
- ⚠️ Deduplication complexe : Utilise
requestDeduplicatormais peut être simplifié - ✅ Unified refresh : Bien intégré avec
useUnifiedRefresh
- ⚠️ Force refresh par défaut :
2. Backend Services
lib/services/notifications/notification-service.ts
- Rôle : Service singleton qui agrège les notifications
- Problèmes identifiés :
- ⚠️ Pas de méthode markAsRead : Le service ne peut pas marquer les notifications comme lues
- ⚠️ Background refresh inutilisé :
scheduleBackgroundRefresh()existe mais n'est jamais appelé - ✅ Cache bien géré : Redis avec TTL approprié
- ✅ Adapter pattern : Architecture extensible
Adapters
LeantimeAdapter (leantime-adapter.ts)
- ✅ Fonctionnel : Récupère les notifications Leantime
- ❌ Pas de markAsRead : Ne peut pas marquer les notifications comme lues
- ⚠️ Cache complexe : Cache des user IDs avec TTL
RocketChatAdapter (rocketchat-adapter.ts)
- ✅ Fonctionnel : Récupère les messages non lus
- ❌ Pas de markAsRead : Ne peut pas marquer les messages comme lus
- ⚠️ Logique de recherche utilisateur : Complexe, pourrait être optimisée
EmailAdapter (email-adapter.ts)
- ✅ Fonctionnel : Récupère les emails non lus
- ❌ Pas de markAsRead : Ne peut pas marquer les emails comme lus
- ⚠️ Support Graph API : Gère Microsoft Graph mais logique complexe
3. API Routes
/api/notifications/count ✅
- Fonctionnel : Retourne le nombre de notifications non lues
- Support force refresh :
?force=truepour bypasser le cache - ✅ Bien implémenté
/api/notifications ✅
- Fonctionnel : Retourne la liste des notifications
- Pagination : Support
pageetlimit - ✅ Bien implémenté
/api/notifications/[id]/read ❌ MANQUANT
- Problème critique : Aucun endpoint pour marquer les notifications comme lues
- Impact : Les utilisateurs ne peuvent pas marquer les notifications comme lues depuis le dropdown
🐛 Problèmes Critiques Identifiés
1. ❌ Pas de fonctionnalité "Mark as Read"
Problème :
- Aucun endpoint API pour marquer les notifications comme lues
- Aucune méthode dans le service ou les adapters
- Les utilisateurs ne peuvent pas interagir avec les notifications
Impact :
- UX dégradée : les notifications restent "non lues" indéfiniment
- Badge rouge persiste même après avoir vu les notifications
- Pas de moyen de gérer les notifications
Solution nécessaire :
- Créer
/api/notifications/[id]/readendpoint - Ajouter
markAsRead()dansNotificationAdapterinterface - Implémenter dans chaque adapter (Leantime, RocketChat, Email)
- Ajouter bouton "Mark as read" dans le dropdown
- Mettre à jour le count après marquage
2. ❌ Logs de debug excessifs
Problème :
notification-badge.tsxcontient 6console.logau render- Logs dans plusieurs fichiers (adapters, service, hooks)
- Pollution de la console en production
Impact :
- Performance dégradée (logs à chaque render)
- Console difficile à déboguer
- Informations sensibles potentiellement exposées
Solution nécessaire :
- Utiliser
logger.debug()au lieu deconsole.log - Retirer les logs de production
- Garder uniquement les logs d'erreur
3. ⚠️ Double fetch dans notification-badge
Problème :
// Ligne 66-70 : Fetch quand dropdown s'ouvre
useEffect(() => {
if (isOpen && status === 'authenticated') {
manualFetch();
}
}, [isOpen, status]);
// Ligne 73-78 : Fetch au mount
useEffect(() => {
if (status === 'authenticated') {
manualFetch();
}
}, [status]);
// Ligne 85-89 : Fetch dans handleOpenChange
const handleOpenChange = (open: boolean) => {
setIsOpen(open);
if (open && status === 'authenticated') {
manualFetch();
}
};
Impact :
- Appels API redondants
- Charge serveur inutile
- Expérience utilisateur dégradée (loading multiple)
Solution nécessaire :
- Unifier la logique de fetch
- Utiliser un seul point d'entrée
- Éviter les appels multiples
4. ⚠️ Force refresh par défaut
Problème :
use-notifications.tsligne 155 :fetchNotificationCount(true)au mount- Bypasse le cache à chaque chargement initial
- Augmente la charge serveur
Impact :
- Latence accrue au chargement
- Charge serveur inutile
- Cache Redis sous-utilisé
Solution nécessaire :
- Utiliser le cache par défaut au mount
- Force refresh uniquement pour refresh manuel
- Aligner avec le pattern des autres widgets
5. ⚠️ Pas de pagination dans le dropdown
Problème :
- Limite fixe à 10 notifications (ligne 81 de
notification-badge.tsx) - Pas de "Load more" ou scroll infini
- Utilisateurs avec beaucoup de notifications ne voient pas tout
Impact :
- UX limitée pour les utilisateurs actifs
- Notifications importantes peuvent être cachées
- Pas de moyen de voir l'historique complet
Solution nécessaire :
- Implémenter pagination ou scroll infini
- Bouton "Load more" ou auto-load au scroll
- Afficher le total de notifications
6. ⚠️ Pas de tri/filtre
Problème :
- Toutes les notifications mélangées (Leantime, RocketChat, Email)
- Pas de tri par date, source, type
- Pas de filtre par source ou statut (lu/non lu)
Impact :
- Difficile de trouver des notifications spécifiques
- UX dégradée pour les utilisateurs avec beaucoup de notifications
- Pas de moyen de gérer efficacement les notifications
Solution nécessaire :
- Ajouter tri par date (déjà fait côté service mais pas exposé)
- Ajouter filtres par source (Leantime, RocketChat, Email)
- Ajouter filtre lu/non lu
- Grouper par source ou date
7. ⚠️ Pas d'actions sur les notifications
Problème :
- Impossible d'interagir avec les notifications depuis le dropdown
- Pas de bouton "Mark as read"
- Pas de bouton "Delete" ou "Dismiss"
- Pas de lien direct vers la source (sauf via
notification.link)
Impact :
- UX limitée
- Utilisateurs doivent aller dans chaque service pour gérer les notifications
- Pas de gestion centralisée
Solution nécessaire :
- Ajouter bouton "Mark as read" sur chaque notification
- Ajouter bouton "Mark all as read"
- Ajouter bouton "Dismiss" pour les notifications non actionnables
- Améliorer les liens vers les sources
8. ⚠️ Background refresh inutilisé
Problème :
scheduleBackgroundRefresh()existe dansnotification-service.ts(ligne 362)- Jamais appelé
- Code mort
Impact :
- Code inutile qui complique la maintenance
- Potentiel de confusion pour les développeurs
Solution nécessaire :
- Soit implémenter le background refresh
- Soit supprimer le code mort
- Le système de refresh unifié remplace cette fonctionnalité
9. ⚠️ Gestion d'erreurs incomplète
Problème :
- Erreurs génériques affichées
- Pas de retry automatique
- Pas de distinction entre erreurs temporaires/permanentes
- Pas de fallback si un adapter échoue
Impact :
- UX dégradée en cas d'erreur
- Utilisateurs ne comprennent pas les erreurs
- Pas de résilience si un service est down
Solution nécessaire :
- Améliorer les messages d'erreur
- Implémenter retry avec backoff exponentiel
- Distinguer erreurs temporaires/permanentes
- Fallback gracieux si un adapter échoue (afficher les autres)
10. ⚠️ Performance et optimisation
Problèmes :
- Pas de virtualisation pour les longues listes
- Re-renders potentiels excessifs
- Pas de memoization des composants de notification
- Logs à chaque render
Impact :
- Performance dégradée avec beaucoup de notifications
- Expérience utilisateur ralentie
- Consommation mémoire élevée
Solution nécessaire :
- Implémenter virtualisation (react-window ou react-virtual)
- Memoizer les composants de notification
- Optimiser les re-renders
- Retirer les logs de production
📊 État Actuel vs État Idéal
État Actuel ❌
Utilisateur ouvre dropdown
└─> Fetch notifications (force refresh)
└─> Affiche 10 notifications
└─> ❌ Pas d'action possible
└─> Utilisateur doit aller dans chaque service
└─> Badge reste rouge même après avoir vu
État Idéal ✅
Utilisateur ouvre dropdown
└─> Fetch notifications (cache par défaut)
└─> Affiche notifications avec pagination
└─> ✅ Actions disponibles :
├─> Mark as read (individuel)
├─> Mark all as read
├─> Dismiss
└─> Ouvrir dans source
└─> Badge mis à jour immédiatement
└─> Cache invalidé
└─> Count rafraîchi
🎯 Plan d'Action Recommandé
Phase 1 : Corrections Critiques (Priorité Haute)
-
Créer endpoint
/api/notifications/[id]/read- POST pour marquer comme lu
- Support pour tous les adapters
- Invalidation du cache après marquage
-
Ajouter
markAsRead()dans les adapters- Implémenter dans LeantimeAdapter
- Implémenter dans RocketChatAdapter (marquer message comme lu)
- Implémenter dans EmailAdapter (marquer email comme lu)
-
Ajouter bouton "Mark as read" dans le dropdown
- Sur chaque notification
- Bouton "Mark all as read"
- Mise à jour optimiste de l'UI
-
Nettoyer les logs de debug
- Retirer tous les
console.logde production - Utiliser
logger.debug()uniquement - Garder uniquement les logs d'erreur
- Retirer tous les
Phase 2 : Améliorations UX (Priorité Moyenne)
-
Corriger le double fetch
- Unifier la logique de fetch
- Un seul point d'entrée
- Éviter les appels multiples
-
Utiliser le cache par défaut
- Retirer
force=trueau mount - Utiliser cache pour initial load
- Force refresh uniquement pour refresh manuel
- Retirer
-
Implémenter pagination
- Scroll infini ou "Load more"
- Afficher le total
- Gérer le loading state
-
Ajouter tri/filtre
- Tri par date (déjà fait côté service)
- Filtre par source
- Filtre lu/non lu
- Grouper par source ou date
Phase 3 : Optimisations (Priorité Basse)
-
Améliorer la gestion d'erreurs
- Messages d'erreur plus clairs
- Retry automatique
- Fallback gracieux
-
Optimiser les performances
- Virtualisation pour longues listes
- Memoization des composants
- Réduire les re-renders
-
Nettoyer le code mort
- Supprimer
scheduleBackgroundRefresh()si inutilisé - Simplifier la deduplication si possible
- Supprimer
📝 Fichiers à Modifier
Backend
app/api/notifications/[id]/read/route.ts- NOUVEAUlib/services/notifications/notification-adapter.interface.ts- AjoutermarkAsRead()lib/services/notifications/notification-service.ts- Ajouter méthodemarkAsRead()lib/services/notifications/leantime-adapter.ts- ImplémentermarkAsRead()lib/services/notifications/rocketchat-adapter.ts- ImplémentermarkAsRead()lib/services/notifications/email-adapter.ts- ImplémentermarkAsRead()
Frontend
components/notification-badge.tsx- Nettoyer logs, ajouter actions, paginationhooks/use-notifications.ts- AjoutermarkAsRead(), retirer force refresh par défautlib/types/notification.ts- Vérifier si besoin d'ajouter des champs
🔍 Points d'Attention
-
Synchronisation avec les sources : Quand on marque une notification comme lue, il faut aussi la marquer dans la source (Leantime, RocketChat, Email)
-
Cache invalidation : Après
markAsRead(), invalider le cache pour que le count se mette à jour immédiatement -
Optimistic updates : Mettre à jour l'UI immédiatement avant la confirmation serveur pour une meilleure UX
-
Gestion des erreurs : Si le marquage échoue, rollback l'update optimiste
-
Multi-sources : Chaque adapter a sa propre logique pour marquer comme lu, il faut gérer les différences
✅ Résumé
Problèmes critiques : 3
- Pas de fonctionnalité "Mark as Read"
- Logs de debug excessifs
- Double fetch
Problèmes importants : 4
- Force refresh par défaut
- Pas de pagination
- Pas de tri/filtre
- Pas d'actions
Optimisations : 3
- Background refresh inutilisé
- Gestion d'erreurs incomplète
- Performance
Total : 10 problèmes identifiés nécessitant des corrections
Recommandation : Commencer par la Phase 1 (corrections critiques) qui résoudra les problèmes les plus impactants pour l'UX.