feat: mise en place de la messagerie [#17]

This commit is contained in:
Luc SORIGNET
2025-05-26 13:24:42 +02:00
parent e2df29d851
commit d37145b73e
64 changed files with 13113 additions and 853 deletions

View File

@ -0,0 +1,340 @@
# API Messagerie Instantanée - Guide Développeur
## Vue d'ensemble
Cette documentation technique présente l'implémentation du système de messagerie instantanée, incluant les APIs WebSocket et REST, l'architecture des composants React et les fonctions utilitaires.
## API WebSocket
### Connexion
**URL de connexion :**
```javascript
// Développement
ws://localhost:8000/ws/chat/{userId}/
// Production
wss://[domaine]/ws/chat/{userId}/
```
### Messages WebSocket
#### Messages entrants (serveur → client)
```javascript
// Liste des conversations
{
"type": "conversations_list",
"conversations": [...]
}
// Nouveau message reçu
{
"type": "new_message",
"message": {
"id": 123,
"conversation_id": 456,
"sender_id": 789,
"content": "Contenu du message",
"timestamp": "2024-01-01T12:00:00Z"
}
}
// Utilisateur en train d'écrire
{
"type": "typing_start",
"conversation_id": 456,
"user_id": 789
}
// Utilisateur a arrêté d'écrire
{
"type": "typing_stop",
"conversation_id": 456,
"user_id": 789
}
```
#### Messages sortants (client → serveur)
```javascript
// Envoyer un message
{
"type": "chat_message",
"conversation_id": 456,
"message": "Contenu du message"
}
// Signaler début de frappe
{
"type": "typing_start",
"conversation_id": 456
}
// Signaler fin de frappe
{
"type": "typing_stop",
"conversation_id": 456
}
// Marquer comme lu
{
"type": "mark_as_read",
"conversation_id": 456
}
// Rejoindre une conversation
{
"type": "join_conversation",
"conversation_id": 456
}
```
## API REST
### Endpoints disponibles
```javascript
// Récupérer les conversations
GET /api/messagerie/conversations/{userId}/
Response: Array<Conversation>
// Récupérer les messages d'une conversation
GET /api/messagerie/messages/{conversationId}/
Response: Array<Message>
// Rechercher des destinataires
GET /api/messagerie/search/{establishmentId}/?q={query}
Response: Array<User>
// Créer une conversation
POST /api/messagerie/conversations/create/
Body: { "participants": [userId1, userId2] }
Response: Conversation
// Envoyer un email (séparé de la messagerie instantanée)
POST /api/email/send/
Body: { "recipients": [...], "subject": "...", "content": "..." }
```
## Composants React
### InstantChat
**Props :**
```javascript
{
userProfileId: number, // ID de l'utilisateur connecté
establishmentId: number // ID de l'établissement
}
```
**États principaux :**
- `conversations` : Liste des conversations
- `selectedConversation` : Conversation active
- `messages` : Messages de la conversation active
- `searchQuery` : Terme de recherche
- `searchResults` : Résultats de recherche de contacts
### useWebSocket Hook
**Paramètres :**
```javascript
useWebSocket(
userProfileId, // ID utilisateur
onMessage, // Callback pour messages reçus
onConnectionChange // Callback changement de connexion
);
```
**Valeurs retournées :**
```javascript
{
isConnected: boolean,
connectionStatus: string,
sendChatMessage: (conversationId, content) => boolean,
sendTypingStart: (conversationId) => void,
sendTypingStop: (conversationId) => void,
markAsRead: (conversationId) => void,
joinConversation: (conversationId) => void,
reconnect: () => void
}
```
## Actions Redux/State
### messagerieAction.js
```javascript
// Récupérer les conversations
fetchConversations(userId): Promise<Array<Conversation>>
// Récupérer les messages
fetchMessages(conversationId): Promise<Array<Message>>
// Rechercher des destinataires
searchMessagerieRecipients(establishmentId, query): Promise<Array<User>>
// Créer une conversation
createConversation(participants): Promise<Conversation>
```
### emailAction.js
```javascript
// Envoyer un email
sendEmail(recipients, subject, content, csrfToken): Promise<Response>
// Rechercher des destinataires email
searchEmailRecipients(establishmentId, query): Promise<Array<User>>
```
## Modèles de Données
### Conversation
```javascript
{
conversation_id: number,
participants: Array<User>,
last_message: Message,
created_at: string,
updated_at: string
}
```
### Message
```javascript
{
id: number,
conversation_id: number,
sender_id: number,
content: string,
timestamp: string,
is_read: boolean
}
```
### User
```javascript
{
id: number,
first_name: string,
last_name: string,
email: string,
role: string
}
```
## Gestion des Erreurs
### WebSocket
```javascript
// Reconnexion automatique
const reconnectWebSocket = () => {
setConnectionStatus('reconnecting');
// Logique de reconnexion avec backoff exponentiel
};
// Gestion des erreurs de connexion
wsRef.current.onerror = (error) => {
logger.error('Erreur WebSocket:', error);
setIsConnected(false);
};
```
### API REST
```javascript
// Wrapper avec gestion d'erreur
const apiCall = async (url, options) => {
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`Erreur ${response.status}`);
}
return await response.json();
} catch (error) {
logger.error('Erreur API:', error);
throw error;
}
};
```
## Configuration des Tests
### Jest Setup
```javascript
// jest.setup.js
global.WebSocket = class MockWebSocket {
// Mock complet du WebSocket pour les tests
};
global.fetch = jest.fn(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve([]),
})
);
```
### Tests des Composants
```javascript
// Exemple de test
test('renders InstantChat component', async () => {
await act(async () => {
render(<InstantChat userProfileId={1} establishmentId={123} />);
});
expect(screen.getByText('Messages')).toBeInTheDocument();
});
```
## Intégration Backend
### Consumer Django
```python
# consumers.py
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
# Logique de connexion
async def chat_message(self, event):
# Traitement des messages
```
### URLs Configuration
```python
# routing.py
websocket_urlpatterns = [
re_path(r'ws/chat/(?P<user_id>\w+)/$', ChatConsumer.as_asgi()),
]
```
## Optimisations
### Performance
- Pagination des messages anciens (load on scroll)
- Debounce pour la recherche de contacts (300ms)
- Memoization des composants avec React.memo
- Lazy loading des conversations
### UX
- Reconnexion automatique avec feedback visuel
- Sauvegarde locale des messages en cours de frappe
- Indicateurs de livraison des messages
- Scrolling automatique vers les nouveaux messages

View File

@ -0,0 +1,126 @@
# Système de Messagerie Instantanée
## Présentation
Le système de messagerie instantanée de N3WT-SCHOOL permet aux utilisateurs de l'établissement (administrateurs, professeurs, parents, étudiants) de communiquer en temps réel via une interface chat moderne et intuitive.
## Fonctionnalités
### Chat en Temps Réel
- Envoi et réception de messages instantanés
- Notification de statut de frappe (utilisateur en train d'écrire)
- Indicateur de statut de connexion WebSocket
- Reconnexion automatique en cas de perte de connexion
### Gestion des Conversations
- Liste des conversations existantes
- Création de nouvelles conversations
- Recherche de destinataires par nom ou email
- Compteur de messages non lus
### Interface Utilisateur
- Interface moderne en deux panneaux (conversations + chat)
- Bulles de messages différenciées (expéditeur/destinataire)
- Indicateurs visuels de statut de connexion
- Recherche temps réel de contacts
## Utilisation
### Accès au Chat
Le système de messagerie est accessible via les pages suivantes :
- **Parents** : `/[locale]/parents/messagerie`
- **Administrateurs** : Intégré dans le panneau d'administration
### Créer une Conversation
1. Cliquer sur le bouton "+" en haut à droite de la liste des conversations
2. Rechercher un contact en tapant son nom ou email
3. Sélectionner le destinataire dans les résultats
4. La conversation se crée automatiquement
### Envoyer un Message
1. Sélectionner une conversation dans la liste de gauche
2. Taper le message dans le champ de saisie en bas
3. Appuyer sur Entrée ou cliquer sur le bouton d'envoi
## Architecture Technique
### Frontend (React/Next.js)
**Composants principaux :**
- `InstantChat` : Composant principal du chat
- `ConnectionStatus` : Affichage du statut de connexion
- `ConversationItem` : Élément de liste de conversation
- `MessageBubble` : Bulle de message individuelle
- `MessageInput` : Zone de saisie de message
- `TypingIndicator` : Indicateur de frappe
**Hook personnalisé :**
- `useWebSocket` : Gestion de la connexion WebSocket et des événements
### Backend (Django)
**Module GestionMessagerie :**
- `consumers.py` : Consumer WebSocket pour la messagerie temps réel
- `routing.py` : Configuration des routes WebSocket
- `urls.py` : URLs API REST pour les conversations et messages
**Module GestionEmail :**
- `views.py` : Vues pour l'envoi d'emails classiques
- `urls.py` : URLs pour les fonctions email
### Communication
- **WebSocket** : Communication bidirectionnelle temps réel
- **REST API** : Chargement initial des données et recherche
- **Channels** : Gestion des groupes de conversation Django
## Configuration
### URLs WebSocket
Les URLs sont configurées automatiquement selon l'environnement :
- **Développement** : `ws://localhost:8000/ws/chat/`
- **Production** : `wss://[domaine]/ws/chat/`
### Variables d'Environnement
Le système utilise les configurations standard de l'application pour :
- Base de données (conversations, messages, utilisateurs)
- Authentification (sessions Django)
- Établissements (filtrage par établissement)
## Sécurité
- Authentification requise pour accéder au chat
- Filtrage des conversations par établissement
- Validation côté serveur de tous les messages
- Gestion des permissions selon le rôle utilisateur
## Tests
Le système dispose de tests unitaires Jest couvrant :
- Rendu des composants
- Gestion des connexions WebSocket
- Recherche de contacts
- Envoi de messages
- Indicateurs de frappe
Exécution des tests :
```bash
npm test
```