> ## 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 de migração de armazenamento

> Copie, verifique, faça a transição e reverta o armazenamento do provedor sem perda de dados

Este runbook migra objetos do CaseBender sem alterar as chaves de objeto. Ele usa
semântica copy-first: a origem permanece autoritativa e intacta até o
vencimento da janela de rollback. Aplica-se a sistemas de arquivos locais, armazenamento
compatível com MinIO/S3, AWS S3 e GCS por meio de remotes `rclone`.

## Pré-condições

* Leia a política de suporte de armazenamento e as notas da release de ambos os provedores.
* Confirme que a release usa o outbox de exclusão durável, independente de provedor. A
  lacuna histórica de exclusão exclusiva do MinIO está corrigida; não carregue essa
  limitação obsoleta para um novo projeto.
* Confirme capacidade, criptografia, versionamento, retenção, ciclo de vida,
  tamanho de objeto, metadados e comportamento de nomenclatura do destino.
* Crie identidades de migração de leitura na origem e de escrita no destino com menor privilégio.
* Configure a confiança TLS; nunca use `--no-check-certificate`.
* Faça e teste um backup de consistência do PostgreSQL e do armazenamento de origem.
* Registre a contagem de objetos, o total de bytes, as versões/snapshots de origem e a configuração.
* Defina uma janela de mudança que permita silenciar escritas e fazer rollback.

Gere e proteja o inventário autoritativo de objetos do PostgreSQL:

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

Cada item migrado deve identificar uma versão/geração exata do objeto de origem,
tamanho e SHA-256. O PostgreSQL e essas versões exatas são um único conjunto de consistência.
Não migre um objeto “latest” flutuante quando uma versão estiver registrada.

Os exemplos abaixo usam `source:casebender` e `destination:casebender`. Mantenha a
configuração e os logs do rclone fora do repositório e proteja-os como sensíveis.

## 1. Inventário 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
```

Revise avisos de metadados não suportados. Criptografia, retenção,
legal hold, ACL e histórico de versões específicos do provedor podem não ser copiados como metadados
ordinários de objeto; configure esses controles no destino e preserve as versões de origem no
backup. Nunca use `sync` para a cópia inicial porque ele pode excluir objetos
do destino.

## 2. Cópia-semente enquanto a aplicação está 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
```

Ajuste a concorrência abaixo dos limites de throttle do provedor. Retente objetos com falha e retenha
o log completo. Não infira integridade a partir de ETags: objetos multipart e
criptografados podem ter ETags que não são MD5.

## 3. Silencie as escritas e capture o ponto de consistência

Bloqueie escritas de usuário e de integração usando o procedimento de manutenção da release.
Pause ingestão e workers somente após a fila ser drenada ou retida de forma durável.
Registre o timestamp/LSN do banco de dados, a versão/snapshot do bucket de origem e as
réplicas da implantação. Verifique se nenhuma escrita de armazenamento está ocorrendo.

Execute o delta final:

```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
```

Não exclua nem desabilite a origem.

## 4. Verifique antes da transição

```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` calcula o hash do conteúdo baixado e evita a
ambiguidade de ETag do provedor. Exija zero objetos ausentes, alterados ou ilegíveis. Investigue
diferenças de contagem provenientes de objetos marcadores do provedor ou sidecars locais `.meta.json`;
não ignore diferenças sem uma explicação registrada.

Execute o teste de contrato do destino a partir da rede da aplicação:

```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
```

Para exemplos de GCS ou local, consulte o uso do script. Também amostrar evidências de alto valor,
objetos multipart grandes, nomes Unicode, arquivos vazios, metadados MIME e objetos
retidos.

## 5. Transição

1. Salve a configuração antiga do provedor e a versão de recurso do Secret no
   registro criptografado da mudança.
2. Confirme que as entradas de `StorageMigrationLedger` estão `VERIFIED`. O processador de
   migração copia primeiro, relê, verifica o SHA-256, registra a versão do
   provedor de destino e só então transita para `CUTOVER`.
3. Altere somente os perfis explícitos do provedor e as credenciais. Preserve o conteúdo
   do bucket e as chaves duráveis.
4. Reinicie a aplicação web e aguarde `/api/health/ready`.
5. Execute testes de upload/download/list/copy/delete da aplicação e verifique o SHA-256.
6. Verifique anexos e evidências existentes em várias idades e tamanhos.
7. Retome workers e ingestão e, em seguida, as escritas de usuário.
8. Monitore erros de armazenamento, exclusões com falha, latência, throttling, profundidade de fila e
   eventos de auditoria continuamente durante a janela de rollback.

Não execute reescritas de chaves no banco de dados, a menos que uma migração específica da release as
exija explicitamente.

Durante uma janela de compatibilidade documentada, referências legadas podem ser lidas da
origem enquanto objetos respaldados pelo ledger usam o destino. Não implemente
escritas duplas ilimitadas. Encerre as leituras legadas somente após a reconciliação confirmar
que não há referências ausentes e a aprovação de rollback permitir.

## 6. Rollback

O rollback é seguro somente enquanto a origem antiga for retida e as novas escritas puderem ser
reconciliadas.

1. Reentre no modo de manutenção e silencie as escritas.
2. Registre todos os objetos gravados no destino desde a transição.
3. Copie o delta reverso para a origem sem exclusão:

```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. Exija uma verificação limpa e, em seguida, restaure a configuração anterior do provedor e
   a versão da credencial.
5. Reinicie, execute testes de ciclo de vida/integridade da aplicação e retome o tráfego.
6. Mantenha ambos os stores e toda a evidência até a conclusão da revisão de incidente/mudança.

Se a retenção ou a política da origem impedir a cópia reversa, pare e restaure o
backup de consistência registrado; não improvise uma sincronização destrutiva.

## 7. Encerramento

* Reconcilie as contagens/bytes finais e arquive hashes, logs, versões de ferramentas, aprovações,
  versões de configuração e resultados amostrados da aplicação.
* Rotacione as credenciais temporárias de migração.
* Mantenha a origem somente leitura pelo período aprovado de rollback.
* Após o aceite formal e a revisão jurídica/de retenção, remova os dados de origem usando o
  processo auditado de descarte do provedor.
* Atualize o registro de suporte com produto/versão do provedor, detalhes de TLS/CA,
  resultado do contrato, resultado de desempenho, resultado de backup e exercício de rollback.

Execute uma verificação isolada de restauração antes do descarte da origem:

```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>'
```

Registre o ponto de recuperação e o tempo de recuperação reais. Objetivos de RPO/RTO sem um
exercício medido de restauração e rollback não são evidência.

## Ressalvas específicas de provedor

* **S3/Ceph RGW:** preserve IDs de versão e delete markers; cópias ordinárias podem
  não reter o estado de Object Lock/legal-hold. Requalifique a versão exata do produto
  e a CA privada.
* **GCS:** preserve gerações numéricas; retenção de bucket, retenção de objeto,
  holds baseados em evento e política CMEK exigem atestação separada no destino.
* **Azure:** preserve IDs de versão de blob; imutabilidade e legal hold são
  específicos do destino e blobs copiados recebem novos IDs de versão.
* **MinIO legado:** mantenha tanto o snapshot original do volume quanto a exportação pela API S3.
  Nunca importe o layout interno do sistema de arquivos do MinIO para outro provedor.

Consulte [Backup e restauração](/pt-BR/deployment/storage-backup-restore) e
[Ciclo de vida do MinIO](/pt-BR/deployment/storage-minio-lifecycle).
