-- -- PostgreSQL database dump -- \restrict ttCln7QPzFfEuTFQuEAFDv3kegteolKfFYEJ8UXnE3ahDRWx0ZUEy3J0kR47I2X -- Dumped from database version 17.6 -- Dumped by pg_dump version 17.6 SET statement_timeout = 0; SET lock_timeout = 0; SET idle_in_transaction_session_timeout = 0; SET transaction_timeout = 0; SET client_encoding = 'UTF8'; SET standard_conforming_strings = on; SELECT pg_catalog.set_config('search_path', '', false); SET check_function_bodies = false; SET xmloption = content; SET client_min_messages = warning; SET row_security = off; -- -- Name: _realtime; Type: SCHEMA; Schema: -; Owner: - -- CREATE SCHEMA _realtime; -- -- Name: auth; Type: SCHEMA; Schema: -; Owner: - -- CREATE SCHEMA auth; -- -- Name: pg_cron; Type: EXTENSION; Schema: -; Owner: - -- CREATE EXTENSION IF NOT EXISTS pg_cron WITH SCHEMA pg_catalog; -- -- Name: EXTENSION pg_cron; Type: COMMENT; Schema: -; Owner: - -- COMMENT ON EXTENSION pg_cron IS 'Job scheduler for PostgreSQL'; -- -- Name: extensions; Type: SCHEMA; Schema: -; Owner: - -- CREATE SCHEMA extensions; -- -- Name: graphql; Type: SCHEMA; Schema: -; Owner: - -- CREATE SCHEMA graphql; -- -- Name: graphql_public; Type: SCHEMA; Schema: -; Owner: - -- CREATE SCHEMA graphql_public; -- -- Name: pg_net; Type: EXTENSION; Schema: -; Owner: - -- CREATE EXTENSION IF NOT EXISTS pg_net WITH SCHEMA extensions; -- -- Name: EXTENSION pg_net; Type: COMMENT; Schema: -; Owner: - -- COMMENT ON EXTENSION pg_net IS 'Async HTTP'; -- -- Name: pgbouncer; Type: SCHEMA; Schema: -; Owner: - -- CREATE SCHEMA pgbouncer; -- -- Name: realtime; Type: SCHEMA; Schema: -; Owner: - -- CREATE SCHEMA realtime; -- -- Name: storage; Type: SCHEMA; Schema: -; Owner: - -- CREATE SCHEMA storage; -- -- Name: supabase_functions; Type: SCHEMA; Schema: -; Owner: - -- CREATE SCHEMA supabase_functions; -- -- Name: vault; Type: SCHEMA; Schema: -; Owner: - -- CREATE SCHEMA vault; -- -- Name: btree_gist; Type: EXTENSION; Schema: -; Owner: - -- CREATE EXTENSION IF NOT EXISTS btree_gist WITH SCHEMA public; -- -- Name: EXTENSION btree_gist; Type: COMMENT; Schema: -; Owner: - -- COMMENT ON EXTENSION btree_gist IS 'support for indexing common datatypes in GiST'; -- -- Name: citext; Type: EXTENSION; Schema: -; Owner: - -- CREATE EXTENSION IF NOT EXISTS citext WITH SCHEMA public; -- -- Name: EXTENSION citext; Type: COMMENT; Schema: -; Owner: - -- COMMENT ON EXTENSION citext IS 'data type for case-insensitive character strings'; -- -- Name: pg_graphql; Type: EXTENSION; Schema: -; Owner: - -- CREATE EXTENSION IF NOT EXISTS pg_graphql WITH SCHEMA graphql; -- -- Name: EXTENSION pg_graphql; Type: COMMENT; Schema: -; Owner: - -- COMMENT ON EXTENSION pg_graphql IS 'pg_graphql: GraphQL support'; -- -- Name: pg_stat_statements; Type: EXTENSION; Schema: -; Owner: - -- CREATE EXTENSION IF NOT EXISTS pg_stat_statements WITH SCHEMA extensions; -- -- Name: EXTENSION pg_stat_statements; Type: COMMENT; Schema: -; Owner: - -- COMMENT ON EXTENSION pg_stat_statements IS 'track planning and execution statistics of all SQL statements executed'; -- -- Name: pg_trgm; Type: EXTENSION; Schema: -; Owner: - -- CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public; -- -- Name: EXTENSION pg_trgm; Type: COMMENT; Schema: -; Owner: - -- COMMENT ON EXTENSION pg_trgm IS 'text similarity measurement and index searching based on trigrams'; -- -- Name: pgcrypto; Type: EXTENSION; Schema: -; Owner: - -- CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA extensions; -- -- Name: EXTENSION pgcrypto; Type: COMMENT; Schema: -; Owner: - -- COMMENT ON EXTENSION pgcrypto IS 'cryptographic functions'; -- -- Name: supabase_vault; Type: EXTENSION; Schema: -; Owner: - -- CREATE EXTENSION IF NOT EXISTS supabase_vault WITH SCHEMA vault; -- -- Name: EXTENSION supabase_vault; Type: COMMENT; Schema: -; Owner: - -- COMMENT ON EXTENSION supabase_vault IS 'Supabase Vault Extension'; -- -- Name: uuid-ossp; Type: EXTENSION; Schema: -; Owner: - -- CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA extensions; -- -- Name: EXTENSION "uuid-ossp"; Type: COMMENT; Schema: -; Owner: - -- COMMENT ON EXTENSION "uuid-ossp" IS 'generate universally unique identifiers (UUIDs)'; -- -- Name: aal_level; Type: TYPE; Schema: auth; Owner: - -- CREATE TYPE auth.aal_level AS ENUM ( 'aal1', 'aal2', 'aal3' ); -- -- Name: code_challenge_method; Type: TYPE; Schema: auth; Owner: - -- CREATE TYPE auth.code_challenge_method AS ENUM ( 's256', 'plain' ); -- -- Name: factor_status; Type: TYPE; Schema: auth; Owner: - -- CREATE TYPE auth.factor_status AS ENUM ( 'unverified', 'verified' ); -- -- Name: factor_type; Type: TYPE; Schema: auth; Owner: - -- CREATE TYPE auth.factor_type AS ENUM ( 'totp', 'webauthn', 'phone' ); -- -- Name: oauth_authorization_status; Type: TYPE; Schema: auth; Owner: - -- CREATE TYPE auth.oauth_authorization_status AS ENUM ( 'pending', 'approved', 'denied', 'expired' ); -- -- Name: oauth_client_type; Type: TYPE; Schema: auth; Owner: - -- CREATE TYPE auth.oauth_client_type AS ENUM ( 'public', 'confidential' ); -- -- Name: oauth_registration_type; Type: TYPE; Schema: auth; Owner: - -- CREATE TYPE auth.oauth_registration_type AS ENUM ( 'dynamic', 'manual' ); -- -- Name: oauth_response_type; Type: TYPE; Schema: auth; Owner: - -- CREATE TYPE auth.oauth_response_type AS ENUM ( 'code' ); -- -- Name: one_time_token_type; Type: TYPE; Schema: auth; Owner: - -- CREATE TYPE auth.one_time_token_type AS ENUM ( 'confirmation_token', 'reauthentication_token', 'recovery_token', 'email_change_token_new', 'email_change_token_current', 'phone_change_token' ); -- -- Name: commitment_log_source; Type: TYPE; Schema: public; Owner: - -- CREATE TYPE public.commitment_log_source AS ENUM ( 'manual', 'auto' ); -- -- Name: determined_field_type; Type: TYPE; Schema: public; Owner: - -- CREATE TYPE public.determined_field_type AS ENUM ( 'text', 'textarea', 'number', 'date', 'select', 'boolean' ); -- -- Name: financial_record_type; Type: TYPE; Schema: public; Owner: - -- CREATE TYPE public.financial_record_type AS ENUM ( 'receita', 'despesa' ); -- -- Name: recurrence_exception_type; Type: TYPE; Schema: public; Owner: - -- CREATE TYPE public.recurrence_exception_type AS ENUM ( 'cancel_session', 'reschedule_session', 'patient_missed', 'therapist_canceled', 'holiday_block' ); -- -- Name: recurrence_type; Type: TYPE; Schema: public; Owner: - -- CREATE TYPE public.recurrence_type AS ENUM ( 'weekly', 'biweekly', 'monthly', 'yearly', 'custom_weekdays' ); -- -- Name: status_agenda_serie; Type: TYPE; Schema: public; Owner: - -- CREATE TYPE public.status_agenda_serie AS ENUM ( 'ativo', 'pausado', 'cancelado' ); -- -- Name: status_evento_agenda; Type: TYPE; Schema: public; Owner: - -- CREATE TYPE public.status_evento_agenda AS ENUM ( 'agendado', 'realizado', 'faltou', 'cancelado', 'remarcar' ); -- -- Name: status_excecao_agenda; Type: TYPE; Schema: public; Owner: - -- CREATE TYPE public.status_excecao_agenda AS ENUM ( 'pendente', 'ativo', 'arquivado' ); -- -- Name: tipo_evento_agenda; Type: TYPE; Schema: public; Owner: - -- CREATE TYPE public.tipo_evento_agenda AS ENUM ( 'sessao', 'bloqueio' ); -- -- Name: tipo_excecao_agenda; Type: TYPE; Schema: public; Owner: - -- CREATE TYPE public.tipo_excecao_agenda AS ENUM ( 'bloqueio', 'horario_extra' ); -- -- Name: action; Type: TYPE; Schema: realtime; Owner: - -- CREATE TYPE realtime.action AS ENUM ( 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'ERROR' ); -- -- Name: equality_op; Type: TYPE; Schema: realtime; Owner: - -- CREATE TYPE realtime.equality_op AS ENUM ( 'eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'in' ); -- -- Name: user_defined_filter; Type: TYPE; Schema: realtime; Owner: - -- CREATE TYPE realtime.user_defined_filter AS ( column_name text, op realtime.equality_op, value text ); -- -- Name: wal_column; Type: TYPE; Schema: realtime; Owner: - -- CREATE TYPE realtime.wal_column AS ( name text, type_name text, type_oid oid, value jsonb, is_pkey boolean, is_selectable boolean ); -- -- Name: wal_rls; Type: TYPE; Schema: realtime; Owner: - -- CREATE TYPE realtime.wal_rls AS ( wal jsonb, is_rls_enabled boolean, subscription_ids uuid[], errors text[] ); -- -- Name: buckettype; Type: TYPE; Schema: storage; Owner: - -- CREATE TYPE storage.buckettype AS ENUM ( 'STANDARD', 'ANALYTICS', 'VECTOR' ); -- -- Name: email(); Type: FUNCTION; Schema: auth; Owner: - -- CREATE FUNCTION auth.email() RETURNS text LANGUAGE sql STABLE AS $$ select coalesce( nullif(current_setting('request.jwt.claim.email', true), ''), (nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'email') )::text $$; -- -- Name: FUNCTION email(); Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON FUNCTION auth.email() IS 'Deprecated. Use auth.jwt() -> ''email'' instead.'; -- -- Name: jwt(); Type: FUNCTION; Schema: auth; Owner: - -- CREATE FUNCTION auth.jwt() RETURNS jsonb LANGUAGE sql STABLE AS $$ select coalesce( nullif(current_setting('request.jwt.claim', true), ''), nullif(current_setting('request.jwt.claims', true), '') )::jsonb $$; -- -- Name: role(); Type: FUNCTION; Schema: auth; Owner: - -- CREATE FUNCTION auth.role() RETURNS text LANGUAGE sql STABLE AS $$ select coalesce( nullif(current_setting('request.jwt.claim.role', true), ''), (nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'role') )::text $$; -- -- Name: FUNCTION role(); Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON FUNCTION auth.role() IS 'Deprecated. Use auth.jwt() -> ''role'' instead.'; -- -- Name: uid(); Type: FUNCTION; Schema: auth; Owner: - -- CREATE FUNCTION auth.uid() RETURNS uuid LANGUAGE sql STABLE AS $$ select coalesce( nullif(current_setting('request.jwt.claim.sub', true), ''), (nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'sub') )::uuid $$; -- -- Name: FUNCTION uid(); Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON FUNCTION auth.uid() IS 'Deprecated. Use auth.jwt() -> ''sub'' instead.'; -- -- Name: grant_pg_cron_access(); Type: FUNCTION; Schema: extensions; Owner: - -- CREATE FUNCTION extensions.grant_pg_cron_access() RETURNS event_trigger LANGUAGE plpgsql AS $$ BEGIN IF EXISTS ( SELECT FROM pg_event_trigger_ddl_commands() AS ev JOIN pg_extension AS ext ON ev.objid = ext.oid WHERE ext.extname = 'pg_cron' ) THEN grant usage on schema cron to postgres with grant option; alter default privileges in schema cron grant all on tables to postgres with grant option; alter default privileges in schema cron grant all on functions to postgres with grant option; alter default privileges in schema cron grant all on sequences to postgres with grant option; alter default privileges for user supabase_admin in schema cron grant all on sequences to postgres with grant option; alter default privileges for user supabase_admin in schema cron grant all on tables to postgres with grant option; alter default privileges for user supabase_admin in schema cron grant all on functions to postgres with grant option; grant all privileges on all tables in schema cron to postgres with grant option; revoke all on table cron.job from postgres; grant select on table cron.job to postgres with grant option; END IF; END; $$; -- -- Name: FUNCTION grant_pg_cron_access(); Type: COMMENT; Schema: extensions; Owner: - -- COMMENT ON FUNCTION extensions.grant_pg_cron_access() IS 'Grants access to pg_cron'; -- -- Name: grant_pg_graphql_access(); Type: FUNCTION; Schema: extensions; Owner: - -- CREATE FUNCTION extensions.grant_pg_graphql_access() RETURNS event_trigger LANGUAGE plpgsql AS $_$ DECLARE func_is_graphql_resolve bool; BEGIN func_is_graphql_resolve = ( SELECT n.proname = 'resolve' FROM pg_event_trigger_ddl_commands() AS ev LEFT JOIN pg_catalog.pg_proc AS n ON ev.objid = n.oid ); IF func_is_graphql_resolve THEN -- Update public wrapper to pass all arguments through to the pg_graphql resolve func DROP FUNCTION IF EXISTS graphql_public.graphql; create or replace function graphql_public.graphql( "operationName" text default null, query text default null, variables jsonb default null, extensions jsonb default null ) returns jsonb language sql as $$ select graphql.resolve( query := query, variables := coalesce(variables, '{}'), "operationName" := "operationName", extensions := extensions ); $$; -- This hook executes when `graphql.resolve` is created. That is not necessarily the last -- function in the extension so we need to grant permissions on existing entities AND -- update default permissions to any others that are created after `graphql.resolve` grant usage on schema graphql to postgres, anon, authenticated, service_role; grant select on all tables in schema graphql to postgres, anon, authenticated, service_role; grant execute on all functions in schema graphql to postgres, anon, authenticated, service_role; grant all on all sequences in schema graphql to postgres, anon, authenticated, service_role; alter default privileges in schema graphql grant all on tables to postgres, anon, authenticated, service_role; alter default privileges in schema graphql grant all on functions to postgres, anon, authenticated, service_role; alter default privileges in schema graphql grant all on sequences to postgres, anon, authenticated, service_role; -- Allow postgres role to allow granting usage on graphql and graphql_public schemas to custom roles grant usage on schema graphql_public to postgres with grant option; grant usage on schema graphql to postgres with grant option; END IF; END; $_$; -- -- Name: FUNCTION grant_pg_graphql_access(); Type: COMMENT; Schema: extensions; Owner: - -- COMMENT ON FUNCTION extensions.grant_pg_graphql_access() IS 'Grants access to pg_graphql'; -- -- Name: grant_pg_net_access(); Type: FUNCTION; Schema: extensions; Owner: - -- CREATE FUNCTION extensions.grant_pg_net_access() RETURNS event_trigger LANGUAGE plpgsql AS $$ BEGIN IF EXISTS ( SELECT 1 FROM pg_event_trigger_ddl_commands() AS ev JOIN pg_extension AS ext ON ev.objid = ext.oid WHERE ext.extname = 'pg_net' ) THEN GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role; ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; END IF; END; $$; -- -- Name: FUNCTION grant_pg_net_access(); Type: COMMENT; Schema: extensions; Owner: - -- COMMENT ON FUNCTION extensions.grant_pg_net_access() IS 'Grants access to pg_net'; -- -- Name: pgrst_ddl_watch(); Type: FUNCTION; Schema: extensions; Owner: - -- CREATE FUNCTION extensions.pgrst_ddl_watch() RETURNS event_trigger LANGUAGE plpgsql AS $$ DECLARE cmd record; BEGIN FOR cmd IN SELECT * FROM pg_event_trigger_ddl_commands() LOOP IF cmd.command_tag IN ( 'CREATE SCHEMA', 'ALTER SCHEMA' , 'CREATE TABLE', 'CREATE TABLE AS', 'SELECT INTO', 'ALTER TABLE' , 'CREATE FOREIGN TABLE', 'ALTER FOREIGN TABLE' , 'CREATE VIEW', 'ALTER VIEW' , 'CREATE MATERIALIZED VIEW', 'ALTER MATERIALIZED VIEW' , 'CREATE FUNCTION', 'ALTER FUNCTION' , 'CREATE TRIGGER' , 'CREATE TYPE', 'ALTER TYPE' , 'CREATE RULE' , 'COMMENT' ) -- don't notify in case of CREATE TEMP table or other objects created on pg_temp AND cmd.schema_name is distinct from 'pg_temp' THEN NOTIFY pgrst, 'reload schema'; END IF; END LOOP; END; $$; -- -- Name: pgrst_drop_watch(); Type: FUNCTION; Schema: extensions; Owner: - -- CREATE FUNCTION extensions.pgrst_drop_watch() RETURNS event_trigger LANGUAGE plpgsql AS $$ DECLARE obj record; BEGIN FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects() LOOP IF obj.object_type IN ( 'schema' , 'table' , 'foreign table' , 'view' , 'materialized view' , 'function' , 'trigger' , 'type' , 'rule' ) AND obj.is_temporary IS false -- no pg_temp objects THEN NOTIFY pgrst, 'reload schema'; END IF; END LOOP; END; $$; -- -- Name: set_graphql_placeholder(); Type: FUNCTION; Schema: extensions; Owner: - -- CREATE FUNCTION extensions.set_graphql_placeholder() RETURNS event_trigger LANGUAGE plpgsql AS $_$ DECLARE graphql_is_dropped bool; BEGIN graphql_is_dropped = ( SELECT ev.schema_name = 'graphql_public' FROM pg_event_trigger_dropped_objects() AS ev WHERE ev.schema_name = 'graphql_public' ); IF graphql_is_dropped THEN create or replace function graphql_public.graphql( "operationName" text default null, query text default null, variables jsonb default null, extensions jsonb default null ) returns jsonb language plpgsql as $$ DECLARE server_version float; BEGIN server_version = (SELECT (SPLIT_PART((select version()), ' ', 2))::float); IF server_version >= 14 THEN RETURN jsonb_build_object( 'errors', jsonb_build_array( jsonb_build_object( 'message', 'pg_graphql extension is not enabled.' ) ) ); ELSE RETURN jsonb_build_object( 'errors', jsonb_build_array( jsonb_build_object( 'message', 'pg_graphql is only available on projects running Postgres 14 onwards.' ) ) ); END IF; END; $$; END IF; END; $_$; -- -- Name: FUNCTION set_graphql_placeholder(); Type: COMMENT; Schema: extensions; Owner: - -- COMMENT ON FUNCTION extensions.set_graphql_placeholder() IS 'Reintroduces placeholder function for graphql_public.graphql'; -- -- Name: get_auth(text); Type: FUNCTION; Schema: pgbouncer; Owner: - -- CREATE FUNCTION pgbouncer.get_auth(p_usename text) RETURNS TABLE(username text, password text) LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $_$ begin raise debug 'PgBouncer auth request: %', p_usename; return query select rolname::text, case when rolvaliduntil < now() then null else rolpassword::text end from pg_authid where rolname=$1 and rolcanlogin; end; $_$; -- -- Name: __rls_ping(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.__rls_ping() RETURNS text LANGUAGE sql STABLE AS $$ select 'ok'::text; $$; SET default_tablespace = ''; SET default_table_access_method = heap; -- -- Name: subscriptions; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.subscriptions ( id uuid DEFAULT gen_random_uuid() NOT NULL, user_id uuid, plan_id uuid NOT NULL, status text DEFAULT 'active'::text NOT NULL, current_period_start timestamp with time zone, current_period_end timestamp with time zone, cancel_at_period_end boolean DEFAULT false NOT NULL, provider text DEFAULT 'manual'::text NOT NULL, provider_customer_id text, provider_subscription_id text, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, tenant_id uuid, plan_key text, "interval" text, source text DEFAULT 'manual'::text NOT NULL, started_at timestamp with time zone DEFAULT now() NOT NULL, canceled_at timestamp with time zone, activated_at timestamp with time zone, past_due_since timestamp with time zone, suspended_at timestamp with time zone, suspended_reason text, cancelled_at timestamp with time zone, cancel_reason text, expired_at timestamp with time zone, CONSTRAINT subscriptions_interval_check CHECK (("interval" = ANY (ARRAY['month'::text, 'year'::text]))), CONSTRAINT subscriptions_owner_xor CHECK ((((tenant_id IS NOT NULL) AND (user_id IS NULL)) OR ((tenant_id IS NULL) AND (user_id IS NOT NULL)))), CONSTRAINT subscriptions_status_check CHECK ((status = ANY (ARRAY['pending'::text, 'active'::text, 'past_due'::text, 'suspended'::text, 'cancelled'::text, 'expired'::text]))) ); -- -- Name: activate_subscription_from_intent(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.activate_subscription_from_intent(p_intent_id uuid) RETURNS public.subscriptions LANGUAGE plpgsql SECURITY DEFINER AS $$ declare v_intent record; v_sub public.subscriptions; v_days int; v_user_id uuid; v_plan_id uuid; v_target text; begin -- l?? pela VIEW unificada select * into v_intent from public.subscription_intents where id = p_intent_id; if not found then raise exception 'Intent n??o encontrado: %', p_intent_id; end if; if v_intent.status <> 'paid' then raise exception 'Intent precisa estar paid para ativar assinatura'; end if; -- resolve target e plan_id via plans.key select p.id, p.target into v_plan_id, v_target from public.plans p where p.key = v_intent.plan_key limit 1; if v_plan_id is null then raise exception 'Plano n??o encontrado em plans.key = %', v_intent.plan_key; end if; v_target := lower(coalesce(v_target, '')); -- ??? supervisor adicionado if v_target not in ('clinic', 'therapist', 'supervisor') then raise exception 'Target inv??lido em plans.target: %', v_target; end if; -- regra por target if v_target = 'clinic' then if v_intent.tenant_id is null then raise exception 'Intent sem tenant_id'; end if; else -- therapist ou supervisor: vinculado ao user v_user_id := v_intent.user_id; if v_user_id is null then v_user_id := v_intent.created_by_user_id; end if; end if; if v_target in ('therapist', 'supervisor') and v_user_id is null then raise exception 'N??o foi poss??vel determinar user_id para assinatura %.', v_target; end if; -- cancela assinatura ativa anterior if v_target = 'clinic' then update public.subscriptions set status = 'cancelled', cancelled_at = now() where tenant_id = v_intent.tenant_id and plan_id = v_plan_id and status = 'active'; else -- therapist ou supervisor update public.subscriptions set status = 'cancelled', cancelled_at = now() where user_id = v_user_id and plan_id = v_plan_id and status = 'active' and tenant_id is null; end if; -- dura????o do plano (30 dias para mensal) v_days := case when lower(coalesce(v_intent.interval, 'month')) = 'year' then 365 else 30 end; -- cria nova assinatura insert into public.subscriptions ( user_id, plan_id, status, started_at, expires_at, cancelled_at, activated_at, tenant_id, plan_key, interval, source, created_at, updated_at ) values ( case when v_target = 'clinic' then null else v_user_id end, v_plan_id, 'active', now(), now() + make_interval(days => v_days), null, now(), case when v_target = 'clinic' then v_intent.tenant_id else null end, v_intent.plan_key, v_intent.interval, 'manual', now(), now() ) returning * into v_sub; -- grava v??nculo intent ??? subscription if v_target = 'clinic' then update public.subscription_intents_tenant set subscription_id = v_sub.id where id = p_intent_id; else update public.subscription_intents_personal set subscription_id = v_sub.id where id = p_intent_id; end if; return v_sub; end; $$; -- -- Name: admin_credit_addon(uuid, text, integer, uuid, text, text, integer); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.admin_credit_addon(p_tenant_id uuid, p_addon_type text, p_amount integer, p_product_id uuid DEFAULT NULL::uuid, p_description text DEFAULT 'Cr??dito manual'::text, p_payment_method text DEFAULT 'manual'::text, p_price_cents integer DEFAULT 0) RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_credit addon_credits%ROWTYPE; v_balance_before INTEGER; v_balance_after INTEGER; v_tx_id UUID; BEGIN -- Upsert addon_credits INSERT INTO addon_credits (tenant_id, addon_type, balance, total_purchased) VALUES (p_tenant_id, p_addon_type, 0, 0) ON CONFLICT (tenant_id, addon_type) DO NOTHING; -- Lock e leitura SELECT * INTO v_credit FROM addon_credits WHERE tenant_id = p_tenant_id AND addon_type = p_addon_type FOR UPDATE; v_balance_before := v_credit.balance; v_balance_after := v_credit.balance + p_amount; -- Atualiza saldo UPDATE addon_credits SET balance = v_balance_after, total_purchased = total_purchased + p_amount, low_balance_notified = CASE WHEN v_balance_after > COALESCE(low_balance_threshold, 10) THEN false ELSE low_balance_notified END, updated_at = now() WHERE id = v_credit.id; -- Registra transa????o INSERT INTO addon_transactions ( tenant_id, addon_type, type, amount, balance_before, balance_after, product_id, description, admin_user_id, payment_method, price_cents ) VALUES ( p_tenant_id, p_addon_type, 'purchase', p_amount, v_balance_before, v_balance_after, p_product_id, p_description, auth.uid(), p_payment_method, p_price_cents ) RETURNING id INTO v_tx_id; RETURN jsonb_build_object( 'success', true, 'transaction_id', v_tx_id, 'balance_before', v_balance_before, 'balance_after', v_balance_after ); END; $$; -- -- Name: FUNCTION admin_credit_addon(p_tenant_id uuid, p_addon_type text, p_amount integer, p_product_id uuid, p_description text, p_payment_method text, p_price_cents integer); Type: COMMENT; Schema: public; Owner: - -- COMMENT ON FUNCTION public.admin_credit_addon(p_tenant_id uuid, p_addon_type text, p_amount integer, p_product_id uuid, p_description text, p_payment_method text, p_price_cents integer) IS 'Admin adiciona cr??ditos de add-on a um tenant. Cria registro se n??o existir.'; -- -- Name: admin_delete_email_template_global(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.admin_delete_email_template_global(p_id uuid) RETURNS boolean LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ BEGIN DELETE FROM public.email_templates_global WHERE id = p_id; IF NOT FOUND THEN RAISE EXCEPTION 'Template com id % n??o encontrado', p_id; END IF; RETURN true; END; $$; -- -- Name: admin_fix_plan_target(text, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.admin_fix_plan_target(p_plan_key text, p_new_target text) RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$ declare v_plan_id uuid; begin -- (opcional) restringe targets v??lidos if p_new_target not in ('clinic','therapist') then raise exception 'Target inv??lido: %', p_new_target using errcode='P0001'; end if; -- trava o plano select id into v_plan_id from public.plans where key = p_plan_key for update; if v_plan_id is null then raise exception 'Plano n??o encontrado: %', p_plan_key using errcode='P0001'; end if; -- seguran??a: n??o mexer se existe subscription if exists (select 1 from public.subscriptions s where s.plan_id = v_plan_id) then raise exception 'Plano % possui subscriptions. Migra????o bloqueada.', p_plan_key using errcode='P0001'; end if; -- liga bypass SOMENTE nesta transa????o perform set_config('app.plan_migration_bypass', '1', true); update public.plans set target = p_new_target where id = v_plan_id; end $$; -- -- Name: admin_upsert_email_template_global(uuid, text, text, text, text, text, text, boolean, jsonb); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.admin_upsert_email_template_global(p_id uuid DEFAULT NULL::uuid, p_key text DEFAULT NULL::text, p_domain text DEFAULT NULL::text, p_channel text DEFAULT 'email'::text, p_subject text DEFAULT NULL::text, p_body_html text DEFAULT NULL::text, p_body_text text DEFAULT NULL::text, p_is_active boolean DEFAULT true, p_variables jsonb DEFAULT '{}'::jsonb) RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_result jsonb; v_id uuid; BEGIN -- UPDATE existente IF p_id IS NOT NULL THEN UPDATE public.email_templates_global SET subject = COALESCE(p_subject, subject), body_html = COALESCE(p_body_html, body_html), body_text = p_body_text, is_active = p_is_active, variables = COALESCE(p_variables, variables), version = version + 1 WHERE id = p_id RETURNING to_jsonb(email_templates_global.*) INTO v_result; IF v_result IS NULL THEN RAISE EXCEPTION 'Template com id % n??o encontrado', p_id; END IF; RETURN v_result; END IF; -- INSERT novo IF p_key IS NULL OR p_domain IS NULL OR p_subject IS NULL OR p_body_html IS NULL THEN RAISE EXCEPTION 'key, domain, subject e body_html s??o obrigat??rios para novo template'; END IF; INSERT INTO public.email_templates_global (key, domain, channel, subject, body_html, body_text, is_active, variables) VALUES (p_key, p_domain, p_channel, p_subject, p_body_html, p_body_text, p_is_active, p_variables) RETURNING to_jsonb(email_templates_global.*) INTO v_result; RETURN v_result; END; $$; -- -- Name: agenda_cfg_sync(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.agenda_cfg_sync() RETURNS trigger LANGUAGE plpgsql AS $$ begin if new.agenda_view_mode = 'custom' then new.usar_horario_admin_custom := true; new.admin_inicio_visualizacao := new.agenda_custom_start; new.admin_fim_visualizacao := new.agenda_custom_end; else new.usar_horario_admin_custom := false; end if; return new; end; $$; -- -- Name: agendador_dias_disponiveis(text, integer, integer); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.agendador_dias_disponiveis(p_slug text, p_ano integer, p_mes integer) RETURNS TABLE(data date, tem_slots boolean) LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_owner_id uuid; v_antecedencia int; v_agora timestamptz; v_data date; v_data_inicio date; v_data_fim date; v_db_dow int; v_tem_slot boolean; v_bloqueado boolean; BEGIN SELECT c.owner_id, c.antecedencia_minima_horas INTO v_owner_id, v_antecedencia FROM public.agendador_configuracoes c WHERE c.link_slug = p_slug AND c.ativo = true LIMIT 1; IF v_owner_id IS NULL THEN RETURN; END IF; v_agora := now(); v_data_inicio := make_date(p_ano, p_mes, 1); v_data_fim := (v_data_inicio + interval '1 month' - interval '1 day')::date; v_data := v_data_inicio; WHILE v_data <= v_data_fim LOOP v_db_dow := extract(dow from v_data::timestamp)::int; -- ?????? Dia inteiro bloqueado? (agenda_bloqueios) ??????????????????????????????????????????????????????????????????????????? SELECT EXISTS ( SELECT 1 FROM public.agenda_bloqueios b WHERE b.owner_id = v_owner_id AND b.data_inicio <= v_data AND COALESCE(b.data_fim, v_data) >= v_data AND b.hora_inicio IS NULL -- bloqueio de dia inteiro AND ( (NOT b.recorrente) OR (b.recorrente AND b.dia_semana = v_db_dow) ) ) INTO v_bloqueado; IF v_bloqueado THEN v_data := v_data + 1; CONTINUE; END IF; -- ?????? Tem slots dispon??veis no dia? ??????????????????????????????????????????????????????????????????????????????????????????????????????????????? SELECT EXISTS ( SELECT 1 FROM public.agenda_online_slots s WHERE s.owner_id = v_owner_id AND s.weekday = v_db_dow AND s.enabled = true AND (v_data::text || ' ' || s.time::text)::timestamp AT TIME ZONE 'America/Sao_Paulo' >= v_agora + (v_antecedencia || ' hours')::interval ) INTO v_tem_slot; IF v_tem_slot THEN data := v_data; tem_slots := true; RETURN NEXT; END IF; v_data := v_data + 1; END LOOP; END; $$; -- -- Name: agendador_gerar_slug(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.agendador_gerar_slug() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE v_slug text; v_exists boolean; BEGIN -- s?? gera se ativou e n??o tem slug ainda IF NEW.ativo = true AND (NEW.link_slug IS NULL OR NEW.link_slug = '') THEN LOOP v_slug := lower(substring(replace(gen_random_uuid()::text, '-', ''), 1, 8)); SELECT EXISTS ( SELECT 1 FROM public.agendador_configuracoes WHERE link_slug = v_slug AND owner_id <> NEW.owner_id ) INTO v_exists; EXIT WHEN NOT v_exists; END LOOP; NEW.link_slug := v_slug; END IF; RETURN NEW; END; $$; -- -- Name: agendador_slots_disponiveis(text, date); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.agendador_slots_disponiveis(p_slug text, p_data date) RETURNS TABLE(hora time without time zone, disponivel boolean) LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_owner_id uuid; v_duracao int; v_antecedencia int; v_agora timestamptz; v_db_dow int; v_slot time; v_slot_fim time; v_slot_ts timestamptz; v_ocupado boolean; -- loop de recorr??ncias v_rule RECORD; v_rule_start_dow int; v_first_occ date; v_day_diff int; v_ex_type text; BEGIN SELECT c.owner_id, c.duracao_sessao_min, c.antecedencia_minima_horas INTO v_owner_id, v_duracao, v_antecedencia FROM public.agendador_configuracoes c WHERE c.link_slug = p_slug AND c.ativo = true LIMIT 1; IF v_owner_id IS NULL THEN RETURN; END IF; v_agora := now(); v_db_dow := extract(dow from p_data::timestamp)::int; -- ?????? Dia inteiro bloqueado? (agenda_bloqueios sem hora) ????????????????????????????????????????????????????????? -- Se sim, n??o h?? nenhum slot dispon??vel ??? retorna vazio. IF EXISTS ( SELECT 1 FROM public.agenda_bloqueios b WHERE b.owner_id = v_owner_id AND b.data_inicio <= p_data AND COALESCE(b.data_fim, p_data) >= p_data AND b.hora_inicio IS NULL -- bloqueio de dia inteiro AND ( (NOT b.recorrente) OR (b.recorrente AND b.dia_semana = v_db_dow) ) ) THEN RETURN; END IF; FOR v_slot IN SELECT s.time FROM public.agenda_online_slots s WHERE s.owner_id = v_owner_id AND s.weekday = v_db_dow AND s.enabled = true ORDER BY s.time LOOP v_slot_fim := v_slot + (v_duracao || ' minutes')::interval; v_ocupado := false; -- ?????? Anteced??ncia m??nima ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? v_slot_ts := (p_data::text || ' ' || v_slot::text)::timestamp AT TIME ZONE 'America/Sao_Paulo'; IF v_slot_ts < v_agora + (v_antecedencia || ' hours')::interval THEN v_ocupado := true; END IF; -- ?????? Bloqueio de hor??rio espec??fico (agenda_bloqueios com hora) ????????????????????????????????? IF NOT v_ocupado THEN SELECT EXISTS ( SELECT 1 FROM public.agenda_bloqueios b WHERE b.owner_id = v_owner_id AND b.data_inicio <= p_data AND COALESCE(b.data_fim, p_data) >= p_data AND b.hora_inicio IS NOT NULL AND b.hora_inicio < v_slot_fim AND b.hora_fim > v_slot AND ( (NOT b.recorrente) OR (b.recorrente AND b.dia_semana = v_db_dow) ) ) INTO v_ocupado; END IF; -- ?????? Eventos avulsos internos (agenda_eventos) ???????????????????????????????????????????????????????????????????????????????????? IF NOT v_ocupado THEN SELECT EXISTS ( SELECT 1 FROM public.agenda_eventos e WHERE e.owner_id = v_owner_id AND e.status::text NOT IN ('cancelado', 'faltou') AND (e.inicio_em AT TIME ZONE 'America/Sao_Paulo')::date = p_data AND (e.inicio_em AT TIME ZONE 'America/Sao_Paulo')::time < v_slot_fim AND (e.fim_em AT TIME ZONE 'America/Sao_Paulo')::time > v_slot ) INTO v_ocupado; END IF; -- ?????? Recorr??ncias ativas (recurrence_rules) ????????????????????????????????????????????????????????????????????????????????????????????? IF NOT v_ocupado THEN FOR v_rule IN SELECT r.id, r.start_date::date AS start_date, r.end_date::date AS end_date, r.start_time::time AS start_time, r.end_time::time AS end_time, COALESCE(r.interval, 1)::int AS interval FROM public.recurrence_rules r WHERE r.owner_id = v_owner_id AND r.status = 'ativo' AND p_data >= r.start_date::date AND (r.end_date IS NULL OR p_data <= r.end_date::date) AND v_db_dow = ANY(r.weekdays) AND r.start_time::time < v_slot_fim AND r.end_time::time > v_slot LOOP v_rule_start_dow := extract(dow from v_rule.start_date)::int; v_first_occ := v_rule.start_date + (((v_db_dow - v_rule_start_dow + 7) % 7))::int; v_day_diff := (p_data - v_first_occ)::int; IF v_day_diff >= 0 AND v_day_diff % (7 * v_rule.interval) = 0 THEN v_ex_type := NULL; SELECT ex.type INTO v_ex_type FROM public.recurrence_exceptions ex WHERE ex.recurrence_id = v_rule.id AND ex.original_date = p_data LIMIT 1; IF v_ex_type IS NULL OR v_ex_type NOT IN ( 'cancel_session', 'patient_missed', 'therapist_canceled', 'holiday_block', 'reschedule_session' ) THEN v_ocupado := true; EXIT; END IF; END IF; END LOOP; END IF; -- ?????? Recorr??ncias remarcadas para este dia ???????????????????????????????????????????????????????????????????????????????????????????????? IF NOT v_ocupado THEN SELECT EXISTS ( SELECT 1 FROM public.recurrence_exceptions ex JOIN public.recurrence_rules r ON r.id = ex.recurrence_id WHERE r.owner_id = v_owner_id AND r.status = 'ativo' AND ex.type = 'reschedule_session' AND ex.new_date = p_data AND COALESCE(ex.new_start_time, r.start_time)::time < v_slot_fim AND COALESCE(ex.new_end_time, r.end_time)::time > v_slot ) INTO v_ocupado; END IF; -- ?????? Solicita????es p??blicas pendentes ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????? IF NOT v_ocupado THEN SELECT EXISTS ( SELECT 1 FROM public.agendador_solicitacoes sol WHERE sol.owner_id = v_owner_id AND sol.status = 'pendente' AND sol.data_solicitada = p_data AND sol.hora_solicitada = v_slot AND (sol.reservado_ate IS NULL OR sol.reservado_ate > v_agora) ) INTO v_ocupado; END IF; hora := v_slot; disponivel := NOT v_ocupado; RETURN NEXT; END LOOP; END; $$; -- -- Name: auto_create_financial_record_from_session(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.auto_create_financial_record_from_session() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_price NUMERIC(10,2); v_services_total NUMERIC(10,2); v_already_billed BOOLEAN; BEGIN -- ?????? Guards de sa??da r??pida ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? -- S?? processa quando o status muda PARA 'realizado' IF NEW.status::TEXT <> 'realizado' THEN RETURN NEW; END IF; -- S?? processa quando houve mudan??a real de status IF OLD.status IS NOT DISTINCT FROM NEW.status THEN RETURN NEW; END IF; -- S?? sess??es (n??o bloqueios, feriados, etc.) IF NEW.tipo::TEXT <> 'sessao' THEN RETURN NEW; END IF; -- Paciente obrigat??rio para vincular a cobran??a IF NEW.patient_id IS NULL THEN RETURN NEW; END IF; -- Sess??es de pacote t??m cobran??a gerenciada por billing_contract IF NEW.billing_contract_id IS NOT NULL THEN RETURN NEW; END IF; -- Idempot??ncia: j?? existe financial_record para este evento? SELECT billed INTO v_already_billed FROM public.agenda_eventos WHERE id = NEW.id; IF v_already_billed = TRUE THEN -- Confirma no financial_records tamb??m (dupla verifica????o) IF EXISTS ( SELECT 1 FROM public.financial_records WHERE agenda_evento_id = NEW.id AND deleted_at IS NULL ) THEN RETURN NEW; END IF; END IF; -- ?????? Busca do pre??o ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? v_price := NULL; -- Prioridade 1: soma dos servi??os da regra de recorr??ncia IF NEW.recurrence_id IS NOT NULL THEN SELECT COALESCE(SUM(rrs.final_price), 0) INTO v_services_total FROM public.recurrence_rule_services rrs WHERE rrs.rule_id = NEW.recurrence_id; IF v_services_total > 0 THEN v_price := v_services_total; END IF; -- Prioridade 2: price direto da regra (fallback se sem servi??os) IF v_price IS NULL OR v_price = 0 THEN SELECT price INTO v_price FROM public.recurrence_rules WHERE id = NEW.recurrence_id; END IF; END IF; -- Prioridade 3: price do pr??prio evento de agenda IF v_price IS NULL OR v_price = 0 THEN v_price := NEW.price; END IF; -- Sem pre??o ??? n??o criar registro (n??o ?? erro, apenas skip silencioso) IF v_price IS NULL OR v_price <= 0 THEN RETURN NEW; END IF; -- ?????? Cria????o do financial_record ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? INSERT INTO public.financial_records ( owner_id, tenant_id, patient_id, agenda_evento_id, type, amount, discount_amount, final_amount, clinic_fee_pct, clinic_fee_amount, status, due_date -- payment_method: NULL at?? o momento do pagamento (mark_as_paid preenche) ) VALUES ( NEW.owner_id, NEW.tenant_id, NEW.patient_id, NEW.id, 'receita', v_price, 0, v_price, 0, -- clinic_fee_pct: sem campo de configura????o global no schema atual. 0, -- clinic_fee_amount: calculado manualmente ou via update posterior. 'pending', (NEW.inicio_em::DATE + 7) -- vencimento padr??o: 7 dias ap??s a sess??o ); -- ?????? Marca sess??o como billed ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? -- UPDATE em billed (n??o em status) ??? n??o re-dispara este trigger UPDATE public.agenda_eventos SET billed = TRUE WHERE id = NEW.id; RETURN NEW; EXCEPTION WHEN OTHERS THEN -- Log silencioso: nunca bloquear a agenda por falha financeira RAISE WARNING '[auto_create_financial_record_from_session] evento=% erro=%', NEW.id, SQLERRM; RETURN NEW; END; $$; -- -- Name: FUNCTION auto_create_financial_record_from_session(); Type: COMMENT; Schema: public; Owner: - -- COMMENT ON FUNCTION public.auto_create_financial_record_from_session() IS 'Trigger que cria automaticamente um financial_record (receita, pending) quando uma sess??o de agenda ?? marcada como realizada. Prioridade de pre??o: recurrence_rule_services > recurrence_rules.price > agenda_eventos.price. Skip silencioso se sem pre??o, pacote ou registro j?? existente.'; -- -- Name: can_delete_patient(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.can_delete_patient(p_patient_id uuid) RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER AS $$ SELECT NOT EXISTS ( SELECT 1 FROM public.agenda_eventos WHERE patient_id = p_patient_id UNION ALL SELECT 1 FROM public.recurrence_rules WHERE patient_id = p_patient_id UNION ALL SELECT 1 FROM public.billing_contracts WHERE patient_id = p_patient_id ); $$; -- -- Name: cancel_notifications_on_opt_out(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.cancel_notifications_on_opt_out() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER AS $$ BEGIN -- WhatsApp opt-out IF OLD.whatsapp_opt_in = true AND NEW.whatsapp_opt_in = false THEN PERFORM public.cancel_patient_pending_notifications( NEW.patient_id, 'whatsapp' ); END IF; -- Email opt-out IF OLD.email_opt_in = true AND NEW.email_opt_in = false THEN PERFORM public.cancel_patient_pending_notifications( NEW.patient_id, 'email' ); END IF; -- SMS opt-out IF OLD.sms_opt_in = true AND NEW.sms_opt_in = false THEN PERFORM public.cancel_patient_pending_notifications( NEW.patient_id, 'sms' ); END IF; RETURN NEW; END; $$; -- -- Name: cancel_notifications_on_session_cancel(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.cancel_notifications_on_session_cancel() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER AS $$ BEGIN IF NEW.status IN ('cancelado', 'excluido') AND OLD.status NOT IN ('cancelado', 'excluido') THEN PERFORM public.cancel_patient_pending_notifications( NEW.patient_id, NULL, NEW.id ); END IF; RETURN NEW; END; $$; -- -- Name: cancel_patient_pending_notifications(uuid, text, uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.cancel_patient_pending_notifications(p_patient_id uuid, p_channel text DEFAULT NULL::text, p_evento_id uuid DEFAULT NULL::uuid) RETURNS integer LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE v_canceled integer; BEGIN UPDATE public.notification_queue SET status = 'cancelado', updated_at = now() WHERE patient_id = p_patient_id AND status IN ('pendente', 'processando') AND (p_channel IS NULL OR channel = p_channel) AND (p_evento_id IS NULL OR agenda_evento_id = p_evento_id); GET DIAGNOSTICS v_canceled = ROW_COUNT; RETURN v_canceled; END; $$; -- -- Name: cancel_recurrence_from(uuid, date); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.cancel_recurrence_from(p_recurrence_id uuid, p_from_date date) RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ BEGIN UPDATE public.recurrence_rules SET end_date = p_from_date - INTERVAL '1 day', open_ended = false, status = CASE WHEN p_from_date <= start_date THEN 'cancelado' ELSE status END, updated_at = now() WHERE id = p_recurrence_id; END; $$; -- -- Name: cancel_subscription(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.cancel_subscription(p_subscription_id uuid) RETURNS public.subscriptions LANGUAGE plpgsql SECURITY DEFINER AS $$ declare v_sub public.subscriptions; v_owner_type text; v_owner_ref uuid; begin select * into v_sub from public.subscriptions where id = p_subscription_id for update; if not found then raise exception 'Subscription n??o encontrada'; end if; if v_sub.status = 'canceled' then return v_sub; end if; if v_sub.tenant_id is not null then v_owner_type := 'clinic'; v_owner_ref := v_sub.tenant_id; elsif v_sub.user_id is not null then v_owner_type := 'therapist'; v_owner_ref := v_sub.user_id; else v_owner_type := null; v_owner_ref := null; end if; update public.subscriptions set status = 'canceled', cancel_at_period_end = false, updated_at = now() where id = p_subscription_id returning * into v_sub; insert into public.subscription_events( subscription_id, owner_id, owner_type, owner_ref, event_type, old_plan_id, new_plan_id, created_by, reason, source, metadata ) values ( v_sub.id, v_owner_ref, v_owner_type, v_owner_ref, 'canceled', v_sub.plan_id, v_sub.plan_id, auth.uid(), 'Cancelamento manual via admin', 'admin_panel', jsonb_build_object('previous_status', 'active') ); if v_owner_ref is not null then insert into public.entitlements_invalidation(owner_id, changed_at) values (v_owner_ref, now()) on conflict (owner_id) do update set changed_at = excluded.changed_at; end if; return v_sub; end; $$; -- -- Name: cancelar_eventos_serie(uuid, timestamp with time zone); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.cancelar_eventos_serie(p_serie_id uuid, p_a_partir_de timestamp with time zone DEFAULT now()) RETURNS integer LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE v_count integer; BEGIN UPDATE public.agenda_eventos SET status = 'cancelado', updated_at = now() WHERE serie_id = p_serie_id AND inicio_em >= p_a_partir_de AND status NOT IN ('realizado', 'cancelado'); GET DIAGNOSTICS v_count = ROW_COUNT; RETURN v_count; END; $$; -- -- Name: FUNCTION cancelar_eventos_serie(p_serie_id uuid, p_a_partir_de timestamp with time zone); Type: COMMENT; Schema: public; Owner: - -- COMMENT ON FUNCTION public.cancelar_eventos_serie(p_serie_id uuid, p_a_partir_de timestamp with time zone) IS 'Cancela todos os eventos futuros de uma s??rie a partir de p_a_partir_de (inclusive). N??o cancela eventos j?? realizados.'; -- -- Name: change_subscription_plan(uuid, uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.change_subscription_plan(p_subscription_id uuid, p_new_plan_id uuid) RETURNS public.subscriptions LANGUAGE plpgsql SECURITY DEFINER AS $$ declare v_sub public.subscriptions; v_old_plan uuid; v_new_key text; v_owner_type text; v_owner_ref uuid; v_new_target text; v_sub_target text; begin select * into v_sub from public.subscriptions where id = p_subscription_id for update; if not found then raise exception 'Subscription n??o encontrada'; end if; v_old_plan := v_sub.plan_id; if v_old_plan = p_new_plan_id then return v_sub; end if; select key, target into v_new_key, v_new_target from public.plans where id = p_new_plan_id; if v_new_key is null then raise exception 'Plano n??o encontrado'; end if; v_new_target := lower(coalesce(v_new_target, '')); v_sub_target := case when v_sub.tenant_id is not null then 'clinic' else 'therapist' end; if v_new_target <> v_sub_target then raise exception 'Plano inv??lido para este tipo de assinatura. Assinatura ?? % e o plano ?? %.', v_sub_target, v_new_target using errcode = 'P0001'; end if; if v_sub.tenant_id is not null then v_owner_type := 'clinic'; v_owner_ref := v_sub.tenant_id; elsif v_sub.user_id is not null then v_owner_type := 'therapist'; v_owner_ref := v_sub.user_id; else v_owner_type := null; v_owner_ref := null; end if; update public.subscriptions set plan_id = p_new_plan_id, plan_key = v_new_key, updated_at = now() where id = p_subscription_id returning * into v_sub; insert into public.subscription_events( subscription_id, owner_id, owner_type, owner_ref, event_type, old_plan_id, new_plan_id, created_by, reason, source, metadata ) values ( v_sub.id, v_owner_ref, v_owner_type, v_owner_ref, 'plan_changed', v_old_plan, p_new_plan_id, auth.uid(), 'Plan change via DEV menu', 'dev_menu', jsonb_build_object( 'previous_plan', v_old_plan, 'new_plan', p_new_plan_id, 'new_plan_key', v_new_key, 'new_plan_target', v_new_target ) ); if v_owner_ref is not null then insert into public.entitlements_invalidation (owner_id, changed_at) values (v_owner_ref, now()) on conflict (owner_id) do update set changed_at = excluded.changed_at; end if; return v_sub; end; $$; -- -- Name: cleanup_notification_queue(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.cleanup_notification_queue() RETURNS integer LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE v_deleted integer; BEGIN DELETE FROM public.notification_queue WHERE status IN ('enviado', 'cancelado', 'ignorado') AND created_at < now() - interval '90 days'; GET DIAGNOSTICS v_deleted = ROW_COUNT; RETURN v_deleted; END; $$; -- -- Name: create_clinic_tenant(text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.create_clinic_tenant(p_name text) RETURNS uuid LANGUAGE plpgsql SECURITY DEFINER AS $$ declare v_uid uuid; v_tenant uuid; v_name text; begin v_uid := auth.uid(); if v_uid is null then raise exception 'Not authenticated'; end if; v_name := nullif(trim(coalesce(p_name, '')), ''); if v_name is null then v_name := 'Cl??nica'; end if; insert into public.tenants (name, kind, created_at) values (v_name, 'clinic', now()) returning id into v_tenant; insert into public.tenant_members (tenant_id, user_id, role, status, created_at) values (v_tenant, v_uid, 'tenant_admin', 'active', now()); return v_tenant; end; $$; -- -- Name: financial_records; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.financial_records ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, tenant_id uuid, type public.financial_record_type DEFAULT 'receita'::public.financial_record_type NOT NULL, amount numeric(10,2) NOT NULL, description text, category text, payment_method text, paid_at timestamp with time zone, due_date date, installments smallint DEFAULT 1, installment_number smallint DEFAULT 1, installment_group uuid, agenda_evento_id uuid, patient_id uuid, clinic_fee_pct numeric(5,2) DEFAULT 0, clinic_fee_amount numeric(10,2) DEFAULT 0, net_amount numeric(10,2) GENERATED ALWAYS AS ((amount - clinic_fee_amount)) STORED, insurance_plan_id uuid, notes text, tags text[], created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, deleted_at timestamp with time zone, discount_amount numeric(10,2) DEFAULT 0 NOT NULL, final_amount numeric(10,2) DEFAULT 0 NOT NULL, status text DEFAULT 'pending'::text NOT NULL, category_id uuid, CONSTRAINT financial_records_amount_check CHECK ((amount >= (0)::numeric)), CONSTRAINT financial_records_clinic_fee_amount_check CHECK ((clinic_fee_amount >= (0)::numeric)), CONSTRAINT financial_records_clinic_fee_pct_check CHECK (((clinic_fee_pct >= (0)::numeric) AND (clinic_fee_pct <= (100)::numeric))), CONSTRAINT financial_records_discount_amount_check CHECK ((discount_amount >= (0)::numeric)), CONSTRAINT financial_records_final_amount_check CHECK ((final_amount >= (0)::numeric)), CONSTRAINT financial_records_installments_check CHECK ((installments >= 1)), CONSTRAINT financial_records_status_check CHECK ((status = ANY (ARRAY['pending'::text, 'paid'::text, 'partial'::text, 'overdue'::text, 'cancelled'::text, 'refunded'::text]))) ); -- -- Name: create_financial_record_for_session(uuid, uuid, uuid, uuid, numeric, date); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.create_financial_record_for_session(p_tenant_id uuid, p_owner_id uuid, p_patient_id uuid, p_agenda_evento_id uuid, p_amount numeric, p_due_date date) RETURNS SETOF public.financial_records LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_existing public.financial_records%ROWTYPE; v_new public.financial_records%ROWTYPE; BEGIN -- Idempot??ncia: retorna o registro existente se j?? foi criado SELECT * INTO v_existing FROM public.financial_records WHERE agenda_evento_id = p_agenda_evento_id AND deleted_at IS NULL LIMIT 1; IF FOUND THEN RETURN NEXT v_existing; RETURN; END IF; -- Cria o novo registro INSERT INTO public.financial_records ( tenant_id, owner_id, patient_id, agenda_evento_id, amount, discount_amount, final_amount, status, due_date ) VALUES ( p_tenant_id, p_owner_id, p_patient_id, p_agenda_evento_id, p_amount, 0, p_amount, 'pending', p_due_date ) RETURNING * INTO v_new; -- Marca o evento da agenda como billed = true UPDATE public.agenda_eventos SET billed = TRUE WHERE id = p_agenda_evento_id; RETURN NEXT v_new; END; $$; -- -- Name: create_patient_intake_request(text, text, text, text, text, boolean); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.create_patient_intake_request(p_token text, p_name text, p_email text DEFAULT NULL::text, p_phone text DEFAULT NULL::text, p_notes text DEFAULT NULL::text, p_consent boolean DEFAULT false) RETURNS uuid LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ declare v_owner uuid; v_active boolean; v_expires timestamptz; v_max_uses int; v_uses int; v_id uuid; begin select owner_id, active, expires_at, max_uses, uses into v_owner, v_active, v_expires, v_max_uses, v_uses from public.patient_invites where token = p_token limit 1; if v_owner is null then raise exception 'Token inv??lido'; end if; if v_active is not true then raise exception 'Link desativado'; end if; if v_expires is not null and now() > v_expires then raise exception 'Link expirado'; end if; if v_max_uses is not null and v_uses >= v_max_uses then raise exception 'Limite de uso atingido'; end if; if p_name is null or length(trim(p_name)) = 0 then raise exception 'Nome ?? obrigat??rio'; end if; insert into public.patient_intake_requests (owner_id, token, name, email, phone, notes, consent, status) values (v_owner, p_token, trim(p_name), nullif(lower(trim(p_email)), ''), nullif(trim(p_phone), ''), nullif(trim(p_notes), ''), coalesce(p_consent, false), 'new') returning id into v_id; update public.patient_invites set uses = uses + 1 where token = p_token; return v_id; end; $$; -- -- Name: create_patient_intake_request_v2(text, jsonb); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.create_patient_intake_request_v2(p_token text, p_payload jsonb) RETURNS uuid LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $_$ declare v_owner_id uuid; v_intake_id uuid; v_birth_raw text; v_birth date; begin select owner_id into v_owner_id from public.patient_invites where token = p_token; if v_owner_id is null then raise exception 'Token inv??lido ou expirado'; end if; v_birth_raw := nullif(trim(coalesce( p_payload->>'data_nascimento', '' )), ''); v_birth := case when v_birth_raw is null then null when v_birth_raw ~ '^\d{4}-\d{2}-\d{2}$' then v_birth_raw::date when v_birth_raw ~ '^\d{2}-\d{2}-\d{4}$' then to_date(v_birth_raw, 'DD-MM-YYYY') else null end; insert into public.patient_intake_requests ( owner_id, token, status, consent, nome_completo, email_principal, telefone, avatar_url, -- ???? AQUI data_nascimento, cpf, rg, genero, estado_civil, profissao, escolaridade, nacionalidade, naturalidade, cep, pais, cidade, estado, endereco, numero, complemento, bairro, observacoes, notas_internas, encaminhado_por, onde_nos_conheceu ) values ( v_owner_id, p_token, 'new', coalesce((p_payload->>'consent')::boolean, false), nullif(trim(p_payload->>'nome_completo'), ''), nullif(trim(p_payload->>'email_principal'), ''), nullif(regexp_replace(coalesce(p_payload->>'telefone',''), '\D', '', 'g'), ''), nullif(trim(p_payload->>'avatar_url'), ''), -- ???? AQUI v_birth, nullif(regexp_replace(coalesce(p_payload->>'cpf',''), '\D', '', 'g'), ''), nullif(trim(p_payload->>'rg'), ''), nullif(trim(p_payload->>'genero'), ''), nullif(trim(p_payload->>'estado_civil'), ''), nullif(trim(p_payload->>'profissao'), ''), nullif(trim(p_payload->>'escolaridade'), ''), nullif(trim(p_payload->>'nacionalidade'), ''), nullif(trim(p_payload->>'naturalidade'), ''), nullif(regexp_replace(coalesce(p_payload->>'cep',''), '\D', '', 'g'), ''), nullif(trim(p_payload->>'pais'), ''), nullif(trim(p_payload->>'cidade'), ''), nullif(trim(p_payload->>'estado'), ''), nullif(trim(p_payload->>'endereco'), ''), nullif(trim(p_payload->>'numero'), ''), nullif(trim(p_payload->>'complemento'), ''), nullif(trim(p_payload->>'bairro'), ''), nullif(trim(p_payload->>'observacoes'), ''), nullif(trim(p_payload->>'notas_internas'), ''), nullif(trim(p_payload->>'encaminhado_por'), ''), nullif(trim(p_payload->>'onde_nos_conheceu'), '') ) returning id into v_intake_id; return v_intake_id; end; $_$; -- -- Name: create_support_session(uuid, integer); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.create_support_session(p_tenant_id uuid, p_ttl_minutes integer DEFAULT 60) RETURNS json LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_admin_id uuid; v_role text; v_token text; v_expires timestamp with time zone; v_session support_sessions; BEGIN -- Verifica autentica????o v_admin_id := auth.uid(); IF v_admin_id IS NULL THEN RAISE EXCEPTION 'N??o autenticado.' USING ERRCODE = 'P0001'; END IF; -- Verifica role saas_admin SELECT role INTO v_role FROM public.profiles WHERE id = v_admin_id; IF v_role <> 'saas_admin' THEN RAISE EXCEPTION 'Acesso negado. Somente saas_admin pode criar sess??es de suporte.' USING ERRCODE = 'P0002'; END IF; -- Valida TTL (1 a 120 minutos) IF p_ttl_minutes < 1 OR p_ttl_minutes > 120 THEN RAISE EXCEPTION 'TTL inv??lido. Use entre 1 e 120 minutos.' USING ERRCODE = 'P0003'; END IF; -- Valida tenant IF NOT EXISTS (SELECT 1 FROM public.tenants WHERE id = p_tenant_id) THEN RAISE EXCEPTION 'Tenant n??o encontrado.' USING ERRCODE = 'P0004'; END IF; -- Gera token ??nico (64 chars hex, sem pgcrypto) v_token := replace(gen_random_uuid()::text, '-', '') || replace(gen_random_uuid()::text, '-', ''); v_expires := now() + (p_ttl_minutes || ' minutes')::interval; -- Insere sess??o INSERT INTO public.support_sessions (tenant_id, admin_id, token, expires_at) VALUES (p_tenant_id, v_admin_id, v_token, v_expires) RETURNING * INTO v_session; RETURN json_build_object( 'token', v_session.token, 'expires_at', v_session.expires_at, 'session_id', v_session.id ); END; $$; -- -- Name: therapist_payouts; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.therapist_payouts ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, tenant_id uuid NOT NULL, period_start date NOT NULL, period_end date NOT NULL, total_sessions integer DEFAULT 0 NOT NULL, gross_amount numeric(10,2) DEFAULT 0 NOT NULL, clinic_fee_total numeric(10,2) DEFAULT 0 NOT NULL, net_amount numeric(10,2) DEFAULT 0 NOT NULL, status text DEFAULT 'pending'::text NOT NULL, paid_at timestamp with time zone, notes text, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT therapist_payouts_clinic_fee_total_check CHECK ((clinic_fee_total >= (0)::numeric)), CONSTRAINT therapist_payouts_gross_amount_check CHECK ((gross_amount >= (0)::numeric)), CONSTRAINT therapist_payouts_net_amount_check CHECK ((net_amount >= (0)::numeric)), CONSTRAINT therapist_payouts_period_chk CHECK ((period_end >= period_start)), CONSTRAINT therapist_payouts_status_check CHECK ((status = ANY (ARRAY['pending'::text, 'paid'::text, 'cancelled'::text]))) ); -- -- Name: create_therapist_payout(uuid, uuid, date, date); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.create_therapist_payout(p_tenant_id uuid, p_therapist_id uuid, p_period_start date, p_period_end date) RETURNS public.therapist_payouts LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_payout public.therapist_payouts%ROWTYPE; v_total_sessions INTEGER; v_gross NUMERIC(10,2); v_clinic_fee NUMERIC(10,2); v_net NUMERIC(10,2); BEGIN -- ?????? Verifica????o de permiss??o ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? -- Apenas o pr??prio terapeuta ou o tenant_admin pode criar o repasse IF auth.uid() <> p_therapist_id AND NOT public.is_tenant_admin(p_tenant_id) THEN RAISE EXCEPTION 'Sem permiss??o para criar repasse para este terapeuta.'; END IF; -- ?????? Verifica se j?? existe repasse para o mesmo per??odo ??????????????????????????????????????????????????? IF EXISTS ( SELECT 1 FROM public.therapist_payouts WHERE owner_id = p_therapist_id AND tenant_id = p_tenant_id AND period_start = p_period_start AND period_end = p_period_end AND status <> 'cancelled' ) THEN RAISE EXCEPTION 'J?? existe um repasse ativo para o per??odo % a % deste terapeuta.', p_period_start, p_period_end; END IF; -- ?????? Agrega os financial_records eleg??veis ?????????????????????????????????????????????????????????????????????????????????????????? -- Eleg??veis: paid, receita, owner=terapeuta, tenant correto, paid_at no per??odo, -- n??o soft-deleted, ainda n??o vinculados a nenhum payout. SELECT COUNT(*) AS total_sessions, COALESCE(SUM(amount), 0) AS gross_amount, COALESCE(SUM(clinic_fee_amount), 0) AS clinic_fee_total, COALESCE(SUM(net_amount), 0) AS net_amount INTO v_total_sessions, v_gross, v_clinic_fee, v_net FROM public.financial_records fr WHERE fr.owner_id = p_therapist_id AND fr.tenant_id = p_tenant_id AND fr.type = 'receita' AND fr.status = 'paid' AND fr.deleted_at IS NULL AND fr.paid_at::DATE BETWEEN p_period_start AND p_period_end AND NOT EXISTS ( SELECT 1 FROM public.therapist_payout_records tpr WHERE tpr.financial_record_id = fr.id ); -- Sem registros eleg??veis ??? n??o criar payout vazio IF v_total_sessions = 0 THEN RAISE EXCEPTION 'Nenhum registro financeiro eleg??vel encontrado para o per??odo % a %.', p_period_start, p_period_end; END IF; -- ?????? Cria o repasse ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? INSERT INTO public.therapist_payouts ( owner_id, tenant_id, period_start, period_end, total_sessions, gross_amount, clinic_fee_total, net_amount, status ) VALUES ( p_therapist_id, p_tenant_id, p_period_start, p_period_end, v_total_sessions, v_gross, v_clinic_fee, v_net, 'pending' ) RETURNING * INTO v_payout; -- ?????? Vincula os financial_records ao repasse ???????????????????????????????????????????????????????????????????????????????????? INSERT INTO public.therapist_payout_records (payout_id, financial_record_id) SELECT v_payout.id, fr.id FROM public.financial_records fr WHERE fr.owner_id = p_therapist_id AND fr.tenant_id = p_tenant_id AND fr.type = 'receita' AND fr.status = 'paid' AND fr.deleted_at IS NULL AND fr.paid_at::DATE BETWEEN p_period_start AND p_period_end AND NOT EXISTS ( SELECT 1 FROM public.therapist_payout_records tpr WHERE tpr.financial_record_id = fr.id ); RETURN v_payout; END; $$; -- -- Name: FUNCTION create_therapist_payout(p_tenant_id uuid, p_therapist_id uuid, p_period_start date, p_period_end date); Type: COMMENT; Schema: public; Owner: - -- COMMENT ON FUNCTION public.create_therapist_payout(p_tenant_id uuid, p_therapist_id uuid, p_period_start date, p_period_end date) IS 'Cria um repasse para o terapeuta com todos os financial_records paid+receita do per??odo que ainda n??o estejam vinculados a outro repasse. Lan??a exce????o se n??o houver registros eleg??veis ou se j?? houver repasse ativo no per??odo.'; -- -- Name: current_member_id(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.current_member_id(p_tenant_id uuid) RETURNS uuid LANGUAGE sql STABLE AS $$ select tm.id from public.tenant_members tm where tm.tenant_id = p_tenant_id and tm.user_id = auth.uid() limit 1 $$; -- -- Name: current_member_role(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.current_member_role(p_tenant_id uuid) RETURNS text LANGUAGE sql STABLE AS $$ select tm.role from public.tenant_members tm where tm.tenant_id = p_tenant_id and tm.user_id = auth.uid() limit 1 $$; -- -- Name: debit_addon_credit(uuid, text, uuid, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.debit_addon_credit(p_tenant_id uuid, p_addon_type text, p_queue_id uuid DEFAULT NULL::uuid, p_description text DEFAULT 'Consumo'::text) RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_credit addon_credits%ROWTYPE; v_balance_before INTEGER; v_balance_after INTEGER; BEGIN -- Lock e leitura SELECT * INTO v_credit FROM addon_credits WHERE tenant_id = p_tenant_id AND addon_type = p_addon_type AND is_active = true FOR UPDATE; IF NOT FOUND THEN RETURN jsonb_build_object('success', false, 'reason', 'no_credits', 'balance', 0); END IF; -- Verifica saldo IF v_credit.balance <= 0 THEN RETURN jsonb_build_object('success', false, 'reason', 'insufficient_balance', 'balance', 0); END IF; -- Verifica rate limit di??rio IF v_credit.daily_limit IS NOT NULL THEN -- Reset se passou do dia IF v_credit.daily_reset_at IS NULL OR v_credit.daily_reset_at < date_trunc('day', now()) THEN UPDATE addon_credits SET daily_used = 0, daily_reset_at = date_trunc('day', now()) + interval '1 day' WHERE id = v_credit.id; v_credit.daily_used := 0; END IF; IF v_credit.daily_used >= v_credit.daily_limit THEN RETURN jsonb_build_object('success', false, 'reason', 'daily_limit_reached', 'balance', v_credit.balance); END IF; END IF; -- Verifica rate limit hor??rio IF v_credit.hourly_limit IS NOT NULL THEN IF v_credit.hourly_reset_at IS NULL OR v_credit.hourly_reset_at < date_trunc('hour', now()) THEN UPDATE addon_credits SET hourly_used = 0, hourly_reset_at = date_trunc('hour', now()) + interval '1 hour' WHERE id = v_credit.id; v_credit.hourly_used := 0; END IF; IF v_credit.hourly_used >= v_credit.hourly_limit THEN RETURN jsonb_build_object('success', false, 'reason', 'hourly_limit_reached', 'balance', v_credit.balance); END IF; END IF; -- Verifica expira????o IF v_credit.expires_at IS NOT NULL AND v_credit.expires_at < now() THEN RETURN jsonb_build_object('success', false, 'reason', 'credits_expired', 'balance', v_credit.balance); END IF; v_balance_before := v_credit.balance; v_balance_after := v_credit.balance - 1; -- Debita UPDATE addon_credits SET balance = v_balance_after, total_consumed = total_consumed + 1, daily_used = COALESCE(daily_used, 0) + 1, hourly_used = COALESCE(hourly_used, 0) + 1, updated_at = now() WHERE id = v_credit.id; -- Registra transa????o INSERT INTO addon_transactions ( tenant_id, addon_type, type, amount, balance_before, balance_after, queue_id, description ) VALUES ( p_tenant_id, p_addon_type, 'consume', -1, v_balance_before, v_balance_after, p_queue_id, p_description ); RETURN jsonb_build_object( 'success', true, 'balance_before', v_balance_before, 'balance_after', v_balance_after ); END; $$; -- -- Name: FUNCTION debit_addon_credit(p_tenant_id uuid, p_addon_type text, p_queue_id uuid, p_description text); Type: COMMENT; Schema: public; Owner: - -- COMMENT ON FUNCTION public.debit_addon_credit(p_tenant_id uuid, p_addon_type text, p_queue_id uuid, p_description text) IS 'Debita 1 cr??dito de add-on. Verifica saldo, rate limits e expira????o.'; -- -- Name: delete_commitment_full(uuid, uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.delete_commitment_full(p_tenant_id uuid, p_commitment_id uuid) RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ declare v_is_native boolean; v_fields int := 0; v_logs int := 0; v_parent int := 0; begin if auth.uid() is null then raise exception 'Not authenticated'; end if; if not exists ( select 1 from public.tenant_members tm where tm.tenant_id = p_tenant_id and tm.user_id = auth.uid() and tm.status = 'active' ) then raise exception 'Not allowed'; end if; select dc.is_native into v_is_native from public.determined_commitments dc where dc.tenant_id = p_tenant_id and dc.id = p_commitment_id; if v_is_native is null then raise exception 'Commitment not found'; end if; if v_is_native = true then raise exception 'Cannot delete native commitment'; end if; delete from public.determined_commitment_fields where tenant_id = p_tenant_id and commitment_id = p_commitment_id; get diagnostics v_fields = row_count; delete from public.commitment_time_logs where tenant_id = p_tenant_id and commitment_id = p_commitment_id; get diagnostics v_logs = row_count; delete from public.determined_commitments where tenant_id = p_tenant_id and id = p_commitment_id; get diagnostics v_parent = row_count; if v_parent <> 1 then raise exception 'Parent not deleted (RLS/owner issue).'; end if; return jsonb_build_object( 'ok', true, 'deleted', jsonb_build_object( 'fields', v_fields, 'logs', v_logs, 'commitment', v_parent ) ); end; $$; -- -- Name: delete_determined_commitment(uuid, uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.delete_determined_commitment(p_tenant_id uuid, p_commitment_id uuid) RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ declare v_is_native boolean; v_fields_deleted int := 0; v_logs_deleted int := 0; v_commitment_deleted int := 0; begin if auth.uid() is null then raise exception 'Not authenticated'; end if; if not exists ( select 1 from public.tenant_members tm where tm.tenant_id = p_tenant_id and tm.user_id = auth.uid() and tm.status = 'active' ) then raise exception 'Not allowed'; end if; select dc.is_native into v_is_native from public.determined_commitments dc where dc.tenant_id = p_tenant_id and dc.id = p_commitment_id; if v_is_native is null then raise exception 'Commitment not found for tenant'; end if; if v_is_native = true then raise exception 'Cannot delete native commitment'; end if; delete from public.determined_commitment_fields f where f.tenant_id = p_tenant_id and f.commitment_id = p_commitment_id; get diagnostics v_fields_deleted = row_count; delete from public.commitment_time_logs l where l.tenant_id = p_tenant_id and l.commitment_id = p_commitment_id; get diagnostics v_logs_deleted = row_count; delete from public.determined_commitments dc where dc.tenant_id = p_tenant_id and dc.id = p_commitment_id; get diagnostics v_commitment_deleted = row_count; if v_commitment_deleted <> 1 then raise exception 'Delete did not remove the commitment (tenant mismatch?)'; end if; return jsonb_build_object( 'ok', true, 'tenant_id', p_tenant_id, 'commitment_id', p_commitment_id, 'deleted', jsonb_build_object( 'fields', v_fields_deleted, 'logs', v_logs_deleted, 'commitment', v_commitment_deleted ) ); end; $$; -- -- Name: dev_list_auth_users(integer); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.dev_list_auth_users(p_limit integer DEFAULT 50) RETURNS TABLE(id uuid, email text, created_at timestamp with time zone) LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public', 'auth' AS $$ begin -- s?? saas_admin pode ver if not exists ( select 1 from public.profiles p where p.id = auth.uid() and p.role = 'saas_admin' ) then return; end if; return query select u.id, u.email, u.created_at from auth.users u order by u.created_at desc limit greatest(1, least(coalesce(p_limit, 50), 500)); end; $$; -- -- Name: dev_list_custom_users(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.dev_list_custom_users() RETURNS TABLE(user_id uuid, email text, created_at timestamp with time zone, global_role text, tenant_role text, tenant_id uuid, password_dev text, kind text) LANGUAGE sql SECURITY DEFINER SET search_path TO 'public' AS $$ with base as ( select u.id as user_id, lower(u.email) as email, u.created_at from auth.users u where lower(u.email) not in ( 'clinic@agenciapsi.com.br', 'therapist@agenciapsi.com.br', 'patient@agenciapsi.com.br', 'saas@agenciapsi.com.br' ) ), prof as ( select p.id, p.role as global_role from public.profiles p ), last_membership as ( select distinct on (tm.user_id) tm.user_id, tm.tenant_id, tm.role as tenant_role, tm.created_at from public.tenant_members tm where tm.status = 'active' order by tm.user_id, tm.created_at desc ) select b.user_id, b.email, b.created_at, pr.global_role, lm.tenant_role, lm.tenant_id, dc.password_dev, dc.kind from base b left join prof pr on pr.id = b.user_id left join last_membership lm on lm.user_id = b.user_id left join public.dev_user_credentials dc on lower(dc.email) = b.email order by b.created_at desc; $$; -- -- Name: dev_list_intent_leads(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.dev_list_intent_leads() RETURNS TABLE(email text, last_intent_at timestamp with time zone, plan_key text, billing_interval text, status text, tenant_id uuid) LANGUAGE sql SECURITY DEFINER SET search_path TO 'public' AS $$ select lower(si.email) as email, max(si.created_at) as last_intent_at, (array_agg(si.plan_key order by si.created_at desc))[1] as plan_key, (array_agg(si.interval order by si.created_at desc))[1] as billing_interval, (array_agg(si.status order by si.created_at desc))[1] as status, (array_agg(si.tenant_id order by si.created_at desc))[1] as tenant_id from public.subscription_intents si where si.email is not null and not exists ( select 1 from auth.users au where lower(au.email) = lower(si.email) ) group by lower(si.email) order by max(si.created_at) desc; $$; -- -- Name: dev_public_debug_snapshot(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.dev_public_debug_snapshot() RETURNS TABLE(users_total integer, tenants_total integer, intents_new_total integer, latest_intents jsonb) LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $_$ declare v_latest jsonb; begin select jsonb_agg( jsonb_build_object( 'created_at', si.created_at, 'email_masked', regexp_replace(lower(si.email), '(^.).*(@.*$)', '\1***\2'), 'plan_key', si.plan_key, 'status', si.status ) order by si.created_at desc ) into v_latest from ( select si.* from public.subscription_intents si where si.email is not null order by si.created_at desc limit 5 ) si; return query select (select count(*)::int from auth.users) as users_total, (select count(*)::int from public.tenants) as tenants_total, (select count(*)::int from public.subscription_intents where status = 'new') as intents_new_total, coalesce(v_latest, '[]'::jsonb) as latest_intents; end; $_$; -- -- Name: ensure_personal_tenant(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.ensure_personal_tenant() RETURNS uuid LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE v_uid uuid; v_existing uuid; BEGIN v_uid := auth.uid(); IF v_uid IS NULL THEN RAISE EXCEPTION 'Not authenticated'; END IF; SELECT tm.tenant_id INTO v_existing FROM public.tenant_members tm JOIN public.tenants t ON t.id = tm.tenant_id WHERE tm.user_id = v_uid AND tm.status = 'active' AND t.kind IN ('therapist', 'saas') ORDER BY tm.created_at DESC LIMIT 1; IF v_existing IS NOT NULL THEN RETURN v_existing; END IF; RETURN public.provision_account_tenant(v_uid, 'therapist'); END; $$; -- -- Name: ensure_personal_tenant_for_user(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.ensure_personal_tenant_for_user(p_user_id uuid) RETURNS uuid LANGUAGE plpgsql SECURITY DEFINER AS $$ declare v_uid uuid; v_existing uuid; v_tenant uuid; v_email text; v_name text; begin v_uid := p_user_id; if v_uid is null then raise exception 'Missing user id'; end if; -- s?? considera tenant pessoal (kind='saas') select tm.tenant_id into v_existing from public.tenant_members tm join public.tenants t on t.id = tm.tenant_id where tm.user_id = v_uid and tm.status = 'active' and t.kind = 'saas' order by tm.created_at desc limit 1; if v_existing is not null then return v_existing; end if; select email into v_email from auth.users where id = v_uid; v_name := coalesce(split_part(v_email, '@', 1), 'Conta'); insert into public.tenants (name, kind, created_at) values (v_name || ' (Pessoal)', 'saas', now()) returning id into v_tenant; insert into public.tenant_members (tenant_id, user_id, role, status, created_at) values (v_tenant, v_uid, 'tenant_admin', 'active', now()); return v_tenant; end; $$; -- -- Name: faq_votar(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.faq_votar(faq_id uuid) RETURNS void LANGUAGE sql SECURITY DEFINER AS $$ update public.saas_faq set votos = votos + 1, updated_at = now() where id = faq_id and ativo = true; $$; -- -- Name: fix_all_subscription_mismatches(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.fix_all_subscription_mismatches() RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$ declare r record; begin for r in select distinct s.user_id as owner_id from public.subscriptions s where s.status = 'active' and s.user_id is not null loop perform public.rebuild_owner_entitlements(r.owner_id); end loop; end; $$; -- -- Name: fn_agenda_regras_semanais_no_overlap(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.fn_agenda_regras_semanais_no_overlap() RETURNS trigger LANGUAGE plpgsql AS $$ declare v_count int; begin if new.ativo is false then return new; end if; select count(*) into v_count from public.agenda_regras_semanais r where r.owner_id = new.owner_id and r.dia_semana = new.dia_semana and r.ativo is true and (tg_op = 'INSERT' or r.id <> new.id) and (new.hora_inicio < r.hora_fim and new.hora_fim > r.hora_inicio); if v_count > 0 then raise exception 'Janela sobreposta: j?? existe uma regra ativa nesse intervalo.'; end if; return new; end; $$; -- -- Name: get_financial_report(uuid, date, date, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.get_financial_report(p_owner_id uuid, p_start_date date, p_end_date date, p_group_by text DEFAULT 'month'::text) RETURNS TABLE(group_key text, group_label text, total_receitas numeric, total_despesas numeric, saldo numeric, total_pendente numeric, total_overdue numeric, count_records bigint) LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public' AS $$ -- ?????? Valida p_group_by antes de executar ?????????????????????????????????????????????????????????????????????????????????????????????????????? -- (lan??a erro se valor inv??lido; plpgsql seria necess??rio para isso em SQL puro, -- ent??o usamos um CTE de valida????o com CASE WHEN para retornar vazio em vez de erro) WITH base AS ( SELECT fr.type, fr.amount, fr.final_amount, fr.status, fr.deleted_at, -- Chave de agrupamento calculada conforme p_group_by CASE p_group_by WHEN 'month' THEN TO_CHAR( COALESCE(fr.paid_at::DATE, fr.due_date, fr.created_at::DATE), 'YYYY-MM' ) WHEN 'week' THEN TO_CHAR( COALESCE(fr.paid_at::DATE, fr.due_date, fr.created_at::DATE), 'IYYY-"W"IW' ) WHEN 'category' THEN COALESCE(fr.category_id::TEXT, fr.category, 'sem_categoria') WHEN 'patient' THEN COALESCE(fr.patient_id::TEXT, 'sem_paciente') ELSE NULL -- group_by inv??lido ??? group_key NULL ??? retorno vazio END AS gkey, -- Label leg??vel (enriquecido via JOIN abaixo quando poss??vel) CASE p_group_by WHEN 'month' THEN TO_CHAR( COALESCE(fr.paid_at::DATE, fr.due_date, fr.created_at::DATE), 'YYYY-MM' ) WHEN 'week' THEN TO_CHAR( COALESCE(fr.paid_at::DATE, fr.due_date, fr.created_at::DATE), 'IYYY-"W"IW' ) WHEN 'category' THEN COALESCE(fc.name, fr.category, 'Sem categoria') WHEN 'patient' THEN COALESCE(p.nome_completo, fr.patient_id::TEXT, 'Sem paciente') ELSE NULL END AS glabel FROM public.financial_records fr LEFT JOIN public.financial_categories fc ON fc.id = fr.category_id LEFT JOIN public.patients p ON p.id = fr.patient_id WHERE fr.owner_id = p_owner_id AND fr.deleted_at IS NULL AND COALESCE(fr.paid_at::DATE, fr.due_date, fr.created_at::DATE) BETWEEN p_start_date AND p_end_date ) SELECT gkey AS group_key, glabel AS group_label, COALESCE(SUM(final_amount) FILTER (WHERE type = 'receita' AND status = 'paid'), 0) AS total_receitas, COALESCE(SUM(final_amount) FILTER (WHERE type = 'despesa' AND status = 'paid'), 0) AS total_despesas, COALESCE(SUM(final_amount) FILTER (WHERE type = 'receita' AND status = 'paid'), 0) - COALESCE(SUM(final_amount) FILTER (WHERE type = 'despesa' AND status = 'paid'), 0) AS saldo, COALESCE(SUM(final_amount) FILTER (WHERE status = 'pending'), 0) AS total_pendente, COALESCE(SUM(final_amount) FILTER (WHERE status = 'overdue'), 0) AS total_overdue, COUNT(*) AS count_records FROM base WHERE gkey IS NOT NULL -- descarta p_group_by inv??lido GROUP BY gkey, glabel ORDER BY gkey ASC; $$; -- -- Name: FUNCTION get_financial_report(p_owner_id uuid, p_start_date date, p_end_date date, p_group_by text); Type: COMMENT; Schema: public; Owner: - -- COMMENT ON FUNCTION public.get_financial_report(p_owner_id uuid, p_start_date date, p_end_date date, p_group_by text) IS 'Relat??rio financeiro agrupado por m??s, semana ISO, categoria ou paciente. p_group_by aceita: ''month'' | ''week'' | ''category'' | ''patient''. Totais de receita/despesa consideram apenas registros com status=paid. total_pendente e total_overdue incluem todos os tipos (receita + despesa).'; -- -- Name: get_financial_summary(uuid, integer, integer); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.get_financial_summary(p_owner_id uuid, p_year integer, p_month integer) RETURNS TABLE(total_receitas numeric, total_despesas numeric, total_pendente numeric, saldo_liquido numeric, total_repasse numeric, count_receitas bigint, count_despesas bigint) LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public' AS $$ SELECT -- Receitas pagas no per??odo COALESCE(SUM(amount) FILTER ( WHERE type = 'receita' AND status = 'paid' ), 0) AS total_receitas, -- Despesas pagas no per??odo COALESCE(SUM(amount) FILTER ( WHERE type = 'despesa' AND status = 'paid' ), 0) AS total_despesas, -- Tudo pendente ou vencido (receitas + despesas) COALESCE(SUM(amount) FILTER ( WHERE status IN ('pending', 'overdue') ), 0) AS total_pendente, -- Saldo l??quido (receitas pagas ??? despesas pagas) COALESCE(SUM(amount) FILTER ( WHERE type = 'receita' AND status = 'paid' ), 0) - COALESCE(SUM(amount) FILTER ( WHERE type = 'despesa' AND status = 'paid' ), 0) AS saldo_liquido, -- Total repassado ?? cl??nica (apenas receitas pagas) COALESCE(SUM(clinic_fee_amount) FILTER ( WHERE type = 'receita' AND status = 'paid' ), 0) AS total_repasse, -- Contadores (excluindo soft-deleted) COUNT(*) FILTER (WHERE type = 'receita' AND deleted_at IS NULL) AS count_receitas, COUNT(*) FILTER (WHERE type = 'despesa' AND deleted_at IS NULL) AS count_despesas FROM public.financial_records WHERE owner_id = p_owner_id AND deleted_at IS NULL AND EXTRACT(YEAR FROM COALESCE(paid_at::DATE, due_date, created_at::DATE)) = p_year AND EXTRACT(MONTH FROM COALESCE(paid_at::DATE, due_date, created_at::DATE)) = p_month; $$; -- -- Name: get_my_email(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.get_my_email() RETURNS text LANGUAGE sql SECURITY DEFINER SET search_path TO 'public', 'auth' AS $$ select lower(email) from auth.users where id = auth.uid(); $$; -- -- Name: guard_account_type_immutable(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.guard_account_type_immutable() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN IF OLD.account_type <> 'free' AND NEW.account_type IS DISTINCT FROM OLD.account_type THEN RAISE EXCEPTION 'account_type ?? imut??vel ap??s escolha (atual: "%" para tentativa: "%"). Para mudar de perfil, crie uma nova conta.', OLD.account_type, NEW.account_type USING ERRCODE = 'P0001'; END IF; RETURN NEW; END; $$; -- -- Name: guard_locked_commitment(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.guard_locked_commitment() RETURNS trigger LANGUAGE plpgsql AS $$ begin if (old.is_locked = true) then if (tg_op = 'DELETE') then raise exception 'Compromisso bloqueado n??o pode ser exclu??do.'; end if; if (tg_op = 'UPDATE') then if (new.active = false) then raise exception 'Compromisso bloqueado n??o pode ser desativado.'; end if; -- trava renomear (mant??m o "Sess??o" sempre igual) if (new.name is distinct from old.name) then raise exception 'Compromisso bloqueado n??o pode ser renomeado.'; end if; -- se quiser travar descri????o tamb??m, descomente: -- if (new.description is distinct from old.description) then -- raise exception 'Compromisso bloqueado n??o pode alterar descri????o.'; -- end if; end if; end if; return new; end; $$; -- -- Name: guard_no_change_core_plan_key(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.guard_no_change_core_plan_key() RETURNS trigger LANGUAGE plpgsql AS $$ begin if old.key in ('clinic_free','clinic_pro','therapist_free','therapist_pro') and new.key is distinct from old.key then raise exception 'N??o ?? permitido alterar a key do plano padr??o (%).', old.key using errcode = 'P0001'; end if; return new; end $$; -- -- Name: guard_no_change_plan_target(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.guard_no_change_plan_target() RETURNS trigger LANGUAGE plpgsql AS $$ declare v_bypass text; begin -- bypass controlado por sess??o/transa????o: -- s?? passa se app.plan_migration_bypass = '1' v_bypass := current_setting('app.plan_migration_bypass', true); if v_bypass = '1' then return new; end if; -- comportamento original (bloqueia qualquer mudan??a) if new.target is distinct from old.target then raise exception 'N??o ?? permitido alterar target do plano (%) de % para %.', old.key, old.target, new.target using errcode = 'P0001'; end if; return new; end $$; -- -- Name: guard_no_delete_core_plans(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.guard_no_delete_core_plans() RETURNS trigger LANGUAGE plpgsql AS $$ begin if old.key in ('clinic_free','clinic_pro','therapist_free','therapist_pro') then raise exception 'Plano padr??o (%) n??o pode ser removido.', old.key using errcode = 'P0001'; end if; return old; end $$; -- -- Name: guard_patient_cannot_own_tenant(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.guard_patient_cannot_own_tenant() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE v_account_type text; BEGIN SELECT account_type INTO v_account_type FROM public.profiles WHERE id = NEW.user_id; IF v_account_type = 'patient' AND NEW.role IN ('tenant_admin', 'therapist') THEN RAISE EXCEPTION 'Usu??rio com perfil "patient" n??o pode ser propriet??rio ou terapeuta de um tenant. Se tornou profissional? Crie uma nova conta.' USING ERRCODE = 'P0001'; END IF; RETURN NEW; END; $$; -- -- Name: guard_tenant_kind_immutable(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.guard_tenant_kind_immutable() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN IF NEW.kind IS DISTINCT FROM OLD.kind THEN RAISE EXCEPTION 'tenants.kind ?? imut??vel ap??s cria????o. Tentativa de alterar "%" para "%".', OLD.kind, NEW.kind USING ERRCODE = 'P0001'; END IF; RETURN NEW; END; $$; -- -- Name: handle_new_user(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.handle_new_user() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ BEGIN INSERT INTO public.profiles (id, role, account_type) VALUES (NEW.id, 'portal_user', 'free') ON CONFLICT (id) DO NOTHING; RETURN NEW; END; $$; -- -- Name: handle_new_user_create_personal_tenant(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.handle_new_user_create_personal_tenant() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER AS $$ BEGIN -- Desabilitado. Tenant criado no onboarding via provision_account_tenant(). RETURN NEW; END; $$; -- -- Name: has_feature(uuid, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.has_feature(p_owner_id uuid, p_feature_key text) RETURNS boolean LANGUAGE sql STABLE AS $$ select exists ( select 1 from public.owner_feature_entitlements e where e.owner_id = p_owner_id and e.feature_key = p_feature_key ); $$; -- -- Name: is_clinic_tenant(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.is_clinic_tenant(_tenant_id uuid) RETURNS boolean LANGUAGE sql STABLE AS $$ SELECT EXISTS ( SELECT 1 FROM public.tenants t WHERE t.id = _tenant_id AND t.kind IN ('clinic', 'clinic_coworking', 'clinic_reception', 'clinic_full') ); $$; -- -- Name: is_saas_admin(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.is_saas_admin() RETURNS boolean LANGUAGE sql STABLE AS $$ select exists ( select 1 from public.saas_admins sa where sa.user_id = auth.uid() ); $$; -- -- Name: is_tenant_admin(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.is_tenant_admin(p_tenant_id uuid) RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public' SET row_security TO 'off' AS $$ select exists ( select 1 from public.tenant_members tm where tm.tenant_id = p_tenant_id and tm.user_id = auth.uid() and tm.role = 'tenant_admin' and tm.status = 'active' ); $$; -- -- Name: is_tenant_member(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.is_tenant_member(_tenant_id uuid) RETURNS boolean LANGUAGE sql STABLE AS $$ select exists ( select 1 from public.tenant_members m where m.tenant_id = _tenant_id and m.user_id = auth.uid() and m.status = 'active' ); $$; -- -- Name: is_therapist_tenant(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.is_therapist_tenant(_tenant_id uuid) RETURNS boolean LANGUAGE sql STABLE AS $$ SELECT EXISTS ( SELECT 1 FROM public.tenants t WHERE t.id = _tenant_id AND t.kind = 'therapist' ); $$; -- -- Name: jwt_email(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.jwt_email() RETURNS text LANGUAGE sql STABLE AS $$ select nullif(lower(current_setting('request.jwt.claim.email', true)), ''); $$; -- -- Name: list_financial_records(uuid, integer, integer, text, text, uuid, integer, integer); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.list_financial_records(p_owner_id uuid, p_year integer DEFAULT NULL::integer, p_month integer DEFAULT NULL::integer, p_type text DEFAULT NULL::text, p_status text DEFAULT NULL::text, p_patient_id uuid DEFAULT NULL::uuid, p_limit integer DEFAULT 50, p_offset integer DEFAULT 0) RETURNS SETOF public.financial_records LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public' AS $$ SELECT * FROM public.financial_records WHERE owner_id = p_owner_id AND deleted_at IS NULL AND (p_type IS NULL OR type::TEXT = p_type) AND (p_status IS NULL OR status = p_status) AND (p_patient_id IS NULL OR patient_id = p_patient_id) AND (p_year IS NULL OR EXTRACT(YEAR FROM COALESCE(paid_at::DATE, due_date, created_at::DATE)) = p_year) AND (p_month IS NULL OR EXTRACT(MONTH FROM COALESCE(paid_at::DATE, due_date, created_at::DATE)) = p_month) ORDER BY COALESCE(paid_at, due_date::TIMESTAMPTZ, created_at) DESC LIMIT p_limit OFFSET p_offset; $$; -- -- Name: mark_as_paid(uuid, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.mark_as_paid(p_financial_record_id uuid, p_payment_method text) RETURNS SETOF public.financial_records LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_record public.financial_records%ROWTYPE; BEGIN -- Garante que o registro pertence ao usu??rio autenticado (RLS n??o aplica em SECURITY DEFINER) SELECT * INTO v_record FROM public.financial_records WHERE id = p_financial_record_id AND owner_id = auth.uid() AND deleted_at IS NULL; IF NOT FOUND THEN RAISE EXCEPTION 'Registro financeiro n??o encontrado ou sem permiss??o.'; END IF; IF v_record.status NOT IN ('pending', 'overdue') THEN RAISE EXCEPTION 'Apenas cobran??as pendentes ou vencidas podem ser marcadas como pagas.'; END IF; UPDATE public.financial_records SET status = 'paid', paid_at = NOW(), payment_method = p_payment_method, updated_at = NOW() WHERE id = p_financial_record_id RETURNING * INTO v_record; RETURN NEXT v_record; END; $$; -- -- Name: mark_payout_as_paid(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.mark_payout_as_paid(p_payout_id uuid) RETURNS public.therapist_payouts LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_payout public.therapist_payouts%ROWTYPE; BEGIN -- Busca o payout SELECT * INTO v_payout FROM public.therapist_payouts WHERE id = p_payout_id; IF NOT FOUND THEN RAISE EXCEPTION 'Repasse n??o encontrado: %', p_payout_id; END IF; -- Verifica permiss??o: apenas tenant_admin do tenant do repasse IF NOT public.is_tenant_admin(v_payout.tenant_id) THEN RAISE EXCEPTION 'Apenas o administrador da cl??nica pode marcar repasses como pagos.'; END IF; -- Verifica status IF v_payout.status <> 'pending' THEN RAISE EXCEPTION 'Repasse j?? est?? com status ''%''. Apenas repasses pendentes podem ser pagos.', v_payout.status; END IF; -- Atualiza UPDATE public.therapist_payouts SET status = 'paid', paid_at = NOW(), updated_at = NOW() WHERE id = p_payout_id RETURNING * INTO v_payout; RETURN v_payout; END; $$; -- -- Name: FUNCTION mark_payout_as_paid(p_payout_id uuid); Type: COMMENT; Schema: public; Owner: - -- COMMENT ON FUNCTION public.mark_payout_as_paid(p_payout_id uuid) IS 'Marca um repasse de terapeuta como pago. Apenas o tenant_admin pode chamar. Apenas repasses com status=pending podem ser finalizados.'; -- -- Name: my_tenants(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.my_tenants() RETURNS TABLE(tenant_id uuid, role text, status text, kind text) LANGUAGE sql STABLE AS $$ select tm.tenant_id, tm.role, tm.status, t.kind from public.tenant_members tm join public.tenants t on t.id = tm.tenant_id where tm.user_id = auth.uid(); $$; -- -- Name: notice_track_click(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.notice_track_click(p_notice_id uuid) RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$ begin update public.global_notices set clicks_count = clicks_count + 1 where id = p_notice_id; end; $$; -- -- Name: notice_track_view(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.notice_track_view(p_notice_id uuid) RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$ begin update public.global_notices set views_count = views_count + 1 where id = p_notice_id; end; $$; -- -- Name: notify_on_intake(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.notify_on_intake() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER AS $$ BEGIN IF NEW.status = 'new' THEN INSERT INTO public.notifications ( owner_id, tenant_id, type, ref_id, ref_table, payload ) VALUES ( NEW.owner_id, NEW.tenant_id, 'new_patient', NEW.id, 'patient_intake_requests', jsonb_build_object( 'title', 'Novo cadastro externo', 'detail', COALESCE(NEW.nome_completo, 'Paciente'), 'deeplink', '/therapist/patients/cadastro/recebidos', 'avatar_initials', upper(left(COALESCE(NEW.nome_completo, '?'), 2)) ) ); END IF; RETURN NEW; END; $$; -- -- Name: notify_on_scheduling(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.notify_on_scheduling() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER AS $$ BEGIN IF NEW.status = 'pendente' THEN INSERT INTO public.notifications ( owner_id, tenant_id, type, ref_id, ref_table, payload ) VALUES ( NEW.owner_id, NEW.tenant_id, 'new_scheduling', NEW.id, 'agendador_solicitacoes', jsonb_build_object( 'title', 'Nova solicita????o de agendamento', 'detail', COALESCE(NEW.paciente_nome, 'Paciente') || ' ' || COALESCE(NEW.paciente_sobrenome, '') || ' ??? ' || COALESCE(NEW.tipo, ''), 'deeplink', '/therapist/agendamentos-recebidos', 'avatar_initials', upper(left(COALESCE(NEW.paciente_nome, '?'), 1) || left(COALESCE(NEW.paciente_sobrenome, ''), 1)) ) ); END IF; RETURN NEW; END; $$; -- -- Name: notify_on_session_status(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.notify_on_session_status() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE v_nome text; BEGIN IF NEW.status IN ('faltou', 'cancelado') AND OLD.status IS DISTINCT FROM NEW.status THEN SELECT nome_completo INTO v_nome FROM public.patients WHERE id = NEW.patient_id LIMIT 1; INSERT INTO public.notifications ( owner_id, tenant_id, type, ref_id, ref_table, payload ) VALUES ( NEW.owner_id, NEW.tenant_id, 'session_status', NEW.id, 'agenda_eventos', jsonb_build_object( 'title', CASE WHEN NEW.status = 'faltou' THEN 'Paciente faltou' ELSE 'Sess??o cancelada' END, 'detail', COALESCE(v_nome, 'Paciente') || ' ??? ' || to_char(NEW.inicio_em, 'DD/MM HH24:MI'), 'deeplink', '/therapist/agenda', 'avatar_initials', upper(left(COALESCE(v_nome, '?'), 2)) ) ); END IF; RETURN NEW; END; $$; -- -- Name: on_new_user_seed_patient_groups(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.on_new_user_seed_patient_groups() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ BEGIN PERFORM public.seed_default_patient_groups(NEW.id); RETURN NEW; END; $$; -- -- Name: patients_validate_member_consistency(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.patients_validate_member_consistency() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE v_tenant_responsible uuid; v_tenant_therapist uuid; BEGIN -- responsible_member sempre deve existir e ser do tenant SELECT tenant_id INTO v_tenant_responsible FROM public.tenant_members WHERE id = NEW.responsible_member_id; IF v_tenant_responsible IS NULL THEN RAISE EXCEPTION 'Responsible member not found'; END IF; IF NEW.tenant_id IS NULL THEN RAISE EXCEPTION 'tenant_id is required'; END IF; IF v_tenant_responsible <> NEW.tenant_id THEN RAISE EXCEPTION 'Responsible member must belong to the same tenant'; END IF; -- therapist scope: therapist_member_id deve existir e ser do mesmo tenant IF NEW.patient_scope = 'therapist' THEN IF NEW.therapist_member_id IS NULL THEN RAISE EXCEPTION 'therapist_member_id is required when patient_scope=therapist'; END IF; SELECT tenant_id INTO v_tenant_therapist FROM public.tenant_members WHERE id = NEW.therapist_member_id; IF v_tenant_therapist IS NULL THEN RAISE EXCEPTION 'Therapist member not found'; END IF; IF v_tenant_therapist <> NEW.tenant_id THEN RAISE EXCEPTION 'Therapist member must belong to the same tenant'; END IF; END IF; RETURN NEW; END; $$; -- -- Name: patients_validate_responsible_member_tenant(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.patients_validate_responsible_member_tenant() RETURNS trigger LANGUAGE plpgsql AS $$ declare m_tenant uuid; begin select tenant_id into m_tenant from public.tenant_members where id = new.responsible_member_id; if m_tenant is null then raise exception 'Responsible member not found'; end if; if new.tenant_id is null then raise exception 'tenant_id is required'; end if; if m_tenant <> new.tenant_id then raise exception 'Responsible member must belong to the same tenant'; end if; return new; end; $$; -- -- Name: populate_notification_queue(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.populate_notification_queue() RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$ BEGIN INSERT INTO public.notification_queue ( tenant_id, owner_id, agenda_evento_id, patient_id, channel, template_key, schedule_key, resolved_vars, recipient_address, scheduled_at, idempotency_key ) SELECT ae.tenant_id, ae.owner_id, ae.id AS agenda_evento_id, ae.patient_id, ch.channel, 'session.' || REPLACE(ns.event_type, '_sessao', '') || '.' || ch.channel, ns.schedule_key, jsonb_build_object( 'nome_paciente', COALESCE(p.nome_completo, 'Paciente'), 'data_sessao', TO_CHAR(ae.inicio_em AT TIME ZONE 'America/Sao_Paulo', 'DD/MM/YYYY'), 'hora_sessao', TO_CHAR(ae.inicio_em AT TIME ZONE 'America/Sao_Paulo', 'HH24:MI'), 'nome_terapeuta', COALESCE(prof.full_name, 'Terapeuta'), 'modalidade', COALESCE(ae.modalidade, 'Presencial'), 'titulo', COALESCE(ae.titulo, 'Sess??o') ), CASE ch.channel WHEN 'whatsapp' THEN COALESCE(p.telefone, '') WHEN 'sms' THEN COALESCE(p.telefone, '') WHEN 'email' THEN COALESCE(p.email_principal, '') END, CASE WHEN (ae.inicio_em - (ns.offset_minutes || ' minutes')::interval)::time < ns.allowed_time_start THEN DATE_TRUNC('day', ae.inicio_em - (ns.offset_minutes || ' minutes')::interval) + ns.allowed_time_start WHEN (ae.inicio_em - (ns.offset_minutes || ' minutes')::interval)::time > ns.allowed_time_end THEN DATE_TRUNC('day', ae.inicio_em - (ns.offset_minutes || ' minutes')::interval) + ns.allowed_time_start ELSE ae.inicio_em - (ns.offset_minutes || ' minutes')::interval END, ae.id::text || ':' || ns.schedule_key || ':' || ch.channel || ':' || ae.inicio_em::date::text FROM public.agenda_eventos ae JOIN public.patients p ON p.id = ae.patient_id LEFT JOIN public.profiles prof ON prof.id = ae.owner_id JOIN public.notification_schedules ns ON ns.owner_id = ae.owner_id AND ns.is_active = true AND ns.deleted_at IS NULL AND ns.trigger_type = 'before_event' AND ns.event_type = 'lembrete_sessao' JOIN public.notification_channels nc ON nc.owner_id = ae.owner_id AND nc.is_active = true AND nc.deleted_at IS NULL CROSS JOIN LATERAL ( SELECT 'whatsapp' AS channel WHERE ns.whatsapp_enabled AND nc.channel = 'whatsapp' UNION ALL SELECT 'email' AS channel WHERE ns.email_enabled AND nc.channel = 'email' UNION ALL SELECT 'sms' AS channel WHERE ns.sms_enabled AND nc.channel = 'sms' ) ch LEFT JOIN public.notification_preferences np ON np.patient_id = ae.patient_id AND np.owner_id = ae.owner_id AND np.deleted_at IS NULL WHERE ae.inicio_em > now() AND ae.inicio_em <= now() + interval '48 hours' AND ae.status NOT IN ('cancelado', 'faltou') AND CASE ch.channel WHEN 'whatsapp' THEN COALESCE(p.telefone, '') != '' WHEN 'sms' THEN COALESCE(p.telefone, '') != '' WHEN 'email' THEN COALESCE(p.email_principal, '') != '' END AND CASE ch.channel WHEN 'whatsapp' THEN COALESCE(np.whatsapp_opt_in, true) WHEN 'email' THEN COALESCE(np.email_opt_in, true) WHEN 'sms' THEN COALESCE(np.sms_opt_in, false) END AND EXISTS ( SELECT 1 FROM public.profiles tp WHERE tp.id = ae.owner_id AND COALESCE(tp.notify_reminders, true) = true ) ON CONFLICT (idempotency_key) DO NOTHING; END; $$; -- -- Name: prevent_promoting_to_system(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.prevent_promoting_to_system() RETURNS trigger LANGUAGE plpgsql AS $$ begin if new.is_system = true and old.is_system is distinct from true then raise exception 'N??o ?? permitido transformar um grupo comum em grupo do sistema.'; end if; return new; end; $$; -- -- Name: prevent_saas_membership(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.prevent_saas_membership() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN IF EXISTS ( SELECT 1 FROM public.profiles WHERE id = NEW.user_id AND role = 'saas_admin' ) THEN RAISE EXCEPTION 'SaaS admin cannot belong to tenant'; END IF; RETURN NEW; END; $$; -- -- Name: prevent_system_group_changes(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.prevent_system_group_changes() RETURNS trigger LANGUAGE plpgsql AS $$ begin -- Se for grupo do sistema, regras r??gidas: if old.is_system = true then -- nunca pode deletar if tg_op = 'DELETE' then raise exception 'Grupos padr??o do sistema n??o podem ser alterados ou exclu??dos.'; end if; if tg_op = 'UPDATE' then -- permite SOMENTE mudar tenant_id e/ou updated_at -- qualquer mudan??a de conte??do permanece proibida if new.nome is distinct from old.nome or new.descricao is distinct from old.descricao or new.cor is distinct from old.cor or new.is_active is distinct from old.is_active or new.is_system is distinct from old.is_system or new.owner_id is distinct from old.owner_id or new.therapist_id is distinct from old.therapist_id or new.created_at is distinct from old.created_at then raise exception 'Grupos padr??o do sistema n??o podem ser alterados ou exclu??dos.'; end if; -- chegou aqui: s?? tenant_id/updated_at mudaram -> ok return new; end if; end if; -- n??o-system: deixa passar if tg_op = 'DELETE' then return old; end if; return new; end; $$; -- -- Name: provision_account_tenant(uuid, text, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.provision_account_tenant(p_user_id uuid, p_kind text, p_name text DEFAULT NULL::text) RETURNS uuid LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE v_tenant_id uuid; v_account_type text; v_name text; BEGIN IF p_kind NOT IN ('therapist', 'clinic_coworking', 'clinic_reception', 'clinic_full') THEN RAISE EXCEPTION 'kind inv??lido: "%". Use: therapist, clinic_coworking, clinic_reception, clinic_full.', p_kind USING ERRCODE = 'P0001'; END IF; v_account_type := CASE WHEN p_kind = 'therapist' THEN 'therapist' ELSE 'clinic' END; IF EXISTS ( SELECT 1 FROM public.tenant_members tm JOIN public.tenants t ON t.id = tm.tenant_id WHERE tm.user_id = p_user_id AND tm.role = 'tenant_admin' AND tm.status = 'active' AND t.kind = p_kind ) THEN RAISE EXCEPTION 'Usu??rio j?? possui um tenant do tipo "%".', p_kind USING ERRCODE = 'P0001'; END IF; v_name := COALESCE( NULLIF(TRIM(p_name), ''), ( SELECT COALESCE(NULLIF(TRIM(pr.full_name), ''), SPLIT_PART(au.email, '@', 1)) FROM public.profiles pr JOIN auth.users au ON au.id = pr.id WHERE pr.id = p_user_id ), 'Conta' ); INSERT INTO public.tenants (name, kind, created_at) VALUES (v_name, p_kind, now()) RETURNING id INTO v_tenant_id; INSERT INTO public.tenant_members (tenant_id, user_id, role, status, created_at) VALUES (v_tenant_id, p_user_id, 'tenant_admin', 'active', now()); UPDATE public.profiles SET account_type = v_account_type WHERE id = p_user_id; PERFORM public.seed_determined_commitments(v_tenant_id); RETURN v_tenant_id; END; $$; -- -- Name: FUNCTION provision_account_tenant(p_user_id uuid, p_kind text, p_name text); Type: COMMENT; Schema: public; Owner: - -- COMMENT ON FUNCTION public.provision_account_tenant(p_user_id uuid, p_kind text, p_name text) IS 'Cria o tenant do tipo correto e atualiza account_type no profile. Chamar no onboarding ap??s escolha/pagamento de plano therapist ou clinic. p_kind: therapist | clinic_coworking | clinic_reception | clinic_full'; -- -- Name: reactivate_subscription(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.reactivate_subscription(p_subscription_id uuid) RETURNS public.subscriptions LANGUAGE plpgsql SECURITY DEFINER AS $$ declare v_sub public.subscriptions; v_owner_type text; v_owner_ref uuid; begin select * into v_sub from public.subscriptions where id = p_subscription_id for update; if not found then raise exception 'Subscription n??o encontrada'; end if; if v_sub.status = 'active' then return v_sub; end if; if v_sub.tenant_id is not null then v_owner_type := 'clinic'; v_owner_ref := v_sub.tenant_id; elsif v_sub.user_id is not null then v_owner_type := 'therapist'; v_owner_ref := v_sub.user_id; else v_owner_type := null; v_owner_ref := null; end if; update public.subscriptions set status = 'active', cancel_at_period_end = false, updated_at = now() where id = p_subscription_id returning * into v_sub; insert into public.subscription_events( subscription_id, owner_id, owner_type, owner_ref, event_type, old_plan_id, new_plan_id, created_by, reason, source, metadata ) values ( v_sub.id, v_owner_ref, v_owner_type, v_owner_ref, 'reactivated', v_sub.plan_id, v_sub.plan_id, auth.uid(), 'Reativa????o manual via admin', 'admin_panel', jsonb_build_object('previous_status', 'canceled') ); if v_owner_ref is not null then insert into public.entitlements_invalidation(owner_id, changed_at) values (v_owner_ref, now()) on conflict (owner_id) do update set changed_at = excluded.changed_at; end if; return v_sub; end; $$; -- -- Name: rebuild_owner_entitlements(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.rebuild_owner_entitlements(p_owner_id uuid) RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$ declare v_plan_id uuid; begin -- Plano ativo do owner (owner = subscriptions.user_id) select s.plan_id into v_plan_id from public.subscriptions s where s.user_id = p_owner_id and s.status = 'active' order by s.created_at desc limit 1; -- Sempre zera entitlements do owner (rebuild) delete from public.owner_feature_entitlements e where e.owner_id = p_owner_id; -- Se n??o tem assinatura ativa, acabou if v_plan_id is null then return; end if; -- Recria entitlements esperados pelo plano insert into public.owner_feature_entitlements (owner_id, feature_key, sources, limits_list) select p_owner_id as owner_id, f.key as feature_key, array['plan'::text] as sources, '{}'::jsonb as limits_list from public.plan_features pf join public.features f on f.id = pf.feature_id where pf.plan_id = v_plan_id; end; $$; -- -- Name: revoke_support_session(text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.revoke_support_session(p_token text) RETURNS boolean LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_admin_id uuid; v_role text; BEGIN v_admin_id := auth.uid(); IF v_admin_id IS NULL THEN RAISE EXCEPTION 'N??o autenticado.' USING ERRCODE = 'P0001'; END IF; SELECT role INTO v_role FROM public.profiles WHERE id = v_admin_id; IF v_role <> 'saas_admin' THEN RAISE EXCEPTION 'Acesso negado.' USING ERRCODE = 'P0002'; END IF; DELETE FROM public.support_sessions WHERE token = p_token AND admin_id = v_admin_id; RETURN FOUND; END; $$; -- -- Name: rotate_patient_invite_token(text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.rotate_patient_invite_token(p_new_token text) RETURNS uuid LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ declare v_uid uuid; v_id uuid; begin -- pega o usu??rio logado v_uid := auth.uid(); if v_uid is null then raise exception 'Usu??rio n??o autenticado'; end if; -- desativa tokens antigos ativos do usu??rio update public.patient_invites set active = false where owner_id = v_uid and active = true; -- cria novo token insert into public.patient_invites (owner_id, token, active) values (v_uid, p_new_token, true) returning id into v_id; return v_id; end; $$; -- -- Name: saas_votar_doc(uuid, boolean); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.saas_votar_doc(p_doc_id uuid, p_util boolean) RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER AS $$ declare v_uid uuid := auth.uid(); v_voto_antigo boolean; begin if v_uid is null then raise exception 'N??o autenticado'; end if; -- Verifica se j?? votou select util into v_voto_antigo from public.saas_doc_votos where doc_id = p_doc_id and user_id = v_uid; if found then -- J?? votou igual ??? cancela o voto (toggle) if v_voto_antigo = p_util then delete from public.saas_doc_votos where doc_id = p_doc_id and user_id = v_uid; update public.saas_docs set votos_util = greatest(0, votos_util - (case when p_util then 1 else 0 end)), votos_nao_util = greatest(0, votos_nao_util - (case when not p_util then 1 else 0 end)), updated_at = now() where id = p_doc_id; return jsonb_build_object('acao', 'removido', 'util', null); else -- Mudou de voto update public.saas_doc_votos set util = p_util, updated_at = now() where doc_id = p_doc_id and user_id = v_uid; update public.saas_docs set votos_util = greatest(0, votos_util + (case when p_util then 1 else -1 end)), votos_nao_util = greatest(0, votos_nao_util + (case when not p_util then 1 else -1 end)), updated_at = now() where id = p_doc_id; return jsonb_build_object('acao', 'atualizado', 'util', p_util); end if; else -- Primeiro voto insert into public.saas_doc_votos (doc_id, user_id, util) values (p_doc_id, v_uid, p_util); update public.saas_docs set votos_util = votos_util + (case when p_util then 1 else 0 end), votos_nao_util = votos_nao_util + (case when not p_util then 1 else 0 end), updated_at = now() where id = p_doc_id; return jsonb_build_object('acao', 'registrado', 'util', p_util); end if; end; $$; -- -- Name: safe_delete_patient(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.safe_delete_patient(p_patient_id uuid) RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER AS $$ BEGIN -- Bloqueia se houver hist??rico IF NOT public.can_delete_patient(p_patient_id) THEN RETURN jsonb_build_object( 'ok', false, 'error', 'has_history', 'message', 'Este paciente possui hist??rico cl??nico ou financeiro e n??o pode ser removido. Voc?? pode desativar ou arquivar o paciente.' ); END IF; -- Verifica ownership via RLS (owner_id ou responsible_member_id) IF NOT EXISTS ( SELECT 1 FROM public.patients WHERE id = p_patient_id AND ( owner_id = auth.uid() OR responsible_member_id IN ( SELECT id FROM public.tenant_members WHERE user_id = auth.uid() ) ) ) THEN RETURN jsonb_build_object( 'ok', false, 'error', 'forbidden', 'message', 'Sem permiss??o para excluir este paciente.' ); END IF; DELETE FROM public.patients WHERE id = p_patient_id; RETURN jsonb_build_object('ok', true); END; $$; -- -- Name: sanitize_phone_br(text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.sanitize_phone_br(raw_phone text) RETURNS text LANGUAGE plpgsql IMMUTABLE AS $$ DECLARE digits text; BEGIN digits := regexp_replace(COALESCE(raw_phone, ''), '[^0-9]', '', 'g'); IF digits = '' THEN RETURN ''; END IF; IF length(digits) = 10 OR length(digits) = 11 THEN digits := '55' || digits; END IF; RETURN digits; END; $$; -- -- Name: seed_default_financial_categories(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.seed_default_financial_categories(p_user_id uuid) RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ BEGIN INSERT INTO public.financial_categories (user_id, name, type, color, icon, sort_order) VALUES (p_user_id, 'Sess??o', 'receita', '#22c55e', 'pi pi-heart', 1), (p_user_id, 'Supervis??o', 'receita', '#6366f1', 'pi pi-users', 2), (p_user_id, 'Conv??nio', 'receita', '#3b82f6', 'pi pi-building', 3), (p_user_id, 'Grupo terap??utico', 'receita', '#f59e0b', 'pi pi-sitemap', 4), (p_user_id, 'Outro (receita)', 'receita', '#8b5cf6', 'pi pi-plus-circle', 5), (p_user_id, 'Aluguel sala', 'despesa', '#ef4444', 'pi pi-home', 1), (p_user_id, 'Plataforma/SaaS', 'despesa', '#f97316', 'pi pi-desktop', 2), (p_user_id, 'Repasse cl??nica', 'despesa', '#64748b', 'pi pi-arrow-right-arrow-left', 3), (p_user_id, 'Supervis??o (custo)', 'despesa', '#6366f1', 'pi pi-users', 4), (p_user_id, 'Outro (despesa)', 'despesa', '#94a3b8', 'pi pi-minus-circle', 5) ON CONFLICT DO NOTHING; END; $$; -- -- Name: seed_default_patient_groups(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.seed_default_patient_groups(p_tenant_id uuid) RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_owner_id uuid; BEGIN -- busca o owner (tenant_admin) do tenant SELECT user_id INTO v_owner_id FROM public.tenant_members WHERE tenant_id = p_tenant_id AND role = 'tenant_admin' AND status = 'active' LIMIT 1; IF v_owner_id IS NULL THEN RETURN; END IF; INSERT INTO public.patient_groups (owner_id, nome, cor, is_system, tenant_id) VALUES (v_owner_id, 'Crian??as', '#60a5fa', true, p_tenant_id), (v_owner_id, 'Adolescentes', '#a78bfa', true, p_tenant_id), (v_owner_id, 'Idosos', '#34d399', true, p_tenant_id) ON CONFLICT (owner_id, nome) DO NOTHING; END; $$; -- -- Name: seed_determined_commitments(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.seed_determined_commitments(p_tenant_id uuid) RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$ declare v_id uuid; begin -- Sess??o (locked + sempre ativa) if not exists ( select 1 from public.determined_commitments where tenant_id = p_tenant_id and is_native = true and native_key = 'session' ) then insert into public.determined_commitments (tenant_id, is_native, native_key, is_locked, active, name, description) values (p_tenant_id, true, 'session', true, true, 'Sess??o', 'Sess??o com paciente'); end if; -- Leitura if not exists ( select 1 from public.determined_commitments where tenant_id = p_tenant_id and is_native = true and native_key = 'reading' ) then insert into public.determined_commitments (tenant_id, is_native, native_key, is_locked, active, name, description) values (p_tenant_id, true, 'reading', false, true, 'Leitura', 'Praticar leitura'); end if; -- Supervis??o if not exists ( select 1 from public.determined_commitments where tenant_id = p_tenant_id and is_native = true and native_key = 'supervision' ) then insert into public.determined_commitments (tenant_id, is_native, native_key, is_locked, active, name, description) values (p_tenant_id, true, 'supervision', false, true, 'Supervis??o', 'Supervis??o'); end if; -- Aula ??? (corrigido) if not exists ( select 1 from public.determined_commitments where tenant_id = p_tenant_id and is_native = true and native_key = 'class' ) then insert into public.determined_commitments (tenant_id, is_native, native_key, is_locked, active, name, description) values (p_tenant_id, true, 'class', false, false, 'Aula', 'Dar aula'); end if; -- An??lise pessoal if not exists ( select 1 from public.determined_commitments where tenant_id = p_tenant_id and is_native = true and native_key = 'analysis' ) then insert into public.determined_commitments (tenant_id, is_native, native_key, is_locked, active, name, description) values (p_tenant_id, true, 'analysis', false, true, 'An??lise Pessoal', 'Minha an??lise pessoal'); end if; -- ------------------------------------------------------- -- Campos padr??o (idempotentes por (commitment_id, key)) -- ------------------------------------------------------- -- Leitura select id into v_id from public.determined_commitments where tenant_id = p_tenant_id and is_native = true and native_key = 'reading' limit 1; if v_id is not null then if not exists (select 1 from public.determined_commitment_fields where commitment_id = v_id and key = 'book') then insert into public.determined_commitment_fields (tenant_id, commitment_id, key, label, field_type, required, sort_order) values (p_tenant_id, v_id, 'book', 'Livro', 'text', false, 10); end if; if not exists (select 1 from public.determined_commitment_fields where commitment_id = v_id and key = 'author') then insert into public.determined_commitment_fields (tenant_id, commitment_id, key, label, field_type, required, sort_order) values (p_tenant_id, v_id, 'author', 'Autor', 'text', false, 20); end if; if not exists (select 1 from public.determined_commitment_fields where commitment_id = v_id and key = 'notes') then insert into public.determined_commitment_fields (tenant_id, commitment_id, key, label, field_type, required, sort_order) values (p_tenant_id, v_id, 'notes', 'Observa????o', 'textarea', false, 30); end if; end if; -- Supervis??o select id into v_id from public.determined_commitments where tenant_id = p_tenant_id and is_native = true and native_key = 'supervision' limit 1; if v_id is not null then if not exists (select 1 from public.determined_commitment_fields where commitment_id = v_id and key = 'supervisor') then insert into public.determined_commitment_fields (tenant_id, commitment_id, key, label, field_type, required, sort_order) values (p_tenant_id, v_id, 'supervisor', 'Supervisor', 'text', false, 10); end if; if not exists (select 1 from public.determined_commitment_fields where commitment_id = v_id and key = 'topic') then insert into public.determined_commitment_fields (tenant_id, commitment_id, key, label, field_type, required, sort_order) values (p_tenant_id, v_id, 'topic', 'Assunto', 'text', false, 20); end if; if not exists (select 1 from public.determined_commitment_fields where commitment_id = v_id and key = 'notes') then insert into public.determined_commitment_fields (tenant_id, commitment_id, key, label, field_type, required, sort_order) values (p_tenant_id, v_id, 'notes', 'Observa????o', 'textarea', false, 30); end if; end if; -- Aula select id into v_id from public.determined_commitments where tenant_id = p_tenant_id and is_native = true and native_key = 'class' limit 1; if v_id is not null then if not exists (select 1 from public.determined_commitment_fields where commitment_id = v_id and key = 'theme') then insert into public.determined_commitment_fields (tenant_id, commitment_id, key, label, field_type, required, sort_order) values (p_tenant_id, v_id, 'theme', 'Tema', 'text', false, 10); end if; if not exists (select 1 from public.determined_commitment_fields where commitment_id = v_id and key = 'group') then insert into public.determined_commitment_fields (tenant_id, commitment_id, key, label, field_type, required, sort_order) values (p_tenant_id, v_id, 'group', 'Turma', 'text', false, 20); end if; if not exists (select 1 from public.determined_commitment_fields where commitment_id = v_id and key = 'notes') then insert into public.determined_commitment_fields (tenant_id, commitment_id, key, label, field_type, required, sort_order) values (p_tenant_id, v_id, 'notes', 'Observa????o', 'textarea', false, 30); end if; end if; -- An??lise select id into v_id from public.determined_commitments where tenant_id = p_tenant_id and is_native = true and native_key = 'analysis' limit 1; if v_id is not null then if not exists (select 1 from public.determined_commitment_fields where commitment_id = v_id and key = 'analyst') then insert into public.determined_commitment_fields (tenant_id, commitment_id, key, label, field_type, required, sort_order) values (p_tenant_id, v_id, 'analyst', 'Analista', 'text', false, 10); end if; if not exists (select 1 from public.determined_commitment_fields where commitment_id = v_id and key = 'focus') then insert into public.determined_commitment_fields (tenant_id, commitment_id, key, label, field_type, required, sort_order) values (p_tenant_id, v_id, 'focus', 'Foco', 'text', false, 20); end if; if not exists (select 1 from public.determined_commitment_fields where commitment_id = v_id and key = 'notes') then insert into public.determined_commitment_fields (tenant_id, commitment_id, key, label, field_type, required, sort_order) values (p_tenant_id, v_id, 'notes', 'Observa????o', 'textarea', false, 30); end if; end if; end; $$; -- -- Name: set_insurance_plans_updated_at(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.set_insurance_plans_updated_at() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$; -- -- Name: set_owner_id(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.set_owner_id() RETURNS trigger LANGUAGE plpgsql AS $$ begin if new.owner_id is null then new.owner_id := auth.uid(); end if; return new; end; $$; -- -- Name: set_services_updated_at(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.set_services_updated_at() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$; -- -- Name: set_tenant_feature_exception(uuid, text, boolean, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.set_tenant_feature_exception(p_tenant_id uuid, p_feature_key text, p_enabled boolean, p_reason text DEFAULT NULL::text) RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$ begin -- ??? S?? owner ou admin do tenant podem alterar features if not exists ( select 1 from public.tenant_members where tenant_id = p_tenant_id and user_id = auth.uid() and role in ('owner', 'admin') and status = 'active' ) then raise exception 'Acesso negado: apenas owner/admin pode alterar features do tenant.'; end if; insert into public.tenant_features (tenant_id, feature_key, enabled) values (p_tenant_id, p_feature_key, p_enabled) on conflict (tenant_id, feature_key) do update set enabled = excluded.enabled; insert into public.tenant_feature_exceptions_log ( tenant_id, feature_key, enabled, reason, created_by ) values ( p_tenant_id, p_feature_key, p_enabled, p_reason, auth.uid() ); end; $$; -- -- Name: set_updated_at(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.set_updated_at() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$; -- -- Name: set_updated_at_recurrence(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.set_updated_at_recurrence() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$; -- -- Name: split_recurrence_at(uuid, date); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.split_recurrence_at(p_recurrence_id uuid, p_from_date date) RETURNS uuid LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_old public.recurrence_rules; v_new_id uuid; BEGIN -- busca a regra original SELECT * INTO v_old FROM public.recurrence_rules WHERE id = p_recurrence_id; IF NOT FOUND THEN RAISE EXCEPTION 'recurrence_rule % n??o encontrada', p_recurrence_id; END IF; -- encerra a regra antiga na data anterior UPDATE public.recurrence_rules SET end_date = p_from_date - INTERVAL '1 day', open_ended = false, updated_at = now() WHERE id = p_recurrence_id; -- cria nova regra a partir de p_from_date INSERT INTO public.recurrence_rules ( tenant_id, owner_id, therapist_id, patient_id, determined_commitment_id, type, interval, weekdays, start_time, end_time, timezone, duration_min, start_date, end_date, max_occurrences, open_ended, modalidade, titulo_custom, observacoes, extra_fields, status ) SELECT tenant_id, owner_id, therapist_id, patient_id, determined_commitment_id, type, interval, weekdays, start_time, end_time, timezone, duration_min, p_from_date, v_old.end_date, v_old.max_occurrences, v_old.open_ended, modalidade, titulo_custom, observacoes, extra_fields, status FROM public.recurrence_rules WHERE id = p_recurrence_id RETURNING id INTO v_new_id; RETURN v_new_id; END; $$; -- -- Name: subscription_intents_view_insert(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.subscription_intents_view_insert() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER AS $$ declare v_target text; v_plan_id uuid; begin select p.id, p.target into v_plan_id, v_target from public.plans p where p.key = new.plan_key; if v_plan_id is null then raise exception 'Plano inv??lido: plan_key=%', new.plan_key; end if; if lower(v_target) = 'clinic' then if new.tenant_id is null then raise exception 'Inten????o clinic exige tenant_id.'; end if; insert into public.subscription_intents_tenant ( id, tenant_id, created_by_user_id, email, plan_id, plan_key, interval, amount_cents, currency, status, source, notes, created_at, paid_at ) values ( coalesce(new.id, gen_random_uuid()), new.tenant_id, new.created_by_user_id, new.email, v_plan_id, new.plan_key, coalesce(new.interval,'month'), new.amount_cents, coalesce(new.currency,'BRL'), coalesce(new.status,'pending'), coalesce(new.source,'manual'), new.notes, coalesce(new.created_at, now()), new.paid_at ); new.plan_target := 'clinic'; return new; end if; -- therapist ou supervisor ??? tabela personal if lower(v_target) in ('therapist', 'supervisor') then insert into public.subscription_intents_personal ( id, user_id, created_by_user_id, email, plan_id, plan_key, interval, amount_cents, currency, status, source, notes, created_at, paid_at ) values ( coalesce(new.id, gen_random_uuid()), new.user_id, new.created_by_user_id, new.email, v_plan_id, new.plan_key, coalesce(new.interval,'month'), new.amount_cents, coalesce(new.currency,'BRL'), coalesce(new.status,'pending'), coalesce(new.source,'manual'), new.notes, coalesce(new.created_at, now()), new.paid_at ); new.plan_target := lower(v_target); -- 'therapist' ou 'supervisor' return new; end if; raise exception 'Target de plano n??o suportado: %', v_target; end; $$; -- -- Name: subscriptions_validate_scope(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.subscriptions_validate_scope() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE v_target text; BEGIN SELECT lower(p.target) INTO v_target FROM public.plans p WHERE p.id = NEW.plan_id; IF v_target IS NULL THEN RAISE EXCEPTION 'Plano inv??lido (target nulo).'; END IF; IF v_target = 'clinic' THEN IF NEW.tenant_id IS NULL THEN RAISE EXCEPTION 'Assinatura clinic exige tenant_id.'; END IF; IF NEW.user_id IS NOT NULL THEN RAISE EXCEPTION 'Assinatura clinic n??o pode ter user_id (XOR).'; END IF; ELSIF v_target IN ('therapist', 'supervisor') THEN -- supervisor ?? pessoal como therapist IF NEW.tenant_id IS NOT NULL THEN RAISE EXCEPTION 'Assinatura % n??o deve ter tenant_id.', v_target; END IF; IF NEW.user_id IS NULL THEN RAISE EXCEPTION 'Assinatura % exige user_id.', v_target; END IF; ELSIF v_target = 'patient' THEN IF NEW.tenant_id IS NOT NULL THEN RAISE EXCEPTION 'Assinatura patient n??o deve ter tenant_id.'; END IF; IF NEW.user_id IS NULL THEN RAISE EXCEPTION 'Assinatura patient exige user_id.'; END IF; ELSE RAISE EXCEPTION 'Target de plano inv??lido: %', v_target; END IF; RETURN NEW; END; $$; -- -- Name: sync_busy_mirror_agenda_eventos(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.sync_busy_mirror_agenda_eventos() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ declare clinic_tenant uuid; is_personal boolean; should_mirror boolean; begin -- Anti-recurs??o: espelho n??o espelha if (tg_op <> 'DELETE') then if new.mirror_of_event_id is not null then return new; end if; else if old.mirror_of_event_id is not null then return old; end if; end if; -- Define se ?? pessoal e se deve espelhar if (tg_op = 'DELETE') then is_personal := (old.tenant_id = old.owner_id); should_mirror := (old.visibility_scope in ('busy_only','private')); else is_personal := (new.tenant_id = new.owner_id); should_mirror := (new.visibility_scope in ('busy_only','private')); end if; -- Se n??o ?? pessoal, n??o faz nada if not is_personal then if (tg_op = 'DELETE') then return old; end if; return new; end if; -- DELETE: remove espelhos existentes if (tg_op = 'DELETE') then delete from public.agenda_eventos e where e.mirror_of_event_id = old.id and e.mirror_source = 'personal_busy_mirror'; return old; end if; -- INSERT/UPDATE: -- Se n??o deve espelhar, remove espelhos e sai if not should_mirror then delete from public.agenda_eventos e where e.mirror_of_event_id = new.id and e.mirror_source = 'personal_busy_mirror'; return new; end if; -- Para cada cl??nica onde o usu??rio ?? therapist active, cria/atualiza o "Ocupado" for clinic_tenant in select tm.tenant_id from public.tenant_members tm where tm.user_id = new.owner_id and tm.role = 'therapist' and tm.status = 'active' and tm.tenant_id <> new.owner_id loop insert into public.agenda_eventos ( tenant_id, owner_id, terapeuta_id, paciente_id, tipo, status, titulo, observacoes, inicio_em, fim_em, mirror_of_event_id, mirror_source, visibility_scope, created_at, updated_at ) values ( clinic_tenant, new.owner_id, new.owner_id, null, 'bloqueio'::public.tipo_evento_agenda, 'agendado'::public.status_evento_agenda, 'Ocupado', null, new.inicio_em, new.fim_em, new.id, 'personal_busy_mirror', 'public', now(), now() ) on conflict (tenant_id, mirror_of_event_id) where mirror_of_event_id is not null do update set owner_id = excluded.owner_id, terapeuta_id = excluded.terapeuta_id, tipo = excluded.tipo, status = excluded.status, titulo = excluded.titulo, observacoes = excluded.observacoes, inicio_em = excluded.inicio_em, fim_em = excluded.fim_em, updated_at = now(); end loop; -- Limpa espelhos de cl??nicas onde o v??nculo therapist active n??o existe mais delete from public.agenda_eventos e where e.mirror_of_event_id = new.id and e.mirror_source = 'personal_busy_mirror' and not exists ( select 1 from public.tenant_members tm where tm.user_id = new.owner_id and tm.role = 'therapist' and tm.status = 'active' and tm.tenant_id = e.tenant_id ); return new; end; $$; -- -- Name: sync_overdue_financial_records(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.sync_overdue_financial_records() RETURNS integer LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_count integer; BEGIN UPDATE public.financial_records SET status = 'overdue', updated_at = NOW() WHERE status = 'pending' AND due_date IS NOT NULL AND due_date < CURRENT_DATE AND deleted_at IS NULL; GET DIAGNOSTICS v_count = ROW_COUNT; RETURN v_count; END; $$; -- -- Name: FUNCTION sync_overdue_financial_records(); Type: COMMENT; Schema: public; Owner: - -- COMMENT ON FUNCTION public.sync_overdue_financial_records() IS 'Marca como overdue todos os financial_records pendentes com due_date vencido. Pode ser chamada manualmente, via pg_cron ou via Supabase Edge Function agendada.'; -- -- Name: tenant_accept_invite(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_accept_invite(p_token uuid) RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public', 'auth' AS $$ declare v_uid uuid; v_email text; v_invite public.tenant_invites%rowtype; begin -- 1) precisa estar autenticado v_uid := auth.uid(); if v_uid is null then raise exception 'not_authenticated' using errcode = 'P0001'; end if; -- 2) pega email real do usu??rio logado sem depender do JWT claim select u.email into v_email from auth.users u where u.id = v_uid; if v_email is null or length(trim(v_email)) = 0 then raise exception 'missing_user_email' using errcode = 'P0001'; end if; -- 3) carrega o invite e trava linha (evita 2 aceites concorrentes) select * into v_invite from public.tenant_invites i where i.token = p_token for update; if not found then raise exception 'invite_not_found' using errcode = 'P0001'; end if; -- 4) valida????es de estado if v_invite.revoked_at is not null then raise exception 'invite_revoked' using errcode = 'P0001'; end if; if v_invite.accepted_at is not null then raise exception 'invite_already_accepted' using errcode = 'P0001'; end if; if v_invite.expires_at is not null and v_invite.expires_at <= now() then raise exception 'invite_expired' using errcode = 'P0001'; end if; -- 5) valida email (case-insensitive) if lower(trim(v_invite.email)) <> lower(trim(v_email)) then raise exception 'email_mismatch' using errcode = 'P0001'; end if; -- 6) consome o invite update public.tenant_invites set accepted_at = now(), accepted_by = v_uid where id = v_invite.id; -- 7) cria ou reativa o membership insert into public.tenant_members (tenant_id, user_id, role, status, created_at) values (v_invite.tenant_id, v_uid, v_invite.role, 'active', now()) on conflict (tenant_id, user_id) do update set role = excluded.role, status = 'active'; -- 8) retorno ??til pro front (voc?? j?? tenta ler tenant_id no AcceptInvitePage) return jsonb_build_object( 'ok', true, 'tenant_id', v_invite.tenant_id, 'role', v_invite.role ); end; $$; -- -- Name: tenant_members; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.tenant_members ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, user_id uuid NOT NULL, role text NOT NULL, status text DEFAULT 'active'::text NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: tenant_add_member_by_email(uuid, text, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_add_member_by_email(p_tenant_id uuid, p_email text, p_role text DEFAULT 'therapist'::text) RETURNS public.tenant_members LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public', 'auth' AS $$ declare v_target_uid uuid; v_member public.tenant_members%rowtype; v_is_admin boolean; v_email text; begin if p_tenant_id is null then raise exception 'tenant_id ?? obrigat??rio'; end if; v_email := lower(trim(coalesce(p_email, ''))); if v_email = '' then raise exception 'email ?? obrigat??rio'; end if; -- valida role permitida if p_role not in ('tenant_admin','therapist','secretary','patient') then raise exception 'role inv??lida: %', p_role; end if; -- apenas admin do tenant (role real no banco) select exists ( select 1 from public.tenant_members tm where tm.tenant_id = p_tenant_id and tm.user_id = auth.uid() and tm.role = 'tenant_admin' and coalesce(tm.status,'active') = 'active' ) into v_is_admin; if not v_is_admin then raise exception 'sem permiss??o: apenas admin da cl??nica pode adicionar membros'; end if; -- acha usu??rio pelo e-mail no Supabase Auth select u.id into v_target_uid from auth.users u where lower(u.email) = v_email limit 1; if v_target_uid is null then raise exception 'nenhum usu??rio encontrado com este e-mail'; end if; -- cria ou reativa membro insert into public.tenant_members (tenant_id, user_id, role, status) values (p_tenant_id, v_target_uid, p_role, 'active') on conflict (tenant_id, user_id) do update set role = excluded.role, status = 'active' returning * into v_member; return v_member; end; $$; -- -- Name: tenant_feature_allowed(uuid, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_feature_allowed(p_tenant_id uuid, p_feature_key text) RETURNS boolean LANGUAGE sql STABLE AS $$ select exists ( select 1 from public.v_tenant_entitlements v where v.tenant_id = p_tenant_id and v.feature_key = p_feature_key and coalesce(v.allowed, false) = true ); $$; -- -- Name: tenant_feature_enabled(uuid, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_feature_enabled(p_tenant_id uuid, p_feature_key text) RETURNS boolean LANGUAGE sql STABLE AS $$ select coalesce( (select tf.enabled from public.tenant_features tf where tf.tenant_id = p_tenant_id and tf.feature_key = p_feature_key), false ); $$; -- -- Name: tenant_features_guard_with_plan(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_features_guard_with_plan() RETURNS trigger LANGUAGE plpgsql AS $$ declare v_allowed boolean; begin -- s?? valida quando est?? habilitando if new.enabled is distinct from true then return new; end if; -- permitido pelo plano do tenant? select exists ( select 1 from public.v_tenant_entitlements_full v where v.tenant_id = new.tenant_id and v.feature_key = new.feature_key and v.allowed = true ) into v_allowed; if not v_allowed then raise exception 'Feature % n??o permitida pelo plano atual do tenant %.', new.feature_key, new.tenant_id using errcode = 'P0001'; end if; return new; end; $$; -- -- Name: tenant_has_feature(uuid, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_has_feature(_tenant_id uuid, _feature text) RETURNS boolean LANGUAGE sql STABLE AS $$ select exists ( select 1 from public.v_tenant_entitlements e where e.tenant_id = _tenant_id and e.feature_key = _feature and e.allowed = true ) or exists ( select 1 from public.tenant_features tf where tf.tenant_id = _tenant_id and tf.feature_key = _feature and tf.enabled = true ); $$; -- -- Name: tenant_invite_member_by_email(uuid, text, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_invite_member_by_email(p_tenant_id uuid, p_email text, p_role text) RETURNS uuid LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public', 'auth' AS $$ declare v_email text; v_my_email text; v_token uuid; v_updated int; begin -- valida????es b??sicas if p_tenant_id is null then raise exception 'tenant_id inv??lido' using errcode = 'P0001'; end if; v_email := lower(trim(coalesce(p_email, ''))); if v_email = '' then raise exception 'Informe um email' using errcode = 'P0001'; end if; -- role permitido (ajuste se quiser) if p_role is null or p_role not in ('therapist', 'secretary') then raise exception 'Role inv??lido (use therapist/secretary)' using errcode = 'P0001'; end if; -- ??? bloqueio: auto-convite v_my_email := public.get_my_email(); if v_my_email is not null and v_email = v_my_email then raise exception 'Voc?? n??o pode convidar o seu pr??prio email.' using errcode = 'P0001'; end if; -- ??? bloqueio: j?? ?? membro ativo do tenant if exists ( select 1 from tenant_members tm join auth.users au on au.id = tm.user_id where tm.tenant_id = p_tenant_id and tm.status = 'active' and lower(au.email) = v_email ) then raise exception 'Este email j?? est?? vinculado a esta cl??nica.' using errcode = 'P0001'; end if; -- ??? permiss??o: s?? admin do tenant pode convidar if not exists ( select 1 from tenant_members me where me.tenant_id = p_tenant_id and me.user_id = auth.uid() and me.status = 'active' and me.role in ('tenant_admin','clinic_admin') ) then raise exception 'Sem permiss??o para convidar membros.' using errcode = 'P0001'; end if; -- Gera token (reenvio simples / regenera????o) v_token := gen_random_uuid(); -- 1) tenta "regerar" um convite pendente existente (mesmo email) update tenant_invites set token = v_token, role = p_role, created_at = now(), expires_at = now() + interval '7 days', accepted_at = null, revoked_at = null where tenant_id = p_tenant_id and lower(email) = v_email and accepted_at is null and revoked_at is null; get diagnostics v_updated = row_count; -- 2) se n??o atualizou nada, cria convite novo if v_updated = 0 then insert into tenant_invites (tenant_id, email, role, token, created_at, expires_at) values (p_tenant_id, v_email, p_role, v_token, now(), now() + interval '7 days'); end if; return v_token; end; $$; -- -- Name: tenant_reactivate_member(uuid, uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_reactivate_member(p_tenant_id uuid, p_member_user_id uuid) RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' SET row_security TO 'off' AS $$ begin if auth.uid() is null then raise exception 'not_authenticated'; end if; if not public.is_tenant_admin(p_tenant_id) then raise exception 'not_allowed'; end if; update public.tenant_members set status = 'active' where tenant_id = p_tenant_id and user_id = p_member_user_id; if not found then raise exception 'membership_not_found'; end if; end; $$; -- -- Name: tenant_remove_member(uuid, uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_remove_member(p_tenant_id uuid, p_member_user_id uuid) RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' SET row_security TO 'off' AS $$ declare v_role text; begin if auth.uid() is null then raise exception 'not_authenticated'; end if; if not public.is_tenant_admin(p_tenant_id) then raise exception 'not_allowed'; end if; if p_member_user_id = auth.uid() then raise exception 'cannot_remove_self'; end if; -- pega role atual do membro (se n??o existir, erro) select role into v_role from public.tenant_members where tenant_id = p_tenant_id and user_id = p_member_user_id; if v_role is null then raise exception 'membership_not_found'; end if; -- trava: se for therapist, n??o pode remover com eventos futuros if v_role = 'therapist' then if exists ( select 1 from public.agenda_eventos e where e.owner_id = p_tenant_id and e.terapeuta_id = p_member_user_id and e.inicio_em >= now() and e.status::text not in ('cancelado','cancelled','canceled') limit 1 ) then raise exception 'cannot_remove_therapist_with_future_events'; end if; end if; update public.tenant_members set status = 'inactive' where tenant_id = p_tenant_id and user_id = p_member_user_id; if not found then raise exception 'membership_not_found'; end if; end; $$; -- -- Name: tenant_remove_member_soft(uuid, uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_remove_member_soft(p_tenant_id uuid, p_member_user_id uuid) RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' SET row_security TO 'off' AS $$ begin if auth.uid() is null then raise exception 'not_authenticated'; end if; if not public.is_tenant_admin(p_tenant_id) then raise exception 'not_allowed'; end if; if p_member_user_id = auth.uid() then raise exception 'cannot_remove_self'; end if; update public.tenant_members set status = 'inactive' where tenant_id = p_tenant_id and user_id = p_member_user_id; if not found then raise exception 'membership_not_found'; end if; end; $$; -- -- Name: tenant_revoke_invite(uuid, text, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_revoke_invite(p_tenant_id uuid, p_email text, p_role text) RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' SET row_security TO 'off' AS $$ declare v_email text; begin if auth.uid() is null then raise exception 'not_authenticated'; end if; if not public.is_tenant_admin(p_tenant_id) then raise exception 'not_allowed'; end if; v_email := lower(trim(p_email)); update public.tenant_invites set revoked_at = now(), revoked_by = auth.uid() where tenant_id = p_tenant_id and lower(email) = v_email and role = p_role and accepted_at is null and revoked_at is null; if not found then raise exception 'invite_not_found'; end if; end; $$; -- -- Name: tenant_set_member_status(uuid, uuid, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_set_member_status(p_tenant_id uuid, p_member_user_id uuid, p_new_status text) RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' SET row_security TO 'off' AS $$ begin if auth.uid() is null then raise exception 'not_authenticated'; end if; -- valida status (adapte aos seus valores reais) if p_new_status not in ('active','inactive','suspended','invited') then raise exception 'invalid_status: %', p_new_status; end if; if not public.is_tenant_admin(p_tenant_id) then raise exception 'not_allowed'; end if; -- evita desativar a si mesmo (opcional) if p_member_user_id = auth.uid() and p_new_status <> 'active' then raise exception 'cannot_disable_self'; end if; update public.tenant_members set status = p_new_status where tenant_id = p_tenant_id and user_id = p_member_user_id; if not found then raise exception 'membership_not_found'; end if; end; $$; -- -- Name: tenant_update_member_role(uuid, uuid, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.tenant_update_member_role(p_tenant_id uuid, p_member_user_id uuid, p_new_role text) RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' SET row_security TO 'off' AS $$ begin -- exige auth if auth.uid() is null then raise exception 'not_authenticated'; end if; -- valida role if p_new_role not in ('tenant_admin','therapist','secretary','patient') then raise exception 'invalid_role: %', p_new_role; end if; -- somente tenant_admin ativo pode alterar role if not public.is_tenant_admin(p_tenant_id) then raise exception 'not_allowed'; end if; -- evita o admin remover o pr??prio admin sem querer (opcional mas recomendado) if p_member_user_id = auth.uid() and p_new_role <> 'tenant_admin' then raise exception 'cannot_demote_self'; end if; update public.tenant_members set role = p_new_role where tenant_id = p_tenant_id and user_id = p_member_user_id; if not found then raise exception 'membership_not_found'; end if; end; $$; -- -- Name: toggle_plan(uuid); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.toggle_plan(owner uuid) RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$ declare current_key text; new_key text; begin select p.key into current_key from subscriptions s join plans p on p.id = s.plan_id where s.owner_id = owner and s.status = 'active'; new_key := case when current_key = 'pro' then 'free' else 'pro' end; update subscriptions s set plan_id = p.id from plans p where p.key = new_key and s.owner_id = owner and s.status = 'active'; end; $$; -- -- Name: transition_subscription(uuid, text, text, jsonb); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.transition_subscription(p_subscription_id uuid, p_to_status text, p_reason text DEFAULT NULL::text, p_metadata jsonb DEFAULT NULL::jsonb) RETURNS public.subscriptions LANGUAGE plpgsql SECURITY DEFINER AS $$ declare v_sub public.subscriptions; v_uid uuid; v_is_allowed boolean := false; begin v_uid := auth.uid(); select * into v_sub from public.subscriptions where id = p_subscription_id; if not found then raise exception 'Assinatura n??o encontrada'; end if; -- ===================================================== -- ???? BLOCO DE AUTORIZA????O -- ===================================================== -- 1) SaaS admin pode tudo if is_saas_admin() then v_is_allowed := true; end if; -- 2) Assinatura pessoal (therapist) if not v_is_allowed and v_sub.tenant_id is null and v_sub.user_id = v_uid then v_is_allowed := true; end if; -- 3) Assinatura de clinic (tenant) if not v_is_allowed and v_sub.tenant_id is not null then if exists ( select 1 from public.tenant_members tm where tm.tenant_id = v_sub.tenant_id and tm.user_id = v_uid and tm.status = 'active' and tm.role = 'tenant_admin' ) then v_is_allowed := true; end if; end if; if not v_is_allowed then raise exception 'Sem permiss??o para transicionar esta assinatura'; end if; -- ===================================================== -- ???? TRANSI????O -- ===================================================== update public.subscriptions set status = p_to_status, updated_at = now(), cancelled_at = case when p_to_status = 'cancelled' then now() else cancelled_at end, suspended_at = case when p_to_status = 'suspended' then now() else suspended_at end, past_due_since = case when p_to_status = 'past_due' then now() else past_due_since end, expired_at = case when p_to_status = 'expired' then now() else expired_at end, activated_at = case when p_to_status = 'active' then now() else activated_at end where id = p_subscription_id returning * into v_sub; -- ===================================================== -- ???? EVENT LOG -- ===================================================== insert into public.subscription_events ( subscription_id, owner_id, event_type, created_at, created_by, source, reason, metadata, owner_type, owner_ref ) values ( v_sub.id, coalesce(v_sub.tenant_id, v_sub.user_id), 'status_changed', now(), v_uid, 'manual_transition', p_reason, p_metadata, case when v_sub.tenant_id is not null then 'tenant' else 'personal' end, coalesce(v_sub.tenant_id, v_sub.user_id) ); return v_sub; end; $$; -- -- Name: trg_fn_financial_records_auto_overdue(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.trg_fn_financial_records_auto_overdue() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ BEGIN IF NEW.status = 'pending' AND NEW.due_date IS NOT NULL AND NEW.due_date < CURRENT_DATE THEN NEW.status := 'overdue'; END IF; RETURN NEW; END; $$; -- -- Name: unstick_notification_queue(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.unstick_notification_queue() RETURNS integer LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE v_unstuck integer; BEGIN UPDATE public.notification_queue SET status = 'pendente', attempts = attempts + 1, last_error = 'Timeout: preso em processando por >10min', next_retry_at = now() + interval '2 minutes' WHERE status = 'processando' AND updated_at < now() - interval '10 minutes'; GET DIAGNOSTICS v_unstuck = ROW_COUNT; RETURN v_unstuck; END; $$; -- -- Name: update_payment_settings_updated_at(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.update_payment_settings_updated_at() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$; -- -- Name: update_professional_pricing_updated_at(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.update_professional_pricing_updated_at() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$; -- -- Name: user_has_feature(uuid, text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.user_has_feature(_user_id uuid, _feature text) RETURNS boolean LANGUAGE sql STABLE AS $$ select exists ( select 1 from public.v_user_entitlements e where e.user_id = _user_id and e.feature_key = _feature and e.allowed = true ); $$; -- -- Name: validate_support_session(text); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.validate_support_session(p_token text) RETURNS json LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_session support_sessions; BEGIN IF p_token IS NULL OR length(trim(p_token)) < 32 THEN RETURN json_build_object('valid', false, 'tenant_id', null); END IF; SELECT * INTO v_session FROM public.support_sessions WHERE token = p_token AND expires_at > now() LIMIT 1; IF NOT FOUND THEN RETURN json_build_object('valid', false, 'tenant_id', null); END IF; RETURN json_build_object( 'valid', true, 'tenant_id', v_session.tenant_id ); END; $$; -- -- Name: whoami(); Type: FUNCTION; Schema: public; Owner: - -- CREATE FUNCTION public.whoami() RETURNS TABLE(uid uuid, role text) LANGUAGE sql STABLE AS $$ select auth.uid() as uid, auth.role() as role; $$; -- -- Name: apply_rls(jsonb, integer); Type: FUNCTION; Schema: realtime; Owner: - -- CREATE FUNCTION realtime.apply_rls(wal jsonb, max_record_bytes integer DEFAULT (1024 * 1024)) RETURNS SETOF realtime.wal_rls LANGUAGE plpgsql AS $$ declare -- Regclass of the table e.g. public.notes entity_ regclass = (quote_ident(wal ->> 'schema') || '.' || quote_ident(wal ->> 'table'))::regclass; -- I, U, D, T: insert, update ... action realtime.action = ( case wal ->> 'action' when 'I' then 'INSERT' when 'U' then 'UPDATE' when 'D' then 'DELETE' else 'ERROR' end ); -- Is row level security enabled for the table is_rls_enabled bool = relrowsecurity from pg_class where oid = entity_; subscriptions realtime.subscription[] = array_agg(subs) from realtime.subscription subs where subs.entity = entity_; -- Subscription vars roles regrole[] = array_agg(distinct us.claims_role::text) from unnest(subscriptions) us; working_role regrole; claimed_role regrole; claims jsonb; subscription_id uuid; subscription_has_access bool; visible_to_subscription_ids uuid[] = '{}'; -- structured info for wal's columns columns realtime.wal_column[]; -- previous identity values for update/delete old_columns realtime.wal_column[]; error_record_exceeds_max_size boolean = octet_length(wal::text) > max_record_bytes; -- Primary jsonb output for record output jsonb; begin perform set_config('role', null, true); columns = array_agg( ( x->>'name', x->>'type', x->>'typeoid', realtime.cast( (x->'value') #>> '{}', coalesce( (x->>'typeoid')::regtype, -- null when wal2json version <= 2.4 (x->>'type')::regtype ) ), (pks ->> 'name') is not null, true )::realtime.wal_column ) from jsonb_array_elements(wal -> 'columns') x left join jsonb_array_elements(wal -> 'pk') pks on (x ->> 'name') = (pks ->> 'name'); old_columns = array_agg( ( x->>'name', x->>'type', x->>'typeoid', realtime.cast( (x->'value') #>> '{}', coalesce( (x->>'typeoid')::regtype, -- null when wal2json version <= 2.4 (x->>'type')::regtype ) ), (pks ->> 'name') is not null, true )::realtime.wal_column ) from jsonb_array_elements(wal -> 'identity') x left join jsonb_array_elements(wal -> 'pk') pks on (x ->> 'name') = (pks ->> 'name'); for working_role in select * from unnest(roles) loop -- Update `is_selectable` for columns and old_columns columns = array_agg( ( c.name, c.type_name, c.type_oid, c.value, c.is_pkey, pg_catalog.has_column_privilege(working_role, entity_, c.name, 'SELECT') )::realtime.wal_column ) from unnest(columns) c; old_columns = array_agg( ( c.name, c.type_name, c.type_oid, c.value, c.is_pkey, pg_catalog.has_column_privilege(working_role, entity_, c.name, 'SELECT') )::realtime.wal_column ) from unnest(old_columns) c; if action <> 'DELETE' and count(1) = 0 from unnest(columns) c where c.is_pkey then return next ( jsonb_build_object( 'schema', wal ->> 'schema', 'table', wal ->> 'table', 'type', action ), is_rls_enabled, -- subscriptions is already filtered by entity (select array_agg(s.subscription_id) from unnest(subscriptions) as s where claims_role = working_role), array['Error 400: Bad Request, no primary key'] )::realtime.wal_rls; -- The claims role does not have SELECT permission to the primary key of entity elsif action <> 'DELETE' and sum(c.is_selectable::int) <> count(1) from unnest(columns) c where c.is_pkey then return next ( jsonb_build_object( 'schema', wal ->> 'schema', 'table', wal ->> 'table', 'type', action ), is_rls_enabled, (select array_agg(s.subscription_id) from unnest(subscriptions) as s where claims_role = working_role), array['Error 401: Unauthorized'] )::realtime.wal_rls; else output = jsonb_build_object( 'schema', wal ->> 'schema', 'table', wal ->> 'table', 'type', action, 'commit_timestamp', to_char( ((wal ->> 'timestamp')::timestamptz at time zone 'utc'), 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"' ), 'columns', ( select jsonb_agg( jsonb_build_object( 'name', pa.attname, 'type', pt.typname ) order by pa.attnum asc ) from pg_attribute pa join pg_type pt on pa.atttypid = pt.oid where attrelid = entity_ and attnum > 0 and pg_catalog.has_column_privilege(working_role, entity_, pa.attname, 'SELECT') ) ) -- Add "record" key for insert and update || case when action in ('INSERT', 'UPDATE') then jsonb_build_object( 'record', ( select jsonb_object_agg( -- if unchanged toast, get column name and value from old record coalesce((c).name, (oc).name), case when (c).name is null then (oc).value else (c).value end ) from unnest(columns) c full outer join unnest(old_columns) oc on (c).name = (oc).name where coalesce((c).is_selectable, (oc).is_selectable) and ( not error_record_exceeds_max_size or (octet_length((c).value::text) <= 64)) ) ) else '{}'::jsonb end -- Add "old_record" key for update and delete || case when action = 'UPDATE' then jsonb_build_object( 'old_record', ( select jsonb_object_agg((c).name, (c).value) from unnest(old_columns) c where (c).is_selectable and ( not error_record_exceeds_max_size or (octet_length((c).value::text) <= 64)) ) ) when action = 'DELETE' then jsonb_build_object( 'old_record', ( select jsonb_object_agg((c).name, (c).value) from unnest(old_columns) c where (c).is_selectable and ( not error_record_exceeds_max_size or (octet_length((c).value::text) <= 64)) and ( not is_rls_enabled or (c).is_pkey ) -- if RLS enabled, we can't secure deletes so filter to pkey ) ) else '{}'::jsonb end; -- Create the prepared statement if is_rls_enabled and action <> 'DELETE' then if (select 1 from pg_prepared_statements where name = 'walrus_rls_stmt' limit 1) > 0 then deallocate walrus_rls_stmt; end if; execute realtime.build_prepared_statement_sql('walrus_rls_stmt', entity_, columns); end if; visible_to_subscription_ids = '{}'; for subscription_id, claims in ( select subs.subscription_id, subs.claims from unnest(subscriptions) subs where subs.entity = entity_ and subs.claims_role = working_role and ( realtime.is_visible_through_filters(columns, subs.filters) or ( action = 'DELETE' and realtime.is_visible_through_filters(old_columns, subs.filters) ) ) ) loop if not is_rls_enabled or action = 'DELETE' then visible_to_subscription_ids = visible_to_subscription_ids || subscription_id; else -- Check if RLS allows the role to see the record perform -- Trim leading and trailing quotes from working_role because set_config -- doesn't recognize the role as valid if they are included set_config('role', trim(both '"' from working_role::text), true), set_config('request.jwt.claims', claims::text, true); execute 'execute walrus_rls_stmt' into subscription_has_access; if subscription_has_access then visible_to_subscription_ids = visible_to_subscription_ids || subscription_id; end if; end if; end loop; perform set_config('role', null, true); return next ( output, is_rls_enabled, visible_to_subscription_ids, case when error_record_exceeds_max_size then array['Error 413: Payload Too Large'] else '{}' end )::realtime.wal_rls; end if; end loop; perform set_config('role', null, true); end; $$; -- -- Name: broadcast_changes(text, text, text, text, text, record, record, text); Type: FUNCTION; Schema: realtime; Owner: - -- CREATE FUNCTION realtime.broadcast_changes(topic_name text, event_name text, operation text, table_name text, table_schema text, new record, old record, level text DEFAULT 'ROW'::text) RETURNS void LANGUAGE plpgsql AS $$ DECLARE -- Declare a variable to hold the JSONB representation of the row row_data jsonb := '{}'::jsonb; BEGIN IF level = 'STATEMENT' THEN RAISE EXCEPTION 'function can only be triggered for each row, not for each statement'; END IF; -- Check the operation type and handle accordingly IF operation = 'INSERT' OR operation = 'UPDATE' OR operation = 'DELETE' THEN row_data := jsonb_build_object('old_record', OLD, 'record', NEW, 'operation', operation, 'table', table_name, 'schema', table_schema); PERFORM realtime.send (row_data, event_name, topic_name); ELSE RAISE EXCEPTION 'Unexpected operation type: %', operation; END IF; EXCEPTION WHEN OTHERS THEN RAISE EXCEPTION 'Failed to process the row: %', SQLERRM; END; $$; -- -- Name: build_prepared_statement_sql(text, regclass, realtime.wal_column[]); Type: FUNCTION; Schema: realtime; Owner: - -- CREATE FUNCTION realtime.build_prepared_statement_sql(prepared_statement_name text, entity regclass, columns realtime.wal_column[]) RETURNS text LANGUAGE sql AS $$ /* Builds a sql string that, if executed, creates a prepared statement to tests retrive a row from *entity* by its primary key columns. Example select realtime.build_prepared_statement_sql('public.notes', '{"id"}'::text[], '{"bigint"}'::text[]) */ select 'prepare ' || prepared_statement_name || ' as select exists( select 1 from ' || entity || ' where ' || string_agg(quote_ident(pkc.name) || '=' || quote_nullable(pkc.value #>> '{}') , ' and ') || ' )' from unnest(columns) pkc where pkc.is_pkey group by entity $$; -- -- Name: cast(text, regtype); Type: FUNCTION; Schema: realtime; Owner: - -- CREATE FUNCTION realtime."cast"(val text, type_ regtype) RETURNS jsonb LANGUAGE plpgsql IMMUTABLE AS $$ declare res jsonb; begin execute format('select to_jsonb(%L::'|| type_::text || ')', val) into res; return res; end $$; -- -- Name: check_equality_op(realtime.equality_op, regtype, text, text); Type: FUNCTION; Schema: realtime; Owner: - -- CREATE FUNCTION realtime.check_equality_op(op realtime.equality_op, type_ regtype, val_1 text, val_2 text) RETURNS boolean LANGUAGE plpgsql IMMUTABLE AS $$ /* Casts *val_1* and *val_2* as type *type_* and check the *op* condition for truthiness */ declare op_symbol text = ( case when op = 'eq' then '=' when op = 'neq' then '!=' when op = 'lt' then '<' when op = 'lte' then '<=' when op = 'gt' then '>' when op = 'gte' then '>=' when op = 'in' then '= any' else 'UNKNOWN OP' end ); res boolean; begin execute format( 'select %L::'|| type_::text || ' ' || op_symbol || ' ( %L::' || ( case when op = 'in' then type_::text || '[]' else type_::text end ) || ')', val_1, val_2) into res; return res; end; $$; -- -- Name: is_visible_through_filters(realtime.wal_column[], realtime.user_defined_filter[]); Type: FUNCTION; Schema: realtime; Owner: - -- CREATE FUNCTION realtime.is_visible_through_filters(columns realtime.wal_column[], filters realtime.user_defined_filter[]) RETURNS boolean LANGUAGE sql IMMUTABLE AS $_$ /* Should the record be visible (true) or filtered out (false) after *filters* are applied */ select -- Default to allowed when no filters present $2 is null -- no filters. this should not happen because subscriptions has a default or array_length($2, 1) is null -- array length of an empty array is null or bool_and( coalesce( realtime.check_equality_op( op:=f.op, type_:=coalesce( col.type_oid::regtype, -- null when wal2json version <= 2.4 col.type_name::regtype ), -- cast jsonb to text val_1:=col.value #>> '{}', val_2:=f.value ), false -- if null, filter does not match ) ) from unnest(filters) f join unnest(columns) col on f.column_name = col.name; $_$; -- -- Name: list_changes(name, name, integer, integer); Type: FUNCTION; Schema: realtime; Owner: - -- CREATE FUNCTION realtime.list_changes(publication name, slot_name name, max_changes integer, max_record_bytes integer) RETURNS SETOF realtime.wal_rls LANGUAGE sql SET log_min_messages TO 'fatal' AS $$ with pub as ( select concat_ws( ',', case when bool_or(pubinsert) then 'insert' else null end, case when bool_or(pubupdate) then 'update' else null end, case when bool_or(pubdelete) then 'delete' else null end ) as w2j_actions, coalesce( string_agg( realtime.quote_wal2json(format('%I.%I', schemaname, tablename)::regclass), ',' ) filter (where ppt.tablename is not null and ppt.tablename not like '% %'), '' ) w2j_add_tables from pg_publication pp left join pg_publication_tables ppt on pp.pubname = ppt.pubname where pp.pubname = publication group by pp.pubname limit 1 ), w2j as ( select x.*, pub.w2j_add_tables from pub, pg_logical_slot_get_changes( slot_name, null, max_changes, 'include-pk', 'true', 'include-transaction', 'false', 'include-timestamp', 'true', 'include-type-oids', 'true', 'format-version', '2', 'actions', pub.w2j_actions, 'add-tables', pub.w2j_add_tables ) x ) select xyz.wal, xyz.is_rls_enabled, xyz.subscription_ids, xyz.errors from w2j, realtime.apply_rls( wal := w2j.data::jsonb, max_record_bytes := max_record_bytes ) xyz(wal, is_rls_enabled, subscription_ids, errors) where w2j.w2j_add_tables <> '' and xyz.subscription_ids[1] is not null $$; -- -- Name: quote_wal2json(regclass); Type: FUNCTION; Schema: realtime; Owner: - -- CREATE FUNCTION realtime.quote_wal2json(entity regclass) RETURNS text LANGUAGE sql IMMUTABLE STRICT AS $$ select ( select string_agg('' || ch,'') from unnest(string_to_array(nsp.nspname::text, null)) with ordinality x(ch, idx) where not (x.idx = 1 and x.ch = '"') and not ( x.idx = array_length(string_to_array(nsp.nspname::text, null), 1) and x.ch = '"' ) ) || '.' || ( select string_agg('' || ch,'') from unnest(string_to_array(pc.relname::text, null)) with ordinality x(ch, idx) where not (x.idx = 1 and x.ch = '"') and not ( x.idx = array_length(string_to_array(nsp.nspname::text, null), 1) and x.ch = '"' ) ) from pg_class pc join pg_namespace nsp on pc.relnamespace = nsp.oid where pc.oid = entity $$; -- -- Name: send(jsonb, text, text, boolean); Type: FUNCTION; Schema: realtime; Owner: - -- CREATE FUNCTION realtime.send(payload jsonb, event text, topic text, private boolean DEFAULT true) RETURNS void LANGUAGE plpgsql AS $$ DECLARE generated_id uuid; final_payload jsonb; BEGIN BEGIN -- Generate a new UUID for the id generated_id := gen_random_uuid(); -- Check if payload has an 'id' key, if not, add the generated UUID IF payload ? 'id' THEN final_payload := payload; ELSE final_payload := jsonb_set(payload, '{id}', to_jsonb(generated_id)); END IF; -- Set the topic configuration EXECUTE format('SET LOCAL realtime.topic TO %L', topic); -- Attempt to insert the message INSERT INTO realtime.messages (id, payload, event, topic, private, extension) VALUES (generated_id, final_payload, event, topic, private, 'broadcast'); EXCEPTION WHEN OTHERS THEN -- Capture and notify the error RAISE WARNING 'ErrorSendingBroadcastMessage: %', SQLERRM; END; END; $$; -- -- Name: subscription_check_filters(); Type: FUNCTION; Schema: realtime; Owner: - -- CREATE FUNCTION realtime.subscription_check_filters() RETURNS trigger LANGUAGE plpgsql AS $$ /* Validates that the user defined filters for a subscription: - refer to valid columns that the claimed role may access - values are coercable to the correct column type */ declare col_names text[] = coalesce( array_agg(c.column_name order by c.ordinal_position), '{}'::text[] ) from information_schema.columns c where format('%I.%I', c.table_schema, c.table_name)::regclass = new.entity and pg_catalog.has_column_privilege( (new.claims ->> 'role'), format('%I.%I', c.table_schema, c.table_name)::regclass, c.column_name, 'SELECT' ); filter realtime.user_defined_filter; col_type regtype; in_val jsonb; begin for filter in select * from unnest(new.filters) loop -- Filtered column is valid if not filter.column_name = any(col_names) then raise exception 'invalid column for filter %', filter.column_name; end if; -- Type is sanitized and safe for string interpolation col_type = ( select atttypid::regtype from pg_catalog.pg_attribute where attrelid = new.entity and attname = filter.column_name ); if col_type is null then raise exception 'failed to lookup type for column %', filter.column_name; end if; -- Set maximum number of entries for in filter if filter.op = 'in'::realtime.equality_op then in_val = realtime.cast(filter.value, (col_type::text || '[]')::regtype); if coalesce(jsonb_array_length(in_val), 0) > 100 then raise exception 'too many values for `in` filter. Maximum 100'; end if; else -- raises an exception if value is not coercable to type perform realtime.cast(filter.value, col_type); end if; end loop; -- Apply consistent order to filters so the unique constraint on -- (subscription_id, entity, filters) can't be tricked by a different filter order new.filters = coalesce( array_agg(f order by f.column_name, f.op, f.value), '{}' ) from unnest(new.filters) f; return new; end; $$; -- -- Name: to_regrole(text); Type: FUNCTION; Schema: realtime; Owner: - -- CREATE FUNCTION realtime.to_regrole(role_name text) RETURNS regrole LANGUAGE sql IMMUTABLE AS $$ select role_name::regrole $$; -- -- Name: topic(); Type: FUNCTION; Schema: realtime; Owner: - -- CREATE FUNCTION realtime.topic() RETURNS text LANGUAGE sql STABLE AS $$ select nullif(current_setting('realtime.topic', true), '')::text; $$; -- -- Name: can_insert_object(text, text, uuid, jsonb); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.can_insert_object(bucketid text, name text, owner uuid, metadata jsonb) RETURNS void LANGUAGE plpgsql AS $$ BEGIN INSERT INTO "storage"."objects" ("bucket_id", "name", "owner", "metadata") VALUES (bucketid, name, owner, metadata); -- hack to rollback the successful insert RAISE sqlstate 'PT200' using message = 'ROLLBACK', detail = 'rollback successful insert'; END $$; -- -- Name: enforce_bucket_name_length(); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.enforce_bucket_name_length() RETURNS trigger LANGUAGE plpgsql AS $$ begin if length(new.name) > 100 then raise exception 'bucket name "%" is too long (% characters). Max is 100.', new.name, length(new.name); end if; return new; end; $$; -- -- Name: extension(text); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.extension(name text) RETURNS text LANGUAGE plpgsql AS $$ DECLARE _parts text[]; _filename text; BEGIN select string_to_array(name, '/') into _parts; select _parts[array_length(_parts,1)] into _filename; -- @todo return the last part instead of 2 return reverse(split_part(reverse(_filename), '.', 1)); END $$; -- -- Name: filename(text); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.filename(name text) RETURNS text LANGUAGE plpgsql AS $$ DECLARE _parts text[]; BEGIN select string_to_array(name, '/') into _parts; return _parts[array_length(_parts,1)]; END $$; -- -- Name: foldername(text); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.foldername(name text) RETURNS text[] LANGUAGE plpgsql AS $$ DECLARE _parts text[]; BEGIN select string_to_array(name, '/') into _parts; return _parts[1:array_length(_parts,1)-1]; END $$; -- -- Name: get_common_prefix(text, text, text); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.get_common_prefix(p_key text, p_prefix text, p_delimiter text) RETURNS text LANGUAGE sql IMMUTABLE AS $$ SELECT CASE WHEN position(p_delimiter IN substring(p_key FROM length(p_prefix) + 1)) > 0 THEN left(p_key, length(p_prefix) + position(p_delimiter IN substring(p_key FROM length(p_prefix) + 1))) ELSE NULL END; $$; -- -- Name: get_size_by_bucket(); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.get_size_by_bucket() RETURNS TABLE(size bigint, bucket_id text) LANGUAGE plpgsql AS $$ BEGIN return query select sum((metadata->>'size')::int) as size, obj.bucket_id from "storage".objects as obj group by obj.bucket_id; END $$; -- -- Name: list_multipart_uploads_with_delimiter(text, text, text, integer, text, text); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.list_multipart_uploads_with_delimiter(bucket_id text, prefix_param text, delimiter_param text, max_keys integer DEFAULT 100, next_key_token text DEFAULT ''::text, next_upload_token text DEFAULT ''::text) RETURNS TABLE(key text, id text, created_at timestamp with time zone) LANGUAGE plpgsql AS $_$ BEGIN RETURN QUERY EXECUTE 'SELECT DISTINCT ON(key COLLATE "C") * from ( SELECT CASE WHEN position($2 IN substring(key from length($1) + 1)) > 0 THEN substring(key from 1 for length($1) + position($2 IN substring(key from length($1) + 1))) ELSE key END AS key, id, created_at FROM storage.s3_multipart_uploads WHERE bucket_id = $5 AND key ILIKE $1 || ''%'' AND CASE WHEN $4 != '''' AND $6 = '''' THEN CASE WHEN position($2 IN substring(key from length($1) + 1)) > 0 THEN substring(key from 1 for length($1) + position($2 IN substring(key from length($1) + 1))) COLLATE "C" > $4 ELSE key COLLATE "C" > $4 END ELSE true END AND CASE WHEN $6 != '''' THEN id COLLATE "C" > $6 ELSE true END ORDER BY key COLLATE "C" ASC, created_at ASC) as e order by key COLLATE "C" LIMIT $3' USING prefix_param, delimiter_param, max_keys, next_key_token, bucket_id, next_upload_token; END; $_$; -- -- Name: list_objects_with_delimiter(text, text, text, integer, text, text, text); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.list_objects_with_delimiter(_bucket_id text, prefix_param text, delimiter_param text, max_keys integer DEFAULT 100, start_after text DEFAULT ''::text, next_token text DEFAULT ''::text, sort_order text DEFAULT 'asc'::text) RETURNS TABLE(name text, id uuid, metadata jsonb, updated_at timestamp with time zone, created_at timestamp with time zone, last_accessed_at timestamp with time zone) LANGUAGE plpgsql STABLE AS $_$ DECLARE v_peek_name TEXT; v_current RECORD; v_common_prefix TEXT; -- Configuration v_is_asc BOOLEAN; v_prefix TEXT; v_start TEXT; v_upper_bound TEXT; v_file_batch_size INT; -- Seek state v_next_seek TEXT; v_count INT := 0; -- Dynamic SQL for batch query only v_batch_query TEXT; BEGIN -- ======================================================================== -- INITIALIZATION -- ======================================================================== v_is_asc := lower(coalesce(sort_order, 'asc')) = 'asc'; v_prefix := coalesce(prefix_param, ''); v_start := CASE WHEN coalesce(next_token, '') <> '' THEN next_token ELSE coalesce(start_after, '') END; v_file_batch_size := LEAST(GREATEST(max_keys * 2, 100), 1000); -- Calculate upper bound for prefix filtering (bytewise, using COLLATE "C") IF v_prefix = '' THEN v_upper_bound := NULL; ELSIF right(v_prefix, 1) = delimiter_param THEN v_upper_bound := left(v_prefix, -1) || chr(ascii(delimiter_param) + 1); ELSE v_upper_bound := left(v_prefix, -1) || chr(ascii(right(v_prefix, 1)) + 1); END IF; -- Build batch query (dynamic SQL - called infrequently, amortized over many rows) IF v_is_asc THEN IF v_upper_bound IS NOT NULL THEN v_batch_query := 'SELECT o.name, o.id, o.updated_at, o.created_at, o.last_accessed_at, o.metadata ' || 'FROM storage.objects o WHERE o.bucket_id = $1 AND o.name COLLATE "C" >= $2 ' || 'AND o.name COLLATE "C" < $3 ORDER BY o.name COLLATE "C" ASC LIMIT $4'; ELSE v_batch_query := 'SELECT o.name, o.id, o.updated_at, o.created_at, o.last_accessed_at, o.metadata ' || 'FROM storage.objects o WHERE o.bucket_id = $1 AND o.name COLLATE "C" >= $2 ' || 'ORDER BY o.name COLLATE "C" ASC LIMIT $4'; END IF; ELSE IF v_upper_bound IS NOT NULL THEN v_batch_query := 'SELECT o.name, o.id, o.updated_at, o.created_at, o.last_accessed_at, o.metadata ' || 'FROM storage.objects o WHERE o.bucket_id = $1 AND o.name COLLATE "C" < $2 ' || 'AND o.name COLLATE "C" >= $3 ORDER BY o.name COLLATE "C" DESC LIMIT $4'; ELSE v_batch_query := 'SELECT o.name, o.id, o.updated_at, o.created_at, o.last_accessed_at, o.metadata ' || 'FROM storage.objects o WHERE o.bucket_id = $1 AND o.name COLLATE "C" < $2 ' || 'ORDER BY o.name COLLATE "C" DESC LIMIT $4'; END IF; END IF; -- ======================================================================== -- SEEK INITIALIZATION: Determine starting position -- ======================================================================== IF v_start = '' THEN IF v_is_asc THEN v_next_seek := v_prefix; ELSE -- DESC without cursor: find the last item in range IF v_upper_bound IS NOT NULL THEN SELECT o.name INTO v_next_seek FROM storage.objects o WHERE o.bucket_id = _bucket_id AND o.name COLLATE "C" >= v_prefix AND o.name COLLATE "C" < v_upper_bound ORDER BY o.name COLLATE "C" DESC LIMIT 1; ELSIF v_prefix <> '' THEN SELECT o.name INTO v_next_seek FROM storage.objects o WHERE o.bucket_id = _bucket_id AND o.name COLLATE "C" >= v_prefix ORDER BY o.name COLLATE "C" DESC LIMIT 1; ELSE SELECT o.name INTO v_next_seek FROM storage.objects o WHERE o.bucket_id = _bucket_id ORDER BY o.name COLLATE "C" DESC LIMIT 1; END IF; IF v_next_seek IS NOT NULL THEN v_next_seek := v_next_seek || delimiter_param; ELSE RETURN; END IF; END IF; ELSE -- Cursor provided: determine if it refers to a folder or leaf IF EXISTS ( SELECT 1 FROM storage.objects o WHERE o.bucket_id = _bucket_id AND o.name COLLATE "C" LIKE v_start || delimiter_param || '%' LIMIT 1 ) THEN -- Cursor refers to a folder IF v_is_asc THEN v_next_seek := v_start || chr(ascii(delimiter_param) + 1); ELSE v_next_seek := v_start || delimiter_param; END IF; ELSE -- Cursor refers to a leaf object IF v_is_asc THEN v_next_seek := v_start || delimiter_param; ELSE v_next_seek := v_start; END IF; END IF; END IF; -- ======================================================================== -- MAIN LOOP: Hybrid peek-then-batch algorithm -- Uses STATIC SQL for peek (hot path) and DYNAMIC SQL for batch -- ======================================================================== LOOP EXIT WHEN v_count >= max_keys; -- STEP 1: PEEK using STATIC SQL (plan cached, very fast) IF v_is_asc THEN IF v_upper_bound IS NOT NULL THEN SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = _bucket_id AND o.name COLLATE "C" >= v_next_seek AND o.name COLLATE "C" < v_upper_bound ORDER BY o.name COLLATE "C" ASC LIMIT 1; ELSE SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = _bucket_id AND o.name COLLATE "C" >= v_next_seek ORDER BY o.name COLLATE "C" ASC LIMIT 1; END IF; ELSE IF v_upper_bound IS NOT NULL THEN SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = _bucket_id AND o.name COLLATE "C" < v_next_seek AND o.name COLLATE "C" >= v_prefix ORDER BY o.name COLLATE "C" DESC LIMIT 1; ELSIF v_prefix <> '' THEN SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = _bucket_id AND o.name COLLATE "C" < v_next_seek AND o.name COLLATE "C" >= v_prefix ORDER BY o.name COLLATE "C" DESC LIMIT 1; ELSE SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = _bucket_id AND o.name COLLATE "C" < v_next_seek ORDER BY o.name COLLATE "C" DESC LIMIT 1; END IF; END IF; EXIT WHEN v_peek_name IS NULL; -- STEP 2: Check if this is a FOLDER or FILE v_common_prefix := storage.get_common_prefix(v_peek_name, v_prefix, delimiter_param); IF v_common_prefix IS NOT NULL THEN -- FOLDER: Emit and skip to next folder (no heap access needed) name := rtrim(v_common_prefix, delimiter_param); id := NULL; updated_at := NULL; created_at := NULL; last_accessed_at := NULL; metadata := NULL; RETURN NEXT; v_count := v_count + 1; -- Advance seek past the folder range IF v_is_asc THEN v_next_seek := left(v_common_prefix, -1) || chr(ascii(delimiter_param) + 1); ELSE v_next_seek := v_common_prefix; END IF; ELSE -- FILE: Batch fetch using DYNAMIC SQL (overhead amortized over many rows) -- For ASC: upper_bound is the exclusive upper limit (< condition) -- For DESC: prefix is the inclusive lower limit (>= condition) FOR v_current IN EXECUTE v_batch_query USING _bucket_id, v_next_seek, CASE WHEN v_is_asc THEN COALESCE(v_upper_bound, v_prefix) ELSE v_prefix END, v_file_batch_size LOOP v_common_prefix := storage.get_common_prefix(v_current.name, v_prefix, delimiter_param); IF v_common_prefix IS NOT NULL THEN -- Hit a folder: exit batch, let peek handle it v_next_seek := v_current.name; EXIT; END IF; -- Emit file name := v_current.name; id := v_current.id; updated_at := v_current.updated_at; created_at := v_current.created_at; last_accessed_at := v_current.last_accessed_at; metadata := v_current.metadata; RETURN NEXT; v_count := v_count + 1; -- Advance seek past this file IF v_is_asc THEN v_next_seek := v_current.name || delimiter_param; ELSE v_next_seek := v_current.name; END IF; EXIT WHEN v_count >= max_keys; END LOOP; END IF; END LOOP; END; $_$; -- -- Name: operation(); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.operation() RETURNS text LANGUAGE plpgsql STABLE AS $$ BEGIN RETURN current_setting('storage.operation', true); END; $$; -- -- Name: protect_delete(); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.protect_delete() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN -- Check if storage.allow_delete_query is set to 'true' IF COALESCE(current_setting('storage.allow_delete_query', true), 'false') != 'true' THEN RAISE EXCEPTION 'Direct deletion from storage tables is not allowed. Use the Storage API instead.' USING HINT = 'This prevents accidental data loss from orphaned objects.', ERRCODE = '42501'; END IF; RETURN NULL; END; $$; -- -- Name: search(text, text, integer, integer, integer, text, text, text); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.search(prefix text, bucketname text, limits integer DEFAULT 100, levels integer DEFAULT 1, offsets integer DEFAULT 0, search text DEFAULT ''::text, sortcolumn text DEFAULT 'name'::text, sortorder text DEFAULT 'asc'::text) RETURNS TABLE(name text, id uuid, updated_at timestamp with time zone, created_at timestamp with time zone, last_accessed_at timestamp with time zone, metadata jsonb) LANGUAGE plpgsql STABLE AS $_$ DECLARE v_peek_name TEXT; v_current RECORD; v_common_prefix TEXT; v_delimiter CONSTANT TEXT := '/'; -- Configuration v_limit INT; v_prefix TEXT; v_prefix_lower TEXT; v_is_asc BOOLEAN; v_order_by TEXT; v_sort_order TEXT; v_upper_bound TEXT; v_file_batch_size INT; -- Dynamic SQL for batch query only v_batch_query TEXT; -- Seek state v_next_seek TEXT; v_count INT := 0; v_skipped INT := 0; BEGIN -- ======================================================================== -- INITIALIZATION -- ======================================================================== v_limit := LEAST(coalesce(limits, 100), 1500); v_prefix := coalesce(prefix, '') || coalesce(search, ''); v_prefix_lower := lower(v_prefix); v_is_asc := lower(coalesce(sortorder, 'asc')) = 'asc'; v_file_batch_size := LEAST(GREATEST(v_limit * 2, 100), 1000); -- Validate sort column CASE lower(coalesce(sortcolumn, 'name')) WHEN 'name' THEN v_order_by := 'name'; WHEN 'updated_at' THEN v_order_by := 'updated_at'; WHEN 'created_at' THEN v_order_by := 'created_at'; WHEN 'last_accessed_at' THEN v_order_by := 'last_accessed_at'; ELSE v_order_by := 'name'; END CASE; v_sort_order := CASE WHEN v_is_asc THEN 'asc' ELSE 'desc' END; -- ======================================================================== -- NON-NAME SORTING: Use path_tokens approach (unchanged) -- ======================================================================== IF v_order_by != 'name' THEN RETURN QUERY EXECUTE format( $sql$ WITH folders AS ( SELECT path_tokens[$1] AS folder FROM storage.objects WHERE objects.name ILIKE $2 || '%%' AND bucket_id = $3 AND array_length(objects.path_tokens, 1) <> $1 GROUP BY folder ORDER BY folder %s ) (SELECT folder AS "name", NULL::uuid AS id, NULL::timestamptz AS updated_at, NULL::timestamptz AS created_at, NULL::timestamptz AS last_accessed_at, NULL::jsonb AS metadata FROM folders) UNION ALL (SELECT path_tokens[$1] AS "name", id, updated_at, created_at, last_accessed_at, metadata FROM storage.objects WHERE objects.name ILIKE $2 || '%%' AND bucket_id = $3 AND array_length(objects.path_tokens, 1) = $1 ORDER BY %I %s) LIMIT $4 OFFSET $5 $sql$, v_sort_order, v_order_by, v_sort_order ) USING levels, v_prefix, bucketname, v_limit, offsets; RETURN; END IF; -- ======================================================================== -- NAME SORTING: Hybrid skip-scan with batch optimization -- ======================================================================== -- Calculate upper bound for prefix filtering IF v_prefix_lower = '' THEN v_upper_bound := NULL; ELSIF right(v_prefix_lower, 1) = v_delimiter THEN v_upper_bound := left(v_prefix_lower, -1) || chr(ascii(v_delimiter) + 1); ELSE v_upper_bound := left(v_prefix_lower, -1) || chr(ascii(right(v_prefix_lower, 1)) + 1); END IF; -- Build batch query (dynamic SQL - called infrequently, amortized over many rows) IF v_is_asc THEN IF v_upper_bound IS NOT NULL THEN v_batch_query := 'SELECT o.name, o.id, o.updated_at, o.created_at, o.last_accessed_at, o.metadata ' || 'FROM storage.objects o WHERE o.bucket_id = $1 AND lower(o.name) COLLATE "C" >= $2 ' || 'AND lower(o.name) COLLATE "C" < $3 ORDER BY lower(o.name) COLLATE "C" ASC LIMIT $4'; ELSE v_batch_query := 'SELECT o.name, o.id, o.updated_at, o.created_at, o.last_accessed_at, o.metadata ' || 'FROM storage.objects o WHERE o.bucket_id = $1 AND lower(o.name) COLLATE "C" >= $2 ' || 'ORDER BY lower(o.name) COLLATE "C" ASC LIMIT $4'; END IF; ELSE IF v_upper_bound IS NOT NULL THEN v_batch_query := 'SELECT o.name, o.id, o.updated_at, o.created_at, o.last_accessed_at, o.metadata ' || 'FROM storage.objects o WHERE o.bucket_id = $1 AND lower(o.name) COLLATE "C" < $2 ' || 'AND lower(o.name) COLLATE "C" >= $3 ORDER BY lower(o.name) COLLATE "C" DESC LIMIT $4'; ELSE v_batch_query := 'SELECT o.name, o.id, o.updated_at, o.created_at, o.last_accessed_at, o.metadata ' || 'FROM storage.objects o WHERE o.bucket_id = $1 AND lower(o.name) COLLATE "C" < $2 ' || 'ORDER BY lower(o.name) COLLATE "C" DESC LIMIT $4'; END IF; END IF; -- Initialize seek position IF v_is_asc THEN v_next_seek := v_prefix_lower; ELSE -- DESC: find the last item in range first (static SQL) IF v_upper_bound IS NOT NULL THEN SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = bucketname AND lower(o.name) COLLATE "C" >= v_prefix_lower AND lower(o.name) COLLATE "C" < v_upper_bound ORDER BY lower(o.name) COLLATE "C" DESC LIMIT 1; ELSIF v_prefix_lower <> '' THEN SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = bucketname AND lower(o.name) COLLATE "C" >= v_prefix_lower ORDER BY lower(o.name) COLLATE "C" DESC LIMIT 1; ELSE SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = bucketname ORDER BY lower(o.name) COLLATE "C" DESC LIMIT 1; END IF; IF v_peek_name IS NOT NULL THEN v_next_seek := lower(v_peek_name) || v_delimiter; ELSE RETURN; END IF; END IF; -- ======================================================================== -- MAIN LOOP: Hybrid peek-then-batch algorithm -- Uses STATIC SQL for peek (hot path) and DYNAMIC SQL for batch -- ======================================================================== LOOP EXIT WHEN v_count >= v_limit; -- STEP 1: PEEK using STATIC SQL (plan cached, very fast) IF v_is_asc THEN IF v_upper_bound IS NOT NULL THEN SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = bucketname AND lower(o.name) COLLATE "C" >= v_next_seek AND lower(o.name) COLLATE "C" < v_upper_bound ORDER BY lower(o.name) COLLATE "C" ASC LIMIT 1; ELSE SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = bucketname AND lower(o.name) COLLATE "C" >= v_next_seek ORDER BY lower(o.name) COLLATE "C" ASC LIMIT 1; END IF; ELSE IF v_upper_bound IS NOT NULL THEN SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = bucketname AND lower(o.name) COLLATE "C" < v_next_seek AND lower(o.name) COLLATE "C" >= v_prefix_lower ORDER BY lower(o.name) COLLATE "C" DESC LIMIT 1; ELSIF v_prefix_lower <> '' THEN SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = bucketname AND lower(o.name) COLLATE "C" < v_next_seek AND lower(o.name) COLLATE "C" >= v_prefix_lower ORDER BY lower(o.name) COLLATE "C" DESC LIMIT 1; ELSE SELECT o.name INTO v_peek_name FROM storage.objects o WHERE o.bucket_id = bucketname AND lower(o.name) COLLATE "C" < v_next_seek ORDER BY lower(o.name) COLLATE "C" DESC LIMIT 1; END IF; END IF; EXIT WHEN v_peek_name IS NULL; -- STEP 2: Check if this is a FOLDER or FILE v_common_prefix := storage.get_common_prefix(lower(v_peek_name), v_prefix_lower, v_delimiter); IF v_common_prefix IS NOT NULL THEN -- FOLDER: Handle offset, emit if needed, skip to next folder IF v_skipped < offsets THEN v_skipped := v_skipped + 1; ELSE name := split_part(rtrim(v_common_prefix, v_delimiter), v_delimiter, levels); id := NULL; updated_at := NULL; created_at := NULL; last_accessed_at := NULL; metadata := NULL; RETURN NEXT; v_count := v_count + 1; END IF; -- Advance seek past the folder range IF v_is_asc THEN v_next_seek := lower(left(v_common_prefix, -1)) || chr(ascii(v_delimiter) + 1); ELSE v_next_seek := lower(v_common_prefix); END IF; ELSE -- FILE: Batch fetch using DYNAMIC SQL (overhead amortized over many rows) -- For ASC: upper_bound is the exclusive upper limit (< condition) -- For DESC: prefix_lower is the inclusive lower limit (>= condition) FOR v_current IN EXECUTE v_batch_query USING bucketname, v_next_seek, CASE WHEN v_is_asc THEN COALESCE(v_upper_bound, v_prefix_lower) ELSE v_prefix_lower END, v_file_batch_size LOOP v_common_prefix := storage.get_common_prefix(lower(v_current.name), v_prefix_lower, v_delimiter); IF v_common_prefix IS NOT NULL THEN -- Hit a folder: exit batch, let peek handle it v_next_seek := lower(v_current.name); EXIT; END IF; -- Handle offset skipping IF v_skipped < offsets THEN v_skipped := v_skipped + 1; ELSE -- Emit file name := split_part(v_current.name, v_delimiter, levels); id := v_current.id; updated_at := v_current.updated_at; created_at := v_current.created_at; last_accessed_at := v_current.last_accessed_at; metadata := v_current.metadata; RETURN NEXT; v_count := v_count + 1; END IF; -- Advance seek past this file IF v_is_asc THEN v_next_seek := lower(v_current.name) || v_delimiter; ELSE v_next_seek := lower(v_current.name); END IF; EXIT WHEN v_count >= v_limit; END LOOP; END IF; END LOOP; END; $_$; -- -- Name: search_by_timestamp(text, text, integer, integer, text, text, text, text); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.search_by_timestamp(p_prefix text, p_bucket_id text, p_limit integer, p_level integer, p_start_after text, p_sort_order text, p_sort_column text, p_sort_column_after text) RETURNS TABLE(key text, name text, id uuid, updated_at timestamp with time zone, created_at timestamp with time zone, last_accessed_at timestamp with time zone, metadata jsonb) LANGUAGE plpgsql STABLE AS $_$ DECLARE v_cursor_op text; v_query text; v_prefix text; BEGIN v_prefix := coalesce(p_prefix, ''); IF p_sort_order = 'asc' THEN v_cursor_op := '>'; ELSE v_cursor_op := '<'; END IF; v_query := format($sql$ WITH raw_objects AS ( SELECT o.name AS obj_name, o.id AS obj_id, o.updated_at AS obj_updated_at, o.created_at AS obj_created_at, o.last_accessed_at AS obj_last_accessed_at, o.metadata AS obj_metadata, storage.get_common_prefix(o.name, $1, '/') AS common_prefix FROM storage.objects o WHERE o.bucket_id = $2 AND o.name COLLATE "C" LIKE $1 || '%%' ), -- Aggregate common prefixes (folders) -- Both created_at and updated_at use MIN(obj_created_at) to match the old prefixes table behavior aggregated_prefixes AS ( SELECT rtrim(common_prefix, '/') AS name, NULL::uuid AS id, MIN(obj_created_at) AS updated_at, MIN(obj_created_at) AS created_at, NULL::timestamptz AS last_accessed_at, NULL::jsonb AS metadata, TRUE AS is_prefix FROM raw_objects WHERE common_prefix IS NOT NULL GROUP BY common_prefix ), leaf_objects AS ( SELECT obj_name AS name, obj_id AS id, obj_updated_at AS updated_at, obj_created_at AS created_at, obj_last_accessed_at AS last_accessed_at, obj_metadata AS metadata, FALSE AS is_prefix FROM raw_objects WHERE common_prefix IS NULL ), combined AS ( SELECT * FROM aggregated_prefixes UNION ALL SELECT * FROM leaf_objects ), filtered AS ( SELECT * FROM combined WHERE ( $5 = '' OR ROW( date_trunc('milliseconds', %I), name COLLATE "C" ) %s ROW( COALESCE(NULLIF($6, '')::timestamptz, 'epoch'::timestamptz), $5 ) ) ) SELECT split_part(name, '/', $3) AS key, name, id, updated_at, created_at, last_accessed_at, metadata FROM filtered ORDER BY COALESCE(date_trunc('milliseconds', %I), 'epoch'::timestamptz) %s, name COLLATE "C" %s LIMIT $4 $sql$, p_sort_column, v_cursor_op, p_sort_column, p_sort_order, p_sort_order ); RETURN QUERY EXECUTE v_query USING v_prefix, p_bucket_id, p_level, p_limit, p_start_after, p_sort_column_after; END; $_$; -- -- Name: search_v2(text, text, integer, integer, text, text, text, text); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.search_v2(prefix text, bucket_name text, limits integer DEFAULT 100, levels integer DEFAULT 1, start_after text DEFAULT ''::text, sort_order text DEFAULT 'asc'::text, sort_column text DEFAULT 'name'::text, sort_column_after text DEFAULT ''::text) RETURNS TABLE(key text, name text, id uuid, updated_at timestamp with time zone, created_at timestamp with time zone, last_accessed_at timestamp with time zone, metadata jsonb) LANGUAGE plpgsql STABLE AS $$ DECLARE v_sort_col text; v_sort_ord text; v_limit int; BEGIN -- Cap limit to maximum of 1500 records v_limit := LEAST(coalesce(limits, 100), 1500); -- Validate and normalize sort_order v_sort_ord := lower(coalesce(sort_order, 'asc')); IF v_sort_ord NOT IN ('asc', 'desc') THEN v_sort_ord := 'asc'; END IF; -- Validate and normalize sort_column v_sort_col := lower(coalesce(sort_column, 'name')); IF v_sort_col NOT IN ('name', 'updated_at', 'created_at') THEN v_sort_col := 'name'; END IF; -- Route to appropriate implementation IF v_sort_col = 'name' THEN -- Use list_objects_with_delimiter for name sorting (most efficient: O(k * log n)) RETURN QUERY SELECT split_part(l.name, '/', levels) AS key, l.name AS name, l.id, l.updated_at, l.created_at, l.last_accessed_at, l.metadata FROM storage.list_objects_with_delimiter( bucket_name, coalesce(prefix, ''), '/', v_limit, start_after, '', v_sort_ord ) l; ELSE -- Use aggregation approach for timestamp sorting -- Not efficient for large datasets but supports correct pagination RETURN QUERY SELECT * FROM storage.search_by_timestamp( prefix, bucket_name, v_limit, levels, start_after, v_sort_ord, v_sort_col, sort_column_after ); END IF; END; $$; -- -- Name: update_updated_at_column(); Type: FUNCTION; Schema: storage; Owner: - -- CREATE FUNCTION storage.update_updated_at_column() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$; -- -- Name: http_request(); Type: FUNCTION; Schema: supabase_functions; Owner: - -- CREATE FUNCTION supabase_functions.http_request() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'supabase_functions' AS $$ DECLARE request_id bigint; payload jsonb; url text := TG_ARGV[0]::text; method text := TG_ARGV[1]::text; headers jsonb DEFAULT '{}'::jsonb; params jsonb DEFAULT '{}'::jsonb; timeout_ms integer DEFAULT 1000; BEGIN IF url IS NULL OR url = 'null' THEN RAISE EXCEPTION 'url argument is missing'; END IF; IF method IS NULL OR method = 'null' THEN RAISE EXCEPTION 'method argument is missing'; END IF; IF TG_ARGV[2] IS NULL OR TG_ARGV[2] = 'null' THEN headers = '{"Content-Type": "application/json"}'::jsonb; ELSE headers = TG_ARGV[2]::jsonb; END IF; IF TG_ARGV[3] IS NULL OR TG_ARGV[3] = 'null' THEN params = '{}'::jsonb; ELSE params = TG_ARGV[3]::jsonb; END IF; IF TG_ARGV[4] IS NULL OR TG_ARGV[4] = 'null' THEN timeout_ms = 1000; ELSE timeout_ms = TG_ARGV[4]::integer; END IF; CASE WHEN method = 'GET' THEN SELECT http_get INTO request_id FROM net.http_get( url, params, headers, timeout_ms ); WHEN method = 'POST' THEN payload = jsonb_build_object( 'old_record', OLD, 'record', NEW, 'type', TG_OP, 'table', TG_TABLE_NAME, 'schema', TG_TABLE_SCHEMA ); SELECT http_post INTO request_id FROM net.http_post( url, payload, params, headers, timeout_ms ); ELSE RAISE EXCEPTION 'method argument % is invalid', method; END CASE; INSERT INTO supabase_functions.hooks (hook_table_id, hook_name, request_id) VALUES (TG_RELID, TG_NAME, request_id); RETURN NEW; END $$; -- -- Name: extensions; Type: TABLE; Schema: _realtime; Owner: - -- CREATE TABLE _realtime.extensions ( id uuid NOT NULL, type text, settings jsonb, tenant_external_id text, inserted_at timestamp(0) without time zone NOT NULL, updated_at timestamp(0) without time zone NOT NULL ); -- -- Name: schema_migrations; Type: TABLE; Schema: _realtime; Owner: - -- CREATE TABLE _realtime.schema_migrations ( version bigint NOT NULL, inserted_at timestamp(0) without time zone ); -- -- Name: tenants; Type: TABLE; Schema: _realtime; Owner: - -- CREATE TABLE _realtime.tenants ( id uuid NOT NULL, name text, external_id text, jwt_secret text, max_concurrent_users integer DEFAULT 200 NOT NULL, inserted_at timestamp(0) without time zone NOT NULL, updated_at timestamp(0) without time zone NOT NULL, max_events_per_second integer DEFAULT 100 NOT NULL, postgres_cdc_default text DEFAULT 'postgres_cdc_rls'::text, max_bytes_per_second integer DEFAULT 100000 NOT NULL, max_channels_per_client integer DEFAULT 100 NOT NULL, max_joins_per_second integer DEFAULT 500 NOT NULL, suspend boolean DEFAULT false, jwt_jwks jsonb, notify_private_alpha boolean DEFAULT false, private_only boolean DEFAULT false NOT NULL, migrations_ran integer DEFAULT 0, broadcast_adapter character varying(255) DEFAULT 'gen_rpc'::character varying, max_presence_events_per_second integer DEFAULT 1000, max_payload_size_in_kb integer DEFAULT 3000, CONSTRAINT jwt_secret_or_jwt_jwks_required CHECK (((jwt_secret IS NOT NULL) OR (jwt_jwks IS NOT NULL))) ); -- -- Name: audit_log_entries; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.audit_log_entries ( instance_id uuid, id uuid NOT NULL, payload json, created_at timestamp with time zone, ip_address character varying(64) DEFAULT ''::character varying NOT NULL ); -- -- Name: TABLE audit_log_entries; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.audit_log_entries IS 'Auth: Audit trail for user actions.'; -- -- Name: flow_state; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.flow_state ( id uuid NOT NULL, user_id uuid, auth_code text, code_challenge_method auth.code_challenge_method, code_challenge text, provider_type text NOT NULL, provider_access_token text, provider_refresh_token text, created_at timestamp with time zone, updated_at timestamp with time zone, authentication_method text NOT NULL, auth_code_issued_at timestamp with time zone, invite_token text, referrer text, oauth_client_state_id uuid, linking_target_id uuid, email_optional boolean DEFAULT false NOT NULL ); -- -- Name: TABLE flow_state; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.flow_state IS 'Stores metadata for all OAuth/SSO login flows'; -- -- Name: identities; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.identities ( provider_id text NOT NULL, user_id uuid NOT NULL, identity_data jsonb NOT NULL, provider text NOT NULL, last_sign_in_at timestamp with time zone, created_at timestamp with time zone, updated_at timestamp with time zone, email text GENERATED ALWAYS AS (lower((identity_data ->> 'email'::text))) STORED, id uuid DEFAULT gen_random_uuid() NOT NULL ); -- -- Name: TABLE identities; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.identities IS 'Auth: Stores identities associated to a user.'; -- -- Name: COLUMN identities.email; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON COLUMN auth.identities.email IS 'Auth: Email is a generated column that references the optional email property in the identity_data'; -- -- Name: instances; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.instances ( id uuid NOT NULL, uuid uuid, raw_base_config text, created_at timestamp with time zone, updated_at timestamp with time zone ); -- -- Name: TABLE instances; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.instances IS 'Auth: Manages users across multiple sites.'; -- -- Name: mfa_amr_claims; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.mfa_amr_claims ( session_id uuid NOT NULL, created_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL, authentication_method text NOT NULL, id uuid NOT NULL ); -- -- Name: TABLE mfa_amr_claims; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.mfa_amr_claims IS 'auth: stores authenticator method reference claims for multi factor authentication'; -- -- Name: mfa_challenges; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.mfa_challenges ( id uuid NOT NULL, factor_id uuid NOT NULL, created_at timestamp with time zone NOT NULL, verified_at timestamp with time zone, ip_address inet NOT NULL, otp_code text, web_authn_session_data jsonb ); -- -- Name: TABLE mfa_challenges; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.mfa_challenges IS 'auth: stores metadata about challenge requests made'; -- -- Name: mfa_factors; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.mfa_factors ( id uuid NOT NULL, user_id uuid NOT NULL, friendly_name text, factor_type auth.factor_type NOT NULL, status auth.factor_status NOT NULL, created_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL, secret text, phone text, last_challenged_at timestamp with time zone, web_authn_credential jsonb, web_authn_aaguid uuid, last_webauthn_challenge_data jsonb ); -- -- Name: TABLE mfa_factors; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.mfa_factors IS 'auth: stores metadata about factors'; -- -- Name: COLUMN mfa_factors.last_webauthn_challenge_data; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON COLUMN auth.mfa_factors.last_webauthn_challenge_data IS 'Stores the latest WebAuthn challenge data including attestation/assertion for customer verification'; -- -- Name: oauth_authorizations; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.oauth_authorizations ( id uuid NOT NULL, authorization_id text NOT NULL, client_id uuid NOT NULL, user_id uuid, redirect_uri text NOT NULL, scope text NOT NULL, state text, resource text, code_challenge text, code_challenge_method auth.code_challenge_method, response_type auth.oauth_response_type DEFAULT 'code'::auth.oauth_response_type NOT NULL, status auth.oauth_authorization_status DEFAULT 'pending'::auth.oauth_authorization_status NOT NULL, authorization_code text, created_at timestamp with time zone DEFAULT now() NOT NULL, expires_at timestamp with time zone DEFAULT (now() + '00:03:00'::interval) NOT NULL, approved_at timestamp with time zone, nonce text, CONSTRAINT oauth_authorizations_authorization_code_length CHECK ((char_length(authorization_code) <= 255)), CONSTRAINT oauth_authorizations_code_challenge_length CHECK ((char_length(code_challenge) <= 128)), CONSTRAINT oauth_authorizations_expires_at_future CHECK ((expires_at > created_at)), CONSTRAINT oauth_authorizations_nonce_length CHECK ((char_length(nonce) <= 255)), CONSTRAINT oauth_authorizations_redirect_uri_length CHECK ((char_length(redirect_uri) <= 2048)), CONSTRAINT oauth_authorizations_resource_length CHECK ((char_length(resource) <= 2048)), CONSTRAINT oauth_authorizations_scope_length CHECK ((char_length(scope) <= 4096)), CONSTRAINT oauth_authorizations_state_length CHECK ((char_length(state) <= 4096)) ); -- -- Name: oauth_client_states; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.oauth_client_states ( id uuid NOT NULL, provider_type text NOT NULL, code_verifier text, created_at timestamp with time zone NOT NULL ); -- -- Name: TABLE oauth_client_states; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.oauth_client_states IS 'Stores OAuth states for third-party provider authentication flows where Supabase acts as the OAuth client.'; -- -- Name: oauth_clients; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.oauth_clients ( id uuid NOT NULL, client_secret_hash text, registration_type auth.oauth_registration_type NOT NULL, redirect_uris text NOT NULL, grant_types text NOT NULL, client_name text, client_uri text, logo_uri text, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, deleted_at timestamp with time zone, client_type auth.oauth_client_type DEFAULT 'confidential'::auth.oauth_client_type NOT NULL, token_endpoint_auth_method text NOT NULL, CONSTRAINT oauth_clients_client_name_length CHECK ((char_length(client_name) <= 1024)), CONSTRAINT oauth_clients_client_uri_length CHECK ((char_length(client_uri) <= 2048)), CONSTRAINT oauth_clients_logo_uri_length CHECK ((char_length(logo_uri) <= 2048)), CONSTRAINT oauth_clients_token_endpoint_auth_method_check CHECK ((token_endpoint_auth_method = ANY (ARRAY['client_secret_basic'::text, 'client_secret_post'::text, 'none'::text]))) ); -- -- Name: oauth_consents; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.oauth_consents ( id uuid NOT NULL, user_id uuid NOT NULL, client_id uuid NOT NULL, scopes text NOT NULL, granted_at timestamp with time zone DEFAULT now() NOT NULL, revoked_at timestamp with time zone, CONSTRAINT oauth_consents_revoked_after_granted CHECK (((revoked_at IS NULL) OR (revoked_at >= granted_at))), CONSTRAINT oauth_consents_scopes_length CHECK ((char_length(scopes) <= 2048)), CONSTRAINT oauth_consents_scopes_not_empty CHECK ((char_length(TRIM(BOTH FROM scopes)) > 0)) ); -- -- Name: one_time_tokens; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.one_time_tokens ( id uuid NOT NULL, user_id uuid NOT NULL, token_type auth.one_time_token_type NOT NULL, token_hash text NOT NULL, relates_to text NOT NULL, created_at timestamp without time zone DEFAULT now() NOT NULL, updated_at timestamp without time zone DEFAULT now() NOT NULL, CONSTRAINT one_time_tokens_token_hash_check CHECK ((char_length(token_hash) > 0)) ); -- -- Name: refresh_tokens; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.refresh_tokens ( instance_id uuid, id bigint NOT NULL, token character varying(255), user_id character varying(255), revoked boolean, created_at timestamp with time zone, updated_at timestamp with time zone, parent character varying(255), session_id uuid ); -- -- Name: TABLE refresh_tokens; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.refresh_tokens IS 'Auth: Store of tokens used to refresh JWT tokens once they expire.'; -- -- Name: refresh_tokens_id_seq; Type: SEQUENCE; Schema: auth; Owner: - -- CREATE SEQUENCE auth.refresh_tokens_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; -- -- Name: refresh_tokens_id_seq; Type: SEQUENCE OWNED BY; Schema: auth; Owner: - -- ALTER SEQUENCE auth.refresh_tokens_id_seq OWNED BY auth.refresh_tokens.id; -- -- Name: saml_providers; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.saml_providers ( id uuid NOT NULL, sso_provider_id uuid NOT NULL, entity_id text NOT NULL, metadata_xml text NOT NULL, metadata_url text, attribute_mapping jsonb, created_at timestamp with time zone, updated_at timestamp with time zone, name_id_format text, CONSTRAINT "entity_id not empty" CHECK ((char_length(entity_id) > 0)), CONSTRAINT "metadata_url not empty" CHECK (((metadata_url = NULL::text) OR (char_length(metadata_url) > 0))), CONSTRAINT "metadata_xml not empty" CHECK ((char_length(metadata_xml) > 0)) ); -- -- Name: TABLE saml_providers; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.saml_providers IS 'Auth: Manages SAML Identity Provider connections.'; -- -- Name: saml_relay_states; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.saml_relay_states ( id uuid NOT NULL, sso_provider_id uuid NOT NULL, request_id text NOT NULL, for_email text, redirect_to text, created_at timestamp with time zone, updated_at timestamp with time zone, flow_state_id uuid, CONSTRAINT "request_id not empty" CHECK ((char_length(request_id) > 0)) ); -- -- Name: TABLE saml_relay_states; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.saml_relay_states IS 'Auth: Contains SAML Relay State information for each Service Provider initiated login.'; -- -- Name: schema_migrations; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.schema_migrations ( version character varying(255) NOT NULL ); -- -- Name: TABLE schema_migrations; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.schema_migrations IS 'Auth: Manages updates to the auth system.'; -- -- Name: sessions; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.sessions ( id uuid NOT NULL, user_id uuid NOT NULL, created_at timestamp with time zone, updated_at timestamp with time zone, factor_id uuid, aal auth.aal_level, not_after timestamp with time zone, refreshed_at timestamp without time zone, user_agent text, ip inet, tag text, oauth_client_id uuid, refresh_token_hmac_key text, refresh_token_counter bigint, scopes text, CONSTRAINT sessions_scopes_length CHECK ((char_length(scopes) <= 4096)) ); -- -- Name: TABLE sessions; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.sessions IS 'Auth: Stores session data associated to a user.'; -- -- Name: COLUMN sessions.not_after; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON COLUMN auth.sessions.not_after IS 'Auth: Not after is a nullable column that contains a timestamp after which the session should be regarded as expired.'; -- -- Name: COLUMN sessions.refresh_token_hmac_key; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON COLUMN auth.sessions.refresh_token_hmac_key IS 'Holds a HMAC-SHA256 key used to sign refresh tokens for this session.'; -- -- Name: COLUMN sessions.refresh_token_counter; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON COLUMN auth.sessions.refresh_token_counter IS 'Holds the ID (counter) of the last issued refresh token.'; -- -- Name: sso_domains; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.sso_domains ( id uuid NOT NULL, sso_provider_id uuid NOT NULL, domain text NOT NULL, created_at timestamp with time zone, updated_at timestamp with time zone, CONSTRAINT "domain not empty" CHECK ((char_length(domain) > 0)) ); -- -- Name: TABLE sso_domains; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.sso_domains IS 'Auth: Manages SSO email address domain mapping to an SSO Identity Provider.'; -- -- Name: sso_providers; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.sso_providers ( id uuid NOT NULL, resource_id text, created_at timestamp with time zone, updated_at timestamp with time zone, disabled boolean, CONSTRAINT "resource_id not empty" CHECK (((resource_id = NULL::text) OR (char_length(resource_id) > 0))) ); -- -- Name: TABLE sso_providers; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.sso_providers IS 'Auth: Manages SSO identity provider information; see saml_providers for SAML.'; -- -- Name: COLUMN sso_providers.resource_id; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON COLUMN auth.sso_providers.resource_id IS 'Auth: Uniquely identifies a SSO provider according to a user-chosen resource ID (case insensitive), useful in infrastructure as code.'; -- -- Name: users; Type: TABLE; Schema: auth; Owner: - -- CREATE TABLE auth.users ( instance_id uuid, id uuid NOT NULL, aud character varying(255), role character varying(255), email character varying(255), encrypted_password character varying(255), email_confirmed_at timestamp with time zone, invited_at timestamp with time zone, confirmation_token character varying(255), confirmation_sent_at timestamp with time zone, recovery_token character varying(255), recovery_sent_at timestamp with time zone, email_change_token_new character varying(255), email_change character varying(255), email_change_sent_at timestamp with time zone, last_sign_in_at timestamp with time zone, raw_app_meta_data jsonb, raw_user_meta_data jsonb, is_super_admin boolean, created_at timestamp with time zone, updated_at timestamp with time zone, phone text DEFAULT NULL::character varying, phone_confirmed_at timestamp with time zone, phone_change text DEFAULT ''::character varying, phone_change_token character varying(255) DEFAULT ''::character varying, phone_change_sent_at timestamp with time zone, confirmed_at timestamp with time zone GENERATED ALWAYS AS (LEAST(email_confirmed_at, phone_confirmed_at)) STORED, email_change_token_current character varying(255) DEFAULT ''::character varying, email_change_confirm_status smallint DEFAULT 0, banned_until timestamp with time zone, reauthentication_token character varying(255) DEFAULT ''::character varying, reauthentication_sent_at timestamp with time zone, is_sso_user boolean DEFAULT false NOT NULL, deleted_at timestamp with time zone, is_anonymous boolean DEFAULT false NOT NULL, CONSTRAINT users_email_change_confirm_status_check CHECK (((email_change_confirm_status >= 0) AND (email_change_confirm_status <= 2))) ); -- -- Name: TABLE users; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON TABLE auth.users IS 'Auth: Stores user login data within a secure schema.'; -- -- Name: COLUMN users.is_sso_user; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON COLUMN auth.users.is_sso_user IS 'Auth: Set this column to true when the account comes from SSO. These accounts can have duplicate emails.'; -- -- Name: _db_migrations; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public._db_migrations ( id integer NOT NULL, filename text NOT NULL, hash text NOT NULL, category text DEFAULT 'migration'::text NOT NULL, applied_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: _db_migrations_id_seq; Type: SEQUENCE; Schema: public; Owner: - -- CREATE SEQUENCE public._db_migrations_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; -- -- Name: _db_migrations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - -- ALTER SEQUENCE public._db_migrations_id_seq OWNED BY public._db_migrations.id; -- -- Name: addon_credits; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.addon_credits ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, owner_id uuid, addon_type text NOT NULL, balance integer DEFAULT 0 NOT NULL, total_purchased integer DEFAULT 0 NOT NULL, total_consumed integer DEFAULT 0 NOT NULL, low_balance_threshold integer DEFAULT 10, low_balance_notified boolean DEFAULT false, daily_limit integer, hourly_limit integer, daily_used integer DEFAULT 0, hourly_used integer DEFAULT 0, daily_reset_at timestamp with time zone, hourly_reset_at timestamp with time zone, from_number_override text, expires_at timestamp with time zone, is_active boolean DEFAULT true, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now() ); -- -- Name: TABLE addon_credits; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON TABLE public.addon_credits IS 'Saldo de cr??ditos de add-ons por tenant. Um registro por (tenant_id, addon_type).'; -- -- Name: addon_products; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.addon_products ( id uuid DEFAULT gen_random_uuid() NOT NULL, slug text NOT NULL, name text NOT NULL, description text, addon_type text NOT NULL, icon text DEFAULT 'pi pi-box'::text, credits_amount integer DEFAULT 0, price_cents integer DEFAULT 0 NOT NULL, currency text DEFAULT 'BRL'::text, is_active boolean DEFAULT true, is_visible boolean DEFAULT true, sort_order integer DEFAULT 0, metadata jsonb DEFAULT '{}'::jsonb, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now(), deleted_at timestamp with time zone ); -- -- Name: TABLE addon_products; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON TABLE public.addon_products IS 'Cat??logo de recursos extras vendidos pela plataforma (SMS, servidor, dom??nio, etc.)'; -- -- Name: addon_transactions; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.addon_transactions ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, owner_id uuid, addon_type text NOT NULL, type text NOT NULL, amount integer NOT NULL, balance_before integer DEFAULT 0 NOT NULL, balance_after integer DEFAULT 0 NOT NULL, product_id uuid, queue_id uuid, description text, admin_user_id uuid, payment_method text, payment_reference text, price_cents integer, currency text DEFAULT 'BRL'::text, created_at timestamp with time zone DEFAULT now(), metadata jsonb DEFAULT '{}'::jsonb ); -- -- Name: TABLE addon_transactions; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON TABLE public.addon_transactions IS 'Hist??rico de todas as transa????es de cr??ditos: compras, consumo, ajustes, reembolsos.'; -- -- Name: agenda_bloqueios; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.agenda_bloqueios ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, tenant_id uuid, tipo text NOT NULL, titulo text NOT NULL, data_inicio date NOT NULL, data_fim date, hora_inicio time without time zone, hora_fim time without time zone, recorrente boolean DEFAULT false NOT NULL, dia_semana smallint, observacao text, origem text DEFAULT 'manual'::text NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT agenda_bloqueios_tipo_check CHECK ((tipo = ANY (ARRAY['feriado_nacional'::text, 'feriado_municipal'::text, 'bloqueio'::text]))) ); -- -- Name: agenda_configuracoes; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.agenda_configuracoes ( owner_id uuid NOT NULL, duracao_padrao_minutos integer DEFAULT 50 NOT NULL, intervalo_padrao_minutos integer DEFAULT 0 NOT NULL, timezone text DEFAULT 'America/Sao_Paulo'::text NOT NULL, usar_horario_admin_custom boolean DEFAULT false NOT NULL, admin_inicio_visualizacao time without time zone, admin_fim_visualizacao time without time zone, admin_slot_visual_minutos integer DEFAULT 30 NOT NULL, online_ativo boolean DEFAULT false NOT NULL, online_min_antecedencia_horas integer DEFAULT 24 NOT NULL, online_max_dias_futuro integer DEFAULT 60 NOT NULL, online_cancelar_ate_horas integer DEFAULT 12 NOT NULL, online_reagendar_ate_horas integer DEFAULT 12 NOT NULL, online_limite_agendamentos_futuros integer DEFAULT 1 NOT NULL, online_modo text DEFAULT 'automatico'::text NOT NULL, online_buffer_antes_min integer DEFAULT 0 NOT NULL, online_buffer_depois_min integer DEFAULT 0 NOT NULL, online_modalidade text DEFAULT 'ambos'::text NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, usar_granularidade_custom boolean DEFAULT false NOT NULL, granularidade_min integer, setup_concluido boolean DEFAULT false NOT NULL, setup_concluido_em timestamp with time zone, agenda_view_mode text DEFAULT 'full_24h'::text NOT NULL, agenda_custom_start time without time zone, agenda_custom_end time without time zone, session_duration_min integer DEFAULT 50 NOT NULL, session_break_min integer DEFAULT 10 NOT NULL, pausas_semanais jsonb DEFAULT '[]'::jsonb NOT NULL, setup_clinica_concluido boolean DEFAULT false NOT NULL, setup_clinica_concluido_em timestamp with time zone, tenant_id uuid, jornada_igual_todos boolean DEFAULT true, slot_mode text DEFAULT 'fixed'::text NOT NULL, CONSTRAINT agenda_configuracoes_admin_slot_visual_minutos_check CHECK ((admin_slot_visual_minutos = ANY (ARRAY[5, 10, 15, 20, 30, 60]))), CONSTRAINT agenda_configuracoes_check CHECK (((usar_horario_admin_custom = false) OR ((admin_inicio_visualizacao IS NOT NULL) AND (admin_fim_visualizacao IS NOT NULL) AND (admin_fim_visualizacao > admin_inicio_visualizacao)))), CONSTRAINT agenda_configuracoes_duracao_padrao_minutos_check CHECK (((duracao_padrao_minutos >= 10) AND (duracao_padrao_minutos <= 240))), CONSTRAINT agenda_configuracoes_granularidade_min_check CHECK (((granularidade_min IS NULL) OR (granularidade_min = ANY (ARRAY[5, 10, 15, 20, 30, 45, 50, 60])))), CONSTRAINT agenda_configuracoes_intervalo_padrao_minutos_check CHECK (((intervalo_padrao_minutos >= 0) AND (intervalo_padrao_minutos <= 120))), CONSTRAINT agenda_configuracoes_online_buffer_antes_min_check CHECK (((online_buffer_antes_min >= 0) AND (online_buffer_antes_min <= 120))), CONSTRAINT agenda_configuracoes_online_buffer_depois_min_check CHECK (((online_buffer_depois_min >= 0) AND (online_buffer_depois_min <= 120))), CONSTRAINT agenda_configuracoes_online_cancelar_ate_horas_check CHECK (((online_cancelar_ate_horas >= 0) AND (online_cancelar_ate_horas <= 720))), CONSTRAINT agenda_configuracoes_online_limite_agendamentos_futuros_check CHECK (((online_limite_agendamentos_futuros >= 1) AND (online_limite_agendamentos_futuros <= 10))), CONSTRAINT agenda_configuracoes_online_max_dias_futuro_check CHECK (((online_max_dias_futuro >= 1) AND (online_max_dias_futuro <= 365))), CONSTRAINT agenda_configuracoes_online_min_antecedencia_horas_check CHECK (((online_min_antecedencia_horas >= 0) AND (online_min_antecedencia_horas <= 720))), CONSTRAINT agenda_configuracoes_online_modalidade_check CHECK ((online_modalidade = ANY (ARRAY['online'::text, 'presencial'::text, 'ambos'::text]))), CONSTRAINT agenda_configuracoes_online_modo_check CHECK ((online_modo = ANY (ARRAY['automatico'::text, 'aprovacao'::text]))), CONSTRAINT agenda_configuracoes_online_reagendar_ate_horas_check CHECK (((online_reagendar_ate_horas >= 0) AND (online_reagendar_ate_horas <= 720))), CONSTRAINT agenda_configuracoes_slot_mode_chk CHECK ((slot_mode = ANY (ARRAY['fixed'::text, 'dynamic'::text]))), CONSTRAINT session_break_min_chk CHECK (((session_break_min >= 0) AND (session_break_min <= 60))), CONSTRAINT session_duration_min_chk CHECK (((session_duration_min >= 10) AND (session_duration_min <= 240))) ); -- -- Name: agenda_eventos; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.agenda_eventos ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, tipo public.tipo_evento_agenda DEFAULT 'sessao'::public.tipo_evento_agenda NOT NULL, status public.status_evento_agenda DEFAULT 'agendado'::public.status_evento_agenda NOT NULL, titulo text, observacoes text, inicio_em timestamp with time zone NOT NULL, fim_em timestamp with time zone NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, terapeuta_id uuid, tenant_id uuid NOT NULL, visibility_scope text DEFAULT 'public'::text NOT NULL, mirror_of_event_id uuid, mirror_source text, patient_id uuid, determined_commitment_id uuid, link_online text, titulo_custom text, extra_fields jsonb, recurrence_id uuid, recurrence_date date, modalidade text DEFAULT 'presencial'::text, price numeric(10,2), billing_contract_id uuid, billed boolean DEFAULT false NOT NULL, services_customized boolean DEFAULT false NOT NULL, insurance_plan_id uuid, insurance_guide_number text, insurance_value numeric(10,2), insurance_plan_service_id uuid, CONSTRAINT agenda_eventos_check CHECK ((fim_em > inicio_em)) ); -- -- Name: COLUMN agenda_eventos.price; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.agenda_eventos.price IS 'Valor da sess??o em BRL. Preenchido automaticamente pela tabela professional_pricing do profissional.'; -- -- Name: agenda_excecoes; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.agenda_excecoes ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, data date NOT NULL, hora_inicio time without time zone, hora_fim time without time zone, tipo public.tipo_excecao_agenda NOT NULL, motivo text, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, status public.status_excecao_agenda DEFAULT 'ativo'::public.status_excecao_agenda NOT NULL, fonte text DEFAULT 'manual'::text NOT NULL, aplicavel_online boolean DEFAULT true NOT NULL, tenant_id uuid NOT NULL, CONSTRAINT agenda_excecoes_check CHECK ((((hora_inicio IS NULL) AND (hora_fim IS NULL)) OR ((hora_inicio IS NOT NULL) AND (hora_fim IS NOT NULL) AND (hora_fim > hora_inicio)))), CONSTRAINT agenda_excecoes_fonte_check CHECK ((fonte = ANY (ARRAY['manual'::text, 'feriado_google'::text, 'sistema'::text]))) ); -- -- Name: agenda_online_slots; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.agenda_online_slots ( id bigint NOT NULL, owner_id uuid NOT NULL, weekday integer NOT NULL, "time" time without time zone NOT NULL, enabled boolean DEFAULT true NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, tenant_id uuid NOT NULL, CONSTRAINT agenda_online_slots_weekday_check CHECK ((weekday = ANY (ARRAY[0, 1, 2, 3, 4, 5, 6]))) ); -- -- Name: agenda_online_slots_id_seq; Type: SEQUENCE; Schema: public; Owner: - -- CREATE SEQUENCE public.agenda_online_slots_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; -- -- Name: agenda_online_slots_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - -- ALTER SEQUENCE public.agenda_online_slots_id_seq OWNED BY public.agenda_online_slots.id; -- -- Name: agenda_regras_semanais; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.agenda_regras_semanais ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, dia_semana smallint NOT NULL, hora_inicio time without time zone NOT NULL, hora_fim time without time zone NOT NULL, modalidade text DEFAULT 'ambos'::text NOT NULL, ativo boolean DEFAULT true NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, tenant_id uuid NOT NULL, CONSTRAINT agenda_regras_semanais_check CHECK ((hora_fim > hora_inicio)), CONSTRAINT agenda_regras_semanais_dia_semana_check CHECK (((dia_semana >= 0) AND (dia_semana <= 6))), CONSTRAINT agenda_regras_semanais_modalidade_check CHECK (((modalidade = ANY (ARRAY['online'::text, 'presencial'::text, 'ambos'::text])) OR (modalidade IS NULL))) ); -- -- Name: agenda_slots_bloqueados_semanais; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.agenda_slots_bloqueados_semanais ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, dia_semana smallint NOT NULL, hora_inicio time without time zone NOT NULL, motivo text, ativo boolean DEFAULT true NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, tenant_id uuid NOT NULL, CONSTRAINT agenda_slots_bloqueados_semanais_dia_semana_check CHECK (((dia_semana >= 0) AND (dia_semana <= 6))) ); -- -- Name: agenda_slots_regras; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.agenda_slots_regras ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, dia_semana smallint NOT NULL, passo_minutos integer NOT NULL, offset_minutos integer DEFAULT 0 NOT NULL, buffer_antes_min integer DEFAULT 0 NOT NULL, buffer_depois_min integer DEFAULT 0 NOT NULL, min_antecedencia_horas integer DEFAULT 0 NOT NULL, ativo boolean DEFAULT true NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, tenant_id uuid NOT NULL, CONSTRAINT agenda_slots_regras_buffer_antes_min_check CHECK (((buffer_antes_min >= 0) AND (buffer_antes_min <= 240))), CONSTRAINT agenda_slots_regras_buffer_depois_min_check CHECK (((buffer_depois_min >= 0) AND (buffer_depois_min <= 240))), CONSTRAINT agenda_slots_regras_dia_semana_check CHECK (((dia_semana >= 0) AND (dia_semana <= 6))), CONSTRAINT agenda_slots_regras_min_antecedencia_horas_check CHECK (((min_antecedencia_horas >= 0) AND (min_antecedencia_horas <= 720))), CONSTRAINT agenda_slots_regras_offset_minutos_check CHECK (((offset_minutos >= 0) AND (offset_minutos <= 55))), CONSTRAINT agenda_slots_regras_passo_minutos_check CHECK (((passo_minutos >= 5) AND (passo_minutos <= 240))) ); -- -- Name: agendador_configuracoes; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.agendador_configuracoes ( owner_id uuid NOT NULL, tenant_id uuid, ativo boolean DEFAULT false NOT NULL, link_slug text, imagem_fundo_url text, imagem_header_url text, logomarca_url text, cor_primaria text DEFAULT '#4b6bff'::text, nome_exibicao text, endereco text, botao_como_chegar_ativo boolean DEFAULT true NOT NULL, maps_url text, modo_aprovacao text DEFAULT 'aprovacao'::text NOT NULL, modalidade text DEFAULT 'presencial'::text NOT NULL, tipos_habilitados jsonb DEFAULT '["primeira", "retorno"]'::jsonb NOT NULL, duracao_sessao_min integer DEFAULT 50 NOT NULL, antecedencia_minima_horas integer DEFAULT 24 NOT NULL, prazo_resposta_horas integer DEFAULT 2 NOT NULL, reserva_horas integer DEFAULT 2 NOT NULL, pagamento_obrigatorio boolean DEFAULT false NOT NULL, pix_chave text, pix_countdown_minutos integer DEFAULT 20 NOT NULL, triagem_motivo boolean DEFAULT true NOT NULL, triagem_como_conheceu boolean DEFAULT false NOT NULL, verificacao_email boolean DEFAULT false NOT NULL, exigir_aceite_lgpd boolean DEFAULT true NOT NULL, mensagem_boas_vindas text, texto_como_se_preparar text, texto_termos_lgpd text, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, pagamento_modo text DEFAULT 'sem_pagamento'::text NOT NULL, pagamento_metodos_visiveis text[] DEFAULT '{}'::text[] NOT NULL, CONSTRAINT agendador_configuracoes_antecedencia_check CHECK (((antecedencia_minima_horas >= 0) AND (antecedencia_minima_horas <= 720))), CONSTRAINT agendador_configuracoes_duracao_check CHECK (((duracao_sessao_min >= 10) AND (duracao_sessao_min <= 240))), CONSTRAINT agendador_configuracoes_modalidade_check CHECK ((modalidade = ANY (ARRAY['presencial'::text, 'online'::text, 'ambos'::text]))), CONSTRAINT agendador_configuracoes_modo_check CHECK ((modo_aprovacao = ANY (ARRAY['automatico'::text, 'aprovacao'::text]))), CONSTRAINT agendador_configuracoes_pix_countdown_check CHECK (((pix_countdown_minutos >= 5) AND (pix_countdown_minutos <= 120))), CONSTRAINT agendador_configuracoes_prazo_check CHECK (((prazo_resposta_horas >= 1) AND (prazo_resposta_horas <= 72))), CONSTRAINT agendador_configuracoes_reserva_check CHECK (((reserva_horas >= 1) AND (reserva_horas <= 48))) ); -- -- Name: COLUMN agendador_configuracoes.pagamento_modo; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.agendador_configuracoes.pagamento_modo IS 'sem_pagamento | pagar_na_hora | pix_antecipado'; -- -- Name: COLUMN agendador_configuracoes.pagamento_metodos_visiveis; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.agendador_configuracoes.pagamento_metodos_visiveis IS 'M??todos exibidos ao paciente quando pagamento_modo = pagar_na_hora. Ex: {pix, deposito, dinheiro, cartao, convenio}'; -- -- Name: agendador_solicitacoes; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.agendador_solicitacoes ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, tenant_id uuid, paciente_nome text NOT NULL, paciente_sobrenome text, paciente_email text NOT NULL, paciente_celular text, paciente_cpf text, tipo text NOT NULL, modalidade text NOT NULL, data_solicitada date NOT NULL, hora_solicitada time without time zone NOT NULL, reservado_ate timestamp with time zone, motivo text, como_conheceu text, pix_status text DEFAULT 'pendente'::text, pix_pago_em timestamp with time zone, status text DEFAULT 'pendente'::text NOT NULL, recusado_motivo text, autorizado_em timestamp with time zone, autorizado_por uuid, user_id uuid, patient_id uuid, evento_id uuid, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT agendador_sol_modalidade_check CHECK ((modalidade = ANY (ARRAY['presencial'::text, 'online'::text]))), CONSTRAINT agendador_sol_pix_check CHECK (((pix_status IS NULL) OR (pix_status = ANY (ARRAY['pendente'::text, 'pago'::text, 'expirado'::text])))), CONSTRAINT agendador_sol_status_check CHECK ((status = ANY (ARRAY['pendente'::text, 'autorizado'::text, 'recusado'::text, 'expirado'::text, 'convertido'::text]))), CONSTRAINT agendador_sol_tipo_check CHECK ((tipo = ANY (ARRAY['primeira'::text, 'retorno'::text, 'reagendar'::text]))) ); -- -- Name: billing_contracts; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.billing_contracts ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, tenant_id uuid NOT NULL, patient_id uuid NOT NULL, type text NOT NULL, total_sessions integer, sessions_used integer DEFAULT 0, package_price numeric(10,2), amount numeric(10,2), billing_interval text, active_from timestamp with time zone DEFAULT now(), active_to timestamp with time zone, status text DEFAULT 'active'::text NOT NULL, created_at timestamp with time zone DEFAULT now(), CONSTRAINT billing_contracts_interval_chk CHECK (((billing_interval IS NULL) OR (billing_interval = ANY (ARRAY['monthly'::text, 'weekly'::text])))), CONSTRAINT billing_contracts_sess_used_chk CHECK (((sessions_used IS NULL) OR (sessions_used >= 0))), CONSTRAINT billing_contracts_status_chk CHECK ((status = ANY (ARRAY['active'::text, 'completed'::text, 'cancelled'::text]))), CONSTRAINT billing_contracts_total_sess_chk CHECK (((total_sessions IS NULL) OR (total_sessions > 0))), CONSTRAINT billing_contracts_type_chk CHECK ((type = ANY (ARRAY['per_session'::text, 'package'::text, 'subscription'::text]))) ); -- -- Name: commitment_services; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.commitment_services ( id uuid DEFAULT gen_random_uuid() NOT NULL, commitment_id uuid NOT NULL, service_id uuid NOT NULL, quantity integer DEFAULT 1 NOT NULL, unit_price numeric(10,2) NOT NULL, discount_pct numeric(5,2) DEFAULT 0, discount_flat numeric(10,2) DEFAULT 0, final_price numeric(10,2) NOT NULL, created_at timestamp with time zone DEFAULT now(), CONSTRAINT commitment_services_disc_flat_chk CHECK ((discount_flat >= (0)::numeric)), CONSTRAINT commitment_services_disc_pct_chk CHECK (((discount_pct >= (0)::numeric) AND (discount_pct <= (100)::numeric))), CONSTRAINT commitment_services_final_price_chk CHECK ((final_price >= (0)::numeric)), CONSTRAINT commitment_services_quantity_chk CHECK ((quantity > 0)) ); -- -- Name: commitment_time_logs; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.commitment_time_logs ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, commitment_id uuid NOT NULL, calendar_event_id uuid, source public.commitment_log_source DEFAULT 'manual'::public.commitment_log_source NOT NULL, started_at timestamp with time zone NOT NULL, ended_at timestamp with time zone NOT NULL, minutes integer NOT NULL, created_by uuid, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: company_profiles; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.company_profiles ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, nome_fantasia text, razao_social text, tipo_empresa text, cnpj text, ie text, im text, cep text, logradouro text, numero text, complemento text, bairro text, cidade text, estado text, email text, telefone text, site text, logo_url text, redes_sociais jsonb DEFAULT '[]'::jsonb NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: current_tenant_id; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.current_tenant_id AS SELECT current_setting('request.jwt.claim.tenant_id'::text, true) AS current_setting; -- -- Name: determined_commitment_fields; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.determined_commitment_fields ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, commitment_id uuid NOT NULL, key text NOT NULL, label text NOT NULL, field_type public.determined_field_type DEFAULT 'text'::public.determined_field_type NOT NULL, required boolean DEFAULT false NOT NULL, sort_order integer DEFAULT 0 NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: determined_commitments; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.determined_commitments ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, created_by uuid, is_native boolean DEFAULT false NOT NULL, native_key text, is_locked boolean DEFAULT false NOT NULL, active boolean DEFAULT true NOT NULL, name text NOT NULL, description text, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, bg_color text, text_color text ); -- -- Name: dev_user_credentials; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.dev_user_credentials ( id uuid DEFAULT gen_random_uuid() NOT NULL, user_id uuid, email text NOT NULL, password_dev text NOT NULL, kind text DEFAULT 'custom'::text NOT NULL, note text, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: email_layout_config; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.email_layout_config ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, header_config jsonb DEFAULT '{"layout": null, "content": "", "enabled": false}'::jsonb NOT NULL, footer_config jsonb DEFAULT '{"layout": null, "content": "", "enabled": false}'::jsonb NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: email_templates_global; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.email_templates_global ( id uuid DEFAULT gen_random_uuid() NOT NULL, key text NOT NULL, domain text NOT NULL, channel text DEFAULT 'email'::text NOT NULL, subject text NOT NULL, body_html text NOT NULL, body_text text, version integer DEFAULT 1 NOT NULL, is_active boolean DEFAULT true NOT NULL, variables jsonb, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: email_templates_tenant; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.email_templates_tenant ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, owner_id uuid, template_key text NOT NULL, subject text, body_html text, body_text text, enabled boolean DEFAULT true NOT NULL, synced_version integer, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: entitlements_invalidation; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.entitlements_invalidation ( owner_id uuid NOT NULL, changed_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: features; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.features ( id uuid DEFAULT gen_random_uuid() NOT NULL, key text NOT NULL, description text, created_at timestamp with time zone DEFAULT now() NOT NULL, descricao text DEFAULT ''::text NOT NULL, name text DEFAULT ''::text NOT NULL ); -- -- Name: COLUMN features.descricao; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.features.descricao IS 'Descri????o humana da feature (exibi????o no admin e documenta????o).'; -- -- Name: feriados; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.feriados ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid, owner_id uuid, tipo text DEFAULT 'municipal'::text NOT NULL, nome text NOT NULL, data date NOT NULL, cidade text, estado text, observacao text, bloqueia_sessoes boolean DEFAULT false NOT NULL, criado_em timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT feriados_tipo_check CHECK ((tipo = ANY (ARRAY['municipal'::text, 'personalizado'::text]))) ); -- -- Name: financial_categories; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.financial_categories ( id uuid DEFAULT gen_random_uuid() NOT NULL, user_id uuid NOT NULL, name text NOT NULL, type public.financial_record_type DEFAULT 'receita'::public.financial_record_type NOT NULL, color text DEFAULT '#6366f1'::text, icon text DEFAULT 'pi pi-tag'::text, sort_order integer DEFAULT 0, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: financial_exceptions; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.financial_exceptions ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid, tenant_id uuid NOT NULL, exception_type text NOT NULL, charge_mode text NOT NULL, charge_value numeric(10,2), charge_pct numeric(5,2), min_hours_notice integer, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now(), CONSTRAINT financial_exceptions_charge_chk CHECK ((charge_mode = ANY (ARRAY['none'::text, 'full'::text, 'fixed_fee'::text, 'percentage'::text]))), CONSTRAINT financial_exceptions_type_chk CHECK ((exception_type = ANY (ARRAY['patient_no_show'::text, 'patient_cancellation'::text, 'professional_cancellation'::text]))) ); -- -- Name: global_notices; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.global_notices ( id uuid DEFAULT gen_random_uuid() NOT NULL, title text, message text DEFAULT ''::text NOT NULL, variant text DEFAULT 'info'::text NOT NULL, roles text[] DEFAULT '{}'::text[] NOT NULL, contexts text[] DEFAULT '{}'::text[] NOT NULL, starts_at timestamp with time zone, ends_at timestamp with time zone, is_active boolean DEFAULT true NOT NULL, priority integer DEFAULT 0 NOT NULL, dismissible boolean DEFAULT true NOT NULL, persist_dismiss boolean DEFAULT true NOT NULL, dismiss_scope text DEFAULT 'device'::text NOT NULL, show_once boolean DEFAULT false NOT NULL, max_views integer, cooldown_minutes integer, version integer DEFAULT 1 NOT NULL, action_type text DEFAULT 'none'::text NOT NULL, action_label text, action_url text, action_route text, views_count integer DEFAULT 0 NOT NULL, clicks_count integer DEFAULT 0 NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, created_by uuid, content_align text DEFAULT 'left'::text NOT NULL, link_target text DEFAULT '_blank'::text NOT NULL, CONSTRAINT global_notices_action_type_check CHECK ((action_type = ANY (ARRAY['none'::text, 'internal'::text, 'external'::text]))), CONSTRAINT global_notices_content_align_check CHECK ((content_align = ANY (ARRAY['left'::text, 'center'::text, 'right'::text, 'justify'::text]))), CONSTRAINT global_notices_dismiss_scope_check CHECK ((dismiss_scope = ANY (ARRAY['session'::text, 'device'::text, 'user'::text]))), CONSTRAINT global_notices_link_target_check CHECK ((link_target = ANY (ARRAY['_blank'::text, '_self'::text, '_parent'::text, '_top'::text]))), CONSTRAINT global_notices_variant_check CHECK ((variant = ANY (ARRAY['info'::text, 'success'::text, 'warning'::text, 'error'::text]))) ); -- -- Name: insurance_plan_services; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.insurance_plan_services ( id uuid DEFAULT gen_random_uuid() NOT NULL, insurance_plan_id uuid NOT NULL, name text NOT NULL, value numeric(10,2) NOT NULL, active boolean DEFAULT true NOT NULL, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now() ); -- -- Name: insurance_plans; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.insurance_plans ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, tenant_id uuid NOT NULL, name text NOT NULL, notes text, default_value numeric(10,2), active boolean DEFAULT true NOT NULL, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now() ); -- -- Name: login_carousel_slides; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.login_carousel_slides ( id uuid DEFAULT gen_random_uuid() NOT NULL, title text NOT NULL, body text NOT NULL, icon text DEFAULT 'pi-star'::text NOT NULL, ordem integer DEFAULT 0 NOT NULL, ativo boolean DEFAULT true NOT NULL, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now() ); -- -- Name: module_features; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.module_features ( module_id uuid NOT NULL, feature_id uuid NOT NULL, enabled boolean DEFAULT true NOT NULL, limits jsonb, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: modules; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.modules ( id uuid DEFAULT gen_random_uuid() NOT NULL, key text NOT NULL, name text NOT NULL, description text, is_active boolean DEFAULT true NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: notice_dismissals; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.notice_dismissals ( id uuid DEFAULT gen_random_uuid() NOT NULL, notice_id uuid NOT NULL, user_id uuid NOT NULL, version integer DEFAULT 1 NOT NULL, dismissed_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: notification_channels; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.notification_channels ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, owner_id uuid NOT NULL, channel text NOT NULL, provider text NOT NULL, is_active boolean DEFAULT false NOT NULL, display_name text, sender_address text, credentials jsonb DEFAULT '{}'::jsonb NOT NULL, connection_status text DEFAULT 'disconnected'::text, last_health_check timestamp with time zone, metadata jsonb DEFAULT '{}'::jsonb, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, deleted_at timestamp with time zone, CONSTRAINT notification_channels_channel_check CHECK ((channel = ANY (ARRAY['whatsapp'::text, 'email'::text, 'sms'::text]))), CONSTRAINT notification_channels_connection_status_check CHECK ((connection_status = ANY (ARRAY['connected'::text, 'disconnected'::text, 'connecting'::text, 'qr_pending'::text, 'error'::text]))), CONSTRAINT notification_channels_provider_check CHECK ((provider = ANY (ARRAY['evolution_api'::text, 'meta_official'::text, 'twilio'::text, 'zenvia'::text, 'sendgrid'::text, 'resend'::text, 'smtp'::text, 'zapi'::text]))) ); -- -- Name: notification_logs; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.notification_logs ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, owner_id uuid NOT NULL, queue_id uuid, agenda_evento_id uuid, patient_id uuid NOT NULL, channel text NOT NULL, template_key text NOT NULL, schedule_key text, recipient_address text NOT NULL, resolved_message text, resolved_vars jsonb, status text NOT NULL, provider text, provider_message_id text, provider_status text, provider_response jsonb, sent_at timestamp with time zone, delivered_at timestamp with time zone, read_at timestamp with time zone, failed_at timestamp with time zone, failure_reason text, estimated_cost_brl numeric(8,4) DEFAULT 0, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT notification_logs_status_check CHECK ((status = ANY (ARRAY['sent'::text, 'delivered'::text, 'read'::text, 'failed'::text, 'bounced'::text, 'opted_out'::text]))) ); -- -- Name: notification_preferences; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.notification_preferences ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, owner_id uuid NOT NULL, patient_id uuid NOT NULL, whatsapp_opt_in boolean DEFAULT true NOT NULL, email_opt_in boolean DEFAULT true NOT NULL, sms_opt_in boolean DEFAULT false NOT NULL, preferred_time_start time without time zone DEFAULT '08:00:00'::time without time zone, preferred_time_end time without time zone DEFAULT '20:00:00'::time without time zone, lgpd_consent_given boolean DEFAULT false NOT NULL, lgpd_consent_date timestamp with time zone, lgpd_consent_version text, lgpd_consent_ip inet, lgpd_opt_out_date timestamp with time zone, lgpd_opt_out_reason text, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, deleted_at timestamp with time zone ); -- -- Name: notification_queue; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.notification_queue ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, owner_id uuid NOT NULL, agenda_evento_id uuid, patient_id uuid NOT NULL, channel text NOT NULL, template_key text NOT NULL, schedule_key text NOT NULL, resolved_vars jsonb DEFAULT '{}'::jsonb NOT NULL, recipient_address text NOT NULL, status text DEFAULT 'pendente'::text NOT NULL, scheduled_at timestamp with time zone NOT NULL, sent_at timestamp with time zone, next_retry_at timestamp with time zone, attempts integer DEFAULT 0 NOT NULL, max_attempts integer DEFAULT 5 NOT NULL, last_error text, idempotency_key text NOT NULL, provider_message_id text, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT notification_queue_channel_check CHECK ((channel = ANY (ARRAY['whatsapp'::text, 'email'::text, 'sms'::text]))), CONSTRAINT notification_queue_status_check CHECK ((status = ANY (ARRAY['pendente'::text, 'processando'::text, 'enviado'::text, 'falhou'::text, 'cancelado'::text, 'ignorado'::text]))) ); -- -- Name: notification_schedules; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.notification_schedules ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, owner_id uuid NOT NULL, schedule_key text NOT NULL, event_type text NOT NULL, trigger_type text NOT NULL, offset_minutes integer DEFAULT 0, whatsapp_enabled boolean DEFAULT true NOT NULL, email_enabled boolean DEFAULT true NOT NULL, sms_enabled boolean DEFAULT false NOT NULL, allowed_time_start time without time zone DEFAULT '08:00:00'::time without time zone, allowed_time_end time without time zone DEFAULT '20:00:00'::time without time zone, skip_weekends boolean DEFAULT false, skip_holidays boolean DEFAULT false, is_active boolean DEFAULT true NOT NULL, sort_order integer DEFAULT 0, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, deleted_at timestamp with time zone, CONSTRAINT notification_schedules_event_type_check CHECK ((event_type = ANY (ARRAY['lembrete_sessao'::text, 'confirmacao_sessao'::text, 'cancelamento_sessao'::text, 'reagendamento'::text, 'cobranca_pendente'::text, 'boas_vindas_paciente'::text]))), CONSTRAINT notification_schedules_trigger_type_check CHECK ((trigger_type = ANY (ARRAY['before_event'::text, 'after_event'::text, 'immediate'::text]))) ); -- -- Name: notification_templates; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.notification_templates ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid, owner_id uuid, key text NOT NULL, domain text NOT NULL, channel text NOT NULL, event_type text NOT NULL, body_text text NOT NULL, meta_template_name text, meta_template_namespace text, meta_components jsonb, meta_status text DEFAULT 'draft'::text, variables jsonb DEFAULT '[]'::jsonb, version integer DEFAULT 1 NOT NULL, is_active boolean DEFAULT true NOT NULL, is_default boolean DEFAULT false NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, deleted_at timestamp with time zone, CONSTRAINT notification_templates_channel_check CHECK ((channel = ANY (ARRAY['whatsapp'::text, 'sms'::text]))), CONSTRAINT notification_templates_domain_check CHECK ((domain = ANY (ARRAY['session'::text, 'intake'::text, 'billing'::text, 'system'::text]))), CONSTRAINT notification_templates_event_type_check CHECK ((event_type = ANY (ARRAY['lembrete_sessao'::text, 'confirmacao_sessao'::text, 'cancelamento_sessao'::text, 'reagendamento'::text, 'cobranca_pendente'::text, 'boas_vindas_paciente'::text, 'intake_recebido'::text, 'intake_aprovado'::text, 'intake_rejeitado'::text]))), CONSTRAINT notification_templates_meta_status_check CHECK ((meta_status = ANY (ARRAY['draft'::text, 'pending_approval'::text, 'approved'::text, 'rejected'::text]))) ); -- -- Name: notifications; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.notifications ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, tenant_id uuid, type text NOT NULL, ref_id uuid, ref_table text, payload jsonb DEFAULT '{}'::jsonb NOT NULL, read_at timestamp with time zone, archived boolean DEFAULT false NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT notifications_type_check CHECK ((type = ANY (ARRAY['new_scheduling'::text, 'new_patient'::text, 'recurrence_alert'::text, 'session_status'::text]))) ); -- -- Name: plan_features; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.plan_features ( plan_id uuid NOT NULL, feature_id uuid NOT NULL, enabled boolean DEFAULT true NOT NULL, limits jsonb, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: tenant_modules; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.tenant_modules ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, module_id uuid NOT NULL, status text DEFAULT 'active'::text NOT NULL, settings jsonb, provider text DEFAULT 'manual'::text NOT NULL, provider_item_id text, installed_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: owner_feature_entitlements; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.owner_feature_entitlements AS WITH base AS ( SELECT s.user_id AS owner_id, f.key AS feature_key, pf.limits, 'plan'::text AS source FROM ((public.subscriptions s JOIN public.plan_features pf ON (((pf.plan_id = s.plan_id) AND (pf.enabled = true)))) JOIN public.features f ON ((f.id = pf.feature_id))) WHERE ((s.status = 'active'::text) AND (s.user_id IS NOT NULL)) UNION ALL SELECT tm.owner_id, f.key AS feature_key, mf.limits, 'module'::text AS source FROM (((public.tenant_modules tm JOIN public.modules m ON (((m.id = tm.module_id) AND (m.is_active = true)))) JOIN public.module_features mf ON (((mf.module_id = m.id) AND (mf.enabled = true)))) JOIN public.features f ON ((f.id = mf.feature_id))) WHERE ((tm.status = 'active'::text) AND (tm.owner_id IS NOT NULL)) ) SELECT owner_id, feature_key, array_agg(DISTINCT source) AS sources, jsonb_agg(limits) FILTER (WHERE (limits IS NOT NULL)) AS limits_list FROM base GROUP BY owner_id, feature_key; -- -- Name: owner_users; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.owner_users ( owner_id uuid NOT NULL, user_id uuid NOT NULL, role text DEFAULT 'admin'::text NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: patient_discounts; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.patient_discounts ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, tenant_id uuid NOT NULL, patient_id uuid NOT NULL, discount_pct numeric(5,2) DEFAULT 0, discount_flat numeric(10,2) DEFAULT 0, reason text, active boolean DEFAULT true NOT NULL, active_from timestamp with time zone DEFAULT now(), active_to timestamp with time zone, created_at timestamp with time zone DEFAULT now() ); -- -- Name: patient_group_patient; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.patient_group_patient ( patient_group_id uuid NOT NULL, patient_id uuid NOT NULL, created_at timestamp with time zone DEFAULT now(), tenant_id uuid NOT NULL ); -- -- Name: patient_groups; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.patient_groups ( id uuid DEFAULT gen_random_uuid() NOT NULL, nome text NOT NULL, descricao text, cor text, is_active boolean DEFAULT true NOT NULL, is_system boolean DEFAULT false NOT NULL, owner_id uuid DEFAULT auth.uid() NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, therapist_id uuid, tenant_id uuid NOT NULL ); -- -- Name: patient_intake_requests; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.patient_intake_requests ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, token text NOT NULL, consent boolean DEFAULT false NOT NULL, status text DEFAULT 'new'::text NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, converted_patient_id uuid, rejected_reason text, updated_at timestamp with time zone DEFAULT now() NOT NULL, cpf text, rg text, cep text, nome_completo text, email_principal text, telefone text, pais text, cidade text, estado text, endereco text, numero text, bairro text, complemento text, data_nascimento date, naturalidade text, genero text, estado_civil text, onde_nos_conheceu text, encaminhado_por text, observacoes text, notas_internas text, email_alternativo text, telefone_alternativo text, profissao text, escolaridade text, nacionalidade text, avatar_url text, tenant_id uuid, CONSTRAINT chk_intakes_status CHECK ((status = ANY (ARRAY['new'::text, 'converted'::text, 'rejected'::text]))) ); -- -- Name: patient_invites; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.patient_invites ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, token text NOT NULL, active boolean DEFAULT true NOT NULL, expires_at timestamp with time zone, max_uses integer, uses integer DEFAULT 0 NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, tenant_id uuid ); -- -- Name: patient_patient_tag; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.patient_patient_tag ( owner_id uuid NOT NULL, patient_id uuid NOT NULL, tag_id uuid NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, tenant_id uuid NOT NULL ); -- -- Name: patient_tags; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.patient_tags ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, nome text NOT NULL, cor text, is_padrao boolean DEFAULT false NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone, tenant_id uuid NOT NULL ); -- -- Name: patients; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.patients ( id uuid DEFAULT gen_random_uuid() NOT NULL, nome_completo text NOT NULL, email_principal text, telefone text, created_at timestamp with time zone DEFAULT now(), owner_id uuid, avatar_url text, status text DEFAULT 'Ativo'::text, last_attended_at timestamp with time zone, is_native boolean DEFAULT false, naturalidade text, data_nascimento date, rg text, cpf text, identification_color text, genero text, estado_civil text, email_alternativo text, pais text DEFAULT 'Brasil'::text, cep text, cidade text, estado text, endereco text, numero text, bairro text, complemento text, escolaridade text, profissao text, nome_parente text, grau_parentesco text, telefone_alternativo text, onde_nos_conheceu text, encaminhado_por text, nome_responsavel text, telefone_responsavel text, cpf_responsavel text, observacao_responsavel text, cobranca_no_responsavel boolean DEFAULT false, observacoes text, notas_internas text, updated_at timestamp with time zone DEFAULT now(), telefone_parente text, tenant_id uuid NOT NULL, responsible_member_id uuid NOT NULL, user_id uuid, patient_scope text DEFAULT 'clinic'::text NOT NULL, therapist_member_id uuid, CONSTRAINT cpf_responsavel_format_check CHECK (((cpf_responsavel IS NULL) OR (cpf_responsavel ~ '^\d{11}$'::text))), CONSTRAINT patients_cpf_format_check CHECK (((cpf IS NULL) OR (cpf ~ '^\d{11}$'::text))), CONSTRAINT patients_patient_scope_check CHECK ((patient_scope = ANY (ARRAY['clinic'::text, 'therapist'::text]))), CONSTRAINT patients_status_check CHECK ((status = ANY (ARRAY['Ativo'::text, 'Inativo'::text, 'Alta'::text, 'Encaminhado'::text, 'Arquivado'::text]))), CONSTRAINT patients_therapist_scope_consistency CHECK ((((patient_scope = 'clinic'::text) AND (therapist_member_id IS NULL)) OR ((patient_scope = 'therapist'::text) AND (therapist_member_id IS NOT NULL)))) ); -- -- Name: COLUMN patients.avatar_url; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.patients.avatar_url IS 'URL p??blica da imagem de avatar armazenada no Supabase Storage'; -- -- Name: payment_settings; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.payment_settings ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, tenant_id uuid, pix_ativo boolean DEFAULT false NOT NULL, pix_tipo text DEFAULT 'cpf'::text NOT NULL, pix_chave text DEFAULT ''::text NOT NULL, pix_nome_titular text DEFAULT ''::text NOT NULL, deposito_ativo boolean DEFAULT false NOT NULL, deposito_banco text DEFAULT ''::text NOT NULL, deposito_agencia text DEFAULT ''::text NOT NULL, deposito_conta text DEFAULT ''::text NOT NULL, deposito_tipo_conta text DEFAULT 'corrente'::text NOT NULL, deposito_titular text DEFAULT ''::text NOT NULL, deposito_cpf_cnpj text DEFAULT ''::text NOT NULL, dinheiro_ativo boolean DEFAULT false NOT NULL, cartao_ativo boolean DEFAULT false NOT NULL, cartao_instrucao text DEFAULT ''::text NOT NULL, convenio_ativo boolean DEFAULT false NOT NULL, convenio_lista text DEFAULT ''::text NOT NULL, observacoes_pagamento text DEFAULT ''::text NOT NULL, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now() ); -- -- Name: plan_prices; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.plan_prices ( id uuid DEFAULT gen_random_uuid() NOT NULL, plan_id uuid NOT NULL, currency text DEFAULT 'BRL'::text NOT NULL, "interval" text NOT NULL, amount_cents integer NOT NULL, is_active boolean DEFAULT true NOT NULL, active_from timestamp with time zone DEFAULT now() NOT NULL, active_to timestamp with time zone, source text DEFAULT 'manual'::text NOT NULL, provider text, provider_price_id text, created_at timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT plan_prices_amount_cents_check CHECK ((amount_cents >= 0)), CONSTRAINT plan_prices_interval_check CHECK (("interval" = ANY (ARRAY['month'::text, 'year'::text]))) ); -- -- Name: TABLE plan_prices; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON TABLE public.plan_prices IS 'Hist??rico de pre??os por plano (fonte: manual/gateway).'; -- -- Name: plan_public; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.plan_public ( plan_id uuid NOT NULL, public_name text DEFAULT ''::text NOT NULL, public_description text DEFAULT ''::text NOT NULL, badge text, is_featured boolean DEFAULT false NOT NULL, is_visible boolean DEFAULT true NOT NULL, sort_order integer DEFAULT 0 NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: TABLE plan_public; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON TABLE public.plan_public IS 'Configura????o de vitrine (p??gina p??blica) dos planos.'; -- -- Name: plan_public_bullets; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.plan_public_bullets ( id uuid DEFAULT gen_random_uuid() NOT NULL, plan_id uuid NOT NULL, text text NOT NULL, sort_order integer DEFAULT 0 NOT NULL, highlight boolean DEFAULT false NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: plans; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.plans ( id uuid DEFAULT gen_random_uuid() NOT NULL, key text NOT NULL, name text NOT NULL, description text, is_active boolean DEFAULT true NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, price_cents integer DEFAULT 0 NOT NULL, currency text DEFAULT 'BRL'::text NOT NULL, billing_interval text DEFAULT 'month'::text NOT NULL, target text, max_supervisees integer, CONSTRAINT plans_target_check CHECK ((target = ANY (ARRAY['patient'::text, 'therapist'::text, 'clinic'::text, 'supervisor'::text]))) ); -- -- Name: COLUMN plans.name; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.plans.name IS 'Nome interno do plano (admin). A key ?? t??cnica/imut??vel.'; -- -- Name: COLUMN plans.target; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.plans.target IS 'P??blico-alvo do plano: patient, therapist ou clinic.'; -- -- Name: COLUMN plans.max_supervisees; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.plans.max_supervisees IS 'Limite de terapeutas que podem ser supervisionados. Apenas para planos target=supervisor. NULL = sem limite.'; -- -- Name: professional_pricing; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.professional_pricing ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, tenant_id uuid NOT NULL, determined_commitment_id uuid, price numeric(10,2) NOT NULL, notes text, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now() ); -- -- Name: TABLE professional_pricing; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON TABLE public.professional_pricing IS 'DEPRECATED: substitu??da por public.services. Manter at?? pr??xima release de limpeza.'; -- -- Name: profiles; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.profiles ( id uuid NOT NULL, role text DEFAULT 'tenant_member'::text NOT NULL, full_name text, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, avatar_url text, phone text, bio text, language text DEFAULT 'pt-BR'::text NOT NULL, timezone text DEFAULT 'America/Sao_Paulo'::text NOT NULL, notify_system_email boolean DEFAULT true NOT NULL, notify_reminders boolean DEFAULT true NOT NULL, notify_news boolean DEFAULT false NOT NULL, account_type text DEFAULT 'free'::text NOT NULL, platform_roles text[] DEFAULT '{}'::text[] NOT NULL, nickname text, work_description text, work_description_other text, site_url text, social_instagram text, social_youtube text, social_facebook text, social_x text, social_custom jsonb DEFAULT '[]'::jsonb NOT NULL, CONSTRAINT profiles_account_type_check CHECK ((account_type = ANY (ARRAY['free'::text, 'patient'::text, 'therapist'::text, 'clinic'::text]))), CONSTRAINT profiles_role_check CHECK ((role = ANY (ARRAY['saas_admin'::text, 'tenant_member'::text, 'portal_user'::text, 'patient'::text]))) ); -- -- Name: COLUMN profiles.phone; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.profiles.phone IS 'WhatsApp / telefone no formato (99) 99999-9999'; -- -- Name: COLUMN profiles.bio; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.profiles.bio IS 'Breve apresenta????o p??blica (m??x 300 chars no front)'; -- -- Name: COLUMN profiles.account_type; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.profiles.account_type IS 'Tipo de conta: free=sem perfil ainda, patient=paciente (imut??vel), therapist=terapeuta (imut??vel), clinic=cl??nica (imut??vel).'; -- -- Name: COLUMN profiles.platform_roles; Type: COMMENT; Schema: public; Owner: - -- 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.'; -- -- Name: COLUMN profiles.nickname; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.profiles.nickname IS 'Apelido preferido para comunica????o interna (Ag??ncia PSI)'; -- -- Name: COLUMN profiles.work_description; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.profiles.work_description IS 'Categoria de trabalho selecionada no perfil p??blico'; -- -- Name: COLUMN profiles.work_description_other; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.profiles.work_description_other IS 'Descri????o livre quando work_description = ''outro'''; -- -- Name: COLUMN profiles.site_url; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.profiles.site_url IS 'Endere??o do site pessoal ou profissional'; -- -- Name: COLUMN profiles.social_instagram; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.profiles.social_instagram IS 'Handle ou URL do Instagram'; -- -- Name: COLUMN profiles.social_youtube; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.profiles.social_youtube IS 'Handle ou URL do canal no YouTube'; -- -- Name: COLUMN profiles.social_facebook; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.profiles.social_facebook IS 'Handle ou URL da p??gina no Facebook'; -- -- Name: COLUMN profiles.social_x; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.profiles.social_x IS 'Handle ou URL do perfil no X (Twitter)'; -- -- Name: COLUMN profiles.social_custom; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.profiles.social_custom IS 'Array JSON com redes adicionais livres: [{name, url}]'; -- -- Name: recurrence_exceptions; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.recurrence_exceptions ( id uuid DEFAULT gen_random_uuid() NOT NULL, recurrence_id uuid NOT NULL, tenant_id uuid NOT NULL, original_date date NOT NULL, type public.recurrence_exception_type NOT NULL, new_date date, new_start_time time without time zone, new_end_time time without time zone, modalidade text, observacoes text, titulo_custom text, extra_fields jsonb, reason text, agenda_evento_id uuid, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: recurrence_rule_services; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.recurrence_rule_services ( id uuid DEFAULT gen_random_uuid() NOT NULL, rule_id uuid NOT NULL, service_id uuid NOT NULL, quantity integer DEFAULT 1 NOT NULL, unit_price numeric(10,2) NOT NULL, discount_pct numeric(5,2) DEFAULT 0, discount_flat numeric(10,2) DEFAULT 0, final_price numeric(10,2) NOT NULL, created_at timestamp with time zone DEFAULT now(), CONSTRAINT recurrence_rule_services_disc_flat_chk CHECK ((discount_flat >= (0)::numeric)), CONSTRAINT recurrence_rule_services_disc_pct_chk CHECK (((discount_pct >= (0)::numeric) AND (discount_pct <= (100)::numeric))), CONSTRAINT recurrence_rule_services_final_price_chk CHECK ((final_price >= (0)::numeric)), CONSTRAINT recurrence_rule_services_quantity_chk CHECK ((quantity > 0)) ); -- -- Name: recurrence_rules; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.recurrence_rules ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, owner_id uuid NOT NULL, therapist_id uuid, patient_id uuid, determined_commitment_id uuid, type public.recurrence_type DEFAULT 'weekly'::public.recurrence_type NOT NULL, "interval" smallint DEFAULT 1 NOT NULL, weekdays smallint[] DEFAULT '{}'::smallint[] NOT NULL, start_time time without time zone NOT NULL, end_time time without time zone NOT NULL, timezone text DEFAULT 'America/Sao_Paulo'::text NOT NULL, duration_min smallint DEFAULT 50 NOT NULL, start_date date NOT NULL, end_date date, max_occurrences integer, open_ended boolean DEFAULT true NOT NULL, modalidade text DEFAULT 'presencial'::text, titulo_custom text, observacoes text, extra_fields jsonb, status text DEFAULT 'ativo'::text NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, price numeric(10,2), insurance_plan_id uuid, insurance_guide_number text, insurance_value numeric(10,2), insurance_plan_service_id uuid, CONSTRAINT recurrence_rules_dates_chk CHECK (((end_date IS NULL) OR (end_date >= start_date))), CONSTRAINT recurrence_rules_interval_chk CHECK (("interval" >= 1)), CONSTRAINT recurrence_rules_status_check CHECK ((status = ANY (ARRAY['ativo'::text, 'pausado'::text, 'cancelado'::text]))), CONSTRAINT recurrence_rules_times_chk CHECK ((end_time > start_time)) ); -- -- Name: saas_admins; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.saas_admins ( user_id uuid NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: saas_doc_votos; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.saas_doc_votos ( id uuid DEFAULT gen_random_uuid() NOT NULL, doc_id uuid NOT NULL, user_id uuid NOT NULL, util boolean NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: saas_docs; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.saas_docs ( id uuid DEFAULT gen_random_uuid() NOT NULL, titulo text NOT NULL, conteudo text DEFAULT ''::text NOT NULL, medias jsonb DEFAULT '[]'::jsonb NOT NULL, tipo_acesso text DEFAULT 'usuario'::text NOT NULL, pagina_path text NOT NULL, docs_relacionados uuid[] DEFAULT '{}'::uuid[] NOT NULL, ativo boolean DEFAULT true NOT NULL, ordem integer DEFAULT 0 NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, categoria text, exibir_no_faq boolean DEFAULT false NOT NULL, votos_util integer DEFAULT 0 NOT NULL, votos_nao_util integer DEFAULT 0 NOT NULL, CONSTRAINT saas_docs_tipo_acesso_check CHECK ((tipo_acesso = ANY (ARRAY['admin'::text, 'usuario'::text]))) ); -- -- Name: COLUMN saas_docs.categoria; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.saas_docs.categoria IS 'Agrupa docs no portal FAQ (ex: Conta, Agenda, Pagamentos)'; -- -- Name: COLUMN saas_docs.exibir_no_faq; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.saas_docs.exibir_no_faq IS 'Se true, a doc e seus itens FAQ aparecem no portal de FAQ'; -- -- Name: saas_faq; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.saas_faq ( id uuid DEFAULT gen_random_uuid() NOT NULL, pergunta text NOT NULL, categoria text, publico boolean DEFAULT false NOT NULL, votos integer DEFAULT 0 NOT NULL, titulo text, conteudo text, tipo_acesso text DEFAULT 'usuario'::text NOT NULL, pagina_path text NOT NULL, pagina_label text, medias jsonb DEFAULT '[]'::jsonb NOT NULL, faqs_relacionados uuid[] DEFAULT '{}'::uuid[] NOT NULL, ativo boolean DEFAULT true NOT NULL, ordem integer DEFAULT 0 NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: saas_faq_itens; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.saas_faq_itens ( id uuid DEFAULT gen_random_uuid() NOT NULL, doc_id uuid NOT NULL, pergunta text NOT NULL, resposta text, ordem integer DEFAULT 0 NOT NULL, ativo boolean DEFAULT true NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: TABLE saas_faq_itens; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON TABLE public.saas_faq_itens IS 'Pares pergunta/resposta vinculados a um documento de ajuda'; -- -- Name: services; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.services ( id uuid DEFAULT gen_random_uuid() NOT NULL, owner_id uuid NOT NULL, tenant_id uuid NOT NULL, name text NOT NULL, description text, price numeric(10,2) NOT NULL, duration_min integer, active boolean DEFAULT true NOT NULL, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now() ); -- -- Name: subscription_events; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.subscription_events ( id uuid DEFAULT gen_random_uuid() NOT NULL, subscription_id uuid NOT NULL, owner_id uuid NOT NULL, event_type text NOT NULL, old_plan_id uuid, new_plan_id uuid, created_at timestamp with time zone DEFAULT now() NOT NULL, created_by uuid, source text DEFAULT 'admin_ui'::text, reason text, metadata jsonb, owner_type text NOT NULL, owner_ref uuid NOT NULL, CONSTRAINT subscription_events_owner_ref_consistency_chk CHECK ((owner_id = owner_ref)), CONSTRAINT subscription_events_owner_type_chk CHECK (((owner_type IS NULL) OR (owner_type = ANY (ARRAY['clinic'::text, 'therapist'::text])))) ); -- -- Name: subscription_intents_personal; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.subscription_intents_personal ( id uuid DEFAULT gen_random_uuid() NOT NULL, user_id uuid NOT NULL, created_by_user_id uuid, email text NOT NULL, plan_id uuid NOT NULL, plan_key text, "interval" text, amount_cents integer, currency text, status text DEFAULT 'new'::text NOT NULL, source text DEFAULT 'manual'::text NOT NULL, notes text, created_at timestamp with time zone DEFAULT now() NOT NULL, paid_at timestamp with time zone, subscription_id uuid, CONSTRAINT sint_personal_interval_check CHECK ((("interval" IS NULL) OR ("interval" = ANY (ARRAY['month'::text, 'year'::text])))), CONSTRAINT sint_personal_status_check CHECK ((status = ANY (ARRAY['new'::text, 'waiting_payment'::text, 'paid'::text, 'canceled'::text]))) ); -- -- Name: subscription_intents_tenant; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.subscription_intents_tenant ( id uuid DEFAULT gen_random_uuid() NOT NULL, user_id uuid NOT NULL, created_by_user_id uuid, email text NOT NULL, plan_id uuid NOT NULL, plan_key text, "interval" text, amount_cents integer, currency text, status text DEFAULT 'new'::text NOT NULL, source text DEFAULT 'manual'::text NOT NULL, notes text, created_at timestamp with time zone DEFAULT now() NOT NULL, paid_at timestamp with time zone, tenant_id uuid NOT NULL, subscription_id uuid, CONSTRAINT sint_tenant_interval_check CHECK ((("interval" IS NULL) OR ("interval" = ANY (ARRAY['month'::text, 'year'::text])))), CONSTRAINT sint_tenant_status_check CHECK ((status = ANY (ARRAY['new'::text, 'waiting_payment'::text, 'paid'::text, 'canceled'::text]))) ); -- -- Name: subscription_intents; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.subscription_intents AS SELECT t.id, t.user_id, t.created_by_user_id, t.email, t.plan_id, t.plan_key, t."interval", t.amount_cents, t.currency, t.status, t.source, t.notes, t.created_at, t.paid_at, t.tenant_id, t.subscription_id, 'clinic'::text AS plan_target FROM public.subscription_intents_tenant t UNION ALL SELECT p.id, p.user_id, p.created_by_user_id, p.email, p.plan_id, p.plan_key, p."interval", p.amount_cents, p.currency, p.status, p.source, p.notes, p.created_at, p.paid_at, NULL::uuid AS tenant_id, p.subscription_id, 'therapist'::text AS plan_target FROM public.subscription_intents_personal p; -- -- Name: subscription_intents_legacy; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.subscription_intents_legacy ( id uuid DEFAULT gen_random_uuid() NOT NULL, user_id uuid, email text, plan_key text NOT NULL, "interval" text NOT NULL, amount_cents integer NOT NULL, currency text DEFAULT 'BRL'::text NOT NULL, status text DEFAULT 'new'::text NOT NULL, source text DEFAULT 'landing'::text NOT NULL, notes text, created_at timestamp with time zone DEFAULT now() NOT NULL, paid_at timestamp with time zone, tenant_id uuid NOT NULL, created_by_user_id uuid, CONSTRAINT subscription_intents_interval_check CHECK (("interval" = ANY (ARRAY['month'::text, 'year'::text]))), CONSTRAINT subscription_intents_status_check CHECK ((status = ANY (ARRAY['new'::text, 'waiting_payment'::text, 'paid'::text, 'canceled'::text]))) ); -- -- Name: support_sessions; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.support_sessions ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, admin_id uuid NOT NULL, token text DEFAULT encode(extensions.gen_random_bytes(32), 'hex'::text) NOT NULL, expires_at timestamp with time zone DEFAULT (now() + '01:00:00'::interval) NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: tenant_feature_exceptions_log; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.tenant_feature_exceptions_log ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, feature_key text NOT NULL, enabled boolean NOT NULL, reason text, created_by uuid, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: tenant_features; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.tenant_features ( tenant_id uuid NOT NULL, feature_key text NOT NULL, enabled boolean DEFAULT false NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: tenant_invites; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.tenant_invites ( id uuid DEFAULT gen_random_uuid() NOT NULL, tenant_id uuid NOT NULL, email text NOT NULL, role text NOT NULL, token uuid DEFAULT gen_random_uuid() NOT NULL, invited_by uuid, created_at timestamp with time zone DEFAULT now() NOT NULL, expires_at timestamp with time zone DEFAULT (now() + '7 days'::interval) NOT NULL, accepted_at timestamp with time zone, accepted_by uuid, revoked_at timestamp with time zone, revoked_by uuid, CONSTRAINT tenant_invites_role_check CHECK ((role = ANY (ARRAY['therapist'::text, 'secretary'::text]))) ); -- -- Name: tenants; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.tenants ( id uuid DEFAULT gen_random_uuid() NOT NULL, name text, created_at timestamp with time zone DEFAULT now() NOT NULL, kind text DEFAULT 'saas'::text NOT NULL, CONSTRAINT tenants_kind_check CHECK ((kind = ANY (ARRAY['therapist'::text, 'clinic_coworking'::text, 'clinic_reception'::text, 'clinic_full'::text, 'clinic'::text, 'saas'::text, 'supervisor'::text]))) ); -- -- Name: COLUMN tenants.kind; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.tenants.kind IS 'Tipo do tenant. Imut??vel ap??s cria????o. therapist=terapeuta solo. clinic_coworking/clinic_reception/clinic_full=cl??nicas. clinic e saas s??o legados.'; -- -- Name: therapist_payout_records; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.therapist_payout_records ( payout_id uuid NOT NULL, financial_record_id uuid NOT NULL ); -- -- Name: user_settings; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.user_settings ( user_id uuid NOT NULL, theme_mode text DEFAULT 'dark'::text NOT NULL, preset text DEFAULT 'Aura'::text NOT NULL, primary_color text DEFAULT 'noir'::text NOT NULL, surface_color text DEFAULT 'slate'::text NOT NULL, menu_mode text DEFAULT 'static'::text NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, layout_variant text DEFAULT 'classic'::text NOT NULL, CONSTRAINT user_settings_layout_variant_check CHECK ((layout_variant = ANY (ARRAY['classic'::text, 'rail'::text]))), CONSTRAINT user_settings_menu_mode_check CHECK ((menu_mode = ANY (ARRAY['static'::text, 'overlay'::text]))), CONSTRAINT user_settings_theme_mode_check CHECK ((theme_mode = ANY (ARRAY['light'::text, 'dark'::text]))) ); -- -- Name: TABLE user_settings; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON TABLE public.user_settings IS 'Prefer??ncias de apar??ncia e layout por usu??rio'; -- -- Name: COLUMN user_settings.user_id; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.user_settings.user_id IS 'FK = auth.users.id ??? um registro por usu??rio'; -- -- Name: COLUMN user_settings.theme_mode; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.user_settings.theme_mode IS 'light | dark'; -- -- Name: COLUMN user_settings.preset; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.user_settings.preset IS 'Preset PrimeVue: Aura | Lara | Nora'; -- -- Name: COLUMN user_settings.primary_color; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.user_settings.primary_color IS 'Nome da cor prim??ria (ex: blue, emerald, noir)'; -- -- Name: COLUMN user_settings.surface_color; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.user_settings.surface_color IS 'Nome da surface (ex: slate, zinc, neutral)'; -- -- Name: COLUMN user_settings.menu_mode; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.user_settings.menu_mode IS 'static | overlay'; -- -- Name: COLUMN user_settings.layout_variant; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON COLUMN public.user_settings.layout_variant IS 'classic (sidebar) | rail (mini rail + painel)'; -- -- Name: v_auth_users_public; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_auth_users_public AS SELECT id AS user_id, email, created_at, last_sign_in_at FROM auth.users u; -- -- Name: v_cashflow_projection; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_cashflow_projection WITH (security_invoker='on') AS SELECT gs.mes, to_char(gs.mes, 'YYYY-MM'::text) AS mes_label, COALESCE(sum(fr.final_amount) FILTER (WHERE ((fr.type = 'receita'::public.financial_record_type) AND (fr.status = ANY (ARRAY['pending'::text, 'overdue'::text])))), (0)::numeric) AS receitas_projetadas, COALESCE(sum(fr.final_amount) FILTER (WHERE ((fr.type = 'despesa'::public.financial_record_type) AND (fr.status = ANY (ARRAY['pending'::text, 'overdue'::text])))), (0)::numeric) AS despesas_projetadas, COALESCE(sum(fr.final_amount) FILTER (WHERE ((fr.type = 'receita'::public.financial_record_type) AND (fr.status = 'pending'::text))), (0)::numeric) AS receitas_pendentes, COALESCE(sum(fr.final_amount) FILTER (WHERE ((fr.type = 'receita'::public.financial_record_type) AND (fr.status = 'overdue'::text))), (0)::numeric) AS receitas_vencidas, COALESCE(sum(fr.final_amount) FILTER (WHERE ((fr.type = 'despesa'::public.financial_record_type) AND (fr.status = 'pending'::text))), (0)::numeric) AS despesas_pendentes, COALESCE(sum(fr.final_amount) FILTER (WHERE ((fr.type = 'despesa'::public.financial_record_type) AND (fr.status = 'overdue'::text))), (0)::numeric) AS despesas_vencidas, (COALESCE(sum(fr.final_amount) FILTER (WHERE ((fr.type = 'receita'::public.financial_record_type) AND (fr.status = ANY (ARRAY['pending'::text, 'overdue'::text])))), (0)::numeric) - COALESCE(sum(fr.final_amount) FILTER (WHERE ((fr.type = 'despesa'::public.financial_record_type) AND (fr.status = ANY (ARRAY['pending'::text, 'overdue'::text])))), (0)::numeric)) AS saldo_projetado, count(fr.id) FILTER (WHERE (fr.status = ANY (ARRAY['pending'::text, 'overdue'::text]))) AS count_registros FROM (generate_series(((date_trunc('month'::text, (CURRENT_DATE)::timestamp with time zone))::date)::timestamp with time zone, (((date_trunc('month'::text, (CURRENT_DATE)::timestamp with time zone) + '5 mons'::interval))::date)::timestamp with time zone, '1 mon'::interval) gs(mes) LEFT JOIN public.financial_records fr ON (((fr.deleted_at IS NULL) AND (fr.status = ANY (ARRAY['pending'::text, 'overdue'::text])) AND ((date_trunc('month'::text, (fr.due_date)::timestamp with time zone))::date = gs.mes)))) GROUP BY gs.mes ORDER BY gs.mes; -- -- Name: VIEW v_cashflow_projection; Type: COMMENT; Schema: public; Owner: - -- COMMENT ON VIEW public.v_cashflow_projection IS 'Fluxo de caixa projetado: pr??ximos 6 meses com totais de pending+overdue por due_date. Usa security_invoker=on ??? filtra automaticamente pelo auth.uid() via RLS de financial_records.'; -- -- Name: v_commitment_totals; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_commitment_totals AS SELECT c.tenant_id, c.id AS commitment_id, (COALESCE(sum(l.minutes), (0)::bigint))::integer AS total_minutes FROM (public.determined_commitments c LEFT JOIN public.commitment_time_logs l ON ((l.commitment_id = c.id))) GROUP BY c.tenant_id, c.id; -- -- Name: v_patient_groups_with_counts; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_patient_groups_with_counts AS SELECT pg.id, pg.nome, pg.cor, pg.owner_id, pg.is_system, pg.is_active, pg.created_at, pg.updated_at, (COALESCE(count(pgp.patient_id), (0)::bigint))::integer AS patients_count FROM (public.patient_groups pg LEFT JOIN public.patient_group_patient pgp ON ((pgp.patient_group_id = pg.id))) GROUP BY pg.id, pg.nome, pg.cor, pg.owner_id, pg.is_system, pg.is_active, pg.created_at, pg.updated_at; -- -- Name: v_plan_active_prices; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_plan_active_prices AS SELECT plan_id, max( CASE WHEN (("interval" = 'month'::text) AND is_active) THEN amount_cents ELSE NULL::integer END) AS monthly_cents, max( CASE WHEN (("interval" = 'year'::text) AND is_active) THEN amount_cents ELSE NULL::integer END) AS yearly_cents, max( CASE WHEN (("interval" = 'month'::text) AND is_active) THEN currency ELSE NULL::text END) AS monthly_currency, max( CASE WHEN (("interval" = 'year'::text) AND is_active) THEN currency ELSE NULL::text END) AS yearly_currency FROM public.plan_prices GROUP BY plan_id; -- -- Name: v_public_pricing; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_public_pricing AS SELECT p.id AS plan_id, p.key AS plan_key, p.name AS plan_name, COALESCE(pp.public_name, ''::text) AS public_name, COALESCE(pp.public_description, ''::text) AS public_description, pp.badge, COALESCE(pp.is_featured, false) AS is_featured, COALESCE(pp.is_visible, true) AS is_visible, COALESCE(pp.sort_order, 0) AS sort_order, ap.monthly_cents, ap.yearly_cents, ap.monthly_currency, ap.yearly_currency, COALESCE(( SELECT jsonb_agg(jsonb_build_object('id', b.id, 'text', b.text, 'highlight', b.highlight, 'sort_order', b.sort_order) ORDER BY b.sort_order, b.created_at) AS jsonb_agg FROM public.plan_public_bullets b WHERE (b.plan_id = p.id)), '[]'::jsonb) AS bullets, p.target AS plan_target FROM ((public.plans p LEFT JOIN public.plan_public pp ON ((pp.plan_id = p.id))) LEFT JOIN public.v_plan_active_prices ap ON ((ap.plan_id = p.id))) ORDER BY COALESCE(pp.sort_order, 0), p.key; -- -- Name: v_subscription_feature_mismatch; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_subscription_feature_mismatch AS WITH expected AS ( SELECT s.user_id AS owner_id, f.key AS feature_key FROM ((public.subscriptions s JOIN public.plan_features pf ON (((pf.plan_id = s.plan_id) AND (pf.enabled = true)))) JOIN public.features f ON ((f.id = pf.feature_id))) WHERE ((s.status = 'active'::text) AND (s.tenant_id IS NULL) AND (s.user_id IS NOT NULL)) ), actual AS ( SELECT e.owner_id, e.feature_key FROM public.owner_feature_entitlements e ) SELECT COALESCE(expected.owner_id, actual.owner_id) AS owner_id, COALESCE(expected.feature_key, actual.feature_key) AS feature_key, CASE WHEN ((expected.feature_key IS NOT NULL) AND (actual.feature_key IS NULL)) THEN 'missing_entitlement'::text WHEN ((expected.feature_key IS NULL) AND (actual.feature_key IS NOT NULL)) THEN 'unexpected_entitlement'::text ELSE NULL::text END AS mismatch_type FROM (expected FULL JOIN actual ON (((expected.owner_id = actual.owner_id) AND (expected.feature_key = actual.feature_key)))) WHERE ((expected.feature_key IS NULL) OR (actual.feature_key IS NULL)); -- -- Name: v_subscription_health; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_subscription_health AS SELECT s.id AS subscription_id, s.user_id AS owner_id, s.status, s.plan_id, p.key AS plan_key, s.current_period_start, s.current_period_end, s.updated_at, CASE WHEN (s.plan_id IS NULL) THEN 'missing_plan'::text WHEN (p.id IS NULL) THEN 'invalid_plan'::text WHEN ((s.status = 'active'::text) AND (s.current_period_end IS NOT NULL) AND (s.current_period_end < now())) THEN 'expired_but_active'::text WHEN ((s.status = 'canceled'::text) AND (s.current_period_end > now())) THEN 'canceled_but_still_in_period'::text ELSE 'ok'::text END AS health_status, CASE WHEN (s.tenant_id IS NOT NULL) THEN 'clinic'::text ELSE 'therapist'::text END AS owner_type, COALESCE(s.tenant_id, s.user_id) AS owner_ref FROM (public.subscriptions s LEFT JOIN public.plans p ON ((p.id = s.plan_id))); -- -- Name: v_subscription_health_v2; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_subscription_health_v2 AS SELECT s.id AS subscription_id, s.user_id AS owner_id, CASE WHEN (s.tenant_id IS NOT NULL) THEN 'clinic'::text ELSE 'therapist'::text END AS owner_type, COALESCE(s.tenant_id, s.user_id) AS owner_ref, s.status, s.plan_id, p.key AS plan_key, s.current_period_start, s.current_period_end, s.updated_at, CASE WHEN (s.plan_id IS NULL) THEN 'missing_plan'::text WHEN (p.id IS NULL) THEN 'invalid_plan'::text WHEN ((s.status = 'active'::text) AND (s.current_period_end IS NOT NULL) AND (s.current_period_end < now())) THEN 'expired_but_active'::text WHEN ((s.status = 'canceled'::text) AND (s.current_period_end > now())) THEN 'canceled_but_still_in_period'::text ELSE 'ok'::text END AS health_status FROM (public.subscriptions s LEFT JOIN public.plans p ON ((p.id = s.plan_id))); -- -- Name: v_tag_patient_counts; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_tag_patient_counts AS SELECT t.id, t.owner_id, t.nome, t.cor, t.is_padrao, t.created_at, t.updated_at, (COALESCE(count(ppt.patient_id), (0)::bigint))::integer AS pacientes_count, (COALESCE(count(ppt.patient_id), (0)::bigint))::integer AS patient_count FROM (public.patient_tags t LEFT JOIN public.patient_patient_tag ppt ON (((ppt.tag_id = t.id) AND (ppt.owner_id = t.owner_id)))) GROUP BY t.id, t.owner_id, t.nome, t.cor, t.is_padrao, t.created_at, t.updated_at; -- -- Name: v_tenant_active_subscription; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_tenant_active_subscription AS SELECT DISTINCT ON (tenant_id) tenant_id, plan_id, plan_key, "interval", status, current_period_start, current_period_end, created_at FROM public.subscriptions s WHERE ((tenant_id IS NOT NULL) AND (status = 'active'::text) AND ((current_period_end IS NULL) OR (current_period_end > now()))) ORDER BY tenant_id, created_at DESC; -- -- Name: v_tenant_entitlements; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_tenant_entitlements AS SELECT a.tenant_id, f.key AS feature_key, true AS allowed FROM ((public.v_tenant_active_subscription a JOIN public.plan_features pf ON (((pf.plan_id = a.plan_id) AND (pf.enabled = true)))) JOIN public.features f ON ((f.id = pf.feature_id))); -- -- Name: v_tenant_entitlements_full; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_tenant_entitlements_full AS SELECT a.tenant_id, f.key AS feature_key, (pf.enabled = true) AS allowed, pf.limits, a.plan_id, p.key AS plan_key FROM (((public.v_tenant_active_subscription a JOIN public.plan_features pf ON ((pf.plan_id = a.plan_id))) JOIN public.features f ON ((f.id = pf.feature_id))) JOIN public.plans p ON ((p.id = a.plan_id))); -- -- Name: v_tenant_entitlements_json; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_tenant_entitlements_json AS SELECT tenant_id, max(plan_key) AS plan_key, jsonb_object_agg(feature_key, jsonb_build_object('allowed', allowed, 'limits', COALESCE(limits, '{}'::jsonb)) ORDER BY feature_key) AS entitlements FROM public.v_tenant_entitlements_full GROUP BY tenant_id; -- -- Name: v_tenant_feature_exceptions; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_tenant_feature_exceptions AS SELECT tf.tenant_id, a.plan_key, tf.feature_key, 'commercial_exception'::text AS exception_type FROM ((public.tenant_features tf JOIN public.v_tenant_active_subscription a ON ((a.tenant_id = tf.tenant_id))) LEFT JOIN public.v_tenant_entitlements_full v ON (((v.tenant_id = tf.tenant_id) AND (v.feature_key = tf.feature_key)))) WHERE ((tf.enabled = true) AND (COALESCE(v.allowed, false) = false)); -- -- Name: v_tenant_feature_mismatch; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_tenant_feature_mismatch AS WITH plan_allowed AS ( SELECT v.tenant_id, v.feature_key, v.allowed FROM public.v_tenant_entitlements_full v ), overrides AS ( SELECT tf.tenant_id, tf.feature_key, tf.enabled FROM public.tenant_features tf ) SELECT o.tenant_id, o.feature_key, CASE WHEN ((o.enabled = true) AND (COALESCE(p.allowed, false) = false)) THEN 'unexpected_override'::text ELSE NULL::text END AS mismatch_type FROM (overrides o LEFT JOIN plan_allowed p ON (((p.tenant_id = o.tenant_id) AND (p.feature_key = o.feature_key)))) WHERE ((o.enabled = true) AND (COALESCE(p.allowed, false) = false)); -- -- Name: v_tenant_members_with_profiles; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_tenant_members_with_profiles AS SELECT tm.id AS tenant_member_id, tm.tenant_id, tm.user_id, tm.role, tm.status, tm.created_at, p.full_name, au.email FROM ((public.tenant_members tm LEFT JOIN public.profiles p ON ((p.id = tm.user_id))) LEFT JOIN auth.users au ON ((au.id = tm.user_id))); -- -- Name: v_tenant_people; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_tenant_people AS SELECT 'member'::text AS type, m.tenant_id, m.user_id, u.email, m.role, m.status, NULL::uuid AS invite_token, NULL::timestamp with time zone AS expires_at FROM (public.tenant_members m JOIN auth.users u ON ((u.id = m.user_id))) UNION ALL SELECT 'invite'::text AS type, i.tenant_id, NULL::uuid AS user_id, i.email, i.role, 'invited'::text AS status, i.token AS invite_token, i.expires_at FROM public.tenant_invites i WHERE ((i.accepted_at IS NULL) AND (i.revoked_at IS NULL)); -- -- Name: v_tenant_staff; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_tenant_staff AS SELECT ('m_'::text || (tm.id)::text) AS row_id, tm.tenant_id, tm.user_id, tm.role, tm.status, tm.created_at, p.full_name, au.email, NULL::uuid AS invite_token FROM ((public.tenant_members tm LEFT JOIN public.profiles p ON ((p.id = tm.user_id))) LEFT JOIN auth.users au ON ((au.id = tm.user_id))) UNION ALL SELECT ('i_'::text || (ti.id)::text) AS row_id, ti.tenant_id, NULL::uuid AS user_id, ti.role, 'invited'::text AS status, ti.created_at, NULL::text AS full_name, ti.email, ti.token AS invite_token FROM public.tenant_invites ti WHERE ((ti.accepted_at IS NULL) AND (ti.revoked_at IS NULL) AND (ti.expires_at > now())); -- -- Name: v_user_active_subscription; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_user_active_subscription AS SELECT DISTINCT ON (user_id) user_id, plan_id, plan_key, "interval", status, current_period_start, current_period_end, created_at FROM public.subscriptions s WHERE ((tenant_id IS NULL) AND (user_id IS NOT NULL) AND (status = 'active'::text) AND ((current_period_end IS NULL) OR (current_period_end > now()))) ORDER BY user_id, created_at DESC; -- -- Name: v_user_entitlements; Type: VIEW; Schema: public; Owner: - -- CREATE VIEW public.v_user_entitlements AS SELECT a.user_id, f.key AS feature_key, true AS allowed FROM ((public.v_user_active_subscription a JOIN public.plan_features pf ON (((pf.plan_id = a.plan_id) AND (pf.enabled = true)))) JOIN public.features f ON ((f.id = pf.feature_id))); -- -- Name: messages; Type: TABLE; Schema: realtime; Owner: - -- CREATE TABLE realtime.messages ( topic text NOT NULL, extension text NOT NULL, payload jsonb, event text, private boolean DEFAULT false, updated_at timestamp without time zone DEFAULT now() NOT NULL, inserted_at timestamp without time zone DEFAULT now() NOT NULL, id uuid DEFAULT gen_random_uuid() NOT NULL ) PARTITION BY RANGE (inserted_at); -- -- Name: messages_2026_03_20; Type: TABLE; Schema: realtime; Owner: - -- CREATE TABLE realtime.messages_2026_03_20 ( topic text NOT NULL, extension text NOT NULL, payload jsonb, event text, private boolean DEFAULT false, updated_at timestamp without time zone DEFAULT now() NOT NULL, inserted_at timestamp without time zone DEFAULT now() NOT NULL, id uuid DEFAULT gen_random_uuid() NOT NULL ); -- -- Name: messages_2026_03_21; Type: TABLE; Schema: realtime; Owner: - -- CREATE TABLE realtime.messages_2026_03_21 ( topic text NOT NULL, extension text NOT NULL, payload jsonb, event text, private boolean DEFAULT false, updated_at timestamp without time zone DEFAULT now() NOT NULL, inserted_at timestamp without time zone DEFAULT now() NOT NULL, id uuid DEFAULT gen_random_uuid() NOT NULL ); -- -- Name: messages_2026_03_22; Type: TABLE; Schema: realtime; Owner: - -- CREATE TABLE realtime.messages_2026_03_22 ( topic text NOT NULL, extension text NOT NULL, payload jsonb, event text, private boolean DEFAULT false, updated_at timestamp without time zone DEFAULT now() NOT NULL, inserted_at timestamp without time zone DEFAULT now() NOT NULL, id uuid DEFAULT gen_random_uuid() NOT NULL ); -- -- Name: messages_2026_03_23; Type: TABLE; Schema: realtime; Owner: - -- CREATE TABLE realtime.messages_2026_03_23 ( topic text NOT NULL, extension text NOT NULL, payload jsonb, event text, private boolean DEFAULT false, updated_at timestamp without time zone DEFAULT now() NOT NULL, inserted_at timestamp without time zone DEFAULT now() NOT NULL, id uuid DEFAULT gen_random_uuid() NOT NULL ); -- -- Name: messages_2026_03_24; Type: TABLE; Schema: realtime; Owner: - -- CREATE TABLE realtime.messages_2026_03_24 ( topic text NOT NULL, extension text NOT NULL, payload jsonb, event text, private boolean DEFAULT false, updated_at timestamp without time zone DEFAULT now() NOT NULL, inserted_at timestamp without time zone DEFAULT now() NOT NULL, id uuid DEFAULT gen_random_uuid() NOT NULL ); -- -- Name: messages_2026_03_25; Type: TABLE; Schema: realtime; Owner: - -- CREATE TABLE realtime.messages_2026_03_25 ( topic text NOT NULL, extension text NOT NULL, payload jsonb, event text, private boolean DEFAULT false, updated_at timestamp without time zone DEFAULT now() NOT NULL, inserted_at timestamp without time zone DEFAULT now() NOT NULL, id uuid DEFAULT gen_random_uuid() NOT NULL ); -- -- Name: messages_2026_03_26; Type: TABLE; Schema: realtime; Owner: - -- CREATE TABLE realtime.messages_2026_03_26 ( topic text NOT NULL, extension text NOT NULL, payload jsonb, event text, private boolean DEFAULT false, updated_at timestamp without time zone DEFAULT now() NOT NULL, inserted_at timestamp without time zone DEFAULT now() NOT NULL, id uuid DEFAULT gen_random_uuid() NOT NULL ); -- -- Name: schema_migrations; Type: TABLE; Schema: realtime; Owner: - -- CREATE TABLE realtime.schema_migrations ( version bigint NOT NULL, inserted_at timestamp(0) without time zone ); -- -- Name: subscription; Type: TABLE; Schema: realtime; Owner: - -- CREATE TABLE realtime.subscription ( id bigint NOT NULL, subscription_id uuid NOT NULL, entity regclass NOT NULL, filters realtime.user_defined_filter[] DEFAULT '{}'::realtime.user_defined_filter[] NOT NULL, claims jsonb NOT NULL, claims_role regrole GENERATED ALWAYS AS (realtime.to_regrole((claims ->> 'role'::text))) STORED NOT NULL, created_at timestamp without time zone DEFAULT timezone('utc'::text, now()) NOT NULL ); -- -- Name: subscription_id_seq; Type: SEQUENCE; Schema: realtime; Owner: - -- ALTER TABLE realtime.subscription ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY ( SEQUENCE NAME realtime.subscription_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1 ); -- -- Name: buckets; Type: TABLE; Schema: storage; Owner: - -- CREATE TABLE storage.buckets ( id text NOT NULL, name text NOT NULL, owner uuid, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now(), public boolean DEFAULT false, avif_autodetection boolean DEFAULT false, file_size_limit bigint, allowed_mime_types text[], owner_id text, type storage.buckettype DEFAULT 'STANDARD'::storage.buckettype NOT NULL ); -- -- Name: COLUMN buckets.owner; Type: COMMENT; Schema: storage; Owner: - -- COMMENT ON COLUMN storage.buckets.owner IS 'Field is deprecated, use owner_id instead'; -- -- Name: buckets_analytics; Type: TABLE; Schema: storage; Owner: - -- CREATE TABLE storage.buckets_analytics ( name text NOT NULL, type storage.buckettype DEFAULT 'ANALYTICS'::storage.buckettype NOT NULL, format text DEFAULT 'ICEBERG'::text NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, id uuid DEFAULT gen_random_uuid() NOT NULL, deleted_at timestamp with time zone ); -- -- Name: buckets_vectors; Type: TABLE; Schema: storage; Owner: - -- CREATE TABLE storage.buckets_vectors ( id text NOT NULL, type storage.buckettype DEFAULT 'VECTOR'::storage.buckettype NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: iceberg_namespaces; Type: TABLE; Schema: storage; Owner: - -- CREATE TABLE storage.iceberg_namespaces ( id uuid DEFAULT gen_random_uuid() NOT NULL, bucket_name text NOT NULL, name text NOT NULL COLLATE pg_catalog."C", created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, metadata jsonb DEFAULT '{}'::jsonb NOT NULL, catalog_id uuid NOT NULL ); -- -- Name: iceberg_tables; Type: TABLE; Schema: storage; Owner: - -- CREATE TABLE storage.iceberg_tables ( id uuid DEFAULT gen_random_uuid() NOT NULL, namespace_id uuid NOT NULL, bucket_name text NOT NULL, name text NOT NULL COLLATE pg_catalog."C", location text NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL, remote_table_id text, shard_key text, shard_id text, catalog_id uuid NOT NULL ); -- -- Name: migrations; Type: TABLE; Schema: storage; Owner: - -- CREATE TABLE storage.migrations ( id integer NOT NULL, name character varying(100) NOT NULL, hash character varying(40) NOT NULL, executed_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP ); -- -- Name: objects; Type: TABLE; Schema: storage; Owner: - -- CREATE TABLE storage.objects ( id uuid DEFAULT gen_random_uuid() NOT NULL, bucket_id text, name text, owner uuid, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now(), last_accessed_at timestamp with time zone DEFAULT now(), metadata jsonb, path_tokens text[] GENERATED ALWAYS AS (string_to_array(name, '/'::text)) STORED, version text, owner_id text, user_metadata jsonb ); -- -- Name: COLUMN objects.owner; Type: COMMENT; Schema: storage; Owner: - -- COMMENT ON COLUMN storage.objects.owner IS 'Field is deprecated, use owner_id instead'; -- -- Name: s3_multipart_uploads; Type: TABLE; Schema: storage; Owner: - -- CREATE TABLE storage.s3_multipart_uploads ( id text NOT NULL, in_progress_size bigint DEFAULT 0 NOT NULL, upload_signature text NOT NULL, bucket_id text NOT NULL, key text NOT NULL COLLATE pg_catalog."C", version text NOT NULL, owner_id text, created_at timestamp with time zone DEFAULT now() NOT NULL, user_metadata jsonb ); -- -- Name: s3_multipart_uploads_parts; Type: TABLE; Schema: storage; Owner: - -- CREATE TABLE storage.s3_multipart_uploads_parts ( id uuid DEFAULT gen_random_uuid() NOT NULL, upload_id text NOT NULL, size bigint DEFAULT 0 NOT NULL, part_number integer NOT NULL, bucket_id text NOT NULL, key text NOT NULL COLLATE pg_catalog."C", etag text NOT NULL, owner_id text, version text NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: vector_indexes; Type: TABLE; Schema: storage; Owner: - -- CREATE TABLE storage.vector_indexes ( id text DEFAULT gen_random_uuid() NOT NULL, name text NOT NULL COLLATE pg_catalog."C", bucket_id text NOT NULL, data_type text NOT NULL, dimension integer NOT NULL, distance_metric text NOT NULL, metadata_configuration jsonb, created_at timestamp with time zone DEFAULT now() NOT NULL, updated_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: hooks; Type: TABLE; Schema: supabase_functions; Owner: - -- CREATE TABLE supabase_functions.hooks ( id bigint NOT NULL, hook_table_id integer NOT NULL, hook_name text NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, request_id bigint ); -- -- Name: TABLE hooks; Type: COMMENT; Schema: supabase_functions; Owner: - -- COMMENT ON TABLE supabase_functions.hooks IS 'Supabase Functions Hooks: Audit trail for triggered hooks.'; -- -- Name: hooks_id_seq; Type: SEQUENCE; Schema: supabase_functions; Owner: - -- CREATE SEQUENCE supabase_functions.hooks_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; -- -- Name: hooks_id_seq; Type: SEQUENCE OWNED BY; Schema: supabase_functions; Owner: - -- ALTER SEQUENCE supabase_functions.hooks_id_seq OWNED BY supabase_functions.hooks.id; -- -- Name: migrations; Type: TABLE; Schema: supabase_functions; Owner: - -- CREATE TABLE supabase_functions.migrations ( version text NOT NULL, inserted_at timestamp with time zone DEFAULT now() NOT NULL ); -- -- Name: messages_2026_03_20; Type: TABLE ATTACH; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages ATTACH PARTITION realtime.messages_2026_03_20 FOR VALUES FROM ('2026-03-20 00:00:00') TO ('2026-03-21 00:00:00'); -- -- Name: messages_2026_03_21; Type: TABLE ATTACH; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages ATTACH PARTITION realtime.messages_2026_03_21 FOR VALUES FROM ('2026-03-21 00:00:00') TO ('2026-03-22 00:00:00'); -- -- Name: messages_2026_03_22; Type: TABLE ATTACH; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages ATTACH PARTITION realtime.messages_2026_03_22 FOR VALUES FROM ('2026-03-22 00:00:00') TO ('2026-03-23 00:00:00'); -- -- Name: messages_2026_03_23; Type: TABLE ATTACH; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages ATTACH PARTITION realtime.messages_2026_03_23 FOR VALUES FROM ('2026-03-23 00:00:00') TO ('2026-03-24 00:00:00'); -- -- Name: messages_2026_03_24; Type: TABLE ATTACH; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages ATTACH PARTITION realtime.messages_2026_03_24 FOR VALUES FROM ('2026-03-24 00:00:00') TO ('2026-03-25 00:00:00'); -- -- Name: messages_2026_03_25; Type: TABLE ATTACH; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages ATTACH PARTITION realtime.messages_2026_03_25 FOR VALUES FROM ('2026-03-25 00:00:00') TO ('2026-03-26 00:00:00'); -- -- Name: messages_2026_03_26; Type: TABLE ATTACH; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages ATTACH PARTITION realtime.messages_2026_03_26 FOR VALUES FROM ('2026-03-26 00:00:00') TO ('2026-03-27 00:00:00'); -- -- Name: refresh_tokens id; Type: DEFAULT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.refresh_tokens ALTER COLUMN id SET DEFAULT nextval('auth.refresh_tokens_id_seq'::regclass); -- -- Name: _db_migrations id; Type: DEFAULT; Schema: public; Owner: - -- ALTER TABLE ONLY public._db_migrations ALTER COLUMN id SET DEFAULT nextval('public._db_migrations_id_seq'::regclass); -- -- Name: agenda_online_slots id; Type: DEFAULT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_online_slots ALTER COLUMN id SET DEFAULT nextval('public.agenda_online_slots_id_seq'::regclass); -- -- Name: hooks id; Type: DEFAULT; Schema: supabase_functions; Owner: - -- ALTER TABLE ONLY supabase_functions.hooks ALTER COLUMN id SET DEFAULT nextval('supabase_functions.hooks_id_seq'::regclass); -- -- Name: extensions extensions_pkey; Type: CONSTRAINT; Schema: _realtime; Owner: - -- ALTER TABLE ONLY _realtime.extensions ADD CONSTRAINT extensions_pkey PRIMARY KEY (id); -- -- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: _realtime; Owner: - -- ALTER TABLE ONLY _realtime.schema_migrations ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); -- -- Name: tenants tenants_pkey; Type: CONSTRAINT; Schema: _realtime; Owner: - -- ALTER TABLE ONLY _realtime.tenants ADD CONSTRAINT tenants_pkey PRIMARY KEY (id); -- -- Name: mfa_amr_claims amr_id_pk; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.mfa_amr_claims ADD CONSTRAINT amr_id_pk PRIMARY KEY (id); -- -- Name: audit_log_entries audit_log_entries_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.audit_log_entries ADD CONSTRAINT audit_log_entries_pkey PRIMARY KEY (id); -- -- Name: flow_state flow_state_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.flow_state ADD CONSTRAINT flow_state_pkey PRIMARY KEY (id); -- -- Name: identities identities_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.identities ADD CONSTRAINT identities_pkey PRIMARY KEY (id); -- -- Name: identities identities_provider_id_provider_unique; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.identities ADD CONSTRAINT identities_provider_id_provider_unique UNIQUE (provider_id, provider); -- -- Name: instances instances_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.instances ADD CONSTRAINT instances_pkey PRIMARY KEY (id); -- -- Name: mfa_amr_claims mfa_amr_claims_session_id_authentication_method_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.mfa_amr_claims ADD CONSTRAINT mfa_amr_claims_session_id_authentication_method_pkey UNIQUE (session_id, authentication_method); -- -- Name: mfa_challenges mfa_challenges_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.mfa_challenges ADD CONSTRAINT mfa_challenges_pkey PRIMARY KEY (id); -- -- Name: mfa_factors mfa_factors_last_challenged_at_key; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.mfa_factors ADD CONSTRAINT mfa_factors_last_challenged_at_key UNIQUE (last_challenged_at); -- -- Name: mfa_factors mfa_factors_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.mfa_factors ADD CONSTRAINT mfa_factors_pkey PRIMARY KEY (id); -- -- Name: oauth_authorizations oauth_authorizations_authorization_code_key; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.oauth_authorizations ADD CONSTRAINT oauth_authorizations_authorization_code_key UNIQUE (authorization_code); -- -- Name: oauth_authorizations oauth_authorizations_authorization_id_key; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.oauth_authorizations ADD CONSTRAINT oauth_authorizations_authorization_id_key UNIQUE (authorization_id); -- -- Name: oauth_authorizations oauth_authorizations_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.oauth_authorizations ADD CONSTRAINT oauth_authorizations_pkey PRIMARY KEY (id); -- -- Name: oauth_client_states oauth_client_states_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.oauth_client_states ADD CONSTRAINT oauth_client_states_pkey PRIMARY KEY (id); -- -- Name: oauth_clients oauth_clients_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.oauth_clients ADD CONSTRAINT oauth_clients_pkey PRIMARY KEY (id); -- -- Name: oauth_consents oauth_consents_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.oauth_consents ADD CONSTRAINT oauth_consents_pkey PRIMARY KEY (id); -- -- Name: oauth_consents oauth_consents_user_client_unique; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.oauth_consents ADD CONSTRAINT oauth_consents_user_client_unique UNIQUE (user_id, client_id); -- -- Name: one_time_tokens one_time_tokens_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.one_time_tokens ADD CONSTRAINT one_time_tokens_pkey PRIMARY KEY (id); -- -- Name: refresh_tokens refresh_tokens_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.refresh_tokens ADD CONSTRAINT refresh_tokens_pkey PRIMARY KEY (id); -- -- Name: refresh_tokens refresh_tokens_token_unique; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.refresh_tokens ADD CONSTRAINT refresh_tokens_token_unique UNIQUE (token); -- -- Name: saml_providers saml_providers_entity_id_key; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.saml_providers ADD CONSTRAINT saml_providers_entity_id_key UNIQUE (entity_id); -- -- Name: saml_providers saml_providers_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.saml_providers ADD CONSTRAINT saml_providers_pkey PRIMARY KEY (id); -- -- Name: saml_relay_states saml_relay_states_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.saml_relay_states ADD CONSTRAINT saml_relay_states_pkey PRIMARY KEY (id); -- -- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.schema_migrations ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); -- -- Name: sessions sessions_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.sessions ADD CONSTRAINT sessions_pkey PRIMARY KEY (id); -- -- Name: sso_domains sso_domains_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.sso_domains ADD CONSTRAINT sso_domains_pkey PRIMARY KEY (id); -- -- Name: sso_providers sso_providers_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.sso_providers ADD CONSTRAINT sso_providers_pkey PRIMARY KEY (id); -- -- Name: users users_phone_key; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.users ADD CONSTRAINT users_phone_key UNIQUE (phone); -- -- Name: users users_pkey; Type: CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.users ADD CONSTRAINT users_pkey PRIMARY KEY (id); -- -- Name: _db_migrations _db_migrations_filename_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public._db_migrations ADD CONSTRAINT _db_migrations_filename_key UNIQUE (filename); -- -- Name: _db_migrations _db_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public._db_migrations ADD CONSTRAINT _db_migrations_pkey PRIMARY KEY (id); -- -- Name: addon_credits addon_credits_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.addon_credits ADD CONSTRAINT addon_credits_pkey PRIMARY KEY (id); -- -- Name: addon_products addon_products_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.addon_products ADD CONSTRAINT addon_products_pkey PRIMARY KEY (id); -- -- Name: addon_products addon_products_slug_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.addon_products ADD CONSTRAINT addon_products_slug_key UNIQUE (slug); -- -- Name: addon_transactions addon_transactions_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.addon_transactions ADD CONSTRAINT addon_transactions_pkey PRIMARY KEY (id); -- -- Name: agenda_bloqueios agenda_bloqueios_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_bloqueios ADD CONSTRAINT agenda_bloqueios_pkey PRIMARY KEY (id); -- -- Name: agenda_configuracoes agenda_configuracoes_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_configuracoes ADD CONSTRAINT agenda_configuracoes_pkey PRIMARY KEY (owner_id); -- -- Name: agenda_eventos agenda_eventos_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_eventos ADD CONSTRAINT agenda_eventos_pkey PRIMARY KEY (id); -- -- Name: agenda_eventos agenda_eventos_sem_sobreposicao; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_eventos ADD CONSTRAINT agenda_eventos_sem_sobreposicao EXCLUDE USING gist (owner_id WITH =, tstzrange(inicio_em, fim_em, '[)'::text) WITH &&); -- -- Name: agenda_excecoes agenda_excecoes_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_excecoes ADD CONSTRAINT agenda_excecoes_pkey PRIMARY KEY (id); -- -- Name: agenda_online_slots agenda_online_slots_owner_id_weekday_time_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_online_slots ADD CONSTRAINT agenda_online_slots_owner_id_weekday_time_key UNIQUE (owner_id, weekday, "time"); -- -- Name: agenda_online_slots agenda_online_slots_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_online_slots ADD CONSTRAINT agenda_online_slots_pkey PRIMARY KEY (id); -- -- Name: agenda_regras_semanais agenda_regras_semanais_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_regras_semanais ADD CONSTRAINT agenda_regras_semanais_pkey PRIMARY KEY (id); -- -- Name: agenda_regras_semanais agenda_regras_semanais_unique; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_regras_semanais ADD CONSTRAINT agenda_regras_semanais_unique UNIQUE (owner_id, dia_semana, hora_inicio, hora_fim, modalidade); -- -- Name: agenda_slots_bloqueados_semanais agenda_slots_bloqueados_seman_owner_id_dia_semana_hora_inic_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_slots_bloqueados_semanais ADD CONSTRAINT agenda_slots_bloqueados_seman_owner_id_dia_semana_hora_inic_key UNIQUE (owner_id, dia_semana, hora_inicio); -- -- Name: agenda_slots_bloqueados_semanais agenda_slots_bloqueados_semanais_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_slots_bloqueados_semanais ADD CONSTRAINT agenda_slots_bloqueados_semanais_pkey PRIMARY KEY (id); -- -- Name: agenda_slots_regras agenda_slots_regras_owner_id_dia_semana_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_slots_regras ADD CONSTRAINT agenda_slots_regras_owner_id_dia_semana_key UNIQUE (owner_id, dia_semana); -- -- Name: agenda_slots_regras agenda_slots_regras_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_slots_regras ADD CONSTRAINT agenda_slots_regras_pkey PRIMARY KEY (id); -- -- Name: agendador_configuracoes agendador_configuracoes_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agendador_configuracoes ADD CONSTRAINT agendador_configuracoes_pkey PRIMARY KEY (owner_id); -- -- Name: agendador_solicitacoes agendador_solicitacoes_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agendador_solicitacoes ADD CONSTRAINT agendador_solicitacoes_pkey PRIMARY KEY (id); -- -- Name: billing_contracts billing_contracts_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.billing_contracts ADD CONSTRAINT billing_contracts_pkey PRIMARY KEY (id); -- -- Name: commitment_services commitment_services_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.commitment_services ADD CONSTRAINT commitment_services_pkey PRIMARY KEY (id); -- -- Name: commitment_time_logs commitment_time_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.commitment_time_logs ADD CONSTRAINT commitment_time_logs_pkey PRIMARY KEY (id); -- -- Name: company_profiles company_profiles_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.company_profiles ADD CONSTRAINT company_profiles_pkey PRIMARY KEY (id); -- -- Name: company_profiles company_profiles_tenant_id_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.company_profiles ADD CONSTRAINT company_profiles_tenant_id_key UNIQUE (tenant_id); -- -- Name: determined_commitment_fields determined_commitment_fields_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.determined_commitment_fields ADD CONSTRAINT determined_commitment_fields_pkey PRIMARY KEY (id); -- -- Name: determined_commitments determined_commitments_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.determined_commitments ADD CONSTRAINT determined_commitments_pkey PRIMARY KEY (id); -- -- Name: determined_commitments determined_commitments_tenant_native_key_uq; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.determined_commitments ADD CONSTRAINT determined_commitments_tenant_native_key_uq UNIQUE (tenant_id, native_key); -- -- Name: dev_user_credentials dev_user_credentials_email_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.dev_user_credentials ADD CONSTRAINT dev_user_credentials_email_key UNIQUE (email); -- -- Name: dev_user_credentials dev_user_credentials_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.dev_user_credentials ADD CONSTRAINT dev_user_credentials_pkey PRIMARY KEY (id); -- -- Name: email_layout_config email_layout_config_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.email_layout_config ADD CONSTRAINT email_layout_config_pkey PRIMARY KEY (id); -- -- Name: email_layout_config email_layout_config_tenant_id_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.email_layout_config ADD CONSTRAINT email_layout_config_tenant_id_key UNIQUE (tenant_id); -- -- Name: email_templates_global email_templates_global_key_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.email_templates_global ADD CONSTRAINT email_templates_global_key_key UNIQUE (key); -- -- Name: email_templates_global email_templates_global_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.email_templates_global ADD CONSTRAINT email_templates_global_pkey PRIMARY KEY (id); -- -- Name: email_templates_tenant email_templates_tenant_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.email_templates_tenant ADD CONSTRAINT email_templates_tenant_pkey PRIMARY KEY (id); -- -- Name: email_templates_tenant email_templates_tenant_tenant_id_owner_id_template_key_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.email_templates_tenant ADD CONSTRAINT email_templates_tenant_tenant_id_owner_id_template_key_key UNIQUE (tenant_id, owner_id, template_key); -- -- Name: entitlements_invalidation entitlements_invalidation_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.entitlements_invalidation ADD CONSTRAINT entitlements_invalidation_pkey PRIMARY KEY (owner_id); -- -- Name: features features_key_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.features ADD CONSTRAINT features_key_key UNIQUE (key); -- -- Name: features features_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.features ADD CONSTRAINT features_pkey PRIMARY KEY (id); -- -- Name: feriados feriados_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.feriados ADD CONSTRAINT feriados_pkey PRIMARY KEY (id); -- -- Name: feriados feriados_tenant_id_data_nome_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.feriados ADD CONSTRAINT feriados_tenant_id_data_nome_key UNIQUE (tenant_id, data, nome); -- -- Name: financial_categories financial_categories_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.financial_categories ADD CONSTRAINT financial_categories_pkey PRIMARY KEY (id); -- -- Name: financial_exceptions financial_exceptions_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.financial_exceptions ADD CONSTRAINT financial_exceptions_pkey PRIMARY KEY (id); -- -- Name: financial_records financial_records_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.financial_records ADD CONSTRAINT financial_records_pkey PRIMARY KEY (id); -- -- Name: global_notices global_notices_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.global_notices ADD CONSTRAINT global_notices_pkey PRIMARY KEY (id); -- -- Name: insurance_plan_services insurance_plan_services_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.insurance_plan_services ADD CONSTRAINT insurance_plan_services_pkey PRIMARY KEY (id); -- -- Name: insurance_plans insurance_plans_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.insurance_plans ADD CONSTRAINT insurance_plans_pkey PRIMARY KEY (id); -- -- Name: login_carousel_slides login_carousel_slides_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.login_carousel_slides ADD CONSTRAINT login_carousel_slides_pkey PRIMARY KEY (id); -- -- Name: module_features module_features_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.module_features ADD CONSTRAINT module_features_pkey PRIMARY KEY (module_id, feature_id); -- -- Name: modules modules_key_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.modules ADD CONSTRAINT modules_key_key UNIQUE (key); -- -- Name: modules modules_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.modules ADD CONSTRAINT modules_pkey PRIMARY KEY (id); -- -- Name: notice_dismissals notice_dismissals_notice_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notice_dismissals ADD CONSTRAINT notice_dismissals_notice_id_user_id_key UNIQUE (notice_id, user_id); -- -- Name: notice_dismissals notice_dismissals_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notice_dismissals ADD CONSTRAINT notice_dismissals_pkey PRIMARY KEY (id); -- -- Name: notification_channels notification_channels_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_channels ADD CONSTRAINT notification_channels_pkey PRIMARY KEY (id); -- -- Name: notification_logs notification_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_logs ADD CONSTRAINT notification_logs_pkey PRIMARY KEY (id); -- -- Name: notification_preferences notification_preferences_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_preferences ADD CONSTRAINT notification_preferences_pkey PRIMARY KEY (id); -- -- Name: notification_queue notification_queue_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_queue ADD CONSTRAINT notification_queue_pkey PRIMARY KEY (id); -- -- Name: notification_schedules notification_schedules_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_schedules ADD CONSTRAINT notification_schedules_pkey PRIMARY KEY (id); -- -- Name: notification_templates notification_templates_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_templates ADD CONSTRAINT notification_templates_pkey PRIMARY KEY (id); -- -- Name: notifications notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notifications ADD CONSTRAINT notifications_pkey PRIMARY KEY (id); -- -- Name: owner_users owner_users_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.owner_users ADD CONSTRAINT owner_users_pkey PRIMARY KEY (owner_id, user_id); -- -- Name: patient_discounts patient_discounts_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_discounts ADD CONSTRAINT patient_discounts_pkey PRIMARY KEY (id); -- -- Name: patient_group_patient patient_group_patient_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_group_patient ADD CONSTRAINT patient_group_patient_pkey PRIMARY KEY (patient_group_id, patient_id); -- -- Name: patient_groups patient_groups_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_groups ADD CONSTRAINT patient_groups_pkey PRIMARY KEY (id); -- -- Name: patient_intake_requests patient_intake_requests_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_intake_requests ADD CONSTRAINT patient_intake_requests_pkey PRIMARY KEY (id); -- -- Name: patient_invites patient_invites_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_invites ADD CONSTRAINT patient_invites_pkey PRIMARY KEY (id); -- -- Name: patient_invites patient_invites_token_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_invites ADD CONSTRAINT patient_invites_token_key UNIQUE (token); -- -- Name: patient_patient_tag patient_patient_tag_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_patient_tag ADD CONSTRAINT patient_patient_tag_pkey PRIMARY KEY (patient_id, tag_id); -- -- Name: patient_tags patient_tags_owner_name_uniq; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_tags ADD CONSTRAINT patient_tags_owner_name_uniq UNIQUE (owner_id, nome); -- -- Name: patient_tags patient_tags_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_tags ADD CONSTRAINT patient_tags_pkey PRIMARY KEY (id); -- -- Name: patients patients_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patients ADD CONSTRAINT patients_pkey PRIMARY KEY (id); -- -- Name: payment_settings payment_settings_owner_id_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.payment_settings ADD CONSTRAINT payment_settings_owner_id_key UNIQUE (owner_id); -- -- Name: payment_settings payment_settings_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.payment_settings ADD CONSTRAINT payment_settings_pkey PRIMARY KEY (id); -- -- Name: plan_features plan_features_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.plan_features ADD CONSTRAINT plan_features_pkey PRIMARY KEY (plan_id, feature_id); -- -- Name: plan_prices plan_prices_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.plan_prices ADD CONSTRAINT plan_prices_pkey PRIMARY KEY (id); -- -- Name: plan_public_bullets plan_public_bullets_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.plan_public_bullets ADD CONSTRAINT plan_public_bullets_pkey PRIMARY KEY (id); -- -- Name: plan_public plan_public_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.plan_public ADD CONSTRAINT plan_public_pkey PRIMARY KEY (plan_id); -- -- Name: plans plans_key_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.plans ADD CONSTRAINT plans_key_key UNIQUE (key); -- -- Name: plans plans_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.plans ADD CONSTRAINT plans_pkey PRIMARY KEY (id); -- -- Name: professional_pricing professional_pricing_owner_commitment_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.professional_pricing ADD CONSTRAINT professional_pricing_owner_commitment_key UNIQUE (owner_id, determined_commitment_id); -- -- Name: professional_pricing professional_pricing_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.professional_pricing ADD CONSTRAINT professional_pricing_pkey PRIMARY KEY (id); -- -- Name: profiles profiles_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.profiles ADD CONSTRAINT profiles_pkey PRIMARY KEY (id); -- -- Name: recurrence_exceptions recurrence_exceptions_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.recurrence_exceptions ADD CONSTRAINT recurrence_exceptions_pkey PRIMARY KEY (id); -- -- Name: recurrence_exceptions recurrence_exceptions_unique; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.recurrence_exceptions ADD CONSTRAINT recurrence_exceptions_unique UNIQUE (recurrence_id, original_date); -- -- Name: recurrence_rule_services recurrence_rule_services_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.recurrence_rule_services ADD CONSTRAINT recurrence_rule_services_pkey PRIMARY KEY (id); -- -- Name: recurrence_rules recurrence_rules_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.recurrence_rules ADD CONSTRAINT recurrence_rules_pkey PRIMARY KEY (id); -- -- Name: saas_admins saas_admins_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.saas_admins ADD CONSTRAINT saas_admins_pkey PRIMARY KEY (user_id); -- -- Name: saas_doc_votos saas_doc_votos_doc_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.saas_doc_votos ADD CONSTRAINT saas_doc_votos_doc_id_user_id_key UNIQUE (doc_id, user_id); -- -- Name: saas_doc_votos saas_doc_votos_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.saas_doc_votos ADD CONSTRAINT saas_doc_votos_pkey PRIMARY KEY (id); -- -- Name: saas_docs saas_docs_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.saas_docs ADD CONSTRAINT saas_docs_pkey PRIMARY KEY (id); -- -- Name: saas_faq_itens saas_faq_itens_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.saas_faq_itens ADD CONSTRAINT saas_faq_itens_pkey PRIMARY KEY (id); -- -- Name: saas_faq saas_faq_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.saas_faq ADD CONSTRAINT saas_faq_pkey PRIMARY KEY (id); -- -- Name: services services_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.services ADD CONSTRAINT services_pkey PRIMARY KEY (id); -- -- Name: subscription_events subscription_events_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscription_events ADD CONSTRAINT subscription_events_pkey PRIMARY KEY (id); -- -- Name: subscription_intents_personal subscription_intents_personal_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscription_intents_personal ADD CONSTRAINT subscription_intents_personal_pkey PRIMARY KEY (id); -- -- Name: subscription_intents_legacy subscription_intents_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscription_intents_legacy ADD CONSTRAINT subscription_intents_pkey PRIMARY KEY (id); -- -- Name: subscription_intents_tenant subscription_intents_tenant_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscription_intents_tenant ADD CONSTRAINT subscription_intents_tenant_pkey PRIMARY KEY (id); -- -- Name: subscriptions subscriptions_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscriptions ADD CONSTRAINT subscriptions_pkey PRIMARY KEY (id); -- -- Name: support_sessions support_sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.support_sessions ADD CONSTRAINT support_sessions_pkey PRIMARY KEY (id); -- -- Name: support_sessions support_sessions_token_unique; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.support_sessions ADD CONSTRAINT support_sessions_token_unique UNIQUE (token); -- -- Name: tenant_feature_exceptions_log tenant_feature_exceptions_log_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_feature_exceptions_log ADD CONSTRAINT tenant_feature_exceptions_log_pkey PRIMARY KEY (id); -- -- Name: tenant_features tenant_features_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_features ADD CONSTRAINT tenant_features_pkey PRIMARY KEY (tenant_id, feature_key); -- -- Name: tenant_invites tenant_invites_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_invites ADD CONSTRAINT tenant_invites_pkey PRIMARY KEY (id); -- -- Name: tenant_members tenant_members_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_members ADD CONSTRAINT tenant_members_pkey PRIMARY KEY (id); -- -- Name: tenant_members tenant_members_tenant_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_members ADD CONSTRAINT tenant_members_tenant_id_user_id_key UNIQUE (tenant_id, user_id); -- -- Name: tenant_modules tenant_modules_owner_id_module_id_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_modules ADD CONSTRAINT tenant_modules_owner_id_module_id_key UNIQUE (owner_id, module_id); -- -- Name: tenant_modules tenant_modules_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_modules ADD CONSTRAINT tenant_modules_pkey PRIMARY KEY (id); -- -- Name: tenants tenants_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenants ADD CONSTRAINT tenants_pkey PRIMARY KEY (id); -- -- Name: therapist_payout_records therapist_payout_records_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.therapist_payout_records ADD CONSTRAINT therapist_payout_records_pkey PRIMARY KEY (payout_id, financial_record_id); -- -- Name: therapist_payouts therapist_payouts_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.therapist_payouts ADD CONSTRAINT therapist_payouts_pkey PRIMARY KEY (id); -- -- Name: addon_credits uq_addon_credits_tenant_type; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.addon_credits ADD CONSTRAINT uq_addon_credits_tenant_type UNIQUE (tenant_id, addon_type); -- -- Name: notification_channels uq_channel_per_owner; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_channels ADD CONSTRAINT uq_channel_per_owner UNIQUE NULLS NOT DISTINCT (owner_id, channel, deleted_at); -- -- Name: notification_preferences uq_notif_prefs_patient_owner; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_preferences ADD CONSTRAINT uq_notif_prefs_patient_owner UNIQUE NULLS NOT DISTINCT (owner_id, patient_id, deleted_at); -- -- Name: notification_queue uq_notif_queue_idempotency; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_queue ADD CONSTRAINT uq_notif_queue_idempotency UNIQUE (idempotency_key); -- -- Name: notification_schedules uq_notif_schedule_owner; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_schedules ADD CONSTRAINT uq_notif_schedule_owner UNIQUE NULLS NOT DISTINCT (owner_id, schedule_key, deleted_at); -- -- Name: notification_templates uq_notif_template_key; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_templates ADD CONSTRAINT uq_notif_template_key UNIQUE NULLS NOT DISTINCT (tenant_id, owner_id, key, deleted_at); -- -- Name: user_settings user_settings_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.user_settings ADD CONSTRAINT user_settings_pkey PRIMARY KEY (user_id); -- -- Name: messages messages_pkey; Type: CONSTRAINT; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages ADD CONSTRAINT messages_pkey PRIMARY KEY (id, inserted_at); -- -- Name: messages_2026_03_20 messages_2026_03_20_pkey; Type: CONSTRAINT; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages_2026_03_20 ADD CONSTRAINT messages_2026_03_20_pkey PRIMARY KEY (id, inserted_at); -- -- Name: messages_2026_03_21 messages_2026_03_21_pkey; Type: CONSTRAINT; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages_2026_03_21 ADD CONSTRAINT messages_2026_03_21_pkey PRIMARY KEY (id, inserted_at); -- -- Name: messages_2026_03_22 messages_2026_03_22_pkey; Type: CONSTRAINT; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages_2026_03_22 ADD CONSTRAINT messages_2026_03_22_pkey PRIMARY KEY (id, inserted_at); -- -- Name: messages_2026_03_23 messages_2026_03_23_pkey; Type: CONSTRAINT; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages_2026_03_23 ADD CONSTRAINT messages_2026_03_23_pkey PRIMARY KEY (id, inserted_at); -- -- Name: messages_2026_03_24 messages_2026_03_24_pkey; Type: CONSTRAINT; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages_2026_03_24 ADD CONSTRAINT messages_2026_03_24_pkey PRIMARY KEY (id, inserted_at); -- -- Name: messages_2026_03_25 messages_2026_03_25_pkey; Type: CONSTRAINT; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages_2026_03_25 ADD CONSTRAINT messages_2026_03_25_pkey PRIMARY KEY (id, inserted_at); -- -- Name: messages_2026_03_26 messages_2026_03_26_pkey; Type: CONSTRAINT; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.messages_2026_03_26 ADD CONSTRAINT messages_2026_03_26_pkey PRIMARY KEY (id, inserted_at); -- -- Name: subscription pk_subscription; Type: CONSTRAINT; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.subscription ADD CONSTRAINT pk_subscription PRIMARY KEY (id); -- -- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: realtime; Owner: - -- ALTER TABLE ONLY realtime.schema_migrations ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); -- -- Name: buckets_analytics buckets_analytics_pkey; Type: CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.buckets_analytics ADD CONSTRAINT buckets_analytics_pkey PRIMARY KEY (id); -- -- Name: buckets buckets_pkey; Type: CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.buckets ADD CONSTRAINT buckets_pkey PRIMARY KEY (id); -- -- Name: buckets_vectors buckets_vectors_pkey; Type: CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.buckets_vectors ADD CONSTRAINT buckets_vectors_pkey PRIMARY KEY (id); -- -- Name: iceberg_namespaces iceberg_namespaces_pkey; Type: CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.iceberg_namespaces ADD CONSTRAINT iceberg_namespaces_pkey PRIMARY KEY (id); -- -- Name: iceberg_tables iceberg_tables_pkey; Type: CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.iceberg_tables ADD CONSTRAINT iceberg_tables_pkey PRIMARY KEY (id); -- -- Name: migrations migrations_name_key; Type: CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.migrations ADD CONSTRAINT migrations_name_key UNIQUE (name); -- -- Name: migrations migrations_pkey; Type: CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.migrations ADD CONSTRAINT migrations_pkey PRIMARY KEY (id); -- -- Name: objects objects_pkey; Type: CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.objects ADD CONSTRAINT objects_pkey PRIMARY KEY (id); -- -- Name: s3_multipart_uploads_parts s3_multipart_uploads_parts_pkey; Type: CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.s3_multipart_uploads_parts ADD CONSTRAINT s3_multipart_uploads_parts_pkey PRIMARY KEY (id); -- -- Name: s3_multipart_uploads s3_multipart_uploads_pkey; Type: CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.s3_multipart_uploads ADD CONSTRAINT s3_multipart_uploads_pkey PRIMARY KEY (id); -- -- Name: vector_indexes vector_indexes_pkey; Type: CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.vector_indexes ADD CONSTRAINT vector_indexes_pkey PRIMARY KEY (id); -- -- Name: hooks hooks_pkey; Type: CONSTRAINT; Schema: supabase_functions; Owner: - -- ALTER TABLE ONLY supabase_functions.hooks ADD CONSTRAINT hooks_pkey PRIMARY KEY (id); -- -- Name: migrations migrations_pkey; Type: CONSTRAINT; Schema: supabase_functions; Owner: - -- ALTER TABLE ONLY supabase_functions.migrations ADD CONSTRAINT migrations_pkey PRIMARY KEY (version); -- -- Name: extensions_tenant_external_id_index; Type: INDEX; Schema: _realtime; Owner: - -- CREATE INDEX extensions_tenant_external_id_index ON _realtime.extensions USING btree (tenant_external_id); -- -- Name: extensions_tenant_external_id_type_index; Type: INDEX; Schema: _realtime; Owner: - -- CREATE UNIQUE INDEX extensions_tenant_external_id_type_index ON _realtime.extensions USING btree (tenant_external_id, type); -- -- Name: tenants_external_id_index; Type: INDEX; Schema: _realtime; Owner: - -- CREATE UNIQUE INDEX tenants_external_id_index ON _realtime.tenants USING btree (external_id); -- -- Name: audit_logs_instance_id_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX audit_logs_instance_id_idx ON auth.audit_log_entries USING btree (instance_id); -- -- Name: confirmation_token_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE UNIQUE INDEX confirmation_token_idx ON auth.users USING btree (confirmation_token) WHERE ((confirmation_token)::text !~ '^[0-9 ]*$'::text); -- -- Name: email_change_token_current_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE UNIQUE INDEX email_change_token_current_idx ON auth.users USING btree (email_change_token_current) WHERE ((email_change_token_current)::text !~ '^[0-9 ]*$'::text); -- -- Name: email_change_token_new_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE UNIQUE INDEX email_change_token_new_idx ON auth.users USING btree (email_change_token_new) WHERE ((email_change_token_new)::text !~ '^[0-9 ]*$'::text); -- -- Name: factor_id_created_at_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX factor_id_created_at_idx ON auth.mfa_factors USING btree (user_id, created_at); -- -- Name: flow_state_created_at_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX flow_state_created_at_idx ON auth.flow_state USING btree (created_at DESC); -- -- Name: identities_email_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX identities_email_idx ON auth.identities USING btree (email text_pattern_ops); -- -- Name: INDEX identities_email_idx; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON INDEX auth.identities_email_idx IS 'Auth: Ensures indexed queries on the email column'; -- -- Name: identities_user_id_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX identities_user_id_idx ON auth.identities USING btree (user_id); -- -- Name: idx_auth_code; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX idx_auth_code ON auth.flow_state USING btree (auth_code); -- -- Name: idx_oauth_client_states_created_at; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX idx_oauth_client_states_created_at ON auth.oauth_client_states USING btree (created_at); -- -- Name: idx_user_id_auth_method; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX idx_user_id_auth_method ON auth.flow_state USING btree (user_id, authentication_method); -- -- Name: mfa_challenge_created_at_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX mfa_challenge_created_at_idx ON auth.mfa_challenges USING btree (created_at DESC); -- -- Name: mfa_factors_user_friendly_name_unique; Type: INDEX; Schema: auth; Owner: - -- CREATE UNIQUE INDEX mfa_factors_user_friendly_name_unique ON auth.mfa_factors USING btree (friendly_name, user_id) WHERE (TRIM(BOTH FROM friendly_name) <> ''::text); -- -- Name: mfa_factors_user_id_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX mfa_factors_user_id_idx ON auth.mfa_factors USING btree (user_id); -- -- Name: oauth_auth_pending_exp_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX oauth_auth_pending_exp_idx ON auth.oauth_authorizations USING btree (expires_at) WHERE (status = 'pending'::auth.oauth_authorization_status); -- -- Name: oauth_clients_deleted_at_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX oauth_clients_deleted_at_idx ON auth.oauth_clients USING btree (deleted_at); -- -- Name: oauth_consents_active_client_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX oauth_consents_active_client_idx ON auth.oauth_consents USING btree (client_id) WHERE (revoked_at IS NULL); -- -- Name: oauth_consents_active_user_client_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX oauth_consents_active_user_client_idx ON auth.oauth_consents USING btree (user_id, client_id) WHERE (revoked_at IS NULL); -- -- Name: oauth_consents_user_order_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX oauth_consents_user_order_idx ON auth.oauth_consents USING btree (user_id, granted_at DESC); -- -- Name: one_time_tokens_relates_to_hash_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX one_time_tokens_relates_to_hash_idx ON auth.one_time_tokens USING hash (relates_to); -- -- Name: one_time_tokens_token_hash_hash_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX one_time_tokens_token_hash_hash_idx ON auth.one_time_tokens USING hash (token_hash); -- -- Name: one_time_tokens_user_id_token_type_key; Type: INDEX; Schema: auth; Owner: - -- CREATE UNIQUE INDEX one_time_tokens_user_id_token_type_key ON auth.one_time_tokens USING btree (user_id, token_type); -- -- Name: reauthentication_token_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE UNIQUE INDEX reauthentication_token_idx ON auth.users USING btree (reauthentication_token) WHERE ((reauthentication_token)::text !~ '^[0-9 ]*$'::text); -- -- Name: recovery_token_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE UNIQUE INDEX recovery_token_idx ON auth.users USING btree (recovery_token) WHERE ((recovery_token)::text !~ '^[0-9 ]*$'::text); -- -- Name: refresh_tokens_instance_id_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX refresh_tokens_instance_id_idx ON auth.refresh_tokens USING btree (instance_id); -- -- Name: refresh_tokens_instance_id_user_id_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX refresh_tokens_instance_id_user_id_idx ON auth.refresh_tokens USING btree (instance_id, user_id); -- -- Name: refresh_tokens_parent_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX refresh_tokens_parent_idx ON auth.refresh_tokens USING btree (parent); -- -- Name: refresh_tokens_session_id_revoked_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX refresh_tokens_session_id_revoked_idx ON auth.refresh_tokens USING btree (session_id, revoked); -- -- Name: refresh_tokens_updated_at_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX refresh_tokens_updated_at_idx ON auth.refresh_tokens USING btree (updated_at DESC); -- -- Name: saml_providers_sso_provider_id_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX saml_providers_sso_provider_id_idx ON auth.saml_providers USING btree (sso_provider_id); -- -- Name: saml_relay_states_created_at_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX saml_relay_states_created_at_idx ON auth.saml_relay_states USING btree (created_at DESC); -- -- Name: saml_relay_states_for_email_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX saml_relay_states_for_email_idx ON auth.saml_relay_states USING btree (for_email); -- -- Name: saml_relay_states_sso_provider_id_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX saml_relay_states_sso_provider_id_idx ON auth.saml_relay_states USING btree (sso_provider_id); -- -- Name: sessions_not_after_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX sessions_not_after_idx ON auth.sessions USING btree (not_after DESC); -- -- Name: sessions_oauth_client_id_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX sessions_oauth_client_id_idx ON auth.sessions USING btree (oauth_client_id); -- -- Name: sessions_user_id_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX sessions_user_id_idx ON auth.sessions USING btree (user_id); -- -- Name: sso_domains_domain_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE UNIQUE INDEX sso_domains_domain_idx ON auth.sso_domains USING btree (lower(domain)); -- -- Name: sso_domains_sso_provider_id_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX sso_domains_sso_provider_id_idx ON auth.sso_domains USING btree (sso_provider_id); -- -- Name: sso_providers_resource_id_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE UNIQUE INDEX sso_providers_resource_id_idx ON auth.sso_providers USING btree (lower(resource_id)); -- -- Name: sso_providers_resource_id_pattern_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX sso_providers_resource_id_pattern_idx ON auth.sso_providers USING btree (resource_id text_pattern_ops); -- -- Name: unique_phone_factor_per_user; Type: INDEX; Schema: auth; Owner: - -- CREATE UNIQUE INDEX unique_phone_factor_per_user ON auth.mfa_factors USING btree (user_id, phone); -- -- Name: user_id_created_at_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX user_id_created_at_idx ON auth.sessions USING btree (user_id, created_at); -- -- Name: users_email_partial_key; Type: INDEX; Schema: auth; Owner: - -- CREATE UNIQUE INDEX users_email_partial_key ON auth.users USING btree (email) WHERE (is_sso_user = false); -- -- Name: INDEX users_email_partial_key; Type: COMMENT; Schema: auth; Owner: - -- COMMENT ON INDEX auth.users_email_partial_key IS 'Auth: A partial unique index that applies only when is_sso_user is false'; -- -- Name: users_instance_id_email_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX users_instance_id_email_idx ON auth.users USING btree (instance_id, lower((email)::text)); -- -- Name: users_instance_id_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX users_instance_id_idx ON auth.users USING btree (instance_id); -- -- Name: users_is_anonymous_idx; Type: INDEX; Schema: auth; Owner: - -- CREATE INDEX users_is_anonymous_idx ON auth.users USING btree (is_anonymous); -- -- Name: agenda_bloqueios_owner_data_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_bloqueios_owner_data_idx ON public.agenda_bloqueios USING btree (owner_id, data_inicio, data_fim); -- -- Name: agenda_bloqueios_owner_id_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_bloqueios_owner_id_idx ON public.agenda_bloqueios USING btree (owner_id); -- -- Name: agenda_bloqueios_recorrente_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_bloqueios_recorrente_idx ON public.agenda_bloqueios USING btree (owner_id, dia_semana) WHERE (recorrente = true); -- -- Name: agenda_bloqueios_tenant_id_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_bloqueios_tenant_id_idx ON public.agenda_bloqueios USING btree (tenant_id); -- -- Name: agenda_configuracoes_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_configuracoes_tenant_idx ON public.agenda_configuracoes USING btree (tenant_id); -- -- Name: agenda_configuracoes_tenant_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_configuracoes_tenant_owner_idx ON public.agenda_configuracoes USING btree (tenant_id, owner_id); -- -- Name: agenda_eventos_billing_contract_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_eventos_billing_contract_idx ON public.agenda_eventos USING btree (billing_contract_id) WHERE (billing_contract_id IS NOT NULL); -- -- Name: agenda_eventos_insurance_plan_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_eventos_insurance_plan_idx ON public.agenda_eventos USING btree (insurance_plan_id); -- -- Name: agenda_eventos_owner_inicio_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_eventos_owner_inicio_idx ON public.agenda_eventos USING btree (owner_id, inicio_em); -- -- Name: agenda_eventos_owner_terapeuta_inicio_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_eventos_owner_terapeuta_inicio_idx ON public.agenda_eventos USING btree (owner_id, terapeuta_id, inicio_em); -- -- Name: agenda_eventos_recurrence_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_eventos_recurrence_idx ON public.agenda_eventos USING btree (recurrence_id) WHERE (recurrence_id IS NOT NULL); -- -- Name: agenda_eventos_tenant_inicio_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_eventos_tenant_inicio_idx ON public.agenda_eventos USING btree (tenant_id, inicio_em); -- -- Name: agenda_eventos_tenant_owner_inicio_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_eventos_tenant_owner_inicio_idx ON public.agenda_eventos USING btree (tenant_id, owner_id, inicio_em); -- -- Name: agenda_excecoes_owner_data_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_excecoes_owner_data_idx ON public.agenda_excecoes USING btree (owner_id, data); -- -- Name: agenda_excecoes_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_excecoes_tenant_idx ON public.agenda_excecoes USING btree (tenant_id); -- -- Name: agenda_excecoes_tenant_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_excecoes_tenant_owner_idx ON public.agenda_excecoes USING btree (tenant_id, owner_id); -- -- Name: agenda_online_slots_owner_weekday_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_online_slots_owner_weekday_idx ON public.agenda_online_slots USING btree (owner_id, weekday); -- -- Name: agenda_online_slots_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_online_slots_tenant_idx ON public.agenda_online_slots USING btree (tenant_id); -- -- Name: agenda_online_slots_tenant_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_online_slots_tenant_owner_idx ON public.agenda_online_slots USING btree (tenant_id, owner_id); -- -- Name: agenda_regras_semanais_owner_dia_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_regras_semanais_owner_dia_idx ON public.agenda_regras_semanais USING btree (owner_id, dia_semana); -- -- Name: agenda_regras_semanais_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_regras_semanais_tenant_idx ON public.agenda_regras_semanais USING btree (tenant_id); -- -- Name: agenda_regras_semanais_tenant_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_regras_semanais_tenant_owner_idx ON public.agenda_regras_semanais USING btree (tenant_id, owner_id); -- -- Name: agenda_slots_bloqueados_semanais_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_slots_bloqueados_semanais_tenant_idx ON public.agenda_slots_bloqueados_semanais USING btree (tenant_id); -- -- Name: agenda_slots_bloqueados_semanais_tenant_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_slots_bloqueados_semanais_tenant_owner_idx ON public.agenda_slots_bloqueados_semanais USING btree (tenant_id, owner_id); -- -- Name: agenda_slots_regras_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_slots_regras_tenant_idx ON public.agenda_slots_regras USING btree (tenant_id); -- -- Name: agenda_slots_regras_tenant_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agenda_slots_regras_tenant_owner_idx ON public.agenda_slots_regras USING btree (tenant_id, owner_id); -- -- Name: agendador_cfg_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agendador_cfg_tenant_idx ON public.agendador_configuracoes USING btree (tenant_id); -- -- Name: agendador_sol_data_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agendador_sol_data_idx ON public.agendador_solicitacoes USING btree (data_solicitada, hora_solicitada); -- -- Name: agendador_sol_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agendador_sol_owner_idx ON public.agendador_solicitacoes USING btree (owner_id, status); -- -- Name: agendador_sol_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX agendador_sol_tenant_idx ON public.agendador_solicitacoes USING btree (tenant_id); -- -- Name: billing_contracts_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX billing_contracts_owner_idx ON public.billing_contracts USING btree (owner_id); -- -- Name: billing_contracts_patient_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX billing_contracts_patient_idx ON public.billing_contracts USING btree (patient_id); -- -- Name: billing_contracts_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX billing_contracts_tenant_idx ON public.billing_contracts USING btree (tenant_id); -- -- Name: commitment_services_commitment_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX commitment_services_commitment_idx ON public.commitment_services USING btree (commitment_id); -- -- Name: commitment_services_service_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX commitment_services_service_idx ON public.commitment_services USING btree (service_id); -- -- Name: commitment_time_logs_calendar_event_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX commitment_time_logs_calendar_event_idx ON public.commitment_time_logs USING btree (calendar_event_id); -- -- Name: commitment_time_logs_commitment_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX commitment_time_logs_commitment_idx ON public.commitment_time_logs USING btree (commitment_id, created_at DESC); -- -- Name: commitment_time_logs_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX commitment_time_logs_tenant_idx ON public.commitment_time_logs USING btree (tenant_id, created_at DESC); -- -- Name: determined_commitment_fields_commitment_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX determined_commitment_fields_commitment_idx ON public.determined_commitment_fields USING btree (commitment_id, sort_order); -- -- Name: determined_commitment_fields_key_uniq; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX determined_commitment_fields_key_uniq ON public.determined_commitment_fields USING btree (commitment_id, key); -- -- Name: determined_commitment_fields_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX determined_commitment_fields_tenant_idx ON public.determined_commitment_fields USING btree (tenant_id); -- -- Name: determined_commitments_active_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX determined_commitments_active_idx ON public.determined_commitments USING btree (tenant_id, active); -- -- Name: determined_commitments_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX determined_commitments_tenant_idx ON public.determined_commitments USING btree (tenant_id); -- -- Name: determined_commitments_tenant_name_uniq; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX determined_commitments_tenant_name_uniq ON public.determined_commitments USING btree (tenant_id, lower(name)); -- -- Name: feriados_global_unique; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX feriados_global_unique ON public.feriados USING btree (data, nome) WHERE (tenant_id IS NULL); -- -- Name: financial_exceptions_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX financial_exceptions_owner_idx ON public.financial_exceptions USING btree (owner_id); -- -- Name: financial_exceptions_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX financial_exceptions_tenant_idx ON public.financial_exceptions USING btree (tenant_id); -- -- Name: idx_addon_credits_tenant; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_addon_credits_tenant ON public.addon_credits USING btree (tenant_id) WHERE (is_active = true); -- -- Name: idx_addon_credits_type; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_addon_credits_type ON public.addon_credits USING btree (addon_type) WHERE (is_active = true); -- -- Name: idx_addon_products_active; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_addon_products_active ON public.addon_products USING btree (is_active, is_visible) WHERE (deleted_at IS NULL); -- -- Name: idx_addon_products_type; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_addon_products_type ON public.addon_products USING btree (addon_type) WHERE (deleted_at IS NULL); -- -- Name: idx_addon_tx_created; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_addon_tx_created ON public.addon_transactions USING btree (created_at DESC); -- -- Name: idx_addon_tx_queue; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_addon_tx_queue ON public.addon_transactions USING btree (queue_id) WHERE (queue_id IS NOT NULL); -- -- Name: idx_addon_tx_tenant; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_addon_tx_tenant ON public.addon_transactions USING btree (tenant_id, addon_type); -- -- Name: idx_addon_tx_type; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_addon_tx_type ON public.addon_transactions USING btree (type); -- -- Name: idx_agenda_eventos_determined_commitment_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_agenda_eventos_determined_commitment_id ON public.agenda_eventos USING btree (determined_commitment_id); -- -- Name: idx_agenda_excecoes_owner_data; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_agenda_excecoes_owner_data ON public.agenda_excecoes USING btree (owner_id, data); -- -- Name: idx_agenda_slots_regras_owner_dia; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_agenda_slots_regras_owner_dia ON public.agenda_slots_regras USING btree (owner_id, dia_semana); -- -- Name: idx_email_templates_global_domain; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_email_templates_global_domain ON public.email_templates_global USING btree (domain) WHERE (is_active = true); -- -- Name: idx_email_templates_global_key; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_email_templates_global_key ON public.email_templates_global USING btree (key) WHERE (is_active = true); -- -- Name: idx_email_templates_tenant_lookup; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_email_templates_tenant_lookup ON public.email_templates_tenant USING btree (tenant_id, template_key) WHERE (enabled = true); -- -- Name: idx_email_templates_tenant_owner; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_email_templates_tenant_owner ON public.email_templates_tenant USING btree (owner_id, template_key) WHERE ((enabled = true) AND (owner_id IS NOT NULL)); -- -- Name: idx_financial_categories_user_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_categories_user_id ON public.financial_categories USING btree (user_id); -- -- Name: idx_financial_records_active; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_records_active ON public.financial_records USING btree (owner_id, paid_at DESC) WHERE (deleted_at IS NULL); -- -- Name: idx_financial_records_agenda_evento_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_records_agenda_evento_id ON public.financial_records USING btree (agenda_evento_id) WHERE (agenda_evento_id IS NOT NULL); -- -- Name: idx_financial_records_category_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_records_category_id ON public.financial_records USING btree (category_id) WHERE (category_id IS NOT NULL); -- -- Name: idx_financial_records_due_date; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_records_due_date ON public.financial_records USING btree (due_date); -- -- Name: idx_financial_records_installment_group; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_records_installment_group ON public.financial_records USING btree (installment_group) WHERE (installment_group IS NOT NULL); -- -- Name: idx_financial_records_owner_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_records_owner_id ON public.financial_records USING btree (owner_id); -- -- Name: idx_financial_records_paid_at; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_records_paid_at ON public.financial_records USING btree (paid_at DESC); -- -- Name: idx_financial_records_patient_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_records_patient_id ON public.financial_records USING btree (patient_id); -- -- Name: idx_financial_records_status; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_records_status ON public.financial_records USING btree (status) WHERE (deleted_at IS NULL); -- -- Name: idx_financial_records_tenant_active; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_records_tenant_active ON public.financial_records USING btree (tenant_id, paid_at DESC) WHERE ((deleted_at IS NULL) AND (tenant_id IS NOT NULL)); -- -- Name: idx_financial_records_tenant_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_records_tenant_id ON public.financial_records USING btree (tenant_id); -- -- Name: idx_financial_records_type_status; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_financial_records_type_status ON public.financial_records USING btree (type, status); -- -- Name: idx_global_notices_active_priority; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_global_notices_active_priority ON public.global_notices USING btree (is_active, priority DESC, starts_at, ends_at); -- -- Name: idx_intakes_converted_patient_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_intakes_converted_patient_id ON public.patient_intake_requests USING btree (converted_patient_id); -- -- Name: idx_intakes_owner_cpf; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_intakes_owner_cpf ON public.patient_intake_requests USING btree (owner_id, cpf); -- -- Name: idx_intakes_owner_created; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_intakes_owner_created ON public.patient_intake_requests USING btree (owner_id, created_at DESC); -- -- Name: idx_intakes_owner_status_created; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_intakes_owner_status_created ON public.patient_intake_requests USING btree (owner_id, status, created_at DESC); -- -- Name: idx_intakes_status_created; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_intakes_status_created ON public.patient_intake_requests USING btree (status, created_at DESC); -- -- Name: idx_notice_dismissals_user; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notice_dismissals_user ON public.notice_dismissals USING btree (user_id, notice_id); -- -- Name: idx_notif_channels_owner_active; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_channels_owner_active ON public.notification_channels USING btree (owner_id, channel) WHERE ((is_active = true) AND (deleted_at IS NULL)); -- -- Name: idx_notif_channels_tenant; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_channels_tenant ON public.notification_channels USING btree (tenant_id) WHERE (deleted_at IS NULL); -- -- Name: idx_notif_logs_owner_date; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_logs_owner_date ON public.notification_logs USING btree (owner_id, created_at DESC); -- -- Name: idx_notif_logs_patient; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_logs_patient ON public.notification_logs USING btree (patient_id, created_at DESC); -- -- Name: idx_notif_logs_provider_msg; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_logs_provider_msg ON public.notification_logs USING btree (provider_message_id) WHERE (provider_message_id IS NOT NULL); -- -- Name: idx_notif_logs_status; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_logs_status ON public.notification_logs USING btree (status, created_at DESC); -- -- Name: idx_notif_logs_tenant_date; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_logs_tenant_date ON public.notification_logs USING btree (tenant_id, created_at DESC); -- -- Name: idx_notif_prefs_owner; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_prefs_owner ON public.notification_preferences USING btree (owner_id) WHERE (deleted_at IS NULL); -- -- Name: idx_notif_prefs_patient; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_prefs_patient ON public.notification_preferences USING btree (patient_id) WHERE (deleted_at IS NULL); -- -- Name: idx_notif_prefs_whatsapp_active; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_prefs_whatsapp_active ON public.notification_preferences USING btree (owner_id, patient_id) WHERE ((whatsapp_opt_in = true) AND (deleted_at IS NULL)); -- -- Name: idx_notif_queue_evento; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_queue_evento ON public.notification_queue USING btree (agenda_evento_id) WHERE (status = ANY (ARRAY['pendente'::text, 'processando'::text])); -- -- Name: idx_notif_queue_patient; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_queue_patient ON public.notification_queue USING btree (patient_id, channel) WHERE (status = 'pendente'::text); -- -- Name: idx_notif_queue_pending; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_queue_pending ON public.notification_queue USING btree (scheduled_at) WHERE (status = 'pendente'::text); -- -- Name: idx_notif_queue_processing; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_queue_processing ON public.notification_queue USING btree (status, updated_at) WHERE (status = 'processando'::text); -- -- Name: idx_notif_queue_retry; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_queue_retry ON public.notification_queue USING btree (next_retry_at) WHERE ((status = 'pendente'::text) AND (attempts > 0)); -- -- Name: idx_notif_queue_tenant; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_queue_tenant ON public.notification_queue USING btree (tenant_id, created_at DESC); -- -- Name: idx_notif_schedules_owner_active; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_schedules_owner_active ON public.notification_schedules USING btree (owner_id, event_type) WHERE ((is_active = true) AND (deleted_at IS NULL)); -- -- Name: idx_notif_templates_default; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_templates_default ON public.notification_templates USING btree (channel, event_type) WHERE ((is_default = true) AND (deleted_at IS NULL) AND (tenant_id IS NULL)); -- -- Name: idx_notif_templates_lookup; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_templates_lookup ON public.notification_templates USING btree (channel, event_type, is_active) WHERE (deleted_at IS NULL); -- -- Name: idx_notif_templates_tenant; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_notif_templates_tenant ON public.notification_templates USING btree (tenant_id, channel, event_type) WHERE ((deleted_at IS NULL) AND (is_active = true)); -- -- Name: idx_patient_group_patient_group_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patient_group_patient_group_id ON public.patient_group_patient USING btree (patient_group_id); -- -- Name: idx_patient_groups_owner; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patient_groups_owner ON public.patient_groups USING btree (owner_id); -- -- Name: idx_patient_groups_owner_system_nome; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patient_groups_owner_system_nome ON public.patient_groups USING btree (owner_id, is_system, nome); -- -- Name: idx_patient_tags_owner; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patient_tags_owner ON public.patient_tags USING btree (owner_id); -- -- Name: idx_patients_created_at; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patients_created_at ON public.patients USING btree (created_at DESC); -- -- Name: idx_patients_last_attended; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patients_last_attended ON public.patients USING btree (last_attended_at DESC); -- -- Name: idx_patients_owner_email_principal; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patients_owner_email_principal ON public.patients USING btree (owner_id, email_principal); -- -- Name: idx_patients_owner_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patients_owner_id ON public.patients USING btree (owner_id); -- -- Name: idx_patients_owner_nome; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patients_owner_nome ON public.patients USING btree (owner_id, nome_completo); -- -- Name: idx_patients_responsible_member; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patients_responsible_member ON public.patients USING btree (responsible_member_id); -- -- Name: idx_patients_status; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patients_status ON public.patients USING btree (status); -- -- Name: idx_patients_tenant; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patients_tenant ON public.patients USING btree (tenant_id); -- -- Name: idx_patients_tenant_email_norm; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_patients_tenant_email_norm ON public.patients USING btree (tenant_id, lower(TRIM(BOTH FROM email_principal))); -- -- Name: idx_pgp_group; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_pgp_group ON public.patient_group_patient USING btree (patient_group_id); -- -- Name: idx_pgp_patient; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_pgp_patient ON public.patient_group_patient USING btree (patient_id); -- -- Name: idx_ppt_patient; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_ppt_patient ON public.patient_patient_tag USING btree (patient_id); -- -- Name: idx_ppt_tag; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_ppt_tag ON public.patient_patient_tag USING btree (tag_id); -- -- Name: idx_slots_bloq_owner_dia; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_slots_bloq_owner_dia ON public.agenda_slots_bloqueados_semanais USING btree (owner_id, dia_semana); -- -- Name: idx_subscription_intents_plan_interval; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_subscription_intents_plan_interval ON public.subscription_intents_legacy USING btree (plan_key, "interval"); -- -- Name: idx_subscription_intents_status; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_subscription_intents_status ON public.subscription_intents_legacy USING btree (status); -- -- Name: idx_subscription_intents_user_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_subscription_intents_user_id ON public.subscription_intents_legacy USING btree (user_id); -- -- Name: idx_tenant_features_tenant; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_tenant_features_tenant ON public.tenant_features USING btree (tenant_id); -- -- Name: idx_tenant_invites_tenant; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_tenant_invites_tenant ON public.tenant_invites USING btree (tenant_id); -- -- Name: idx_tenant_invites_token; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_tenant_invites_token ON public.tenant_invites USING btree (token); -- -- Name: idx_therapist_payout_records_financial_record_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_therapist_payout_records_financial_record_id ON public.therapist_payout_records USING btree (financial_record_id); -- -- Name: idx_therapist_payouts_owner_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_therapist_payouts_owner_id ON public.therapist_payouts USING btree (owner_id); -- -- Name: idx_therapist_payouts_period; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_therapist_payouts_period ON public.therapist_payouts USING btree (period_start, period_end); -- -- Name: idx_therapist_payouts_status; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_therapist_payouts_status ON public.therapist_payouts USING btree (status) WHERE (status = 'pending'::text); -- -- Name: idx_therapist_payouts_tenant_id; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX idx_therapist_payouts_tenant_id ON public.therapist_payouts USING btree (tenant_id); -- -- Name: insurance_plans_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX insurance_plans_owner_idx ON public.insurance_plans USING btree (owner_id); -- -- Name: insurance_plans_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX insurance_plans_tenant_idx ON public.insurance_plans USING btree (tenant_id); -- -- Name: ix_plan_prices_plan; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX ix_plan_prices_plan ON public.plan_prices USING btree (plan_id); -- -- Name: ix_plan_public_bullets_plan; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX ix_plan_public_bullets_plan ON public.plan_public_bullets USING btree (plan_id); -- -- Name: ix_plan_public_sort; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX ix_plan_public_sort ON public.plan_public USING btree (sort_order); -- -- Name: notifications_owner_created; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX notifications_owner_created ON public.notifications USING btree (owner_id, created_at DESC); -- -- Name: notifications_owner_unread; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX notifications_owner_unread ON public.notifications USING btree (owner_id, read_at) WHERE (read_at IS NULL); -- -- Name: patient_discounts_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_discounts_owner_idx ON public.patient_discounts USING btree (owner_id); -- -- Name: patient_discounts_patient_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_discounts_patient_idx ON public.patient_discounts USING btree (patient_id); -- -- Name: patient_discounts_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_discounts_tenant_idx ON public.patient_discounts USING btree (tenant_id); -- -- Name: patient_group_patient_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_group_patient_tenant_idx ON public.patient_group_patient USING btree (tenant_id); -- -- Name: patient_groups_owner_nome_uniq; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX patient_groups_owner_nome_uniq ON public.patient_groups USING btree (owner_id, nome); -- -- Name: patient_groups_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_groups_tenant_idx ON public.patient_groups USING btree (tenant_id); -- -- Name: patient_intake_owner_id_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_intake_owner_id_idx ON public.patient_intake_requests USING btree (owner_id); -- -- Name: patient_intake_requests_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_intake_requests_tenant_idx ON public.patient_intake_requests USING btree (tenant_id); -- -- Name: patient_intake_status_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_intake_status_idx ON public.patient_intake_requests USING btree (status); -- -- Name: patient_intake_token_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_intake_token_idx ON public.patient_intake_requests USING btree (token); -- -- Name: patient_invites_one_active_per_owner; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX patient_invites_one_active_per_owner ON public.patient_invites USING btree (owner_id) WHERE (active = true); -- -- Name: patient_invites_owner_id_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_invites_owner_id_idx ON public.patient_invites USING btree (owner_id); -- -- Name: patient_invites_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_invites_tenant_idx ON public.patient_invites USING btree (tenant_id); -- -- Name: patient_invites_token_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_invites_token_idx ON public.patient_invites USING btree (token); -- -- Name: patient_patient_tag_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_patient_tag_tenant_idx ON public.patient_patient_tag USING btree (tenant_id); -- -- Name: patient_tags_owner_name_uq; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX patient_tags_owner_name_uq ON public.patient_tags USING btree (owner_id, lower(nome)); -- -- Name: patient_tags_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX patient_tags_tenant_idx ON public.patient_tags USING btree (tenant_id); -- -- Name: payment_settings_tenant_id_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX payment_settings_tenant_id_idx ON public.payment_settings USING btree (tenant_id); -- -- Name: ppt_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX ppt_owner_idx ON public.patient_patient_tag USING btree (owner_id); -- -- Name: ppt_patient_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX ppt_patient_idx ON public.patient_patient_tag USING btree (patient_id); -- -- Name: ppt_tag_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX ppt_tag_idx ON public.patient_patient_tag USING btree (tag_id); -- -- Name: professional_pricing_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX professional_pricing_tenant_idx ON public.professional_pricing USING btree (tenant_id); -- -- Name: profiles_work_description_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX profiles_work_description_idx ON public.profiles USING btree (work_description) WHERE (work_description IS NOT NULL); -- -- Name: recurrence_exceptions_rule_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX recurrence_exceptions_rule_idx ON public.recurrence_exceptions USING btree (recurrence_id); -- -- Name: recurrence_exceptions_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX recurrence_exceptions_tenant_idx ON public.recurrence_exceptions USING btree (tenant_id); -- -- Name: recurrence_rule_services_rule_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX recurrence_rule_services_rule_idx ON public.recurrence_rule_services USING btree (rule_id); -- -- Name: recurrence_rule_services_service_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX recurrence_rule_services_service_idx ON public.recurrence_rule_services USING btree (service_id); -- -- Name: recurrence_rules_active_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX recurrence_rules_active_idx ON public.recurrence_rules USING btree (owner_id, status) WHERE (status = 'ativo'::text); -- -- Name: recurrence_rules_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX recurrence_rules_owner_idx ON public.recurrence_rules USING btree (owner_id); -- -- Name: recurrence_rules_patient_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX recurrence_rules_patient_idx ON public.recurrence_rules USING btree (patient_id); -- -- Name: recurrence_rules_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX recurrence_rules_tenant_idx ON public.recurrence_rules USING btree (tenant_id); -- -- Name: saas_doc_votos_doc_id_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_doc_votos_doc_id_idx ON public.saas_doc_votos USING btree (doc_id); -- -- Name: saas_doc_votos_user_id_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_doc_votos_user_id_idx ON public.saas_doc_votos USING btree (user_id); -- -- Name: saas_docs_categoria_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_docs_categoria_idx ON public.saas_docs USING btree (categoria); -- -- Name: saas_docs_exibir_no_faq_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_docs_exibir_no_faq_idx ON public.saas_docs USING btree (exibir_no_faq) WHERE (exibir_no_faq = true); -- -- Name: saas_docs_path_ativo_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_docs_path_ativo_idx ON public.saas_docs USING btree (pagina_path, ativo); -- -- Name: saas_faq_ativo_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_faq_ativo_idx ON public.saas_faq USING btree (ativo); -- -- Name: saas_faq_categoria_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_faq_categoria_idx ON public.saas_faq USING btree (categoria); -- -- Name: saas_faq_fts_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_faq_fts_idx ON public.saas_faq USING gin (to_tsvector('portuguese'::regconfig, ((COALESCE(pergunta, ''::text) || ' '::text) || COALESCE(conteudo, ''::text)))); -- -- Name: saas_faq_itens_ativo_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_faq_itens_ativo_idx ON public.saas_faq_itens USING btree (ativo); -- -- Name: saas_faq_itens_doc_id_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_faq_itens_doc_id_idx ON public.saas_faq_itens USING btree (doc_id); -- -- Name: saas_faq_pagina_path_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_faq_pagina_path_idx ON public.saas_faq USING btree (pagina_path); -- -- Name: saas_faq_publico_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_faq_publico_idx ON public.saas_faq USING btree (publico); -- -- Name: saas_faq_votos_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX saas_faq_votos_idx ON public.saas_faq USING btree (votos DESC); -- -- Name: services_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX services_owner_idx ON public.services USING btree (owner_id); -- -- Name: services_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX services_tenant_idx ON public.services USING btree (tenant_id); -- -- Name: sint_personal_created_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX sint_personal_created_idx ON public.subscription_intents_personal USING btree (created_at DESC); -- -- Name: sint_personal_status_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX sint_personal_status_idx ON public.subscription_intents_personal USING btree (status); -- -- Name: sint_tenant_created_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX sint_tenant_created_idx ON public.subscription_intents_tenant USING btree (created_at DESC); -- -- Name: sint_tenant_status_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX sint_tenant_status_idx ON public.subscription_intents_tenant USING btree (status); -- -- Name: sint_tenant_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX sint_tenant_tenant_idx ON public.subscription_intents_tenant USING btree (tenant_id); -- -- Name: subscription_events_created_at_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX subscription_events_created_at_idx ON public.subscription_events USING btree (created_at DESC); -- -- Name: subscription_events_owner_ref_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX subscription_events_owner_ref_idx ON public.subscription_events USING btree (owner_type, owner_ref); -- -- Name: subscription_events_sub_created_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX subscription_events_sub_created_idx ON public.subscription_events USING btree (subscription_id, created_at DESC); -- -- Name: subscription_events_subscription_id_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX subscription_events_subscription_id_idx ON public.subscription_events USING btree (subscription_id); -- -- Name: subscriptions_one_active_per_tenant; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX subscriptions_one_active_per_tenant ON public.subscriptions USING btree (tenant_id) WHERE (status = 'active'::text); -- -- Name: subscriptions_one_active_per_user; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX subscriptions_one_active_per_user ON public.subscriptions USING btree (user_id) WHERE (status = 'active'::text); -- -- Name: subscriptions_one_active_per_user_personal; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX subscriptions_one_active_per_user_personal ON public.subscriptions USING btree (user_id) WHERE ((tenant_id IS NULL) AND (status = 'active'::text)); -- -- Name: subscriptions_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX subscriptions_owner_idx ON public.subscriptions USING btree (user_id); -- -- Name: subscriptions_plan_key_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX subscriptions_plan_key_idx ON public.subscriptions USING btree (plan_key); -- -- Name: subscriptions_status_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX subscriptions_status_idx ON public.subscriptions USING btree (status); -- -- Name: subscriptions_tenant_id_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX subscriptions_tenant_id_idx ON public.subscriptions USING btree (tenant_id); -- -- Name: subscriptions_tenant_period_end_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX subscriptions_tenant_period_end_idx ON public.subscriptions USING btree (tenant_id, current_period_end); -- -- Name: subscriptions_tenant_status_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX subscriptions_tenant_status_idx ON public.subscriptions USING btree (tenant_id, status); -- -- Name: subscriptions_user_status_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX subscriptions_user_status_idx ON public.subscriptions USING btree (user_id, status, created_at DESC); -- -- Name: support_sessions_expires_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX support_sessions_expires_idx ON public.support_sessions USING btree (expires_at); -- -- Name: support_sessions_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX support_sessions_tenant_idx ON public.support_sessions USING btree (tenant_id); -- -- Name: support_sessions_token_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX support_sessions_token_idx ON public.support_sessions USING btree (token); -- -- Name: tenant_members_tenant_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX tenant_members_tenant_idx ON public.tenant_members USING btree (tenant_id); -- -- Name: tenant_members_user_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX tenant_members_user_idx ON public.tenant_members USING btree (user_id); -- -- Name: tenant_modules_owner_idx; Type: INDEX; Schema: public; Owner: - -- CREATE INDEX tenant_modules_owner_idx ON public.tenant_modules USING btree (owner_id); -- -- Name: unique_member_per_tenant; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX unique_member_per_tenant ON public.tenant_members USING btree (tenant_id, user_id); -- -- Name: uq_patients_tenant_user; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX uq_patients_tenant_user ON public.patients USING btree (tenant_id, user_id) WHERE (user_id IS NOT NULL); -- -- Name: uq_plan_price_active; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX uq_plan_price_active ON public.plan_prices USING btree (plan_id, "interval", currency) WHERE ((is_active = true) AND (active_to IS NULL)); -- -- Name: uq_plan_prices_active; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX uq_plan_prices_active ON public.plan_prices USING btree (plan_id, "interval") WHERE (is_active = true); -- -- Name: uq_subscriptions_active_by_tenant; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX uq_subscriptions_active_by_tenant ON public.subscriptions USING btree (tenant_id) WHERE ((tenant_id IS NOT NULL) AND (status = 'active'::text)); -- -- Name: uq_subscriptions_active_personal_by_user; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX uq_subscriptions_active_personal_by_user ON public.subscriptions USING btree (user_id) WHERE ((tenant_id IS NULL) AND (status = 'active'::text)); -- -- Name: uq_tenant_invites_pending; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX uq_tenant_invites_pending ON public.tenant_invites USING btree (tenant_id, lower(email), role) WHERE ((accepted_at IS NULL) AND (revoked_at IS NULL)); -- -- Name: uq_tenant_members_tenant_user; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX uq_tenant_members_tenant_user ON public.tenant_members USING btree (tenant_id, user_id); -- -- Name: ux_subscriptions_active_per_personal_user; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX ux_subscriptions_active_per_personal_user ON public.subscriptions USING btree (user_id) WHERE ((status = 'active'::text) AND (tenant_id IS NULL)); -- -- Name: ux_subscriptions_active_per_tenant; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX ux_subscriptions_active_per_tenant ON public.subscriptions USING btree (tenant_id) WHERE ((status = 'active'::text) AND (tenant_id IS NOT NULL)); -- -- Name: ix_realtime_subscription_entity; Type: INDEX; Schema: realtime; Owner: - -- CREATE INDEX ix_realtime_subscription_entity ON realtime.subscription USING btree (entity); -- -- Name: messages_inserted_at_topic_index; Type: INDEX; Schema: realtime; Owner: - -- CREATE INDEX messages_inserted_at_topic_index ON ONLY realtime.messages USING btree (inserted_at DESC, topic) WHERE ((extension = 'broadcast'::text) AND (private IS TRUE)); -- -- Name: messages_2026_03_20_inserted_at_topic_idx; Type: INDEX; Schema: realtime; Owner: - -- CREATE INDEX messages_2026_03_20_inserted_at_topic_idx ON realtime.messages_2026_03_20 USING btree (inserted_at DESC, topic) WHERE ((extension = 'broadcast'::text) AND (private IS TRUE)); -- -- Name: messages_2026_03_21_inserted_at_topic_idx; Type: INDEX; Schema: realtime; Owner: - -- CREATE INDEX messages_2026_03_21_inserted_at_topic_idx ON realtime.messages_2026_03_21 USING btree (inserted_at DESC, topic) WHERE ((extension = 'broadcast'::text) AND (private IS TRUE)); -- -- Name: messages_2026_03_22_inserted_at_topic_idx; Type: INDEX; Schema: realtime; Owner: - -- CREATE INDEX messages_2026_03_22_inserted_at_topic_idx ON realtime.messages_2026_03_22 USING btree (inserted_at DESC, topic) WHERE ((extension = 'broadcast'::text) AND (private IS TRUE)); -- -- Name: messages_2026_03_23_inserted_at_topic_idx; Type: INDEX; Schema: realtime; Owner: - -- CREATE INDEX messages_2026_03_23_inserted_at_topic_idx ON realtime.messages_2026_03_23 USING btree (inserted_at DESC, topic) WHERE ((extension = 'broadcast'::text) AND (private IS TRUE)); -- -- Name: messages_2026_03_24_inserted_at_topic_idx; Type: INDEX; Schema: realtime; Owner: - -- CREATE INDEX messages_2026_03_24_inserted_at_topic_idx ON realtime.messages_2026_03_24 USING btree (inserted_at DESC, topic) WHERE ((extension = 'broadcast'::text) AND (private IS TRUE)); -- -- Name: messages_2026_03_25_inserted_at_topic_idx; Type: INDEX; Schema: realtime; Owner: - -- CREATE INDEX messages_2026_03_25_inserted_at_topic_idx ON realtime.messages_2026_03_25 USING btree (inserted_at DESC, topic) WHERE ((extension = 'broadcast'::text) AND (private IS TRUE)); -- -- Name: messages_2026_03_26_inserted_at_topic_idx; Type: INDEX; Schema: realtime; Owner: - -- CREATE INDEX messages_2026_03_26_inserted_at_topic_idx ON realtime.messages_2026_03_26 USING btree (inserted_at DESC, topic) WHERE ((extension = 'broadcast'::text) AND (private IS TRUE)); -- -- Name: subscription_subscription_id_entity_filters_key; Type: INDEX; Schema: realtime; Owner: - -- CREATE UNIQUE INDEX subscription_subscription_id_entity_filters_key ON realtime.subscription USING btree (subscription_id, entity, filters); -- -- Name: bname; Type: INDEX; Schema: storage; Owner: - -- CREATE UNIQUE INDEX bname ON storage.buckets USING btree (name); -- -- Name: bucketid_objname; Type: INDEX; Schema: storage; Owner: - -- CREATE UNIQUE INDEX bucketid_objname ON storage.objects USING btree (bucket_id, name); -- -- Name: buckets_analytics_unique_name_idx; Type: INDEX; Schema: storage; Owner: - -- CREATE UNIQUE INDEX buckets_analytics_unique_name_idx ON storage.buckets_analytics USING btree (name) WHERE (deleted_at IS NULL); -- -- Name: idx_iceberg_namespaces_bucket_id; Type: INDEX; Schema: storage; Owner: - -- CREATE UNIQUE INDEX idx_iceberg_namespaces_bucket_id ON storage.iceberg_namespaces USING btree (catalog_id, name); -- -- Name: idx_iceberg_tables_location; Type: INDEX; Schema: storage; Owner: - -- CREATE UNIQUE INDEX idx_iceberg_tables_location ON storage.iceberg_tables USING btree (location); -- -- Name: idx_iceberg_tables_namespace_id; Type: INDEX; Schema: storage; Owner: - -- CREATE UNIQUE INDEX idx_iceberg_tables_namespace_id ON storage.iceberg_tables USING btree (catalog_id, namespace_id, name); -- -- Name: idx_multipart_uploads_list; Type: INDEX; Schema: storage; Owner: - -- CREATE INDEX idx_multipart_uploads_list ON storage.s3_multipart_uploads USING btree (bucket_id, key, created_at); -- -- Name: idx_objects_bucket_id_name; Type: INDEX; Schema: storage; Owner: - -- CREATE INDEX idx_objects_bucket_id_name ON storage.objects USING btree (bucket_id, name COLLATE "C"); -- -- Name: idx_objects_bucket_id_name_lower; Type: INDEX; Schema: storage; Owner: - -- CREATE INDEX idx_objects_bucket_id_name_lower ON storage.objects USING btree (bucket_id, lower(name) COLLATE "C"); -- -- Name: name_prefix_search; Type: INDEX; Schema: storage; Owner: - -- CREATE INDEX name_prefix_search ON storage.objects USING btree (name text_pattern_ops); -- -- Name: vector_indexes_name_bucket_id_idx; Type: INDEX; Schema: storage; Owner: - -- CREATE UNIQUE INDEX vector_indexes_name_bucket_id_idx ON storage.vector_indexes USING btree (name, bucket_id); -- -- Name: supabase_functions_hooks_h_table_id_h_name_idx; Type: INDEX; Schema: supabase_functions; Owner: - -- CREATE INDEX supabase_functions_hooks_h_table_id_h_name_idx ON supabase_functions.hooks USING btree (hook_table_id, hook_name); -- -- Name: supabase_functions_hooks_request_id_idx; Type: INDEX; Schema: supabase_functions; Owner: - -- CREATE INDEX supabase_functions_hooks_request_id_idx ON supabase_functions.hooks USING btree (request_id); -- -- Name: messages_2026_03_20_inserted_at_topic_idx; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_inserted_at_topic_index ATTACH PARTITION realtime.messages_2026_03_20_inserted_at_topic_idx; -- -- Name: messages_2026_03_20_pkey; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_pkey ATTACH PARTITION realtime.messages_2026_03_20_pkey; -- -- Name: messages_2026_03_21_inserted_at_topic_idx; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_inserted_at_topic_index ATTACH PARTITION realtime.messages_2026_03_21_inserted_at_topic_idx; -- -- Name: messages_2026_03_21_pkey; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_pkey ATTACH PARTITION realtime.messages_2026_03_21_pkey; -- -- Name: messages_2026_03_22_inserted_at_topic_idx; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_inserted_at_topic_index ATTACH PARTITION realtime.messages_2026_03_22_inserted_at_topic_idx; -- -- Name: messages_2026_03_22_pkey; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_pkey ATTACH PARTITION realtime.messages_2026_03_22_pkey; -- -- Name: messages_2026_03_23_inserted_at_topic_idx; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_inserted_at_topic_index ATTACH PARTITION realtime.messages_2026_03_23_inserted_at_topic_idx; -- -- Name: messages_2026_03_23_pkey; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_pkey ATTACH PARTITION realtime.messages_2026_03_23_pkey; -- -- Name: messages_2026_03_24_inserted_at_topic_idx; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_inserted_at_topic_index ATTACH PARTITION realtime.messages_2026_03_24_inserted_at_topic_idx; -- -- Name: messages_2026_03_24_pkey; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_pkey ATTACH PARTITION realtime.messages_2026_03_24_pkey; -- -- Name: messages_2026_03_25_inserted_at_topic_idx; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_inserted_at_topic_index ATTACH PARTITION realtime.messages_2026_03_25_inserted_at_topic_idx; -- -- Name: messages_2026_03_25_pkey; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_pkey ATTACH PARTITION realtime.messages_2026_03_25_pkey; -- -- Name: messages_2026_03_26_inserted_at_topic_idx; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_inserted_at_topic_index ATTACH PARTITION realtime.messages_2026_03_26_inserted_at_topic_idx; -- -- Name: messages_2026_03_26_pkey; Type: INDEX ATTACH; Schema: realtime; Owner: - -- ALTER INDEX realtime.messages_pkey ATTACH PARTITION realtime.messages_2026_03_26_pkey; -- -- Name: users on_auth_user_created; Type: TRIGGER; Schema: auth; Owner: - -- CREATE TRIGGER on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION public.handle_new_user(); -- -- Name: users trg_seed_patient_groups; Type: TRIGGER; Schema: auth; Owner: - -- CREATE TRIGGER trg_seed_patient_groups AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION public.on_new_user_seed_patient_groups(); -- -- Name: agenda_bloqueios agenda_bloqueios_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER agenda_bloqueios_updated_at BEFORE UPDATE ON public.agenda_bloqueios FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: agendador_configuracoes agendador_slug_trigger; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER agendador_slug_trigger BEFORE INSERT OR UPDATE ON public.agendador_configuracoes FOR EACH ROW EXECUTE FUNCTION public.agendador_gerar_slug(); -- -- Name: tenant_members prevent_saas_membership_trigger; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER prevent_saas_membership_trigger BEFORE INSERT ON public.tenant_members FOR EACH ROW EXECUTE FUNCTION public.prevent_saas_membership(); -- -- Name: insurance_plan_services set_insurance_plan_services_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER set_insurance_plan_services_updated_at BEFORE UPDATE ON public.insurance_plan_services FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: user_settings t_user_settings_set_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER t_user_settings_set_updated_at BEFORE UPDATE ON public.user_settings FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: agenda_configuracoes tg_agenda_configuracoes_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER tg_agenda_configuracoes_updated_at BEFORE UPDATE ON public.agenda_configuracoes FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: agenda_eventos tg_agenda_eventos_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER tg_agenda_eventos_updated_at BEFORE UPDATE ON public.agenda_eventos FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: agenda_excecoes tg_agenda_excecoes_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER tg_agenda_excecoes_updated_at BEFORE UPDATE ON public.agenda_excecoes FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: agenda_regras_semanais tg_agenda_regras_semanais_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER tg_agenda_regras_semanais_updated_at BEFORE UPDATE ON public.agenda_regras_semanais FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: recurrence_rules tg_recurrence_rules_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER tg_recurrence_rules_updated_at BEFORE UPDATE ON public.recurrence_rules FOR EACH ROW EXECUTE FUNCTION public.set_updated_at_recurrence(); -- -- Name: plan_public tr_plan_public_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER tr_plan_public_updated_at BEFORE UPDATE ON public.plan_public FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: profiles trg_account_type_immutable; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_account_type_immutable BEFORE UPDATE OF account_type ON public.profiles FOR EACH ROW EXECUTE FUNCTION public.guard_account_type_immutable(); -- -- Name: agenda_configuracoes trg_agenda_cfg_sync; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_agenda_cfg_sync BEFORE INSERT OR UPDATE ON public.agenda_configuracoes FOR EACH ROW EXECUTE FUNCTION public.agenda_cfg_sync(); -- -- Name: agenda_eventos trg_agenda_eventos_busy_mirror_del; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_agenda_eventos_busy_mirror_del AFTER DELETE ON public.agenda_eventos FOR EACH ROW WHEN (((old.mirror_of_event_id IS NULL) AND (old.tenant_id = old.owner_id))) EXECUTE FUNCTION public.sync_busy_mirror_agenda_eventos(); -- -- Name: agenda_eventos trg_agenda_eventos_busy_mirror_ins; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_agenda_eventos_busy_mirror_ins AFTER INSERT ON public.agenda_eventos FOR EACH ROW WHEN (((new.mirror_of_event_id IS NULL) AND (new.tenant_id = new.owner_id) AND (new.visibility_scope = ANY (ARRAY['busy_only'::text, 'private'::text])))) EXECUTE FUNCTION public.sync_busy_mirror_agenda_eventos(); -- -- Name: agenda_eventos trg_agenda_eventos_busy_mirror_upd; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_agenda_eventos_busy_mirror_upd AFTER UPDATE ON public.agenda_eventos FOR EACH ROW WHEN (((new.mirror_of_event_id IS NULL) AND (new.tenant_id = new.owner_id) AND ((new.visibility_scope IS DISTINCT FROM old.visibility_scope) OR (new.inicio_em IS DISTINCT FROM old.inicio_em) OR (new.fim_em IS DISTINCT FROM old.fim_em) OR (new.owner_id IS DISTINCT FROM old.owner_id) OR (new.tenant_id IS DISTINCT FROM old.tenant_id)))) EXECUTE FUNCTION public.sync_busy_mirror_agenda_eventos(); -- -- Name: agenda_regras_semanais trg_agenda_regras_semanais_no_overlap; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_agenda_regras_semanais_no_overlap BEFORE INSERT OR UPDATE ON public.agenda_regras_semanais FOR EACH ROW EXECUTE FUNCTION public.fn_agenda_regras_semanais_no_overlap(); -- -- Name: agenda_eventos trg_auto_financial_from_session; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_auto_financial_from_session AFTER UPDATE OF status ON public.agenda_eventos FOR EACH ROW EXECUTE FUNCTION public.auto_create_financial_record_from_session(); -- -- Name: notification_preferences trg_cancel_notifs_on_opt_out; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_cancel_notifs_on_opt_out AFTER UPDATE ON public.notification_preferences FOR EACH ROW EXECUTE FUNCTION public.cancel_notifications_on_opt_out(); -- -- Name: agenda_eventos trg_cancel_notifs_on_session_cancel; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_cancel_notifs_on_session_cancel AFTER UPDATE ON public.agenda_eventos FOR EACH ROW WHEN ((new.status IS DISTINCT FROM old.status)) EXECUTE FUNCTION public.cancel_notifications_on_session_cancel(); -- -- Name: company_profiles trg_company_profiles_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_company_profiles_updated_at BEFORE UPDATE ON public.company_profiles FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: determined_commitment_fields trg_determined_commitment_fields_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_determined_commitment_fields_updated_at BEFORE UPDATE ON public.determined_commitment_fields FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: determined_commitments trg_determined_commitments_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_determined_commitments_updated_at BEFORE UPDATE ON public.determined_commitments FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: email_layout_config trg_email_layout_config_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_email_layout_config_updated_at BEFORE UPDATE ON public.email_layout_config FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: email_templates_global trg_email_templates_global_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_email_templates_global_updated_at BEFORE UPDATE ON public.email_templates_global FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: email_templates_tenant trg_email_templates_tenant_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_email_templates_tenant_updated_at BEFORE UPDATE ON public.email_templates_tenant FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: financial_exceptions trg_financial_exceptions_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_financial_exceptions_updated_at BEFORE UPDATE ON public.financial_exceptions FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: financial_records trg_financial_records_auto_overdue; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_financial_records_auto_overdue BEFORE UPDATE ON public.financial_records FOR EACH ROW EXECUTE FUNCTION public.trg_fn_financial_records_auto_overdue(); -- -- Name: financial_records trg_financial_records_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_financial_records_updated_at BEFORE UPDATE ON public.financial_records FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: global_notices trg_global_notices_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_global_notices_updated_at BEFORE UPDATE ON public.global_notices FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: insurance_plans trg_insurance_plans_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_insurance_plans_updated_at BEFORE UPDATE ON public.insurance_plans FOR EACH ROW EXECUTE FUNCTION public.set_insurance_plans_updated_at(); -- -- Name: plans trg_no_change_core_plan_key; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_no_change_core_plan_key BEFORE UPDATE ON public.plans FOR EACH ROW EXECUTE FUNCTION public.guard_no_change_core_plan_key(); -- -- Name: plans trg_no_change_plan_target; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_no_change_plan_target BEFORE UPDATE ON public.plans FOR EACH ROW EXECUTE FUNCTION public.guard_no_change_plan_target(); -- -- Name: plans trg_no_delete_core_plans; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_no_delete_core_plans BEFORE DELETE ON public.plans FOR EACH ROW EXECUTE FUNCTION public.guard_no_delete_core_plans(); -- -- Name: notification_channels trg_notification_channels_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_notification_channels_updated_at BEFORE UPDATE ON public.notification_channels FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: notification_logs trg_notification_logs_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_notification_logs_updated_at BEFORE UPDATE ON public.notification_logs FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: notification_preferences trg_notification_preferences_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_notification_preferences_updated_at BEFORE UPDATE ON public.notification_preferences FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: notification_queue trg_notification_queue_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_notification_queue_updated_at BEFORE UPDATE ON public.notification_queue FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: notification_schedules trg_notification_schedules_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_notification_schedules_updated_at BEFORE UPDATE ON public.notification_schedules FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: notification_templates trg_notification_templates_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_notification_templates_updated_at BEFORE UPDATE ON public.notification_templates FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: patient_intake_requests trg_notify_on_intake; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_notify_on_intake AFTER INSERT ON public.patient_intake_requests FOR EACH ROW EXECUTE FUNCTION public.notify_on_intake(); -- -- Name: agendador_solicitacoes trg_notify_on_scheduling; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_notify_on_scheduling AFTER INSERT ON public.agendador_solicitacoes FOR EACH ROW EXECUTE FUNCTION public.notify_on_scheduling(); -- -- Name: agenda_eventos trg_notify_on_session_status; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_notify_on_session_status AFTER UPDATE OF status ON public.agenda_eventos FOR EACH ROW EXECUTE FUNCTION public.notify_on_session_status(); -- -- Name: tenant_members trg_patient_cannot_own_tenant; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_patient_cannot_own_tenant BEFORE INSERT OR UPDATE ON public.tenant_members FOR EACH ROW EXECUTE FUNCTION public.guard_patient_cannot_own_tenant(); -- -- Name: patient_groups trg_patient_groups_set_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_patient_groups_set_updated_at BEFORE UPDATE ON public.patient_groups FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: patient_intake_requests trg_patient_intake_requests_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_patient_intake_requests_updated_at BEFORE UPDATE ON public.patient_intake_requests FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: patient_tags trg_patient_tags_set_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_patient_tags_set_updated_at BEFORE UPDATE ON public.patient_tags FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: patients trg_patients_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_patients_updated_at BEFORE UPDATE ON public.patients FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: patients trg_patients_validate_members; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_patients_validate_members BEFORE INSERT OR UPDATE OF tenant_id, responsible_member_id, patient_scope, therapist_member_id ON public.patients FOR EACH ROW EXECUTE FUNCTION public.patients_validate_member_consistency(); -- -- Name: payment_settings trg_payment_settings_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_payment_settings_updated_at BEFORE UPDATE ON public.payment_settings FOR EACH ROW EXECUTE FUNCTION public.update_payment_settings_updated_at(); -- -- Name: patient_groups trg_prevent_promoting_to_system; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_prevent_promoting_to_system BEFORE UPDATE ON public.patient_groups FOR EACH ROW EXECUTE FUNCTION public.prevent_promoting_to_system(); -- -- Name: patient_groups trg_prevent_system_group_changes; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_prevent_system_group_changes BEFORE DELETE OR UPDATE ON public.patient_groups FOR EACH ROW EXECUTE FUNCTION public.prevent_system_group_changes(); -- -- Name: professional_pricing trg_professional_pricing_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_professional_pricing_updated_at BEFORE UPDATE ON public.professional_pricing FOR EACH ROW EXECUTE FUNCTION public.update_professional_pricing_updated_at(); -- -- Name: profiles trg_profiles_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_profiles_updated_at BEFORE UPDATE ON public.profiles FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: services trg_services_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_services_updated_at BEFORE UPDATE ON public.services FOR EACH ROW EXECUTE FUNCTION public.set_services_updated_at(); -- -- Name: subscription_intents trg_subscription_intents_view_insert; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_subscription_intents_view_insert INSTEAD OF INSERT ON public.subscription_intents FOR EACH ROW EXECUTE FUNCTION public.subscription_intents_view_insert(); -- -- Name: subscriptions trg_subscriptions_validate_scope; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_subscriptions_validate_scope BEFORE INSERT OR UPDATE ON public.subscriptions FOR EACH ROW EXECUTE FUNCTION public.subscriptions_validate_scope(); -- -- Name: tenant_features trg_tenant_features_guard_with_plan; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_tenant_features_guard_with_plan BEFORE INSERT OR UPDATE ON public.tenant_features FOR EACH ROW EXECUTE FUNCTION public.tenant_features_guard_with_plan(); -- -- Name: tenant_features trg_tenant_features_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_tenant_features_updated_at BEFORE UPDATE ON public.tenant_features FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: tenants trg_tenant_kind_immutable; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_tenant_kind_immutable BEFORE UPDATE OF kind ON public.tenants FOR EACH ROW EXECUTE FUNCTION public.guard_tenant_kind_immutable(); -- -- Name: therapist_payouts trg_therapist_payouts_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_therapist_payouts_updated_at BEFORE UPDATE ON public.therapist_payouts FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: user_settings trg_user_settings_updated_at; Type: TRIGGER; Schema: public; Owner: - -- CREATE TRIGGER trg_user_settings_updated_at BEFORE UPDATE ON public.user_settings FOR EACH ROW EXECUTE FUNCTION public.set_updated_at(); -- -- Name: subscription tr_check_filters; Type: TRIGGER; Schema: realtime; Owner: - -- CREATE TRIGGER tr_check_filters BEFORE INSERT OR UPDATE ON realtime.subscription FOR EACH ROW EXECUTE FUNCTION realtime.subscription_check_filters(); -- -- Name: buckets enforce_bucket_name_length_trigger; Type: TRIGGER; Schema: storage; Owner: - -- CREATE TRIGGER enforce_bucket_name_length_trigger BEFORE INSERT OR UPDATE OF name ON storage.buckets FOR EACH ROW EXECUTE FUNCTION storage.enforce_bucket_name_length(); -- -- Name: buckets protect_buckets_delete; Type: TRIGGER; Schema: storage; Owner: - -- CREATE TRIGGER protect_buckets_delete BEFORE DELETE ON storage.buckets FOR EACH STATEMENT EXECUTE FUNCTION storage.protect_delete(); -- -- Name: objects protect_objects_delete; Type: TRIGGER; Schema: storage; Owner: - -- CREATE TRIGGER protect_objects_delete BEFORE DELETE ON storage.objects FOR EACH STATEMENT EXECUTE FUNCTION storage.protect_delete(); -- -- Name: objects update_objects_updated_at; Type: TRIGGER; Schema: storage; Owner: - -- CREATE TRIGGER update_objects_updated_at BEFORE UPDATE ON storage.objects FOR EACH ROW EXECUTE FUNCTION storage.update_updated_at_column(); -- -- Name: extensions extensions_tenant_external_id_fkey; Type: FK CONSTRAINT; Schema: _realtime; Owner: - -- ALTER TABLE ONLY _realtime.extensions ADD CONSTRAINT extensions_tenant_external_id_fkey FOREIGN KEY (tenant_external_id) REFERENCES _realtime.tenants(external_id) ON DELETE CASCADE; -- -- Name: identities identities_user_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.identities ADD CONSTRAINT identities_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: mfa_amr_claims mfa_amr_claims_session_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.mfa_amr_claims ADD CONSTRAINT mfa_amr_claims_session_id_fkey FOREIGN KEY (session_id) REFERENCES auth.sessions(id) ON DELETE CASCADE; -- -- Name: mfa_challenges mfa_challenges_auth_factor_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.mfa_challenges ADD CONSTRAINT mfa_challenges_auth_factor_id_fkey FOREIGN KEY (factor_id) REFERENCES auth.mfa_factors(id) ON DELETE CASCADE; -- -- Name: mfa_factors mfa_factors_user_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.mfa_factors ADD CONSTRAINT mfa_factors_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: oauth_authorizations oauth_authorizations_client_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.oauth_authorizations ADD CONSTRAINT oauth_authorizations_client_id_fkey FOREIGN KEY (client_id) REFERENCES auth.oauth_clients(id) ON DELETE CASCADE; -- -- Name: oauth_authorizations oauth_authorizations_user_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.oauth_authorizations ADD CONSTRAINT oauth_authorizations_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: oauth_consents oauth_consents_client_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.oauth_consents ADD CONSTRAINT oauth_consents_client_id_fkey FOREIGN KEY (client_id) REFERENCES auth.oauth_clients(id) ON DELETE CASCADE; -- -- Name: oauth_consents oauth_consents_user_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.oauth_consents ADD CONSTRAINT oauth_consents_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: one_time_tokens one_time_tokens_user_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.one_time_tokens ADD CONSTRAINT one_time_tokens_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: refresh_tokens refresh_tokens_session_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.refresh_tokens ADD CONSTRAINT refresh_tokens_session_id_fkey FOREIGN KEY (session_id) REFERENCES auth.sessions(id) ON DELETE CASCADE; -- -- Name: saml_providers saml_providers_sso_provider_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.saml_providers ADD CONSTRAINT saml_providers_sso_provider_id_fkey FOREIGN KEY (sso_provider_id) REFERENCES auth.sso_providers(id) ON DELETE CASCADE; -- -- Name: saml_relay_states saml_relay_states_flow_state_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.saml_relay_states ADD CONSTRAINT saml_relay_states_flow_state_id_fkey FOREIGN KEY (flow_state_id) REFERENCES auth.flow_state(id) ON DELETE CASCADE; -- -- Name: saml_relay_states saml_relay_states_sso_provider_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.saml_relay_states ADD CONSTRAINT saml_relay_states_sso_provider_id_fkey FOREIGN KEY (sso_provider_id) REFERENCES auth.sso_providers(id) ON DELETE CASCADE; -- -- Name: sessions sessions_oauth_client_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.sessions ADD CONSTRAINT sessions_oauth_client_id_fkey FOREIGN KEY (oauth_client_id) REFERENCES auth.oauth_clients(id) ON DELETE CASCADE; -- -- Name: sessions sessions_user_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.sessions ADD CONSTRAINT sessions_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: sso_domains sso_domains_sso_provider_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: - -- ALTER TABLE ONLY auth.sso_domains ADD CONSTRAINT sso_domains_sso_provider_id_fkey FOREIGN KEY (sso_provider_id) REFERENCES auth.sso_providers(id) ON DELETE CASCADE; -- -- Name: addon_credits addon_credits_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.addon_credits ADD CONSTRAINT addon_credits_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id); -- -- Name: addon_credits addon_credits_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.addon_credits ADD CONSTRAINT addon_credits_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id); -- -- Name: addon_transactions addon_transactions_admin_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.addon_transactions ADD CONSTRAINT addon_transactions_admin_user_id_fkey FOREIGN KEY (admin_user_id) REFERENCES auth.users(id); -- -- Name: addon_transactions addon_transactions_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.addon_transactions ADD CONSTRAINT addon_transactions_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id); -- -- Name: addon_transactions addon_transactions_product_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.addon_transactions ADD CONSTRAINT addon_transactions_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.addon_products(id); -- -- Name: addon_transactions addon_transactions_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.addon_transactions ADD CONSTRAINT addon_transactions_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id); -- -- Name: agenda_bloqueios agenda_bloqueios_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_bloqueios ADD CONSTRAINT agenda_bloqueios_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: agenda_bloqueios agenda_bloqueios_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_bloqueios ADD CONSTRAINT agenda_bloqueios_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE SET NULL; -- -- Name: agenda_configuracoes agenda_configuracoes_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_configuracoes ADD CONSTRAINT agenda_configuracoes_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: agenda_eventos agenda_eventos_billing_contract_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_eventos ADD CONSTRAINT agenda_eventos_billing_contract_id_fkey FOREIGN KEY (billing_contract_id) REFERENCES public.billing_contracts(id) ON DELETE SET NULL; -- -- Name: agenda_eventos agenda_eventos_determined_commitment_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_eventos ADD CONSTRAINT agenda_eventos_determined_commitment_fk FOREIGN KEY (determined_commitment_id) REFERENCES public.determined_commitments(id) ON DELETE SET NULL; -- -- Name: agenda_eventos agenda_eventos_insurance_plan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_eventos ADD CONSTRAINT agenda_eventos_insurance_plan_id_fkey FOREIGN KEY (insurance_plan_id) REFERENCES public.insurance_plans(id) ON DELETE SET NULL; -- -- Name: agenda_eventos agenda_eventos_insurance_plan_service_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_eventos ADD CONSTRAINT agenda_eventos_insurance_plan_service_id_fkey FOREIGN KEY (insurance_plan_service_id) REFERENCES public.insurance_plan_services(id) ON DELETE SET NULL; -- -- Name: agenda_eventos agenda_eventos_patient_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_eventos ADD CONSTRAINT agenda_eventos_patient_id_fkey FOREIGN KEY (patient_id) REFERENCES public.patients(id) ON DELETE SET NULL; -- -- Name: agenda_eventos agenda_eventos_recurrence_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_eventos ADD CONSTRAINT agenda_eventos_recurrence_id_fkey FOREIGN KEY (recurrence_id) REFERENCES public.recurrence_rules(id) ON DELETE SET NULL; -- -- Name: agenda_eventos agenda_eventos_terapeuta_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_eventos ADD CONSTRAINT agenda_eventos_terapeuta_fk FOREIGN KEY (terapeuta_id) REFERENCES auth.users(id) ON DELETE SET NULL; -- -- Name: agenda_excecoes agenda_excecoes_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_excecoes ADD CONSTRAINT agenda_excecoes_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: agenda_online_slots agenda_online_slots_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_online_slots ADD CONSTRAINT agenda_online_slots_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: agenda_online_slots agenda_online_slots_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_online_slots ADD CONSTRAINT agenda_online_slots_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: agenda_regras_semanais agenda_regras_semanais_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_regras_semanais ADD CONSTRAINT agenda_regras_semanais_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: agenda_slots_bloqueados_semanais agenda_slots_bloqueados_semanais_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_slots_bloqueados_semanais ADD CONSTRAINT agenda_slots_bloqueados_semanais_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: agenda_slots_regras agenda_slots_regras_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agenda_slots_regras ADD CONSTRAINT agenda_slots_regras_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: agendador_configuracoes agendador_configuracoes_owner_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agendador_configuracoes ADD CONSTRAINT agendador_configuracoes_owner_fk FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: agendador_configuracoes agendador_configuracoes_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agendador_configuracoes ADD CONSTRAINT agendador_configuracoes_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: agendador_solicitacoes agendador_sol_owner_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agendador_solicitacoes ADD CONSTRAINT agendador_sol_owner_fk FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: agendador_solicitacoes agendador_sol_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.agendador_solicitacoes ADD CONSTRAINT agendador_sol_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: billing_contracts billing_contracts_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.billing_contracts ADD CONSTRAINT billing_contracts_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: billing_contracts billing_contracts_patient_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.billing_contracts ADD CONSTRAINT billing_contracts_patient_id_fkey FOREIGN KEY (patient_id) REFERENCES public.patients(id) ON DELETE CASCADE; -- -- Name: commitment_services commitment_services_commitment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.commitment_services ADD CONSTRAINT commitment_services_commitment_id_fkey FOREIGN KEY (commitment_id) REFERENCES public.agenda_eventos(id) ON DELETE CASCADE; -- -- Name: commitment_services commitment_services_service_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.commitment_services ADD CONSTRAINT commitment_services_service_id_fkey FOREIGN KEY (service_id) REFERENCES public.services(id) ON DELETE RESTRICT; -- -- Name: commitment_time_logs commitment_time_logs_calendar_event_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.commitment_time_logs ADD CONSTRAINT commitment_time_logs_calendar_event_id_fkey FOREIGN KEY (calendar_event_id) REFERENCES public.agenda_eventos(id) ON DELETE SET NULL; -- -- Name: commitment_time_logs commitment_time_logs_commitment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.commitment_time_logs ADD CONSTRAINT commitment_time_logs_commitment_id_fkey FOREIGN KEY (commitment_id) REFERENCES public.determined_commitments(id) ON DELETE CASCADE; -- -- Name: commitment_time_logs commitment_time_logs_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.commitment_time_logs ADD CONSTRAINT commitment_time_logs_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: company_profiles company_profiles_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.company_profiles ADD CONSTRAINT company_profiles_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: determined_commitment_fields determined_commitment_fields_commitment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.determined_commitment_fields ADD CONSTRAINT determined_commitment_fields_commitment_id_fkey FOREIGN KEY (commitment_id) REFERENCES public.determined_commitments(id) ON DELETE CASCADE; -- -- Name: determined_commitment_fields determined_commitment_fields_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.determined_commitment_fields ADD CONSTRAINT determined_commitment_fields_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: determined_commitments determined_commitments_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.determined_commitments ADD CONSTRAINT determined_commitments_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: email_layout_config email_layout_config_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.email_layout_config ADD CONSTRAINT email_layout_config_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: email_templates_tenant email_templates_tenant_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.email_templates_tenant ADD CONSTRAINT email_templates_tenant_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: email_templates_tenant email_templates_tenant_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.email_templates_tenant ADD CONSTRAINT email_templates_tenant_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: feriados feriados_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.feriados ADD CONSTRAINT feriados_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE SET NULL; -- -- Name: feriados feriados_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.feriados ADD CONSTRAINT feriados_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: financial_categories financial_categories_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.financial_categories ADD CONSTRAINT financial_categories_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: financial_exceptions financial_exceptions_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.financial_exceptions ADD CONSTRAINT financial_exceptions_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: financial_records financial_records_agenda_evento_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.financial_records ADD CONSTRAINT financial_records_agenda_evento_id_fkey FOREIGN KEY (agenda_evento_id) REFERENCES public.agenda_eventos(id) ON DELETE SET NULL; -- -- Name: financial_records financial_records_category_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.financial_records ADD CONSTRAINT financial_records_category_id_fkey FOREIGN KEY (category_id) REFERENCES public.financial_categories(id) ON DELETE SET NULL; -- -- Name: financial_records financial_records_insurance_plan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.financial_records ADD CONSTRAINT financial_records_insurance_plan_id_fkey FOREIGN KEY (insurance_plan_id) REFERENCES public.insurance_plans(id) ON DELETE SET NULL; -- -- Name: financial_records financial_records_patient_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.financial_records ADD CONSTRAINT financial_records_patient_id_fkey FOREIGN KEY (patient_id) REFERENCES public.patients(id) ON DELETE SET NULL; -- -- Name: financial_records financial_records_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.financial_records ADD CONSTRAINT financial_records_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE SET NULL; -- -- Name: financial_records financial_records_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.financial_records ADD CONSTRAINT financial_records_user_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: global_notices global_notices_created_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.global_notices ADD CONSTRAINT global_notices_created_by_fkey FOREIGN KEY (created_by) REFERENCES auth.users(id) ON DELETE SET NULL; -- -- Name: insurance_plan_services insurance_plan_services_plan_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.insurance_plan_services ADD CONSTRAINT insurance_plan_services_plan_fkey FOREIGN KEY (insurance_plan_id) REFERENCES public.insurance_plans(id) ON DELETE CASCADE; -- -- Name: insurance_plans insurance_plans_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.insurance_plans ADD CONSTRAINT insurance_plans_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: module_features module_features_feature_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.module_features ADD CONSTRAINT module_features_feature_id_fkey FOREIGN KEY (feature_id) REFERENCES public.features(id) ON DELETE CASCADE; -- -- Name: module_features module_features_module_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.module_features ADD CONSTRAINT module_features_module_id_fkey FOREIGN KEY (module_id) REFERENCES public.modules(id) ON DELETE CASCADE; -- -- Name: notice_dismissals notice_dismissals_notice_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notice_dismissals ADD CONSTRAINT notice_dismissals_notice_id_fkey FOREIGN KEY (notice_id) REFERENCES public.global_notices(id) ON DELETE CASCADE; -- -- Name: notice_dismissals notice_dismissals_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notice_dismissals ADD CONSTRAINT notice_dismissals_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: notification_channels notification_channels_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_channels ADD CONSTRAINT notification_channels_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: notification_logs notification_logs_queue_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_logs ADD CONSTRAINT notification_logs_queue_id_fkey FOREIGN KEY (queue_id) REFERENCES public.notification_queue(id) ON DELETE SET NULL; -- -- Name: notification_schedules notification_schedules_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_schedules ADD CONSTRAINT notification_schedules_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: notification_templates notification_templates_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notification_templates ADD CONSTRAINT notification_templates_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: notifications notifications_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.notifications ADD CONSTRAINT notifications_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: patient_discounts patient_discounts_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_discounts ADD CONSTRAINT patient_discounts_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: patient_discounts patient_discounts_patient_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_discounts ADD CONSTRAINT patient_discounts_patient_id_fkey FOREIGN KEY (patient_id) REFERENCES public.patients(id) ON DELETE CASCADE; -- -- Name: patient_group_patient patient_group_patient_patient_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_group_patient ADD CONSTRAINT patient_group_patient_patient_id_fkey FOREIGN KEY (patient_id) REFERENCES public.patients(id) ON DELETE CASCADE; -- -- Name: patient_group_patient patient_group_patient_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_group_patient ADD CONSTRAINT patient_group_patient_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: patient_groups patient_groups_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_groups ADD CONSTRAINT patient_groups_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: patient_intake_requests patient_intake_requests_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_intake_requests ADD CONSTRAINT patient_intake_requests_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: patient_invites patient_invites_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_invites ADD CONSTRAINT patient_invites_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: patient_patient_tag patient_patient_tag_tag_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_patient_tag ADD CONSTRAINT patient_patient_tag_tag_id_fkey FOREIGN KEY (tag_id) REFERENCES public.patient_tags(id) ON DELETE CASCADE; -- -- Name: patient_patient_tag patient_patient_tag_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_patient_tag ADD CONSTRAINT patient_patient_tag_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: patient_tags patient_tags_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_tags ADD CONSTRAINT patient_tags_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: patients patients_responsible_member_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patients ADD CONSTRAINT patients_responsible_member_id_fkey FOREIGN KEY (responsible_member_id) REFERENCES public.tenant_members(id) ON DELETE RESTRICT; -- -- Name: patients patients_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patients ADD CONSTRAINT patients_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: patients patients_therapist_member_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patients ADD CONSTRAINT patients_therapist_member_id_fkey FOREIGN KEY (therapist_member_id) REFERENCES public.tenant_members(id); -- -- Name: patients patients_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patients ADD CONSTRAINT patients_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE SET NULL; -- -- Name: payment_settings payment_settings_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.payment_settings ADD CONSTRAINT payment_settings_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: payment_settings payment_settings_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.payment_settings ADD CONSTRAINT payment_settings_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: plan_features plan_features_feature_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.plan_features ADD CONSTRAINT plan_features_feature_id_fkey FOREIGN KEY (feature_id) REFERENCES public.features(id) ON DELETE CASCADE; -- -- Name: plan_features plan_features_plan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.plan_features ADD CONSTRAINT plan_features_plan_id_fkey FOREIGN KEY (plan_id) REFERENCES public.plans(id) ON DELETE CASCADE; -- -- Name: plan_prices plan_prices_plan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.plan_prices ADD CONSTRAINT plan_prices_plan_id_fkey FOREIGN KEY (plan_id) REFERENCES public.plans(id) ON DELETE CASCADE; -- -- Name: plan_public_bullets plan_public_bullets_plan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.plan_public_bullets ADD CONSTRAINT plan_public_bullets_plan_id_fkey FOREIGN KEY (plan_id) REFERENCES public.plans(id) ON DELETE CASCADE; -- -- Name: plan_public plan_public_plan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.plan_public ADD CONSTRAINT plan_public_plan_id_fkey FOREIGN KEY (plan_id) REFERENCES public.plans(id) ON DELETE CASCADE; -- -- Name: patient_patient_tag ppt_patient_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_patient_tag ADD CONSTRAINT ppt_patient_fk FOREIGN KEY (patient_id) REFERENCES public.patients(id) ON DELETE CASCADE; -- -- Name: patient_patient_tag ppt_tag_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.patient_patient_tag ADD CONSTRAINT ppt_tag_fk FOREIGN KEY (tag_id) REFERENCES public.patient_tags(id) ON DELETE CASCADE; -- -- Name: professional_pricing professional_pricing_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.professional_pricing ADD CONSTRAINT professional_pricing_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: profiles profiles_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.profiles ADD CONSTRAINT profiles_id_fkey FOREIGN KEY (id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: recurrence_exceptions recurrence_exceptions_agenda_evento_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.recurrence_exceptions ADD CONSTRAINT recurrence_exceptions_agenda_evento_id_fkey FOREIGN KEY (agenda_evento_id) REFERENCES public.agenda_eventos(id) ON DELETE SET NULL; -- -- Name: recurrence_exceptions recurrence_exceptions_recurrence_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.recurrence_exceptions ADD CONSTRAINT recurrence_exceptions_recurrence_id_fkey FOREIGN KEY (recurrence_id) REFERENCES public.recurrence_rules(id) ON DELETE CASCADE; -- -- Name: recurrence_rule_services recurrence_rule_services_rule_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.recurrence_rule_services ADD CONSTRAINT recurrence_rule_services_rule_id_fkey FOREIGN KEY (rule_id) REFERENCES public.recurrence_rules(id) ON DELETE CASCADE; -- -- Name: recurrence_rule_services recurrence_rule_services_service_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.recurrence_rule_services ADD CONSTRAINT recurrence_rule_services_service_id_fkey FOREIGN KEY (service_id) REFERENCES public.services(id) ON DELETE RESTRICT; -- -- Name: recurrence_rules recurrence_rules_insurance_plan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.recurrence_rules ADD CONSTRAINT recurrence_rules_insurance_plan_id_fkey FOREIGN KEY (insurance_plan_id) REFERENCES public.insurance_plans(id) ON DELETE SET NULL; -- -- Name: recurrence_rules recurrence_rules_insurance_plan_service_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.recurrence_rules ADD CONSTRAINT recurrence_rules_insurance_plan_service_id_fkey FOREIGN KEY (insurance_plan_service_id) REFERENCES public.insurance_plan_services(id) ON DELETE SET NULL; -- -- Name: saas_admins saas_admins_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.saas_admins ADD CONSTRAINT saas_admins_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: saas_doc_votos saas_doc_votos_doc_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.saas_doc_votos ADD CONSTRAINT saas_doc_votos_doc_id_fkey FOREIGN KEY (doc_id) REFERENCES public.saas_docs(id) ON DELETE CASCADE; -- -- Name: saas_doc_votos saas_doc_votos_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.saas_doc_votos ADD CONSTRAINT saas_doc_votos_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: saas_faq_itens saas_faq_itens_doc_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.saas_faq_itens ADD CONSTRAINT saas_faq_itens_doc_id_fkey FOREIGN KEY (doc_id) REFERENCES public.saas_docs(id) ON DELETE CASCADE; -- -- Name: services services_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.services ADD CONSTRAINT services_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: subscription_intents_personal sint_personal_subscription_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscription_intents_personal ADD CONSTRAINT sint_personal_subscription_id_fkey FOREIGN KEY (subscription_id) REFERENCES public.subscriptions(id) ON DELETE SET NULL; -- -- Name: subscription_intents_tenant sint_tenant_subscription_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscription_intents_tenant ADD CONSTRAINT sint_tenant_subscription_id_fkey FOREIGN KEY (subscription_id) REFERENCES public.subscriptions(id) ON DELETE SET NULL; -- -- Name: subscription_events subscription_events_subscription_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscription_events ADD CONSTRAINT subscription_events_subscription_id_fkey FOREIGN KEY (subscription_id) REFERENCES public.subscriptions(id) ON DELETE CASCADE; -- -- Name: subscription_intents_personal subscription_intents_personal_plan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscription_intents_personal ADD CONSTRAINT subscription_intents_personal_plan_id_fkey FOREIGN KEY (plan_id) REFERENCES public.plans(id) ON DELETE RESTRICT; -- -- Name: subscription_intents_tenant subscription_intents_tenant_plan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscription_intents_tenant ADD CONSTRAINT subscription_intents_tenant_plan_id_fkey FOREIGN KEY (plan_id) REFERENCES public.plans(id) ON DELETE RESTRICT; -- -- Name: subscription_intents_legacy subscription_intents_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscription_intents_legacy ADD CONSTRAINT subscription_intents_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE SET NULL; -- -- Name: subscriptions subscriptions_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscriptions ADD CONSTRAINT subscriptions_owner_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: subscriptions subscriptions_plan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.subscriptions ADD CONSTRAINT subscriptions_plan_id_fkey FOREIGN KEY (plan_id) REFERENCES public.plans(id) ON DELETE RESTRICT; -- -- Name: support_sessions support_sessions_admin_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.support_sessions ADD CONSTRAINT support_sessions_admin_fk FOREIGN KEY (admin_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: support_sessions support_sessions_tenant_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.support_sessions ADD CONSTRAINT support_sessions_tenant_fk FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: tenant_features tenant_features_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_features ADD CONSTRAINT tenant_features_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: tenant_invites tenant_invites_accepted_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_invites ADD CONSTRAINT tenant_invites_accepted_by_fkey FOREIGN KEY (accepted_by) REFERENCES auth.users(id) ON DELETE SET NULL; -- -- Name: tenant_invites tenant_invites_invited_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_invites ADD CONSTRAINT tenant_invites_invited_by_fkey FOREIGN KEY (invited_by) REFERENCES auth.users(id) ON DELETE SET NULL; -- -- Name: tenant_invites tenant_invites_revoked_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_invites ADD CONSTRAINT tenant_invites_revoked_by_fkey FOREIGN KEY (revoked_by) REFERENCES auth.users(id) ON DELETE SET NULL; -- -- Name: tenant_invites tenant_invites_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_invites ADD CONSTRAINT tenant_invites_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: tenant_members tenant_members_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_members ADD CONSTRAINT tenant_members_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: tenant_members tenant_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_members ADD CONSTRAINT tenant_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: tenant_modules tenant_modules_module_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_modules ADD CONSTRAINT tenant_modules_module_id_fkey FOREIGN KEY (module_id) REFERENCES public.modules(id) ON DELETE CASCADE; -- -- Name: tenant_modules tenant_modules_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.tenant_modules ADD CONSTRAINT tenant_modules_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: therapist_payout_records therapist_payout_records_financial_record_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.therapist_payout_records ADD CONSTRAINT therapist_payout_records_financial_record_id_fkey FOREIGN KEY (financial_record_id) REFERENCES public.financial_records(id) ON DELETE RESTRICT; -- -- Name: therapist_payout_records therapist_payout_records_payout_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.therapist_payout_records ADD CONSTRAINT therapist_payout_records_payout_id_fkey FOREIGN KEY (payout_id) REFERENCES public.therapist_payouts(id) ON DELETE CASCADE; -- -- Name: therapist_payouts therapist_payouts_owner_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.therapist_payouts ADD CONSTRAINT therapist_payouts_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: therapist_payouts therapist_payouts_tenant_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.therapist_payouts ADD CONSTRAINT therapist_payouts_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE; -- -- Name: user_settings user_settings_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.user_settings ADD CONSTRAINT user_settings_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; -- -- Name: iceberg_namespaces iceberg_namespaces_catalog_id_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.iceberg_namespaces ADD CONSTRAINT iceberg_namespaces_catalog_id_fkey FOREIGN KEY (catalog_id) REFERENCES storage.buckets_analytics(id) ON DELETE CASCADE; -- -- Name: iceberg_tables iceberg_tables_catalog_id_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.iceberg_tables ADD CONSTRAINT iceberg_tables_catalog_id_fkey FOREIGN KEY (catalog_id) REFERENCES storage.buckets_analytics(id) ON DELETE CASCADE; -- -- Name: iceberg_tables iceberg_tables_namespace_id_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.iceberg_tables ADD CONSTRAINT iceberg_tables_namespace_id_fkey FOREIGN KEY (namespace_id) REFERENCES storage.iceberg_namespaces(id) ON DELETE CASCADE; -- -- Name: objects objects_bucketId_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.objects ADD CONSTRAINT "objects_bucketId_fkey" FOREIGN KEY (bucket_id) REFERENCES storage.buckets(id); -- -- Name: s3_multipart_uploads s3_multipart_uploads_bucket_id_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.s3_multipart_uploads ADD CONSTRAINT s3_multipart_uploads_bucket_id_fkey FOREIGN KEY (bucket_id) REFERENCES storage.buckets(id); -- -- Name: s3_multipart_uploads_parts s3_multipart_uploads_parts_bucket_id_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.s3_multipart_uploads_parts ADD CONSTRAINT s3_multipart_uploads_parts_bucket_id_fkey FOREIGN KEY (bucket_id) REFERENCES storage.buckets(id); -- -- Name: s3_multipart_uploads_parts s3_multipart_uploads_parts_upload_id_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.s3_multipart_uploads_parts ADD CONSTRAINT s3_multipart_uploads_parts_upload_id_fkey FOREIGN KEY (upload_id) REFERENCES storage.s3_multipart_uploads(id) ON DELETE CASCADE; -- -- Name: vector_indexes vector_indexes_bucket_id_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: - -- ALTER TABLE ONLY storage.vector_indexes ADD CONSTRAINT vector_indexes_bucket_id_fkey FOREIGN KEY (bucket_id) REFERENCES storage.buckets_vectors(id); -- -- Name: audit_log_entries; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.audit_log_entries ENABLE ROW LEVEL SECURITY; -- -- Name: flow_state; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.flow_state ENABLE ROW LEVEL SECURITY; -- -- Name: identities; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.identities ENABLE ROW LEVEL SECURITY; -- -- Name: instances; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.instances ENABLE ROW LEVEL SECURITY; -- -- Name: mfa_amr_claims; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.mfa_amr_claims ENABLE ROW LEVEL SECURITY; -- -- Name: mfa_challenges; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.mfa_challenges ENABLE ROW LEVEL SECURITY; -- -- Name: mfa_factors; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.mfa_factors ENABLE ROW LEVEL SECURITY; -- -- Name: one_time_tokens; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.one_time_tokens ENABLE ROW LEVEL SECURITY; -- -- Name: refresh_tokens; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.refresh_tokens ENABLE ROW LEVEL SECURITY; -- -- Name: saml_providers; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.saml_providers ENABLE ROW LEVEL SECURITY; -- -- Name: saml_relay_states; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.saml_relay_states ENABLE ROW LEVEL SECURITY; -- -- Name: schema_migrations; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.schema_migrations ENABLE ROW LEVEL SECURITY; -- -- Name: sessions; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.sessions ENABLE ROW LEVEL SECURITY; -- -- Name: sso_domains; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.sso_domains ENABLE ROW LEVEL SECURITY; -- -- Name: sso_providers; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.sso_providers ENABLE ROW LEVEL SECURITY; -- -- Name: users; Type: ROW SECURITY; Schema: auth; Owner: - -- ALTER TABLE auth.users ENABLE ROW LEVEL SECURITY; -- -- Name: addon_credits; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.addon_credits ENABLE ROW LEVEL SECURITY; -- -- Name: addon_credits addon_credits_admin_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY addon_credits_admin_select ON public.addon_credits FOR SELECT TO authenticated USING ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))); -- -- Name: addon_credits addon_credits_admin_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY addon_credits_admin_write ON public.addon_credits TO authenticated USING ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))); -- -- Name: addon_credits addon_credits_select_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY addon_credits_select_own ON public.addon_credits FOR SELECT TO authenticated USING ((public.is_tenant_member(tenant_id) OR (owner_id = auth.uid()))); -- -- Name: addon_products; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.addon_products ENABLE ROW LEVEL SECURITY; -- -- Name: addon_products addon_products_admin_all; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY addon_products_admin_all ON public.addon_products TO authenticated USING ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))); -- -- Name: addon_products addon_products_select_authenticated; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY addon_products_select_authenticated ON public.addon_products FOR SELECT TO authenticated USING (((deleted_at IS NULL) AND (is_active = true) AND (is_visible = true))); -- -- Name: addon_transactions; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.addon_transactions ENABLE ROW LEVEL SECURITY; -- -- Name: addon_transactions addon_transactions_admin_insert; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY addon_transactions_admin_insert ON public.addon_transactions FOR INSERT TO authenticated WITH CHECK ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))); -- -- Name: addon_transactions addon_transactions_admin_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY addon_transactions_admin_select ON public.addon_transactions FOR SELECT TO authenticated USING ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))); -- -- Name: addon_transactions addon_transactions_select_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY addon_transactions_select_own ON public.addon_transactions FOR SELECT TO authenticated USING ((public.is_tenant_member(tenant_id) OR (owner_id = auth.uid()))); -- -- Name: agenda_bloqueios; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.agenda_bloqueios ENABLE ROW LEVEL SECURITY; -- -- Name: agenda_configuracoes; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.agenda_configuracoes ENABLE ROW LEVEL SECURITY; -- -- Name: agenda_configuracoes agenda_configuracoes_clinic_read; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_configuracoes_clinic_read ON public.agenda_configuracoes FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.view'::text))); -- -- Name: agenda_configuracoes agenda_configuracoes_clinic_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_configuracoes_clinic_write ON public.agenda_configuracoes USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))); -- -- Name: agenda_configuracoes agenda_configuracoes_owner; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_configuracoes_owner ON public.agenda_configuracoes USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: agenda_eventos; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.agenda_eventos ENABLE ROW LEVEL SECURITY; -- -- Name: agenda_eventos agenda_eventos_delete; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_eventos_delete ON public.agenda_eventos FOR DELETE USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.delete'::text))); -- -- Name: agenda_eventos agenda_eventos_insert; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_eventos_insert ON public.agenda_eventos FOR INSERT WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.create'::text))); -- -- Name: agenda_eventos agenda_eventos_owner_all; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_eventos_owner_all ON public.agenda_eventos TO authenticated USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: agenda_eventos agenda_eventos_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_eventos_select ON public.agenda_eventos FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.view'::text))); -- -- Name: agenda_eventos agenda_eventos_update; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_eventos_update ON public.agenda_eventos FOR UPDATE USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))); -- -- Name: agenda_excecoes; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.agenda_excecoes ENABLE ROW LEVEL SECURITY; -- -- Name: agenda_excecoes agenda_excecoes_owner; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_excecoes_owner ON public.agenda_excecoes USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: agenda_excecoes agenda_excecoes_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_excecoes_select ON public.agenda_excecoes FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.view'::text))); -- -- Name: agenda_excecoes agenda_excecoes_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_excecoes_write ON public.agenda_excecoes USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))); -- -- Name: agenda_online_slots; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.agenda_online_slots ENABLE ROW LEVEL SECURITY; -- -- Name: agenda_online_slots agenda_online_slots_owner; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_online_slots_owner ON public.agenda_online_slots USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: agenda_online_slots agenda_online_slots_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_online_slots_select ON public.agenda_online_slots FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.view'::text))); -- -- Name: agenda_online_slots agenda_online_slots_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_online_slots_write ON public.agenda_online_slots USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))); -- -- Name: agenda_regras_semanais; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.agenda_regras_semanais ENABLE ROW LEVEL SECURITY; -- -- Name: agenda_regras_semanais agenda_regras_semanais_owner; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_regras_semanais_owner ON public.agenda_regras_semanais USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: agenda_regras_semanais agenda_regras_semanais_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_regras_semanais_select ON public.agenda_regras_semanais FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.view'::text))); -- -- Name: agenda_regras_semanais agenda_regras_semanais_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_regras_semanais_write ON public.agenda_regras_semanais USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))); -- -- Name: agenda_slots_bloqueados_semanais; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.agenda_slots_bloqueados_semanais ENABLE ROW LEVEL SECURITY; -- -- Name: agenda_slots_bloqueados_semanais agenda_slots_bloqueados_semanais_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_slots_bloqueados_semanais_select ON public.agenda_slots_bloqueados_semanais FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.view'::text))); -- -- Name: agenda_slots_bloqueados_semanais agenda_slots_bloqueados_semanais_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_slots_bloqueados_semanais_write ON public.agenda_slots_bloqueados_semanais USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))); -- -- Name: agenda_slots_regras; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.agenda_slots_regras ENABLE ROW LEVEL SECURITY; -- -- Name: agenda_slots_regras agenda_slots_regras_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_slots_regras_select ON public.agenda_slots_regras FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.view'::text))); -- -- Name: agenda_slots_regras agenda_slots_regras_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agenda_slots_regras_write ON public.agenda_slots_regras USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))); -- -- Name: agendador_configuracoes agendador_cfg_public_read; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agendador_cfg_public_read ON public.agendador_configuracoes FOR SELECT TO anon USING (((ativo = true) AND (link_slug IS NOT NULL))); -- -- Name: agendador_configuracoes agendador_cfg_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agendador_cfg_select ON public.agendador_configuracoes FOR SELECT USING ((auth.uid() = owner_id)); -- -- Name: agendador_configuracoes agendador_cfg_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agendador_cfg_write ON public.agendador_configuracoes USING ((auth.uid() = owner_id)) WITH CHECK ((auth.uid() = owner_id)); -- -- Name: agendador_configuracoes; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.agendador_configuracoes ENABLE ROW LEVEL SECURITY; -- -- Name: agendador_solicitacoes agendador_sol_owner_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agendador_sol_owner_select ON public.agendador_solicitacoes FOR SELECT USING ((auth.uid() = owner_id)); -- -- Name: agendador_solicitacoes agendador_sol_owner_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agendador_sol_owner_write ON public.agendador_solicitacoes USING ((auth.uid() = owner_id)) WITH CHECK ((auth.uid() = owner_id)); -- -- Name: agendador_solicitacoes agendador_sol_patient_read; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agendador_sol_patient_read ON public.agendador_solicitacoes FOR SELECT TO authenticated USING (((auth.uid() = user_id) OR (auth.uid() = owner_id))); -- -- Name: agendador_solicitacoes agendador_sol_public_insert; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY agendador_sol_public_insert ON public.agendador_solicitacoes FOR INSERT TO anon WITH CHECK (true); -- -- Name: agendador_solicitacoes; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.agendador_solicitacoes ENABLE ROW LEVEL SECURITY; -- -- Name: billing_contracts; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.billing_contracts ENABLE ROW LEVEL SECURITY; -- -- Name: billing_contracts billing_contracts: owner full access; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "billing_contracts: owner full access" ON public.billing_contracts USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: agenda_bloqueios bloqueios_delete; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY bloqueios_delete ON public.agenda_bloqueios FOR DELETE TO authenticated USING ((owner_id = auth.uid())); -- -- Name: agenda_bloqueios bloqueios_insert; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY bloqueios_insert ON public.agenda_bloqueios FOR INSERT TO authenticated WITH CHECK ((owner_id = auth.uid())); -- -- Name: agenda_bloqueios bloqueios_select_clinic; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY bloqueios_select_clinic ON public.agenda_bloqueios FOR SELECT TO authenticated USING ((tenant_id IN ( SELECT tenant_members.tenant_id FROM public.tenant_members WHERE ((tenant_members.user_id = auth.uid()) AND (tenant_members.role = ANY (ARRAY['admin'::text, 'clinic_admin'::text, 'tenant_admin'::text, 'secretary'::text])))))); -- -- Name: agenda_bloqueios bloqueios_select_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY bloqueios_select_own ON public.agenda_bloqueios FOR SELECT TO authenticated USING ((owner_id = auth.uid())); -- -- Name: agenda_bloqueios bloqueios_update; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY bloqueios_update ON public.agenda_bloqueios FOR UPDATE TO authenticated USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: saas_docs clinic_admin_read_all_docs; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY clinic_admin_read_all_docs ON public.saas_docs FOR SELECT TO authenticated USING (((ativo = true) AND (EXISTS ( SELECT 1 FROM public.profiles WHERE ((profiles.id = auth.uid()) AND (profiles.role = ANY (ARRAY['clinic_admin'::text, 'tenant_admin'::text]))))))); -- -- Name: commitment_services; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.commitment_services ENABLE ROW LEVEL SECURITY; -- -- Name: commitment_services commitment_services: owner full access; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "commitment_services: owner full access" ON public.commitment_services USING ((EXISTS ( SELECT 1 FROM public.services s WHERE ((s.id = commitment_services.service_id) AND (s.owner_id = auth.uid()))))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.services s WHERE ((s.id = commitment_services.service_id) AND (s.owner_id = auth.uid()))))); -- -- Name: commitment_time_logs; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.commitment_time_logs ENABLE ROW LEVEL SECURITY; -- -- Name: company_profiles; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.company_profiles ENABLE ROW LEVEL SECURITY; -- -- Name: company_profiles company_profiles_delete; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY company_profiles_delete ON public.company_profiles FOR DELETE USING ((tenant_id = auth.uid())); -- -- Name: company_profiles company_profiles_insert; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY company_profiles_insert ON public.company_profiles FOR INSERT WITH CHECK ((tenant_id = auth.uid())); -- -- Name: company_profiles company_profiles_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY company_profiles_select ON public.company_profiles FOR SELECT USING ((tenant_id = auth.uid())); -- -- Name: company_profiles company_profiles_update; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY company_profiles_update ON public.company_profiles FOR UPDATE USING ((tenant_id = auth.uid())); -- -- Name: commitment_time_logs ctl_delete_for_active_member; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY ctl_delete_for_active_member ON public.commitment_time_logs FOR DELETE TO authenticated USING ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = commitment_time_logs.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))); -- -- Name: commitment_time_logs ctl_insert_for_active_member; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY ctl_insert_for_active_member ON public.commitment_time_logs FOR INSERT TO authenticated WITH CHECK ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = commitment_time_logs.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))); -- -- Name: commitment_time_logs ctl_select_for_active_member; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY ctl_select_for_active_member ON public.commitment_time_logs FOR SELECT TO authenticated USING ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = commitment_time_logs.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))); -- -- Name: commitment_time_logs ctl_update_for_active_member; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY ctl_update_for_active_member ON public.commitment_time_logs FOR UPDATE TO authenticated USING ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = commitment_time_logs.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = commitment_time_logs.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))); -- -- Name: determined_commitments dc_delete_custom_for_active_member; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY dc_delete_custom_for_active_member ON public.determined_commitments FOR DELETE TO authenticated USING (((is_native = false) AND (EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = determined_commitments.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text)))))); -- -- Name: determined_commitments dc_insert_for_active_member; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY dc_insert_for_active_member ON public.determined_commitments FOR INSERT TO authenticated WITH CHECK ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = determined_commitments.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))); -- -- Name: determined_commitments dc_select_for_active_member; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY dc_select_for_active_member ON public.determined_commitments FOR SELECT TO authenticated USING ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = determined_commitments.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))); -- -- Name: determined_commitments dc_update_for_active_member; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY dc_update_for_active_member ON public.determined_commitments FOR UPDATE TO authenticated USING ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = determined_commitments.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = determined_commitments.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))); -- -- Name: determined_commitment_fields dcf_delete_for_active_member; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY dcf_delete_for_active_member ON public.determined_commitment_fields FOR DELETE TO authenticated USING ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = determined_commitment_fields.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))); -- -- Name: determined_commitment_fields dcf_insert_for_active_member; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY dcf_insert_for_active_member ON public.determined_commitment_fields FOR INSERT TO authenticated WITH CHECK ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = determined_commitment_fields.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))); -- -- Name: determined_commitment_fields dcf_select_for_active_member; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY dcf_select_for_active_member ON public.determined_commitment_fields FOR SELECT TO authenticated USING ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = determined_commitment_fields.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))); -- -- Name: determined_commitment_fields dcf_update_for_active_member; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY dcf_update_for_active_member ON public.determined_commitment_fields FOR UPDATE TO authenticated USING ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = determined_commitment_fields.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = determined_commitment_fields.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text))))); -- -- Name: agenda_bloqueios delete own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "delete own" ON public.agenda_bloqueios FOR DELETE USING ((owner_id = auth.uid())); -- -- Name: determined_commitment_fields; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.determined_commitment_fields ENABLE ROW LEVEL SECURITY; -- -- Name: determined_commitments; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.determined_commitments ENABLE ROW LEVEL SECURITY; -- -- Name: dev_user_credentials dev_creds_select_saas_admin; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY dev_creds_select_saas_admin ON public.dev_user_credentials FOR SELECT TO authenticated USING ((EXISTS ( SELECT 1 FROM public.profiles p WHERE ((p.id = auth.uid()) AND (p.role = 'saas_admin'::text))))); -- -- Name: dev_user_credentials dev_creds_write_saas_admin; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY dev_creds_write_saas_admin ON public.dev_user_credentials TO authenticated USING ((EXISTS ( SELECT 1 FROM public.profiles p WHERE ((p.id = auth.uid()) AND (p.role = 'saas_admin'::text))))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.profiles p WHERE ((p.id = auth.uid()) AND (p.role = 'saas_admin'::text))))); -- -- Name: dev_user_credentials; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.dev_user_credentials ENABLE ROW LEVEL SECURITY; -- -- Name: email_layout_config; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.email_layout_config ENABLE ROW LEVEL SECURITY; -- -- Name: email_templates_global; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.email_templates_global ENABLE ROW LEVEL SECURITY; -- -- Name: email_templates_tenant; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.email_templates_tenant ENABLE ROW LEVEL SECURITY; -- -- Name: entitlements_invalidation ent_inv_select_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY ent_inv_select_own ON public.entitlements_invalidation FOR SELECT USING (((owner_id = auth.uid()) OR public.is_saas_admin())); -- -- Name: entitlements_invalidation ent_inv_update_saas; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY ent_inv_update_saas ON public.entitlements_invalidation FOR UPDATE USING (public.is_saas_admin()) WITH CHECK (public.is_saas_admin()); -- -- Name: entitlements_invalidation ent_inv_write_saas; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY ent_inv_write_saas ON public.entitlements_invalidation FOR INSERT WITH CHECK (public.is_saas_admin()); -- -- Name: entitlements_invalidation; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.entitlements_invalidation ENABLE ROW LEVEL SECURITY; -- -- Name: saas_faq faq_admin_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY faq_admin_write ON public.saas_faq TO authenticated USING ((EXISTS ( SELECT 1 FROM public.profiles WHERE ((profiles.id = auth.uid()) AND (profiles.role = ANY (ARRAY['saas_admin'::text, 'tenant_admin'::text, 'clinic_admin'::text])))))); -- -- Name: saas_faq faq_auth_read; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY faq_auth_read ON public.saas_faq FOR SELECT TO authenticated USING ((ativo = true)); -- -- Name: saas_faq_itens faq_itens_admin_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY faq_itens_admin_write ON public.saas_faq_itens TO authenticated USING ((EXISTS ( SELECT 1 FROM public.profiles WHERE ((profiles.id = auth.uid()) AND (profiles.role = ANY (ARRAY['saas_admin'::text, 'tenant_admin'::text, 'clinic_admin'::text])))))); -- -- Name: saas_faq_itens faq_itens_auth_read; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY faq_itens_auth_read ON public.saas_faq_itens FOR SELECT TO authenticated USING (((ativo = true) AND (EXISTS ( SELECT 1 FROM public.saas_docs d WHERE ((d.id = saas_faq_itens.doc_id) AND (d.ativo = true)))))); -- -- Name: saas_faq faq_public_read; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY faq_public_read ON public.saas_faq FOR SELECT USING (((publico = true) AND (ativo = true))); -- -- Name: features; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.features ENABLE ROW LEVEL SECURITY; -- -- Name: features features_read_authenticated; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY features_read_authenticated ON public.features FOR SELECT TO authenticated USING (true); -- -- Name: features features_write_saas_admin; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY features_write_saas_admin ON public.features TO authenticated USING (public.is_saas_admin()) WITH CHECK (public.is_saas_admin()); -- -- Name: feriados; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.feriados ENABLE ROW LEVEL SECURITY; -- -- Name: feriados feriados_delete; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY feriados_delete ON public.feriados FOR DELETE USING ((owner_id = auth.uid())); -- -- Name: feriados feriados_global_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY feriados_global_select ON public.feriados FOR SELECT USING ((tenant_id IS NULL)); -- -- Name: feriados feriados_insert; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY feriados_insert ON public.feriados FOR INSERT WITH CHECK ((tenant_id IN ( SELECT tenant_members.tenant_id FROM public.tenant_members WHERE (tenant_members.user_id = auth.uid())))); -- -- Name: feriados feriados_saas_delete; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY feriados_saas_delete ON public.feriados FOR DELETE USING ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))); -- -- Name: feriados feriados_saas_insert; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY feriados_saas_insert ON public.feriados FOR INSERT WITH CHECK ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))); -- -- Name: feriados feriados_saas_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY feriados_saas_select ON public.feriados FOR SELECT USING ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))); -- -- Name: feriados feriados_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY feriados_select ON public.feriados FOR SELECT USING ((tenant_id IN ( SELECT tenant_members.tenant_id FROM public.tenant_members WHERE (tenant_members.user_id = auth.uid())))); -- -- Name: financial_categories; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.financial_categories ENABLE ROW LEVEL SECURITY; -- -- Name: financial_categories financial_categories_self; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY financial_categories_self ON public.financial_categories USING ((auth.uid() = user_id)) WITH CHECK ((auth.uid() = user_id)); -- -- Name: financial_exceptions; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.financial_exceptions ENABLE ROW LEVEL SECURITY; -- -- Name: financial_exceptions financial_exceptions: owner full access; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "financial_exceptions: owner full access" ON public.financial_exceptions USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: financial_exceptions financial_exceptions: tenant members read clinic rules; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "financial_exceptions: tenant members read clinic rules" ON public.financial_exceptions FOR SELECT USING (((owner_id IS NULL) AND (EXISTS ( SELECT 1 FROM public.owner_users ou WHERE ((ou.owner_id = financial_exceptions.tenant_id) AND (ou.user_id = auth.uid())))))); -- -- Name: financial_records; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.financial_records ENABLE ROW LEVEL SECURITY; -- -- Name: financial_records financial_records_self; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY financial_records_self ON public.financial_records USING ((auth.uid() = owner_id)) WITH CHECK ((auth.uid() = owner_id)); -- -- Name: financial_records financial_records_tenant_admin; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY financial_records_tenant_admin ON public.financial_records FOR SELECT USING (((tenant_id IS NOT NULL) AND public.is_tenant_admin(tenant_id))); -- -- Name: financial_records financial_records_tenant_member_read; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY financial_records_tenant_member_read ON public.financial_records FOR SELECT USING (((tenant_id IS NOT NULL) AND (EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = financial_records.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text)))))); -- -- Name: email_templates_global global templates readable by authenticated; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "global templates readable by authenticated" ON public.email_templates_global FOR SELECT USING ((auth.role() = 'authenticated'::text)); -- -- Name: global_notices; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.global_notices ENABLE ROW LEVEL SECURITY; -- -- Name: global_notices global_notices_saas_all; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY global_notices_saas_all ON public.global_notices TO authenticated USING ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))); -- -- Name: global_notices global_notices_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY global_notices_select ON public.global_notices FOR SELECT TO authenticated USING ((is_active = true)); -- -- Name: agenda_bloqueios insert own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "insert own" ON public.agenda_bloqueios FOR INSERT WITH CHECK ((owner_id = auth.uid())); -- -- Name: insurance_plan_services; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.insurance_plan_services ENABLE ROW LEVEL SECURITY; -- -- Name: insurance_plan_services insurance_plan_services_owner; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY insurance_plan_services_owner ON public.insurance_plan_services USING ((EXISTS ( SELECT 1 FROM public.insurance_plans ip WHERE ((ip.id = insurance_plan_services.insurance_plan_id) AND (ip.owner_id = auth.uid()))))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.insurance_plans ip WHERE ((ip.id = insurance_plan_services.insurance_plan_id) AND (ip.owner_id = auth.uid()))))); -- -- Name: insurance_plans; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.insurance_plans ENABLE ROW LEVEL SECURITY; -- -- Name: insurance_plans insurance_plans: owner full access; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "insurance_plans: owner full access" ON public.insurance_plans USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: login_carousel_slides; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.login_carousel_slides ENABLE ROW LEVEL SECURITY; -- -- Name: module_features; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.module_features ENABLE ROW LEVEL SECURITY; -- -- Name: module_features module_features_read_authenticated; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY module_features_read_authenticated ON public.module_features FOR SELECT TO authenticated USING (true); -- -- Name: module_features module_features_write_saas_admin; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY module_features_write_saas_admin ON public.module_features TO authenticated USING (public.is_saas_admin()) WITH CHECK (public.is_saas_admin()); -- -- Name: modules; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.modules ENABLE ROW LEVEL SECURITY; -- -- Name: modules modules_read_authenticated; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY modules_read_authenticated ON public.modules FOR SELECT TO authenticated USING (true); -- -- Name: modules modules_write_saas_admin; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY modules_write_saas_admin ON public.modules TO authenticated USING (public.is_saas_admin()) WITH CHECK (public.is_saas_admin()); -- -- Name: notice_dismissals; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.notice_dismissals ENABLE ROW LEVEL SECURITY; -- -- Name: notice_dismissals notice_dismissals_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY notice_dismissals_own ON public.notice_dismissals TO authenticated USING ((user_id = auth.uid())) WITH CHECK ((user_id = auth.uid())); -- -- Name: notification_logs notif_logs_owner; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY notif_logs_owner ON public.notification_logs FOR SELECT USING ((owner_id = auth.uid())); -- -- Name: notification_preferences notif_prefs_owner; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY notif_prefs_owner ON public.notification_preferences USING (((owner_id = auth.uid()) AND (deleted_at IS NULL))) WITH CHECK ((owner_id = auth.uid())); -- -- Name: notification_queue notif_queue_owner; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY notif_queue_owner ON public.notification_queue FOR SELECT USING ((owner_id = auth.uid())); -- -- Name: notification_schedules notif_schedules_owner; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY notif_schedules_owner ON public.notification_schedules USING (((owner_id = auth.uid()) AND (deleted_at IS NULL))) WITH CHECK ((owner_id = auth.uid())); -- -- Name: notification_templates notif_templates_admin_all; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY notif_templates_admin_all ON public.notification_templates TO authenticated USING ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))); -- -- Name: notification_templates notif_templates_read_global; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY notif_templates_read_global ON public.notification_templates FOR SELECT TO authenticated USING (((deleted_at IS NULL) AND (((tenant_id IS NULL) AND (is_default = true)) OR (owner_id = auth.uid()) OR public.is_tenant_member(tenant_id)))); -- -- Name: notification_templates notif_templates_write_owner; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY notif_templates_write_owner ON public.notification_templates TO authenticated USING (((owner_id = auth.uid()) OR public.is_tenant_member(tenant_id))) WITH CHECK (((owner_id = auth.uid()) OR public.is_tenant_member(tenant_id))); -- -- Name: notification_channels; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.notification_channels ENABLE ROW LEVEL SECURITY; -- -- Name: notification_channels notification_channels_owner; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY notification_channels_owner ON public.notification_channels USING (((owner_id = auth.uid()) AND (deleted_at IS NULL))) WITH CHECK ((owner_id = auth.uid())); -- -- Name: notification_logs; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.notification_logs ENABLE ROW LEVEL SECURITY; -- -- Name: notification_preferences; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.notification_preferences ENABLE ROW LEVEL SECURITY; -- -- Name: notification_queue; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.notification_queue ENABLE ROW LEVEL SECURITY; -- -- Name: notification_schedules; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.notification_schedules ENABLE ROW LEVEL SECURITY; -- -- Name: notification_templates; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.notification_templates ENABLE ROW LEVEL SECURITY; -- -- Name: notifications; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.notifications ENABLE ROW LEVEL SECURITY; -- -- Name: notifications owner only; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "owner only" ON public.notifications USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: owner_users; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.owner_users ENABLE ROW LEVEL SECURITY; -- -- Name: owner_users owner_users: user can read own links; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "owner_users: user can read own links" ON public.owner_users FOR SELECT TO authenticated USING ((user_id = auth.uid())); -- -- Name: patient_discounts; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.patient_discounts ENABLE ROW LEVEL SECURITY; -- -- Name: patient_discounts patient_discounts: owner full access; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "patient_discounts: owner full access" ON public.patient_discounts USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: patient_group_patient; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.patient_group_patient ENABLE ROW LEVEL SECURITY; -- -- Name: patient_group_patient patient_group_patient_owner_all; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_group_patient_owner_all ON public.patient_group_patient TO authenticated USING ((EXISTS ( SELECT 1 FROM public.patients p WHERE ((p.id = patient_group_patient.patient_id) AND (p.owner_id = auth.uid()))))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.patients p WHERE ((p.id = patient_group_patient.patient_id) AND (p.owner_id = auth.uid()))))); -- -- Name: patient_group_patient patient_group_patient_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_group_patient_select ON public.patient_group_patient FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.view'::text))); -- -- Name: patient_group_patient patient_group_patient_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_group_patient_write ON public.patient_group_patient USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))); -- -- Name: patient_groups; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.patient_groups ENABLE ROW LEVEL SECURITY; -- -- Name: patient_groups patient_groups_owner_all; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_groups_owner_all ON public.patient_groups TO authenticated USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: patient_groups patient_groups_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_groups_select ON public.patient_groups FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.view'::text))); -- -- Name: patient_groups patient_groups_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_groups_write ON public.patient_groups USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))); -- -- Name: patient_intake_requests; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.patient_intake_requests ENABLE ROW LEVEL SECURITY; -- -- Name: patient_intake_requests patient_intake_requests_owner_all; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_intake_requests_owner_all ON public.patient_intake_requests TO authenticated USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: patient_intake_requests patient_intake_requests_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_intake_requests_select ON public.patient_intake_requests FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.view'::text))); -- -- Name: patient_intake_requests patient_intake_requests_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_intake_requests_write ON public.patient_intake_requests USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))); -- -- Name: patient_invites; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.patient_invites ENABLE ROW LEVEL SECURITY; -- -- Name: patient_invites patient_invites_owner_all; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_invites_owner_all ON public.patient_invites TO authenticated USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: patient_invites patient_invites_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_invites_select ON public.patient_invites FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.view'::text))); -- -- Name: patient_invites patient_invites_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_invites_write ON public.patient_invites USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))); -- -- Name: patient_patient_tag; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.patient_patient_tag ENABLE ROW LEVEL SECURITY; -- -- Name: patient_patient_tag patient_patient_tag_owner_all; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_patient_tag_owner_all ON public.patient_patient_tag TO authenticated USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: patient_patient_tag patient_patient_tag_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_patient_tag_select ON public.patient_patient_tag FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.view'::text))); -- -- Name: patient_patient_tag patient_patient_tag_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_patient_tag_write ON public.patient_patient_tag USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))); -- -- Name: patient_tags; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.patient_tags ENABLE ROW LEVEL SECURITY; -- -- Name: patient_tags patient_tags_owner_all; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_tags_owner_all ON public.patient_tags TO authenticated USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: patient_tags patient_tags_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_tags_select ON public.patient_tags FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.view'::text))); -- -- Name: patient_tags patient_tags_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patient_tags_write ON public.patient_tags USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))); -- -- Name: patients; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.patients ENABLE ROW LEVEL SECURITY; -- -- Name: patients patients_delete; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patients_delete ON public.patients FOR DELETE USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.delete'::text))); -- -- Name: patients patients_insert; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patients_insert ON public.patients FOR INSERT WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.create'::text))); -- -- Name: patients patients_owner_all; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patients_owner_all ON public.patients TO authenticated USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: patients patients_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patients_select ON public.patients FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.view'::text))); -- -- Name: patients patients_update; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY patients_update ON public.patients FOR UPDATE USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'patients.edit'::text))); -- -- Name: payment_settings; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.payment_settings ENABLE ROW LEVEL SECURITY; -- -- Name: payment_settings payment_settings: owner full access; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "payment_settings: owner full access" ON public.payment_settings USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: plan_features; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.plan_features ENABLE ROW LEVEL SECURITY; -- -- Name: plan_features plan_features_read_authenticated; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY plan_features_read_authenticated ON public.plan_features FOR SELECT TO authenticated USING (true); -- -- Name: plan_features plan_features_write_saas_admin; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY plan_features_write_saas_admin ON public.plan_features TO authenticated USING (public.is_saas_admin()) WITH CHECK (public.is_saas_admin()); -- -- Name: plans; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.plans ENABLE ROW LEVEL SECURITY; -- -- Name: plans plans_read_authenticated; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY plans_read_authenticated ON public.plans FOR SELECT TO authenticated USING (true); -- -- Name: plans plans_write_saas_admin; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY plans_write_saas_admin ON public.plans TO authenticated USING (public.is_saas_admin()) WITH CHECK (public.is_saas_admin()); -- -- Name: professional_pricing; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.professional_pricing ENABLE ROW LEVEL SECURITY; -- -- Name: professional_pricing professional_pricing: owner full access; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "professional_pricing: owner full access" ON public.professional_pricing USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: profiles; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY; -- -- Name: profiles profiles_insert_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY profiles_insert_own ON public.profiles FOR INSERT WITH CHECK ((id = auth.uid())); -- -- Name: profiles profiles_read_saas_admin; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY profiles_read_saas_admin ON public.profiles FOR SELECT USING (public.is_saas_admin()); -- -- Name: profiles profiles_select_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY profiles_select_own ON public.profiles FOR SELECT USING ((id = auth.uid())); -- -- Name: profiles profiles_update_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY profiles_update_own ON public.profiles FOR UPDATE USING ((id = auth.uid())) WITH CHECK ((id = auth.uid())); -- -- Name: login_carousel_slides public_read; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY public_read ON public.login_carousel_slides FOR SELECT USING ((ativo = true)); -- -- Name: features read features (auth); Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "read features (auth)" ON public.features FOR SELECT TO authenticated USING (true); -- -- Name: plan_features read plan_features (auth); Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "read plan_features (auth)" ON public.plan_features FOR SELECT TO authenticated USING (true); -- -- Name: plans read plans (auth); Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "read plans (auth)" ON public.plans FOR SELECT TO authenticated USING (true); -- -- Name: recurrence_exceptions; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.recurrence_exceptions ENABLE ROW LEVEL SECURITY; -- -- Name: recurrence_exceptions recurrence_exceptions_tenant; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY recurrence_exceptions_tenant ON public.recurrence_exceptions TO authenticated USING ((tenant_id IN ( SELECT tenant_members.tenant_id FROM public.tenant_members WHERE (tenant_members.user_id = auth.uid())))) WITH CHECK ((tenant_id IN ( SELECT tenant_members.tenant_id FROM public.tenant_members WHERE (tenant_members.user_id = auth.uid())))); -- -- Name: recurrence_rule_services; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.recurrence_rule_services ENABLE ROW LEVEL SECURITY; -- -- Name: recurrence_rule_services recurrence_rule_services: clinic read; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "recurrence_rule_services: clinic read" ON public.recurrence_rule_services FOR SELECT USING ((EXISTS ( SELECT 1 FROM public.recurrence_rules r WHERE ((r.id = recurrence_rule_services.rule_id) AND public.is_clinic_tenant(r.tenant_id) AND public.is_tenant_member(r.tenant_id) AND public.tenant_has_feature(r.tenant_id, 'agenda.view'::text))))); -- -- Name: recurrence_rule_services recurrence_rule_services: clinic write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "recurrence_rule_services: clinic write" ON public.recurrence_rule_services USING ((EXISTS ( SELECT 1 FROM public.recurrence_rules r WHERE ((r.id = recurrence_rule_services.rule_id) AND public.is_clinic_tenant(r.tenant_id) AND public.is_tenant_member(r.tenant_id) AND public.tenant_has_feature(r.tenant_id, 'agenda.edit'::text))))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.recurrence_rules r WHERE ((r.id = recurrence_rule_services.rule_id) AND public.is_clinic_tenant(r.tenant_id) AND public.is_tenant_member(r.tenant_id) AND public.tenant_has_feature(r.tenant_id, 'agenda.edit'::text))))); -- -- Name: recurrence_rule_services recurrence_rule_services: owner full access; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "recurrence_rule_services: owner full access" ON public.recurrence_rule_services TO authenticated USING ((EXISTS ( SELECT 1 FROM public.recurrence_rules r WHERE ((r.id = recurrence_rule_services.rule_id) AND (r.owner_id = auth.uid()))))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.recurrence_rules r WHERE ((r.id = recurrence_rule_services.rule_id) AND (r.owner_id = auth.uid()))))); -- -- Name: recurrence_rules; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.recurrence_rules ENABLE ROW LEVEL SECURITY; -- -- Name: recurrence_rules recurrence_rules_clinic_read; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY recurrence_rules_clinic_read ON public.recurrence_rules FOR SELECT USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.view'::text))); -- -- Name: recurrence_rules recurrence_rules_clinic_write; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY recurrence_rules_clinic_write ON public.recurrence_rules USING ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))) WITH CHECK ((public.is_clinic_tenant(tenant_id) AND public.is_tenant_member(tenant_id) AND public.tenant_has_feature(tenant_id, 'agenda.edit'::text))); -- -- Name: recurrence_rules recurrence_rules_owner; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY recurrence_rules_owner ON public.recurrence_rules TO authenticated USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: subscription_intents_legacy saas_admin can read subscription_intents; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "saas_admin can read subscription_intents" ON public.subscription_intents_legacy FOR SELECT TO authenticated USING ((EXISTS ( SELECT 1 FROM public.saas_admins a WHERE (a.user_id = auth.uid())))); -- -- Name: subscription_intents_legacy saas_admin can update subscription_intents; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "saas_admin can update subscription_intents" ON public.subscription_intents_legacy FOR UPDATE TO authenticated USING ((EXISTS ( SELECT 1 FROM public.saas_admins a WHERE (a.user_id = auth.uid())))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.saas_admins a WHERE (a.user_id = auth.uid())))); -- -- Name: login_carousel_slides saas_admin_full; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY saas_admin_full ON public.login_carousel_slides USING ((EXISTS ( SELECT 1 FROM public.profiles WHERE ((profiles.id = auth.uid()) AND (profiles.role = 'saas_admin'::text))))); -- -- Name: saas_docs saas_admin_full_access; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY saas_admin_full_access ON public.saas_docs TO authenticated USING ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid())))); -- -- Name: saas_admins; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.saas_admins ENABLE ROW LEVEL SECURITY; -- -- Name: saas_admins saas_admins_select_self; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY saas_admins_select_self ON public.saas_admins FOR SELECT TO authenticated USING ((user_id = auth.uid())); -- -- Name: saas_doc_votos; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.saas_doc_votos ENABLE ROW LEVEL SECURITY; -- -- Name: saas_docs; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.saas_docs ENABLE ROW LEVEL SECURITY; -- -- Name: saas_faq; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.saas_faq ENABLE ROW LEVEL SECURITY; -- -- Name: saas_faq_itens; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.saas_faq_itens ENABLE ROW LEVEL SECURITY; -- -- Name: agenda_bloqueios select own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "select own" ON public.agenda_bloqueios FOR SELECT USING ((owner_id = auth.uid())); -- -- Name: services; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.services ENABLE ROW LEVEL SECURITY; -- -- Name: services services: owner full access; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "services: owner full access" ON public.services USING ((owner_id = auth.uid())) WITH CHECK ((owner_id = auth.uid())); -- -- Name: subscription_events; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.subscription_events ENABLE ROW LEVEL SECURITY; -- -- Name: subscription_events subscription_events_read_saas; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY subscription_events_read_saas ON public.subscription_events FOR SELECT USING (public.is_saas_admin()); -- -- Name: subscription_events subscription_events_write_saas; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY subscription_events_write_saas ON public.subscription_events FOR INSERT WITH CHECK (public.is_saas_admin()); -- -- Name: subscription_intents_legacy subscription_intents_insert_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY subscription_intents_insert_own ON public.subscription_intents_legacy FOR INSERT TO authenticated WITH CHECK ((user_id = auth.uid())); -- -- Name: subscription_intents_legacy; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.subscription_intents_legacy ENABLE ROW LEVEL SECURITY; -- -- Name: subscription_intents_legacy subscription_intents_select_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY subscription_intents_select_own ON public.subscription_intents_legacy FOR SELECT TO authenticated USING ((user_id = auth.uid())); -- -- Name: subscriptions; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.subscriptions ENABLE ROW LEVEL SECURITY; -- -- Name: subscriptions subscriptions read own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "subscriptions read own" ON public.subscriptions FOR SELECT TO authenticated USING ((user_id = auth.uid())); -- -- Name: subscriptions subscriptions: read if linked owner_users; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "subscriptions: read if linked owner_users" ON public.subscriptions FOR SELECT TO authenticated USING ((EXISTS ( SELECT 1 FROM public.owner_users ou WHERE ((ou.owner_id = subscriptions.user_id) AND (ou.user_id = auth.uid()))))); -- -- Name: subscriptions subscriptions_insert_own_personal; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY subscriptions_insert_own_personal ON public.subscriptions FOR INSERT TO authenticated WITH CHECK (((user_id = auth.uid()) AND (tenant_id IS NULL))); -- -- Name: subscriptions subscriptions_no_direct_update; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY subscriptions_no_direct_update ON public.subscriptions FOR UPDATE TO authenticated USING (false) WITH CHECK (false); -- -- Name: subscriptions subscriptions_read_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY subscriptions_read_own ON public.subscriptions FOR SELECT TO authenticated USING (((user_id = auth.uid()) OR public.is_saas_admin())); -- -- Name: subscriptions subscriptions_select_for_tenant_members; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY subscriptions_select_for_tenant_members ON public.subscriptions FOR SELECT TO authenticated USING (((tenant_id IS NOT NULL) AND (EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = subscriptions.tenant_id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text)))))); -- -- Name: subscriptions subscriptions_select_own_personal; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY subscriptions_select_own_personal ON public.subscriptions FOR SELECT TO authenticated USING (((user_id = auth.uid()) AND (tenant_id IS NULL))); -- -- Name: subscriptions subscriptions_update_only_saas_admin; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY subscriptions_update_only_saas_admin ON public.subscriptions FOR UPDATE TO authenticated USING (public.is_saas_admin()) WITH CHECK (public.is_saas_admin()); -- -- Name: support_sessions; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.support_sessions ENABLE ROW LEVEL SECURITY; -- -- Name: support_sessions support_sessions_saas_delete; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY support_sessions_saas_delete ON public.support_sessions FOR DELETE USING (((auth.uid() = admin_id) AND (EXISTS ( SELECT 1 FROM public.profiles WHERE ((profiles.id = auth.uid()) AND (profiles.role = 'saas_admin'::text)))))); -- -- Name: support_sessions support_sessions_saas_insert; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY support_sessions_saas_insert ON public.support_sessions FOR INSERT WITH CHECK (((auth.uid() = admin_id) AND (EXISTS ( SELECT 1 FROM public.profiles WHERE ((profiles.id = auth.uid()) AND (profiles.role = 'saas_admin'::text)))))); -- -- Name: support_sessions support_sessions_saas_select; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY support_sessions_saas_select ON public.support_sessions FOR SELECT USING (((auth.uid() = admin_id) AND (EXISTS ( SELECT 1 FROM public.profiles WHERE ((profiles.id = auth.uid()) AND (profiles.role = 'saas_admin'::text)))))); -- -- Name: email_templates_tenant tenant manages own overrides; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "tenant manages own overrides" ON public.email_templates_tenant USING ((tenant_id = auth.uid())) WITH CHECK ((tenant_id = auth.uid())); -- -- Name: email_layout_config tenant owns email layout config; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "tenant owns email layout config" ON public.email_layout_config USING ((tenant_id = auth.uid())) WITH CHECK ((tenant_id = auth.uid())); -- -- Name: tenant_members; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.tenant_members ENABLE ROW LEVEL SECURITY; -- -- Name: tenant_members tenant_members_write_saas; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY tenant_members_write_saas ON public.tenant_members TO authenticated USING (public.is_saas_admin()) WITH CHECK (public.is_saas_admin()); -- -- Name: tenant_modules; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.tenant_modules ENABLE ROW LEVEL SECURITY; -- -- Name: tenant_modules tenant_modules_read_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY tenant_modules_read_own ON public.tenant_modules FOR SELECT TO authenticated USING (((owner_id = auth.uid()) OR public.is_saas_admin())); -- -- Name: tenant_modules tenant_modules_write_saas; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY tenant_modules_write_saas ON public.tenant_modules TO authenticated USING (public.is_saas_admin()) WITH CHECK (public.is_saas_admin()); -- -- Name: tenants; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.tenants ENABLE ROW LEVEL SECURITY; -- -- Name: tenants tenants_read_members; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY tenants_read_members ON public.tenants FOR SELECT TO authenticated USING ((public.is_saas_admin() OR (EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE ((tm.tenant_id = tenants.id) AND (tm.user_id = auth.uid()) AND (tm.status = 'active'::text)))))); -- -- Name: tenants tenants_write_saas; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY tenants_write_saas ON public.tenants TO authenticated USING (public.is_saas_admin()) WITH CHECK (public.is_saas_admin()); -- -- Name: therapist_payout_records; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.therapist_payout_records ENABLE ROW LEVEL SECURITY; -- -- Name: therapist_payout_records therapist_payout_records_self; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY therapist_payout_records_self ON public.therapist_payout_records USING ((EXISTS ( SELECT 1 FROM public.therapist_payouts tp WHERE ((tp.id = therapist_payout_records.payout_id) AND (tp.owner_id = auth.uid()))))) WITH CHECK ((EXISTS ( SELECT 1 FROM public.therapist_payouts tp WHERE ((tp.id = therapist_payout_records.payout_id) AND (tp.owner_id = auth.uid()))))); -- -- Name: therapist_payout_records therapist_payout_records_tenant_admin; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY therapist_payout_records_tenant_admin ON public.therapist_payout_records FOR SELECT USING ((EXISTS ( SELECT 1 FROM public.therapist_payouts tp WHERE ((tp.id = therapist_payout_records.payout_id) AND public.is_tenant_admin(tp.tenant_id))))); -- -- Name: therapist_payouts; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.therapist_payouts ENABLE ROW LEVEL SECURITY; -- -- Name: therapist_payouts therapist_payouts_self; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY therapist_payouts_self ON public.therapist_payouts USING ((auth.uid() = owner_id)) WITH CHECK ((auth.uid() = owner_id)); -- -- Name: therapist_payouts therapist_payouts_tenant_admin; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY therapist_payouts_tenant_admin ON public.therapist_payouts FOR SELECT USING (((tenant_id IS NOT NULL) AND public.is_tenant_admin(tenant_id))); -- -- Name: tenant_members tm_select_admin_all_members; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY tm_select_admin_all_members ON public.tenant_members FOR SELECT TO authenticated USING (public.is_tenant_admin(tenant_id)); -- -- Name: tenant_members tm_select_own_membership; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY tm_select_own_membership ON public.tenant_members FOR SELECT TO authenticated USING ((user_id = auth.uid())); -- -- Name: agenda_bloqueios update own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY "update own" ON public.agenda_bloqueios FOR UPDATE USING ((owner_id = auth.uid())); -- -- Name: user_settings; Type: ROW SECURITY; Schema: public; Owner: - -- ALTER TABLE public.user_settings ENABLE ROW LEVEL SECURITY; -- -- Name: user_settings user_settings_insert_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY user_settings_insert_own ON public.user_settings FOR INSERT WITH CHECK ((user_id = auth.uid())); -- -- Name: user_settings user_settings_select_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY user_settings_select_own ON public.user_settings FOR SELECT USING ((user_id = auth.uid())); -- -- Name: user_settings user_settings_update_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY user_settings_update_own ON public.user_settings FOR UPDATE USING ((user_id = auth.uid())) WITH CHECK ((user_id = auth.uid())); -- -- Name: saas_docs users_read_usuario_docs; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY users_read_usuario_docs ON public.saas_docs FOR SELECT TO authenticated USING (((ativo = true) AND (tipo_acesso = 'usuario'::text))); -- -- Name: saas_doc_votos votos_select_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY votos_select_own ON public.saas_doc_votos FOR SELECT TO authenticated USING ((user_id = auth.uid())); -- -- Name: saas_doc_votos votos_upsert_own; Type: POLICY; Schema: public; Owner: - -- CREATE POLICY votos_upsert_own ON public.saas_doc_votos TO authenticated USING ((user_id = auth.uid())) WITH CHECK ((user_id = auth.uid())); -- -- Name: messages; Type: ROW SECURITY; Schema: realtime; Owner: - -- ALTER TABLE realtime.messages ENABLE ROW LEVEL SECURITY; -- -- Name: objects agendador_storage_owner_delete; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY agendador_storage_owner_delete ON storage.objects FOR DELETE TO authenticated USING (((bucket_id = 'agendador'::text) AND ((storage.foldername(name))[1] = (auth.uid())::text))); -- -- Name: objects agendador_storage_owner_insert; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY agendador_storage_owner_insert ON storage.objects FOR INSERT TO authenticated WITH CHECK (((bucket_id = 'agendador'::text) AND ((storage.foldername(name))[1] = (auth.uid())::text))); -- -- Name: objects agendador_storage_owner_update; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY agendador_storage_owner_update ON storage.objects FOR UPDATE TO authenticated USING (((bucket_id = 'agendador'::text) AND ((storage.foldername(name))[1] = (auth.uid())::text))); -- -- Name: objects agendador_storage_public_read; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY agendador_storage_public_read ON storage.objects FOR SELECT USING ((bucket_id = 'agendador'::text)); -- -- Name: objects avatars authenticated upload; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY "avatars authenticated upload" ON storage.objects FOR INSERT WITH CHECK (((bucket_id = 'avatars'::text) AND (auth.role() = 'authenticated'::text) AND ((storage.foldername(name))[1] = (auth.uid())::text))); -- -- Name: objects avatars owner delete; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY "avatars owner delete" ON storage.objects FOR DELETE USING (((bucket_id = 'avatars'::text) AND ((storage.foldername(name))[1] = (auth.uid())::text))); -- -- Name: objects avatars owner update; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY "avatars owner update" ON storage.objects FOR UPDATE USING (((bucket_id = 'avatars'::text) AND ((storage.foldername(name))[1] = (auth.uid())::text))); -- -- Name: objects avatars public read; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY "avatars public read" ON storage.objects FOR SELECT USING ((bucket_id = 'avatars'::text)); -- -- Name: objects avatars_delete_own; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY avatars_delete_own ON storage.objects FOR DELETE TO authenticated USING (((bucket_id = 'avatars'::text) AND (name ~~ ((auth.uid())::text || '/%'::text)))); -- -- Name: objects avatars_delete_own_folder; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY avatars_delete_own_folder ON storage.objects FOR DELETE USING (((bucket_id = 'avatars'::text) AND (auth.role() = 'authenticated'::text) AND (name ~~ (('owners/'::text || auth.uid()) || '/%'::text)))); -- -- Name: objects avatars_insert_own; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY avatars_insert_own ON storage.objects FOR INSERT TO authenticated WITH CHECK (((bucket_id = 'avatars'::text) AND (name ~~ ((auth.uid())::text || '/%'::text)))); -- -- Name: objects avatars_insert_own_folder; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY avatars_insert_own_folder ON storage.objects FOR INSERT WITH CHECK (((bucket_id = 'avatars'::text) AND (auth.role() = 'authenticated'::text) AND (name ~~ (('owners/'::text || auth.uid()) || '/%'::text)))); -- -- Name: objects avatars_read; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY avatars_read ON storage.objects FOR SELECT USING ((bucket_id = 'avatars'::text)); -- -- Name: objects avatars_select_own; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY avatars_select_own ON storage.objects FOR SELECT TO authenticated USING (((bucket_id = 'avatars'::text) AND (name ~~ ((auth.uid())::text || '/%'::text)))); -- -- Name: objects avatars_update_own; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY avatars_update_own ON storage.objects FOR UPDATE TO authenticated USING (((bucket_id = 'avatars'::text) AND (name ~~ ((auth.uid())::text || '/%'::text)))) WITH CHECK (((bucket_id = 'avatars'::text) AND (name ~~ ((auth.uid())::text || '/%'::text)))); -- -- Name: objects avatars_update_own_folder; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY avatars_update_own_folder ON storage.objects FOR UPDATE USING (((bucket_id = 'avatars'::text) AND (auth.role() = 'authenticated'::text) AND (name ~~ (('owners/'::text || auth.uid()) || '/%'::text)))) WITH CHECK (((bucket_id = 'avatars'::text) AND (auth.role() = 'authenticated'::text) AND (name ~~ (('owners/'::text || auth.uid()) || '/%'::text)))); -- -- Name: buckets; Type: ROW SECURITY; Schema: storage; Owner: - -- ALTER TABLE storage.buckets ENABLE ROW LEVEL SECURITY; -- -- Name: buckets_analytics; Type: ROW SECURITY; Schema: storage; Owner: - -- ALTER TABLE storage.buckets_analytics ENABLE ROW LEVEL SECURITY; -- -- Name: buckets_vectors; Type: ROW SECURITY; Schema: storage; Owner: - -- ALTER TABLE storage.buckets_vectors ENABLE ROW LEVEL SECURITY; -- -- Name: iceberg_namespaces; Type: ROW SECURITY; Schema: storage; Owner: - -- ALTER TABLE storage.iceberg_namespaces ENABLE ROW LEVEL SECURITY; -- -- Name: iceberg_tables; Type: ROW SECURITY; Schema: storage; Owner: - -- ALTER TABLE storage.iceberg_tables ENABLE ROW LEVEL SECURITY; -- -- Name: objects intake_read_anon; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY intake_read_anon ON storage.objects FOR SELECT TO anon USING (((bucket_id = 'avatars'::text) AND (name ~~ 'intakes/%'::text))); -- -- Name: objects intake_read_public; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY intake_read_public ON storage.objects FOR SELECT USING (((bucket_id = 'avatars'::text) AND (name ~~ 'intakes/%'::text))); -- -- Name: objects intake_upload_anon; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY intake_upload_anon ON storage.objects FOR INSERT TO anon WITH CHECK (((bucket_id = 'avatars'::text) AND (name ~~ 'intakes/%'::text))); -- -- Name: objects intake_upload_public; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY intake_upload_public ON storage.objects FOR INSERT WITH CHECK (((bucket_id = 'avatars'::text) AND (name ~~ 'intakes/%'::text))); -- -- Name: migrations; Type: ROW SECURITY; Schema: storage; Owner: - -- ALTER TABLE storage.migrations ENABLE ROW LEVEL SECURITY; -- -- Name: objects; Type: ROW SECURITY; Schema: storage; Owner: - -- ALTER TABLE storage.objects ENABLE ROW LEVEL SECURITY; -- -- Name: objects public_read; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY public_read ON storage.objects FOR SELECT USING ((bucket_id = 'saas-docs'::text)); -- -- Name: s3_multipart_uploads; Type: ROW SECURITY; Schema: storage; Owner: - -- ALTER TABLE storage.s3_multipart_uploads ENABLE ROW LEVEL SECURITY; -- -- Name: s3_multipart_uploads_parts; Type: ROW SECURITY; Schema: storage; Owner: - -- ALTER TABLE storage.s3_multipart_uploads_parts ENABLE ROW LEVEL SECURITY; -- -- Name: objects saas_admin_delete; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY saas_admin_delete ON storage.objects FOR DELETE TO authenticated USING (((bucket_id = 'saas-docs'::text) AND (EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid()))))); -- -- Name: objects saas_admin_upload; Type: POLICY; Schema: storage; Owner: - -- CREATE POLICY saas_admin_upload ON storage.objects FOR INSERT TO authenticated WITH CHECK (((bucket_id = 'saas-docs'::text) AND (EXISTS ( SELECT 1 FROM public.saas_admins WHERE (saas_admins.user_id = auth.uid()))))); -- -- Name: vector_indexes; Type: ROW SECURITY; Schema: storage; Owner: - -- ALTER TABLE storage.vector_indexes ENABLE ROW LEVEL SECURITY; -- -- Name: supabase_realtime; Type: PUBLICATION; Schema: -; Owner: - -- CREATE PUBLICATION supabase_realtime WITH (publish = 'insert, update, delete, truncate'); -- -- Name: supabase_realtime_messages_publication; Type: PUBLICATION; Schema: -; Owner: - -- CREATE PUBLICATION supabase_realtime_messages_publication WITH (publish = 'insert, update, delete, truncate'); -- -- Name: supabase_realtime notifications; Type: PUBLICATION TABLE; Schema: public; Owner: - -- ALTER PUBLICATION supabase_realtime ADD TABLE ONLY public.notifications; -- -- Name: supabase_realtime_messages_publication messages; Type: PUBLICATION TABLE; Schema: realtime; Owner: - -- ALTER PUBLICATION supabase_realtime_messages_publication ADD TABLE ONLY realtime.messages; -- -- Name: issue_graphql_placeholder; Type: EVENT TRIGGER; Schema: -; Owner: - -- CREATE EVENT TRIGGER issue_graphql_placeholder ON sql_drop WHEN TAG IN ('DROP EXTENSION') EXECUTE FUNCTION extensions.set_graphql_placeholder(); -- -- Name: issue_pg_cron_access; Type: EVENT TRIGGER; Schema: -; Owner: - -- CREATE EVENT TRIGGER issue_pg_cron_access ON ddl_command_end WHEN TAG IN ('CREATE EXTENSION') EXECUTE FUNCTION extensions.grant_pg_cron_access(); -- -- Name: issue_pg_graphql_access; Type: EVENT TRIGGER; Schema: -; Owner: - -- CREATE EVENT TRIGGER issue_pg_graphql_access ON ddl_command_end WHEN TAG IN ('CREATE FUNCTION') EXECUTE FUNCTION extensions.grant_pg_graphql_access(); -- -- Name: issue_pg_net_access; Type: EVENT TRIGGER; Schema: -; Owner: - -- CREATE EVENT TRIGGER issue_pg_net_access ON ddl_command_end WHEN TAG IN ('CREATE EXTENSION') EXECUTE FUNCTION extensions.grant_pg_net_access(); -- -- Name: pgrst_ddl_watch; Type: EVENT TRIGGER; Schema: -; Owner: - -- CREATE EVENT TRIGGER pgrst_ddl_watch ON ddl_command_end EXECUTE FUNCTION extensions.pgrst_ddl_watch(); -- -- Name: pgrst_drop_watch; Type: EVENT TRIGGER; Schema: -; Owner: - -- CREATE EVENT TRIGGER pgrst_drop_watch ON sql_drop EXECUTE FUNCTION extensions.pgrst_drop_watch(); -- -- PostgreSQL database dump complete -- \unrestrict ttCln7QPzFfEuTFQuEAFDv3kegteolKfFYEJ8UXnE3ahDRWx0ZUEy3J0kR47I2X