-- ═══════════════════════════════════════════════════════════════════════════ -- Agendador Online — tabelas de configuração e solicitações -- ═══════════════════════════════════════════════════════════════════════════ -- ── 1. agendador_configuracoes ────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS "public"."agendador_configuracoes" ( "owner_id" "uuid" NOT NULL, "tenant_id" "uuid", -- PRO / Ativação "ativo" boolean DEFAULT false NOT NULL, "link_slug" "text", -- Identidade Visual "imagem_fundo_url" "text", "imagem_header_url" "text", "logomarca_url" "text", "cor_primaria" "text" DEFAULT '#4b6bff', -- Perfil Público "nome_exibicao" "text", "endereco" "text", "botao_como_chegar_ativo" boolean DEFAULT true NOT NULL, "maps_url" "text", -- Fluxo de Agendamento "modo_aprovacao" "text" DEFAULT 'aprovacao' NOT NULL, "modalidade" "text" DEFAULT 'presencial' 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 "pagamento_obrigatorio" boolean DEFAULT false NOT NULL, "pix_chave" "text", "pix_countdown_minutos" integer DEFAULT 20 NOT NULL, -- Triagem & Conformidade "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, -- Textos "mensagem_boas_vindas" "text", "texto_como_se_preparar" "text", "texto_termos_lgpd" "text", -- Timestamps "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT "agendador_configuracoes_pkey" PRIMARY KEY ("owner_id"), CONSTRAINT "agendador_configuracoes_owner_fk" FOREIGN KEY ("owner_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE, CONSTRAINT "agendador_configuracoes_tenant_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE CASCADE, CONSTRAINT "agendador_configuracoes_modo_check" CHECK ("modo_aprovacao" = ANY (ARRAY['automatico','aprovacao'])), CONSTRAINT "agendador_configuracoes_modalidade_check" CHECK ("modalidade" = ANY (ARRAY['presencial','online','ambos'])), CONSTRAINT "agendador_configuracoes_duracao_check" CHECK ("duracao_sessao_min" >= 10 AND "duracao_sessao_min" <= 240), CONSTRAINT "agendador_configuracoes_antecedencia_check" CHECK ("antecedencia_minima_horas" >= 0 AND "antecedencia_minima_horas" <= 720), CONSTRAINT "agendador_configuracoes_reserva_check" CHECK ("reserva_horas" >= 1 AND "reserva_horas" <= 48), 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) ); ALTER TABLE "public"."agendador_configuracoes" ENABLE ROW LEVEL SECURITY; DROP POLICY IF EXISTS "agendador_cfg_select" ON "public"."agendador_configuracoes"; CREATE POLICY "agendador_cfg_select" ON "public"."agendador_configuracoes" FOR SELECT USING (auth.uid() = owner_id); DROP POLICY IF EXISTS "agendador_cfg_write" ON "public"."agendador_configuracoes"; CREATE POLICY "agendador_cfg_write" ON "public"."agendador_configuracoes" USING (auth.uid() = owner_id) WITH CHECK (auth.uid() = owner_id); CREATE INDEX IF NOT EXISTS "agendador_cfg_tenant_idx" ON "public"."agendador_configuracoes" ("tenant_id"); -- ── 2. agendador_solicitacoes ─────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS "public"."agendador_solicitacoes" ( "id" "uuid" DEFAULT gen_random_uuid() NOT NULL, "owner_id" "uuid" NOT NULL, "tenant_id" "uuid", -- Dados do paciente "paciente_nome" "text" NOT NULL, "paciente_sobrenome" "text", "paciente_email" "text" NOT NULL, "paciente_celular" "text", "paciente_cpf" "text", -- Agendamento solicitado "tipo" "text" NOT NULL, "modalidade" "text" NOT NULL, "data_solicitada" date NOT NULL, "hora_solicitada" time NOT NULL, -- Reserva temporária "reservado_ate" timestamp with time zone, -- Triagem "motivo" "text", "como_conheceu" "text", -- Pagamento "pix_status" "text" DEFAULT 'pendente', "pix_pago_em" timestamp with time zone, -- Status geral "status" "text" DEFAULT 'pendente' NOT NULL, "recusado_motivo" "text", -- Autorização "autorizado_em" timestamp with time zone, "autorizado_por" "uuid", -- Vínculos internos "user_id" "uuid", "patient_id" "uuid", "evento_id" "uuid", -- Timestamps "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT "agendador_solicitacoes_pkey" PRIMARY KEY ("id"), CONSTRAINT "agendador_sol_owner_fk" FOREIGN KEY ("owner_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE, CONSTRAINT "agendador_sol_tenant_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE CASCADE, CONSTRAINT "agendador_sol_status_check" CHECK ("status" = ANY (ARRAY['pendente','autorizado','recusado','expirado'])), CONSTRAINT "agendador_sol_tipo_check" CHECK ("tipo" = ANY (ARRAY['primeira','retorno','reagendar'])), CONSTRAINT "agendador_sol_modalidade_check" CHECK ("modalidade" = ANY (ARRAY['presencial','online'])), CONSTRAINT "agendador_sol_pix_check" CHECK ("pix_status" IS NULL OR "pix_status" = ANY (ARRAY['pendente','pago','expirado'])) ); ALTER TABLE "public"."agendador_solicitacoes" ENABLE ROW LEVEL SECURITY; DROP POLICY IF EXISTS "agendador_sol_owner_select" ON "public"."agendador_solicitacoes"; CREATE POLICY "agendador_sol_owner_select" ON "public"."agendador_solicitacoes" FOR SELECT USING (auth.uid() = owner_id); DROP POLICY IF EXISTS "agendador_sol_owner_write" ON "public"."agendador_solicitacoes"; CREATE POLICY "agendador_sol_owner_write" ON "public"."agendador_solicitacoes" USING (auth.uid() = owner_id) WITH CHECK (auth.uid() = owner_id); CREATE INDEX IF NOT EXISTS "agendador_sol_owner_idx" ON "public"."agendador_solicitacoes" ("owner_id", "status"); CREATE INDEX IF NOT EXISTS "agendador_sol_tenant_idx" ON "public"."agendador_solicitacoes" ("tenant_id"); CREATE INDEX IF NOT EXISTS "agendador_sol_data_idx" ON "public"."agendador_solicitacoes" ("data_solicitada", "hora_solicitada");