✨ Nouvelles fonctionnalités: - Ajout du mode terrain pour utilisation mobile hors connexion - Génération automatique de reçus PDF avec template personnalisé - Révision complète du système de cartes avec amélioration des performances 🔧 Améliorations techniques: - Refactoring du module chat avec architecture simplifiée - Optimisation du système de sécurité NIST SP 800-63B - Amélioration de la gestion des secteurs géographiques - Support UTF-8 étendu pour les noms d'utilisateurs 📱 Application mobile: - Nouveau mode terrain dans user_field_mode_page - Interface utilisateur adaptative pour conditions difficiles - Synchronisation offline améliorée 🗺️ Cartographie: - Optimisation des performances MapBox - Meilleure gestion des tuiles hors ligne - Amélioration de l'affichage des secteurs 📄 Documentation: - Ajout guide Android (ANDROID-GUIDE.md) - Documentation sécurité API (API-SECURITY.md) - Guide module chat (CHAT_MODULE.md) 🐛 Corrections: - Résolution des erreurs 400 lors de la création d'utilisateurs - Correction de la validation des noms d'utilisateurs - Fix des problèmes de synchronisation chat 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
10 KiB
Module Chat - Documentation API
Vue d'ensemble
Le module Chat permet aux utilisateurs de l'application GeoSector de communiquer entre eux via une messagerie intégrée. Il supporte les conversations privées, de groupe et les diffusions (broadcast).
Architecture
Tables de base de données
chat_rooms: Salles de conversationchat_messages: Messages échangéschat_participants: Participants aux conversationschat_read_receipts: Accusés de lecture
Permissions par rôle
| Rôle | Permissions |
|---|---|
| 1 - Utilisateur | Conversations privées et groupes avec membres de son entité |
| 2 - Admin entité | Toutes conversations de son entité + création de diffusions |
| > 2 - Super admin | Accès total à toutes les conversations |
Flux d'utilisation du module Chat
📱 Vue d'ensemble du flux
Le module Chat fonctionne en mode chargement dynamique : les données sont récupérées à la demande, pas toutes en une fois au login.
1. Au login (/api/login)
La réponse du login contient un objet chat avec les informations de base :
{
"status": "success",
"user": {...},
"amicale": {...},
"chat": {
"total_rooms": 5, // Nombre total de conversations
"unread_messages": 12, // Total messages non lus
"chat_enabled": true, // Module activé pour cet utilisateur
"last_active_room": { // Dernière conversation active
"id": "uuid-room-123",
"title": "Discussion équipe",
"type": "group",
"last_message": "À demain !",
"last_message_at": "2025-01-17 18:30:00"
}
}
}
→ Permet d'afficher un badge de notification et de savoir si le chat est disponible
2. Ouverture de la page Chat
Étape 1 : Chargement initial
GET /api/chat/rooms
→ Récupère la liste des conversations avec aperçu du dernier message
Étape 2 : Sélection d'une conversation
GET /api/chat/rooms/{room_id}/messages?limit=50
→ Charge les 50 derniers messages (pagination disponible)
Étape 3 : Marquage comme lu
POST /api/chat/rooms/{room_id}/read
→ Met à jour les compteurs de messages non lus
3. Actions utilisateur
| Action | Endpoint | Description |
|---|---|---|
| Envoyer un message | POST /api/chat/rooms/{id}/messages |
Envoie et retourne le message créé |
| Créer une conversation | POST /api/chat/rooms |
Crée une nouvelle room |
| Obtenir les destinataires | GET /api/chat/recipients |
Liste des contacts disponibles |
| Charger plus de messages | GET /api/chat/rooms/{id}/messages?before={msg_id} |
Pagination |
4. Stratégies de rafraîchissement
Polling (recommandé pour débuter)
- Rafraîchir
/api/chat/roomstoutes les 30 secondes - Rafraîchir les messages de la conversation active toutes les 10 secondes
Pull to refresh
- Permettre à l'utilisateur de rafraîchir manuellement
Lifecycle events
- Recharger quand l'app revient au premier plan
- Rafraîchir après envoi d'un message
5. Exemple d'implémentation Flutter
class ChatService {
Timer? _roomsTimer;
Timer? _messagesTimer;
// 1. Au login, stocker les infos de base
void initFromLogin(Map<String, dynamic> chatData) {
_unreadCount = chatData['unread_messages'];
_chatEnabled = chatData['chat_enabled'];
notifyListeners();
}
// 2. À l'ouverture du chat
Future<void> openChatPage() async {
// Charger les conversations
final rooms = await api.get('/api/chat/rooms');
_rooms = rooms['rooms'];
// Démarrer le polling
_startPolling();
}
// 3. Sélection d'une conversation
Future<void> selectRoom(String roomId) async {
// Charger les messages
final response = await api.get('/api/chat/rooms/$roomId/messages');
_currentMessages = response['messages'];
// Marquer comme lu
await api.post('/api/chat/rooms/$roomId/read');
// Rafraîchir plus fréquemment cette conversation
_startMessagePolling(roomId);
}
// 4. Polling automatique
void _startPolling() {
_roomsTimer = Timer.periodic(Duration(seconds: 30), (_) {
_refreshRooms();
});
}
// 5. Nettoyage
void dispose() {
_roomsTimer?.cancel();
_messagesTimer?.cancel();
}
}
Endpoints API
1. GET /api/chat/rooms
Description : Récupère la liste des conversations de l'utilisateur
Réponse :
{
"status": "success",
"rooms": [
{
"id": "uuid-room-1",
"title": "Discussion équipe",
"type": "group",
"created_at": "2025-01-17 10:00:00",
"created_by": 123,
"updated_at": "2025-01-17 14:30:00",
"last_message": "Bonjour tout le monde",
"last_message_at": "2025-01-17 14:30:00",
"unread_count": 3,
"participant_count": 5,
"participants": [
{
"user_id": 123,
"name": "Jean Dupont",
"first_name": "Jean",
"is_admin": true
}
]
}
]
}
2. POST /api/chat/rooms
Description : Crée une nouvelle conversation
Body :
{
"type": "private|group|broadcast",
"title": "Titre optionnel (requis pour group/broadcast)",
"participants": [456, 789], // IDs des participants
"initial_message": "Message initial optionnel"
}
Règles :
private: Maximum 2 participants (incluant le créateur)group: Plusieurs participants possiblesbroadcast: Réservé aux admins (rôle >= 2)
Réponse :
{
"status": "success",
"room": {
"id": "uuid-new-room",
"title": "Nouvelle conversation",
"type": "group",
"created_at": "2025-01-17 15:00:00",
"participants": [...]
},
"existing": false // true si conversation privée existante trouvée
}
3. GET /api/chat/rooms/{id}/messages
Description : Récupère les messages d'une conversation
Paramètres :
limit: Nombre de messages (défaut: 50, max: 100)before: ID du message pour pagination
Réponse :
{
"status": "success",
"messages": [
{
"id": "uuid-message-1",
"content": "Bonjour !",
"sender_id": 123,
"sender_name": "Jean Dupont",
"sender_first_name": "Jean",
"sent_at": "2025-01-17 14:00:00",
"edited_at": null,
"is_deleted": false,
"is_read": true,
"is_mine": false,
"read_count": 3
}
],
"has_more": true
}
4. POST /api/chat/rooms/{id}/messages
Description : Envoie un message dans une conversation
Body :
{
"content": "Contenu du message (max 5000 caractères)"
}
Réponse :
{
"status": "success",
"message": {
"id": "uuid-new-message",
"content": "Message envoyé",
"sender_id": 123,
"sender_name": "Jean Dupont",
"sent_at": "2025-01-17 15:30:00",
"is_mine": true,
"is_read": false,
"read_count": 0
}
}
5. POST /api/chat/rooms/{id}/read
Description : Marque les messages comme lus
Body (optionnel) :
{
"message_ids": ["uuid-1", "uuid-2"] // Si omis, marque tous les messages
}
Réponse :
{
"status": "success",
"unread_count": 0 // Nombre de messages non lus restants
}
6. GET /api/chat/recipients
Description : Liste des destinataires possibles pour créer une conversation
Réponse :
{
"status": "success",
"recipients": [
{
"id": 456,
"name": "Marie Martin",
"first_name": "Marie",
"role": 1,
"entite_id": 5
}
],
"recipients_by_entity": {
"Amicale de Grenoble": [
{...}
],
"Amicale de Lyon": [
{...}
]
}
}
Fonctionnalités clés
1. Types de conversations
Private (Conversation privée)
- Entre 2 utilisateurs uniquement
- Détection automatique de conversation existante
- Pas de titre requis
Group (Groupe)
- Plusieurs participants
- Titre optionnel mais recommandé
- Admin de groupe (créateur)
Broadcast (Diffusion)
- Réservé aux admins (rôle >= 2)
- Communication unidirectionnelle possible
- Pour annonces importantes
2. Gestion des permissions
Le système vérifie automatiquement :
- L'appartenance à une conversation avant lecture/écriture
- Les droits de création selon le type de conversation
- La visibilité des destinataires selon le rôle
3. Statuts de lecture
- Accusés de lecture individuels : Chaque message peut être marqué comme lu
- Compteur de non-lus : Par conversation et global
- Last read : Timestamp de dernière lecture par participant
4. Optimisations
- Pagination : Chargement progressif des messages
- Index optimisés : Pour les requêtes fréquentes
- Vue SQL : Pour récupération rapide du dernier message
Sécurité
Chiffrement
- Les noms d'utilisateurs sont stockés chiffrés (AES-256)
- Déchiffrement à la volée lors de la lecture
Validation
- Longueur maximale des messages : 5000 caractères
- Trim automatique du contenu
- Vérification des permissions à chaque action
Isolation
- Les utilisateurs ne voient que leurs conversations autorisées
- Filtrage par entité selon le rôle
- Soft delete pour conservation de l'historique
Migration
Exécuter le script SQL :
mysql -u root -p geo_app < scripts/sql/create_chat_tables.sql
Évolutions futures possibles
- Notifications push : Intégration avec Firebase/WebSocket
- Fichiers joints : Support d'images et documents
- Réactions : Emojis sur les messages
- Mentions : @username pour notifier
- Recherche : Dans l'historique des messages
- Chiffrement E2E : Pour conversations sensibles
- Statuts de présence : En ligne/Hors ligne
- Indicateur de frappe : "X est en train d'écrire..."
Tests
Cas de test recommandés
-
Création de conversation privée
- Vérifier la détection de conversation existante
- Tester avec utilisateurs de différentes entités
-
Envoi de messages
- Messages avec caractères UTF-8 (émojis, accents)
- Messages très longs (limite 5000)
- Messages vides (doivent être rejetés)
-
Marquage comme lu
- Marquer messages spécifiques
- Marquer tous les messages d'une room
- Vérifier les compteurs
-
Permissions
- Utilisateur simple ne peut pas créer de broadcast
- Accès refusé aux conversations non autorisées
- Filtrage correct des destinataires
Support
Pour toute question ou problème :
- Vérifier les logs dans
/logs/ - Consulter les tables
chat_*en base de données - Tester avec les scripts de test fournis