# Sauvegardes — base de données et fichiers (MG-142)

Ce qu'il faut sauvegarder, et surtout : **ce qu'il faut restaurer**.
Une sauvegarde qu'on n'a jamais testée n'est pas une sauvegarde.

---

## 1. Ce qui doit être sauvegardé

| Élément | Où | Critique ? | Remplaçable ? |
|---|---|---|---|
| Base de données | MySQL OVH | **oui** | non — contient les textes et les messages |
| `public/uploads/` | serveur | **oui** | non — photos téléversées par Maud |
| `public/images/` | serveur | moyen | oui — présent dans le dépôt Git |
| Code source | Git | non | oui — c'est GitHub la référence |
| `.env.prod.local` | serveur | **oui** | non — contient les secrets |
| `var/log/rgpd_purge.log` | serveur | moyen | non — preuve de conformité RGPD |

`vendor/`, `var/cache/` et `public/build/` se régénèrent : inutile de les
sauvegarder.

---

## 2. Ce qu'OVH fournit déjà

Les hébergements mutualisés OVH incluent une sauvegarde automatique :

- **Base de données** — sauvegarde quotidienne, conservée 30 jours
- **Fichiers** — instantanés quotidiens

Espace client → *Hébergements* → onglet **Sauvegarde**, ou
*Bases de données* → votre base → onglet **Sauvegardes**.

> **Ne pas s'en contenter.** Cette sauvegarde couvre la panne matérielle, pas
> l'erreur humaine détectée trois semaines plus tard, ni la résiliation du
> compte. Elle vit au même endroit que le site.

---

## 3. Sauvegarde automatique de la base

### Le script

Créer `~/scripts/backup-db.sh` sur le serveur :

```bash
#!/usr/bin/env bash
set -euo pipefail

DEST="$HOME/backups"
mkdir -p "$DEST"

DB_HOST="votre-serveur.mysql.db"
DB_USER="votre_utilisateur"
DB_PASS="votre_mot_de_passe"
DB_NAME="votre_base"

FICHIER="$DEST/maudgaquere-$(date +%Y%m%d-%H%M%S).sql.gz"

mysqldump -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" \
    --single-transaction --quick --default-character-set=utf8mb4 \
    "$DB_NAME" | gzip > "$FICHIER"

# Une sauvegarde vide est pire qu'une absence de sauvegarde : elle rassure à tort.
if [ ! -s "$FICHIER" ] || [ "$(stat -c%s "$FICHIER")" -lt 1024 ]; then
    echo "ERREUR : sauvegarde vide ou anormalement petite — $FICHIER" >&2
    rm -f "$FICHIER"
    exit 1
fi

# Rotation : 30 jours de quotidiennes.
find "$DEST" -name 'maudgaquere-*.sql.gz' -mtime +30 -delete

echo "OK $FICHIER ($(du -h "$FICHIER" | cut -f1))"
```

```bash
chmod 700 ~/scripts/backup-db.sh    # il contient le mot de passe
```

### La tâche planifiée

Espace client OVH → *Hébergements* → **Tâches planifiées** :

| Réglage | Valeur |
|---|---|
| Commande | `~/scripts/backup-db.sh` |
| Langage | *Autre* (shell) |
| Fréquence | quotidienne, vers 3 h du matin |
| E-mail de log | l'adresse de Maxime, **en cas d'échec seulement** |

---

## 4. Sauvegarde des fichiers téléversés

`public/uploads/` contient les images envoyées depuis le back-office. Elles
n'existent nulle part ailleurs.

```bash
#!/usr/bin/env bash
set -euo pipefail

DEST="$HOME/backups"
mkdir -p "$DEST"

tar czf "$DEST/uploads-$(date +%Y%m%d).tar.gz" -C "$HOME/gaquere/public" uploads
find "$DEST" -name 'uploads-*.tar.gz' -mtime +30 -delete
```

Fréquence : hebdomadaire suffit, ces fichiers changent peu.

---

## 5. Copie hors du serveur ⚠️ l'étape que l'on saute

Une sauvegarde stockée sur le serveur sauvegardé ne protège que de l'erreur
humaine. Elle ne protège ni de la perte du compte, ni d'une compromission.

**Récupérer les sauvegardes sur une machine distincte**, une fois par semaine :

```bash
# Depuis le poste de Maxime
rsync -avz --delete \
    monlogin@ftp.clusterXXX.hosting.ovh.net:~/backups/ \
    ~/sauvegardes/maud-gaquere/
```

À automatiser côté poste (tâche planifiée Windows, ou cron).

**Garder aussi une copie de `.env.prod.local`**, dans un gestionnaire de mots
de passe et non dans un dossier en clair : sans lui, restaurer le site suppose
de reconstituer tous les secrets.

---

## 6. Restaurer

### La base

```bash
# Toujours sauvegarder l'état actuel AVANT de restaurer :
# si la sauvegarde est mauvaise, on aura tout perdu.
mysqldump -h SERVEUR -u USER -pPASS BASE | gzip > ~/avant-restauration.sql.gz

gunzip -c ~/backups/maudgaquere-AAAAMMJJ-HHMMSS.sql.gz \
    | mysql -h SERVEUR -u USER -pPASS BASE

php ~/gaquere/bin/console cache:clear --env=prod
```

### Les fichiers

```bash
tar xzf ~/backups/uploads-AAAAMMJJ.tar.gz -C ~/gaquere/public/
chmod -R 775 ~/gaquere/public/uploads
```

### Le site entier

```bash
cd ~
git clone git@github.com:VOTRE-COMPTE/gaquere.git
cd gaquere
# restaurer .env.prod.local depuis le gestionnaire de mots de passe
composer install --no-dev --optimize-autoloader
# restaurer la base et les uploads (ci-dessus)
php bin/console cache:clear --env=prod
```

---

## 7. Tester la restauration — deux fois par an

**C'est le seul moyen de savoir si les sauvegardes fonctionnent.**

1. Restaurer la dernière sauvegarde dans la **base de développement locale**
2. Lancer le site en local
3. Vérifier : les neuf pages, les ateliers, les 14 questions, les messages
4. Noter la date du test ci-dessous

| Date du test | Résultat | Par |
|---|---|---|
| | | |
| | | |

> Une sauvegarde jamais restaurée est une hypothèse, pas une garantie. Les
> échecs les plus courants : mot de passe changé sans mettre à jour le script,
> quota disque atteint, encodage perdu sur les accents.

---

## 8. Récapitulatif

| Quoi | Fréquence | Où | Rétention |
|---|---|---|---|
| Base (script) | quotidienne | `~/backups/` | 30 jours |
| Base (OVH) | quotidienne | infrastructure OVH | 30 jours |
| Uploads | hebdomadaire | `~/backups/` | 30 jours |
| Copie hors serveur | hebdomadaire | poste de Maxime | 6 mois |
| Code | à chaque commit | GitHub | illimité |
| Secrets | à chaque changement | gestionnaire de mots de passe | — |
| Test de restauration | semestrielle | local | — |
