216 lines
5.6 KiB
Markdown
216 lines
5.6 KiB
Markdown
# 🚀 Proposition : Notifications en Temps Réel
|
|
|
|
## 📊 Analyse Actuelle vs Proposition
|
|
|
|
### ❌ Système Actuel (Polling toutes les 30s)
|
|
|
|
**Problèmes :**
|
|
- ⏱️ Délai de 30 secondes maximum avant notification
|
|
- 🔄 Polling constant même sans nouveaux messages
|
|
- 💻 Charge serveur inutile
|
|
- 📱 UX moins réactive
|
|
|
|
**Flow actuel :**
|
|
```
|
|
Polling toutes les 30s
|
|
└─> API /notifications/count
|
|
└─> NotificationService
|
|
└─> LeantimeAdapter
|
|
└─> Badge mis à jour
|
|
```
|
|
|
|
---
|
|
|
|
### ✅ Système Proposé (Event-Driven)
|
|
|
|
**Avantages :**
|
|
- ⚡ Notifications instantanées (0-1 seconde)
|
|
- 🎯 Déclenchement uniquement quand nécessaire
|
|
- 💚 Réduction de la charge serveur
|
|
- 🎨 Meilleure UX
|
|
|
|
**Flow proposé :**
|
|
```
|
|
Widget détecte nouveau message/email
|
|
└─> Trigger notification refresh
|
|
└─> API /notifications/count (force refresh)
|
|
└─> Badge mis à jour immédiatement
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 Implémentation Proposée
|
|
|
|
### 1. Hook pour déclencher les notifications
|
|
|
|
**Fichier :** `hooks/use-trigger-notification.ts`
|
|
|
|
```typescript
|
|
import { useSession } from 'next-auth/react';
|
|
|
|
export function useTriggerNotification() {
|
|
const { data: session } = useSession();
|
|
|
|
const triggerNotificationRefresh = async () => {
|
|
if (!session?.user?.id) return;
|
|
|
|
try {
|
|
// Force refresh du notification count
|
|
await fetch('/api/notifications/count?_t=' + Date.now(), {
|
|
method: 'GET',
|
|
credentials: 'include',
|
|
cache: 'no-store'
|
|
});
|
|
|
|
// Le hook useNotifications écoutera ce changement
|
|
// via le système de refresh unifié
|
|
} catch (error) {
|
|
console.error('Error triggering notification refresh:', error);
|
|
}
|
|
};
|
|
|
|
return { triggerNotificationRefresh };
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 2. Intégration dans Parole (RocketChat)
|
|
|
|
**Fichier :** `components/parole.tsx`
|
|
|
|
**Modification :**
|
|
```typescript
|
|
import { useTriggerNotification } from '@/hooks/use-trigger-notification';
|
|
|
|
export function Parole() {
|
|
const { triggerNotificationRefresh } = useTriggerNotification();
|
|
const [lastMessageCount, setLastMessageCount] = useState(0);
|
|
|
|
const fetchMessages = async (isRefresh = false) => {
|
|
// ... code existant ...
|
|
|
|
const data = await response.json();
|
|
const currentUnreadCount = data.messages?.reduce((sum: number, msg: any) =>
|
|
sum + (msg.unread || 0), 0) || 0;
|
|
|
|
// Si nouveau message non lu détecté
|
|
if (currentUnreadCount > lastMessageCount) {
|
|
triggerNotificationRefresh(); // ⚡ Déclenchement immédiat
|
|
}
|
|
|
|
setLastMessageCount(currentUnreadCount);
|
|
};
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 3. Intégration dans Courrier (Email)
|
|
|
|
**Fichier :** `hooks/use-email-state.ts`
|
|
|
|
**Modification :**
|
|
```typescript
|
|
import { useTriggerNotification } from '@/hooks/use-trigger-notification';
|
|
|
|
export const useEmailState = () => {
|
|
const { triggerNotificationRefresh } = useTriggerNotification();
|
|
|
|
const checkForNewEmails = useCallback(async () => {
|
|
// ... code existant ...
|
|
|
|
if (data.newestEmailId && data.newestEmailId > lastKnownEmailId) {
|
|
// Nouvel email détecté
|
|
triggerNotificationRefresh(); // ⚡ Déclenchement immédiat
|
|
|
|
toast({
|
|
variant: "new-email",
|
|
title: "New emails",
|
|
description: "You have new emails in your inbox",
|
|
});
|
|
}
|
|
}, [triggerNotificationRefresh, ...]);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 4. Adapters pour RocketChat et Email (Optionnel)
|
|
|
|
Créer des adapters dédiés qui peuvent être pollés plus fréquemment :
|
|
|
|
**Fichier :** `lib/services/notifications/rocketchat-adapter.ts`
|
|
**Fichier :** `lib/services/notifications/email-adapter.ts`
|
|
|
|
Ces adapters pourraient :
|
|
- Poller toutes les 10-15 secondes (au lieu de 30s)
|
|
- Ou être déclenchés en temps réel via WebSocket/SSE
|
|
|
|
---
|
|
|
|
## 🎯 Stratégie Hybride Recommandée
|
|
|
|
### Combinaison Polling + Event-Driven
|
|
|
|
1. **Polling de base** : 30 secondes pour Leantime (inchangé)
|
|
2. **Event-driven** : Déclenchement immédiat quand :
|
|
- Parole détecte un nouveau message
|
|
- Courrier détecte un nouvel email
|
|
- Devoirs détecte une nouvelle tâche
|
|
|
|
3. **Cache invalidation** : Quand un widget détecte du nouveau, invalider le cache des notifications
|
|
|
|
---
|
|
|
|
## 📝 Plan d'Implémentation
|
|
|
|
### Phase 1 : Hook de déclenchement
|
|
- [ ] Créer `use-trigger-notification.ts`
|
|
- [ ] Fonction pour forcer le refresh du count
|
|
|
|
### Phase 2 : Intégration Parole
|
|
- [ ] Détecter nouveaux messages non lus
|
|
- [ ] Appeler `triggerNotificationRefresh()` quand détecté
|
|
|
|
### Phase 3 : Intégration Courrier
|
|
- [ ] Détecter nouveaux emails
|
|
- [ ] Appeler `triggerNotificationRefresh()` quand détecté
|
|
|
|
### Phase 4 : Optimisation
|
|
- [ ] Réduire polling Leantime à 60s (moins critique)
|
|
- [ ] Garder event-driven pour Parole/Courrier (temps réel)
|
|
|
|
---
|
|
|
|
## 🔄 Flow Final Proposé
|
|
|
|
```
|
|
Widget Parole/Courrier
|
|
└─> Détecte nouveau message/email
|
|
└─> triggerNotificationRefresh()
|
|
└─> POST /api/notifications/trigger-refresh
|
|
└─> Invalide cache Redis
|
|
└─> NotificationService.refreshCount()
|
|
└─> Badge mis à jour (< 1 seconde)
|
|
```
|
|
|
|
---
|
|
|
|
## 💡 Avantages de cette Approche
|
|
|
|
1. **Temps réel** : Notifications instantanées
|
|
2. **Efficace** : Pas de polling inutile
|
|
3. **Scalable** : Facile d'ajouter d'autres widgets
|
|
4. **Rétrocompatible** : Le polling reste en fallback
|
|
5. **Performance** : Réduction de 70-80% des appels API
|
|
|
|
---
|
|
|
|
## 🚨 Points d'Attention
|
|
|
|
1. **Déduplication** : S'assurer qu'on ne déclenche pas plusieurs fois
|
|
2. **Rate limiting** : Limiter les triggers si trop fréquents
|
|
3. **Fallback** : Garder le polling comme backup
|
|
4. **Cache** : Invalider intelligemment
|