# Backup e ripristino

## Comandi

```bash
php artisan francoach:backup
php artisan francoach:backup --database-only
php artisan francoach:backup --files-only
php artisan francoach:backup --no-rotation
php artisan francoach:backup --verify=francoach_YYYYMMDD_HHMMSS_XXXXXX.zip
php artisan francoach:backup --verify=francoach_YYYYMMDD_HHMMSS_XXXXXX.zip --deep
```

Ogni esecuzione crea ZIP e file `.sha256`. Il pacchetto contiene dump MySQL/MariaDB o copia SQLite, file pubblici controllati, fotografie e file privati configurati, oltre a un manifest con SHA-256 per ogni elemento.

## Configurazione

```dotenv
BACKUP_PATH=/home/account/backups/francoach
BACKUP_RETENTION_DAYS=30
BACKUP_KEEP_MINIMUM=7
BACKUP_ENCRYPTION_PASSPHRASE=passphrase-lunga-e-unica
MYSQLDUMP_BINARY=/usr/bin/mysqldump
```

`BACKUP_PATH` deve essere fuori dalla document root. La directory è creata con permessi `0700`; archivi e checksum usano `0600`. La cifratura AES-256 è opzionale e richiede supporto ZIP PHP. Conservare la passphrase in un password manager separato: senza di essa il ripristino non è possibile.

## Pianificazione e rotazione

Lo scheduler esegue il backup completo ogni giorno alle 02:15, timezone `Europe/Rome`, senza sovrapposizioni. I file più vecchi di `BACKUP_RETENTION_DAYS` vengono eliminati preservando almeno `BACKUP_KEEP_MINIMUM` pacchetti.

La rotazione locale non sostituisce una copia off-site. Trasferire almeno una copia cifrata su storage separato con accesso ristretto e retention indipendente. Verificare spazio disco e `storage/logs/backup-*.log`.

## Controllo integrità

Prima di considerare valido un backup:

```bash
php artisan francoach:backup --verify=nome.zip --deep
```

La verifica normale confronta il checksum esterno. `--deep` apre il pacchetto e ricalcola l’hash di ogni elemento. Eseguire mensilmente un ripristino di prova su ambiente isolato.

## Ripristino completo

1. mettere l’app in manutenzione;
2. salvare una copia dello stato corrente;
3. scegliere codice, database e file dello stesso punto temporale;
4. verificare ZIP e checksum;
5. estrarre in directory privata temporanea;
6. importare `database/database.sql` in database vuoto:

```bash
mysql --host=HOST --user=USER --password DATABASE < database.sql
```

7. per SQLite sostituire il file solo a processo applicativo fermo;
8. ripristinare `files/public` nella root del disco pubblico configurato;
9. ripristinare fotografie e altre directory private nelle rispettive posizioni;
10. ripristinare proprietario e permessi;
11. eseguire `php artisan optimize:clear && php artisan optimize`;
12. verificare login, fotografie autorizzate, upload, sessioni, notifiche e cron;
13. disattivare manutenzione solo dopo il collaudo.

Non estrarre mai un backup dentro `public/`. Non sovrascrivere un database attivo senza manutenzione e conferma.

## Ripristino selettivo

Il manifest individua percorso, dimensione e SHA-256. Per un singolo file, estrarlo in area privata, verificarne hash e destinazione, quindi sostituirlo conservando una copia recuperabile. Le fotografie devono mantenere record database e varianti coerenti; in caso contrario ripristinare database e storage insieme.

## Log incidente

Registrare data, operatore, backup usato, checksum, release codice, database destinazione, elementi ripristinati, test svolti ed esito. Non inserire passphrase o credenziali nel log.
