Files
agenciapsilmno/docs/HANDOFF_E_TESTES.md
T
Leonardo eb9dcc714f docs: gotcha pgrst.db_schemas nao sobrevive ao restart do stack
Apos supabase stop/start a GUC de exposicao dos schemas tenant some -> 404 nas
tabelas tenant. HANDOFF Passo 0 agora manda rodar refresh_pgrst_schemas() pos-start.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 21:02:02 -03:00

10 KiB

Handoff — Onde paramos, Riscos e Passo a passo de teste

Estado consolidado dos dois épicos grandes (schema-per-tenant + freemium/PLG). Última atualização: 2026-06-13. Branch de trabalho: feat/schema-per-tenant (base) e feat/freemium-plg (empilhada — contém tudo). main segue no modelo RLS antigo.


1. Onde paramos (estado atual)

Branches

  • main — modelo RLS-only (produção atual). Recebeu só F0/F1/F2 aditivos da schema-per-tenant.
  • feat/schema-per-tenant — migração completa F0→F6.2 + wiring + F6.4. F6.3 DROP NÃO aplicado.
  • feat/freemium-plgramificada da schema-per-tenant, contém TODO o freemium (F1/F2/F3) + os dois runbooks de deploy + este handoff. É a branch a deployar (tem os dois épicos).

Banco LOCAL (Docker supabase_db_agenciapsi-primesakai)

Está no estado schema-per-tenant + freemium aplicado:

  • Schemas tenant_<slug> existem (9 tenants clonados) + dados COPIADOS (espelho ainda em public).
  • Todas as migrations + todos os manual/*.supabase_admin.sql aplicados, EXCETO o F6.3 DROP.
  • enable_confirmations está true no config.toml mas só ativa após reiniciar o stack.

Schema-per-tenant — feito / pendente

  • Estrutura, helpers, template, clone/drop, provisionamento, 66 funções migradas, dados dos 9 tenants copiados+verificados, PostgREST dinâmico (local), frontend/edge roteando por schema.
  • F6.3 DROP (remove o espelho em public) — preparado, NÃO aplicado. Aguarda teste no browser + OK + backup fresco. (task #7)
  • 📄 Deploy: docs/DEPLOY_SCHEMA_PER_TENANT.md.

Freemium/PLG — feito / pendente

  • F1 limite de pacientes (trigger runtime + toast + Upgrade PRO).
  • F2 self-service (confirmação de e-mail, RPCs idempotentes, signup reescrito, /onboarding, welcome email, vitrine "Grátis") + fix de regressão do audit em tenant_members.
  • F3 4 extras (blacklist, /saas/usuarios + notify devs, esqueci-email, root_redirect).
  • F4 deploy (hosted) — runbook em docs/DEPLOY_FREEMIUM_F4.md. Não deployado.
  • Teste local ponta-a-ponta — exige reiniciar o stack (seção 3).

Tudo commitado e pushado em feat/freemium-plg. Nada pendente no working tree

(só .env/dashboard/.claude locais, intencionalmente fora).


2. Riscos (todos)

🔴 Críticos

  1. PostgREST dinâmico no hosted — a exposição de schemas tenant usa ALTER ROLE authenticator SET pgrst.db_schemas. Pode ser restrito no hosted. Se falhar, o app novo recebe 404 nas tabelas tenant. Testar cedo (Fase C do runbook); fallback = Exposed schemas no dashboard (estático → problema com signup self-service). Decidir antes de abrir signup.
  2. F6.3 DROP é irreversível — remove as tabelas tenant de public. Só após dias de soak no modelo novo + backup fresco. Rollback = restore (f6_3_ROLLBACK.md).
  3. Confirmação de e-mail + SMTP do GoTrue (hosted) — com Confirm email = ON, se o SMTP do GoTrue não estiver configurado com provedor real, ninguém consegue logar (o link de confirmação não chega). Configurar SMTP no dashboard ANTES de ligar a confirmação.

🟠 Importantes

  1. Manual files fora do fluxo do db.cjs — os manual/*.supabase_admin.sql NÃO são aplicados pelo db.cjs migrate. São aplicados à mão (psql como supabase_admin). Fácil esquecer um → função/trigger ausente. Os runbooks listam a ordem.
  2. postgres não é superuser no stack local — por isso vários objetos são supabase_admin. No hosted o postgres é mais privilegiado, mas o schema auth é de supabase_admin: o trigger da blacklist em auth.users e os OWNER TO supabase_admin podem precisar de SQL Editor ou troca pra OWNER TO postgres.
  3. config.toml é gitignoredenable_confirmations=true está só no arquivo local (não versionado). No hosted a confirmação vai pelo dashboard (Auth → Confirm email).
  4. Migração de dados (cutover)f6_1 COPIA; conferir paridade de contagens por tenant/tabela antes de confiar (e antes do DROP).
  5. Edge functions novas precisam deployrecover-access e send-welcome-email (freemium)
    • as edges de roteamento por schema (schema-per-tenant). Esquecer = esqueci-email/welcome/ webhooks quebram.
  6. Slug é IMUTÁVEL — = nome do schema físico. Uma vez escolhido, não muda (trava em 3 camadas). UX do signup deixa claro, mas é definitivo.

🟡 Menores / a observar

  1. Enforcement de limite é por-linha (BEFORE INSERT) — um bulk insert de pacientes numa única statement pode passar marginalmente do limite (cada linha não vê as anteriores da mesma statement). Na prática o cadastro é 1 a 1; ok.
  2. notify_all_devs dispara a cada subscription (inclui a free do auto_provision) — em escala, muitos avisos no sino do dev. Intencional; reavaliar se incomodar.
  3. send-welcome-email usa SMTP de sistema (separado do canal do tenant) — precisa secrets no hosted; é best-effort (falha não bloqueia login).
  4. auto_provision idempotente retorna o 1º tenant ativo se o user já tem algum — usuário multi-tenant que se cadastra de novo não ganha tenant novo (esperado).
  5. Local vs main inconsistente — o banco local está no modelo novo; o código da main é RLS. Se fizer git checkout main, o app antigo ainda funciona porque public tem as tabelas (até o DROP). Não rodar main esperando o modelo novo (e vice-versa).

3. Passo a passo — como testar TUDO (local)

Pré: Docker do Supabase rodando (portas 643xx). Frontend via npm run dev.

Passo 0 — Ativar a confirmação de e-mail

A confirmação só vale após reiniciar o stack (o volume do banco persiste — nada se perde):

supabase stop && supabase start      # se falhar com containers unhealthy, rode start de novo (transiente)

Conferir no Studio/Mailpit que está de pé. (Se preferir NÃO testar confirmação agora, pule — o front trata os dois casos; mas o fluxo "confirme e-mail" só aparece com isto ligado.)

🔴 GOTCHA OBRIGATÓRIO pós-restart — a GUC pgrst.db_schemas (exposição dos schemas tenant no PostgREST) NÃO sobrevive ao supabase stop/start (o start reseta a role authenticator). Sem isso o app dá 404 em todas as tabelas tenant. Rodar SEMPRE após start:

docker exec -i supabase_db_agenciapsi-primesakai psql -U supabase_admin -h 127.0.0.1 -d postgres \
  -c "select public.refresh_pgrst_schemas();"

(Confirma exposição: curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:64321/rest/v1/patients?limit=1" -H "Accept-Profile: tenant_<slug>" deve dar 200.)

Passo 1 — Schema-per-tenant: tenants EXISTENTES ainda funcionam

  1. npm run dev, logar num tenant existente (ex.: clínica Bem-Estar / um terapeuta).
  2. Abrir Agenda, Pacientes, Financeiro, Conversas → tudo carrega (lendo de tenant_<slug>).
  3. Criar/editar um registro (ex.: um bloqueio na agenda, editar um paciente) → salva sem erro.
  4. Sino de notificações abre (dual-source tenant + sistema).

Se algo não carregar, é sinal de roteamento de schema — anotar a tela/erro.

Passo 2 — Freemium: signup self-service NOVO (o fluxo principal)

  1. Deslogar. Ir em /lp → conferir o cartão "Grátis" na vitrine.
  2. Criar conta grátis → escolher tipo (terapeuta/clínica) + seu nome + nome do negócio + slug (ver a checagem de disponibilidade ao vivo) + e-mail + senha.
  3. Submeter → cai na tela "Confirme seu e-mail" (NÃO loga ainda).
  4. Abrir o Mailpit (caixa de e-mail local) → achar o e-mail de confirmação → clicar no link.
  5. Voltar/entrar em /auth/login → logar → cai em /onboarding → "Preparando seu ambiente…" → provisiona → entra no painel do tenant novo.
  6. Conferir no Mailpit o e-mail de boas-vindas (welcome — best-effort).
  7. Conferir que o schema tenant_<slug-escolhido> foi criado (Studio) e que você é master.

Passo 3 — Limite do plano gratuito

  1. No tenant gratuito recém-criado (ou num clinic_free existente), cadastrar pacientes.
  2. Ao passar do limite (clínica=30, terapeuta=20) → aparece o toast "Limite do plano gratuito" com botão "Fazer upgrade" (não o erro cru).
  3. Conferir o botão "Upgrade PRO" dourado no topbar (visível porque o plano é free).

Passo 4 — SaaS / dev (logar como saas_admin)

  1. /saas/usuarios → o cliente novo aparece com selo "Novo" (verde, 24h), com slug/e-mail/plano.
  2. Sino do dev → recebeu "Nova assinatura" (do provisionamento).
  3. /saas/app-config:
    • Adicionar um e-mail na blacklist (ex.: bloqueado@x.com). Depois, deslogar e tentar criar conta com ele → bloqueado de verdade.
    • Testar @dominio.com (domínio inteiro).
    • Trocar root_redirect (landing↔login) e abrir / deslogado → confere o destino.

Passo 5 — Esqueci meu e-mail

  1. /auth/login"Esqueci meu e-mail" → digitar o slug do tenant criado no Passo 2.
  2. Recebe a confirmação com a dica mascarada (jo****@gm****.com) e um magic link no Mailpit.
  3. Clicar no magic link → entra. (O e-mail real nunca aparece na tela.)
  4. ⚠️ Edge functions locais: precisam estar servidas (supabase functions serve ou o runtime do stack). Se o esqueci-email/welcome não responder, é a edge não estar de pé localmente.

Passo 6 — Pegadinha #4 (sino ao trocar de usuário)

  1. Logado como user A, com notificações no sino → logout.
  2. Logar como user B → o sino não mostra notificações do A (foi resetado no logout).

Passo 7 (opcional, destrutivo, só quando confiante) — preparar o DROP

NÃO aplicar agora. Quando tudo acima estiver validado por dias: seguir a Fase G do docs/DEPLOY_SCHEMA_PER_TENANT.md (backup fresco → f6_3_drop_public_tenant_tables).


4. Atalhos / referências

  • Runbooks: docs/DEPLOY_SCHEMA_PER_TENANT.md, docs/DEPLOY_FREEMIUM_F4.md.
  • Rollback do DROP: database-novo/manual/f6_3_ROLLBACK.md.
  • Migrations: database-novo/migrations/ (aplicar via node database-novo/db.cjs migrate).
  • Manual privilegiados: database-novo/manual/*.supabase_admin.sql (aplicar como supabase_admin).
  • Wiki: Obsidian/Brain/wiki/Migracao Schema-per-Tenant.md e Obsidian/Brain/wiki/Freemium PLG.md.
  • Portas locais: API 64321 · DB 64322 · Studio 64323 (stack shiftada +10000).