Files
Documentos-Unicos/projetos/newwhats.clube67.com/wasabi-migracao-e-limpeza.md
T
VPS 4 Builder 6b5ebd48ca docs(newwhats): runbook de migração de mídia local → Wasabi + limpeza de disco
- novo: wasabi-migracao-e-limpeza.md (fluxo executado 04/jul, v1.0.70)
- wasabi-midias.md: ver-também cruzado

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 19:18:39 +02:00

98 lines
4.6 KiB
Markdown

# newwhats.clube67.com — Migração de mídia local → Wasabi & limpeza de disco
> Runbook **executado no DEV em 04/jul/2026 (release v1.0.70)** para tirar TODA a mídia
> do disco do servidor e deixar só no Wasabi. Repetível em produção com os alvos de PROD.
> Complementa `wasabi-midias.md` (design de index + delete em lote); aqui é o **fluxo de
> migração one-shot + limpeza**, a feature de **thumbnails** e o **guard de recuperabilidade**.
## Contexto: onde a mídia vive
Campo `mediaUrl` na tabela `messages` (Postgres `newwhats_dev` / prod equivalente; colunas
camelCase, model Prisma `@@map("messages")`) tem 3 estados:
| `mediaUrl` | Significado | Arquivo em disco? |
|---|---|---|
| `whatsapp/<tenant>/<instance>/<ts>-<nome>` | já no **Wasabi** (servido remoto) | não |
| `/media/<instanceId>/<file>` | **LOCAL** — servido do disco | sim (`/app/media/...`) |
| `NULL` | lazy — re-baixável do WhatsApp via `mediaPayload` | não |
Mídia local mora em `newwhats.dev/data/media` (montado como `/app/media` no container
`newwhats-backend-dev`). **`newwhats.dev` é a cópia em execução (git-ignored); `newwhats.local`
é a fonte versionada.** O container monta `newwhats.dev/plugins`.
## Config do Wasabi (importante: NÃO está em env)
Vem do **Dragonfly**, chave `plugin:config:UnifiedStorageProvider` (DB `/1` em
`redis://…@10.99.0.3:6379/1`; a senha está na `DRAGONFLY_URL` do container). Ler:
```
redis-cli -h 10.99.0.3 -p 6379 -a <senha> -n 1 GET plugin:config:UnifiedStorageProvider
```
Valores DEV: bucket `whatsbasemidia`, endpoint `https://s3.wasabisys.com`, region `us-east-1`.
Cliente S3 = `forcePathStyle:true`; upload com `ACL:'public-read'`.
## Convenção de key (replicar EXATAMENTE)
Plugin ativo `newwhats.dev/plugins/UnifiedStorageProvider/index.js` (~L330):
```
whatsapp/<tenantId>/<instanceId>/<Date.now()>-<nomeSanitizado>
```
As mídias já no Wasabi usam isso — se a key divergir, o serving quebra.
## Passo a passo da migração
Rodar **DENTRO do container** `newwhats-backend-dev` (tem `@aws-sdk/client-s3`, `pg`, os
arquivos em `/app/media` e `DATABASE_URL`): `export NODE_PATH=/app/node_modules; cd /app`.
Para cada linha `WHERE "mediaUrl" LIKE '/media/%'`:
1. ler o arquivo local (`/app/media/` + `mediaUrl` sem o prefixo `/media/`);
2. `PutObject` no Wasabi com a key acima, `ContentType` do mime, `ACL:'public-read'`;
3. **`HeadObject` conferindo `ContentLength == tamanho local`** (rede de segurança);
4. só então `UPDATE messages SET "mediaUrl" = <key>`;
5. `unlinkSync` do arquivo local.
Idempotente e resumível (ao migrar, o `mediaUrl` deixa de casar `/media/%`). **Rodar
`DRY_RUN=1` primeiro** (verifica existência/tamanho, sem enviar/apagar). Script de
referência: `migrate_media.js`.
### Refs mortas
`/media/…` **sem arquivo E sem `mediaPayload`** = referência quebrada (no DEV eram 257).
`UPDATE messages SET "mediaUrl" = NULL` → aí o guard `media_recoverable=false` exibe
"indisponível" de forma limpa (em vez de tentar carregar path quebrado → 404).
### Órfãos e esvaziamento final
Após migrar tudo, nenhum `mediaUrl` referencia arquivo local → qualquer arquivo que
sobrar em `data/media` é órfão. Confirmar `erros=0` no resumo e então esvaziar
(`find data/media -mindepth 1 -delete`). No DEV liberou ~2,1 GB.
## Feature acoplada (mesma release)
- **Thumbnails**: no re-download, além de subir a mídia, gera `sharp → 400px → webp q60`
e grava `<mediaUrl>.thumb.webp` no Wasabi. O `MessageBubble` pede a thumb na prévia e
cai pro full via `onError`. (commit `2c8eb41` / submódulo `09edeb9`)
- **`mediaRecoverable`**: `GET /inbox/:chatId/messages` devolve `Boolean(mediaUrl || mediaPath
|| mediaPayload)`; o frontend mapeia p/ `media_recoverable` e o guard evita o `400` de
`/media/:id/download` em mídia legada.
## Resultado no DEV (04/jul/2026)
- 659 mídias migradas (~2,0 GB), 0 erros; 257 refs mortas → NULL; disco: 2,1 GB → 0.
- Banco final: 2.231 no Wasabi, 26.793 lazy (NULL+payload), 0 refs `/media/`.
## Cuidados
- **Sempre** `HeadObject` antes de apagar o local; nunca apagar sem upload confirmado.
- O **"janitor"** do plugin (`setInterval` 120s) só varre `localFallbackDir`/`uploads` e
**não atualiza o banco** — não serve para migrar a mídia do WhatsApp.
- Limpar temporários com credenciais depois (`/tmp/wasabi.env`, creds do Dragonfly).
- Testar sempre no `dev.newwhats` antes; **pedir aprovação antes de rodar em produção**.
## Para PRODUÇÃO
O newwhats de produção **não roda na VPS4**. Aplicar o mesmo fluxo contra o diretório de
mídia, o banco e a config Dragonfly **de produção**. Ver `ambiente-dev.md` e
`infra/maquinas-e-rede.md`.