diff --git a/Obsidian/Brain/log.md b/Obsidian/Brain/log.md index 67ca2a4..3af18ef 100644 --- a/Obsidian/Brain/log.md +++ b/Obsidian/Brain/log.md @@ -1651,3 +1651,6 @@ Touched: Migracao Schema-per-Tenant ## [2026-06-13 04:52] session | F3 schema-per-tenant: frontend tenantDb Touched: Migracao Schema-per-Tenant + +## [2026-06-13 09:10] session | F4 edge functions + F1b anon-tables-public +Touched: Migracao Schema-per-Tenant diff --git a/Obsidian/Brain/wiki/Migracao Schema-per-Tenant.md b/Obsidian/Brain/wiki/Migracao Schema-per-Tenant.md index d18e982..a818ec2 100644 --- a/Obsidian/Brain/wiki/Migracao Schema-per-Tenant.md +++ b/Obsidian/Brain/wiki/Migracao Schema-per-Tenant.md @@ -1,6 +1,25 @@ # Migração Schema-per-Tenant -**Status:** F3 concluída no branch `feat/schema-per-tenant` (2026-06-13, build de produção passa). Próximo: F4 (edge functions). F0-F2 estão em `main`; F3+ no branch até cutover (F5/F6). +**Status:** F4 concluída no branch `feat/schema-per-tenant` (2026-06-13). Próximo: decisão de roteamento anon-por-token, depois F5 (PostgREST). F0-F2 em `main`; F3+ no branch até cutover. + +## F4 — entregue (branch, commit 9b21642) +- `_shared/tenant.ts`: helper das edge functions — `adminClient()` (service_role/public), `tenantDbForId(admin, tenantId)`, `schemaForTenant`, `listTenantSchemas` (crons varrem todos), `resolveTenantByChannel` (webhook→tenant via channel_routing), `tenantSchemaName` +- `_shared/whatsapp-hooks.ts` refatorado: hooks de tabela tenant recebem `tdb`; RPCs de crédito (deduct/add_whatsapp_credits) + tenant_members continuam em `supa`+p_tenant_id +- 23 edge functions migradas. Categorias: + - **inbound** (twilio/evolution): tenant_id da URL → tdb + - **crons de fila** (process-notification/email/sms/whatsapp-queue): varrem `listTenantSchemas` e drenam a fila de CADA schema — consequência direta da Q3 (filas viraram per-tenant). Modo single-tenant se `body.tenant_id` vier. + - **crons reminders/checks** (send-session-reminders, conversation-sla-check, whatsapp-heartbeat-check, convert-abandoned-intakes, sync-email-templates): loop por tenant + - **routing por tenant_id** (send-whatsapp-message, send-session-reminder-manual, twilio-provision, de/reactivate-channel, twilio-webhook): tenantDbForId; channel-actions sem tenant_id varrem schemas por channel_id (O(n) tenants) + - **asaas-***: tenant_id do body → tdb; asaas-webhook fica global + - **notification-webhook** (Meta Cloud API): resolve via channel_routing por phone_number_id, fan-out por message_id quando não casa +- caller `useAgendaEventLifecycle.js` passa tenant_id pro send-session-reminder-manual (evento vive no schema) +- Sem deno local → validado por grep (zero tenant_id em cadeias tdb, clients todos declarados, imports batem). Type-check real só no deploy. + +### ⚠️ DECISÃO PENDENTE — roteamento anon-por-token (bloqueia F5/F6) +Fluxos anônimos identificam o tenant por TOKEN/SLUG, não por login, então não sabem o schema: `save-intake-progress` (lê patient_intake_requests por token), intake RPCs (get-intake-invite-info, submit-patient-intake), `AgendadorPublicoPage`+RPCs do agendador (link_slug), document share links (validate_share_token, sign_document_by_token). Opções: +- **A** Índice global `public_access_tokens(token_hash→tenant_id)` + triggers de sync (O(1), +1 tabela global + triggers) +- **B** RPCs SECURITY DEFINER que varrem schemas pelo token (sem tabela nova, O(n) por request) +- **C** Manter as tabelas anon-facing (patient_intake_requests, patient_invites, document_share_links, agendador_configuracoes/solicitacoes) em PUBLIC com RLS por token — sidesteppa o problema; custo: essas não ganham isolamento físico (mas são as menos sensíveis, feitas pra acesso anon) ## F3 — entregue (branch feat/schema-per-tenant, migration 07) - `src/lib/supabase/tenantClient.js` (`tenantDb()`, `tenantSchemaName()`) + `src/composables/useTenantDb.js`