eb9dcc714f
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>
167 lines
10 KiB
Markdown
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).
|