Correcao Sidebar Classico e Rail, Correcao Layout, Ajuste de Breakpoint para Tailwind, Ajuste AppTopbar, Ajuste Menu PopOver, Recriado Paleta de Cores, Inserido algumas animações leves, Reajuste Cor items NOVOS da tabela, Drawer Ajuda Corrigido no Logout, Whatsapp, sms, email, recursos extras

This commit is contained in:
Leonardo
2026-03-24 21:26:58 -03:00
parent a89d1f5560
commit 53a4980396
453 changed files with 121427 additions and 174407 deletions

View File

@@ -0,0 +1,47 @@
#!/bin/bash
# =============================================================================
# Executa todos os seeds na ordem correta
# =============================================================================
# Uso: bash run_all_seeds.sh
#
# Pré-requisitos:
# - Container supabase_db_agenciapsi-primesakai rodando
# - Schema já aplicado (schema/00_full/schema.sql)
# =============================================================================
CONTAINER="supabase_db_agenciapsi-primesakai"
DIR="$(cd "$(dirname "$0")" && pwd)"
set -e
echo "=== Aplicando seeds — Usuários ==="
for seed in \
seed_001_fixed.sql \
seed_002.sql \
seed_003.sql
do
echo ""
echo ">>> $seed"
docker exec -i "$CONTAINER" psql -U postgres -d postgres < "$DIR/$seed"
echo "<<< OK"
done
echo ""
echo "=== Aplicando seeds — Sistema (planos, features, subscriptions) ==="
for seed in \
seed_010_plans.sql \
seed_011_features.sql \
seed_012_plan_features.sql \
seed_013_subscriptions.sql \
seed_014_global_data.sql
do
echo ""
echo ">>> $seed"
docker exec -i "$CONTAINER" psql -U postgres -d postgres < "$DIR/$seed"
echo "<<< OK"
done
echo ""
echo "=== Todos os seeds aplicados com sucesso ==="

View File

@@ -0,0 +1,327 @@
-- =============================================================================
-- SEED — Usuários fictícios para teste
-- =============================================================================
-- IMPORTANTE: Execute APÓS a migration_001.sql
-- IMPORTANTE: Requer extensão pgcrypto (já ativa no Supabase)
--
-- Cria os seguintes usuários de teste:
--
-- paciente@agenciapsi.com.br senha: Teste@123 → paciente
-- terapeuta@agenciapsi.com.br senha: Teste@123 → terapeuta solo
-- clinica1@agenciapsi.com.br senha: Teste@123 → clínica coworking
-- clinica2@agenciapsi.com.br senha: Teste@123 → clínica com secretaria
-- clinica3@agenciapsi.com.br senha: Teste@123 → clínica full
-- saas@agenciapsi.com.br senha: Teste@123 → admin da plataforma
--
-- =============================================================================
BEGIN;
-- Limpa seeds anteriores se existirem
DELETE FROM auth.users
WHERE email IN (
'paciente@agenciapsi.com.br',
'terapeuta@agenciapsi.com.br',
'clinica1@agenciapsi.com.br',
'clinica2@agenciapsi.com.br',
'clinica3@agenciapsi.com.br',
'saas@agenciapsi.com.br'
);
-- ============================================================
-- 1. Cria usuários no auth.users
-- NOTA: confirmed_at é coluna gerada — removida do INSERT
-- ============================================================
INSERT INTO auth.users (
instance_id,
id,
email,
encrypted_password,
email_confirmed_at,
created_at,
updated_at,
raw_user_meta_data,
raw_app_meta_data,
role,
aud,
is_sso_user,
is_anonymous,
confirmation_token,
recovery_token,
email_change_token_new,
email_change_token_current,
email_change
)
VALUES
-- Paciente
(
'00000000-0000-0000-0000-000000000000',
'aaaaaaaa-0001-0001-0001-000000000001',
'paciente@agenciapsi.com.br',
crypt('Teste@123', gen_salt('bf')),
now(), now(), now(),
'{"name": "Ana Paciente"}'::jsonb,
'{"provider": "email", "providers": ["email"]}'::jsonb,
'authenticated', 'authenticated', false, false, '', '', '', '', ''
),
-- Terapeuta
(
'00000000-0000-0000-0000-000000000000',
'aaaaaaaa-0002-0002-0002-000000000002',
'terapeuta@agenciapsi.com.br',
crypt('Teste@123', gen_salt('bf')),
now(), now(), now(),
'{"name": "Bruno Terapeuta"}'::jsonb,
'{"provider": "email", "providers": ["email"]}'::jsonb,
'authenticated', 'authenticated', false, false, '', '', '', '', ''
),
-- Clínica 1 — Coworking
(
'00000000-0000-0000-0000-000000000000',
'aaaaaaaa-0003-0003-0003-000000000003',
'clinica1@agenciapsi.com.br',
crypt('Teste@123', gen_salt('bf')),
now(), now(), now(),
'{"name": "Clínica Espaço Psi"}'::jsonb,
'{"provider": "email", "providers": ["email"]}'::jsonb,
'authenticated', 'authenticated', false, false, '', '', '', '', ''
),
-- Clínica 2 — Recepção
(
'00000000-0000-0000-0000-000000000000',
'aaaaaaaa-0004-0004-0004-000000000004',
'clinica2@agenciapsi.com.br',
crypt('Teste@123', gen_salt('bf')),
now(), now(), now(),
'{"name": "Clínica Mente sã"}'::jsonb,
'{"provider": "email", "providers": ["email"]}'::jsonb,
'authenticated', 'authenticated', false, false, '', '', '', '', ''
),
-- Clínica 3 — Full
(
'00000000-0000-0000-0000-000000000000',
'aaaaaaaa-0005-0005-0005-000000000005',
'clinica3@agenciapsi.com.br',
crypt('Teste@123', gen_salt('bf')),
now(), now(), now(),
'{"name": "Clínica Bem Estar"}'::jsonb,
'{"provider": "email", "providers": ["email"]}'::jsonb,
'authenticated', 'authenticated', false, false, '', '', '', '', ''
),
-- SaaS Admin
(
'00000000-0000-0000-0000-000000000000',
'aaaaaaaa-0006-0006-0006-000000000006',
'saas@agenciapsi.com.br',
crypt('Teste@123', gen_salt('bf')),
now(), now(), now(),
'{"name": "Admin Plataforma"}'::jsonb,
'{"provider": "email", "providers": ["email"]}'::jsonb,
'authenticated', 'authenticated', false, false, '', '', '', '', ''
);
-- auth.identities (obrigatório para GoTrue reconhecer login email/senha)
INSERT INTO auth.identities (id, user_id, provider_id, provider, identity_data, created_at, updated_at, last_sign_in_at)
VALUES
(gen_random_uuid(), 'aaaaaaaa-0001-0001-0001-000000000001', 'paciente@agenciapsi.com.br', 'email', '{"sub": "aaaaaaaa-0001-0001-0001-000000000001", "email": "paciente@agenciapsi.com.br", "email_verified": true}'::jsonb, now(), now(), now()),
(gen_random_uuid(), 'aaaaaaaa-0002-0002-0002-000000000002', 'terapeuta@agenciapsi.com.br', 'email', '{"sub": "aaaaaaaa-0002-0002-0002-000000000002", "email": "terapeuta@agenciapsi.com.br", "email_verified": true}'::jsonb, now(), now(), now()),
(gen_random_uuid(), 'aaaaaaaa-0003-0003-0003-000000000003', 'clinica1@agenciapsi.com.br', 'email', '{"sub": "aaaaaaaa-0003-0003-0003-000000000003", "email": "clinica1@agenciapsi.com.br", "email_verified": true}'::jsonb, now(), now(), now()),
(gen_random_uuid(), 'aaaaaaaa-0004-0004-0004-000000000004', 'clinica2@agenciapsi.com.br', 'email', '{"sub": "aaaaaaaa-0004-0004-0004-000000000004", "email": "clinica2@agenciapsi.com.br", "email_verified": true}'::jsonb, now(), now(), now()),
(gen_random_uuid(), 'aaaaaaaa-0005-0005-0005-000000000005', 'clinica3@agenciapsi.com.br', 'email', '{"sub": "aaaaaaaa-0005-0005-0005-000000000005", "email": "clinica3@agenciapsi.com.br", "email_verified": true}'::jsonb, now(), now(), now()),
(gen_random_uuid(), 'aaaaaaaa-0006-0006-0006-000000000006', 'saas@agenciapsi.com.br', 'email', '{"sub": "aaaaaaaa-0006-0006-0006-000000000006", "email": "saas@agenciapsi.com.br", "email_verified": true}'::jsonb, now(), now(), now())
ON CONFLICT (provider, provider_id) DO NOTHING;
-- ============================================================
-- 2. Profiles
-- ============================================================
INSERT INTO public.profiles (id, role, account_type, full_name)
VALUES
('aaaaaaaa-0001-0001-0001-000000000001', 'portal_user', 'patient', 'Ana Paciente'),
('aaaaaaaa-0002-0002-0002-000000000002', 'tenant_member', 'therapist', 'Bruno Terapeuta'),
('aaaaaaaa-0003-0003-0003-000000000003', 'tenant_member', 'clinic', 'Clínica Espaço Psi'),
('aaaaaaaa-0004-0004-0004-000000000004', 'tenant_member', 'clinic', 'Clínica Mente sã'),
('aaaaaaaa-0005-0005-0005-000000000005', 'tenant_member', 'clinic', 'Clínica Bem Estar'),
('aaaaaaaa-0006-0006-0006-000000000006', 'saas_admin', 'free', 'Admin Plataforma')
ON CONFLICT (id) DO UPDATE SET
role = EXCLUDED.role,
account_type = EXCLUDED.account_type,
full_name = EXCLUDED.full_name;
-- ============================================================
-- 3. SaaS Admin na tabela saas_admins
-- ============================================================
INSERT INTO public.saas_admins (user_id, created_at)
VALUES ('aaaaaaaa-0006-0006-0006-000000000006', now())
ON CONFLICT (user_id) DO NOTHING;
-- ============================================================
-- 4. Tenant do terapeuta
-- ============================================================
INSERT INTO public.tenants (id, name, kind, created_at)
VALUES ('bbbbbbbb-0002-0002-0002-000000000002', 'Bruno Terapeuta', 'therapist', now())
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at)
VALUES ('bbbbbbbb-0002-0002-0002-000000000002', 'aaaaaaaa-0002-0002-0002-000000000002', 'tenant_admin', 'active', now())
ON CONFLICT (tenant_id, user_id) DO NOTHING;
DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0002-0002-0002-000000000002'); END $$;
-- ============================================================
-- 5. Tenant da Clínica 1 — Coworking
-- ============================================================
INSERT INTO public.tenants (id, name, kind, created_at)
VALUES ('bbbbbbbb-0003-0003-0003-000000000003', 'Clínica Espaço Psi', 'clinic_coworking', now())
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at)
VALUES ('bbbbbbbb-0003-0003-0003-000000000003', 'aaaaaaaa-0003-0003-0003-000000000003', 'tenant_admin', 'active', now())
ON CONFLICT (tenant_id, user_id) DO NOTHING;
DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0003-0003-0003-000000000003'); END $$;
-- ============================================================
-- 6. Tenant da Clínica 2 — Recepção
-- ============================================================
INSERT INTO public.tenants (id, name, kind, created_at)
VALUES ('bbbbbbbb-0004-0004-0004-000000000004', 'Clínica Mente sã', 'clinic_reception', now())
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at)
VALUES ('bbbbbbbb-0004-0004-0004-000000000004', 'aaaaaaaa-0004-0004-0004-000000000004', 'tenant_admin', 'active', now())
ON CONFLICT (tenant_id, user_id) DO NOTHING;
DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0004-0004-0004-000000000004'); END $$;
-- ============================================================
-- 7. Tenant da Clínica 3 — Full
-- ============================================================
INSERT INTO public.tenants (id, name, kind, created_at)
VALUES ('bbbbbbbb-0005-0005-0005-000000000005', 'Clínica Bem Estar', 'clinic_full', now())
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at)
VALUES ('bbbbbbbb-0005-0005-0005-000000000005', 'aaaaaaaa-0005-0005-0005-000000000005', 'tenant_admin', 'active', now())
ON CONFLICT (tenant_id, user_id) DO NOTHING;
DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0005-0005-0005-000000000005'); END $$;
-- ============================================================
-- 8. Subscriptions ativas para cada conta
-- ============================================================
-- Terapeuta → plano therapist_free
INSERT INTO public.subscriptions (
user_id, plan_id, plan_key, status, interval,
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'aaaaaaaa-0002-0002-0002-000000000002',
p.id, p.key, 'active', 'month',
now(), now() + interval '30 days',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'therapist_free';
-- Clínica 1 → plano clinic_free
INSERT INTO public.subscriptions (
tenant_id, plan_id, plan_key, status, interval,
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'bbbbbbbb-0003-0003-0003-000000000003',
p.id, p.key, 'active', 'month',
now(), now() + interval '30 days',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'clinic_free';
-- Clínica 2 → plano clinic_free
INSERT INTO public.subscriptions (
tenant_id, plan_id, plan_key, status, interval,
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'bbbbbbbb-0004-0004-0004-000000000004',
p.id, p.key, 'active', 'month',
now(), now() + interval '30 days',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'clinic_free';
-- Clínica 3 → plano clinic_free
INSERT INTO public.subscriptions (
tenant_id, plan_id, plan_key, status, interval,
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'bbbbbbbb-0005-0005-0005-000000000005',
p.id, p.key, 'active', 'month',
now(), now() + interval '30 days',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'clinic_free';
-- Paciente → plano patient_free
INSERT INTO public.subscriptions (
user_id, plan_id, plan_key, status, interval,
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'aaaaaaaa-0001-0001-0001-000000000001',
p.id, p.key, 'active', 'month',
now(), now() + interval '30 days',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'patient_free';
-- ============================================================
-- 9. Vincula terapeuta à Clínica 3 (full) como exemplo
-- ============================================================
INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at)
VALUES (
'bbbbbbbb-0005-0005-0005-000000000005',
'aaaaaaaa-0002-0002-0002-000000000002',
'therapist',
'active',
now()
)
ON CONFLICT (tenant_id, user_id) DO NOTHING;
-- ============================================================
-- 10. Confirma
-- ============================================================
DO $$
BEGIN
RAISE NOTICE '✅ Seed aplicado com sucesso.';
RAISE NOTICE '';
RAISE NOTICE ' Usuários criados:';
RAISE NOTICE ' paciente@agenciapsi.com.br → patient';
RAISE NOTICE ' terapeuta@agenciapsi.com.br → therapist (tenant próprio + vinculado à Clínica 3)';
RAISE NOTICE ' clinica1@agenciapsi.com.br → clinic_coworking';
RAISE NOTICE ' clinica2@agenciapsi.com.br → clinic_reception';
RAISE NOTICE ' clinica3@agenciapsi.com.br → clinic_full';
RAISE NOTICE ' saas@agenciapsi.com.br → saas_admin';
RAISE NOTICE ' Senha de todos: Teste@123';
END;
$$;
COMMIT;

View File

@@ -0,0 +1,199 @@
-- =============================================================================
-- SEED 002 — Supervisor e Editor
-- =============================================================================
-- Execute APÓS seed_001.sql
-- Requer: pgcrypto (já ativo no Supabase)
--
-- Cria os seguintes usuários de teste:
--
-- supervisor@agenciapsi.com.br senha: Teste@123 → supervisor da Clínica 3
-- editor@agenciapsi.com.br senha: Teste@123 → editor de conteúdo (plataforma)
--
-- UUIDs reservados:
-- Supervisor → aaaaaaaa-0007-0007-0007-000000000007
-- Editor → aaaaaaaa-0008-0008-0008-000000000008
--
-- =============================================================================
BEGIN;
-- ============================================================
-- 0. Migration: adiciona platform_roles em profiles (se não existir)
-- ============================================================
ALTER TABLE public.profiles
ADD COLUMN IF NOT EXISTS platform_roles text[] NOT NULL DEFAULT '{}';
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.';
-- ============================================================
-- 1. Remove seeds anteriores (idempotente)
-- ============================================================
DELETE FROM auth.users
WHERE email IN (
'supervisor@agenciapsi.com.br',
'editor@agenciapsi.com.br'
);
-- ============================================================
-- 2. Cria usuários no auth.users
-- ============================================================
INSERT INTO auth.users (
instance_id,
id,
email,
encrypted_password,
email_confirmed_at,
created_at,
updated_at,
raw_user_meta_data,
raw_app_meta_data,
role,
aud,
is_sso_user,
is_anonymous,
confirmation_token,
recovery_token,
email_change_token_new,
email_change_token_current,
email_change
)
VALUES
-- Supervisor
(
'00000000-0000-0000-0000-000000000000',
'aaaaaaaa-0007-0007-0007-000000000007',
'supervisor@agenciapsi.com.br',
crypt('Teste@123', gen_salt('bf')),
now(), now(), now(),
'{"name": "Carlos Supervisor"}'::jsonb,
'{"provider": "email", "providers": ["email"]}'::jsonb,
'authenticated', 'authenticated', false, false, '', '', '', '', ''
),
-- Editor de Conteúdo
(
'00000000-0000-0000-0000-000000000000',
'aaaaaaaa-0008-0008-0008-000000000008',
'editor@agenciapsi.com.br',
crypt('Teste@123', gen_salt('bf')),
now(), now(), now(),
'{"name": "Diana Editora"}'::jsonb,
'{"provider": "email", "providers": ["email"]}'::jsonb,
'authenticated', 'authenticated', false, false, '', '', '', '', ''
);
-- ============================================================
-- 3. auth.identities (obrigatório para GoTrue reconhecer login)
-- ============================================================
INSERT INTO auth.identities (id, user_id, provider_id, provider, identity_data, created_at, updated_at, last_sign_in_at)
VALUES
(
gen_random_uuid(),
'aaaaaaaa-0007-0007-0007-000000000007',
'supervisor@agenciapsi.com.br',
'email',
'{"sub": "aaaaaaaa-0007-0007-0007-000000000007", "email": "supervisor@agenciapsi.com.br", "email_verified": true}'::jsonb,
now(), now(), now()
),
(
gen_random_uuid(),
'aaaaaaaa-0008-0008-0008-000000000008',
'editor@agenciapsi.com.br',
'email',
'{"sub": "aaaaaaaa-0008-0008-0008-000000000008", "email": "editor@agenciapsi.com.br", "email_verified": true}'::jsonb,
now(), now(), now()
)
ON CONFLICT (provider, provider_id) DO NOTHING;
-- ============================================================
-- 4. Profiles
-- Supervisor → tenant_member (papel no tenant via tenant_members.role)
-- Editor → tenant_member + platform_roles = '{editor}'
-- ============================================================
INSERT INTO public.profiles (id, role, account_type, full_name, platform_roles)
VALUES
(
'aaaaaaaa-0007-0007-0007-000000000007',
'tenant_member',
'therapist',
'Carlos Supervisor',
'{}'
),
(
'aaaaaaaa-0008-0008-0008-000000000008',
'tenant_member',
'therapist',
'Diana Editora',
'{editor}' -- permissão de plataforma: acesso à área do editor
)
ON CONFLICT (id) DO UPDATE SET
role = EXCLUDED.role,
account_type = EXCLUDED.account_type,
full_name = EXCLUDED.full_name,
platform_roles = EXCLUDED.platform_roles;
-- ============================================================
-- 5. Vincula Supervisor à Clínica 3 (Full) com role 'supervisor'
-- ============================================================
INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at)
VALUES (
'bbbbbbbb-0005-0005-0005-000000000005', -- Clínica Bem Estar (Full)
'aaaaaaaa-0007-0007-0007-000000000007', -- Carlos Supervisor
'supervisor',
'active',
now()
)
ON CONFLICT (tenant_id, user_id) DO UPDATE SET
role = EXCLUDED.role,
status = EXCLUDED.status;
-- ============================================================
-- 6. Vincula Editor à Clínica 3 como terapeuta
-- (contexto de tenant para o editor poder usar /therapist também,
-- se necessário. O papel de editor vem de platform_roles.)
-- ============================================================
INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at)
VALUES (
'bbbbbbbb-0005-0005-0005-000000000005', -- Clínica Bem Estar (Full)
'aaaaaaaa-0008-0008-0008-000000000008', -- Diana Editora
'therapist',
'active',
now()
)
ON CONFLICT (tenant_id, user_id) DO UPDATE SET
role = EXCLUDED.role,
status = EXCLUDED.status;
-- ============================================================
-- 7. Confirma
-- ============================================================
DO $$
BEGIN
RAISE NOTICE '✅ Seed 002 aplicado com sucesso.';
RAISE NOTICE '';
RAISE NOTICE ' Migration aplicada:';
RAISE NOTICE ' → profiles.platform_roles text[] adicionada (se não existia)';
RAISE NOTICE '';
RAISE NOTICE ' Usuários criados:';
RAISE NOTICE ' supervisor@agenciapsi.com.br → supervisor da Clínica Bem Estar (Full)';
RAISE NOTICE ' editor@agenciapsi.com.br → editor de conteúdo (platform_roles = {editor})';
RAISE NOTICE ' Senha de todos: Teste@123';
END;
$$;
COMMIT;

View File

@@ -0,0 +1,283 @@
-- =============================================================================
-- SEED 003 — Terapeuta 2, Terapeuta 3 e Secretária
-- =============================================================================
-- Execute APÓS seed_001.sql (e seed_002.sql se quiser todos os seeds)
-- Requer: pgcrypto (já ativo no Supabase)
--
-- Cria os seguintes usuários de teste:
--
-- therapist2@agenciapsi.com.br senha: Teste@123 → terapeuta 2 (tenant próprio + Clínica 3)
-- therapist3@agenciapsi.com.br senha: Teste@123 → terapeuta 3 (tenant próprio + Clínica 3)
-- secretary@agenciapsi.com.br senha: Teste@123 → clinic_admin na Clínica 2 (Mente sã)
--
-- UUIDs reservados:
-- Terapeuta 2 → aaaaaaaa-0009-0009-0009-000000000009
-- Terapeuta 3 → aaaaaaaa-0010-0010-0010-000000000010
-- Secretária → aaaaaaaa-0011-0011-0011-000000000011
-- Tenant Terapeuta 2 → bbbbbbbb-0009-0009-0009-000000000009
-- Tenant Terapeuta 3 → bbbbbbbb-0010-0010-0010-000000000010
-- =============================================================================
BEGIN;
-- ============================================================
-- 1. Remove seeds anteriores (idempotente)
-- ============================================================
DELETE FROM auth.users
WHERE email IN (
'therapist2@agenciapsi.com.br',
'therapist3@agenciapsi.com.br',
'secretary@agenciapsi.com.br'
);
-- ============================================================
-- 2. Cria usuários no auth.users
-- ⚠️ confirmed_at é coluna gerada — NÃO incluir na lista
-- ============================================================
INSERT INTO auth.users (
instance_id,
id,
email,
encrypted_password,
email_confirmed_at,
created_at,
updated_at,
raw_user_meta_data,
raw_app_meta_data,
role,
aud,
is_sso_user,
is_anonymous,
confirmation_token,
recovery_token,
email_change_token_new,
email_change_token_current,
email_change
)
VALUES
-- Terapeuta 2
(
'00000000-0000-0000-0000-000000000000',
'aaaaaaaa-0009-0009-0009-000000000009',
'therapist2@agenciapsi.com.br',
crypt('Teste@123', gen_salt('bf')),
now(), now(), now(),
'{"name": "Eva Terapeuta"}'::jsonb,
'{"provider": "email", "providers": ["email"]}'::jsonb,
'authenticated', 'authenticated', false, false, '', '', '', '', ''
),
-- Terapeuta 3
(
'00000000-0000-0000-0000-000000000000',
'aaaaaaaa-0010-0010-0010-000000000010',
'therapist3@agenciapsi.com.br',
crypt('Teste@123', gen_salt('bf')),
now(), now(), now(),
'{"name": "Felipe Terapeuta"}'::jsonb,
'{"provider": "email", "providers": ["email"]}'::jsonb,
'authenticated', 'authenticated', false, false, '', '', '', '', ''
),
-- Secretária
(
'00000000-0000-0000-0000-000000000000',
'aaaaaaaa-0011-0011-0011-000000000011',
'secretary@agenciapsi.com.br',
crypt('Teste@123', gen_salt('bf')),
now(), now(), now(),
'{"name": "Gabriela Secretária"}'::jsonb,
'{"provider": "email", "providers": ["email"]}'::jsonb,
'authenticated', 'authenticated', false, false, '', '', '', '', ''
);
-- ============================================================
-- 3. auth.identities (obrigatório para GoTrue reconhecer login)
-- ============================================================
INSERT INTO auth.identities (id, user_id, provider_id, provider, identity_data, created_at, updated_at, last_sign_in_at)
VALUES
(
gen_random_uuid(),
'aaaaaaaa-0009-0009-0009-000000000009',
'therapist2@agenciapsi.com.br',
'email',
'{"sub": "aaaaaaaa-0009-0009-0009-000000000009", "email": "therapist2@agenciapsi.com.br", "email_verified": true}'::jsonb,
now(), now(), now()
),
(
gen_random_uuid(),
'aaaaaaaa-0010-0010-0010-000000000010',
'therapist3@agenciapsi.com.br',
'email',
'{"sub": "aaaaaaaa-0010-0010-0010-000000000010", "email": "therapist3@agenciapsi.com.br", "email_verified": true}'::jsonb,
now(), now(), now()
),
(
gen_random_uuid(),
'aaaaaaaa-0011-0011-0011-000000000011',
'secretary@agenciapsi.com.br',
'email',
'{"sub": "aaaaaaaa-0011-0011-0011-000000000011", "email": "secretary@agenciapsi.com.br", "email_verified": true}'::jsonb,
now(), now(), now()
)
ON CONFLICT (provider, provider_id) DO NOTHING;
-- ============================================================
-- 4. Profiles
-- ============================================================
INSERT INTO public.profiles (id, role, account_type, full_name)
VALUES
(
'aaaaaaaa-0009-0009-0009-000000000009',
'tenant_member',
'therapist',
'Eva Terapeuta'
),
(
'aaaaaaaa-0010-0010-0010-000000000010',
'tenant_member',
'therapist',
'Felipe Terapeuta'
),
(
'aaaaaaaa-0011-0011-0011-000000000011',
'tenant_member',
'therapist',
'Gabriela Secretária'
)
ON CONFLICT (id) DO UPDATE SET
role = EXCLUDED.role,
account_type = EXCLUDED.account_type,
full_name = EXCLUDED.full_name;
-- ============================================================
-- 5. Tenants pessoais dos Terapeutas 2 e 3
-- ============================================================
INSERT INTO public.tenants (id, name, kind, created_at)
VALUES
('bbbbbbbb-0009-0009-0009-000000000009', 'Eva Terapeuta', 'therapist', now()),
('bbbbbbbb-0010-0010-0010-000000000010', 'Felipe Terapeuta', 'therapist', now())
ON CONFLICT (id) DO NOTHING;
-- Terapeuta 2 → tenant_admin do próprio tenant
INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at)
VALUES (
'bbbbbbbb-0009-0009-0009-000000000009',
'aaaaaaaa-0009-0009-0009-000000000009',
'tenant_admin', 'active', now()
)
ON CONFLICT (tenant_id, user_id) DO NOTHING;
-- Terapeuta 3 → tenant_admin do próprio tenant
INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at)
VALUES (
'bbbbbbbb-0010-0010-0010-000000000010',
'aaaaaaaa-0010-0010-0010-000000000010',
'tenant_admin', 'active', now()
)
ON CONFLICT (tenant_id, user_id) DO NOTHING;
-- ============================================================
-- 6. Vincula Terapeutas 2 e 3 à Clínica 3 — Full
-- (mesmo padrão de terapeuta@agenciapsi.com.br no seed_001)
-- ============================================================
INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at)
VALUES
(
'bbbbbbbb-0005-0005-0005-000000000005', -- Clínica Bem Estar (Full)
'aaaaaaaa-0009-0009-0009-000000000009', -- Eva Terapeuta
'therapist', 'active', now()
),
(
'bbbbbbbb-0005-0005-0005-000000000005', -- Clínica Bem Estar (Full)
'aaaaaaaa-0010-0010-0010-000000000010', -- Felipe Terapeuta
'therapist', 'active', now()
)
ON CONFLICT (tenant_id, user_id) DO NOTHING;
-- ============================================================
-- 7. Vincula Secretária à Clínica 2 (Recepção) como clinic_admin
-- A secretária gerencia a recepção/agenda da clínica.
-- Acessa a área /admin com o mesmo contexto de clinic_admin.
-- ============================================================
INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at)
VALUES (
'bbbbbbbb-0004-0004-0004-000000000004', -- Clínica Mente sã (Recepção)
'aaaaaaaa-0011-0011-0011-000000000011', -- Gabriela Secretária
'clinic_admin', 'active', now()
)
ON CONFLICT (tenant_id, user_id) DO NOTHING;
-- ============================================================
-- 8. Subscriptions
-- Terapeutas 2 e 3 → therapist_free (escopo: user_id)
-- Secretária → sem assinatura própria (usa o plano da Clínica 2)
-- ============================================================
-- Terapeuta 2 → therapist_free
INSERT INTO public.subscriptions (
user_id, plan_id, plan_key, status, interval,
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'aaaaaaaa-0009-0009-0009-000000000009',
p.id, p.key, 'active', 'month',
now(), now() + interval '30 days',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'therapist_free'
AND NOT EXISTS (
SELECT 1 FROM public.subscriptions s
WHERE s.user_id = 'aaaaaaaa-0009-0009-0009-000000000009' AND s.status = 'active'
);
-- Terapeuta 3 → therapist_free
INSERT INTO public.subscriptions (
user_id, plan_id, plan_key, status, interval,
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'aaaaaaaa-0010-0010-0010-000000000010',
p.id, p.key, 'active', 'month',
now(), now() + interval '30 days',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'therapist_free'
AND NOT EXISTS (
SELECT 1 FROM public.subscriptions s
WHERE s.user_id = 'aaaaaaaa-0010-0010-0010-000000000010' AND s.status = 'active'
);
-- Nota: a Secretária não tem assinatura própria.
-- O acesso vem do plano da Clínica 2 (tenant_id = bbbbbbbb-0004-0004-0004-000000000004).
-- ============================================================
-- 9. Confirma
-- ============================================================
DO $$
BEGIN
RAISE NOTICE '✅ Seed 003 aplicado com sucesso.';
RAISE NOTICE '';
RAISE NOTICE ' Usuários criados:';
RAISE NOTICE ' therapist2@agenciapsi.com.br → tenant próprio (bbbbbbbb-0009) + Clínica 3 como therapist';
RAISE NOTICE ' therapist3@agenciapsi.com.br → tenant próprio (bbbbbbbb-0010) + Clínica 3 como therapist';
RAISE NOTICE ' secretary@agenciapsi.com.br → clinic_admin na Clínica 2 Mente sã (bbbbbbbb-0004)';
RAISE NOTICE ' Senha de todos: Teste@123';
END;
$$;
COMMIT;

View File

@@ -0,0 +1,74 @@
-- =============================================================================
-- SEED 010 — Planos e Preços
-- =============================================================================
-- Idempotente: ON CONFLICT (id) DO UPDATE
--
-- Planos:
-- patient_free → pacientes (R$0)
-- therapist_free → terapeutas solo (R$0)
-- therapist_pro → terapeutas PRO (R$49/mês, R$490/ano)
-- clinic_free → clínicas (R$0)
-- clinic_pro → clínicas PRO (R$149/mês, R$1490/ano)
-- supervisor_free → supervisores (R$0, até 3 supervisionados)
-- supervisor_pro → supervisores PRO (R$0, até 20 supervisionados)
--
-- UUIDs preservados do data_dump original para consistência.
-- =============================================================================
BEGIN;
-- ============================================================
-- 1. Plans
-- ============================================================
INSERT INTO public.plans (id, key, name, description, is_active, created_at, price_cents, currency, billing_interval, target, max_supervisees)
VALUES
('984c1f29-a975-4208-93ac-2118ed1039b7', 'patient_free', 'Paciente Free', 'Plano gratuito para pacientes', true, '2026-03-03 22:40:11.413107+00', 0, 'BRL', 'month', 'patient', NULL),
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'therapist_free', 'THERAPIST FREE', 'Plano gratuito para terapeutas.', true, '2026-03-01 09:40:48.439668+00', 0, 'BRL', 'month', 'therapist', NULL),
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'therapist_pro', 'THERAPIST PRO', 'Plano completo para terapeutas.', true, '2026-03-01 09:25:03.878498+00', 4900, 'BRL', 'month', 'therapist', NULL),
('01a5867f-0705-4714-ac97-a23470949157', 'clinic_free', 'CLINIC FREE', 'Plano gratuito para clínicas iniciarem.', true, '2026-03-01 09:25:03.878498+00', 0, 'BRL', 'month', 'clinic', NULL),
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'clinic_pro', 'CLINIC PRO', 'Plano completo para clínicas.', true, '2026-03-01 09:30:06.50975+00', 14900, 'BRL', 'month', 'clinic', NULL),
('8c4895a3-e12d-48de-a078-efb8a4ea2eb2', 'supervisor_free', 'Supervisor Free', 'Plano gratuito de supervisão. Até 3 terapeutas supervisionados.', true, '2026-03-05 00:58:17.218326+00', 0, 'BRL', 'month', 'supervisor', 3),
('ca28e46c-0687-45d5-9406-0a0f56a5b625', 'supervisor_pro', 'Supervisor PRO', 'Plano profissional de supervisão. Até 20 terapeutas supervisionados.', true, '2026-03-05 00:58:17.218326+00', 0, 'BRL', 'month', 'supervisor', 20)
ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name,
description = EXCLUDED.description,
is_active = EXCLUDED.is_active,
price_cents = EXCLUDED.price_cents,
currency = EXCLUDED.currency,
billing_interval = EXCLUDED.billing_interval,
max_supervisees = EXCLUDED.max_supervisees;
-- ============================================================
-- 2. Plan Prices (somente planos pagos)
-- ============================================================
INSERT INTO public.plan_prices (id, plan_id, currency, "interval", amount_cents, is_active, active_from, active_to, source, provider, provider_price_id, created_at)
VALUES
-- therapist_pro: R$49/mês
('37510504-4617-4421-9979-4249778bd5ae', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'BRL', 'month', 4900, true, '2026-03-01 09:25:03.878498+00', NULL, 'manual', NULL, NULL, '2026-03-01 09:25:03.878498+00'),
-- therapist_pro: R$490/ano
('225afd5a-9f30-46bc-a0df-5eb8f91660cb', '82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'BRL', 'year', 49000, true, '2026-03-01 09:25:03.878498+00', NULL, 'manual', NULL, NULL, '2026-03-01 09:25:03.878498+00'),
-- clinic_pro: R$149/mês
('124779b4-362d-4890-9631-747021ecc1c0', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'BRL', 'month', 14900, true, '2026-03-01 09:30:06.50975+00', NULL, 'manual', NULL, NULL, '2026-03-01 09:30:06.50975+00'),
-- clinic_pro: R$1490/ano
('73908784-6299-45c8-b547-e1556b45c292', 'a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'BRL', 'year', 149000, true, '2026-03-01 09:30:06.50975+00', NULL, 'manual', NULL, NULL, '2026-03-01 09:30:06.50975+00')
ON CONFLICT (id) DO UPDATE SET
amount_cents = EXCLUDED.amount_cents,
is_active = EXCLUDED.is_active,
active_from = EXCLUDED.active_from,
active_to = EXCLUDED.active_to;
-- ============================================================
-- 3. Confirma
-- ============================================================
DO $$
BEGIN
RAISE NOTICE 'seed_010_plans: 7 planos e 4 preços inseridos/atualizados.';
END;
$$;
COMMIT;

View File

@@ -0,0 +1,78 @@
-- =============================================================================
-- SEED 011 — Features (capacidades do sistema)
-- =============================================================================
-- Idempotente: ON CONFLICT (id) DO UPDATE
-- UUIDs preservados do data_dump original.
--
-- 26 features organizadas por domínio:
-- agenda.* → visualizar, gerenciar agenda
-- patients.* → módulo de pacientes
-- online_scheduling.* → agendamento online
-- supervisor.* → supervisão clínica
-- reports / reminders → relatórios e lembretes
-- clinic / branding → funcionalidades de clínica
-- intake → triagem / cadastro externo
-- =============================================================================
BEGIN;
INSERT INTO public.features (id, key, description, created_at, descricao, name)
VALUES
-- ── Agenda ──
('5e539124-630f-4c2a-a9de-7999317085e6', 'agenda.view', NULL, '2026-02-21 02:36:01.562728+00', 'Visualizar agenda', 'Visualizar Agenda'),
('a74fef14-c9d9-4884-ba45-f81c60e0783a', 'agenda.manage', NULL, '2026-02-21 02:35:50.629667+00', 'Adicionar Compromissos na agenda', 'Gerenciar Agenda'),
-- ── Pacientes ──
('a56482a1-0787-49da-90a7-e1857488734a', 'patients', 'Patients module', '2026-03-02 12:35:19.955748+00', 'Pacientes', 'Pacientes'),
('57f631a1-9ebe-480b-a2cb-144ad32ff5f0', 'patients.view', NULL, '2026-02-28 11:15:14.275572+00', 'Visualizar pacientes', 'Visualizar Pacientes'),
('4e5bc50b-e339-42fe-9d91-61e8555f83e7', 'patients.manage', NULL, '2026-02-28 11:15:14.275572+00', 'Gerenciar pacientes', 'Gerenciar Pacientes'),
-- ── Agendamento Online ──
('53a48c3b-0617-4618-adf8-f3a255c51ee4', 'online_scheduling', 'Online scheduling capability', '2026-03-01 09:59:15.432733+00', 'Agendamento online', 'Agendamento Online (Público)'),
('5739aa27-b089-4b15-b149-31b13d768825', 'online_scheduling.manage', 'Gerenciar agendamento online (config/admin)', '2026-02-15 21:50:02.056357+00', 'Gerenciar agendamento online (admin)', 'Agendamento Online'),
('0bfe0b1c-8c3d-4c0c-af29-2ddc24f31bc7', 'online_scheduling.public', 'Página pública de agendamento', '2026-02-15 21:50:02.056357+00', 'Página pública de agendamento', 'Página Pública de Agendamento'),
-- ── Supervisão ──
('9ab8bdbb-838b-4946-aa5d-fd9cfdd257b3', 'supervisor.access', NULL, '2026-03-05 00:58:17.218326+00', 'Acesso básico ao espaço de supervisão (sala, lista de supervisionados).', 'Acesso à Supervisão'),
('1167b54a-0e93-43a2-94d7-c12e64eb56de', 'supervisor.invite', NULL, '2026-03-05 00:58:17.218326+00', 'Permite convidar terapeutas para participar da sala de supervisão.', 'Convidar Supervisionados'),
('761e4495-b46a-4791-9519-86ffe48dc47f', 'supervisor.sessions', NULL, '2026-03-05 00:58:17.218326+00', 'Agendamento e registro de sessões de supervisão.', 'Sessões de Supervisão'),
('7e82ee01-44f6-4b3f-9861-840c58e13f58', 'supervisor.reports', NULL, '2026-03-05 00:58:17.218326+00', 'Relatórios avançados de progresso e evolução dos supervisionados.', 'Relatórios de Supervisão'),
-- ── Relatórios ──
('b3efa25d-60a4-4974-8153-6ec098b3d477', 'reports_basic', 'Basic reports', '2026-03-01 09:59:15.432733+00', 'Relatórios básicos', 'Relatórios Básicos'),
('bf133ad1-da8e-4ea9-bd66-21901cb50075', 'reports_advanced', 'Advanced reports', '2026-03-01 09:59:15.432733+00', 'Relatórios avançados', 'Relatórios Avançados (v2)'),
('a830e45b-3bb4-4b17-812d-fe83777a2377', 'advanced_reports', 'Relatórios avançados (KPIs, filtros e exportações)', '2026-02-15 23:29:55.845638+00', 'Relatórios avançados', 'Relatórios Avançados'),
-- ── Lembretes ──
('f5d66212-fd73-4472-a306-07928e5deaec', 'reminders', 'Notifications/reminders capability', '2026-03-01 09:59:15.432733+00', 'Lembretes', 'Lembretes'),
('8cc81988-d02a-4542-9cb2-ce2ed7c18d60', 'sms_reminder', 'Lembretes por SMS (confirmações e avisos)', '2026-02-15 23:29:55.845638+00', 'Lembretes por SMS', 'Lembretes por SMS'),
-- ── Clínica ──
('9b36c65d-b3b3-4bed-b6d5-f7ee8c087c80', 'clinic_calendar', 'Clinic calendar / admin view', '2026-03-01 09:59:15.432733+00', 'Agenda da clínica', 'Agenda da Clínica'),
('336aeeba-b18e-4e68-8303-d42ba09f4b20', 'secretary', 'Secretary features (clinic)', '2026-03-01 09:59:15.432733+00', 'Secretaria', 'Secretaria'),
('30c9cdd5-7c8c-44d9-8c0b-614165bb9496', 'shared_reception', 'Shared reception / secretary', '2026-03-02 12:35:19.955748+00', 'Recepção / Secretária', 'Recepção Compartilhada'),
('74fc1321-4d17-49c3-b72e-db3a7f4be451', 'rooms', 'Rooms / coworking', '2026-03-02 12:35:19.955748+00', 'Salas / Coworking', 'Salas / Coworking'),
-- ── Intake / Cadastro externo ──
('c109ad27-0edf-4774-91a7-94dac4faab49', 'intake_public', 'Public intake link', '2026-03-02 12:35:19.955748+00', 'Link externo de cadastro', 'Link Externo de Cadastro'),
('90e92108-8124-40ee-88a0-f0ecafb57d76', 'intakes_pro', 'Cadastros/Intakes PRO (fluxos avançados e automações)', '2026-02-15 23:29:55.845638+00', 'Formulários PRO', 'Formulários PRO'),
-- ── Branding / API / Auditoria ──
('f393178c-284d-422f-b096-8793f85428d5', 'custom_branding', 'Custom branding', '2026-03-01 09:59:15.432733+00', 'Personalização de marca', 'Marca Personalizada'),
('d6f54674-ea8b-484b-af0e-99127a510da2', 'api_access', 'API/Integrations access', '2026-03-01 09:59:15.432733+00', 'Integrações/API', 'Acesso à API'),
('a5593d96-dd95-46bb-bef0-bd379b56ad50', 'audit_log', 'Audit log capability', '2026-03-01 09:59:15.432733+00', 'Auditoria', 'Log de Auditoria')
ON CONFLICT (id) DO UPDATE SET
key = EXCLUDED.key,
description = EXCLUDED.description,
descricao = EXCLUDED.descricao,
name = EXCLUDED.name;
DO $$
BEGIN
RAISE NOTICE 'seed_011_features: 26 features inseridas/atualizadas.';
END;
$$;
COMMIT;

View File

@@ -0,0 +1,191 @@
-- =============================================================================
-- SEED 012 — Plan Features (vínculo plano ↔ feature com limites)
-- =============================================================================
-- Idempotente: ON CONFLICT (plan_id, feature_id) DO UPDATE
--
-- Legenda:
-- enabled=true → feature ativa no plano
-- enabled=false → feature aparece como "PRO" / upsell na UI
-- limits jsonb → limites quantitativos (sessions_per_month, etc.)
--
-- IMPORTANTE: therapist_free e clinic_free incluem features básicas
-- necessárias para o sistema funcionar (agenda, pacientes, etc.).
-- O data_dump de 11/03 estava incompleto para esses planos.
-- =============================================================================
BEGIN;
-- Limpa plan_features existentes para reinserir de forma limpa
DELETE FROM public.plan_features;
-- ════════════════════════════════════════════════════════════════
-- CLINIC PRO (a74bc2d4) — todas as features habilitadas
-- ════════════════════════════════════════════════════════════════
INSERT INTO public.plan_features (plan_id, feature_id, enabled, limits) VALUES
-- Agenda
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '5e539124-630f-4c2a-a9de-7999317085e6', true, NULL), -- agenda.view
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'a74fef14-c9d9-4884-ba45-f81c60e0783a', true, NULL), -- agenda.manage
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '9b36c65d-b3b3-4bed-b6d5-f7ee8c087c80', true, '{"max_patients": 9999, "max_therapists": 999}'), -- clinic_calendar
-- Pacientes
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'a56482a1-0787-49da-90a7-e1857488734a', true, NULL), -- patients
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '57f631a1-9ebe-480b-a2cb-144ad32ff5f0', true, NULL), -- patients.view
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '4e5bc50b-e339-42fe-9d91-61e8555f83e7', true, NULL), -- patients.manage
-- Agendamento online
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '53a48c3b-0617-4618-adf8-f3a255c51ee4', true, '{"sessions_per_month": 9999}'), -- online_scheduling
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '5739aa27-b089-4b15-b149-31b13d768825', true, NULL), -- online_scheduling.manage
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '0bfe0b1c-8c3d-4c0c-af29-2ddc24f31bc7', true, NULL), -- online_scheduling.public
-- Relatórios
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'b3efa25d-60a4-4974-8153-6ec098b3d477', true, NULL), -- reports_basic
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'bf133ad1-da8e-4ea9-bd66-21901cb50075', true, NULL), -- reports_advanced
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'a830e45b-3bb4-4b17-812d-fe83777a2377', true, NULL), -- advanced_reports
-- Lembretes
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'f5d66212-fd73-4472-a306-07928e5deaec', true, '{"reminders_per_month": 9999}'), -- reminders
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '8cc81988-d02a-4542-9cb2-ce2ed7c18d60', true, NULL), -- sms_reminder
-- Clínica
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '336aeeba-b18e-4e68-8303-d42ba09f4b20', true, NULL), -- secretary
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '30c9cdd5-7c8c-44d9-8c0b-614165bb9496', true, NULL), -- shared_reception
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '74fc1321-4d17-49c3-b72e-db3a7f4be451', true, NULL), -- rooms
-- Intake
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'c109ad27-0edf-4774-91a7-94dac4faab49', true, NULL), -- intake_public
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', '90e92108-8124-40ee-88a0-f0ecafb57d76', true, NULL), -- intakes_pro
-- PRO exclusivo
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'f393178c-284d-422f-b096-8793f85428d5', true, NULL), -- custom_branding
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'd6f54674-ea8b-484b-af0e-99127a510da2', true, NULL), -- api_access
('a74bc2d4-88c6-4cc6-b004-ef2bcb1b5145', 'a5593d96-dd95-46bb-bef0-bd379b56ad50', true, NULL); -- audit_log
-- ════════════════════════════════════════════════════════════════
-- CLINIC FREE (01a5867f) — features básicas para funcionar
-- ════════════════════════════════════════════════════════════════
INSERT INTO public.plan_features (plan_id, feature_id, enabled, limits) VALUES
-- Agenda
('01a5867f-0705-4714-ac97-a23470949157', '5e539124-630f-4c2a-a9de-7999317085e6', true, NULL), -- agenda.view
('01a5867f-0705-4714-ac97-a23470949157', 'a74fef14-c9d9-4884-ba45-f81c60e0783a', true, NULL), -- agenda.manage
('01a5867f-0705-4714-ac97-a23470949157', '9b36c65d-b3b3-4bed-b6d5-f7ee8c087c80', true, '{"max_patients": 30, "max_therapists": 5}'), -- clinic_calendar
-- Pacientes
('01a5867f-0705-4714-ac97-a23470949157', 'a56482a1-0787-49da-90a7-e1857488734a', true, NULL), -- patients
('01a5867f-0705-4714-ac97-a23470949157', '57f631a1-9ebe-480b-a2cb-144ad32ff5f0', true, NULL), -- patients.view
('01a5867f-0705-4714-ac97-a23470949157', '4e5bc50b-e339-42fe-9d91-61e8555f83e7', true, NULL), -- patients.manage
-- Agendamento online (com limites)
('01a5867f-0705-4714-ac97-a23470949157', '53a48c3b-0617-4618-adf8-f3a255c51ee4', true, '{"sessions_per_month": 40}'), -- online_scheduling
('01a5867f-0705-4714-ac97-a23470949157', '5739aa27-b089-4b15-b149-31b13d768825', true, NULL), -- online_scheduling.manage
('01a5867f-0705-4714-ac97-a23470949157', '0bfe0b1c-8c3d-4c0c-af29-2ddc24f31bc7', true, NULL), -- online_scheduling.public
-- Relatórios (básico sim, avançado não)
('01a5867f-0705-4714-ac97-a23470949157', 'b3efa25d-60a4-4974-8153-6ec098b3d477', true, NULL), -- reports_basic
('01a5867f-0705-4714-ac97-a23470949157', 'bf133ad1-da8e-4ea9-bd66-21901cb50075', false, NULL), -- reports_advanced (PRO)
('01a5867f-0705-4714-ac97-a23470949157', 'a830e45b-3bb4-4b17-812d-fe83777a2377', false, NULL), -- advanced_reports (PRO)
-- Lembretes (com limites)
('01a5867f-0705-4714-ac97-a23470949157', 'f5d66212-fd73-4472-a306-07928e5deaec', true, '{"reminders_per_month": 50}'), -- reminders
('01a5867f-0705-4714-ac97-a23470949157', '8cc81988-d02a-4542-9cb2-ce2ed7c18d60', false, NULL), -- sms_reminder (PRO)
-- Intake
('01a5867f-0705-4714-ac97-a23470949157', 'c109ad27-0edf-4774-91a7-94dac4faab49', true, NULL), -- intake_public
('01a5867f-0705-4714-ac97-a23470949157', '90e92108-8124-40ee-88a0-f0ecafb57d76', false, NULL), -- intakes_pro (PRO)
-- PRO-only (desabilitado)
('01a5867f-0705-4714-ac97-a23470949157', '336aeeba-b18e-4e68-8303-d42ba09f4b20', false, NULL), -- secretary (PRO)
('01a5867f-0705-4714-ac97-a23470949157', '30c9cdd5-7c8c-44d9-8c0b-614165bb9496', false, NULL), -- shared_reception (PRO)
('01a5867f-0705-4714-ac97-a23470949157', '74fc1321-4d17-49c3-b72e-db3a7f4be451', false, NULL), -- rooms (PRO)
('01a5867f-0705-4714-ac97-a23470949157', 'f393178c-284d-422f-b096-8793f85428d5', false, NULL), -- custom_branding (PRO)
('01a5867f-0705-4714-ac97-a23470949157', 'd6f54674-ea8b-484b-af0e-99127a510da2', false, NULL), -- api_access (PRO)
('01a5867f-0705-4714-ac97-a23470949157', 'a5593d96-dd95-46bb-bef0-bd379b56ad50', false, NULL); -- audit_log (PRO)
-- ════════════════════════════════════════════════════════════════
-- THERAPIST PRO (82067ba7) — todas as features habilitadas
-- ════════════════════════════════════════════════════════════════
INSERT INTO public.plan_features (plan_id, feature_id, enabled, limits) VALUES
-- Agenda
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', '5e539124-630f-4c2a-a9de-7999317085e6', true, NULL), -- agenda.view
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'a74fef14-c9d9-4884-ba45-f81c60e0783a', true, NULL), -- agenda.manage
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', '9b36c65d-b3b3-4bed-b6d5-f7ee8c087c80', true, NULL), -- clinic_calendar
-- Pacientes
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', '57f631a1-9ebe-480b-a2cb-144ad32ff5f0', true, NULL), -- patients.view
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', '4e5bc50b-e339-42fe-9d91-61e8555f83e7', true, NULL), -- patients.manage
-- Agendamento online
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', '53a48c3b-0617-4618-adf8-f3a255c51ee4', true, '{"sessions_per_month": 9999}'), -- online_scheduling
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', '5739aa27-b089-4b15-b149-31b13d768825', true, NULL), -- online_scheduling.manage
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', '0bfe0b1c-8c3d-4c0c-af29-2ddc24f31bc7', true, NULL), -- online_scheduling.public
-- Relatórios
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'b3efa25d-60a4-4974-8153-6ec098b3d477', true, NULL), -- reports_basic
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'bf133ad1-da8e-4ea9-bd66-21901cb50075', true, NULL), -- reports_advanced
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'a830e45b-3bb4-4b17-812d-fe83777a2377', true, NULL), -- advanced_reports
-- Lembretes
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'f5d66212-fd73-4472-a306-07928e5deaec', true, '{"reminders_per_month": 9999}'), -- reminders
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', '8cc81988-d02a-4542-9cb2-ce2ed7c18d60', true, NULL), -- sms_reminder
-- Clínica
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', '336aeeba-b18e-4e68-8303-d42ba09f4b20', true, NULL), -- secretary
-- Intake
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'c109ad27-0edf-4774-91a7-94dac4faab49', true, NULL), -- intake_public
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', '90e92108-8124-40ee-88a0-f0ecafb57d76', true, NULL), -- intakes_pro
-- PRO exclusivo
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'f393178c-284d-422f-b096-8793f85428d5', true, NULL), -- custom_branding
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'd6f54674-ea8b-484b-af0e-99127a510da2', true, NULL), -- api_access
('82067ba7-16f0-4803-b36f-4c4e8919d4b4', 'a5593d96-dd95-46bb-bef0-bd379b56ad50', true, NULL); -- audit_log
-- ════════════════════════════════════════════════════════════════
-- THERAPIST FREE (c56fe2a8) — features básicas para funcionar
-- ════════════════════════════════════════════════════════════════
INSERT INTO public.plan_features (plan_id, feature_id, enabled, limits) VALUES
-- Agenda
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '5e539124-630f-4c2a-a9de-7999317085e6', true, NULL), -- agenda.view
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'a74fef14-c9d9-4884-ba45-f81c60e0783a', true, NULL), -- agenda.manage
-- Pacientes
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '57f631a1-9ebe-480b-a2cb-144ad32ff5f0', true, NULL), -- patients.view
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '4e5bc50b-e339-42fe-9d91-61e8555f83e7', true, NULL), -- patients.manage
-- Agendamento online (com limites)
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '53a48c3b-0617-4618-adf8-f3a255c51ee4', true, '{"sessions_per_month": 40}'), -- online_scheduling
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '5739aa27-b089-4b15-b149-31b13d768825', true, NULL), -- online_scheduling.manage
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '0bfe0b1c-8c3d-4c0c-af29-2ddc24f31bc7', true, NULL), -- online_scheduling.public
-- Relatórios (básico sim, avançado não)
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'b3efa25d-60a4-4974-8153-6ec098b3d477', true, NULL), -- reports_basic
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'bf133ad1-da8e-4ea9-bd66-21901cb50075', false, NULL), -- reports_advanced (PRO)
-- Lembretes (com limites)
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'f5d66212-fd73-4472-a306-07928e5deaec', true, '{"reminders_per_month": 50}'), -- reminders
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '8cc81988-d02a-4542-9cb2-ce2ed7c18d60', false, NULL), -- sms_reminder (PRO)
-- Intake
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'c109ad27-0edf-4774-91a7-94dac4faab49', true, NULL), -- intake_public
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', '90e92108-8124-40ee-88a0-f0ecafb57d76', false, NULL), -- intakes_pro (PRO)
-- PRO-only (desabilitado)
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'f393178c-284d-422f-b096-8793f85428d5', false, NULL), -- custom_branding (PRO)
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'd6f54674-ea8b-484b-af0e-99127a510da2', false, NULL), -- api_access (PRO)
('c56fe2a8-2c17-4048-adc7-ff7fbd89461a', 'a5593d96-dd95-46bb-bef0-bd379b56ad50', false, NULL); -- audit_log (PRO)
-- ════════════════════════════════════════════════════════════════
-- SUPERVISOR FREE (8c4895a3) — acesso + convite
-- ════════════════════════════════════════════════════════════════
INSERT INTO public.plan_features (plan_id, feature_id, enabled, limits) VALUES
('8c4895a3-e12d-48de-a078-efb8a4ea2eb2', '9ab8bdbb-838b-4946-aa5d-fd9cfdd257b3', true, NULL), -- supervisor.access
('8c4895a3-e12d-48de-a078-efb8a4ea2eb2', '1167b54a-0e93-43a2-94d7-c12e64eb56de', true, NULL); -- supervisor.invite
-- ════════════════════════════════════════════════════════════════
-- SUPERVISOR PRO (ca28e46c) — acesso + convite + sessões + relatórios
-- ════════════════════════════════════════════════════════════════
INSERT INTO public.plan_features (plan_id, feature_id, enabled, limits) VALUES
('ca28e46c-0687-45d5-9406-0a0f56a5b625', '9ab8bdbb-838b-4946-aa5d-fd9cfdd257b3', true, NULL), -- supervisor.access
('ca28e46c-0687-45d5-9406-0a0f56a5b625', '1167b54a-0e93-43a2-94d7-c12e64eb56de', true, NULL), -- supervisor.invite
('ca28e46c-0687-45d5-9406-0a0f56a5b625', '761e4495-b46a-4791-9519-86ffe48dc47f', true, NULL), -- supervisor.sessions
('ca28e46c-0687-45d5-9406-0a0f56a5b625', '7e82ee01-44f6-4b3f-9861-840c58e13f58', true, NULL); -- supervisor.reports
-- ════════════════════════════════════════════════════════════════
-- PATIENT FREE (984c1f29) — sem features de plano (acesso via portal)
-- ════════════════════════════════════════════════════════════════
-- Pacientes acessam via portal_user, não precisam de features de plano.
-- O acesso é controlado pelo role 'portal_user' no profile.
DO $$
BEGIN
RAISE NOTICE 'seed_012_plan_features: plan_features inseridos para todos os 7 planos.';
END;
$$;
COMMIT;

View File

@@ -0,0 +1,184 @@
-- =============================================================================
-- SEED 013 — Subscriptions + Determined Commitments
-- =============================================================================
-- Execute APÓS: seed_010 (plans), seed_011 (features), seed_012 (plan_features)
-- E APÓS: seed_001, seed_002, seed_003 (usuários e tenants)
--
-- Cria subscriptions para todos os usuários de teste e chama
-- seed_determined_commitments() para tenants que ainda não têm.
--
-- Mapeamento:
-- paciente@ (user_id) → patient_free
-- terapeuta@ (user_id) → therapist_free
-- clinica1@ (tenant_id) → clinic_free (coworking)
-- clinica2@ (tenant_id) → clinic_free (recepção)
-- clinica3@ (tenant_id) → clinic_free (full)
-- supervisor@ (user_id) → supervisor_free
-- editor@ (user_id) → therapist_free (acesso via platform_roles)
-- therapist2@ (user_id) → therapist_free
-- therapist3@ (user_id) → therapist_free
-- secretary@ → sem plano próprio (usa plano da Clínica 2)
-- saas@ → saas_admin (sem plano)
-- =============================================================================
BEGIN;
-- Limpa subscriptions de seed anteriores
DELETE FROM public.subscriptions WHERE source = 'seed';
-- ============================================================
-- 1. Subscriptions — user_id scope (therapist, patient, supervisor)
-- ============================================================
-- Paciente → patient_free
INSERT INTO public.subscriptions (
user_id, plan_id, plan_key, status, "interval",
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'aaaaaaaa-0001-0001-0001-000000000001',
p.id, p.key, 'active', 'month',
now(), now() + interval '1 year',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'patient_free';
-- Terapeuta → therapist_free
INSERT INTO public.subscriptions (
user_id, plan_id, plan_key, status, "interval",
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'aaaaaaaa-0002-0002-0002-000000000002',
p.id, p.key, 'active', 'month',
now(), now() + interval '1 year',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'therapist_free';
-- Supervisor → supervisor_free
INSERT INTO public.subscriptions (
user_id, plan_id, plan_key, status, "interval",
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'aaaaaaaa-0007-0007-0007-000000000007',
p.id, p.key, 'active', 'month',
now(), now() + interval '1 year',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'supervisor_free';
-- Editor → therapist_free (acesso editor vem de platform_roles)
INSERT INTO public.subscriptions (
user_id, plan_id, plan_key, status, "interval",
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'aaaaaaaa-0008-0008-0008-000000000008',
p.id, p.key, 'active', 'month',
now(), now() + interval '1 year',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'therapist_free';
-- Terapeuta 2 → therapist_free
INSERT INTO public.subscriptions (
user_id, plan_id, plan_key, status, "interval",
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'aaaaaaaa-0009-0009-0009-000000000009',
p.id, p.key, 'active', 'month',
now(), now() + interval '1 year',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'therapist_free';
-- Terapeuta 3 → therapist_free
INSERT INTO public.subscriptions (
user_id, plan_id, plan_key, status, "interval",
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'aaaaaaaa-0010-0010-0010-000000000010',
p.id, p.key, 'active', 'month',
now(), now() + interval '1 year',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'therapist_free';
-- ============================================================
-- 2. Subscriptions — tenant_id scope (clinic)
-- ============================================================
-- Clínica 1 (Espaço Psi / Coworking) → clinic_free
INSERT INTO public.subscriptions (
tenant_id, plan_id, plan_key, status, "interval",
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'bbbbbbbb-0003-0003-0003-000000000003',
p.id, p.key, 'active', 'month',
now(), now() + interval '1 year',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'clinic_free';
-- Clínica 2 (Mente sã / Recepção) → clinic_free
INSERT INTO public.subscriptions (
tenant_id, plan_id, plan_key, status, "interval",
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'bbbbbbbb-0004-0004-0004-000000000004',
p.id, p.key, 'active', 'month',
now(), now() + interval '1 year',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'clinic_free';
-- Clínica 3 (Bem Estar / Full) → clinic_free
INSERT INTO public.subscriptions (
tenant_id, plan_id, plan_key, status, "interval",
current_period_start, current_period_end,
source, started_at, activated_at
)
SELECT
'bbbbbbbb-0005-0005-0005-000000000005',
p.id, p.key, 'active', 'month',
now(), now() + interval '1 year',
'seed', now(), now()
FROM public.plans p WHERE p.key = 'clinic_free';
-- ============================================================
-- 3. Determined Commitments (idempotente por design da função)
-- ============================================================
-- Chama para todos os tenants. A função usa ON CONFLICT internamente.
DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0002-0002-0002-000000000002'); END $$; -- Terapeuta
DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0003-0003-0003-000000000003'); END $$; -- Clínica 1
DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0004-0004-0004-000000000004'); END $$; -- Clínica 2
DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0005-0005-0005-000000000005'); END $$; -- Clínica 3
DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0009-0009-0009-000000000009'); END $$; -- Terapeuta 2
DO $$ BEGIN PERFORM public.seed_determined_commitments('bbbbbbbb-0010-0010-0010-000000000010'); END $$; -- Terapeuta 3
-- ============================================================
-- 4. Confirma
-- ============================================================
DO $$
DECLARE
v_count integer;
BEGIN
SELECT count(*) INTO v_count FROM public.subscriptions WHERE source = 'seed';
RAISE NOTICE 'seed_013_subscriptions: % subscriptions ativas criadas.', v_count;
SELECT count(*) INTO v_count FROM public.determined_commitments WHERE is_native = true;
RAISE NOTICE 'seed_013_subscriptions: % determined_commitments nativos existentes.', v_count;
END;
$$;
COMMIT;

View File

@@ -0,0 +1,427 @@
-- =============================================================================
-- SEED 014 — Dados Globais (Email Templates, Notification Templates, Carousel)
-- =============================================================================
-- Idempotente: ON CONFLICT DO UPDATE / DO NOTHING
--
-- Cria:
-- 11 email_templates_global (templates de email do sistema)
-- 7 notification_templates WhatsApp (default)
-- 6 notification_templates SMS (default)
-- 3 login_carousel_slides (slides da página de login)
-- =============================================================================
BEGIN;
-- ============================================================
-- 1. Email Templates Globais
-- ============================================================
INSERT INTO public.email_templates_global
(key, domain, channel, subject, body_html, body_text, version, is_active, variables)
VALUES
-- session.reminder.email
(
'session.reminder.email',
'session',
'email',
'Lembrete: sua sessão amanhã às {{session_time}}',
'
<p>Olá, <strong>{{patient_name}}</strong>!</p>
<p>Este é um lembrete da sua sessão agendada para <strong>{{session_date}}</strong> às <strong>{{session_time}}</strong>.</p>
<p>Modalidade: <strong>{{session_modality}}</strong></p>
{{#if session_link}}
<p><a href="{{session_link}}">Clique aqui para entrar na sessão online</a></p>
{{/if}}
<p>Em caso de necessidade de cancelamento, entre em contato com antecedência.</p>
<p>Até logo,<br><strong>{{therapist_name}}</strong></p>
',
'Olá, {{patient_name}}! Lembrete da sua sessão: {{session_date}} às {{session_time}} ({{session_modality}}).',
2,
true,
'{"patient_name":"Nome completo do paciente","session_date":"Data da sessão (ex: 20/03/2026)","session_time":"Horário da sessão (ex: 14:00)","session_modality":"Presencial ou Online","session_link":"Link da videochamada (apenas online)","therapist_name":"Nome do terapeuta"}'
),
-- session.confirmation.email
(
'session.confirmation.email',
'session',
'email',
'Sessão confirmada — {{session_date}} às {{session_time}}',
'
<p>Olá, <strong>{{patient_name}}</strong>!</p>
<p>Sua sessão foi confirmada com sucesso.</p>
<ul>
<li><strong>Data:</strong> {{session_date}}</li>
<li><strong>Horário:</strong> {{session_time}}</li>
<li><strong>Modalidade:</strong> {{session_modality}}</li>
{{#if session_address}}<li><strong>Local:</strong> {{session_address}}</li>{{/if}}
</ul>
<p>Até lá,<br><strong>{{therapist_name}}</strong></p>
',
'Sessão confirmada: {{session_date}} às {{session_time}} ({{session_modality}}).',
1,
true,
'{"patient_name":"Nome do paciente","session_date":"Data da sessão","session_time":"Horário da sessão","session_modality":"Presencial ou Online","session_address":"Endereço (apenas presencial)","therapist_name":"Nome do terapeuta"}'
),
-- session.cancellation.email
(
'session.cancellation.email',
'session',
'email',
'Sessão cancelada — {{session_date}}',
'
<p>Olá, <strong>{{patient_name}}</strong>!</p>
<p>Informamos que sua sessão do dia <strong>{{session_date}}</strong> às <strong>{{session_time}}</strong> foi cancelada.</p>
{{#if cancellation_reason}}<p>Motivo: {{cancellation_reason}}</p>{{/if}}
<p>Entre em contato para reagendar.</p>
<p><strong>{{therapist_name}}</strong></p>
',
NULL,
1,
true,
'{"patient_name":"Nome do paciente","session_date":"Data cancelada","session_time":"Horário cancelado","cancellation_reason":"Motivo do cancelamento (opcional)","therapist_name":"Nome do terapeuta"}'
),
-- session.rescheduled.email
(
'session.rescheduled.email',
'session',
'email',
'Sessão reagendada — {{session_date}} às {{session_time}}',
'
<p>Olá, <strong>{{patient_name}}</strong>!</p>
<p>Sua sessão foi reagendada para <strong>{{session_date}}</strong> às <strong>{{session_time}}</strong>.</p>
<p>Modalidade: <strong>{{session_modality}}</strong></p>
<p>Até lá,<br><strong>{{therapist_name}}</strong></p>
',
NULL,
1,
true,
'{"patient_name":"Nome do paciente","session_date":"Nova data","session_time":"Novo horário","session_modality":"Presencial ou Online","therapist_name":"Nome do terapeuta"}'
),
-- intake.received.email
(
'intake.received.email',
'intake',
'email',
'Recebemos seu cadastro — {{clinic_name}}',
'
<p>Olá, <strong>{{patient_name}}</strong>!</p>
<p>Recebemos seu cadastro com sucesso. Nossa equipe entrará em contato em breve para dar continuidade ao processo.</p>
<p>Obrigado pela confiança,<br><strong>{{clinic_name}}</strong></p>
',
NULL,
1,
true,
'{"patient_name":"Nome do solicitante","clinic_name":"Nome da clínica ou terapeuta"}'
),
-- intake.approved.email
(
'intake.approved.email',
'intake',
'email',
'Cadastro aprovado — bem-vindo(a)!',
'
<p>Olá, <strong>{{patient_name}}</strong>!</p>
<p>Seu cadastro foi aprovado. Você já pode acessar o portal e agendar sua primeira sessão.</p>
<p><a href="{{portal_link}}">Acessar portal →</a></p>
<p>Qualquer dúvida, estamos à disposição.<br><strong>{{therapist_name}}</strong></p>
',
NULL,
1,
true,
'{"patient_name":"Nome do paciente","therapist_name":"Nome do terapeuta","portal_link":"Link do portal do paciente"}'
),
-- intake.rejected.email
(
'intake.rejected.email',
'intake',
'email',
'Atualização sobre seu cadastro — {{clinic_name}}',
'
<p>Olá, <strong>{{patient_name}}</strong>!</p>
<p>Agradecemos seu interesse. Infelizmente não será possível dar continuidade ao seu cadastro no momento.</p>
{{#if rejection_reason}}<p>{{rejection_reason}}</p>{{/if}}
<p><strong>{{clinic_name}}</strong></p>
',
NULL,
1,
true,
'{"patient_name":"Nome do paciente","clinic_name":"Nome da clínica","rejection_reason":"Motivo (opcional)"}'
),
-- scheduler.request_accepted.email
(
'scheduler.request_accepted.email',
'session',
'email',
'Sua solicitação foi aceita — {{session_date}} às {{session_time}}',
'
<p>Olá, <strong>{{patient_name}}</strong>!</p>
<p>Sua solicitação de agendamento foi aceita.</p>
<ul>
<li><strong>Data:</strong> {{session_date}}</li>
<li><strong>Horário:</strong> {{session_time}}</li>
<li><strong>Tipo:</strong> {{session_type}}</li>
<li><strong>Modalidade:</strong> {{session_modality}}</li>
</ul>
<p>Até logo,<br><strong>{{therapist_name}}</strong></p>
',
NULL,
1,
true,
'{"patient_name":"Nome do paciente","session_date":"Data confirmada","session_time":"Horário confirmado","session_type":"Primeira consulta / Retorno","session_modality":"Presencial ou Online","therapist_name":"Nome do terapeuta"}'
),
-- scheduler.request_rejected.email
(
'scheduler.request_rejected.email',
'session',
'email',
'Atualização sobre sua solicitação de agendamento',
'
<p>Olá, <strong>{{patient_name}}</strong>!</p>
<p>Infelizmente não foi possível confirmar sua solicitação de agendamento para <strong>{{session_date}}</strong>.</p>
{{#if rejection_reason}}<p>Motivo: {{rejection_reason}}</p>{{/if}}
<p>Entre em contato para verificar outros horários disponíveis.</p>
<p><strong>{{therapist_name}}</strong></p>
',
NULL,
1,
true,
'{"patient_name":"Nome do paciente","session_date":"Data solicitada","rejection_reason":"Motivo (opcional)","therapist_name":"Nome do terapeuta"}'
),
-- system.welcome.email
(
'system.welcome.email',
'system',
'email',
'Bem-vindo(a) ao {{clinic_name}}!',
'
<p>Olá, <strong>{{patient_name}}</strong>!</p>
<p>Seja bem-vindo(a)! Sua conta foi criada com sucesso.</p>
<p><a href="{{portal_link}}">Acessar minha área →</a></p>
',
NULL,
1,
true,
'{"patient_name":"Nome do paciente","clinic_name":"Nome da clínica","portal_link":"Link do portal"}'
),
-- system.password_reset.email
(
'system.password_reset.email',
'system',
'email',
'Redefinição de senha',
'
<p>Olá, <strong>{{patient_name}}</strong>!</p>
<p>Recebemos uma solicitação para redefinir sua senha.</p>
<p><a href="{{reset_link}}">Clique aqui para redefinir sua senha →</a></p>
<p>Se você não solicitou a redefinição, ignore este e-mail.</p>
',
NULL,
1,
true,
'{"patient_name":"Nome do usuário","reset_link":"Link de redefinição de senha"}'
)
ON CONFLICT (key) DO UPDATE SET
domain = EXCLUDED.domain,
channel = EXCLUDED.channel,
subject = EXCLUDED.subject,
body_html = EXCLUDED.body_html,
body_text = EXCLUDED.body_text,
version = EXCLUDED.version,
is_active = EXCLUDED.is_active,
variables = EXCLUDED.variables,
updated_at = now();
-- ============================================================
-- 2. Notification Templates — WhatsApp (default)
-- ============================================================
INSERT INTO public.notification_templates
(tenant_id, owner_id, key, domain, channel, event_type, body_text, variables, is_default, is_active)
VALUES
-- Lembrete 24h
(
NULL, NULL,
'session.lembrete.whatsapp',
'session', 'whatsapp', 'lembrete_sessao',
E'Olá, {{nome_paciente}}! \U0001F44B\n\nLembrete da sua sessão com {{nome_terapeuta}}.\n\n\U0001F4C5 Data: {{data_sessao}}\n\U0001F550 Hora: {{hora_sessao}}\n\U0001F4CD Modalidade: {{modalidade}}\n\nQualquer dúvida, entre em contato. Até lá! \U0001F49A',
'["nome_paciente","nome_terapeuta","data_sessao","hora_sessao","modalidade"]',
true, true
),
-- Lembrete 2h
(
NULL, NULL,
'session.lembrete_2h.whatsapp',
'session', 'whatsapp', 'lembrete_sessao',
E'Olá, {{nome_paciente}}! Sua sessão com {{nome_terapeuta}} começa em 2 horas.\n\n\U0001F550 Hora: {{hora_sessao}}\n\U0001F4CD Modalidade: {{modalidade}}\n\nAté já! \U0001F60A',
'["nome_paciente","nome_terapeuta","data_sessao","hora_sessao","modalidade"]',
true, true
),
-- Confirmação
(
NULL, NULL,
'session.confirmacao.whatsapp',
'session', 'whatsapp', 'confirmacao_sessao',
E'Olá, {{nome_paciente}}! \u2705\n\nSua sessão foi confirmada!\n\n\U0001F4C5 Data: {{data_sessao}}\n\U0001F550 Hora: {{hora_sessao}}\n\U0001F4CD Modalidade: {{modalidade}}\n\nAté lá! \U0001F49A',
'["nome_paciente","nome_terapeuta","data_sessao","hora_sessao","modalidade","link_confirmacao"]',
true, true
),
-- Cancelamento
(
NULL, NULL,
'session.cancelamento.whatsapp',
'session', 'whatsapp', 'cancelamento_sessao',
E'Olá, {{nome_paciente}}. Infelizmente a sessão do dia {{data_sessao}} às {{hora_sessao}} foi cancelada.\n\nEntre em contato para reagendar. \U0001F64F',
'["nome_paciente","nome_terapeuta","data_sessao","hora_sessao","modalidade"]',
true, true
),
-- Reagendamento
(
NULL, NULL,
'session.reagendamento.whatsapp',
'session', 'whatsapp', 'reagendamento',
E'Olá, {{nome_paciente}}! Sua sessão foi reagendada.\n\n\U0001F4C5 Nova data: {{data_sessao}}\n\U0001F550 Novo horário: {{hora_sessao}}\n\U0001F4CD Modalidade: {{modalidade}}\n\nAté lá! \U0001F60A',
'["nome_paciente","nome_terapeuta","data_sessao","hora_sessao","modalidade"]',
true, true
),
-- Cobrança pendente
(
NULL, NULL,
'cobranca.pendente.whatsapp',
'billing', 'whatsapp', 'cobranca_pendente',
E'Olá, {{nome_paciente}}. Identificamos uma cobrança pendente no valor de {{valor_sessao}} referente à sua sessão do dia {{data_sessao}}.\n\nPor favor, entre em contato para regularizar. \U0001F64F',
'["nome_paciente","nome_terapeuta","data_sessao","hora_sessao","modalidade","valor_sessao"]',
true, true
),
-- Boas-vindas
(
NULL, NULL,
'sistema.boas_vindas.whatsapp',
'system', 'whatsapp', 'boas_vindas_paciente',
E'Olá, {{nome_paciente}}! \U0001F389\n\nSeja muito bem-vindo(a)! Estamos felizes em ter você aqui.\n\nEm caso de dúvidas, estamos à disposição. Até a nossa primeira sessão! \U0001F49A',
'["nome_paciente","nome_terapeuta","data_sessao","hora_sessao","modalidade"]',
true, true
)
ON CONFLICT (tenant_id, owner_id, key, deleted_at) DO NOTHING;
-- ============================================================
-- 3. Notification Templates — SMS (default)
-- ============================================================
INSERT INTO public.notification_templates
(tenant_id, owner_id, key, domain, channel, event_type, body_text, variables, is_default, is_active)
VALUES
(
NULL, NULL,
'session.reminder.sms',
'session', 'sms', 'lembrete_sessao',
'Olá {{patient_name}}, lembrete da sua sessão em {{session_date}} às {{session_time}} com {{therapist_name}}. Modalidade: {{session_modality}}.',
'["patient_name","session_date","session_time","therapist_name","session_modality"]',
true, true
),
(
NULL, NULL,
'session.confirmation.sms',
'session', 'sms', 'confirmacao_sessao',
'Sessão confirmada! {{session_date}} às {{session_time}} ({{session_modality}}) com {{therapist_name}}.',
'["patient_name","session_date","session_time","session_modality","therapist_name"]',
true, true
),
(
NULL, NULL,
'session.cancellation.sms',
'session', 'sms', 'cancelamento_sessao',
'Sua sessão de {{session_date}} às {{session_time}} foi cancelada. Entre em contato para reagendar. — {{therapist_name}}',
'["patient_name","session_date","session_time","therapist_name"]',
true, true
),
(
NULL, NULL,
'session.rescheduled.sms',
'session', 'sms', 'reagendamento',
'Sua sessão foi reagendada para {{session_date}} às {{session_time}} ({{session_modality}}). — {{therapist_name}}',
'["patient_name","session_date","session_time","session_modality","therapist_name"]',
true, true
),
(
NULL, NULL,
'intake.received.sms',
'intake', 'sms', 'intake_recebido',
'Olá {{patient_name}}, recebemos seu cadastro. Em breve entraremos em contato. — {{clinic_name}}',
'["patient_name","clinic_name"]',
true, true
),
(
NULL, NULL,
'intake.approved.sms',
'intake', 'sms', 'intake_aprovado',
'Olá {{patient_name}}, seu cadastro foi aprovado! Acesse o portal para agendar sua sessão. — {{therapist_name}}',
'["patient_name","therapist_name"]',
true, true
)
ON CONFLICT (tenant_id, owner_id, key, deleted_at) DO NOTHING;
-- ============================================================
-- 4. Login Carousel Slides
-- ============================================================
-- Limpa slides existentes e reinsere
DELETE FROM public.login_carousel_slides;
INSERT INTO public.login_carousel_slides (title, body, icon, ordem, ativo)
VALUES
(
'<strong>Gestão clínica simplificada</strong>',
'Agendamentos, prontuários e sessões em um único painel. Foco no que importa: <em>seus pacientes</em>.',
'pi-calendar-clock',
0,
true
),
(
'<strong>Múltiplos profissionais, uma só plataforma</strong>',
'Adicione terapeutas, gerencie vínculos por clínica e mantenha equipes organizadas com controle de acesso por papel.',
'pi-users',
1,
true
),
(
'<strong>Seguro, privado e sempre disponível</strong>',
'Dados protegidos com autenticação robusta, controle de acesso por perfil e conformidade com as boas práticas de privacidade.',
'pi-shield',
2,
true
);
-- ============================================================
-- 5. Confirma
-- ============================================================
DO $$
DECLARE
v_emails integer;
v_notif integer;
v_slides integer;
BEGIN
SELECT count(*) INTO v_emails FROM public.email_templates_global;
SELECT count(*) INTO v_notif FROM public.notification_templates WHERE is_default = true;
SELECT count(*) INTO v_slides FROM public.login_carousel_slides WHERE ativo = true;
RAISE NOTICE 'seed_014_global_data: % email templates, % notification templates, % carousel slides.', v_emails, v_notif, v_slides;
END;
$$;
COMMIT;

View File

@@ -0,0 +1,929 @@
-- ============================================================
-- SEED DE TESTE — AgenciaPsi
-- ============================================================
-- Cria 10 terapeutas com pacientes, agendamentos, sessões,
-- cancelamentos, remarcações, faltas, grupos, financeiro, etc.
--
-- IMPORTANTE:
-- 1) Os usuários (auth.users) devem ser criados via Supabase Auth
-- ou via auth.users INSERT direto (requer service_role).
-- Este script assume que os 10 users já existem no auth.users.
--
-- 2) Execute este script com a service_role key no SQL Editor
-- do Supabase (ou via psql com permissão).
--
-- 3) Todos os UUIDs são fixos e determinísticos para facilitar
-- depuração. Prefixo:
-- Terapeutas: aaaaaaaa-0001..0010
-- Tenants: bbbbbbbb-0001..0010
-- Pacientes: cccccccc-0001..0050
-- Eventos: dddddddd-0001..0200
-- Financeiro: eeeeeeee-0001..0200
-- Grupos: ffffffff-0001..0020
-- Recorrência: 11111111-0001..0010
--
-- ============================================================
-- ────────────────────────────────────────────────────────────
-- 0. LIMPAR DADOS DE TESTE (idempotente)
-- ────────────────────────────────────────────────────────────
DO $$
DECLARE
_tenant_ids uuid[] := ARRAY[
'bbbbbbbb-0000-0000-0000-000000000001'::uuid,
'bbbbbbbb-0000-0000-0000-000000000002'::uuid,
'bbbbbbbb-0000-0000-0000-000000000003'::uuid,
'bbbbbbbb-0000-0000-0000-000000000004'::uuid,
'bbbbbbbb-0000-0000-0000-000000000005'::uuid,
'bbbbbbbb-0000-0000-0000-000000000006'::uuid,
'bbbbbbbb-0000-0000-0000-000000000007'::uuid,
'bbbbbbbb-0000-0000-0000-000000000008'::uuid,
'bbbbbbbb-0000-0000-0000-000000000009'::uuid,
'bbbbbbbb-0000-0000-0000-000000000010'::uuid
];
BEGIN
-- Financeiro
DELETE FROM public.financial_records WHERE tenant_id = ANY(_tenant_ids);
-- Eventos
DELETE FROM public.agenda_eventos WHERE tenant_id = ANY(_tenant_ids);
-- Recorrências
DELETE FROM public.recurrence_rules WHERE tenant_id = ANY(_tenant_ids);
-- Grupos
DELETE FROM public.patient_group_patient WHERE tenant_id = ANY(_tenant_ids);
DELETE FROM public.patient_groups WHERE tenant_id = ANY(_tenant_ids);
-- Pacientes
DELETE FROM public.patients WHERE tenant_id = ANY(_tenant_ids);
-- Notificações
DELETE FROM public.notification_channels WHERE tenant_id = ANY(_tenant_ids);
DELETE FROM public.notification_templates WHERE tenant_id = ANY(_tenant_ids);
DELETE FROM public.notification_logs WHERE tenant_id = ANY(_tenant_ids);
DELETE FROM public.notification_schedules WHERE tenant_id = ANY(_tenant_ids);
-- Regras semanais
DELETE FROM public.agenda_regras_semanais WHERE tenant_id = ANY(_tenant_ids);
-- Serviços
DELETE FROM public.services WHERE tenant_id = ANY(_tenant_ids);
-- Tenant members
DELETE FROM public.tenant_members WHERE tenant_id = ANY(_tenant_ids);
-- Company profiles
DELETE FROM public.company_profiles WHERE tenant_id = ANY(_tenant_ids);
-- Tenants
DELETE FROM public.tenants WHERE id = ANY(_tenant_ids);
-- Profiles
DELETE FROM public.profiles WHERE id IN (
'aaaaaaaa-0000-0000-0000-000000000001'::uuid,
'aaaaaaaa-0000-0000-0000-000000000002'::uuid,
'aaaaaaaa-0000-0000-0000-000000000003'::uuid,
'aaaaaaaa-0000-0000-0000-000000000004'::uuid,
'aaaaaaaa-0000-0000-0000-000000000005'::uuid,
'aaaaaaaa-0000-0000-0000-000000000006'::uuid,
'aaaaaaaa-0000-0000-0000-000000000007'::uuid,
'aaaaaaaa-0000-0000-0000-000000000008'::uuid,
'aaaaaaaa-0000-0000-0000-000000000009'::uuid,
'aaaaaaaa-0000-0000-0000-000000000010'::uuid
);
-- Auth users (requer service_role)
DELETE FROM auth.users WHERE id IN (
'aaaaaaaa-0000-0000-0000-000000000001'::uuid,
'aaaaaaaa-0000-0000-0000-000000000002'::uuid,
'aaaaaaaa-0000-0000-0000-000000000003'::uuid,
'aaaaaaaa-0000-0000-0000-000000000004'::uuid,
'aaaaaaaa-0000-0000-0000-000000000005'::uuid,
'aaaaaaaa-0000-0000-0000-000000000006'::uuid,
'aaaaaaaa-0000-0000-0000-000000000007'::uuid,
'aaaaaaaa-0000-0000-0000-000000000008'::uuid,
'aaaaaaaa-0000-0000-0000-000000000009'::uuid,
'aaaaaaaa-0000-0000-0000-000000000010'::uuid
);
END $$;
-- ────────────────────────────────────────────────────────────
-- 1. USUÁRIOS (auth.users) — 10 terapeutas
-- ────────────────────────────────────────────────────────────
-- Desabilitar triggers que chamam funções inexistentes
ALTER TABLE auth.users DISABLE TRIGGER ALL;
-- Senha: Test@1234 (hash bcrypt)
INSERT INTO auth.users (
id, instance_id, email, encrypted_password,
email_confirmed_at, aud, role,
raw_app_meta_data, raw_user_meta_data,
created_at, updated_at
) VALUES
('aaaaaaaa-0000-0000-0000-000000000001', '00000000-0000-0000-0000-000000000000', 'terapeuta01@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dra. Ana Beatriz"}', now(), now()),
('aaaaaaaa-0000-0000-0000-000000000002', '00000000-0000-0000-0000-000000000000', 'terapeuta02@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dr. Carlos Eduardo"}', now(), now()),
('aaaaaaaa-0000-0000-0000-000000000003', '00000000-0000-0000-0000-000000000000', 'terapeuta03@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dra. Fernanda Lima"}', now(), now()),
('aaaaaaaa-0000-0000-0000-000000000004', '00000000-0000-0000-0000-000000000000', 'terapeuta04@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dr. Gabriel Santos"}', now(), now()),
('aaaaaaaa-0000-0000-0000-000000000005', '00000000-0000-0000-0000-000000000000', 'terapeuta05@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dra. Juliana Alves"}', now(), now()),
('aaaaaaaa-0000-0000-0000-000000000006', '00000000-0000-0000-0000-000000000000', 'terapeuta06@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dr. Lucas Oliveira"}', now(), now()),
('aaaaaaaa-0000-0000-0000-000000000007', '00000000-0000-0000-0000-000000000000', 'terapeuta07@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dra. Mariana Costa"}', now(), now()),
('aaaaaaaa-0000-0000-0000-000000000008', '00000000-0000-0000-0000-000000000000', 'terapeuta08@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dr. Pedro Henrique"}', now(), now()),
('aaaaaaaa-0000-0000-0000-000000000009', '00000000-0000-0000-0000-000000000000', 'terapeuta09@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dra. Renata Souza"}', now(), now()),
('aaaaaaaa-0000-0000-0000-000000000010', '00000000-0000-0000-0000-000000000000', 'terapeuta10@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dr. Thiago Nunes"}', now(), now())
ON CONFLICT (id) DO NOTHING;
-- Identities (necessárias para login via email)
INSERT INTO auth.identities (id, user_id, identity_data, provider, provider_id, last_sign_in_at, created_at, updated_at)
SELECT id, id, jsonb_build_object('sub', id::text, 'email', email), 'email', id::text, now(), now(), now()
FROM auth.users WHERE id IN (
'aaaaaaaa-0000-0000-0000-000000000001','aaaaaaaa-0000-0000-0000-000000000002',
'aaaaaaaa-0000-0000-0000-000000000003','aaaaaaaa-0000-0000-0000-000000000004',
'aaaaaaaa-0000-0000-0000-000000000005','aaaaaaaa-0000-0000-0000-000000000006',
'aaaaaaaa-0000-0000-0000-000000000007','aaaaaaaa-0000-0000-0000-000000000008',
'aaaaaaaa-0000-0000-0000-000000000009','aaaaaaaa-0000-0000-0000-000000000010'
)
ON CONFLICT DO NOTHING;
-- Reabilitar triggers
ALTER TABLE auth.users ENABLE TRIGGER ALL;
-- ────────────────────────────────────────────────────────────
-- 2. PROFILES
-- ────────────────────────────────────────────────────────────
INSERT INTO public.profiles (id, full_name, role, phone, bio, account_type) VALUES
('aaaaaaaa-0000-0000-0000-000000000001', 'Dra. Ana Beatriz', 'tenant_member', '(11) 91234-0001', 'Psicóloga clínica — TCC e EMDR', 'therapist'),
('aaaaaaaa-0000-0000-0000-000000000002', 'Dr. Carlos Eduardo', 'tenant_member', '(11) 91234-0002', 'Psicólogo — Psicanálise', 'therapist'),
('aaaaaaaa-0000-0000-0000-000000000003', 'Dra. Fernanda Lima', 'tenant_member', '(16) 91234-0003', 'Psicóloga infantil — Ludoterapia', 'therapist'),
('aaaaaaaa-0000-0000-0000-000000000004', 'Dr. Gabriel Santos', 'tenant_member', '(16) 91234-0004', 'Psicólogo — Gestalt-terapia', 'therapist'),
('aaaaaaaa-0000-0000-0000-000000000005', 'Dra. Juliana Alves', 'tenant_member', '(21) 91234-0005', 'Psicóloga — Neuropsicologia', 'therapist'),
('aaaaaaaa-0000-0000-0000-000000000006', 'Dr. Lucas Oliveira', 'tenant_member', '(21) 91234-0006', 'Psicólogo — Terapia Sistêmica', 'therapist'),
('aaaaaaaa-0000-0000-0000-000000000007', 'Dra. Mariana Costa', 'tenant_member', '(31) 91234-0007', 'Psicóloga — Humanismo', 'therapist'),
('aaaaaaaa-0000-0000-0000-000000000008', 'Dr. Pedro Henrique', 'tenant_member', '(31) 91234-0008', 'Psicólogo — Análise do Comportamento', 'therapist'),
('aaaaaaaa-0000-0000-0000-000000000009', 'Dra. Renata Souza', 'tenant_member', '(41) 91234-0009', 'Psicóloga — Psicossomática', 'therapist'),
('aaaaaaaa-0000-0000-0000-000000000010', 'Dr. Thiago Nunes', 'tenant_member', '(41) 91234-0010', 'Psicólogo — Terapia Cognitiva', 'therapist')
ON CONFLICT (id) DO UPDATE SET full_name = EXCLUDED.full_name, role = EXCLUDED.role;
-- ────────────────────────────────────────────────────────────
-- 3. TENANTS + MEMBERS
-- ────────────────────────────────────────────────────────────
INSERT INTO public.tenants (id, name, kind) VALUES
('bbbbbbbb-0000-0000-0000-000000000001', 'Consultório Dra. Ana Beatriz', 'therapist'),
('bbbbbbbb-0000-0000-0000-000000000002', 'Consultório Dr. Carlos Eduardo', 'therapist'),
('bbbbbbbb-0000-0000-0000-000000000003', 'Consultório Dra. Fernanda Lima', 'therapist'),
('bbbbbbbb-0000-0000-0000-000000000004', 'Consultório Dr. Gabriel Santos', 'therapist'),
('bbbbbbbb-0000-0000-0000-000000000005', 'Consultório Dra. Juliana Alves', 'therapist'),
('bbbbbbbb-0000-0000-0000-000000000006', 'Consultório Dr. Lucas Oliveira', 'therapist'),
('bbbbbbbb-0000-0000-0000-000000000007', 'Consultório Dra. Mariana Costa', 'therapist'),
('bbbbbbbb-0000-0000-0000-000000000008', 'Consultório Dr. Pedro Henrique', 'therapist'),
('bbbbbbbb-0000-0000-0000-000000000009', 'Consultório Dra. Renata Souza', 'therapist'),
('bbbbbbbb-0000-0000-0000-000000000010', 'Consultório Dr. Thiago Nunes', 'therapist')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.tenant_members (tenant_id, user_id, role, status)
SELECT
('bbbbbbbb-0000-0000-0000-00000000000' || i)::uuid,
('aaaaaaaa-0000-0000-0000-00000000000' || i)::uuid,
'tenant_admin', 'active'
FROM generate_series(1, 9) AS s(i)
UNION ALL
SELECT
'bbbbbbbb-0000-0000-0000-000000000010'::uuid,
'aaaaaaaa-0000-0000-0000-000000000010'::uuid,
'tenant_admin', 'active'
ON CONFLICT DO NOTHING;
-- ────────────────────────────────────────────────────────────
-- 4. SERVIÇOS (1 serviço padrão por terapeuta)
-- ────────────────────────────────────────────────────────────
INSERT INTO public.services (id, owner_id, tenant_id, name, price, duration_min, active)
SELECT
('99999999-0000-0000-0000-00000000000' || i)::uuid,
('aaaaaaaa-0000-0000-0000-00000000000' || i)::uuid,
('bbbbbbbb-0000-0000-0000-00000000000' || i)::uuid,
'Sessão Individual', (150 + i * 10)::numeric, 50, true
FROM generate_series(1, 9) AS s(i)
UNION ALL
SELECT
'99999999-0000-0000-0000-000000000010'::uuid,
'aaaaaaaa-0000-0000-0000-000000000010'::uuid,
'bbbbbbbb-0000-0000-0000-000000000010'::uuid,
'Sessão Individual', 250::numeric, 50, true
ON CONFLICT DO NOTHING;
-- ────────────────────────────────────────────────────────────
-- 5. PACIENTES — 5 por terapeuta = 50 pacientes
-- ────────────────────────────────────────────────────────────
DO $$
DECLARE
_nomes text[] := ARRAY[
'Maria Silva','João Pereira','Camila Rocha','Rafael Dias','Larissa Melo',
'Bruno Costa','Amanda Ferreira','Felipe Souza','Isabela Nunes','Diego Almeida',
'Patrícia Lima','Rodrigo Santos','Letícia Araujo','Gustavo Ribeiro','Bianca Carvalho',
'Matheus Gomes','Natália Barbosa','André Vieira','Carolina Martins','Lucas Teixeira',
'Aline Pinto','Henrique Moura','Vanessa Cardoso','Marcos Fernandes','Tatiana Lopes',
'Thiago Nascimento','Juliana Duarte','Eduardo Correia','Fernanda Monteiro','Paulo Campos',
'Simone Reis','Ricardo Azevedo','Debora Mendes','Alexandre Freitas','Sandra Oliveira',
'Daniel Cunha','Priscila Moreira','Roberto Andrade','Cláudia Batista','Leandro Rezende',
'Adriana Sousa','Vinicius Castro','Luciana Pereira','Fabio Miranda','Elaine Barros',
'Renato Faria','Cristina Machado','Marcelo Prado','Gabriela Assis','Sergio Nogueira'
];
_phones text[] := ARRAY[
'(11) 98765-1001','(11) 98765-1002','(11) 98765-1003','(11) 98765-1004','(11) 98765-1005',
'(11) 98765-1006','(11) 98765-1007','(11) 98765-1008','(11) 98765-1009','(11) 98765-1010',
'(16) 98765-1011','(16) 98765-1012','(16) 98765-1013','(16) 98765-1014','(16) 98765-1015',
'(16) 98765-1016','(16) 98765-1017','(16) 98765-1018','(16) 98765-1019','(16) 98765-1020',
'(21) 98765-1021','(21) 98765-1022','(21) 98765-1023','(21) 98765-1024','(21) 98765-1025',
'(21) 98765-1026','(21) 98765-1027','(21) 98765-1028','(21) 98765-1029','(21) 98765-1030',
'(31) 98765-1031','(31) 98765-1032','(31) 98765-1033','(31) 98765-1034','(31) 98765-1035',
'(31) 98765-1036','(31) 98765-1037','(31) 98765-1038','(31) 98765-1039','(31) 98765-1040',
'(41) 98765-1041','(41) 98765-1042','(41) 98765-1043','(41) 98765-1044','(41) 98765-1045',
'(41) 98765-1046','(41) 98765-1047','(41) 98765-1048','(41) 98765-1049','(41) 98765-1050'
];
_statuses text[] := ARRAY['Ativo','Ativo','Ativo','Ativo','Inativo'];
_t int;
_p int;
_idx int;
_pid uuid;
_oid uuid;
_tid uuid;
_mid uuid;
BEGIN
FOR _t IN 1..10 LOOP
IF _t < 10 THEN
_oid := ('aaaaaaaa-0000-0000-0000-00000000000' || _t)::uuid;
_tid := ('bbbbbbbb-0000-0000-0000-00000000000' || _t)::uuid;
ELSE
_oid := 'aaaaaaaa-0000-0000-0000-000000000010'::uuid;
_tid := 'bbbbbbbb-0000-0000-0000-000000000010'::uuid;
END IF;
-- Buscar o id do tenant_member para este user/tenant
SELECT id INTO _mid FROM public.tenant_members
WHERE tenant_id = _tid AND user_id = _oid LIMIT 1;
FOR _p IN 1..5 LOOP
_idx := (_t - 1) * 5 + _p;
_pid := ('cccccccc-0000-0000-0000-' || lpad(_idx::text, 12, '0'))::uuid;
INSERT INTO public.patients (
id, nome_completo, email_principal, telefone,
status, owner_id, tenant_id, responsible_member_id,
data_nascimento, genero, cidade, estado
) VALUES (
_pid,
_nomes[_idx],
'paciente' || _idx || '@teste.agenciapsi.com',
_phones[_idx],
_statuses[_p],
_oid, _tid, _mid,
'1985-01-01'::date + (_idx * 120 || ' days')::interval,
CASE WHEN _idx % 2 = 0 THEN 'Feminino' ELSE 'Masculino' END,
CASE
WHEN _t <= 2 THEN 'são Paulo'
WHEN _t <= 4 THEN 'são Carlos'
WHEN _t <= 6 THEN 'Rio de Janeiro'
WHEN _t <= 8 THEN 'Belo Horizonte'
ELSE 'Curitiba'
END,
CASE
WHEN _t <= 2 THEN 'SP'
WHEN _t <= 4 THEN 'SP'
WHEN _t <= 6 THEN 'RJ'
WHEN _t <= 8 THEN 'MG'
ELSE 'PR'
END
) ON CONFLICT (id) DO NOTHING;
END LOOP;
END LOOP;
END $$;
-- ────────────────────────────────────────────────────────────
-- 6. GRUPOS DE PACIENTES — 2 por terapeuta
-- ────────────────────────────────────────────────────────────
DO $$
DECLARE
_t int;
_oid uuid;
_tid uuid;
_g1 uuid;
_g2 uuid;
BEGIN
FOR _t IN 1..10 LOOP
IF _t < 10 THEN
_oid := ('aaaaaaaa-0000-0000-0000-00000000000' || _t)::uuid;
_tid := ('bbbbbbbb-0000-0000-0000-00000000000' || _t)::uuid;
ELSE
_oid := 'aaaaaaaa-0000-0000-0000-000000000010'::uuid;
_tid := 'bbbbbbbb-0000-0000-0000-000000000010'::uuid;
END IF;
_g1 := ('ffffffff-0000-0000-0000-' || lpad(((_t-1)*2+1)::text, 12, '0'))::uuid;
_g2 := ('ffffffff-0000-0000-0000-' || lpad(((_t-1)*2+2)::text, 12, '0'))::uuid;
INSERT INTO public.patient_groups (id, owner_id, tenant_id, nome, cor, is_active)
VALUES
(_g1, _oid, _tid, 'Adultos', '#6366f1', true),
(_g2, _oid, _tid, 'Crianças', '#f59e0b', true)
ON CONFLICT (id) DO NOTHING;
-- Adicionar 3 pacientes ao grupo Adultos, 2 ao grupo Crianças
INSERT INTO public.patient_group_patient (patient_id, patient_group_id, tenant_id)
SELECT
('cccccccc-0000-0000-0000-' || lpad(((_t-1)*5 + p)::text, 12, '0'))::uuid,
CASE WHEN p <= 3 THEN _g1 ELSE _g2 END,
_tid
FROM generate_series(1, 5) AS s(p)
ON CONFLICT DO NOTHING;
END LOOP;
END $$;
-- ────────────────────────────────────────────────────────────
-- 7. AGENDA — Eventos do último mês + próxima semana
-- Tipos: realizado, faltou, cancelado, agendado, remarcar
-- ────────────────────────────────────────────────────────────
DO $$
DECLARE
_t int;
_p int;
_d int;
_idx int;
_oid uuid;
_tid uuid;
_pid uuid;
_eid uuid;
_status text;
_statuses text[] := ARRAY['realizado','realizado','realizado','faltou','cancelado','realizado','agendado','remarcar','realizado','realizado',
'realizado','realizado','faltou','realizado','cancelado','agendado','agendado','realizado','realizado','realizado'];
_dia date;
_hora time;
_horas time[] := ARRAY['08:00','09:00','10:00','11:00','14:00'];
_evt_counter int := 0;
_modalidade text;
BEGIN
FOR _t IN 1..10 LOOP
IF _t < 10 THEN
_oid := ('aaaaaaaa-0000-0000-0000-00000000000' || _t)::uuid;
_tid := ('bbbbbbbb-0000-0000-0000-00000000000' || _t)::uuid;
ELSE
_oid := 'aaaaaaaa-0000-0000-0000-000000000010'::uuid;
_tid := 'bbbbbbbb-0000-0000-0000-000000000010'::uuid;
END IF;
-- 4 semanas de sessões (seg-sex), 1 sessão por paciente por semana
FOR _d IN 0..27 LOOP
_dia := (current_date - interval '28 days' + (_d || ' days')::interval)::date;
-- Pular finais de semana
IF extract(dow FROM _dia) IN (0, 6) THEN CONTINUE; END IF;
FOR _p IN 1..5 LOOP
-- Cada paciente tem sessão 1x/semana (dias alternados)
IF (_d % 5) != (_p - 1) THEN CONTINUE; END IF;
_evt_counter := _evt_counter + 1;
_idx := (_t - 1) * 5 + _p;
_pid := ('cccccccc-0000-0000-0000-' || lpad(_idx::text, 12, '0'))::uuid;
_eid := ('dddddddd-0000-0000-0000-' || lpad(_evt_counter::text, 12, '0'))::uuid;
_hora := _horas[_p];
_status := _statuses[(_evt_counter - 1) % 20 + 1];
_modalidade := CASE WHEN _p <= 3 THEN 'presencial' ELSE 'online' END;
-- Eventos futuros devem ser 'agendado'
IF _dia > current_date THEN _status := 'agendado'; END IF;
INSERT INTO public.agenda_eventos (
id, owner_id, tenant_id, tipo, status,
patient_id, terapeuta_id,
inicio_em, fim_em,
titulo, modalidade
) VALUES (
_eid, _oid, _tid, 'sessao'::tipo_evento_agenda, _status::status_evento_agenda,
_pid, _oid,
(_dia || ' ' || _hora)::timestamptz,
(_dia || ' ' || _hora)::timestamptz + interval '50 minutes',
'Sessão — ' || (SELECT nome_completo FROM public.patients WHERE id = _pid),
_modalidade
) ON CONFLICT (id) DO NOTHING;
END LOOP;
END LOOP;
END LOOP;
RAISE NOTICE 'Total de eventos criados: %', _evt_counter;
END $$;
-- ────────────────────────────────────────────────────────────
-- 8. FINANCEIRO — 1 lançamento por evento realizado
-- ────────────────────────────────────────────────────────────
INSERT INTO public.financial_records (
id, owner_id, tenant_id, type, amount, final_amount, description,
category, payment_method, status, paid_at, due_date,
agenda_evento_id, patient_id
)
SELECT
gen_random_uuid(),
ae.owner_id,
ae.tenant_id,
'receita',
v.amt,
v.amt,
CASE
WHEN ae.status = 'realizado' THEN 'Sessão realizada'
WHEN ae.status = 'faltou' THEN 'Falta — cobrança parcial'
ELSE 'Sessão cancelada'
END,
'Sessão',
CASE WHEN random() > 0.5 THEN 'pix' ELSE 'cartao_credito' END,
CASE
WHEN ae.status = 'realizado' THEN 'paid'
WHEN ae.status = 'faltou' THEN 'pending'
ELSE 'cancelled'
END,
CASE WHEN ae.status = 'realizado' THEN ae.inicio_em ELSE NULL END,
ae.inicio_em::date,
ae.id,
ae.patient_id
FROM public.agenda_eventos ae
CROSS JOIN LATERAL (
SELECT CASE
WHEN ae.status = 'realizado' THEN (150 + (random() * 100)::int)::numeric
WHEN ae.status = 'faltou' THEN (75 + (random() * 50)::int)::numeric
ELSE 0
END AS amt
) v
WHERE ae.tenant_id IN (
SELECT id FROM public.tenants WHERE id::text LIKE 'bbbbbbbb%'
)
AND ae.status IN ('realizado', 'faltou', 'cancelado');
-- ────────────────────────────────────────────────────────────
-- 9. REGRAS SEMANAIS — horários de atendimento
-- ────────────────────────────────────────────────────────────
DO $$
DECLARE
_t int;
_d int;
_oid uuid;
_tid uuid;
BEGIN
FOR _t IN 1..10 LOOP
IF _t < 10 THEN
_oid := ('aaaaaaaa-0000-0000-0000-00000000000' || _t)::uuid;
_tid := ('bbbbbbbb-0000-0000-0000-00000000000' || _t)::uuid;
ELSE
_oid := 'aaaaaaaa-0000-0000-0000-000000000010'::uuid;
_tid := 'bbbbbbbb-0000-0000-0000-000000000010'::uuid;
END IF;
-- Segunda a sexta, 8h-12h e 14h-18h
FOR _d IN 1..5 LOOP
INSERT INTO public.agenda_regras_semanais (owner_id, tenant_id, dia_semana, hora_inicio, hora_fim, modalidade, ativo)
VALUES
(_oid, _tid, _d, '08:00', '12:00', 'ambos', true),
(_oid, _tid, _d, '14:00', '18:00', 'ambos', true)
ON CONFLICT DO NOTHING;
END LOOP;
END LOOP;
END $$;
-- ────────────────────────────────────────────────────────────
-- 10. RECORRÊNCIAS — 1 por terapeuta (paciente 1)
-- ────────────────────────────────────────────────────────────
DO $$
DECLARE
_t int;
_oid uuid;
_tid uuid;
_pid uuid;
_rid uuid;
BEGIN
FOR _t IN 1..10 LOOP
IF _t < 10 THEN
_oid := ('aaaaaaaa-0000-0000-0000-00000000000' || _t)::uuid;
_tid := ('bbbbbbbb-0000-0000-0000-00000000000' || _t)::uuid;
ELSE
_oid := 'aaaaaaaa-0000-0000-0000-000000000010'::uuid;
_tid := 'bbbbbbbb-0000-0000-0000-000000000010'::uuid;
END IF;
_pid := ('cccccccc-0000-0000-0000-' || lpad(((_t-1)*5 + 1)::text, 12, '0'))::uuid;
_rid := ('11111111-0000-0000-0000-' || lpad(_t::text, 12, '0'))::uuid;
INSERT INTO public.recurrence_rules (
id, tenant_id, owner_id, patient_id,
type, weekdays, start_time, end_time,
start_date, open_ended, modalidade, status
) VALUES (
_rid, _tid, _oid, _pid,
'weekly', ARRAY[(_t % 5) + 1]::smallint[], '09:00', '09:50',
current_date - interval '30 days', true, 'presencial', 'ativo'
) ON CONFLICT (id) DO NOTHING;
END LOOP;
END $$;
-- ────────────────────────────────────────────────────────────
-- 11. NOTIFICATION SCHEDULES — 1 set por terapeuta
-- ────────────────────────────────────────────────────────────
DO $$
DECLARE
_t int;
_oid uuid;
_tid uuid;
BEGIN
FOR _t IN 1..10 LOOP
IF _t < 10 THEN
_oid := ('aaaaaaaa-0000-0000-0000-00000000000' || _t)::uuid;
_tid := ('bbbbbbbb-0000-0000-0000-00000000000' || _t)::uuid;
ELSE
_oid := 'aaaaaaaa-0000-0000-0000-000000000010'::uuid;
_tid := 'bbbbbbbb-0000-0000-0000-000000000010'::uuid;
END IF;
INSERT INTO public.notification_schedules (
tenant_id, owner_id, schedule_key, event_type,
trigger_type, offset_minutes,
whatsapp_enabled, email_enabled, is_active
) VALUES
(_tid, _oid, 'lembrete_24h', 'lembrete_sessao', 'before_event', 1440, true, true, true),
(_tid, _oid, 'lembrete_2h', 'lembrete_sessao', 'before_event', 120, true, false, true),
(_tid, _oid, 'confirmacao', 'confirmacao_sessao', 'immediate', 0, true, true, true),
(_tid, _oid, 'cancelamento', 'cancelamento_sessao', 'immediate', 0, true, true, true)
ON CONFLICT DO NOTHING;
END LOOP;
END $$;
-- ════════════════════════════════════════════════════════════
-- 12. DADOS PARA terapeuta@agenciapsi.com.br
-- ════════════════════════════════════════════════════════════
-- 20 pacientes, 10+ grupos, 10+ eventos de cada status,
-- 10+ lançamentos, 10+ regras semanais, 10+ recorrências,
-- 10+ notificações
-- ────────────────────────────────────────────────────────────
-- 12a. LIMPEZA dos dados de teste deste usuário
DO $$
DECLARE
_oid uuid;
_tid uuid;
BEGIN
SELECT id INTO _oid FROM auth.users WHERE email = 'terapeuta@agenciapsi.com.br';
IF _oid IS NULL THEN
RAISE NOTICE 'Usuário terapeuta@agenciapsi.com.br não encontrado — pulando limpeza';
RETURN;
END IF;
SELECT t.id INTO _tid
FROM public.tenants t
JOIN public.tenant_members tm ON tm.tenant_id = t.id
WHERE tm.user_id = _oid
LIMIT 1;
IF _tid IS NULL THEN
RAISE NOTICE 'Tenant não encontrado para terapeuta@agenciapsi.com.br — pulando limpeza';
RETURN;
END IF;
-- Limpar apenas dados de seed (pacientes com email @seed.teste)
DELETE FROM public.financial_records WHERE tenant_id = _tid AND description LIKE '%[SEED]%';
DELETE FROM public.agenda_eventos WHERE tenant_id = _tid AND titulo LIKE '%[SEED]%';
DELETE FROM public.recurrence_rules WHERE tenant_id = _tid AND observacoes = '[SEED]';
DELETE FROM public.patient_group_patient WHERE tenant_id = _tid AND patient_id IN (
SELECT id FROM public.patients WHERE tenant_id = _tid AND email_principal LIKE '%@seed.teste.agenciapsi.com'
);
DELETE FROM public.patient_groups WHERE tenant_id = _tid AND nome LIKE '%[SEED]%';
DELETE FROM public.patients WHERE tenant_id = _tid AND email_principal LIKE '%@seed.teste.agenciapsi.com';
DELETE FROM public.agenda_regras_semanais WHERE tenant_id = _tid AND owner_id = _oid;
DELETE FROM public.notification_schedules WHERE tenant_id = _tid AND owner_id = _oid;
RAISE NOTICE 'Limpeza concluída para terapeuta@agenciapsi.com.br (tenant: %)', _tid;
END $$;
-- 12b. INSERIR DADOS
DO $$
DECLARE
_oid uuid;
_tid uuid;
_mid uuid;
_pid uuid;
_eid uuid;
_gid uuid;
_i int;
_d int;
_dia date;
_hora time;
_status text;
_evt_counter int := 0;
_nomes text[] := ARRAY[
'Amanda Rodrigues','Bruno Ferreira','Camila Teixeira','Diego Nascimento','Elisa Cardoso',
'Felipe Moura','Giovana Ribeiro','Hugo Martins','Isabela Correia','João Vitor Almeida',
'Karen Oliveira','Leonardo Duarte','Marina Santos','Nicolas Costa','Olívia Mendes',
'Paulo Ricardo','Quésia Lima','Rafael Araújo','Sofia Carvalho','Tomás Barbosa'
];
_phones text[] := ARRAY[
'(16) 99001-0001','(16) 99001-0002','(16) 99001-0003','(16) 99001-0004','(16) 99001-0005',
'(16) 99001-0006','(16) 99001-0007','(16) 99001-0008','(16) 99001-0009','(16) 99001-0010',
'(16) 99001-0011','(16) 99001-0012','(16) 99001-0013','(16) 99001-0014','(16) 99001-0015',
'(16) 99001-0016','(16) 99001-0017','(16) 99001-0018','(16) 99001-0019','(16) 99001-0020'
];
_cidades text[] := ARRAY[
'são Carlos','são Carlos','Araraquara','Araraquara','Ribeirão Preto',
'Ribeirão Preto','são Carlos','são Carlos','Araraquara','Araraquara',
'são Carlos','são Carlos','Ribeirão Preto','Ribeirão Preto','são Carlos',
'são Carlos','Araraquara','Araraquara','Ribeirão Preto','são Carlos'
];
_generos text[] := ARRAY[
'Feminino','Masculino','Feminino','Masculino','Feminino',
'Masculino','Feminino','Masculino','Feminino','Masculino',
'Feminino','Masculino','Feminino','Masculino','Feminino',
'Masculino','Feminino','Masculino','Feminino','Masculino'
];
_grupo_nomes text[] := ARRAY[
'Adultos [SEED]','Adolescentes [SEED]','Crianças [SEED]','Casais [SEED]','Idosos [SEED]',
'TCC [SEED]','Psicanálise [SEED]','Gestalt [SEED]','EMDR [SEED]','Grupo Familiar [SEED]'
];
_grupo_cores text[] := ARRAY[
'#6366f1','#f59e0b','#10b981','#ef4444','#8b5cf6',
'#3b82f6','#ec4899','#14b8a6','#f97316','#64748b'
];
-- Status cíclicos para eventos passados
_statuses text[] := ARRAY[
'realizado','realizado','realizado','faltou','cancelado',
'realizado','realizado','remarcar','realizado','faltou',
'realizado','realizado','realizado','cancelado','realizado',
'realizado','faltou','realizado','realizado','realizado'
];
_horas time[] := ARRAY['08:00','09:00','10:00','11:00','14:00','15:00','16:00','17:00'];
BEGIN
-- Buscar user
SELECT id INTO _oid FROM auth.users WHERE email = 'terapeuta@agenciapsi.com.br';
IF _oid IS NULL THEN
RAISE NOTICE 'Usuário terapeuta@agenciapsi.com.br não encontrado — abortando seed';
RETURN;
END IF;
-- Buscar tenant
SELECT t.id INTO _tid
FROM public.tenants t
JOIN public.tenant_members tm ON tm.tenant_id = t.id
WHERE tm.user_id = _oid
LIMIT 1;
IF _tid IS NULL THEN
RAISE NOTICE 'Tenant não encontrado — abortando seed';
RETURN;
END IF;
-- Buscar member_id
SELECT id INTO _mid FROM public.tenant_members
WHERE tenant_id = _tid AND user_id = _oid LIMIT 1;
RAISE NOTICE 'Seed para: % / tenant: % / member: %', _oid, _tid, _mid;
-- ── 20 PACIENTES ──────────────────────────────────────────
FOR _i IN 1..20 LOOP
_pid := gen_random_uuid();
INSERT INTO public.patients (
id, nome_completo, email_principal, telefone,
status, owner_id, tenant_id, responsible_member_id,
data_nascimento, genero, cidade, estado
) VALUES (
_pid,
_nomes[_i],
'seed.paciente' || _i || '@seed.teste.agenciapsi.com',
_phones[_i],
CASE WHEN _i <= 16 THEN 'Ativo' WHEN _i <= 18 THEN 'Inativo' ELSE 'Alta' END,
_oid, _tid, _mid,
('1980-01-01'::date + (_i * 400 || ' days')::interval)::date,
_generos[_i],
_cidades[_i],
'SP'
);
END LOOP;
-- ── 10 GRUPOS ─────────────────────────────────────────────
FOR _i IN 1..10 LOOP
_gid := gen_random_uuid();
INSERT INTO public.patient_groups (id, owner_id, tenant_id, nome, cor, is_active)
VALUES (_gid, _oid, _tid, _grupo_nomes[_i], _grupo_cores[_i], true);
-- Adicionar 2 pacientes por grupo
INSERT INTO public.patient_group_patient (patient_id, patient_group_id, tenant_id)
SELECT p.id, _gid, _tid
FROM public.patients p
WHERE p.tenant_id = _tid
AND p.email_principal LIKE '%@seed.teste.agenciapsi.com'
ORDER BY p.nome_completo
OFFSET ((_i - 1) * 2)
LIMIT 2;
END LOOP;
-- ── EVENTOS (últimos 42 dias + próxima semana) ────────────
-- Garante pelo menos: 10 realizado, 10 faltou, 10 cancelado,
-- 10 agendado, 10 remarcar
_evt_counter := 0;
FOR _d IN 0..48 LOOP
_dia := (current_date - interval '42 days' + (_d || ' days')::interval)::date;
IF extract(dow FROM _dia) IN (0, 6) THEN CONTINUE; END IF;
FOR _i IN 1..4 LOOP
_evt_counter := _evt_counter + 1;
_hora := _horas[((_evt_counter - 1) % 8) + 1];
-- Pegar um paciente cíclico
SELECT id INTO _pid FROM public.patients
WHERE tenant_id = _tid AND email_principal LIKE '%@seed.teste.agenciapsi.com'
ORDER BY nome_completo
OFFSET ((_evt_counter - 1) % 20)
LIMIT 1;
IF _pid IS NULL THEN CONTINUE; END IF;
-- Status: passado = cíclico, futuro = agendado
IF _dia > current_date THEN
_status := 'agendado';
ELSE
_status := _statuses[((_evt_counter - 1) % 20) + 1];
END IF;
_eid := gen_random_uuid();
BEGIN
INSERT INTO public.agenda_eventos (
id, owner_id, tenant_id, tipo, status,
patient_id, terapeuta_id,
inicio_em, fim_em,
titulo, modalidade
) VALUES (
_eid, _oid, _tid,
'sessao'::tipo_evento_agenda,
_status::status_evento_agenda,
_pid, _oid,
(_dia || ' ' || _hora)::timestamptz,
(_dia || ' ' || _hora)::timestamptz + interval '50 minutes',
'[SEED] Sessão — ' || _nomes[((_evt_counter - 1) % 20) + 1],
CASE WHEN _i <= 2 THEN 'presencial' ELSE 'online' END
);
EXCEPTION WHEN exclusion_violation THEN
-- Horário já ocupado, pular
NULL;
END;
END LOOP;
END LOOP;
RAISE NOTICE 'Eventos tentados: % (alguns podem ter sido pulados por sobreposição)', _evt_counter;
-- ── FINANCEIRO ────────────────────────────────────────────
INSERT INTO public.financial_records (
id, owner_id, tenant_id, type, amount, final_amount, description,
category, payment_method, status, paid_at, due_date,
agenda_evento_id, patient_id
)
SELECT
gen_random_uuid(),
ae.owner_id,
ae.tenant_id,
'receita',
v.amt,
v.amt,
'[SEED] ' || CASE
WHEN ae.status = 'realizado'::status_evento_agenda THEN 'Sessão realizada'
WHEN ae.status = 'faltou'::status_evento_agenda THEN 'Falta — cobrança parcial'
ELSE 'Sessão cancelada'
END,
'Sessão',
CASE WHEN random() > 0.5 THEN 'pix' ELSE 'cartao_credito' END,
CASE
WHEN ae.status = 'realizado'::status_evento_agenda THEN 'paid'
WHEN ae.status = 'faltou'::status_evento_agenda THEN 'pending'
ELSE 'cancelled'
END,
CASE WHEN ae.status = 'realizado'::status_evento_agenda THEN ae.inicio_em ELSE NULL END,
ae.inicio_em::date,
ae.id,
ae.patient_id
FROM public.agenda_eventos ae
CROSS JOIN LATERAL (
SELECT CASE
WHEN ae.status = 'realizado'::status_evento_agenda THEN (150 + (random() * 100)::int)::numeric
WHEN ae.status = 'faltou'::status_evento_agenda THEN (75 + (random() * 50)::int)::numeric
ELSE 0
END AS amt
) v
WHERE ae.tenant_id = _tid
AND ae.titulo LIKE '[SEED]%'
AND ae.status IN ('realizado'::status_evento_agenda, 'faltou'::status_evento_agenda, 'cancelado'::status_evento_agenda);
-- ── REGRAS SEMANAIS (10 — manhã e tarde, seg-sex) ────────
INSERT INTO public.agenda_regras_semanais (owner_id, tenant_id, dia_semana, hora_inicio, hora_fim, modalidade, ativo)
VALUES
(_oid, _tid, 1, '08:00', '12:00', 'ambos', true),
(_oid, _tid, 1, '14:00', '18:00', 'ambos', true),
(_oid, _tid, 2, '08:00', '12:00', 'ambos', true),
(_oid, _tid, 2, '14:00', '18:00', 'ambos', true),
(_oid, _tid, 3, '08:00', '12:00', 'ambos', true),
(_oid, _tid, 3, '14:00', '18:00', 'ambos', true),
(_oid, _tid, 4, '08:00', '12:00', 'ambos', true),
(_oid, _tid, 4, '14:00', '18:00', 'ambos', true),
(_oid, _tid, 5, '08:00', '12:00', 'ambos', true),
(_oid, _tid, 5, '14:00', '18:00', 'ambos', true)
ON CONFLICT DO NOTHING;
-- ── RECORRÊNCIAS (10 pacientes com sessão semanal) ────────
FOR _i IN 1..10 LOOP
SELECT id INTO _pid FROM public.patients
WHERE tenant_id = _tid AND email_principal LIKE '%@seed.teste.agenciapsi.com'
ORDER BY nome_completo
OFFSET (_i - 1) LIMIT 1;
IF _pid IS NULL THEN CONTINUE; END IF;
INSERT INTO public.recurrence_rules (
id, tenant_id, owner_id, patient_id, type, weekdays,
start_time, end_time, start_date, open_ended, modalidade, status, observacoes
) VALUES (
gen_random_uuid(), _tid, _oid, _pid, 'weekly',
ARRAY[_i % 5]::int[],
('08:00'::time + ((_i - 1) * 60 || ' minutes')::interval),
('08:50'::time + ((_i - 1) * 60 || ' minutes')::interval),
current_date - interval '30 days',
true,
CASE WHEN _i <= 5 THEN 'presencial' ELSE 'online' END,
'ativo',
'[SEED]'
);
END LOOP;
-- ── NOTIFICATION SCHEDULES (10) ───────────────────────────
INSERT INTO public.notification_schedules (
tenant_id, owner_id, schedule_key, event_type,
trigger_type, offset_minutes,
whatsapp_enabled, email_enabled, is_active
) VALUES
(_tid, _oid, 'lembrete_24h', 'lembrete_sessao', 'before_event', 1440, true, true, true),
(_tid, _oid, 'lembrete_2h', 'lembrete_sessao', 'before_event', 120, true, false, true),
(_tid, _oid, 'lembrete_30min', 'lembrete_sessao', 'before_event', 30, true, false, true),
(_tid, _oid, 'confirmacao', 'confirmacao_sessao', 'immediate', 0, true, true, true),
(_tid, _oid, 'cancelamento', 'cancelamento_sessao', 'immediate', 0, true, true, true),
(_tid, _oid, 'lembrete_48h', 'lembrete_sessao', 'before_event', 2880, false, true, true),
(_tid, _oid, 'lembrete_1h', 'lembrete_sessao', 'before_event', 60, true, false, true),
(_tid, _oid, 'confirmacao_email', 'confirmacao_sessao', 'immediate', 0, false, true, true),
(_tid, _oid, 'cancel_email', 'cancelamento_sessao', 'immediate', 0, false, true, true),
(_tid, _oid, 'lembrete_1semana', 'lembrete_sessao', 'before_event', 10080,false, true, false)
ON CONFLICT DO NOTHING;
RAISE NOTICE '══════════════════════════════════════════';
RAISE NOTICE ' SEED terapeuta@agenciapsi.com.br COMPLETO';
RAISE NOTICE ' Pacientes: 20';
RAISE NOTICE ' Grupos: 10';
RAISE NOTICE ' Eventos: %', _evt_counter;
RAISE NOTICE ' Regras semanais: 10';
RAISE NOTICE ' Recorrências: 10';
RAISE NOTICE ' Notificações: 10';
RAISE NOTICE '══════════════════════════════════════════';
END $$;
-- ────────────────────────────────────────────────────────────
-- 13. RESUMO
-- ────────────────────────────────────────────────────────────
DO $$
DECLARE
_users int;
_tenants int;
_patients int;
_events int;
_records int;
_groups int;
_recurrences int;
BEGIN
SELECT count(*) INTO _users FROM auth.users WHERE id::text LIKE 'aaaaaaaa%';
SELECT count(*) INTO _tenants FROM public.tenants WHERE id::text LIKE 'bbbbbbbb%';
SELECT count(*) INTO _patients FROM public.patients WHERE tenant_id::text LIKE 'bbbbbbbb%';
SELECT count(*) INTO _events FROM public.agenda_eventos WHERE tenant_id::text LIKE 'bbbbbbbb%';
SELECT count(*) INTO _records FROM public.financial_records WHERE tenant_id::text LIKE 'bbbbbbbb%';
SELECT count(*) INTO _groups FROM public.patient_groups WHERE tenant_id::text LIKE 'bbbbbbbb%';
SELECT count(*) INTO _recurrences FROM public.recurrence_rules WHERE tenant_id::text LIKE 'bbbbbbbb%';
RAISE NOTICE '══════════════════════════════════════════';
RAISE NOTICE ' SEED COMPLETO — RESUMO';
RAISE NOTICE '══════════════════════════════════════════';
RAISE NOTICE ' Terapeutas: %', _users;
RAISE NOTICE ' Tenants: %', _tenants;
RAISE NOTICE ' Pacientes: %', _patients;
RAISE NOTICE ' Eventos agenda: %', _events;
RAISE NOTICE ' Lançamentos fin.: %', _records;
RAISE NOTICE ' Grupos: %', _groups;
RAISE NOTICE ' Recorrências: %', _recurrences;
RAISE NOTICE '══════════════════════════════════════════';
RAISE NOTICE ' Login: terapeuta01@teste.agenciapsi.com';
RAISE NOTICE ' Senha: Test@1234';
RAISE NOTICE '══════════════════════════════════════════';
END $$;

View File

@@ -0,0 +1,231 @@
-- ============================================================
-- CLEANUP — Remove TODOS os dados de seed/teste
-- AgenciaPsi — 2026-03-22
-- ============================================================
-- Remove dados criados por seed_test_data.sql:
-- - 10 terapeutas fictícios (aaaaaaaa-*)
-- - 10 tenants fictícios (bbbbbbbb-*)
-- - 50 pacientes fictícios (cccccccc-*)
-- - Eventos, financeiro, grupos, recorrências
-- - Dados seed do terapeuta@agenciapsi.com.br ([SEED])
-- - Notification queue/logs dos tenants de teste
-- - Addon credits/transactions dos tenants de teste
--
-- SEGURO: Não apaga dados reais (apenas UUIDs/emails conhecidos)
-- ============================================================
DO $$
DECLARE
_tenant_ids uuid[] := ARRAY[
'bbbbbbbb-0000-0000-0000-000000000001'::uuid,
'bbbbbbbb-0000-0000-0000-000000000002'::uuid,
'bbbbbbbb-0000-0000-0000-000000000003'::uuid,
'bbbbbbbb-0000-0000-0000-000000000004'::uuid,
'bbbbbbbb-0000-0000-0000-000000000005'::uuid,
'bbbbbbbb-0000-0000-0000-000000000006'::uuid,
'bbbbbbbb-0000-0000-0000-000000000007'::uuid,
'bbbbbbbb-0000-0000-0000-000000000008'::uuid,
'bbbbbbbb-0000-0000-0000-000000000009'::uuid,
'bbbbbbbb-0000-0000-0000-000000000010'::uuid
];
_user_ids uuid[] := ARRAY[
'aaaaaaaa-0000-0000-0000-000000000001'::uuid,
'aaaaaaaa-0000-0000-0000-000000000002'::uuid,
'aaaaaaaa-0000-0000-0000-000000000003'::uuid,
'aaaaaaaa-0000-0000-0000-000000000004'::uuid,
'aaaaaaaa-0000-0000-0000-000000000005'::uuid,
'aaaaaaaa-0000-0000-0000-000000000006'::uuid,
'aaaaaaaa-0000-0000-0000-000000000007'::uuid,
'aaaaaaaa-0000-0000-0000-000000000008'::uuid,
'aaaaaaaa-0000-0000-0000-000000000009'::uuid,
'aaaaaaaa-0000-0000-0000-000000000010'::uuid
];
_real_oid uuid;
_real_tid uuid;
_deleted int;
_total int := 0;
BEGIN
RAISE NOTICE '══════════════════════════════════════════';
RAISE NOTICE ' CLEANUP — Removendo dados de teste...';
RAISE NOTICE '══════════════════════════════════════════';
-- ── Notification queue e logs (tenants fictícios) ──────────
DELETE FROM public.notification_logs WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' notification_logs: % removidos', _deleted;
DELETE FROM public.notification_queue WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' notification_queue: % removidos', _deleted;
DELETE FROM public.notification_preferences WHERE owner_id = ANY(_user_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' notification_preferences: % removidos', _deleted;
DELETE FROM public.notification_schedules WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' notification_schedules: % removidos', _deleted;
DELETE FROM public.notification_channels WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' notification_channels: % removidos', _deleted;
DELETE FROM public.notification_templates WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' notification_templates: % removidos', _deleted;
-- ── Addon credits/transactions (tenants fictícios) ─────────
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'addon_transactions') THEN
DELETE FROM public.addon_transactions WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' addon_transactions: % removidos', _deleted;
END IF;
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'addon_credits') THEN
DELETE FROM public.addon_credits WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' addon_credits: % removidos', _deleted;
END IF;
-- ── Financeiro ─────────────────────────────────────────────
DELETE FROM public.financial_records WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' financial_records: % removidos', _deleted;
-- ── Eventos agenda ─────────────────────────────────────────
DELETE FROM public.agenda_eventos WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' agenda_eventos: % removidos', _deleted;
-- ── Recorrências ───────────────────────────────────────────
DELETE FROM public.recurrence_rules WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' recurrence_rules: % removidos', _deleted;
-- ── Grupos ─────────────────────────────────────────────────
DELETE FROM public.patient_group_patient WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' patient_group_patient: % removidos', _deleted;
DELETE FROM public.patient_groups WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' patient_groups: % removidos', _deleted;
-- ── Pacientes ──────────────────────────────────────────────
DELETE FROM public.patients WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' patients: % removidos', _deleted;
-- ── Regras semanais ────────────────────────────────────────
DELETE FROM public.agenda_regras_semanais WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' agenda_regras_semanais: % removidos', _deleted;
-- ── Serviços ───────────────────────────────────────────────
DELETE FROM public.services WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' services: % removidos', _deleted;
-- ── Tenant members ─────────────────────────────────────────
DELETE FROM public.tenant_members WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' tenant_members: % removidos', _deleted;
-- ── Company profiles ───────────────────────────────────────
DELETE FROM public.company_profiles WHERE tenant_id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' company_profiles: % removidos', _deleted;
-- ── Tenants ────────────────────────────────────────────────
DELETE FROM public.tenants WHERE id = ANY(_tenant_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' tenants: % removidos', _deleted;
-- ── Profiles ───────────────────────────────────────────────
DELETE FROM public.profiles WHERE id = ANY(_user_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' profiles: % removidos', _deleted;
-- ── Auth users ─────────────────────────────────────────────
ALTER TABLE auth.users DISABLE TRIGGER ALL;
DELETE FROM auth.identities WHERE user_id = ANY(_user_ids);
DELETE FROM auth.users WHERE id = ANY(_user_ids);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' auth.users: % removidos', _deleted;
ALTER TABLE auth.users ENABLE TRIGGER ALL;
-- ══════════════════════════════════════════════════════════
-- DADOS [SEED] DO terapeuta@agenciapsi.com.br
-- ══════════════════════════════════════════════════════════
SELECT id INTO _real_oid FROM auth.users WHERE email = 'terapeuta@agenciapsi.com.br';
IF _real_oid IS NOT NULL THEN
SELECT t.id INTO _real_tid
FROM public.tenants t
JOIN public.tenant_members tm ON tm.tenant_id = t.id
WHERE tm.user_id = _real_oid
LIMIT 1;
IF _real_tid IS NOT NULL THEN
RAISE NOTICE '';
RAISE NOTICE ' Limpando [SEED] de terapeuta@agenciapsi.com.br...';
-- Notification queue/logs deste tenant (apenas os de teste)
DELETE FROM public.notification_logs WHERE tenant_id = _real_tid
AND queue_id IN (SELECT id FROM public.notification_queue WHERE tenant_id = _real_tid);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' notification_logs (real): % removidos', _deleted;
DELETE FROM public.notification_queue WHERE tenant_id = _real_tid;
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' notification_queue (real):% removidos', _deleted;
-- Financeiro [SEED]
DELETE FROM public.financial_records WHERE tenant_id = _real_tid AND description LIKE '[SEED]%';
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' financial_records [SEED]: % removidos', _deleted;
-- Eventos [SEED]
DELETE FROM public.agenda_eventos WHERE tenant_id = _real_tid AND titulo LIKE '[SEED]%';
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' agenda_eventos [SEED]: % removidos', _deleted;
-- Recorrências [SEED]
DELETE FROM public.recurrence_rules WHERE tenant_id = _real_tid AND observacoes = '[SEED]';
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' recurrence_rules [SEED]: % removidos', _deleted;
-- Grupos [SEED]
DELETE FROM public.patient_group_patient WHERE tenant_id = _real_tid AND patient_id IN (
SELECT id FROM public.patients WHERE tenant_id = _real_tid AND email_principal LIKE '%@seed.teste.agenciapsi.com'
);
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' group_patient [SEED]: % removidos', _deleted;
DELETE FROM public.patient_groups WHERE tenant_id = _real_tid AND nome LIKE '%[SEED]%';
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' patient_groups [SEED]: % removidos', _deleted;
-- Pacientes seed
DELETE FROM public.patients WHERE tenant_id = _real_tid AND email_principal LIKE '%@seed.teste.agenciapsi.com';
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' patients [SEED]: % removidos', _deleted;
-- Regras semanais e schedules (reseta tudo deste owner)
DELETE FROM public.agenda_regras_semanais WHERE tenant_id = _real_tid AND owner_id = _real_oid;
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' regras_semanais (real): % removidos', _deleted;
DELETE FROM public.notification_schedules WHERE tenant_id = _real_tid AND owner_id = _real_oid;
GET DIAGNOSTICS _deleted = ROW_COUNT; _total := _total + _deleted;
RAISE NOTICE ' notif_schedules (real): % removidos', _deleted;
END IF;
ELSE
RAISE NOTICE ' terapeuta@agenciapsi.com.br não encontrado — pulando';
END IF;
RAISE NOTICE '';
RAISE NOTICE '══════════════════════════════════════════';
RAISE NOTICE ' CLEANUP COMPLETO — % registros removidos', _total;
RAISE NOTICE '══════════════════════════════════════════';
END $$;