From 13b3951a1e70c3134b6f3a89e63e953fa5320898 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 17:46:18 +0000 Subject: [PATCH] Changes Co-authored-by: domfelipe <53182096+domfelipe@users.noreply.github.com> --- src/integrations/supabase/types.ts | 50 ++++++++++++++- ...5_bf18cc9e-7019-4b50-bc80-ddfd10c3ce3b.sql | 62 +++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 supabase/migrations/20260417174615_bf18cc9e-7019-4b50-bc80-ddfd10c3ce3b.sql diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts index c3e0690..21418a2 100644 --- a/src/integrations/supabase/types.ts +++ b/src/integrations/supabase/types.ts @@ -97,6 +97,33 @@ export type Database = { } Relationships: [] } + paddle_webhook_events: { + Row: { + environment: string + event_type: string + id: string + paddle_event_id: string + payload: Json | null + processed_at: string + } + Insert: { + environment: string + event_type: string + id?: string + paddle_event_id: string + payload?: Json | null + processed_at?: string + } + Update: { + environment?: string + event_type?: string + id?: string + paddle_event_id?: string + payload?: Json | null + processed_at?: string + } + Relationships: [] + } plans: { Row: { created_at: string @@ -154,6 +181,7 @@ export type Database = { full_name: string id: string onboarding_completed: boolean + paddle_customer_id: string | null phone: string | null stripe_customer_id: string | null updated_at: string @@ -166,6 +194,7 @@ export type Database = { full_name?: string id: string onboarding_completed?: boolean + paddle_customer_id?: string | null phone?: string | null stripe_customer_id?: string | null updated_at?: string @@ -178,6 +207,7 @@ export type Database = { full_name?: string id?: string onboarding_completed?: boolean + paddle_customer_id?: string | null phone?: string | null stripe_customer_id?: string | null updated_at?: string @@ -215,8 +245,13 @@ export type Database = { created_at: string current_period_end: string | null current_period_start: string | null + environment: string id: string + paddle_customer_id: string | null + paddle_subscription_id: string | null plan_id: string | null + price_id: string | null + product_id: string | null status: string stripe_subscription_id: string | null updated_at: string @@ -228,8 +263,13 @@ export type Database = { created_at?: string current_period_end?: string | null current_period_start?: string | null + environment?: string id?: string + paddle_customer_id?: string | null + paddle_subscription_id?: string | null plan_id?: string | null + price_id?: string | null + product_id?: string | null status: string stripe_subscription_id?: string | null updated_at?: string @@ -241,8 +281,13 @@ export type Database = { created_at?: string current_period_end?: string | null current_period_start?: string | null + environment?: string id?: string + paddle_customer_id?: string | null + paddle_subscription_id?: string | null plan_id?: string | null + price_id?: string | null + product_id?: string | null status?: string stripe_subscription_id?: string | null updated_at?: string @@ -270,7 +315,10 @@ export type Database = { [_ in never]: never } Functions: { - [_ in never]: never + has_active_subscription: { + Args: { check_env?: string; user_uuid: string } + Returns: boolean + } } Enums: { [_ in never]: never diff --git a/supabase/migrations/20260417174615_bf18cc9e-7019-4b50-bc80-ddfd10c3ce3b.sql b/supabase/migrations/20260417174615_bf18cc9e-7019-4b50-bc80-ddfd10c3ce3b.sql new file mode 100644 index 0000000..3370c72 --- /dev/null +++ b/supabase/migrations/20260417174615_bf18cc9e-7019-4b50-bc80-ddfd10c3ce3b.sql @@ -0,0 +1,62 @@ +-- Migrar tabela subscriptions para o formato Paddle +ALTER TABLE public.subscriptions + ADD COLUMN IF NOT EXISTS paddle_subscription_id text, + ADD COLUMN IF NOT EXISTS paddle_customer_id text, + ADD COLUMN IF NOT EXISTS product_id text, + ADD COLUMN IF NOT EXISTS price_id text, + ADD COLUMN IF NOT EXISTS environment text NOT NULL DEFAULT 'sandbox'; + +-- Índices +CREATE UNIQUE INDEX IF NOT EXISTS idx_subscriptions_paddle_id + ON public.subscriptions(paddle_subscription_id) + WHERE paddle_subscription_id IS NOT NULL; + +CREATE INDEX IF NOT EXISTS idx_subscriptions_user_id ON public.subscriptions(user_id); + +-- Constraint única (user_id, environment) para upsert idempotente do webhook +CREATE UNIQUE INDEX IF NOT EXISTS idx_subscriptions_user_env + ON public.subscriptions(user_id, environment); + +-- Adicionar paddle_customer_id ao profiles (substitui stripe_customer_id conceitualmente) +ALTER TABLE public.profiles + ADD COLUMN IF NOT EXISTS paddle_customer_id text; + +-- Função utilitária para checar assinatura ativa +CREATE OR REPLACE FUNCTION public.has_active_subscription( + user_uuid uuid, + check_env text DEFAULT 'live' +) +RETURNS boolean +LANGUAGE sql +STABLE +SECURITY DEFINER +SET search_path = public +AS $$ + SELECT EXISTS ( + SELECT 1 FROM public.subscriptions + WHERE user_id = user_uuid + AND environment = check_env + AND status IN ('active', 'trialing') + AND (current_period_end IS NULL OR current_period_end > now()) + ); +$$; + +-- Trigger updated_at na subscriptions +DROP TRIGGER IF EXISTS update_subscriptions_updated_at ON public.subscriptions; +CREATE TRIGGER update_subscriptions_updated_at + BEFORE UPDATE ON public.subscriptions + FOR EACH ROW + EXECUTE FUNCTION public.update_updated_at_column(); + +-- Tabela de eventos de webhook (idempotência) — renomeando conceitualmente para paddle +CREATE TABLE IF NOT EXISTS public.paddle_webhook_events ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + paddle_event_id text NOT NULL UNIQUE, + event_type text NOT NULL, + environment text NOT NULL, + payload jsonb, + processed_at timestamptz NOT NULL DEFAULT now() +); + +ALTER TABLE public.paddle_webhook_events ENABLE ROW LEVEL SECURITY; +-- Sem políticas: apenas service_role acessa \ No newline at end of file