Backup
Statut
Document opérationnel — v1.1 — 2026-06-20.
Objectif
Permettre une restauration complète de DMV après un sinistre (perte de données, corruption, suppression accidentelle, panne Supabase).
La stratégie repose sur des sauvegardes PostgreSQL quotidiennes automatisées, conservées 7 jours, avec checksums d'intégrité.
Ce qui est sauvegardé
| Élément | Méthode | Couvert |
|---|---|---|
| Base PostgreSQL (schéma + données) | pg_dump format custom | ✅ |
| Politiques RLS | Incluses dans le dump + policies.csv diagnostic | ✅ |
| Triggers, fonctions, extensions | Incluses dans le dump | ✅ |
| Schéma lisible | schema.sql.gz | ✅ |
| Données lisibles (INSERT) | data.sql.gz | ✅ |
| Edge Functions | Code source dans git | ✅ (via git) |
Ce qui n'est pas sauvegardé
| Élément | Impact | Action |
|---|---|---|
Storage Supabase (buckets acteurs, publications, documents) | Perte des logos, bannières, PDFs | Sync manuel via supabase storage download ou AWS S3 CLI |
| État déployé des Edge Functions | Divergence possible avec git | supabase functions download si état prod ≠ git |
| Configuration projet Supabase (Auth, SMTP, providers) | Reconfiguration manuelle | Snapshot via dashboard Supabase |
| Rôles globaux PostgreSQL | Gérés par Supabase, non exportables par pg_dump | N/A |
Scripts
Deux scripts distincts selon l'environnement.
Version macOS (backup_supabase.sh)
Utilisé pour déclencher un backup manuel depuis la machine de développement.
Le script versionné est désormais api/ops/backup_supabase_mac.sh. Le fichier
racine backup_supabase.sh reste un wrapper local stable, utilisé aussi par le
cron macOS.
Mode recommandé : fournir des variables PostgreSQL explicites dans
dmv-public/.env.local ou dans l'environnement shell :
SUPABASE_DB_HOST=<host PostgreSQL Supabase ou pooler>
SUPABASE_DB_PORT=5432
SUPABASE_DB_NAME=postgres
SUPABASE_DB_USER=<postgres.<project_ref> ou utilisateur dédié>
SUPABASE_DB_PASSWORD=<Settings → Database → mot de passe>
Ordre de résolution des credentials du script macOS :
- variables explicites
SUPABASE_DB_* - configuration
supabase db dump --linked --dry-rundu projetdmv-backoffice - dérivation du host depuis
NEXT_PUBLIC_SUPABASE_URL
Usage :
./backup_supabase.sh
./backup_supabase.sh -m "avant migration users"
OUT_DIR=~/Backups/supabase ./backup_supabase.sh
Le host PostgreSQL n'est dérivé depuis NEXT_PUBLIC_SUPABASE_URL qu'en dernier
recours.
Cron macOS
La machine locale peut exécuter un backup quotidien via crontab.
Commande actuellement utilisée :
0 9 * * * /Users/sylvain/dev/dmv/backup_supabase.sh --no-interactive >> /Users/sylvain/dev/dmv/backups/cron.log 2>&1
Le script macOS exporte explicitement un PATH compatible cron/launchd
(Homebrew, /usr/bin, /bin, etc.) pour garantir la disponibilité de
pg_dump, pg_restore et psql hors shell interactif.
Version VPS (backup_supabase_vps.sh)
Utilisé pour les sauvegardes automatiques sur le VPS Debian. Lit les credentials depuis /srv/dmv/api/.env (variables DB_* de Laravel).
Contenu d'un backup
Chaque exécution crée un dossier horodaté dans le répertoire de sortie :
backups/
└── 2026-05-17_02-00-00/
├── full.backup # dump complet format custom (pour pg_restore)
├── full.backup.sha256
├── schema.sql.gz # schéma lisible compressé
├── schema.sql.gz.sha256
├── data.sql.gz # données lisibles compressées
├── data.sql.gz.sha256
├── schemas.list # liste des schémas
├── policies.csv # politiques RLS
├── triggers.csv # triggers
├── functions.csv # fonctions et signatures
├── meta.txt # métadonnées de session
└── backup.log # log complet de l'exécution
Cron VPS
Le backup tourne automatiquement chaque nuit à 2h00 sur le VPS, lancé sous l'utilisateur deploy.
Fichier : /etc/cron.d/dmv-backup
0 2 * * * deploy /var/www/backup_supabase.sh --no-interactive >> /var/log/dmv/backup-cron.log 2>&1
Le log cron /var/log/dmv/backup-cron.log est géré par logrotate (rotation quotidienne, 7 fichiers, compressés).
Rétention
7 jours de backups datés conservés sur le VPS dans /srv/dmv/backups/. Les dossiers plus anciens sont supprimés automatiquement à chaque exécution.
En local macOS, la rotation est identique par défaut : 7 jours de backups datés
dans /Users/sylvain/dev/dmv/backups/.
Déploiement initial sur le VPS
Commandes à exécuter une seule fois. postgresql-client (pg_dump, pg_restore, psql) est
inclus dans deployment/install.sh depuis la v1.1 — si le VPS a été installé avant, l'ajouter manuellement.
# ── 1. postgresql-client (si VPS installé avant la v1.1) ─────────────────────
sudo apt-get install -y postgresql-client
# ── 2. Répertoires ────────────────────────────────────────────────────────────
sudo mkdir -p /var/www/backups /var/log/dmv
sudo chown deploy:deploy /var/www/backups /var/log/dmv
# ── 3. Script de backup ───────────────────────────────────────────────────────
# Depuis la machine locale :
scp backup_supabase_vps.sh deploy@<vps>:/var/www/backup_supabase.sh
# Sur le VPS :
sudo chmod +x /var/www/backup_supabase.sh
sudo chown deploy:deploy /var/www/backup_supabase.sh
# ── 4. Cron ───────────────────────────────────────────────────────────────────
sudo cp ops/cron.d/dmv-backup /etc/cron.d/dmv-backup
sudo chmod 644 /etc/cron.d/dmv-backup
# ── 5. Logrotate ──────────────────────────────────────────────────────────────
sudo cp ops/logrotate.d/dmv-backup /etc/logrotate.d/dmv-backup
# ── 6. Test immédiat ──────────────────────────────────────────────────────────
sudo -u deploy /var/www/backup_supabase.sh -m "test installation"
# Vérifier : ls -lh /var/www/backups/
Restauration
La restauration s'effectue depuis full.backup avec pg_restore.
Vérification de l'intégrité avant restore :
sha256sum -c full.backup.sha256
Restauration vers une base cible :
export PGPASSWORD="<mot de passe>"
pg_restore \
--dbname="postgresql://postgres@db.<ref>.supabase.co:5432/postgres?sslmode=require" \
--clean --if-exists \
--no-owner --no-privileges \
full.backup
Options :
--clean --if-exists: supprime les objets existants avant de les recréer (utile si la base n'est pas vide).--no-owner --no-privileges: ne recrée pas les rôles propriétaires ni les ACL (Supabase les gère de son côté).
Vérification manuelle
Pour tester qu'un backup est lisible sans le restaurer :
pg_restore --list full.backup | head -50
Points ouverts
- Backup Storage Supabase (buckets
acteurs,publications,documents) : non couvert, à traiter via la CLI Supabase ou l'API S3 compatible. - Alerte en cas d'échec du cron : actuellement silencieux hors log. À connecter à une alerte Slack ou email.
- Backup off-site : les backups sont sur le même VPS que l'application. Une copie vers un stockage externe (S3, Backblaze) est recommandée pour un DR complet.