> ## Documentation Index
> Fetch the complete documentation index at: https://docs.casebender.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Runbook di migrazione dello storage

> Copia, verifica, effettua il cutover e fai rollback dello storage del provider senza perdita di dati

Questo runbook migra gli oggetti CaseBender senza modificare le chiavi oggetto. Usa
semantiche copy-first: la sorgente resta autorevole e intatta fino alla
scadenza della finestra di rollback. Si applica a filesystem local, storage
MinIO/S3-compatibile, AWS S3 e GCS tramite remote `rclone`.

## Precondizioni

* Leggi la policy di supporto dello storage e le note di release per entrambi i provider.
* Conferma che la release usi l'outbox di eliminazione persistente neutrale rispetto al provider. Il
  gap storico di eliminazione solo-MinIO è corretto; non portare quella
  limitazione obsoleta in un nuovo progetto.
* Conferma capacità, crittografia, versioning, retention, ciclo di vita,
  dimensione degli oggetti, metadata e comportamento dei nomi della destinazione.
* Crea identità di migrazione least-privilege in lettura sulla sorgente e in scrittura sulla destinazione.
* Configura il trust TLS; non usare mai `--no-check-certificate`.
* Esegui e testa un backup di consistenza di PostgreSQL e dello storage sorgente.
* Registra conteggio oggetti, byte totali, versioni/snapshot della sorgente e configurazione.
* Imposta una finestra di modifica che consenta la quiescenza delle write e il rollback.

Genera e proteggi l'inventory autorevole degli oggetti PostgreSQL:

```sh theme={null}
pnpm storage:backup-verify inventory \
  --output '<protected-manifest.json>'
chmod 600 '<protected-manifest.json>'
```

Ogni elemento migrato deve identificare una versione/generazione esatta dell'oggetto
sorgente, la dimensione e lo SHA-256. PostgreSQL e quelle versioni esatte sono un unico insieme di consistenza.
Non migrare un oggetto “latest” fluttuante quando è registrata una versione.

Gli esempi seguenti usano `source:casebender` e `destination:casebender`. Conserva la configurazione
rclone e i log al di fuori del repository e proteggili come sensibili.

## 1. Inventory e dry run

```sh theme={null}
rclone version
rclone size source:casebender --json > source-size.before.json
rclone lsf source:casebender --recursive --files-only \
  > source-objects.before.txt
rclone copy source:casebender destination:casebender \
  --checksum --metadata --dry-run --log-level INFO \
  --log-file migration-dry-run.log
```

Rivedi gli avvisi sui metadata non supportati. Crittografia, retention,
legal hold, ACL e cronologia delle versioni specifici del provider potrebbero non copiarsi come metadata
oggetto ordinari; configura tali controlli nella destinazione e conserva le versioni della sorgente nel
backup. Non usare mai `sync` per la copia iniziale perché può eliminare oggetti
nella destinazione.

## 2. Copia seed mentre l'applicazione è online

```sh theme={null}
rclone copy source:casebender destination:casebender \
  --checksum --metadata --fast-list --transfers 8 --checkers 16 \
  --log-level INFO --log-file migration-seed.log
```

Regola la concorrenza al di sotto dei limiti di throttle del provider. Riprova gli oggetti falliti e conserva
il log completo. Non inferire l'integrità dagli ETag: gli oggetti multipart e
crittografati possono avere ETag non-MD5.

## 3. Metti in quiescenza le write e acquisisci il punto di consistenza

Blocca le write di utenti e integrazioni usando la procedura di manutenzione della release.
Metti in pausa ingestion e worker solo dopo che la coda è stata svuotata o conservata in modo persistente.
Registra il timestamp/LSN del database, la versione/snapshot del bucket sorgente e le repliche
del deployment. Verifica che non stiano avvenendo write di storage.

Esegui il delta finale:

```sh theme={null}
rclone copy source:casebender destination:casebender \
  --checksum --metadata --fast-list --transfers 8 --checkers 16 \
  --log-level INFO --log-file migration-final.log
```

Non eliminare né disabilitare la sorgente.

## 4. Verifica prima del cutover

```sh theme={null}
rclone check source:casebender destination:casebender \
  --download --one-way --combined migration-check.txt
rclone size source:casebender --json > source-size.final.json
rclone size destination:casebender --json > destination-size.final.json
```

`rclone check --download` calcola l'hash del contenuto scaricato ed evita l'ambiguità
degli ETag del provider. Richiedi zero oggetti mancanti, modificati o illeggibili. Indaga
le differenze di conteggio da oggetti marker del provider o sidecar `.meta.json` local;
non rinunciare alle differenze senza una spiegazione registrata.

Esegui il contract test della destinazione dalla rete dell'applicazione:

```sh theme={null}
STORAGE_TEST_PROVIDER=s3 \
STORAGE_TEST_ENDPOINT=https://storage.example.com \
STORAGE_TEST_BUCKET=casebender \
AWS_REGION=us-east-1 \
./scripts/storage/validate-storage.sh
```

Per esempi GCS o local, vedi l'uso dello script. Campiona anche evidenze di alto valore,
oggetti multipart di grandi dimensioni, nomi Unicode, file vuoti, metadata MIME e oggetti
in retention.

## 5. Cutover

1. Salva la configurazione del vecchio provider e la versione della risorsa Secret nel
   record di modifica crittografato.
2. Conferma che le voci `StorageMigrationLedger` siano `VERIFIED`. Il processore
   di migrazione copia prima, rilegge, verifica SHA-256, registra la versione del
   provider di destinazione e solo allora transita a `CUTOVER`.
3. Modifica solo i profili provider espliciti e le credenziali. Conserva i contenuti
   del bucket e le chiavi persistenti.
4. Riavvia l'applicazione web e attendi `/api/health/ready`.
5. Esegui i test applicativi upload/download/list/copy/delete e verifica SHA-256.
6. Verifica allegati ed evidenze esistenti su diverse età e dimensioni.
7. Riprendi worker e ingestion, quindi le write utente.
8. Monitora errori di storage, delete fallite, latenza, throttling, profondità della coda ed
   eventi di audit in modo continuo per tutta la finestra di rollback.

Non eseguire riscritture delle chiavi del database a meno che una migrazione specifica della release
non le richieda esplicitamente.

Durante una finestra di compatibilità documentata, i riferimenti legacy possono essere letti dalla
sorgente mentre gli oggetti backed dal ledger usano la destinazione. Non implementare
dual write illimitate. Chiudi le read legacy solo dopo che la riconciliazione conferma
che non ci sono riferimenti mancanti e l'approvazione di rollback lo consente.

## 6. Rollback

Il rollback è sicuro solo mentre la vecchia sorgente è conservata e le nuove write possono essere
riconciliate.

1. Ri-entra in modalità manutenzione e metti in quiescenza le write.
2. Registra tutti gli oggetti scritti nella destinazione dal cutover.
3. Copia il delta inverso verso la sorgente senza eliminazione:

```sh theme={null}
rclone copy destination:casebender source:casebender \
  --checksum --metadata --fast-list \
  --log-level INFO --log-file rollback-copy.log
rclone check destination:casebender source:casebender \
  --download --one-way --combined rollback-check.txt
```

4. Richiedi un check pulito, quindi ripristina la configurazione del provider precedente e
   la versione delle credenziali.
5. Riavvia, esegui i test di ciclo di vita/integrità dell'applicazione e riprendi il traffico.
6. Conserva entrambi gli store e tutte le evidenze fino al completamento della revisione di incidente/modifica.

Se la retention o la policy della sorgente impediscono la copia inversa, fermati e ripristina il
backup di consistenza registrato; non improvvisare una sincronizzazione distruttiva.

## 7. Chiusura

* Riconcilia i conteggi/byte finali e archivia hash, log, versioni degli strumenti, approvazioni,
  versioni di configurazione e risultati applicativi campionati.
* Ruota le credenziali temporanee di migrazione.
* Mantieni la sorgente in sola lettura per il periodo di rollback approvato.
* Dopo il sign-off formale e la revisione legal/retention, rimuovi i dati della sorgente usando il
  processo di smaltimento auditato del provider.
* Aggiorna il record di supporto con prodotto/versione del provider, dettagli TLS/CA,
  risultato del contratto, risultato delle prestazioni, risultato del backup ed esercizio di rollback.

Esegui una verifica di ripristino isolata prima dello smaltimento della sorgente:

```sh theme={null}
pnpm storage:backup-verify verify-restore \
  --manifest '<protected-manifest.json>' \
  --target-profile '<isolated-restore-profile>' \
  --isolated-prefix 'tenants/<test-tenant>/restore-verification/<exercise-id>' \
  --evidence-output '<sanitized-restore-evidence.json>'
```

Registra il recovery point e il recovery time effettivi. Gli obiettivi RPO/RTO senza un
esercizio misurato di ripristino e rollback non sono evidenze.

## Avvertenze specifiche del provider

* **S3/Ceph RGW:** preserva gli ID di versione e i delete marker; le copie ordinarie potrebbero
  non conservare lo stato Object Lock/legal-hold. Riqualifica la versione esatta del prodotto
  e la CA privata.
* **GCS:** preserva le generation numeriche; bucket retention, object retention,
  hold basati su eventi e policy CMEK necessitano di un'attestazione separata della destinazione.
* **Azure:** preserva gli ID di versione dei blob; immutabilità e legal hold sono
  specifici della destinazione e i blob copiati ricevono nuovi ID di versione.
* **MinIO legacy:** conserva sia lo snapshot originale del volume sia l'export API S3.
  Non importare mai il layout interno del filesystem di MinIO in un altro provider.

Vedi [Backup e ripristino](/it/deployment/storage-backup-restore) e
[Ciclo di vita MinIO](/it/deployment/storage-minio-lifecycle).
