10 KiB
🔔 Analyse du Flow 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, Nextcloud, etc.) et les affiche dans un badge clignotant rouge dans la navbar.
🎯 Déclenchement du Badge Rouge Clignotant
Condition d'affichage
Le badge rouge apparaît lorsque :
hasUnread = notificationCount.unread > 0
Fichier : components/notification-badge.tsx:26
const hasUnread = notificationCount.unread > 0;
{hasUnread && (
<Badge variant="notification" size="notification" className="absolute -top-2 -right-2 z-50">
{notificationCount.unread > 99 ? '99+' : notificationCount.unread}
</Badge>
)}
Style du badge
Fichier : components/ui/badge.tsx:18-19
notification: "border-transparent bg-red-500 text-white hover:bg-red-600 absolute -top-1 -right-1 px-1.5 py-0.5 min-w-[1.25rem] h-5 flex items-center justify-center"
Le badge est rouge (bg-red-500) et positionné en haut à droite de l'icône cloche.
🔄 Flow Complet de Notifications
1. Initialisation (Au chargement de la page)
MainNav (navbar)
└─> NotificationBadge (composant)
└─> useNotifications() (hook)
└─> useEffect() [status === 'authenticated']
├─> fetchNotificationCount(true) // Force refresh
└─> fetchNotifications(1, 20) // Charge les 20 premières
Fichiers :
components/main-nav.tsx- Affiche le badgecomponents/notification-badge.tsx:86-91- Fetch initialhooks/use-notifications.ts:265-277- Initialisation
2. Rafraîchissement Automatique (Polling)
Le système utilise un système de rafraîchissement unifié qui poll les notifications toutes les 30 secondes.
useUnifiedRefresh({
resource: 'notifications-count',
interval: 30000, // 30 secondes
priority: 'high',
onRefresh: fetchNotificationCount(true)
})
Fichiers :
hooks/use-notifications.ts:253-262- Configuration du refreshlib/constants/refresh-intervals.ts:12- Interval définilib/services/refresh-manager.ts- Gestionnaire centralisé
Interval de rafraîchissement :
- Notifications Count :
30 secondes(priorité haute) - Notifications List :
30 secondes(priorité haute)
3. Récupération des Notifications (API Calls)
A. Fetch du Count (Badge)
GET /api/notifications/count
└─> NotificationService.getInstance()
└─> getNotificationCount(userId)
├─> Check Redis Cache (TTL: 30s)
└─> Si pas en cache:
├─> LeantimeAdapter.getNotificationCount()
│ └─> API Leantime: getAllNotifications(limit: 1000)
│ └─> Compte les notifications avec read=0
└─> Autres adapters (futurs)
└─> Cache dans Redis (30s)
Fichiers :
app/api/notifications/count/route.tslib/services/notifications/notification-service.ts:182-310lib/services/notifications/leantime-adapter.ts:150-280
B. Fetch de la Liste
GET /api/notifications?page=1&limit=20
└─> NotificationService.getInstance()
└─> getNotifications(userId, page, limit)
├─> Check Redis Cache (TTL: 30s)
└─> Si pas en cache:
├─> LeantimeAdapter.getNotifications()
│ └─> API Leantime: getAllNotifications()
│ └─> Transforme en Notification[]
└─> Autres adapters (futurs)
└─> Trie par timestamp (newest first)
└─> Cache dans Redis (30s)
Fichiers :
app/api/notifications/route.tslib/services/notifications/notification-service.ts:61-177lib/services/notifications/leantime-adapter.ts:57-148
4. Sources de Notifications (Adapters)
Actuellement, un seul adapter est actif :
LeantimeAdapter
Source : Leantime (Agilité - agilite.slm-lab.net)
Méthode API :
{
"jsonrpc": "2.0",
"method": "leantime.rpc.Notifications.Notifications.getAllNotifications",
"params": {
"userId": <leantime_user_id>,
"showNewOnly": 0,
"limitStart": 0,
"limitEnd": 1000
}
}
Types de notifications Leantime :
- Tâches assignées
- Commentaires
- Mentions
- Changements de statut
- Dates d'échéance
Fichier : lib/services/notifications/leantime-adapter.ts
Futurs adapters (non implémentés) :
- NextcloudAdapter
- GiteaAdapter
- DolibarrAdapter
- MoodleAdapter
5. Cache Redis (Performance)
Le système utilise Redis pour mettre en cache les notifications et éviter les appels API répétés.
Clés de cache :
notifications:count:{userId}- TTL: 30 secondesnotifications:list:{userId}:{page}:{limit}- TTL: 30 secondes
Stratégie :
- Cache-first avec fallback API
- Background refresh si TTL < 50%
- Invalidation automatique après 30s
Fichier : lib/services/notifications/notification-service.ts:11-18
6. Déduplication des Requêtes
Le système utilise un request deduplicator pour éviter les appels API en double.
Window de déduplication : 2000ms (2 secondes)
Fichier : hooks/use-notifications.ts:39-59
const requestKey = `notifications-count-${session.user.id}`;
const data = await requestDeduplicator.execute(
requestKey,
async () => { /* fetch */ },
2000 // 2 secondes
);
🎨 Affichage du Badge
Composant NotificationBadge
Localisation : components/notification-badge.tsx
Structure :
<DropdownMenu>
<DropdownMenuTrigger>
<Button>
<Bell /> {/* Icône cloche */}
{hasUnread && (
<Badge variant="notification">
{count > 99 ? '99+' : count}
</Badge>
)}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
{/* Liste des notifications */}
</DropdownMenuContent>
</DropdownMenu>
États du Badge
| État | Condition | Affichage |
|---|---|---|
| Visible | notificationCount.unread > 0 |
Badge rouge avec nombre |
| Caché | notificationCount.unread === 0 |
Pas de badge |
| 99+ | notificationCount.unread > 99 |
Affiche "99+" |
🔍 Déclencheurs du Badge Rouge
1. Notifications Leantime
Les notifications sont créées dans Leantime lorsque :
- Une tâche vous est assignée
- Quelqu'un commente sur une tâche
- Vous êtes mentionné
- Une date d'échéance approche
- Un statut change
Flow :
Action dans Leantime
└─> Leantime crée notification (read=0)
└─> Polling toutes les 30s
└─> LeantimeAdapter récupère
└─> NotificationService agrège
└─> API retourne count
└─> Badge apparaît si unread > 0
2. Rafraîchissement Automatique
Le badge se met à jour automatiquement via :
- Polling : Toutes les 30 secondes
- Ouverture du dropdown : Fetch immédiat
- Mount du composant : Fetch initial
Fichier : hooks/use-notifications.ts:253-262
3. Marquer comme lu
Quand l'utilisateur marque une notification comme lue :
Clic sur "Mark as read"
└─> POST /api/notifications/{id}/read
└─> LeantimeAdapter.markAsRead()
└─> API Leantime: markNotificationRead()
└─> Update local state (optimistic)
└─> Refresh count (polling)
└─> Badge disparaît si unread === 0
Fichier : hooks/use-notifications.ts:123-189
📊 Structure des Données
NotificationCount
interface NotificationCount {
total: number; // Total de notifications
unread: number; // Nombre de non lues (TRIGGER DU BADGE)
sources: {
leantime: {
total: number;
unread: number;
}
}
}
Notification
interface Notification {
id: string;
source: 'leantime' | 'nextcloud' | ...;
sourceId: string;
type: string;
title: string;
message: string;
link?: string;
isRead: boolean; // false = non lue
timestamp: Date;
priority: 'low' | 'normal' | 'high';
user: { id: string; name?: string; };
metadata?: Record<string, any>;
}
🚀 Points d'Entrée (Triggers)
1. Au chargement de l'app
NotificationBadgemonteuseNotificationss'initialise- Fetch immédiat du count et de la liste
2. Polling automatique
- Toutes les 30 secondes
- Via
useUnifiedRefresh - Priorité haute
3. Ouverture du dropdown
- Fetch immédiat des notifications
- Rafraîchissement du count
4. Actions utilisateur
- Marquer comme lu → Update count
- Marquer tout comme lu → unread = 0
🔧 Configuration
Intervalles de rafraîchissement
Fichier : lib/constants/refresh-intervals.ts
NOTIFICATIONS_COUNT: 30000 // 30 secondes
NOTIFICATIONS: 30000 // 30 secondes
Cache TTL
Fichier : lib/services/notifications/notification-service.ts:15-16
COUNT_CACHE_TTL = 30; // 30 secondes
LIST_CACHE_TTL = 30; // 30 secondes
🐛 Debugging
Logs disponibles
Le système logge abondamment :
[NOTIFICATION_BADGE]- Actions du composant[useNotifications]- Actions du hook[NOTIFICATION_SERVICE]- Service backend[LEANTIME_ADAPTER]- Appels API Leantime
Endpoints de debug
GET /api/debug/notifications- État du systèmeGET /api/debug/leantime-methods- Méthodes Leantime disponibles
📝 Résumé : Ce qui déclenche le badge rouge
- Condition :
notificationCount.unread > 0 - Source principale : Leantime (notifications non lues)
- Rafraîchissement : Toutes les 30 secondes automatiquement
- Cache : Redis (30s TTL) pour performance
- Déduplication : 2 secondes pour éviter les doublons
- Affichage : Badge rouge avec nombre (ou "99+")
Le badge apparaît dès qu'il y a au moins une notification non lue dans Leantime (ou autres sources futures).