# CHANGELOG — Banco de Dados AgênciaPsi Registro histórico de todas as migrations aplicadas no banco. Formato: data | arquivo | o que mudou | por quê --- ## [001] — 2026-03-03 **Arquivo:** `migration_001.sql` **Seed:** `seed_001.sql` ### Contexto O schema original foi construído de forma incremental e acumulou inconsistências no modelo de identidade. Usuários não tinham um tipo de conta definido formalmente, tenants não distinguiam terapeuta de clínica, e não existia suporte a paciente como tipo de conta de plataforma. ### O que mudou #### `profiles` - ✅ Adicionada coluna `account_type text NOT NULL DEFAULT 'free'` - Valores: `free | patient | therapist | clinic` - Imutável após sair de `free` (trigger `trg_account_type_immutable`) - Usuários com role=`patient` migrados para `account_type='patient'` - Usuários com tenant `saas` ativo migrados para `account_type='therapist'` #### `tenants` - ✅ Novos valores aceitos em `kind`: - `therapist` → terapeuta individual (substitui `saas`) - `clinic_coworking` → clínica tipo 1: gestão de salas - `clinic_reception` → clínica tipo 2: secretaria + múltiplas agendas - `clinic_full` → clínica tipo 3: coworking + secretaria - ✅ `kind` agora é imutável após criação (trigger `trg_tenant_kind_immutable`) - ✅ 10 tenants `saas` órfãos (sem admin, sem subscriptions) deletados - ✅ Tenants `saas` com admin ativo migrados para `kind='therapist'` - ⚠️ `saas` e `clinic` (legados) mantidos no CHECK por compatibilidade. Não criar novos tenants com esses kinds. #### `plans` - ✅ Adicionado `patient` como valor válido em `target` - ✅ Inserido plano `patient_free` (gratuito, target=patient) #### Novas funções | Função | Descrição | |--------|-----------| | `provision_account_tenant(user_id, kind, name?)` | Cria tenant + membership + atualiza account_type. Chamar no onboarding. | | `is_therapist_tenant(tenant_id)` | Retorna true se tenant é do tipo therapist | | `is_clinic_tenant(tenant_id)` | Atualizada: inclui todos os subtipos de clínica | | `guard_tenant_kind_immutable()` | Trigger: bloqueia alteração de tenants.kind | | `guard_account_type_immutable()` | Trigger: bloqueia alteração de account_type após escolha | | `guard_patient_cannot_own_tenant()` | Trigger: bloqueia paciente de ser tenant_admin/therapist | #### Funções atualizadas | Função | O que mudou | |--------|-------------| | `handle_new_user()` | Agora insere `account_type='free'` | | `handle_new_user_create_personal_tenant()` | Desabilitada — tenant criado no onboarding | | `ensure_personal_tenant()` | Busca por `kind IN ('therapist','saas')` e delega para `provision_account_tenant` | ### Regras de negócio agora garantidas no banco 1. **Paciente é para sempre paciente** — `account_type` imutável após escolha 2. **Terapeuta nunca vira clínica e vice-versa** — `tenants.kind` imutável 3. **Paciente não pode ter tenant** — trigger bloqueia na inserção 4. **Cada tipo de conta tem seu tipo de tenant** — `provision_account_tenant` garante ### Usuários de seed (apenas dev/staging) | Email | Tipo | Tenant | |-------|------|--------| | paciente@agenciapsi.com.br | patient | nenhum | | terapeuta@agenciapsi.com.br | therapist | tenant próprio (therapist) + vinculado à Clínica 3 | | clinica1@agenciapsi.com.br | clinic | clinic_coworking | | clinica2@agenciapsi.com.br | clinic | clinic_reception | | clinica3@agenciapsi.com.br | clinic | clinic_full | | saas@agenciapsi.com.br | saas_admin | nenhum | > Senha de todos: `Teste@123` --- ## [002] — seed_002.sql **Arquivo:** `Novo-DB/seed_002.sql` ### O que cria #### Migration embutida - ✅ `profiles.platform_roles text[] NOT NULL DEFAULT '{}'` — adicionada via `ADD COLUMN IF NOT EXISTS` (idempotente) #### Usuários de teste | Email | Senha | Papel | Tenant | |-------|-------|-------|--------| | `supervisor@agenciapsi.com.br` | `Teste@123` | `supervisor` em `tenant_members` | Clínica Bem Estar (Full) | | `editor@agenciapsi.com.br` | `Teste@123` | `therapist` em `tenant_members` + `platform_roles = '{editor}'` | Clínica Bem Estar (Full) | UUIDs reservados: - Supervisor: `aaaaaaaa-0007-0007-0007-000000000007` - Editor: `aaaaaaaa-0008-0008-0008-000000000008` --- ## [PENDENTE] — Migration necessária: `platform_roles` em `profiles` **Contexto:** Implementação das áreas de **Supervisor** (papel de tenant) e **Editor** (papel de plataforma). O papel de Editor é atribuído pelo `saas_admin` e armazenado diretamente no perfil do usuário, independente de qual tenant ele pertence. ### O que precisa ser aplicado no banco #### `profiles` - ⚠️ **Adicionar coluna** `platform_roles text[] NOT NULL DEFAULT '{}'` - Armazena papéis globais de plataforma. Ex.: `'{editor}'` - Quem pode escrever: somente `saas_admin` (via RLS ou função privilegiada) - Quem pode ter: qualquer usuário autenticado, **exceto** `account_type = 'patient'` - Valores previstos: `editor` (mais podem ser adicionados futuramente) #### SQL sugerido ```sql ALTER TABLE public.profiles ADD COLUMN IF NOT EXISTS platform_roles text[] NOT NULL DEFAULT '{}'; -- Comentário descritivo COMMENT ON COLUMN public.profiles.platform_roles IS 'Papéis globais de plataforma, independentes de tenant. Ex: editor de microlearning. Atribuído pelo saas_admin.'; -- RLS: somente saas_admin pode atualizar platform_roles (exemplo) -- CREATE POLICY "saas_admin pode atualizar platform_roles" -- ON public.profiles FOR UPDATE -- USING (auth.uid() IN (SELECT id FROM public.profiles WHERE role = 'saas_admin')) -- WITH CHECK (true); ``` #### `tenant_members` (sem alteração necessária) - O papel `supervisor` já é suportado como valor text em `tenant_members.role`. - Nenhuma alteração de schema é necessária — basta inserir memberships com `role = 'supervisor'`. ### Impacto se não aplicado - Área do Editor (`/editor`) fica inacessível a todos (coluna ausente → `platform_roles` vem `null` → acesso negado). - Área do Supervisor (`/supervisor`) funciona normalmente — não depende desta migration. --- ## Futuro — registrado mas não implementado ### Vínculo Terapeuta ↔ Clínica (a implementar) - Terapeuta autoriza explicitamente que secretaria gerencie suas sessões - Permissão só válida se clínica tiver `kind IN ('clinic_reception', 'clinic_full')` - Secretaria acessa apenas sessões — não prontuário nem anotações - Dissociação bloqueada se houver `agenda_eventos` futuros (`inicio_em > now()`) - Após dissociação: cada parte fica com seus próprios pacientes - Requer: coluna de permissão no vínculo + função de dissociação com validação --- *Última atualização: 2026-03-03*