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

167 lines
10 KiB
Markdown

# 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-plg`**ramificada 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
4. **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.
5. **`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`.
6. **`config.toml` é gitignored** — `enable_confirmations=true` está só no arquivo local
(não versionado). No hosted a confirmação vai pelo **dashboard** (Auth → Confirm email).
7. **Migração de dados (cutover)** — `f6_1` COPIA; conferir **paridade de contagens** por
tenant/tabela antes de confiar (e antes do DROP).
8. **Edge functions novas precisam deploy** — `recover-access` e `send-welcome-email` (freemium)
+ as edges de roteamento por schema (schema-per-tenant). Esquecer = esqueci-email/welcome/
webhooks quebram.
9. **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
10. **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.
11. **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.
12. **send-welcome-email usa SMTP de sistema** (separado do canal do tenant) — precisa secrets
no hosted; é best-effort (falha não bloqueia login).
13. **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).
14. **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):
```bash
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:
> ```bash
> 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).