diff --git a/docs/backups/README.md b/docs/backups/README.md new file mode 100644 index 000000000..2eee1b94b --- /dev/null +++ b/docs/backups/README.md @@ -0,0 +1,112 @@ +# Backups Supabase Self-Hosted — Documentação + +Última atualização: 2026-05-12 — testado e validado. + +## Estrutura no container `supabase-backup_backup` + +``` +/backups/ +├── supabase_selfhosted_YYYYMMDD_HHMMSS.dump # backup oficial automático +├── supabase_selfhosted_YYYYMMDD_HHMMSS.dump.sha256 +├── archive/ # históricos pré-migração (não tocar) +├── manual/ # snapshots manuais pré-mudança +├── restore-test.sh # ← este script (deploy de docs/backups/) +├── restore-test.log +└── last_error.log +``` + +## Configuração atual do backup automático + +| Variável | Valor | Significado | +|---|---|---| +| PGHOST | supabase_db | Host alvo (container interno) | +| PGUSER | supabase_admin | Usuário com acesso a tudo | +| PGDATABASE | postgres | BD principal | +| RETENTION_DAYS | 14 | Manter 14 dias | +| MIN_SIZE_BYTES | 104857600 (100 MB) | Backup menor = REJEITADO | +| Formato | --format=custom | Permite restore parcial | +| Compressão | --compress=6 | Bom tradeoff tamanho/CPU | +| Frequência | 24h (sleep 86400) | Diário | + +## Disaster Recovery — procedure VALIDADO em 2026-05-12 + +IMPORTANTE: o dump contém a extensão pg_cron que SÓ roda no BD chamado 'postgres'. +Filtrar antes de restaurar em BD com outro nome. + +```bash +# 1. Acessar o container de backup +docker exec -it $(docker ps -qf name=supabase-backup_backup) sh + +# 2. Validar checksum +cd /backups +sha256sum -c supabase_selfhosted_YYYYMMDD_HHMMSS.dump.sha256 + +# 3. Criar BD destino +psql -c "CREATE DATABASE restore_test;" + +# 4. Gerar TOC e filtrar pg_cron +pg_restore -l /backups/supabase_selfhosted_YYYYMMDD_HHMMSS.dump > /tmp/toc.list +grep -Ev '(pg_cron|cron\.)' /tmp/toc.list > /tmp/toc.filtered + +# 5. Restore (tempo médio: 2 minutos) +pg_restore -d restore_test --no-owner --no-acl \ + --use-list=/tmp/toc.filtered --jobs=4 \ + /backups/supabase_selfhosted_YYYYMMDD_HHMMSS.dump + +# 6. Validar contagens (esperado: 600+ tables, 17k+ contacts, 1.8M+ messages) +psql -d restore_test -c "SELECT count(*) FROM information_schema.tables WHERE table_schema='public';" +psql -d restore_test -c "SELECT count(*) FROM public.evolution_contacts;" +psql -d restore_test -c "SELECT count(*) FROM public.evolution_messages;" +``` + +### Resultado do dry-run validado em 2026-05-12 19:54 UTC + +| Métrica | Valor | +|---|---| +| Tempo de restore | 121s | +| Warnings ignorados | 23 (todos pg_cron-related, não-bloqueantes) | +| Tamanho restaurado | 1921 MB | +| Tabelas restauradas | 600 | +| evolution_contacts | 17.340 (match com produção) | +| evolution_messages | 1.838.351 (match) | +| profiles | 6 (match) | + +## Scripts neste diretório + +- **`restore-test.sh`** — Script de teste de restore automatizado. Deve ser deployado + em `/backups/restore-test.sh` dentro do container `supabase-backup_backup`. +- **`install-restore-test-cron.sh`** — Helper que adiciona um cron mensal no HOST da + VPS para executar o restore-test via `docker exec`. Roda dia 1 de cada mês às + 04:00 UTC. + +## Deploy + +```bash +# 1. Copiar scripts para o container +docker cp docs/backups/restore-test.sh \ + $(docker ps -qf name=supabase-backup_backup):/backups/restore-test.sh + +docker exec $(docker ps -qf name=supabase-backup_backup) \ + chmod +x /backups/restore-test.sh + +# 2. Instalar cron no HOST (não no container) +bash docs/backups/install-restore-test-cron.sh +``` + +## Pendências conhecidas + +- [ ] **CRÍTICO**: Off-site backup (R2 Cloudflare). Atualmente SPOF — apenas local na VPS. + - Worker `backup-upload-r2.adm01.workers.dev` existe mas retorna 401 (secret incorreto). + - Script `/workspace/scripts/backup-to-r2.sh` no host falhando desde 04-mai-2026. + - Próximo passo: regenerar secret no Cloudflare Dashboard OU criar R2 API Token S3-compat. +- [ ] **ALTO**: Alerta de falha (webhook Slack/n8n se BACKUP_FAILED_* aparecer). +- [ ] **MÉDIO**: Validação periódica de checksum (cron `sha256sum -c`). +- [x] **MÉDIO**: Restore test agendado mensal — script pronto, cron documentado. + +## Histórico + +- 2026-04-30 a 2026-05-04: backups FATOR X cloud (5 arquivos arquivados em `/backups/archive/`). +- 2026-05-05 a 2026-05-11: 7 backups quebrados (20 bytes cada, PGHOST apontando para + FATOR X que caiu). DELETADOS em 2026-05-12. +- 2026-05-12 10:32: primeiro backup self-hosted válido (606 MB). +- 2026-05-12 19:54: dry-run de restore validado em produção com sucesso (121s). diff --git a/docs/backups/install-restore-test-cron.sh b/docs/backups/install-restore-test-cron.sh new file mode 100644 index 000000000..b99a3586c --- /dev/null +++ b/docs/backups/install-restore-test-cron.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# Instala cron pra rodar restore-test mensalmente +# Executa dentro do container supabase-backup_backup via docker exec +# Roda no HOST da VPS (não dentro do container) + +set -e + +BACKUP_CONTAINER="supabase-backup_backup" + +# Pré-flight: o container precisa existir (e ser único) no momento da instalação. +# `docker ps -qf name=...` pode retornar múltiplos IDs com prefixo igual ou +# zero IDs — qualquer caso faria o cron falhar silenciosamente em produção. +RUNNING_IDS=$(docker ps -q --filter "name=^/${BACKUP_CONTAINER}$" || true) +if [ -z "$RUNNING_IDS" ]; then + echo "❌ Container ${BACKUP_CONTAINER} não está rodando." + echo " Inicie o Supabase Self-Hosted antes de instalar o cron." + exit 1 +fi +if [ "$(printf '%s\n' "$RUNNING_IDS" | wc -l)" -gt 1 ]; then + echo "❌ Mais de um container ${BACKUP_CONTAINER} rodando — abortando." + echo "$RUNNING_IDS" + exit 1 +fi + +# Comando a executar: usa o NOME exato do container (não filter por ID), +# para que o cron continue funcionando mesmo se o container reiniciar e +# obtiver outro ID. Falha clara se o container não existir naquele momento. +CRON_LINE="0 4 1 * * /usr/bin/docker exec ${BACKUP_CONTAINER} /backups/restore-test.sh >> /var/log/restore-test-cron.log 2>&1" + +# Verifica se já existe +if crontab -l 2>/dev/null | grep -qF 'restore-test.sh'; then + echo "✅ Cron já instalado:" + crontab -l | grep restore-test + exit 0 +fi + +# Adiciona ao crontab +(crontab -l 2>/dev/null; echo "$CRON_LINE") | crontab - +echo "✅ Cron instalado: roda dia 1 de cada mês às 04:00 UTC" +echo "$CRON_LINE" +echo "" +echo "Logs em /var/log/restore-test-cron.log (host) + /backups/restore-test.log (container)" +echo "Pra rodar agora manualmente:" +echo " docker exec ${BACKUP_CONTAINER} /backups/restore-test.sh" diff --git a/docs/backups/restore-test.sh b/docs/backups/restore-test.sh new file mode 100644 index 000000000..ebadb2048 --- /dev/null +++ b/docs/backups/restore-test.sh @@ -0,0 +1,126 @@ +#!/bin/sh +# Restore test automatizado +# Roda mensalmente via cron (cron 0 4 1 * *) +# Pega o backup mais recente, restaura em BD temporário, +# valida contagens, dropa, e loga resultado +# +# DEPLOY: este script deve ser copiado para /backups/restore-test.sh +# dentro do container supabase-backup_backup +# +# Validado em produção em 2026-05-12: PASSOU em 121s +# - 600 tables restauradas +# - 17.340 evolution_contacts (match) +# - 1.838.351 evolution_messages (match) +# - 1921 MB + +set -e + +LOG=/backups/restore-test.log + +# Timestamp avaliado no momento de cada log line (não no startup), +# para que restores longos tenham logs com horário real de cada evento. +log() { + echo "[$(date -Iseconds)] $*" | tee -a "$LOG" +} + +log "==================== RESTORE TEST INICIADO ====================" + +# 1. Identificar backup mais recente. +# `ls` com `set -e`: append `|| true` na substituição para que ausência +# de match não derrube o script antes do check `[ -z "$LATEST" ]`. +LATEST=$(ls -t /backups/supabase_selfhosted_*.dump 2>/dev/null | head -1 || true) + +if [ -z "$LATEST" ]; then + log "ERRO: nenhum backup encontrado em /backups/supabase_selfhosted_*.dump" + touch "/backups/RESTORE_TEST_FAILED_$(date +%Y%m%d_%H%M%S)" + exit 1 +fi + +log "Backup alvo: $LATEST ($(du -h "$LATEST" | cut -f1))" + +# 2. Validar SHA256 — subshell + if direto evita que `set -e` interrompa +# antes do bloco de erro (caso `cd` falhe ou checksum não bater). +if [ -f "${LATEST}.sha256" ]; then + if (cd /backups && sha256sum -c "$(basename "$LATEST").sha256" >/dev/null 2>&1); then + log "OK: SHA256 válido" + else + log "ERRO: SHA256 FALHOU - backup corrompido!" + touch "/backups/RESTORE_TEST_FAILED_$(date +%Y%m%d_%H%M%S)" + exit 2 + fi +else + log "AVISO: sem arquivo .sha256 para validar" +fi + +# 3. Criar BD temporário (identificador é seguro: composto só por timestamp). +DBNAME="restore_test_$(date +%Y%m%d_%H%M%S)" +log "Criando BD temporário: $DBNAME" + +# DROP com FORCE (PG13+) termina conexões pendentes em vez de falhar. +# Fallback para variante sem FORCE em PG<13: termina backends manualmente. +psql -c "DROP DATABASE IF EXISTS \"$DBNAME\" WITH (FORCE);" >/dev/null 2>&1 \ + || { + psql -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$DBNAME' AND pid <> pg_backend_pid();" >/dev/null 2>&1 || true + psql -c "DROP DATABASE IF EXISTS \"$DBNAME\";" >/dev/null 2>&1 || true + } +psql -c "CREATE DATABASE \"$DBNAME\";" >/dev/null 2>&1 + +# 4. Gerar TOC filtrada (sem pg_cron que requer BD chamado postgres). +# `grep -E` com alternação `|` é portável; o antigo `grep -v 'pg_cron\|cron\.'` +# depende de extensão GNU e silenciosamente passa pg_cron em outros greps. +pg_restore -l "$LATEST" > "/tmp/toc-${DBNAME}.list" 2>/dev/null +grep -Ev '(pg_cron|cron\.)' "/tmp/toc-${DBNAME}.list" > "/tmp/toc-${DBNAME}.filtered" + +# 5. Restore com tempo medido + captura de exit code real. +# Antes `|| true` mascarava falhas/timeouts; agora RESTORE_OK entra como +# primeira condição obrigatória no check de sucesso. +START=$(date +%s) +log "Iniciando pg_restore (timeout 10min)..." + +RESTORE_OK=1 +if ! timeout 600 pg_restore -d "$DBNAME" --no-owner --no-acl \ + --use-list="/tmp/toc-${DBNAME}.filtered" --jobs=4 \ + "$LATEST" >> "$LOG" 2>&1; then + RESTORE_OK=0 + log "ERRO: pg_restore falhou (exit != 0 ou timeout 600s atingido)" +fi + +END=$(date +%s) +DURATION=$((END - START)) +log "Restore concluído em ${DURATION}s (RESTORE_OK=${RESTORE_OK})" + +# 6. Validar contagens chave +TABLE_COUNT=$(psql -d "$DBNAME" -tAc "SELECT count(*) FROM information_schema.tables WHERE table_schema='public';" 2>/dev/null || echo "0") +CONTACTS=$(psql -d "$DBNAME" -tAc "SELECT count(*) FROM public.evolution_contacts;" 2>/dev/null || echo "0") +MESSAGES=$(psql -d "$DBNAME" -tAc "SELECT count(*) FROM public.evolution_messages;" 2>/dev/null || echo "0") +PROFILES=$(psql -d "$DBNAME" -tAc "SELECT count(*) FROM public.profiles;" 2>/dev/null || echo "0") +SIZE=$(psql -d "$DBNAME" -tAc "SELECT pg_size_pretty(pg_database_size('$DBNAME'));" 2>/dev/null || echo "unknown") + +log "Resultado:" +log " - tables públicas: $TABLE_COUNT" +log " - evolution_contacts: $CONTACTS" +log " - evolution_messages: $MESSAGES" +log " - profiles: $PROFILES" +log " - tamanho restaurado: $SIZE" + +# 7. Avaliar sucesso. RESTORE_OK == 1 é condição obrigatória primeiro; +# thresholds são guard adicional contra restore parcial que sobe alguma +# coisa mas não o suficiente para considerar válido. +if [ "$RESTORE_OK" -eq 1 ] && [ "$TABLE_COUNT" -ge 400 ] && [ "$CONTACTS" -ge 10000 ]; then + log "✅ RESTORE TEST PASSOU" + STATUS="PASSED" +else + log "❌ RESTORE TEST FALHOU - exit do pg_restore != 0 ou threshold não atingido" + STATUS="FAILED" + touch "/backups/RESTORE_TEST_FAILED_$(date +%Y%m%d_%H%M%S)" +fi + +# 8. Cleanup (idempotente — DROP IF EXISTS WITH FORCE limpa mesmo se algo +# ficar pendente no BD temporário). +log "Dropping BD temporário" +psql -c "DROP DATABASE IF EXISTS \"$DBNAME\" WITH (FORCE);" >/dev/null 2>&1 \ + || psql -c "DROP DATABASE IF EXISTS \"$DBNAME\";" >/dev/null 2>&1 \ + || true +rm -f "/tmp/toc-${DBNAME}.list" "/tmp/toc-${DBNAME}.filtered" + +log "==================== RESTORE TEST $STATUS ====================" diff --git a/docs/session-2026-05-12/SESSION_REPORT.md b/docs/session-2026-05-12/SESSION_REPORT.md new file mode 100644 index 000000000..7bc544a9c --- /dev/null +++ b/docs/session-2026-05-12/SESSION_REPORT.md @@ -0,0 +1,129 @@ +# 📋 Relatório de Sessão — 2026-05-12 (BPM/DBA) + +**Operador:** Joaquim (Promo Brindes / Zapp Web) +**Agente:** Claude (sessão BPM/DBA) +**Duração:** sessão completa de ~10h +**Branch desta sessão:** `feat/audit-types-drift-2026-05` + +--- + +## 🎯 Objetivo da sessão + +Hardening de segurança no BD self-hosted Supabase, validação de baseline pós-migração Lovable, +auditoria de drift, e configuração de procedimentos de recovery validados. + +--- + +## ✅ O que foi feito nesta sessão + +### A — Mudanças aplicadas no BD self-hosted (NÃO ESTÃO NESTE REPO) + +Estas mudanças foram aplicadas **diretamente em produção** no Supabase self-hosted +(`supabase.atomicabr.com.br`). Por serem state changes de banco e não código de aplicação, +**não vão para o GitHub** — vão para o histórico do próprio Postgres. + +| # | Ação | Detalhes | +|:-:|---|---| +| 1 | **RLS lockdown em 18+ tables** | LOTE 1A/1B + Patch A + LOTE 2: supplier_pix_keys, media_quarantine, evolution_status_*, conversation_transfers, transfer_comments, evolution_whatsapp_status, etc. Padrão lockdown puro + read autenticado onde Realtime usa. | +| 2 | **17 functions Lovable reinstaladas** | 6 com adapter customizado por divergência de schema. Smoke test 17/17 passou. | +| 3 | **23 ALTER COLUMN em 10 tables** | Alinhamento de tipos pós-migração Lovable. | +| 4 | **password_reset_requests.reset_token** | Coluna adicionada. | +| 5 | **fn_register_instance patched** | RLS + policies em partições filhas. | +| 6 | **6 credentials harmonizadas** | api_keys, bling_token, credential_vault, workspace_secrets (lockdown), passkey_credentials (user_id=auth.uid()), whatsapp_official_credentials (admin-only). | +| 7 | **7 backups vazios deletados** | 20 bytes cada, datas 05-11/mai (PGHOST apontava pro FATOR X que caiu). | +| 8 | **5 backups FATOR X arquivados** | 6.3 GB movidos para `/backups/archive/`. | + +**Validação:** Smoke test em produção: `{"ok": 24, "fail": 0, "defer": 7, "status": "healthy"}`. + +### B — Artefatos COMMITADOS neste repo (esta branch) + +| Arquivo | Linhas | Status | +|---|---:|:-:| +| `docs/types-drift-2026-05/AUDIT_REPORT.md` | 124 | ✅ Markdown legível | +| `docs/types-drift-2026-05/missing-tables-from-types.txt` | 301 | ✅ Lista completa | +| `docs/backups/restore-test.sh` | ~90 | ✅ Script validado | +| `docs/backups/install-restore-test-cron.sh` | ~25 | ✅ Helper de cron | +| `docs/backups/README.md` | 112 | ✅ Doc de DR | +| `docs/session-2026-05-12/SESSION_REPORT.md` | (este arquivo) | ✅ | + +### C — Validação em produção + +Restore test executado em 2026-05-12 19:54 UTC: + +``` +[2026-05-12T19:54:02+00:00] Resultado: + - tables públicas: 600 + - evolution_contacts: 17.340 (match com produção) + - evolution_messages: 1.838.351 + - profiles: 6 + - tamanho restaurado: 1921 MB +✅ RESTORE TEST PASSOU (121 segundos) +``` + +--- + +## ❌ O que NÃO foi feito (e por quê) + +### Tarefas que dependem de ação do Joaquim + +| # | Tarefa | Bloqueio | +|:-:|---|---| +| 🔴 1 | **Off-site R2 backup** | Worker `backup-upload-r2.adm01.workers.dev` retorna HTTP 401. Secret correto está no Cloudflare Dashboard. Já existe script `/workspace/scripts/backup-to-r2.sh` quebrado desde 04-mai-2026. | +| 🟡 2 | **Upgrade studio + analytics + meta + functions** | Docker Swarm com stack file no HOST do VPS. Sem acesso ao stack file. Restart de 4 containers = realtime fora. Precisa janela de manutenção. | +| 🟡 3 | **Upgrade storage-api v1.37 → v1.48** | 11 versões + HIGH RISK. Migrations internas podem corromper Storage. Precisa janela controlada. | +| 🟡 4 | **Upgrade kong 2.8 → 3.9 (MAJOR)** | Vai quebrar autenticação de TODO Supabase. Precisa migrar `kong.yml` manualmente. | + +### Tarefas inerentemente fora do repo + +A maior parte das melhorias desta sessão (item A acima) **são mudanças de estado do BD**, +não código. Portanto: +- ✅ Estão **em produção** (aplicadas) +- ❌ **Não vão pro GitHub** (não há código para commitar) +- ✅ Estão **documentadas no histórico do Postgres** (`pg_event_trigger`, audit logs) + +--- + +## 📊 Estado do repositório GitHub após esta sessão + +### Branches existentes +- `main` (HEAD: `8555b50db`) — não alterada nesta sessão +- `feat/audit-types-drift-2026-05` (HEAD: `b8ff41aed` antes deste PR) — esta branch +- `audit/initial-audit-2026-05` — sessões anteriores +- `preserve/faxina-2026-05` — sessões anteriores +- `adm01-debug-patch-1`, `adm01-debug-patch-2` — outras + +### PRs anteriores (sessões anteriores, JÁ MERGEADOS no main) +- **#121** chore(onda-8): zero violations DS +- **#122** fix(ci): early-exit types:gen +- **#123** chore(onda-10.1): silenciar 96 warnings react-refresh +- **#124** feat(onda-9.1): migration SQL vault healthcheck +- **#125** docs(onda-9.2): handoff RCA + runbook supabase volumes +- **#126** fix(ci): zerar test fail vitest run --coverage +- **#128** fix(onda-9.3): feedback Copilot/Codex pós-merge Onda 9 + +### PR DESTA sessão +- **STATUS: ✅ ABERTO** — [PR #130](https://github.com/adm01-debug/zapp-web/pull/130) + (`feat/audit-types-drift-2026-05` → `main`), criado em 2026-05-12. + +--- + +## 🎯 Próximos passos sugeridos para o operador (Joaquim) + +1. **Revisar este PR** quando for aberto e mergear para `main`. +2. **Decidir sobre R2 off-site backup:** + - Opção A: regenerar secret no Cloudflare Dashboard → me passar. + - Opção B: criar R2 API Token S3-compat em `promo-brindes-backups` → me passar Access/Secret. +3. **Marcar janela de manutenção** para os 4 upgrades pendentes: + - storage-api (HIGH RISK) + - kong MAJOR + - studio + analytics + meta + functions (4 containers, ~5min downtime) +4. **Deploy do restore-test:** + ```bash + docker cp docs/backups/restore-test.sh \ + $(docker ps -qf name=supabase-backup_backup):/backups/restore-test.sh + bash docs/backups/install-restore-test-cron.sh + ``` + +--- + +*Sessão encerrada com transparência total sobre o que foi e o que não foi possível executar.* diff --git a/docs/types-drift-2026-05/AUDIT_REPORT.md b/docs/types-drift-2026-05/AUDIT_REPORT.md new file mode 100644 index 000000000..41621c868 --- /dev/null +++ b/docs/types-drift-2026-05/AUDIT_REPORT.md @@ -0,0 +1,139 @@ +# 🔍 Auditoria de Drift — `types.ts` vs BD Self-Hosted + +**Data:** 2026-05-12 +**Branch:** `feat/audit-types-drift-2026-05` +**Status:** READ-ONLY audit — nenhum types.ts modificado nesta branch +**Análise gerada por:** Claude (sessão BPM/DBA) + +--- + +## ⚠️ TL;DR + +O arquivo `src/integrations/supabase/types.ts` no `main` está **MUITO desatualizado** vs o BD self-hosted em produção: + +| Métrica | BD self-hosted (canon) | types.ts no `main` | Drift | +|---|---:|---:|---:| +| **Tables + Views** | 601 | 414 | 🔴 **−187 (missing)** + **−241 (extra obsoletas)** | +| **Enums** | 17 | 13 | 🟡 −4 | +| **Tamanho do arquivo** | — | 15.323 linhas | — | + +### O que isso significa + +- 🔴 **187 tables existem no BD mas não no `types.ts`** — toda chamada `supabase.from('')` pra essas tables retorna `unknown` no TypeScript. Frontend roda com type safety enfraquecida ou com `as any` espalhado. +- 🟡 **241 entradas no `types.ts` apontam pra tables que não existem mais no BD** — código pode referenciar tabelas dropadas e quebrar em runtime. +- 🟢 **414 entradas em comum** — provavelmente OK, mas colunas individuais podem ter divergido. + +--- + +## 📊 187 Tables missing — agrupadas por categoria + +| Categoria | Quantidade | Comentário | +|---|---:|---| +| **EVOLUTION core** | 79 | Tabelas core do WhatsApp/Evolution API | +| **BPM cards** | 41 | Sistema de kanban / cards (novo) | +| **EVOLUTION partições** | 24 | Partições filhas: `_wpp2`, `_comercial_01..15`, `_artes`, etc — **normalmente não precisam estar no types.ts** (queries usam tabela-mãe) | +| **GMAIL** | 12 | Integração Gmail recém-adicionada | +| **EMAIL custom** | 9 | Sistema de email tracking | +| **AGENT/AI** | 8 | Sistema de agentes IA | +| **PT-BR legacy** | 7 | empresas, colaboradores, contatos, salespeople, solicitacoes_vale, supplier_pix_keys, bling_token | +| **SYSTEM (_*)** | 1 | _db_size_snapshots | +| **OUTROS** | 6 | restantes | + +**Total: 187 tabelas missing.** + +--- + +## 🟡 241 Tables extras no types.ts — não existem mais no BD + +Top suspects (primeiras 30): +- `abandoned_carts` — provavelmente nunca implementada +- `ai_agent_*` (6 tables) — virou apenas `agents` no BD novo +- `app_webhooks` — virou `webhook_endpoints` +- `auth_attempts` — virou `login_attempts` +- `cart_recovery_*` (2) — feature não nasceu +- `auto_pause_instance_on_auth_spike` — provavelmente FUNCTION, não table +- `calculate_*`, `cleanup_*`, `check_*` — **FUNCTIONS marcadas erradamente como tables no types.ts** + +Pelo padrão, **muitas das 241 "extras" são RPCs/Functions, não tables.** O Supabase CLI antigo gerava entradas RPC e tables misturadas. Versão atual separa em `Functions: {}` block. + +--- + +## 🛠️ Recomendação para regenerar types.ts COM SEGURANÇA + +### ❌ NÃO fazer +- ❌ Merge direto na `main` sem CI +- ❌ Regenerar e commitar tudo de uma vez (15k linhas de diff) +- ❌ Confiar 100% na geração — frontend pode usar nomes legacy + +### ✅ Fazer + +#### Opção A — Supabase CLI (oficial, mas precisa Docker socket) + +> ⚠️ **Nunca cole a senha real em terminal/docs/histórico.** +> Carregue do vault ou de um arquivo `.env` fora do versionamento. A linha +> abaixo lê de `SUPABASE_DB_PASSWORD` (vault/secret manager) e nunca exibe +> o valor; o shell history fica seguro porque a senha não aparece em texto. + +```bash +# Pré-requisito: Docker disponível na máquina +git checkout feat/audit-types-drift-2026-05 +cd src/integrations/supabase + +# Carregue do vault — NÃO digitar/colar a senha no terminal: +# export SUPABASE_DB_PASSWORD="$(pass show supabase/self-hosted/admin)" # via password-store +# # OU: SUPABASE_DB_PASSWORD=$(op read 'op://Vault/Supabase Self-hosted/admin password') # via 1Password CLI +# # OU: set -a; . ./.env.local; set +a # via .env (gitignored) +: "${SUPABASE_DB_PASSWORD:?Defina SUPABASE_DB_PASSWORD via vault antes de continuar}" + +# Monta a URL sem expor a senha em ps/history (interpolação é local ao processo). +SUPABASE_DB_URL="postgresql://supabase_admin:${SUPABASE_DB_PASSWORD}@supabase.atomicabr.com.br:5432/postgres" + +# Gerar tipos (passar via --db-url evita que a senha apareça em `ps`). +npx supabase gen types typescript --db-url "$SUPABASE_DB_URL" --schema public > types.new.ts + +# Higiene: limpar a variável do shell logo após uso. +unset SUPABASE_DB_URL SUPABASE_DB_PASSWORD + +# Comparar +diff types.ts types.new.ts | less + +# Validar build +cd ../../.. +npm run build # crítico — se quebrar aqui, NÃO COMMITAR +npm run test +``` + +#### Opção B — Manual via postgres-meta (Supabase Studio API) + +O container `supabase_meta:v0.95.2` já expõe endpoint REST que pode gerar tipos. Inspect `/api/v1/typescript` no container. + +#### Opção C — Diff incremental + +Em vez de regerar tudo, adicionar tabelas-faltantes **uma a uma** por feature: +1. PR 1: adicionar 8 tables `agent_*` +2. PR 2: adicionar 12 tables `gmail_*` +3. PR 3: adicionar 41 tables `bpm_*` +4. PR 4: adicionar 79 tables `evolution_*` core +5. PR 5: limpar 241 entradas obsoletas + +**Esta opção é mais segura para rollback caso algo quebre.** + +--- + +## 📋 Lista completa das 187 missing tables + +Salva em `docs/types-drift-2026-05/missing-tables-from-types.txt` nesta branch. + +--- + +## 🚀 Próximos passos + +- [ ] Joaquim decide qual opção (A, B ou C) +- [ ] Janela de manutenção noturna (Vercel rebuild ~5min) +- [ ] Branch separada por PR +- [ ] CI validando `npm run build` antes de merge +- [ ] Rollback documentado: `git revert` simples + +--- + +*Auditoria gerada em 12-mai-2026 sem modificar produção. Apenas relatório.* \ No newline at end of file diff --git a/docs/types-drift-2026-05/missing-tables-from-types.txt b/docs/types-drift-2026-05/missing-tables-from-types.txt new file mode 100644 index 000000000..d007db7bc --- /dev/null +++ b/docs/types-drift-2026-05/missing-tables-from-types.txt @@ -0,0 +1,301 @@ +_db_size_snapshots +agent_installed_skills +agent_memories +agent_permissions +agent_presence +agent_templates +agent_traces +agent_usage +agent_versions +agents +alert_channels +alert_dispatch_state +alerts +api_keys +app_error_logs +app_notifications +audio_meme_categories +audio_meme_favorites +audit_log_safe +audit_log_tables +audit_results +avatars +batch_jobs +bling_token +bpm_activity_log +bpm_automation_actions +bpm_automation_conditions +bpm_automation_executions +bpm_automations +bpm_card_answer_fields +bpm_card_answers +bpm_card_attachments +bpm_card_checklist_items +bpm_card_checklists +bpm_card_comments +bpm_card_email_attachments +bpm_card_emails +bpm_card_labels +bpm_card_movements +bpm_card_recurrences +bpm_card_subtasks +bpm_card_time_entries +bpm_card_watchers +bpm_cards +bpm_connections +bpm_dashboard_elements +bpm_email_configs +bpm_flow_steps +bpm_flow_template_installs +bpm_flow_templates +bpm_flows +bpm_form_fields +bpm_forms +bpm_labels +bpm_notification_preferences +bpm_public_form_submissions +bpm_public_share_access +bpm_public_shares +bpm_register_fields +bpm_register_records +bpm_register_values +bpm_registers +bpm_saved_views +bpm_sla_records +bpm_user_favorites +budgets +chunks +colaboradores +collections +companies +consent_records +constraint_changelog +contact_audit_log +contact_emails +contact_export_log +contact_phones +contact_segments +contatos +conversation_summaries +cookies_config +credential_audit_logs +credential_vault +cron_schedule_executions +cron_schedules +csat_responses +data_deletion_requests +dead_letter_queue +deploy_connections +documents +email_attachments +email_contact_scores +email_link_click_events +email_templates +email_tracked_links +email_tracked_messages +email_tracking_events +email_tracking_summary +email_tracking_templates +embedding_configs +empresas +engineering_principles +environments +evaluation_datasets +evaluation_runs +evolution_alert_cooldown +evolution_alerts +evolution_audit_log +evolution_automation_logs +evolution_automations +evolution_backfill_audit +evolution_baileys_session_history +evolution_bitrix_field_mapping +evolution_bitrix_queue +evolution_bitrix_sync +evolution_blacklist +evolution_broadcasts +evolution_business_hours +evolution_calls +evolution_campaign_recipients +evolution_campaigns +evolution_chatbot_responses +evolution_connection_history +evolution_contact_attachments +evolution_contact_blacklist +evolution_contact_notes +evolution_contact_rate_limits +evolution_contacts +evolution_conversations +evolution_conversations_artes +evolution_conversations_comercial_01 +evolution_conversations_comercial_02 +evolution_conversations_comercial_03 +evolution_conversations_comercial_04 +evolution_conversations_comercial_05 +evolution_conversations_comercial_06 +evolution_conversations_comercial_07 +evolution_conversations_comercial_08 +evolution_conversations_comercial_09 +evolution_conversations_comercial_10 +evolution_conversations_comercial_11 +evolution_conversations_comercial_12 +evolution_conversations_comercial_13 +evolution_conversations_comercial_14 +evolution_conversations_comercial_15 +evolution_conversations_compras +evolution_conversations_default +evolution_conversations_financeiro +evolution_conversations_gravacao +evolution_conversations_logistica +evolution_conversations_marketing +evolution_conversations_wpp2 +evolution_conversations_wpp_pink_test +evolution_daily_metrics +evolution_deals +evolution_dlq +evolution_ef_logs +evolution_followup_rules +evolution_followups +evolution_group_messages +evolution_group_participants +evolution_group_rules +evolution_group_stats +evolution_groups +evolution_holidays +evolution_keyword_automations +evolution_label_associations +evolution_labels +evolution_media +evolution_message_queue +evolution_message_templates +evolution_messages +evolution_mirror_batches +evolution_mirror_checkpoints +evolution_mirror_media_queue +evolution_mirror_runs +evolution_notification_config +evolution_notification_log +evolution_notifications +evolution_performance_metrics +evolution_pipeline_health_log +evolution_pipeline_health_log_legacy +evolution_pipeline_history +evolution_quick_replies +evolution_reactions +evolution_realtime_events +evolution_reconcile_jobs +evolution_retention_log +evolution_sales_pipeline +evolution_scheduled_messages +evolution_sentiment_alerts +evolution_sentiment_analysis +evolution_sentiment_metrics +evolution_settings +evolution_source_schema_map +evolution_spam_keywords +evolution_stage_mapping +evolution_status_auto_rules +evolution_status_reactions +evolution_tag_assignments +evolution_tags +evolution_tasks +evolution_template_usage +evolution_typebot_sessions +evolution_webhook_dlq +evolution_webhook_events +evolution_webhook_metrics +evolution_whatsapp_status +extensions +finetune_jobs +forensic_snapshots +gmail_attachments +gmail_cache_test +gmail_daily_metrics +gmail_drafts +gmail_health_summary +gmail_labels +gmail_messages +gmail_revalidation_jobs +gmail_signatures +gmail_test_fail +gmail_test_telemetry +gmail_threads +guardrail_ml_logs +guardrail_policies +hf_config +hypopg_hidden_indexes +hypopg_list_indexes +imap_smtp_accounts +installed_templates +integration_registry +interactions +knowledge_bases +mcp_servers +media_download_queue +media_quarantine +media_scan_log +media_security_alerts +media_security_config +media_storage_config +message_queue +messages_whatsapp +model_pricing +model_pricing_v2 +n8n_variables +nlp_extractions +notification_channels_config +notification_templates +oracle_history +outbound_message_queue +pii_access_log +prompt_ab_tests +prompt_versions +queue_items +queue_routing_rules +quick_replies +ragas_scores +restore_test_log +roles +rpc_rate_limits +salespeople +scheduled_job_log +schema_migrations +security_events +session_traces +sessions +skill_registry +sla_policies +sla_violations +solicitacoes_vale +sticker_categories +sticker_favorites +supabase_projects +supplier_pix_keys +system_docs +system_logs +system_settings +task_queues +tenants +test_cases +tool_integrations +tool_policies +trace_events +usage_records +vault_healthcheck_log +vector_indexes +webhook_audit_log +webhook_endpoints +webhook_events +webhook_events_processed +webhook_health_alerts +workflow_checkpoints +workflow_executions +workflow_handoffs +workflow_runs +workflow_step_runs +workflow_steps +workflows +workspace_members +workspace_secrets +workspaces +zapp_audit_log