mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 16:03:21 +00:00
341 lines
6.4 KiB
Markdown
341 lines
6.4 KiB
Markdown
# 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
|