453 lines
14 KiB
Markdown
453 lines
14 KiB
Markdown
# 🔔 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.log` au render
|
|
- ❌ **Double fetch** : `manualFetch()` appelé à la fois dans `useEffect` et `handleOpenChange`
|
|
- ❌ **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)
|
|
|
|
#### `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 `requestDeduplicator` mais peut être simplifié
|
|
- ✅ **Unified refresh** : Bien intégré avec `useUnifiedRefresh`
|
|
|
|
### 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=true` pour bypasser le cache
|
|
- ✅ **Bien implémenté**
|
|
|
|
#### `/api/notifications` ✅
|
|
- **Fonctionnel** : Retourne la liste des notifications
|
|
- **Pagination** : Support `page` et `limit`
|
|
- ✅ **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** :
|
|
1. Créer `/api/notifications/[id]/read` endpoint
|
|
2. Ajouter `markAsRead()` dans `NotificationAdapter` interface
|
|
3. Implémenter dans chaque adapter (Leantime, RocketChat, Email)
|
|
4. Ajouter bouton "Mark as read" dans le dropdown
|
|
5. Mettre à jour le count après marquage
|
|
|
|
---
|
|
|
|
### 2. ❌ **Logs de debug excessifs**
|
|
|
|
**Problème** :
|
|
- `notification-badge.tsx` contient 6 `console.log` au 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 de `console.log`
|
|
- Retirer les logs de production
|
|
- Garder uniquement les logs d'erreur
|
|
|
|
---
|
|
|
|
### 3. ⚠️ **Double fetch dans notification-badge**
|
|
|
|
**Problème** :
|
|
```typescript
|
|
// 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.ts` ligne 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 dans `notification-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)
|
|
|
|
1. **Créer endpoint `/api/notifications/[id]/read`**
|
|
- POST pour marquer comme lu
|
|
- Support pour tous les adapters
|
|
- Invalidation du cache après marquage
|
|
|
|
2. **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)
|
|
|
|
3. **Ajouter bouton "Mark as read" dans le dropdown**
|
|
- Sur chaque notification
|
|
- Bouton "Mark all as read"
|
|
- Mise à jour optimiste de l'UI
|
|
|
|
4. **Nettoyer les logs de debug**
|
|
- Retirer tous les `console.log` de production
|
|
- Utiliser `logger.debug()` uniquement
|
|
- Garder uniquement les logs d'erreur
|
|
|
|
### Phase 2 : Améliorations UX (Priorité Moyenne)
|
|
|
|
5. **Corriger le double fetch**
|
|
- Unifier la logique de fetch
|
|
- Un seul point d'entrée
|
|
- Éviter les appels multiples
|
|
|
|
6. **Utiliser le cache par défaut**
|
|
- Retirer `force=true` au mount
|
|
- Utiliser cache pour initial load
|
|
- Force refresh uniquement pour refresh manuel
|
|
|
|
7. **Implémenter pagination**
|
|
- Scroll infini ou "Load more"
|
|
- Afficher le total
|
|
- Gérer le loading state
|
|
|
|
8. **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)
|
|
|
|
9. **Améliorer la gestion d'erreurs**
|
|
- Messages d'erreur plus clairs
|
|
- Retry automatique
|
|
- Fallback gracieux
|
|
|
|
10. **Optimiser les performances**
|
|
- Virtualisation pour longues listes
|
|
- Memoization des composants
|
|
- Réduire les re-renders
|
|
|
|
11. **Nettoyer le code mort**
|
|
- Supprimer `scheduleBackgroundRefresh()` si inutilisé
|
|
- Simplifier la deduplication si possible
|
|
|
|
---
|
|
|
|
## 📝 Fichiers à Modifier
|
|
|
|
### Backend
|
|
1. `app/api/notifications/[id]/read/route.ts` - **NOUVEAU**
|
|
2. `lib/services/notifications/notification-adapter.interface.ts` - Ajouter `markAsRead()`
|
|
3. `lib/services/notifications/notification-service.ts` - Ajouter méthode `markAsRead()`
|
|
4. `lib/services/notifications/leantime-adapter.ts` - Implémenter `markAsRead()`
|
|
5. `lib/services/notifications/rocketchat-adapter.ts` - Implémenter `markAsRead()`
|
|
6. `lib/services/notifications/email-adapter.ts` - Implémenter `markAsRead()`
|
|
|
|
### Frontend
|
|
7. `components/notification-badge.tsx` - Nettoyer logs, ajouter actions, pagination
|
|
8. `hooks/use-notifications.ts` - Ajouter `markAsRead()`, retirer force refresh par défaut
|
|
9. `lib/types/notification.ts` - Vérifier si besoin d'ajouter des champs
|
|
|
|
---
|
|
|
|
## 🔍 Points d'Attention
|
|
|
|
1. **Synchronisation avec les sources** : Quand on marque une notification comme lue, il faut aussi la marquer dans la source (Leantime, RocketChat, Email)
|
|
|
|
2. **Cache invalidation** : Après `markAsRead()`, invalider le cache pour que le count se mette à jour immédiatement
|
|
|
|
3. **Optimistic updates** : Mettre à jour l'UI immédiatement avant la confirmation serveur pour une meilleure UX
|
|
|
|
4. **Gestion des erreurs** : Si le marquage échoue, rollback l'update optimiste
|
|
|
|
5. **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.
|