Plan de Disaster Recovery - Aaperture
Ce document décrit les procédures de sauvegarde et de récupération en cas de sinistre pour l'application Aaperture.
📋 Table des matières
- Vue d'ensemble
- Stratégie de sauvegarde
- Procédures de restauration
- Plan de récupération
- Tests de restauration
- Monitoring et alertes
Vue d'ensemble
Objectifs de récupération
- RTO (Recovery Time Objective) : 4 heures maximum
- RPO (Recovery Point Objective) : 24 heures maximum (perte de données acceptée)
Composants critiques
- Base de données PostgreSQL : Données utilisateurs, sessions, contacts, devis, factures
- Fichiers stockés (Cloudflare R2) : Images, documents, fichiers uploadés
- Configuration : Variables d'environnement, secrets
- Code applicatif : Code source versionné dans GitLab
Stratégie de sauvegarde
Sauvegardes de base de données
Sauvegardes automatiques
- Fréquence : Quotidienne à 2h du matin (heure UTC)
- Type : Sauvegardes complètes avec compression gzip
- Rétention : 30 jours par défaut (configurable via
RETENTION_DAYS) - Emplacement : Répertoire local (
_backups/ouBACKUP_DIR) - Format :
postgres-YYYY-MM-DDTHH-MM-SS.sql.gz
Caractéristiques des sauvegardes
- ✅ Compression gzip pour réduire l'espace disque
- ✅ Checksum SHA-256 pour vérification d'intégrité
- ✅ Logging dans la base de données (
backup_logs) - ✅ Nettoyage automatique des anciennes sauvegardes
- ✅ Notifications email en cas de succès/échec
Configuration
Variables d'environnement :
# Répertoire de sauvegarde (par défaut: _backups/)
BACKUP_DIR=/var/backups/aaperture
# Rétention en jours (par défaut: 30)
RETENTION_DAYS=30
# Timeout pour backups en secondes (par défaut: 1800 = 30 minutes)
BACKUP_TIMEOUT=1800
# Email pour notifications (optionnel)
BACKUP_NOTIFICATION_EMAIL=admin@example.com
Note: Le script backup-db.sh applique automatiquement un timeout configurable via BACKUP_TIMEOUT. Si le backup dépasse ce délai, il sera interrompu avec une erreur. Voir TIMEOUT_MANAGEMENT.md pour plus d'informations sur la gestion des timeouts.
Sauvegardes de fichiers (Cloudflare R2)
Les fichiers sont stockés sur Cloudflare R2 qui offre :
- ✅ Durabilité élevée (99.999999999% - 11 nines)
- ✅ Réplication automatique
- ✅ Versioning optionnel
- ✅ Lifecycle policies pour archivage automatique
Recommandation : Activer le versioning R2 pour les fichiers critiques.
Sauvegardes de configuration
- ✅ Code source versionné dans GitLab (avec historique complet)
- ✅ Variables d'environnement documentées dans
.env.example - ✅ Secrets stockés de manière sécurisée (non versionnés)
Action requise : Créer un dépôt sécurisé pour les secrets de production (ex: HashiCorp Vault, AWS Secrets Manager).
Procédures de restauration
Restauration de la base de données
Prérequis
- Accès au serveur de production ou environnement de staging
- Fichier de sauvegarde disponible
- Accès à la base de données PostgreSQL
- Outils nécessaires :
psql,gunzip
Étape 1 : Vérifier l'intégrité de la sauvegarde
# Vérifier que le fichier existe et n'est pas vide
ls -lh /path/to/backup/postgres-2024-01-01T02-00-00.sql.gz
# Vérifier le checksum (si disponible dans backup_logs)
sha256sum /path/to/backup/postgres-2024-01-01T02-00-00.sql.gz
Étape 2 : Préparer la base de données
# Se connecter à PostgreSQL
psql -h localhost -U postgres -d postgres
# Créer une nouvelle base de données (si restauration complète)
CREATE DATABASE aaperture_restored;
# OU vider la base existante (ATTENTION : supprime toutes les données)
DROP DATABASE IF EXISTS aaperture;
CREATE DATABASE aaperture;
Étape 3 : Restaurer la sauvegarde
# Option 1 : Décompression et restauration en une commande
gunzip -c /path/to/backup/postgres-2024-01-01T02-00-00.sql.gz | \
psql -h localhost -U postgres -d aaperture
# Option 2 : Décompression puis restauration
gunzip /path/to/backup/postgres-2024-01-01T02-00-00.sql.gz
psql -h localhost -U postgres -d aaperture < postgres-2024-01-01T02-00-00.sql
Étape 4 : Vérifier la restauration
# Vérifier le nombre d'enregistrements dans les tables principales
psql -h localhost -U postgres -d aaperture -c "SELECT COUNT(*) FROM users;"
psql -h localhost -U postgres -d aaperture -c "SELECT COUNT(*) FROM sessions;"
psql -h localhost -U postgres -d aaperture -c "SELECT COUNT(*) FROM contacts;"
# Vérifier la date de dernière sauvegarde
psql -h localhost -U postgres -d aaperture -c \
"SELECT MAX(created_at) FROM backup_logs WHERE status = 'completed';"
Étape 5 : Mettre à jour les migrations (si nécessaire)
# Exécuter les migrations Liquibase pour s'assurer que le schéma est à jour
cd infra
./migrate-improved.sh
Restauration de fichiers (Cloudflare R2)
Les fichiers sur R2 sont automatiquement répliqués. En cas de perte locale :
- Les fichiers sont toujours disponibles sur R2
- Vérifier l'accès via l'interface Cloudflare ou l'API
- Si nécessaire, re-synchroniser depuis R2
Restauration complète de l'application
Scénario : Perte complète du serveur
-
Provisionner un nouveau serveur
- Installer Docker et Docker Compose
- Cloner le dépôt GitLab
- Configurer les variables d'environnement
-
Restauration de la base de données
- Suivre les procédures ci-dessus
- Restaurer la dernière sauvegarde disponible
-
Configuration de l'application
- Copier les fichiers
.envdepuis le dépôt sécurisé - Configurer les connexions (DB, Redis, R2)
- Vérifier les certificats SSL/TLS
- Copier les fichiers
-
Démarrage de l'application
cd infra
docker compose -f docker-compose.prod.yml up -d -
Vérification
- Tester l'accès à l'application
- Vérifier les fonctionnalités critiques
- Vérifier les intégrations externes (Google Calendar, Stripe, etc.)
Plan de récupération
Scénarios de sinistre
1. Corruption de la base de données
Symptômes :
- Erreurs PostgreSQL lors des requêtes
- Données manquantes ou incohérentes
- Application inaccessible
Actions :
- Arrêter l'application immédiatement
- Identifier la dernière sauvegarde valide
- Restaurer la sauvegarde (voir procédures ci-dessus)
- Vérifier l'intégrité des données
- Redémarrer l'application
- Notifier les utilisateurs si nécessaire
Temps estimé : 1-2 heures
2. Perte de fichiers
Symptômes :
- Images/documents manquants dans l'application
- Erreurs 404 pour les fichiers
Actions :
- Vérifier l'état de Cloudflare R2
- Si R2 est intact : re-synchroniser les fichiers
- Si R2 est compromis : restaurer depuis backup R2 (si versioning activé)
- Vérifier l'accès aux fichiers restaurés
Temps estimé : 30 minutes - 2 heures
3. Panne du serveur
Symptômes :
- Application inaccessible
- Pas de réponse du serveur
- Timeouts
Actions :
- Diagnostiquer la cause (hardware, réseau, etc.)
- Si récupération impossible rapidement : provisionner nouveau serveur
- Restaurer la base de données
- Reconfigurer l'application
- Redémarrer les services
- Mettre à jour le DNS si nécessaire
Temps estimé : 2-4 heures
4. Attaque de sécurité
Symptômes :
- Activité suspecte dans les logs
- Données modifiées sans autorisation
- Accès non autorisé
Actions :
- Isoler immédiatement : Arrêter l'application, bloquer l'accès réseau
- Analyser l'étendue de la compromission
- Notifier les autorités compétentes si nécessaire
- Restaurer depuis une sauvegarde antérieure à l'attaque
- Appliquer les correctifs de sécurité
- Réinitialiser tous les mots de passe et tokens
- Auditer les logs pour identifier la source
- Redémarrer l'application avec monitoring renforcé
Temps estimé : 4-8 heures
Contacts d'urgence
- Administrateur système : [À compléter]
- Développeur principal : [À compléter]
- Support Cloudflare : [À compléter]
- Support hébergeur : [À compléter]
Tests de restauration
Tests réguliers recommandés
- Mensuel : Test de restauration sur environnement de staging
- Trimestriel : Test de restauration complète (DR drill)
- Après chaque changement majeur : Vérifier que les sauvegardes fonctionnent
Procédure de test
-
Préparer l'environnement de test
# Créer une base de données de test
createdb aaperture_test -
Restaurer une sauvegarde récente
gunzip -c /path/to/backup/postgres-YYYY-MM-DDTHH-MM-SS.sql.gz | \
psql -h localhost -U postgres -d aaperture_test -
Vérifier l'intégrité
- Compter les enregistrements dans les tables principales
- Vérifier les relations (clés étrangères)
- Tester quelques requêtes critiques
-
Documenter les résultats
- Date du test
- Sauvegarde testée
- Résultats (succès/échec)
- Problèmes identifiés
- Actions correctives
Checklist de test
- Sauvegarde restaurée avec succès
- Toutes les tables présentes
- Données cohérentes (pas de corruption)
- Relations entre tables intactes
- Migrations appliquées correctement
- Application fonctionnelle après restauration
- Performance acceptable
Monitoring et alertes
Monitoring des sauvegardes
Timeout des backups : Les backups sont automatiquement interrompus si ils dépassent le délai configuré via BACKUP_TIMEOUT (défaut: 30 minutes). Surveillez les logs pour détecter les timeouts fréquents qui pourraient indiquer un problème de performance ou de taille de base de données.
Monitoring des sauvegardes
Le système de backup envoie automatiquement :
- ✅ Email de succès : Après chaque backup réussi (si
BACKUP_NOTIFICATION_EMAILconfiguré) - ✅ Email d'alerte : En cas d'échec de backup
- ✅ Logs dans la base : Tous les backups sont enregistrés dans
backup_logs
Métriques à surveiller
-
Fréquence des sauvegardes
- Vérifier qu'une sauvegarde est créée quotidiennement
- Alert si aucune sauvegarde depuis 25 heures
-
Taux de succès
- Surveiller le statut des backups (
completedvsfailed) - Alert si taux d'échec > 10%
- Surveiller le statut des backups (
-
Taille des sauvegardes
- Surveiller la taille des fichiers de backup
- Alert si taille anormalement petite (possible corruption)
- Alert si taille anormalement grande (possible problème)
-
Durée des backups
- Surveiller
duration_msdansbackup_logs - Alert si durée > 1 heure (possible problème de performance)
- Surveiller
-
Espace disque
- Surveiller l'espace disponible dans
BACKUP_DIR - Alert si espace < 20%
- Surveiller l'espace disponible dans
Requêtes SQL utiles
-- Dernière sauvegarde réussie
SELECT * FROM backup_logs
WHERE status = 'completed'
ORDER BY created_at DESC
LIMIT 1;
-- Sauvegardes échouées récentes
SELECT * FROM backup_logs
WHERE status = 'failed'
AND created_at > NOW() - INTERVAL '7 days'
ORDER BY created_at DESC;
-- Statistiques des backups
SELECT
status,
COUNT(*) as count,
AVG(duration_ms) as avg_duration_ms,
MAX(created_at) as last_backup
FROM backup_logs
GROUP BY status;
-- Taille moyenne des backups
SELECT
AVG(
CASE
WHEN backup_size LIKE '%G' THEN CAST(REPLACE(backup_size, 'G', '') AS FLOAT) * 1024 * 1024 * 1024
WHEN backup_size LIKE '%M' THEN CAST(REPLACE(backup_size, 'M', '') AS FLOAT) * 1024 * 1024
WHEN backup_size LIKE '%K' THEN CAST(REPLACE(backup_size, 'K', '') AS FLOAT) * 1024
ELSE CAST(REPLACE(backup_size, 'B', '') AS FLOAT)
END
) as avg_size_bytes
FROM backup_logs
WHERE status = 'completed' AND backup_size IS NOT NULL;
Améliorations futures
Sauvegardes incrémentielles
- Implémenter WAL archiving pour point-in-time recovery
- Réduire la fenêtre de perte de données (RPO < 1 heure)
Sauvegardes distantes
- Automatiser la copie des backups vers un emplacement distant (S3, autre serveur)
- Implémenter la rétention multi-niveaux (quotidien, hebdomadaire, mensuel)
Tests automatisés
- Automatiser les tests de restauration dans CI/CD
- Alertes automatiques si test de restauration échoue
Documentation
- Créer des runbooks détaillés pour chaque scénario
- Documenter les procédures de restauration spécifiques par composant
Révision
Ce document doit être révisé :
- Mensuellement : Vérifier que les procédures sont toujours à jour
- Après chaque incident : Mettre à jour avec les leçons apprises
- Après chaque changement majeur : Adapter les procédures si nécessaire
Dernière révision : [Date] Prochaine révision prévue : [Date + 1 mois]