feat: Release version 3.1.4 - Mode terrain et génération PDF
✨ 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>
This commit is contained in:
334
api/docs/API-SECURITY.md
Normal file
334
api/docs/API-SECURITY.md
Normal file
@@ -0,0 +1,334 @@
|
||||
# API Security & Performance Monitoring
|
||||
|
||||
## 📋 Vue d'ensemble
|
||||
|
||||
Système complet de sécurité et monitoring pour l'API GeoSector implémenté et opérationnel.
|
||||
|
||||
### ✅ Fonctionnalités implémentées
|
||||
|
||||
- **Détection d'intrusions** : Brute force, SQL injection, patterns de scan
|
||||
- **Monitoring des performances** : Temps de réponse, utilisation mémoire, requêtes DB
|
||||
- **Alertes email intelligentes** : Throttling, niveaux de priorité
|
||||
- **Blocage d'IP automatique** : Temporaire ou permanent
|
||||
- **Traçabilité complète** : Historique pour audit et analyse
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
### Tables de base de données (préfixe `sec_`)
|
||||
|
||||
```sql
|
||||
-- 4 tables créées dans scripts/sql/create_security_tables.sql
|
||||
sec_alerts -- Alertes de sécurité
|
||||
sec_performance_metrics -- Métriques de performance
|
||||
sec_failed_login_attempts -- Tentatives de connexion échouées
|
||||
sec_blocked_ips -- IPs bloquées
|
||||
```
|
||||
|
||||
### Services PHP implémentés
|
||||
|
||||
```
|
||||
src/Services/Security/
|
||||
├── AlertService.php # Gestion centralisée des alertes
|
||||
├── EmailThrottler.php # Anti-spam pour emails
|
||||
├── SecurityMonitor.php # Détection des menaces
|
||||
├── PerformanceMonitor.php # Monitoring des temps
|
||||
└── IPBlocker.php # Gestion des blocages IP
|
||||
```
|
||||
|
||||
### Contrôleur d'administration
|
||||
|
||||
```
|
||||
src/Controllers/SecurityController.php # Interface d'administration
|
||||
```
|
||||
|
||||
## 🚀 Installation
|
||||
|
||||
### 1. Créer les tables
|
||||
|
||||
```bash
|
||||
# Exécuter le script SQL sur chaque environnement
|
||||
mysql -u root -p geo_app < scripts/sql/create_security_tables.sql
|
||||
```
|
||||
|
||||
### 2. Configurer le cron de purge
|
||||
|
||||
```bash
|
||||
# Ajouter dans crontab (crontab -e)
|
||||
0 2 * * * /usr/bin/php /var/www/geosector/api/scripts/cron/cleanup_security_data.php >> /var/log/security_cleanup.log 2>&1
|
||||
```
|
||||
|
||||
### 3. Tester l'installation
|
||||
|
||||
```bash
|
||||
php test_security.php
|
||||
```
|
||||
|
||||
## 🔒 Fonctionnement
|
||||
|
||||
### Détection automatique
|
||||
|
||||
Le système détecte et bloque automatiquement :
|
||||
|
||||
- **Brute force** : 5 tentatives échouées en 5 minutes → IP bloquée 1h
|
||||
- **SQL injection** : Patterns suspects → IP bloquée définitivement
|
||||
- **Scan de vulnérabilités** : Accès aux fichiers sensibles → IP bloquée 1h
|
||||
- **Rate limiting** : Plus de 60 requêtes/minute → Rejet temporaire
|
||||
|
||||
### Monitoring de performance
|
||||
|
||||
Chaque requête est automatiquement monitorée :
|
||||
|
||||
```php
|
||||
// Dans index.php
|
||||
PerformanceMonitor::startRequest();
|
||||
// ... traitement ...
|
||||
PerformanceMonitor::endRequest($endpoint, $method, $statusCode);
|
||||
```
|
||||
|
||||
### Alertes email
|
||||
|
||||
Configuration des niveaux :
|
||||
|
||||
- **INFO** : Log uniquement
|
||||
- **WARNING** : Email avec throttling 1h
|
||||
- **ERROR** : Email avec throttling 15min
|
||||
- **CRITICAL** : Email avec throttling 5min
|
||||
- **SECURITY** : Email immédiat, priorité haute
|
||||
|
||||
## 📊 Endpoints d'administration
|
||||
|
||||
Tous les endpoints nécessitent une authentification admin (role >= 2) :
|
||||
|
||||
```
|
||||
GET /api/admin/metrics # Métriques de performance
|
||||
GET /api/admin/alerts # Alertes actives
|
||||
POST /api/admin/alerts/:id/resolve # Résoudre une alerte
|
||||
GET /api/admin/blocked-ips # IPs bloquées
|
||||
POST /api/admin/unblock-ip # Débloquer une IP
|
||||
POST /api/admin/block-ip # Bloquer une IP manuellement
|
||||
GET /api/admin/security-report # Rapport complet
|
||||
POST /api/admin/cleanup # Nettoyer les anciennes données
|
||||
POST /api/admin/test-alert # Tester les alertes
|
||||
```
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Seuils par défaut (modifiables dans les services)
|
||||
|
||||
```php
|
||||
// PerformanceMonitor.php
|
||||
const DEFAULT_THRESHOLDS = [
|
||||
'response_time_warning' => 1000, // 1 seconde
|
||||
'response_time_critical' => 3000, // 3 secondes
|
||||
'db_time_warning' => 500, // 500ms
|
||||
'db_time_critical' => 1000, // 1 seconde
|
||||
'memory_warning' => 64, // 64 MB
|
||||
'memory_critical' => 128 // 128 MB
|
||||
];
|
||||
|
||||
// SecurityMonitor.php
|
||||
- Brute force : 5 tentatives en 5 minutes
|
||||
- Rate limit : 60 requêtes par minute
|
||||
- 404 pattern : 10 erreurs 404 en 10 minutes
|
||||
|
||||
// EmailThrottler.php
|
||||
const DEFAULT_CONFIG = [
|
||||
'max_per_hour' => 10,
|
||||
'max_per_day' => 50,
|
||||
'digest_after' => 5,
|
||||
'cooldown_minutes' => 60
|
||||
];
|
||||
```
|
||||
|
||||
### Rétention des données
|
||||
|
||||
Configurée dans `scripts/cron/cleanup_security_data.php` :
|
||||
|
||||
```php
|
||||
$RETENTION_DAYS = [
|
||||
'performance_metrics' => 30, // 30 jours
|
||||
'failed_login_attempts' => 7, // 7 jours
|
||||
'resolved_alerts' => 90, // 90 jours
|
||||
'expired_blocks' => 0 // Déblocage immédiat
|
||||
];
|
||||
```
|
||||
|
||||
## 📈 Métriques surveillées
|
||||
|
||||
### Performance
|
||||
- Temps de réponse total
|
||||
- Temps cumulé des requêtes DB
|
||||
- Nombre de requêtes DB
|
||||
- Utilisation mémoire (pic et moyenne)
|
||||
- Codes HTTP de réponse
|
||||
|
||||
### Sécurité
|
||||
- Tentatives de connexion échouées
|
||||
- IPs bloquées (temporaires/permanentes)
|
||||
- Patterns d'attaque détectés
|
||||
- Alertes par type et niveau
|
||||
|
||||
## 🛡️ Patterns de détection
|
||||
|
||||
### SQL Injection
|
||||
```php
|
||||
// Patterns détectés dans SecurityMonitor.php
|
||||
- UNION SELECT
|
||||
- DROP TABLE
|
||||
- INSERT INTO
|
||||
- UPDATE SET
|
||||
- DELETE FROM
|
||||
- Script tags
|
||||
- OR 1=1
|
||||
- Commentaires SQL (--)
|
||||
```
|
||||
|
||||
### Fichiers sensibles
|
||||
```php
|
||||
// Patterns de scan détectés
|
||||
- admin, administrator
|
||||
- wp-admin, phpmyadmin
|
||||
- .git, .env
|
||||
- config.php
|
||||
- backup, .sql, .zip
|
||||
- shell.php, eval.php
|
||||
```
|
||||
|
||||
## 📝 Exemples d'utilisation
|
||||
|
||||
### Déclencher une alerte manuelle
|
||||
|
||||
```php
|
||||
use App\Services\Security\AlertService;
|
||||
|
||||
AlertService::trigger('CUSTOM_ALERT', [
|
||||
'message' => 'Événement important détecté',
|
||||
'details' => ['user' => $userId, 'action' => $action]
|
||||
], 'WARNING');
|
||||
```
|
||||
|
||||
### Bloquer une IP manuellement
|
||||
|
||||
```php
|
||||
use App\Services\Security\IPBlocker;
|
||||
|
||||
// Blocage temporaire (1 heure)
|
||||
IPBlocker::block('192.168.1.100', 3600, 'Comportement suspect');
|
||||
|
||||
// Blocage permanent
|
||||
IPBlocker::blockPermanent('192.168.1.100', 'Attaque confirmée');
|
||||
```
|
||||
|
||||
### Obtenir les statistiques
|
||||
|
||||
```php
|
||||
use App\Services\Security\SecurityMonitor;
|
||||
use App\Services\Security\PerformanceMonitor;
|
||||
|
||||
$securityStats = SecurityMonitor::getSecurityStats();
|
||||
$perfStats = PerformanceMonitor::getStats(null, 24); // 24h
|
||||
```
|
||||
|
||||
## ⚠️ Points d'attention
|
||||
|
||||
### RGPD
|
||||
- Les IPs sont des données personnelles
|
||||
- Durée de conservation limitée (voir rétention)
|
||||
- Anonymisation après traitement
|
||||
|
||||
### Performance
|
||||
- Overhead < 5ms par requête
|
||||
- Optimisation des tables avec index
|
||||
- Purge automatique des anciennes données
|
||||
|
||||
### Sécurité
|
||||
- Pas d'exposition de données sensibles dans les alertes
|
||||
- Chiffrement des données utilisateur
|
||||
- Whitelist pour IPs de confiance (localhost)
|
||||
|
||||
## 🔄 Maintenance
|
||||
|
||||
### Quotidienne (cron)
|
||||
```bash
|
||||
# Purge automatique à 2h du matin
|
||||
0 2 * * * php /var/www/geosector/api/scripts/cron/cleanup_security_data.php
|
||||
```
|
||||
|
||||
### Hebdomadaire
|
||||
- Vérifier les alertes actives
|
||||
- Analyser les tendances de performance
|
||||
- Ajuster les seuils si nécessaire
|
||||
|
||||
### Mensuelle
|
||||
- Analyser le rapport de sécurité
|
||||
- Mettre à jour les IPs whitelist/blacklist
|
||||
- Optimiser les tables si nécessaire
|
||||
|
||||
## 🐛 Dépannage
|
||||
|
||||
### Les tables n'existent pas
|
||||
```bash
|
||||
# Créer les tables
|
||||
mysql -u root -p geo_app < scripts/sql/create_security_tables.sql
|
||||
```
|
||||
|
||||
### Pas d'alertes email
|
||||
- Vérifier la configuration email dans `AppConfig`
|
||||
- Vérifier les logs : `tail -f logs/geosector-*.log`
|
||||
- Tester avec : `POST /api/admin/test-alert`
|
||||
|
||||
### IP bloquée par erreur
|
||||
```bash
|
||||
# Via API
|
||||
curl -X POST https://dapp.geosector.fr/api/admin/unblock-ip \
|
||||
-H "Authorization: Bearer TOKEN" \
|
||||
-d '{"ip": "192.168.1.100"}'
|
||||
|
||||
# Via MySQL
|
||||
UPDATE sec_blocked_ips SET unblocked_at = NOW() WHERE ip_address = '192.168.1.100';
|
||||
```
|
||||
|
||||
## 📚 Ressources
|
||||
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [PHP Security Best Practices](https://www.php.net/manual/en/security.php)
|
||||
- Code source : `/src/Services/Security/`
|
||||
- Tests : `test_security.php`
|
||||
- Logs : `/logs/geosector-*.log`
|
||||
|
||||
## 🎯 Statut d'implémentation
|
||||
|
||||
✅ **Phase 1** : Infrastructure de base - COMPLÉTÉ
|
||||
- Tables créées avec préfixe `sec_`
|
||||
- Services PHP implémentés
|
||||
- Intégration dans index.php et Database.php
|
||||
|
||||
✅ **Phase 2** : Monitoring de Performance - COMPLÉTÉ
|
||||
- Chronométrage automatique des requêtes
|
||||
- Monitoring des requêtes DB
|
||||
- Alertes sur dégradation
|
||||
|
||||
✅ **Phase 3** : Détection d'intrusions - COMPLÉTÉ
|
||||
- Détection brute force
|
||||
- Détection SQL injection
|
||||
- Blocage IP automatique
|
||||
|
||||
✅ **Phase 4** : Alertes Email - COMPLÉTÉ
|
||||
- Service d'alertes avec throttling
|
||||
- Templates d'emails
|
||||
- Niveaux de priorité
|
||||
|
||||
✅ **Phase 5** : Administration - COMPLÉTÉ
|
||||
- Endpoints d'administration
|
||||
- Interface de gestion
|
||||
- Rapports de sécurité
|
||||
|
||||
✅ **Phase 6** : Maintenance - COMPLÉTÉ
|
||||
- Script de purge automatique
|
||||
- Optimisation des tables
|
||||
- Documentation complète
|
||||
|
||||
---
|
||||
|
||||
*Dernière mise à jour : 2025-01-17*
|
||||
*Version : 1.0.0*
|
||||
419
api/docs/CHAT_MODULE.md
Normal file
419
api/docs/CHAT_MODULE.md
Normal file
@@ -0,0 +1,419 @@
|
||||
# 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 conversation
|
||||
- `chat_messages` : Messages échangés
|
||||
- `chat_participants` : Participants aux conversations
|
||||
- `chat_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 :
|
||||
|
||||
```json
|
||||
{
|
||||
"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/rooms` toutes 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
|
||||
|
||||
```dart
|
||||
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** :
|
||||
```json
|
||||
{
|
||||
"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** :
|
||||
```json
|
||||
{
|
||||
"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 possibles
|
||||
- `broadcast` : Réservé aux admins (rôle >= 2)
|
||||
|
||||
**Réponse** :
|
||||
```json
|
||||
{
|
||||
"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** :
|
||||
```json
|
||||
{
|
||||
"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** :
|
||||
```json
|
||||
{
|
||||
"content": "Contenu du message (max 5000 caractères)"
|
||||
}
|
||||
```
|
||||
|
||||
**Réponse** :
|
||||
```json
|
||||
{
|
||||
"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)** :
|
||||
```json
|
||||
{
|
||||
"message_ids": ["uuid-1", "uuid-2"] // Si omis, marque tous les messages
|
||||
}
|
||||
```
|
||||
|
||||
**Réponse** :
|
||||
```json
|
||||
{
|
||||
"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** :
|
||||
```json
|
||||
{
|
||||
"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 :
|
||||
```bash
|
||||
mysql -u root -p geo_app < scripts/sql/create_chat_tables.sql
|
||||
```
|
||||
|
||||
## Évolutions futures possibles
|
||||
|
||||
1. **Notifications push** : Intégration avec Firebase/WebSocket
|
||||
2. **Fichiers joints** : Support d'images et documents
|
||||
3. **Réactions** : Emojis sur les messages
|
||||
4. **Mentions** : @username pour notifier
|
||||
5. **Recherche** : Dans l'historique des messages
|
||||
6. **Chiffrement E2E** : Pour conversations sensibles
|
||||
7. **Statuts de présence** : En ligne/Hors ligne
|
||||
8. **Indicateur de frappe** : "X est en train d'écrire..."
|
||||
|
||||
## Tests
|
||||
|
||||
### Cas de test recommandés
|
||||
|
||||
1. **Création de conversation privée**
|
||||
- Vérifier la détection de conversation existante
|
||||
- Tester avec utilisateurs de différentes entités
|
||||
|
||||
2. **Envoi de messages**
|
||||
- Messages avec caractères UTF-8 (émojis, accents)
|
||||
- Messages très longs (limite 5000)
|
||||
- Messages vides (doivent être rejetés)
|
||||
|
||||
3. **Marquage comme lu**
|
||||
- Marquer messages spécifiques
|
||||
- Marquer tous les messages d'une room
|
||||
- Vérifier les compteurs
|
||||
|
||||
4. **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
|
||||
176
api/docs/FIX_USER_CREATION_400_ERRORS.md
Normal file
176
api/docs/FIX_USER_CREATION_400_ERRORS.md
Normal file
@@ -0,0 +1,176 @@
|
||||
# Correction des erreurs 400 lors de la création d'utilisateurs
|
||||
|
||||
## Problème identifié
|
||||
Un administrateur (fk_role=2) rencontrait des erreurs 400 répétées lors de tentatives de création de membre, menant à un bannissement par fail2ban :
|
||||
- 17:09:39 - POST /api/users HTTP/1.1 400 (Bad Request)
|
||||
- 17:10:44 - POST /api/users/check-username HTTP/1.1 400 (Bad Request)
|
||||
- 17:11:21 - POST /api/users HTTP/1.1 400 (Bad Request)
|
||||
|
||||
## Causes identifiées
|
||||
|
||||
### 1. Conflit de routage (CRITIQUE)
|
||||
**Problème:** La route `/api/users/check-username` était déclarée APRÈS la route générique `/api/users` dans Router.php, causant une mauvaise interprétation où "check-username" était traité comme un ID utilisateur.
|
||||
|
||||
**Solution:** Déplacer la déclaration de la route spécifique AVANT les routes avec paramètres.
|
||||
|
||||
### 2. Messages d'erreur non informatifs
|
||||
**Problème:** Les erreurs 400 retournaient des messages génériques sans détails sur le champ problématique.
|
||||
|
||||
**Solution:** Ajout de messages d'erreur détaillés incluant :
|
||||
- Le champ en erreur (`field`)
|
||||
- La valeur problématique (`value`)
|
||||
- Le format attendu (`format`)
|
||||
- La raison de l'erreur (`reason`)
|
||||
|
||||
### 3. Manque de logs de débogage
|
||||
**Problème:** Aucun log n'était généré pour tracer les erreurs de validation.
|
||||
|
||||
**Solution:** Ajout de logs détaillés à chaque point de validation.
|
||||
|
||||
## Modifications apportées
|
||||
|
||||
### 1. Router.php (ligne 36-44)
|
||||
```php
|
||||
// AVANT (incorrect)
|
||||
$this->post('users', ['UserController', 'createUser']);
|
||||
$this->post('users/check-username', ['UserController', 'checkUsername']);
|
||||
|
||||
// APRÈS (correct)
|
||||
$this->post('users/check-username', ['UserController', 'checkUsername']); // Route spécifique en premier
|
||||
$this->post('users', ['UserController', 'createUser']);
|
||||
```
|
||||
|
||||
### 2. UserController.php - Amélioration des validations
|
||||
|
||||
#### Validation de l'email
|
||||
```php
|
||||
// Réponse améliorée
|
||||
Response::json([
|
||||
'status' => 'error',
|
||||
'message' => 'Email requis',
|
||||
'field' => 'email' // Indique clairement le champ problématique
|
||||
], 400);
|
||||
```
|
||||
|
||||
#### Validation du username manuel
|
||||
```php
|
||||
// Réponse améliorée
|
||||
Response::json([
|
||||
'status' => 'error',
|
||||
'message' => 'Le nom d\'utilisateur est requis pour cette entité',
|
||||
'field' => 'username',
|
||||
'reason' => 'L\'entité requiert la saisie manuelle des identifiants'
|
||||
], 400);
|
||||
```
|
||||
|
||||
#### Format du username
|
||||
```php
|
||||
// Réponse améliorée
|
||||
Response::json([
|
||||
'status' => 'error',
|
||||
'message' => 'Format du nom d\'utilisateur invalide',
|
||||
'field' => 'username',
|
||||
'format' => '10-30 caractères, commence par une lettre, caractères autorisés: a-z, 0-9, ., -, _',
|
||||
'value' => $username // Montre la valeur soumise
|
||||
], 400);
|
||||
```
|
||||
|
||||
### 3. Ajout de logs détaillés
|
||||
|
||||
Chaque point de validation génère maintenant un log avec :
|
||||
- Le type d'erreur
|
||||
- L'utilisateur qui fait la requête
|
||||
- Les données reçues (sans données sensibles)
|
||||
- Le contexte de l'erreur
|
||||
|
||||
Exemple :
|
||||
```php
|
||||
LogService::log('Erreur création utilisateur : Format username invalide', [
|
||||
'level' => 'warning',
|
||||
'createdBy' => $currentUserId,
|
||||
'email' => $email,
|
||||
'username' => $username,
|
||||
'username_length' => strlen($username)
|
||||
]);
|
||||
```
|
||||
|
||||
## Cas d'erreur 400 possibles
|
||||
|
||||
### Pour /api/users (création)
|
||||
|
||||
1. **Email manquant ou vide**
|
||||
- Message: "Email requis"
|
||||
- Field: "email"
|
||||
|
||||
2. **Nom manquant ou vide**
|
||||
- Message: "Nom requis"
|
||||
- Field: "name"
|
||||
|
||||
3. **Format email invalide**
|
||||
- Message: "Format d'email invalide"
|
||||
- Field: "email"
|
||||
- Value: [email soumis]
|
||||
|
||||
4. **Username manuel requis mais manquant** (si chk_username_manuel=1)
|
||||
- Message: "Le nom d'utilisateur est requis pour cette entité"
|
||||
- Field: "username"
|
||||
- Reason: "L'entité requiert la saisie manuelle des identifiants"
|
||||
|
||||
5. **Format username invalide**
|
||||
- Message: "Format du nom d'utilisateur invalide"
|
||||
- Field: "username"
|
||||
- Format: "10-30 caractères, commence par une lettre..."
|
||||
- Value: [username soumis]
|
||||
|
||||
6. **Mot de passe manuel requis mais manquant** (si chk_mdp_manuel=1)
|
||||
- Message: "Le mot de passe est requis pour cette entité"
|
||||
- Field: "password"
|
||||
- Reason: "L'entité requiert la saisie manuelle des mots de passe"
|
||||
|
||||
### Pour /api/users/check-username
|
||||
|
||||
1. **Username manquant**
|
||||
- Message: "Username requis pour la vérification"
|
||||
- Field: "username"
|
||||
|
||||
2. **Format username invalide**
|
||||
- Message: "Format invalide"
|
||||
- Field: "username"
|
||||
- Format: "10-30 caractères, commence par une lettre..."
|
||||
- Value: [username soumis]
|
||||
|
||||
## Test de la solution
|
||||
|
||||
Un script de test a été créé : `/tests/test_user_creation.php`
|
||||
|
||||
Il teste tous les cas d'erreur possibles et vérifie que :
|
||||
1. Les codes HTTP sont corrects
|
||||
2. Les messages d'erreur sont informatifs
|
||||
3. Les champs en erreur sont identifiés
|
||||
|
||||
## Recommandations pour éviter le bannissement fail2ban
|
||||
|
||||
1. **Côté client (application Flutter)** :
|
||||
- Valider les données AVANT l'envoi
|
||||
- Afficher clairement les erreurs à l'utilisateur
|
||||
- Implémenter un délai entre les tentatives (rate limiting côté client)
|
||||
|
||||
2. **Côté API** :
|
||||
- Les messages d'erreur détaillés permettent maintenant de corriger rapidement les problèmes
|
||||
- Les logs permettent de diagnostiquer les problèmes récurrents
|
||||
|
||||
3. **Configuration fail2ban** :
|
||||
- Considérer d'augmenter le seuil pour les erreurs 400 (ex: 5 tentatives au lieu de 3)
|
||||
- Exclure certaines IP de confiance si nécessaire
|
||||
|
||||
## Suivi des logs
|
||||
|
||||
Les logs sont maintenant générés dans :
|
||||
- `/logs/geosector-[environment]-[date].log` : Logs généraux avec détails des erreurs
|
||||
|
||||
Format des logs :
|
||||
```
|
||||
timestamp;browser;os;client_type;level;metadata;message
|
||||
```
|
||||
|
||||
Les erreurs de validation sont loggées avec le niveau "warning" pour permettre un suivi sans être critiques.
|
||||
@@ -779,7 +779,7 @@ fetch('/api/endpoint', {
|
||||
|
||||
## Changements récents
|
||||
|
||||
### Version 3.0.7 (Janvier 2025)
|
||||
### Version 3.0.7 (Août 2025)
|
||||
|
||||
#### 1. Implémentation complète de la norme NIST SP 800-63B pour les mots de passe
|
||||
- **Nouveau service :** `PasswordSecurityService` pour la gestion sécurisée des mots de passe
|
||||
@@ -797,7 +797,7 @@ fetch('/api/endpoint', {
|
||||
- **Choix client :** Permet d'avoir un mot de passe identique au nom d'utilisateur
|
||||
- **Pas de vérification contextuelle :** Aucune vérification nom/email dans le mot de passe
|
||||
|
||||
### Version 3.0.6 (Janvier 2025)
|
||||
### Version 3.0.6 (Août 2025)
|
||||
|
||||
#### 1. Correction des rôles administrateurs
|
||||
- **Avant :** Les administrateurs d'amicale devaient avoir `fk_role > 2`
|
||||
@@ -836,3 +836,28 @@ fetch('/api/endpoint', {
|
||||
- **Format d'envoi des images :** Base64 data URL pour compatibilité multiplateforme
|
||||
- **Structure de réponse enrichie :** Le logo est inclus dans l'objet `amicale` lors du login
|
||||
- **Optimisation :** Pas de requête HTTP supplémentaire nécessaire pour afficher le logo
|
||||
|
||||
### Version 3.0.8 (Janvier 2025)
|
||||
|
||||
#### 1. Système de génération automatique de reçus fiscaux pour les dons
|
||||
- **Nouveau service :** `ReceiptService` pour la génération automatique de reçus PDF
|
||||
- **Déclencheurs automatiques :**
|
||||
- Création d'un passage avec `fk_type=1` (don) et email valide
|
||||
- Mise à jour d'un passage en don si `nom_recu` est vide/null
|
||||
- **Caractéristiques techniques :**
|
||||
- PDF ultra-légers (< 5KB) générés en format natif sans librairie externe
|
||||
- Support des caractères accentués avec conversion automatique
|
||||
- Stockage structuré : `/uploads/entites/{entite_id}/recus/{operation_id}/`
|
||||
- Enregistrement dans la table `medias` avec catégorie `recu`
|
||||
- **Queue d'envoi email :**
|
||||
- Envoi automatique par email avec pièce jointe PDF
|
||||
- Format MIME multipart pour compatibilité maximale
|
||||
- Gestion dans la table `email_queue` avec statut de suivi
|
||||
- **Nouvelle route API :**
|
||||
- `GET /api/passages/{id}/receipt` : Récupération du PDF d'un reçu
|
||||
- Retourne le PDF en base64 ou téléchargement direct selon Accept header
|
||||
- **Champs base de données utilisés :**
|
||||
- `nom_recu` : Nom du fichier PDF généré
|
||||
- `date_creat_recu` : Date de génération du reçu
|
||||
- `date_sent_recu` : Date d'envoi par email
|
||||
- `chk_email_sent` : Indicateur d'envoi réussi
|
||||
|
||||
135
api/docs/USERNAME_VALIDATION_CHANGES.md
Normal file
135
api/docs/USERNAME_VALIDATION_CHANGES.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# Changements de validation des usernames - Version ultra-souple
|
||||
|
||||
## Date : 17 janvier 2025
|
||||
|
||||
## Contexte
|
||||
Suite aux problèmes d'erreurs 400 et au besoin d'avoir une approche plus moderne et inclusive, les règles de validation des usernames ont été assouplies pour accepter tous les caractères UTF-8, similaire à l'approche NIST pour les mots de passe.
|
||||
|
||||
## Anciennes règles (trop restrictives)
|
||||
- ❌ 10-30 caractères
|
||||
- ❌ Doit commencer par une lettre minuscule
|
||||
- ❌ Seulement : a-z, 0-9, ., -, _
|
||||
- ❌ Pas d'espaces
|
||||
- ❌ Pas de majuscules
|
||||
- ❌ Pas d'accents ou caractères spéciaux
|
||||
|
||||
## Nouvelles règles (ultra-souples)
|
||||
- ✅ **8-30 caractères UTF-8**
|
||||
- ✅ **Tous caractères acceptés** :
|
||||
- Lettres (majuscules/minuscules)
|
||||
- Chiffres
|
||||
- Espaces
|
||||
- Caractères spéciaux (!@#$%^&*()_+-=[]{}|;:'"<>,.?/)
|
||||
- Accents (é, è, à, ñ, ü, etc.)
|
||||
- Émojis (😀, 🎉, ❤️, etc.)
|
||||
- Caractères non-latins (中文, العربية, Русский, etc.)
|
||||
- ✅ **Sensible à la casse** (Jean ≠ jean)
|
||||
- ✅ **Trim automatique** des espaces début/fin
|
||||
- ✅ **Unicité vérifiée** dans toute la base
|
||||
|
||||
## Exemples de usernames valides
|
||||
|
||||
### Noms classiques
|
||||
- `Jean-Pierre`
|
||||
- `Marie Claire` (avec espace)
|
||||
- `O'Connor`
|
||||
- `José García`
|
||||
|
||||
### Avec chiffres et caractères spéciaux
|
||||
- `admin2024`
|
||||
- `user@company`
|
||||
- `test_user#1`
|
||||
- `Marie*123!`
|
||||
|
||||
### International
|
||||
- `李明` (chinois)
|
||||
- `محمد` (arabe)
|
||||
- `Владимир` (russe)
|
||||
- `さくら` (japonais)
|
||||
- `Παύλος` (grec)
|
||||
|
||||
### Modernes/Fun
|
||||
- `🦄Unicorn`
|
||||
- `Player_1 🎮`
|
||||
- `☕Coffee.Lover`
|
||||
- `2024_User`
|
||||
|
||||
## Exemples de usernames invalides
|
||||
- `short` ❌ (moins de 8 caractères)
|
||||
- ` ` ❌ (espaces seulement)
|
||||
- `very_long_username_that_exceeds_thirty_chars` ❌ (plus de 30 caractères)
|
||||
|
||||
## Modifications techniques
|
||||
|
||||
### 1. Code PHP (UserController.php)
|
||||
```php
|
||||
// Avant (restrictif)
|
||||
if (!preg_match('/^[a-z][a-z0-9._-]{9,29}$/', $username))
|
||||
|
||||
// Après (ultra-souple)
|
||||
$username = trim($data['username']);
|
||||
$usernameLength = mb_strlen($username, 'UTF-8');
|
||||
|
||||
if ($usernameLength < 8) {
|
||||
// Erreur : trop court
|
||||
}
|
||||
if ($usernameLength > 30) {
|
||||
// Erreur : trop long
|
||||
}
|
||||
// C'est tout ! Pas d'autre validation
|
||||
```
|
||||
|
||||
### 2. Base de données
|
||||
```sql
|
||||
-- Script à exécuter : scripts/sql/migration_username_utf8_support.sql
|
||||
ALTER TABLE `users`
|
||||
MODIFY COLUMN `encrypted_user_name` varchar(255) DEFAULT '';
|
||||
```
|
||||
|
||||
### 3. Messages d'erreur simplifiés
|
||||
- Avant : "Format du nom d'utilisateur invalide (10-30 caractères, commence par une lettre, caractères autorisés: a-z, 0-9, ., -, _)"
|
||||
- Après :
|
||||
- "Identifiant trop court" + "Minimum 8 caractères"
|
||||
- "Identifiant trop long" + "Maximum 30 caractères"
|
||||
- "Identifiant déjà utilisé"
|
||||
|
||||
## Impact sur l'expérience utilisateur
|
||||
|
||||
### Avantages
|
||||
1. **Inclusivité** : Support de toutes les langues et cultures
|
||||
2. **Modernité** : Permet les émojis et caractères spéciaux
|
||||
3. **Simplicité** : Règles faciles à comprendre (juste la longueur)
|
||||
4. **Flexibilité** : Les utilisateurs peuvent choisir l'identifiant qu'ils veulent
|
||||
5. **Moins d'erreurs** : Moins de rejets pour format invalide
|
||||
|
||||
### Points d'attention
|
||||
1. **Support client** : Former le support aux nouveaux formats possibles
|
||||
2. **Affichage** : S'assurer que l'UI supporte bien l'UTF-8
|
||||
3. **Recherche** : La recherche d'utilisateurs doit gérer la casse et l'UTF-8
|
||||
4. **Export** : Vérifier que les exports CSV/Excel gèrent bien l'UTF-8
|
||||
|
||||
## Sécurité
|
||||
|
||||
### Pas d'impact sur la sécurité
|
||||
- ✅ Les usernames sont toujours chiffrés en base (AES-256-CBC)
|
||||
- ✅ L'unicité est toujours vérifiée
|
||||
- ✅ Les injections SQL sont impossibles (prepared statements)
|
||||
- ✅ Le trim empêche les espaces invisibles
|
||||
|
||||
### Recommandations
|
||||
- Continuer à générer automatiquement des usernames simples (ASCII) pour éviter les problèmes
|
||||
- Mais permettre la saisie manuelle de tout format
|
||||
- Logger les usernames "exotiques" pour détecter d'éventuels abus
|
||||
|
||||
## Tests
|
||||
- Script de test disponible : `/tests/test_username_validation.php`
|
||||
- Teste tous les cas limites et formats internationaux
|
||||
|
||||
## Rollback si nécessaire
|
||||
Si besoin de revenir en arrière :
|
||||
1. Restaurer l'ancienne validation dans UserController
|
||||
2. Les usernames UTF-8 existants continueront de fonctionner
|
||||
3. Seuls les nouveaux seront restreints
|
||||
|
||||
## Conclusion
|
||||
Cette approche ultra-souple aligne les usernames sur les standards modernes d'inclusivité et d'accessibilité, tout en maintenant la sécurité grâce au chiffrement et à la validation de l'unicité.
|
||||
BIN
api/docs/_logo_recu.png
Normal file
BIN
api/docs/_logo_recu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
BIN
api/docs/_recu_template.pdf
Normal file
BIN
api/docs/_recu_template.pdf
Normal file
Binary file not shown.
@@ -18,168 +18,39 @@
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
|
||||
CREATE TABLE `chat_anonymous_users` (
|
||||
`id` varchar(50) NOT NULL,
|
||||
`device_id` varchar(100) NOT NULL,
|
||||
`name` varchar(100) DEFAULT NULL,
|
||||
`email` varchar(100) DEFAULT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`converted_to_user_id` int(10) unsigned DEFAULT NULL,
|
||||
`metadata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`metadata`)),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_device_id` (`device_id`),
|
||||
KEY `idx_converted_user` (`converted_to_user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
-- Tables préfixées "chat_"
|
||||
CREATE TABLE chat_rooms (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
title VARCHAR(255),
|
||||
type ENUM('private', 'group', 'broadcast'),
|
||||
created_at TIMESTAMP,
|
||||
created_by INT
|
||||
);
|
||||
|
||||
CREATE TABLE `chat_attachments` (
|
||||
`id` varchar(50) NOT NULL,
|
||||
`fk_message` varchar(50) NOT NULL,
|
||||
`file_name` varchar(255) NOT NULL,
|
||||
`file_path` varchar(500) NOT NULL,
|
||||
`file_type` varchar(100) NOT NULL,
|
||||
`file_size` int(10) unsigned NOT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_message` (`fk_message`),
|
||||
CONSTRAINT `fk_chat_attachments_message` FOREIGN KEY (`fk_message`) REFERENCES `chat_messages` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
CREATE TABLE chat_messages (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
room_id VARCHAR(36),
|
||||
content TEXT,
|
||||
sender_id INT,
|
||||
sent_at TIMESTAMP,
|
||||
FOREIGN KEY (room_id) REFERENCES chat_rooms(id)
|
||||
);
|
||||
|
||||
CREATE TABLE `chat_audience_targets` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`fk_room` varchar(50) NOT NULL,
|
||||
`target_type` enum('role','entity','all','combined') NOT NULL DEFAULT 'all',
|
||||
`target_id` varchar(50) DEFAULT NULL,
|
||||
`role_filter` varchar(20) DEFAULT NULL,
|
||||
`entity_filter` varchar(50) DEFAULT NULL,
|
||||
`date_creation` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_room` (`fk_room`),
|
||||
KEY `idx_type` (`target_type`),
|
||||
CONSTRAINT `fk_chat_audience_targets_room` FOREIGN KEY (`fk_room`) REFERENCES `chat_rooms` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
CREATE TABLE chat_participants (
|
||||
room_id VARCHAR(36),
|
||||
user_id INT,
|
||||
role INT,
|
||||
entite_id INT,
|
||||
joined_at TIMESTAMP,
|
||||
PRIMARY KEY (room_id, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE `chat_broadcast_lists` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`fk_room` varchar(50) NOT NULL,
|
||||
`name` varchar(100) NOT NULL,
|
||||
`description` text DEFAULT NULL,
|
||||
`fk_user_creator` int(10) unsigned NOT NULL,
|
||||
`date_creation` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_room` (`fk_room`),
|
||||
KEY `idx_user_creator` (`fk_user_creator`),
|
||||
CONSTRAINT `fk_chat_broadcast_lists_room` FOREIGN KEY (`fk_room`) REFERENCES `chat_rooms` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
|
||||
|
||||
|
||||
CREATE TABLE `chat_messages` (
|
||||
`id` varchar(50) NOT NULL,
|
||||
`fk_room` varchar(50) NOT NULL,
|
||||
`fk_user` int(10) unsigned DEFAULT NULL,
|
||||
`sender_type` enum('user','anonymous','system') NOT NULL DEFAULT 'user',
|
||||
`content` text DEFAULT NULL,
|
||||
`content_type` enum('text','image','file') NOT NULL DEFAULT 'text',
|
||||
`date_sent` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`date_delivered` timestamp NULL DEFAULT NULL,
|
||||
`date_read` timestamp NULL DEFAULT NULL,
|
||||
`statut` enum('envoye','livre','lu','error') NOT NULL DEFAULT 'envoye',
|
||||
`is_announcement` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_room` (`fk_room`),
|
||||
KEY `idx_user` (`fk_user`),
|
||||
KEY `idx_date` (`date_sent`),
|
||||
KEY `idx_status` (`statut`),
|
||||
KEY `idx_messages_unread` (`fk_room`,`statut`),
|
||||
CONSTRAINT `fk_chat_messages_room` FOREIGN KEY (`fk_room`) REFERENCES `chat_rooms` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
|
||||
CREATE TABLE `chat_notifications` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`fk_user` int(10) unsigned NOT NULL,
|
||||
`fk_message` varchar(50) DEFAULT NULL,
|
||||
`fk_room` varchar(50) DEFAULT NULL,
|
||||
`type` varchar(50) NOT NULL,
|
||||
`contenu` text DEFAULT NULL,
|
||||
`date_creation` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`date_lecture` timestamp NULL DEFAULT NULL,
|
||||
`statut` enum('non_lue','lue') NOT NULL DEFAULT 'non_lue',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user` (`fk_user`),
|
||||
KEY `idx_message` (`fk_message`),
|
||||
KEY `idx_room` (`fk_room`),
|
||||
KEY `idx_statut` (`statut`),
|
||||
KEY `idx_notifications_unread` (`fk_user`,`statut`),
|
||||
CONSTRAINT `fk_chat_notifications_message` FOREIGN KEY (`fk_message`) REFERENCES `chat_messages` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `fk_chat_notifications_room` FOREIGN KEY (`fk_room`) REFERENCES `chat_rooms` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
|
||||
CREATE TABLE `chat_offline_queue` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(10) unsigned NOT NULL,
|
||||
`operation_type` varchar(50) NOT NULL,
|
||||
`operation_data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`operation_data`)),
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`processed_at` timestamp NULL DEFAULT NULL,
|
||||
`status` enum('pending','processing','completed','failed') NOT NULL DEFAULT 'pending',
|
||||
`error_message` text DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_status` (`status`),
|
||||
KEY `idx_created_at` (`created_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
|
||||
CREATE TABLE `chat_participants` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`id_room` varchar(50) NOT NULL,
|
||||
`id_user` int(10) unsigned DEFAULT NULL,
|
||||
`anonymous_id` varchar(50) DEFAULT NULL,
|
||||
`role` enum('administrateur','participant','en_lecture_seule') NOT NULL DEFAULT 'participant',
|
||||
`date_ajout` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`notification_activee` tinyint(1) unsigned NOT NULL DEFAULT 1,
|
||||
`last_read_message_id` varchar(50) DEFAULT NULL,
|
||||
`via_target` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||
`can_reply` tinyint(1) unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uc_room_user` (`id_room`,`id_user`),
|
||||
KEY `idx_room` (`id_room`),
|
||||
KEY `idx_user` (`id_user`),
|
||||
KEY `idx_anonymous_id` (`anonymous_id`),
|
||||
KEY `idx_participants_active` (`id_room`,`id_user`,`notification_activee`),
|
||||
CONSTRAINT `fk_chat_participants_room` FOREIGN KEY (`id_room`) REFERENCES `chat_rooms` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
|
||||
CREATE TABLE `chat_read_messages` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`fk_message` varchar(50) NOT NULL,
|
||||
`fk_user` int(10) unsigned NOT NULL,
|
||||
`date_read` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uc_message_user` (`fk_message`,`fk_user`),
|
||||
KEY `idx_message` (`fk_message`),
|
||||
KEY `idx_user` (`fk_user`),
|
||||
CONSTRAINT `fk_chat_read_messages_message` FOREIGN KEY (`fk_message`) REFERENCES `chat_messages` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
|
||||
CREATE TABLE `chat_rooms` (
|
||||
`id` varchar(50) NOT NULL,
|
||||
`type` enum('privee','groupe','liste_diffusion','broadcast','announcement') NOT NULL,
|
||||
`title` varchar(100) DEFAULT NULL,
|
||||
`date_creation` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`fk_user` int(10) unsigned NOT NULL,
|
||||
`fk_entite` int(10) unsigned DEFAULT NULL,
|
||||
`statut` enum('active','archive') NOT NULL DEFAULT 'active',
|
||||
`description` text DEFAULT NULL,
|
||||
`reply_permission` enum('all','admins_only','sender_only','none') NOT NULL DEFAULT 'all',
|
||||
`is_pinned` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||
`expiry_date` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user` (`fk_user`),
|
||||
KEY `idx_entite` (`fk_entite`),
|
||||
KEY `idx_type` (`type`),
|
||||
KEY `idx_statut` (`statut`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
CREATE TABLE chat_read_receipts (
|
||||
message_id VARCHAR(36),
|
||||
user_id INT,
|
||||
read_at TIMESTAMP,
|
||||
PRIMARY KEY (message_id, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE `email_counter` (
|
||||
`id` int(10) unsigned NOT NULL DEFAULT 1,
|
||||
|
||||
BIN
api/docs/recu_537254062.pdf
Normal file
BIN
api/docs/recu_537254062.pdf
Normal file
Binary file not shown.
BIN
api/docs/recu_972506460.pdf
Normal file
BIN
api/docs/recu_972506460.pdf
Normal file
Binary file not shown.
Reference in New Issue
Block a user