docs(wasabi): index e delete em lote implementados (endpoints + deleteObjects)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
VPS 4 Builder
2026-06-28 14:53:07 +02:00
parent 9bbd170626
commit 250e47b06e
2 changed files with 33 additions and 16 deletions
+27 -13
View File
@@ -18,21 +18,35 @@ Os paths são hierárquicos por `tenant/instância/...`, o que permite delete em
por prefixo. Confirmar o layout exato no `StorageProvider` antes de implementar
(avatar usa `avatarWasabiPath(tenantId, instanceId, jid)`).
## O que falta (pendência)
## Implementado (28/jun/2026)
### 1. Index de mídias
Listagem/auditoria das mídias por **tenant / instância / chat / período**:
- Fonte primária: tabela `messages` (path + metadados) — evita `listObjects` caro.
- Endpoint admin: `GET /admin/media?instanceId=&chatId=&from=&to=` → paginação,
tamanho total, contagem por tipo.
- Reconciliação opcional DB ↔ bucket para achar **órfãos** (no bucket sem registro).
### 1. Index de mídias
`GET /api/instances/:instanceId/media-index` (auth + escopo tenant/instância).
- Baseado no **DB** (`messages` com `mediaPath != null`) — evita `listObjects` caro.
- Query: `chatId?`, `type?` (IMAGE|VIDEO|AUDIO|DOCUMENT|STICKER), `from?`/`to?` (ISO),
`page`, `pageSize` (≤200).
- Retorna `{ total, page, pageSize, byType, items[] }`.
### 2. Delete em lote
- Por **instância** (offboarding), por **período** (retenção), por **chat** (LGPD).
- Coordenado **DB ↔ Wasabi**: apagar registro e objeto na mesma operação lógica;
nunca deixar órfão nem link quebrado.
- Implementar `deleteObjects` em lote (S3 aceita até 1000/req) além do `deletePrefix`.
- Endpoint admin protegido + dry-run (retorna contagem antes de apagar).
### 2. Delete em lote
`POST /api/instances/:instanceId/media-batch-delete`. Body:
`{ chatId?, type?, from?, to?, dryRun? }`.
- **dryRun=true é o padrão** — só conta (`matched`, `willDeleteObjects`). Para apagar
de fato é preciso enviar `dryRun:false`.
- Coordenado **DB ↔ Wasabi**: `storageProvider.deleteObjects(paths)` (chunks de 1000,
S3 `DeleteObjectsCommand`) + `updateMany` zera `mediaPath`/`mediaUrl` (sem link
quebrado). Filtra paths `http*` (CDN externo) — só apaga objetos do bucket.
- `StorageProvider.deleteObjects(paths)` adicionado à interface, ao registry e ao
provider concreto (UnifiedStorageProvider), além do `deletePrefix` já existente.
> Validado em dev: index retornou 289 mídias (byType ok); dry-run de AUDIO casou 23.
### Pendência restante
- Index por **tamanho em bytes**: o `Message` não guarda `mediaSize` — agregado de
bytes exigiria `HeadObject`/`listObjects`. Avaliar adicionar coluna `mediaSize`.
- **Local fallback** (dev sem Wasabi): `mediaPath` é caminho absoluto local; o
`deleteObjects` só roda quando o storage provider está registrado. Em produção
(Wasabi ativo) o path é a key relativa do bucket — fluxo correto.
- Reconciliação DB ↔ bucket para achar **órfãos** (objeto sem registro).
### 3. Retenção
- Após `messages.transcription` salva, o **áudio pode ser arquivado/descartado**