Files
agenciapsilmno/Obsidian/Brain/wiki/Freemium PLG.md
T
Leonardo 1082123967 freemium F4: referencia o runbook no wiki/log
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 20:42:47 -03:00

6.3 KiB

Freemium / PLG

Épico iniciado em 2026-06-13, branch feat/freemium-plg (sobre Migracao Schema-per-Tenant). Objetivo: qualquer visitante cria conta gratuita sozinho, confirma e-mail, e o ambiente do tenant é provisionado automaticamente. Plano gratuito limitado + botão "Upgrade PRO". Blueprint-diretor: novo-rumo.txt (raiz), vindo do sistema-irmão (sindicato) e adaptado a clínica.

Descoberta (Fase 0) — o que já existia

O sistema já estava ~70-85% pronto:

  • Planos free existem: clinic_free, therapist_free (+ supervisor/patient) com plan_features.limits semeado (clinic_freeclinic_calendar {max_patients:30, max_therapists:5}, online_scheduling {sessions_per_month:40}, reminders {reminders_per_month:50}, documents.upload {max_storage_mb:500}; 14 features premium OFF).
  • Feature gating completo: entitlementsStore.js (views v_tenant_entitlements/v_user_entitlements), FeatureGate.vue, guard meta.feature/upgrade (guards.js:814), badge PRO no menu.
  • Provisionamento schema-per-tenant: ensure_personal_tenant/provision_account_tenantclone_tenant_template. Setup Wizard.
  • Signup self-service: /lp (pricing dinâmico de v_public_pricing) → /auth/signup (Signup.vue:219 signUp inline, cria intent só no pago).
  • RPCs activate_subscription_from_intent, change_subscription_plan. tenants.slug 100% populado.

Gap confirmado: limites semeados mas ninguém lê/enforça. Sem confirmação de e-mail (enable_confirmations=false), sem /onboarding, signup só coleta email+senha, sem welcome email, sem os extras.

Decisões (Fase 0.5)

  1. Modelo do blueprint — confirmação de e-mail ON; signup grava escolha em raw_user_meta_data + signOut-local + tela "confirme e-mail"; provisionamento+intent viram RPCs idempotentes no 1º login (auto_provision_free_tenant(p_slug_override), processar_pos_signup); guard manda logado-sem-tenant → /onboarding. Reescreve o signup inline.
  2. Pacientes = recurso limitado. Trigger BEFORE INSERT em patients lê limits em runtime, resolve tenant por TG_TABLE_SCHEMA, conta linhas vivas, RAISE 'PLAN_LIMIT_REACHED|patients|<n>'. clinic_free=30, therapist_free=20. No template + backfill 9 schemas.
  3. Slug escolhido no signup (sugestão sanitizada + slug_disponivel(p_slug)→{ok,motivo}), imutável, trava 3 camadas.
  4. Todos os 4 extras: /saas/usuarios + notify_all_devs; esqueci-email (magic link por slug, dica mascarada); blacklist (email|slug); root_redirect.

Pegadinhas (do blueprint, ⚠️ caras no irmão)

  • #1 Signup sem sessão (confirmação ON) → tudo com auth.uid() quebra em silêncio. Gravar escolha em metadata, processar pós-confirmação.
  • #2 signOut scope:'local' se não veio sessão — senão vaza sessão anterior e joga no painel errado.
  • #3 Logado-sem-tenant nunca cai em painel quebrado → /onboarding resolve estados (provisionando, slug-colidiu, pago-aguardando, sem-acesso, erro).
  • #4 Sino de notificação singleton precisa re-buscar ao trocar de user (logout+login).

Divergência de infra

Blueprint pede welcome email via Resend; aqui é SMTP/Mailpit (process-email-queue). Reusar o pipeline SMTP existente (best-effort), não Resend.

Fases

  • F1 DONE (2026-06-13) — therapist_free ganhou max_patients=20; trigger enforce_patient_plan_limit em patients (lê plan_features.limits em runtime, resolve plano via tenant_active_plan_id, conta vivos, RAISE PLAN_LIMIT_REACHED|patients|n); helpers globais + wiring + backfill 9 schemas. Front: utils/planLimit.js (toast com CTA via grupo system-alerts) nos 3 pontos de criação de paciente + botão Upgrade PRO no AppTopbar quando plano é free. Migrations: 20260613000005_* + manual/freemium_f1_plan_limits.supabase_admin.sql. Testado em ROLLBACK (clinic_free bloqueia em 30, therapist_free em 20, PRO ilimitado).
  • F2 🟡 NÚCLEO DONE (2026-06-13) — enable_confirmations=true (config.toml, gitignored, ativa no restart do stack); RPCs slug_disponivel/auto_provision_free_tenant/processar_pos_signup (manual/freemium_f2_provisioning.supabase_admin.sql, testados em ROLLBACK clínica+terapeuta); fix de regressão log_audit_change (migration 20260613000006) que quebrava INSERT em tenant_members; Signup.vue reescrito (kind+nome+slug ao vivo+metadata, signOut-local + tela confirme-email); OnboardingPage.vue (provision+estados slug-colidiu/erro); guard → /onboarding; rota registrada. Build OK. Restam (polish): welcome email best-effort (infra SMTP schema-per-tenant) + apresentação do free na vitrine (public_name/preço "Grátis"/bullets — os planos já são is_visible=true mas sem nome/preço).
  • F3 DONE (2026-06-13) — 4 extras. DB/edge: blacklist (tabela + trigger BEFORE INSERT em auth.users + integra slug_disponivel motivo 'bloqueado'); saas_list_account_owners() (donos por tenant, dev-only) + notify_all_devs + trigger em subscriptions; saas_app_config/get_root_redirect(); edge recover-access (esqueci-email por slug → magic link, dica mascarada). Front: SaasUsuariosPage (/saas/usuarios, selo Novo 24h) + SaasAppConfigPage (/saas/app-config, blacklist CRUD + toggle root_redirect); esqueci-email dialog no Login; root_redirect no guard ("/" não-logado→/lp|/login, cache TTL); pegadinha #4 (notificationStore.reset no logout). Arquivos: manual/freemium_f3a/b/c + functions/recover-access. Build OK, DB testado em ROLLBACK. ⚠️ edge recover-access precisa deploy (F4).
  • F2 polish DONE (2026-06-13) — welcome email: edge send-welcome-email (dono do tenant, destinatário do JWT, SMTP global/sistema com defaults Mailpit; best-effort fire-and-forget no OnboardingPage só no provision novo). Vitrine: seed plan_public+bullets dos free (migration 20260613000007); Landingpage mostra "Grátis para sempre" via isFreePlan. ⚠️ send-welcome-email precisa deploy + envs SMTP no hosted (F4). Com isso F2 está 100%.
  • F4 — Deploy (hosted, dirigido pelo Leonardo). Runbook completo em docs/DEPLOY_FREEMIUM_F4.md (commit 2f72886): pré-req #0 = schema-per-tenant no hosted antes; migrations 05/06/07 + 5 manual/freemium_f* + Auth dashboard + deploy das 2 edges + secrets SMTP + rebuild + smoke 8 passos + kill-switches.

Método: commits por assunto; cada migration testada em transação com ROLLBACK antes de aplicar; build a cada bloco front.