

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_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;


CREATE EXTENSION IF NOT EXISTS "pg_cron" WITH SCHEMA "pg_catalog";






CREATE SCHEMA IF NOT EXISTS "graphile_worker";


ALTER SCHEMA "graphile_worker" OWNER TO "postgres";


CREATE EXTENSION IF NOT EXISTS "pgsodium";






COMMENT ON SCHEMA "public" IS 'standard public schema';



CREATE SCHEMA IF NOT EXISTS "stripe";


ALTER SCHEMA "stripe" OWNER TO "postgres";


CREATE EXTENSION IF NOT EXISTS "pg_graphql" WITH SCHEMA "graphql";






CREATE EXTENSION IF NOT EXISTS "pg_stat_statements" WITH SCHEMA "extensions";






CREATE EXTENSION IF NOT EXISTS "pgcrypto" WITH SCHEMA "extensions";






CREATE EXTENSION IF NOT EXISTS "pgjwt" WITH SCHEMA "extensions";






CREATE EXTENSION IF NOT EXISTS "pgtap" WITH SCHEMA "extensions";






CREATE EXTENSION IF NOT EXISTS "supabase_vault" WITH SCHEMA "vault";






CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA "extensions";






CREATE EXTENSION IF NOT EXISTS "wrappers" WITH SCHEMA "extensions";






CREATE TYPE "graphile_worker"."job_spec" AS (
	"identifier" "text",
	"payload" "json",
	"queue_name" "text",
	"run_at" timestamp with time zone,
	"max_attempts" smallint,
	"job_key" "text",
	"priority" smallint,
	"flags" "text"[]
);


ALTER TYPE "graphile_worker"."job_spec" OWNER TO "postgres";


CREATE TYPE "public"."devis_status" AS ENUM (
    'draft',
    'sent',
    'accepted',
    'rejected',
    'expired'
);


ALTER TYPE "public"."devis_status" OWNER TO "postgres";


CREATE TYPE "public"."subscription_plan" AS ENUM (
    'none',
    'trial',
    'standard'
);


ALTER TYPE "public"."subscription_plan" OWNER TO "postgres";


CREATE TYPE "public"."time_range" AS (
	"start_time" time with time zone,
	"end_time" time with time zone
);


ALTER TYPE "public"."time_range" OWNER TO "postgres";


CREATE TYPE "stripe"."invoice_status" AS ENUM (
    'draft',
    'open',
    'paid',
    'uncollectible',
    'void',
    'deleted'
);


ALTER TYPE "stripe"."invoice_status" OWNER TO "postgres";


CREATE TYPE "stripe"."pricing_tiers" AS ENUM (
    'graduated',
    'volume'
);


ALTER TYPE "stripe"."pricing_tiers" OWNER TO "postgres";


CREATE TYPE "stripe"."pricing_type" AS ENUM (
    'one_time',
    'recurring'
);


ALTER TYPE "stripe"."pricing_type" OWNER TO "postgres";


CREATE TYPE "stripe"."subscription_schedule_status" AS ENUM (
    'not_started',
    'active',
    'completed',
    'released',
    'canceled'
);


ALTER TYPE "stripe"."subscription_schedule_status" OWNER TO "postgres";


CREATE TYPE "stripe"."subscription_status" AS ENUM (
    'trialing',
    'active',
    'canceled',
    'incomplete',
    'incomplete_expired',
    'past_due',
    'unpaid',
    'paused'
);


ALTER TYPE "stripe"."subscription_status" OWNER TO "postgres";

SET default_tablespace = '';

SET default_table_access_method = "heap";


CREATE TABLE IF NOT EXISTS "graphile_worker"."_private_jobs" (
    "id" bigint NOT NULL,
    "job_queue_id" integer,
    "task_id" integer NOT NULL,
    "payload" "json" DEFAULT '{}'::"json" NOT NULL,
    "priority" smallint DEFAULT 0 NOT NULL,
    "run_at" timestamp with time zone DEFAULT "now"() NOT NULL,
    "attempts" smallint DEFAULT 0 NOT NULL,
    "max_attempts" smallint DEFAULT 25 NOT NULL,
    "last_error" "text",
    "created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
    "updated_at" timestamp with time zone DEFAULT "now"() NOT NULL,
    "key" "text",
    "locked_at" timestamp with time zone,
    "locked_by" "text",
    "revision" integer DEFAULT 0 NOT NULL,
    "flags" "jsonb",
    "is_available" boolean GENERATED ALWAYS AS ((("locked_at" IS NULL) AND ("attempts" < "max_attempts"))) STORED NOT NULL,
    CONSTRAINT "jobs_key_check" CHECK ((("length"("key") > 0) AND ("length"("key") <= 512))),
    CONSTRAINT "jobs_max_attempts_check" CHECK (("max_attempts" >= 1))
);


ALTER TABLE "graphile_worker"."_private_jobs" OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "graphile_worker"."add_job"("identifier" "text", "payload" "json" DEFAULT NULL::"json", "queue_name" "text" DEFAULT NULL::"text", "run_at" timestamp with time zone DEFAULT NULL::timestamp with time zone, "max_attempts" integer DEFAULT NULL::integer, "job_key" "text" DEFAULT NULL::"text", "priority" integer DEFAULT NULL::integer, "flags" "text"[] DEFAULT NULL::"text"[], "job_key_mode" "text" DEFAULT 'replace'::"text") RETURNS "graphile_worker"."_private_jobs"
    LANGUAGE "plpgsql"
    AS $$
declare
  v_job "graphile_worker"._private_jobs;
begin
  if (job_key is null or job_key_mode is null or job_key_mode in ('replace', 'preserve_run_at')) then
    select * into v_job
    from "graphile_worker".add_jobs(
      ARRAY[(
        identifier,
        payload,
        queue_name,
        run_at,
        max_attempts::smallint,
        job_key,
        priority::smallint,
        flags
      )::"graphile_worker".job_spec],
      (job_key_mode = 'preserve_run_at')
    )
    limit 1;
    return v_job;
  elsif job_key_mode = 'unsafe_dedupe' then
    -- Ensure all the tasks exist
    insert into "graphile_worker"._private_tasks as tasks (identifier)
    values (add_job.identifier)
    on conflict do nothing;
    -- Ensure all the queues exist
    if add_job.queue_name is not null then
      insert into "graphile_worker"._private_job_queues as job_queues (queue_name)
      values (add_job.queue_name)
      on conflict do nothing;
    end if;
    -- Insert job, but if one already exists then do nothing, even if the
    -- existing job has already started (and thus represents an out-of-date
    -- world state). This is dangerous because it means that whatever state
    -- change triggered this add_job may not be acted upon (since it happened
    -- after the existing job started executing, but no further job is being
    -- scheduled), but it is useful in very rare circumstances for
    -- de-duplication. If in doubt, DO NOT USE THIS.
    insert into "graphile_worker"._private_jobs as jobs (
      job_queue_id,
      task_id,
      payload,
      run_at,
      max_attempts,
      key,
      priority,
      flags
    )
      select
        job_queues.id,
        tasks.id,
        coalesce(add_job.payload, '{}'::json),
        coalesce(add_job.run_at, now()),
        coalesce(add_job.max_attempts::smallint, 25::smallint),
        add_job.job_key,
        coalesce(add_job.priority::smallint, 0::smallint),
        (
          select jsonb_object_agg(flag, true)
          from unnest(add_job.flags) as item(flag)
        )
      from "graphile_worker"._private_tasks as tasks
      left join "graphile_worker"._private_job_queues as job_queues
      on job_queues.queue_name = add_job.queue_name
      where tasks.identifier = add_job.identifier
    on conflict (key)
      -- Bump the updated_at so that there's something to return
      do update set
        revision = jobs.revision + 1,
        updated_at = now()
      returning *
      into v_job;
    if v_job.revision = 0 then
      perform pg_notify('jobs:insert', '{"r":' || random()::text || ',"count":1}');
    end if;
    return v_job;
  else
    raise exception 'Invalid job_key_mode value, expected ''replace'', ''preserve_run_at'' or ''unsafe_dedupe''.' using errcode = 'GWBKM';
  end if;
end;
$$;


ALTER FUNCTION "graphile_worker"."add_job"("identifier" "text", "payload" "json", "queue_name" "text", "run_at" timestamp with time zone, "max_attempts" integer, "job_key" "text", "priority" integer, "flags" "text"[], "job_key_mode" "text") OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "graphile_worker"."add_jobs"("specs" "graphile_worker"."job_spec"[], "job_key_preserve_run_at" boolean DEFAULT false) RETURNS SETOF "graphile_worker"."_private_jobs"
    LANGUAGE "plpgsql"
    AS $$
begin
  -- Ensure all the tasks exist
  insert into "graphile_worker"._private_tasks as tasks (identifier)
  select distinct spec.identifier
  from unnest(specs) spec
  on conflict do nothing;
  -- Ensure all the queues exist
  insert into "graphile_worker"._private_job_queues as job_queues (queue_name)
  select distinct spec.queue_name
  from unnest(specs) spec
  where spec.queue_name is not null
  on conflict do nothing;
  -- Ensure any locked jobs have their key cleared - in the case of locked
  -- existing job create a new job instead as it must have already started
  -- executing (i.e. it's world state is out of date, and the fact add_job
  -- has been called again implies there's new information that needs to be
  -- acted upon).
  update "graphile_worker"._private_jobs as jobs
  set
    key = null,
    attempts = jobs.max_attempts,
    updated_at = now()
  from unnest(specs) spec
  where spec.job_key is not null
  and jobs.key = spec.job_key
  and is_available is not true;

  -- WARNING: this count is not 100% accurate; 'on conflict' clause will cause it to be an overestimate
  perform pg_notify('jobs:insert', '{"r":' || random()::text || ',"count":' || array_length(specs, 1)::text || '}');

  -- TODO: is there a risk that a conflict could occur depending on the
  -- isolation level?
  return query insert into "graphile_worker"._private_jobs as jobs (
    job_queue_id,
    task_id,
    payload,
    run_at,
    max_attempts,
    key,
    priority,
    flags
  )
    select
      job_queues.id,
      tasks.id,
      coalesce(spec.payload, '{}'::json),
      coalesce(spec.run_at, now()),
      coalesce(spec.max_attempts, 25),
      spec.job_key,
      coalesce(spec.priority, 0),
      (
        select jsonb_object_agg(flag, true)
        from unnest(spec.flags) as item(flag)
      )
    from unnest(specs) spec
    inner join "graphile_worker"._private_tasks as tasks
    on tasks.identifier = spec.identifier
    left join "graphile_worker"._private_job_queues as job_queues
    on job_queues.queue_name = spec.queue_name
  on conflict (key) do update set
    job_queue_id = excluded.job_queue_id,
    task_id = excluded.task_id,
    payload =
      case
      when json_typeof(jobs.payload) = 'array' and json_typeof(excluded.payload) = 'array' then
        (jobs.payload::jsonb || excluded.payload::jsonb)::json
      else
        excluded.payload
      end,
    max_attempts = excluded.max_attempts,
    run_at = (case
      when job_key_preserve_run_at is true and jobs.attempts = 0 then jobs.run_at
      else excluded.run_at
    end),
    priority = excluded.priority,
    revision = jobs.revision + 1,
    flags = excluded.flags,
    -- always reset error/retry state
    attempts = 0,
    last_error = null,
    updated_at = now()
  where jobs.locked_at is null
  returning *;
end;
$$;


ALTER FUNCTION "graphile_worker"."add_jobs"("specs" "graphile_worker"."job_spec"[], "job_key_preserve_run_at" boolean) OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "graphile_worker"."complete_jobs"("job_ids" bigint[]) RETURNS SETOF "graphile_worker"."_private_jobs"
    LANGUAGE "sql"
    AS $$
  delete from "graphile_worker"._private_jobs as jobs
    where id = any(job_ids)
    and (
      locked_at is null
    or
      locked_at < now() - interval '4 hours'
    )
    returning *;
$$;


ALTER FUNCTION "graphile_worker"."complete_jobs"("job_ids" bigint[]) OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "graphile_worker"."force_unlock_workers"("worker_ids" "text"[]) RETURNS "void"
    LANGUAGE "sql"
    AS $$
update "graphile_worker"._private_jobs as jobs
set locked_at = null, locked_by = null
where locked_by = any(worker_ids);
update "graphile_worker"._private_job_queues as job_queues
set locked_at = null, locked_by = null
where locked_by = any(worker_ids);
$$;


ALTER FUNCTION "graphile_worker"."force_unlock_workers"("worker_ids" "text"[]) OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "graphile_worker"."permanently_fail_jobs"("job_ids" bigint[], "error_message" "text" DEFAULT NULL::"text") RETURNS SETOF "graphile_worker"."_private_jobs"
    LANGUAGE "sql"
    AS $$
  update "graphile_worker"._private_jobs as jobs
    set
      last_error = coalesce(error_message, 'Manually marked as failed'),
      attempts = max_attempts,
      updated_at = now()
    where id = any(job_ids)
    and (
      locked_at is null
    or
      locked_at < NOW() - interval '4 hours'
    )
    returning *;
$$;


ALTER FUNCTION "graphile_worker"."permanently_fail_jobs"("job_ids" bigint[], "error_message" "text") OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "graphile_worker"."remove_job"("job_key" "text") RETURNS "graphile_worker"."_private_jobs"
    LANGUAGE "plpgsql" STRICT
    AS $$
declare
  v_job "graphile_worker"._private_jobs;
begin
  -- Delete job if not locked
  delete from "graphile_worker"._private_jobs as jobs
    where key = job_key
    and (
      locked_at is null
    or
      locked_at < NOW() - interval '4 hours'
    )
  returning * into v_job;
  if not (v_job is null) then
    perform pg_notify('jobs:insert', '{"r":' || random()::text || ',"count":-1}');
    return v_job;
  end if;
  -- Otherwise prevent job from retrying, and clear the key
  update "graphile_worker"._private_jobs as jobs
  set
    key = null,
    attempts = jobs.max_attempts,
    updated_at = now()
  where key = job_key
  returning * into v_job;
  return v_job;
end;
$$;


ALTER FUNCTION "graphile_worker"."remove_job"("job_key" "text") OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "graphile_worker"."reschedule_jobs"("job_ids" bigint[], "run_at" timestamp with time zone DEFAULT NULL::timestamp with time zone, "priority" integer DEFAULT NULL::integer, "attempts" integer DEFAULT NULL::integer, "max_attempts" integer DEFAULT NULL::integer) RETURNS SETOF "graphile_worker"."_private_jobs"
    LANGUAGE "sql"
    AS $$
  update "graphile_worker"._private_jobs as jobs
    set
      run_at = coalesce(reschedule_jobs.run_at, jobs.run_at),
      priority = coalesce(reschedule_jobs.priority::smallint, jobs.priority),
      attempts = coalesce(reschedule_jobs.attempts::smallint, jobs.attempts),
      max_attempts = coalesce(reschedule_jobs.max_attempts::smallint, jobs.max_attempts),
      updated_at = now()
    where id = any(job_ids)
    and (
      locked_at is null
    or
      locked_at < NOW() - interval '4 hours'
    )
    returning *;
$$;


ALTER FUNCTION "graphile_worker"."reschedule_jobs"("job_ids" bigint[], "run_at" timestamp with time zone, "priority" integer, "attempts" integer, "max_attempts" integer) OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."create_last_signed_in_on_profiles"() RETURNS "trigger"
    LANGUAGE "plpgsql" SECURITY DEFINER
    AS $$
    begin
      IF (NEW.last_sign_in_at is null) THEN
        RETURN NULL;
      ELSE
        UPDATE public.profiles
        SET last_signed_in = NEW.last_sign_in_at
        WHERE id = (NEW.id)::uuid;
        RETURN NEW;
      END IF;
    END;
    $$;


ALTER FUNCTION "public"."create_last_signed_in_on_profiles"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."create_tablo_access_for_owner"() RETURNS "trigger"
    LANGUAGE "plpgsql" SECURITY DEFINER
    AS $$
BEGIN
    -- Insert a tablo_access record for the tablo owner
    INSERT INTO tablo_access (
        tablo_id,
        user_id,
        granted_by,
        is_active,
        is_admin
    ) VALUES (
        NEW.id,           -- tablo_id: the newly created tablo's id (now TEXT)
        NEW.owner_id,     -- user_id: the tablo owner gets access
        NEW.owner_id,     -- granted_by: self-granted by the owner
        TRUE,             -- is_active: access is active
        TRUE              -- is_admin: owner has admin privileges
    );
    
    RETURN NEW;
END;
$$;


ALTER FUNCTION "public"."create_tablo_access_for_owner"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."generate_random_string"("length" integer DEFAULT 24) RETURNS "text"
    LANGUAGE "plpgsql"
    AS $$
DECLARE
    chars TEXT := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    result TEXT := '';
    i INTEGER := 0;
BEGIN
    FOR i IN 1..length LOOP
        result := result || substr(chars, floor(random() * length(chars) + 1)::INTEGER, 1);
    END LOOP;
    RETURN result;
END;
$$;


ALTER FUNCTION "public"."generate_random_string"("length" integer) OWNER TO "postgres";


COMMENT ON FUNCTION "public"."generate_random_string"("length" integer) IS 'Generates a random alphanumeric string of specified length (default 24 characters)';



CREATE OR REPLACE FUNCTION "public"."get_my_active_subscription"() RETURNS TABLE("subscription_id" "text", "user_id" "uuid", "user_email" "text", "first_name" "text", "last_name" "text", "status" "text", "current_period_start" timestamp with time zone, "current_period_end" timestamp with time zone, "cancel_at_period_end" boolean, "product_name" "text", "currency" "text", "unit_amount" integer, "billing_interval" "text", "plan" "public"."subscription_plan")
    LANGUAGE "plpgsql" SECURITY DEFINER
    SET "search_path" TO 'public', 'stripe'
    AS $$
begin
  -- Only return data for the authenticated user
  return query
  select 
    s.id as subscription_id,
    (c.metadata->>'user_id')::uuid as user_id,
    p.email as user_email,
    p.first_name,
    p.last_name,
    s.status::text,
    to_timestamp(si.current_period_start) as current_period_start,
    to_timestamp(si.current_period_end) as current_period_end,
    s.cancel_at_period_end,
    pr.name as product_name,
    pc.currency,
    pc.unit_amount,
    pc.recurring->>'interval' as billing_interval,
    p.plan
  from stripe.subscriptions s
  inner join stripe.customers c on c.id = s.customer
  inner join stripe.subscription_items si on si.subscription = s.id
  inner join public.profiles p on p.id = (c.metadata->>'user_id')::uuid
  left join stripe.prices pc on pc.id = si.price
  left join stripe.products pr on pr.id = pc.product
  where (c.metadata->>'user_id')::uuid = auth.uid()  -- Filter by authenticated user only!
    and s.status::text in ('active', 'trialing')
    and si.current_period_end is not null
    and to_timestamp(si.current_period_end) > now()
  order by si.current_period_end desc
  limit 1;
end;
$$;


ALTER FUNCTION "public"."get_my_active_subscription"() OWNER TO "postgres";


COMMENT ON FUNCTION "public"."get_my_active_subscription"() IS 'Returns the current authenticated user''s active subscription (secure, RLS-compliant)';



CREATE OR REPLACE FUNCTION "public"."get_stripe_prices"() RETURNS TABLE("id" "text", "product" "text", "active" boolean, "currency" "text", "unit_amount" integer, "recurring" "jsonb", "created" integer, "metadata" "jsonb")
    LANGUAGE "plpgsql" SECURITY DEFINER
    AS $$
begin
  return query
  select 
    pr.id,
    pr.product,
    pr.active,
    pr.currency,
    pr.unit_amount,
    pr.recurring,
    pr.created,
    pr.metadata
  from stripe.prices pr
  where pr.active = true;
end;
$$;


ALTER FUNCTION "public"."get_stripe_prices"() OWNER TO "postgres";


COMMENT ON FUNCTION "public"."get_stripe_prices"() IS 'Returns all active Stripe prices (public access)';



CREATE OR REPLACE FUNCTION "public"."get_stripe_products"() RETURNS TABLE("id" "text", "name" "text", "description" "text", "active" boolean, "created" integer, "metadata" "jsonb")
    LANGUAGE "plpgsql" SECURITY DEFINER
    AS $$
begin
  return query
  select 
    p.id,
    p.name,
    p.description,
    p.active,
    p.created,
    p.metadata
  from stripe.products p
  where p.active = true;
end;
$$;


ALTER FUNCTION "public"."get_stripe_products"() OWNER TO "postgres";


COMMENT ON FUNCTION "public"."get_stripe_products"() IS 'Returns all active Stripe products (public access)';



CREATE OR REPLACE FUNCTION "public"."get_user_stripe_customer"() RETURNS TABLE("id" "text", "email" "text", "user_id" "uuid", "created" integer, "metadata" "jsonb")
    LANGUAGE "plpgsql" SECURITY DEFINER
    AS $$
begin
  return query
  select 
    c.id,
    c.email,
    (c.metadata->>'user_id')::uuid as user_id,
    c.created,
    c.metadata
  from stripe.customers c
  where (c.metadata->>'user_id')::uuid = auth.uid();
end;
$$;


ALTER FUNCTION "public"."get_user_stripe_customer"() OWNER TO "postgres";


COMMENT ON FUNCTION "public"."get_user_stripe_customer"() IS 'Returns current user''s customer record from Stripe';



CREATE OR REPLACE FUNCTION "public"."get_user_stripe_customer_id"("user_uuid" "uuid") RETURNS "text"
    LANGUAGE "plpgsql" SECURITY DEFINER
    AS $$
declare
  customer_id text;
begin
  select id into customer_id
  from stripe.customers
  where (metadata->>'user_id')::uuid = user_uuid
  limit 1;
  
  return customer_id;
end;
$$;


ALTER FUNCTION "public"."get_user_stripe_customer_id"("user_uuid" "uuid") OWNER TO "postgres";


COMMENT ON FUNCTION "public"."get_user_stripe_customer_id"("user_uuid" "uuid") IS 'Returns the Stripe customer ID for a user';



CREATE OR REPLACE FUNCTION "public"."get_user_stripe_subscriptions"() RETURNS TABLE("id" "text", "customer" "text", "user_id" "uuid", "status" "text", "cancel_at_period_end" boolean, "current_period_start" integer, "current_period_end" integer, "created" integer, "canceled_at" integer, "trial_start" "jsonb", "trial_end" "jsonb", "price_id" "text", "quantity" integer, "metadata" "jsonb")
    LANGUAGE "plpgsql" SECURITY DEFINER
    AS $$
begin
  return query
  select 
    s.id,
    s.customer,
    (c.metadata->>'user_id')::uuid as user_id,
    s.status::text,
    s.cancel_at_period_end,
    si.current_period_start,
    si.current_period_end,
    s.created,
    s.canceled_at,
    s.trial_start,
    s.trial_end,
    si.price as price_id,
    si.quantity,
    s.metadata
  from stripe.subscriptions s
  inner join stripe.customers c on c.id = s.customer
  left join stripe.subscription_items si on si.subscription = s.id
  where (c.metadata->>'user_id')::uuid = auth.uid()
  order by s.created desc;
end;
$$;


ALTER FUNCTION "public"."get_user_stripe_subscriptions"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."get_user_subscription_status"("user_uuid" "uuid") RETURNS TABLE("subscription_id" "text", "status" "text", "current_period_start" integer, "current_period_end" integer, "cancel_at_period_end" boolean, "price_id" "text", "product_name" "text", "plan" "public"."subscription_plan")
    LANGUAGE "plpgsql" SECURITY DEFINER
    AS $$
begin
  return query
  select 
    s.id,
    s.status::text,
    si.current_period_start,
    si.current_period_end,
    s.cancel_at_period_end,
    si.price as price_id,
    p.name as product_name,
    case
      when s.status::text = 'trialing' then 'trial'::subscription_plan
      when s.status::text in ('active', 'past_due') then 'standard'::subscription_plan
      else 'none'::subscription_plan
    end as plan
  from stripe.subscriptions s
  inner join stripe.customers c on c.id = s.customer
  inner join stripe.subscription_items si on si.subscription = s.id
  left join stripe.prices pr on pr.id = si.price
  left join stripe.products p on p.id = pr.product
  where (c.metadata->>'user_id')::uuid = user_uuid
    and s.status::text in ('active', 'trialing', 'past_due')
    and si.current_period_end is not null
  order by si.current_period_end desc
  limit 1;
end;
$$;


ALTER FUNCTION "public"."get_user_subscription_status"("user_uuid" "uuid") OWNER TO "postgres";


COMMENT ON FUNCTION "public"."get_user_subscription_status"("user_uuid" "uuid") IS 'Returns current subscription details using subscription_items for accurate period dates';



CREATE OR REPLACE FUNCTION "public"."handle_event_types_standard_name"() RETURNS "trigger"
    LANGUAGE "plpgsql"
    AS $$
BEGIN
    -- On INSERT: automatically set standard_name from config->>'name', sanitized
    IF TG_OP = 'INSERT' THEN
        -- Extract name from config and sanitize it (replace spaces with hyphens, lowercase)
        NEW.standard_name = LOWER(REPLACE(TRIM(NEW.config->>'name'), ' ', '-'));
        RETURN NEW;
    END IF;
    
    -- On UPDATE: prevent standard_name modification by authenticated users
    IF TG_OP = 'UPDATE' THEN
        -- Only allow system/service role to modify standard_name
        -- If the current user is authenticated (not service_role), prevent standard_name changes
        IF current_setting('role') != 'service_role' AND OLD.standard_name IS DISTINCT FROM NEW.standard_name THEN RAISE EXCEPTION 'standard_name column cannot be modified'; END IF;
        
        -- If name in config changes, update standard_name accordingly (but only for non-authenticated users)
        IF current_setting('role') = 'service_role' AND OLD.config->>'name' IS DISTINCT FROM NEW.config->>'name' THEN
            NEW.standard_name = LOWER(REPLACE(TRIM(NEW.config->>'name'), ' ', '-'));
        END IF;
    END IF;
    
    RETURN NEW;
END;
$$;


ALTER FUNCTION "public"."handle_event_types_standard_name"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."handle_new_user"() RETURNS "trigger"
    LANGUAGE "plpgsql" SECURITY DEFINER
    AS $$
  DECLARE 
    name TEXT;
    first_name TEXT;
    last_name TEXT;
    is_temp BOOLEAN;
    email_prefix TEXT;
  BEGIN   
  -- Extract first_name and last_name from metadata
  first_name = new.raw_user_meta_data ->> 'first_name';
  last_name = new.raw_user_meta_data ->> 'last_name';
  
  -- If first_name is not provided, extract it from email (part before @)
  IF first_name IS NULL OR first_name = '' THEN
    email_prefix = SPLIT_PART(new.email, '@', 1);
    first_name = email_prefix;
  END IF;
  
  -- Determine the full name
  IF new.raw_user_meta_data ->> 'name' IS NOT NULL
  THEN
    name = new.raw_user_meta_data ->> 'name';
    -- If name is provided but not first/last, try to split it
    IF first_name IS NULL AND last_name IS NULL AND name IS NOT NULL THEN
      first_name = SPLIT_PART(name, ' ', 1);
      IF ARRAY_LENGTH(STRING_TO_ARRAY(name, ' '), 1) > 1 THEN
        last_name = SUBSTRING(name FROM LENGTH(SPLIT_PART(name, ' ', 1)) + 2);
      END IF;
    END IF;
  ELSE
    name = CONCAT(first_name, ' ', last_name);
  END IF;

  -- Check if the role is 'invited_user' in app_metadata
  IF COALESCE(new.raw_user_meta_data->>'role', '') = 'invited_user'
  THEN
    is_temp = TRUE;
  ELSE
    is_temp = FALSE;
  END IF;

  INSERT INTO public.profiles (id, name, email, avatar_url, first_name, last_name, is_temporary)
  VALUES (new.id, name, new.email, new.raw_user_meta_data ->> 'avatar_url', first_name, last_name, is_temp);
  
  RETURN new;
END;
  $$;


ALTER FUNCTION "public"."handle_new_user"() OWNER TO "postgres";


COMMENT ON FUNCTION "public"."handle_new_user"() IS 'Trigger function that creates a profile when a new user is created. Sets is_temporary=true for users with app_metadata.role=invited_user. Extracts first_name from email prefix (before @) if not provided in metadata.';



CREATE OR REPLACE FUNCTION "public"."is_paying_user"("user_uuid" "uuid") RETURNS boolean
    LANGUAGE "plpgsql" SECURITY DEFINER
    AS $$
declare
  has_active_subscription boolean;
begin
  select exists(
    select 1
    from stripe.subscriptions s
    inner join stripe.customers c on c.id = s.customer
    inner join stripe.subscription_items si on si.subscription = s.id
    where (c.metadata->>'user_id')::uuid = user_uuid
      and s.status::text in ('active', 'trialing')
      and si.current_period_end is not null
      and to_timestamp(si.current_period_end) > now()
  ) into has_active_subscription;
  
  return has_active_subscription;
end;
$$;


ALTER FUNCTION "public"."is_paying_user"("user_uuid" "uuid") OWNER TO "postgres";


COMMENT ON FUNCTION "public"."is_paying_user"("user_uuid" "uuid") IS 'Returns true if user has an active or trialing subscription';



CREATE OR REPLACE FUNCTION "public"."set_short_user_id"() RETURNS "trigger"
    LANGUAGE "plpgsql"
    AS $$
BEGIN
    NEW.short_user_id = LEFT(NEW.id::TEXT, 6);
    RETURN NEW;
END;
$$;


ALTER FUNCTION "public"."set_short_user_id"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."set_updated_at"() RETURNS "trigger"
    LANGUAGE "plpgsql"
    AS $$
begin
  new.updated_at = now();
  return NEW;
end;
$$;


ALTER FUNCTION "public"."set_updated_at"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."update_event_types_updated_at"() RETURNS "trigger"
    LANGUAGE "plpgsql"
    AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$;


ALTER FUNCTION "public"."update_event_types_updated_at"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."update_profile_subscription_status"() RETURNS "trigger"
    LANGUAGE "plpgsql" SECURITY DEFINER
    AS $$
declare
  v_user_id uuid;
  v_plan subscription_plan;
  v_customer_id text;
begin
  -- Get customer ID based on which table triggered this
  if TG_TABLE_NAME = 'subscriptions' then
    v_customer_id := new.customer;
  elsif TG_TABLE_NAME = 'subscription_items' then
    -- Get customer ID from the subscription
    select customer into v_customer_id
    from stripe.subscriptions
    where id = new.subscription;
  else
    -- Unknown table, skip
    return new;
  end if;
  
  -- Skip if no customer_id found
  if v_customer_id is null then
    return new;
  end if;
  
  -- Extract user_id from customer metadata
  select (metadata->>'user_id')::uuid into v_user_id
  from stripe.customers
  where id = v_customer_id;
  
  -- Skip if no user_id found
  if v_user_id is null then
    return new;
  end if;
  
  -- Determine the user's current plan
  select 
    case
      when exists(
        select 1
        from stripe.subscriptions s
        inner join stripe.customers c on c.id = s.customer
        inner join stripe.subscription_items si on si.subscription = s.id
        where (c.metadata->>'user_id')::uuid = v_user_id
          and s.status::text = 'trialing'
          and si.current_period_end is not null
          and to_timestamp(si.current_period_end) > now()
      ) then 'trial'::subscription_plan
      when exists(
        select 1
        from stripe.subscriptions s
        inner join stripe.customers c on c.id = s.customer
        inner join stripe.subscription_items si on si.subscription = s.id
        where (c.metadata->>'user_id')::uuid = v_user_id
          and s.status::text in ('active', 'past_due')
          and si.current_period_end is not null
          and to_timestamp(si.current_period_end) > now()
      ) then 'standard'::subscription_plan
      else 'none'::subscription_plan
    end into v_plan;
  
  -- Update the user's profile
  update public.profiles
  set plan = v_plan
  where id = v_user_id;
  
  return new;
end;
$$;


ALTER FUNCTION "public"."update_profile_subscription_status"() OWNER TO "postgres";


COMMENT ON FUNCTION "public"."update_profile_subscription_status"() IS 'Trigger function to update profile fields when subscription changes';



CREATE OR REPLACE FUNCTION "public"."update_tablo_invites_on_login"() RETURNS "trigger"
    LANGUAGE "plpgsql" SECURITY DEFINER
    AS $$
    BEGIN
      IF (NEW.last_sign_in_at IS NULL OR NEW.last_sign_in_at = OLD.last_sign_in_at) THEN
        RETURN NULL;
      ELSE
        -- Check if the user is temporary and update pending invites
        UPDATE public.tablo_invites 
        SET is_pending = FALSE
        WHERE invited_email = NEW.email
          AND is_pending = TRUE
          AND EXISTS (
            SELECT 1 FROM public.profiles 
            WHERE id = (NEW.id)::uuid 
            AND is_temporary = TRUE
          );
        RETURN NEW;
      END IF;
    END;
    $$;


ALTER FUNCTION "public"."update_tablo_invites_on_login"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."update_tablos_updated_at"() RETURNS "trigger"
    LANGUAGE "plpgsql"
    AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$;


ALTER FUNCTION "public"."update_tablos_updated_at"() OWNER TO "postgres";


CREATE OR REPLACE FUNCTION "public"."update_updated_at_column"() RETURNS "trigger"
    LANGUAGE "plpgsql"
    AS $$
begin
  new.updated_at = now();
  return new;
end;
$$;


ALTER FUNCTION "public"."update_updated_at_column"() OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "graphile_worker"."_private_job_queues" (
    "id" integer NOT NULL,
    "queue_name" "text" NOT NULL,
    "locked_at" timestamp with time zone,
    "locked_by" "text",
    "is_available" boolean GENERATED ALWAYS AS (("locked_at" IS NULL)) STORED NOT NULL,
    CONSTRAINT "job_queues_queue_name_check" CHECK (("length"("queue_name") <= 128))
);


ALTER TABLE "graphile_worker"."_private_job_queues" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "graphile_worker"."_private_known_crontabs" (
    "identifier" "text" NOT NULL,
    "known_since" timestamp with time zone NOT NULL,
    "last_execution" timestamp with time zone
);


ALTER TABLE "graphile_worker"."_private_known_crontabs" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "graphile_worker"."_private_tasks" (
    "id" integer NOT NULL,
    "identifier" "text" NOT NULL,
    CONSTRAINT "tasks_identifier_check" CHECK (("length"("identifier") <= 128))
);


ALTER TABLE "graphile_worker"."_private_tasks" OWNER TO "postgres";


ALTER TABLE "graphile_worker"."_private_job_queues" ALTER COLUMN "id" ADD GENERATED ALWAYS AS IDENTITY (
    SEQUENCE NAME "graphile_worker"."job_queues_id_seq"
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1
);



CREATE OR REPLACE VIEW "graphile_worker"."jobs" AS
 SELECT "jobs"."id",
    "job_queues"."queue_name",
    "tasks"."identifier" AS "task_identifier",
    "jobs"."priority",
    "jobs"."run_at",
    "jobs"."attempts",
    "jobs"."max_attempts",
    "jobs"."last_error",
    "jobs"."created_at",
    "jobs"."updated_at",
    "jobs"."key",
    "jobs"."locked_at",
    "jobs"."locked_by",
    "jobs"."revision",
    "jobs"."flags"
   FROM (("graphile_worker"."_private_jobs" "jobs"
     JOIN "graphile_worker"."_private_tasks" "tasks" ON (("tasks"."id" = "jobs"."task_id")))
     LEFT JOIN "graphile_worker"."_private_job_queues" "job_queues" ON (("job_queues"."id" = "jobs"."job_queue_id")));


ALTER TABLE "graphile_worker"."jobs" OWNER TO "postgres";


ALTER TABLE "graphile_worker"."_private_jobs" ALTER COLUMN "id" ADD GENERATED ALWAYS AS IDENTITY (
    SEQUENCE NAME "graphile_worker"."jobs_id_seq1"
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1
);



CREATE TABLE IF NOT EXISTS "graphile_worker"."migrations" (
    "id" integer NOT NULL,
    "ts" timestamp with time zone DEFAULT "now"() NOT NULL,
    "breaking" boolean DEFAULT false NOT NULL
);


ALTER TABLE "graphile_worker"."migrations" OWNER TO "postgres";


ALTER TABLE "graphile_worker"."_private_tasks" ALTER COLUMN "id" ADD GENERATED ALWAYS AS IDENTITY (
    SEQUENCE NAME "graphile_worker"."tasks_id_seq"
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1
);



CREATE TABLE IF NOT EXISTS "public"."availabilities" (
    "id" integer NOT NULL,
    "user_id" "uuid" NOT NULL,
    "availability_data" "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,
    "exceptions" "jsonb" DEFAULT '[]'::"jsonb"
);


ALTER TABLE "public"."availabilities" OWNER TO "postgres";


COMMENT ON TABLE "public"."availabilities" IS 'User availability settings with Row Level Security';



COMMENT ON COLUMN "public"."availabilities"."id" IS 'Primary key: auto-incrementing integer';



COMMENT ON COLUMN "public"."availabilities"."user_id" IS 'Foreign key reference to auth.users(id)';



COMMENT ON COLUMN "public"."availabilities"."availability_data" IS 'JSONB object containing availability settings for each day (0-6, where 0 is Monday). Each day has enabled status and time ranges.';



COMMENT ON COLUMN "public"."availabilities"."exceptions" IS 'JSONB object containing date-specific availability exceptions that override regular availability settings. Keys are ISO date strings (YYYY-MM-DD), values contain exception type and optional time ranges.';



CREATE SEQUENCE IF NOT EXISTS "public"."availabilities_id_seq"
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER TABLE "public"."availabilities_id_seq" OWNER TO "postgres";


ALTER SEQUENCE "public"."availabilities_id_seq" OWNED BY "public"."availabilities"."id";



CREATE TABLE IF NOT EXISTS "public"."calendar_subscriptions" (
    "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL,
    "tablo_id" "text" NOT NULL,
    "token" "text" NOT NULL,
    "created_at" timestamp with time zone DEFAULT "now"()
);


ALTER TABLE "public"."calendar_subscriptions" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."devis" (
    "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL,
    "user_id" "uuid" NOT NULL,
    "client_email" "text" NOT NULL,
    "number" character varying(50) NOT NULL,
    "date" timestamp with time zone NOT NULL,
    "due_date" timestamp with time zone NOT NULL,
    "status" "public"."devis_status" DEFAULT 'draft'::"public"."devis_status" NOT NULL,
    "items" "jsonb" DEFAULT '[]'::"jsonb" NOT NULL,
    "subtotal" numeric(10,2) NOT NULL,
    "tax" numeric(10,2) NOT NULL,
    "total" numeric(10,2) NOT NULL,
    "notes" "text",
    "terms" "text",
    "created_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    "updated_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
);


ALTER TABLE "public"."devis" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "public"."event_types" (
    "id" "text" DEFAULT "public"."generate_random_string"(24) NOT NULL,
    "user_id" "uuid" NOT NULL,
    "config" "jsonb" DEFAULT '{}'::"jsonb" NOT NULL,
    "is_active" boolean DEFAULT true NOT NULL,
    "created_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    "updated_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    "deleted_at" timestamp with time zone,
    "standard_name" "text",
    CONSTRAINT "event_types_config_check" CHECK ((("config" ? 'name'::"text") AND (("config" ->> 'name'::"text") <> ''::"text") AND ("config" ? 'duration'::"text") AND ((("config" ->> 'duration'::"text"))::integer > 0)))
);


ALTER TABLE "public"."event_types" OWNER TO "postgres";


COMMENT ON TABLE "public"."event_types" IS 'Event type configurations stored as JSONB with Row Level Security';



COMMENT ON COLUMN "public"."event_types"."id" IS 'Primary key: random 24-character alphanumeric string';



COMMENT ON COLUMN "public"."event_types"."user_id" IS 'Foreign key reference to auth.users.id';



COMMENT ON COLUMN "public"."event_types"."config" IS 'JSONB configuration containing: name (required), description (optional), duration (required), bufferTime, maxBookingsPerDay, requiresApproval, price, location, minAdvanceBooking, etc.';



COMMENT ON COLUMN "public"."event_types"."is_active" IS 'Whether this event type is active and available for booking';



COMMENT ON COLUMN "public"."event_types"."created_at" IS 'Timestamp when the event type was created';



COMMENT ON COLUMN "public"."event_types"."updated_at" IS 'Timestamp when the event type was last updated (auto-updated by trigger)';



COMMENT ON COLUMN "public"."event_types"."deleted_at" IS 'Timestamp for soft deletion (NULL means not deleted)';



COMMENT ON COLUMN "public"."event_types"."standard_name" IS 'Standard name for the event type - not modifiable by authenticated users';



CREATE TABLE IF NOT EXISTS "public"."events" (
    "id" "text" DEFAULT "public"."generate_random_string"(24) NOT NULL,
    "tablo_id" "text" NOT NULL,
    "title" character varying(255) NOT NULL,
    "description" "text",
    "start_date" "date" NOT NULL,
    "start_time" time without time zone NOT NULL,
    "end_time" time without time zone,
    "created_by" "uuid" NOT NULL,
    "created_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    "deleted_at" timestamp with time zone
);


ALTER TABLE "public"."events" OWNER TO "postgres";


COMMENT ON TABLE "public"."events" IS 'Calendar events linked to tablos with Row Level Security';



COMMENT ON COLUMN "public"."events"."id" IS 'Primary key: random 24-character alphanumeric string';



COMMENT ON COLUMN "public"."events"."tablo_id" IS 'Foreign key reference to tablos.id (24-character string)';



COMMENT ON COLUMN "public"."events"."start_date" IS 'Date of the event (YYYY-MM-DD format)';



COMMENT ON COLUMN "public"."events"."start_time" IS 'Start time of the event (HH:MM format)';



COMMENT ON COLUMN "public"."events"."end_time" IS 'End time of the event (HH:MM format), optional';



CREATE TABLE IF NOT EXISTS "public"."tablos" (
    "owner_id" "uuid" NOT NULL,
    "name" character varying(255) NOT NULL,
    "image" "text",
    "color" character varying(50),
    "status" character varying(20) DEFAULT 'todo'::character varying NOT NULL,
    "position" integer DEFAULT 0 NOT NULL,
    "created_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    "deleted_at" timestamp with time zone,
    "id" "text" DEFAULT "public"."generate_random_string"(24) NOT NULL,
    "updated_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT "tablos_status_check" CHECK ((("status")::"text" = ANY (ARRAY[('todo'::character varying)::"text", ('in_progress'::character varying)::"text", ('done'::character varying)::"text"])))
);


ALTER TABLE "public"."tablos" OWNER TO "postgres";


COMMENT ON COLUMN "public"."tablos"."id" IS 'Primary key: random 24-character alphanumeric string';



COMMENT ON COLUMN "public"."tablos"."updated_at" IS 'Timestamp when the tablo was last updated (auto-updated by trigger)';



CREATE OR REPLACE VIEW "public"."events_and_tablos" WITH ("security_invoker"='true') AS
 SELECT DISTINCT "e"."id" AS "event_id",
    "e"."title",
    "e"."start_date",
    "e"."start_time",
    "e"."end_time",
    "e"."description",
    "t"."id" AS "tablo_id",
    "t"."name" AS "tablo_name",
    "t"."color" AS "tablo_color",
    "t"."status" AS "tablo_status"
   FROM ("public"."events" "e"
     LEFT JOIN "public"."tablos" "t" ON (("e"."tablo_id" = "t"."id")))
  WHERE (("e"."deleted_at" IS NULL) AND ("t"."deleted_at" IS NULL))
  ORDER BY "e"."start_date", "e"."start_time";


ALTER TABLE "public"."events_and_tablos" OWNER TO "postgres";


COMMENT ON VIEW "public"."events_and_tablos" IS 'View that returns all events and their associated tablos parameters';



CREATE TABLE IF NOT EXISTS "public"."feedbacks" (
    "id" integer NOT NULL,
    "fd_type" character varying(20) NOT NULL,
    "user_id" "uuid" NOT NULL,
    "message" "text" NOT NULL,
    "created_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT "feedbacks_fd_type_check" CHECK ((("fd_type")::"text" = ANY (ARRAY[('bug'::character varying)::"text", ('feature'::character varying)::"text", ('improvement'::character varying)::"text", ('other'::character varying)::"text"])))
);


ALTER TABLE "public"."feedbacks" OWNER TO "postgres";


CREATE SEQUENCE IF NOT EXISTS "public"."feedbacks_id_seq"
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER TABLE "public"."feedbacks_id_seq" OWNER TO "postgres";


ALTER SEQUENCE "public"."feedbacks_id_seq" OWNED BY "public"."feedbacks"."id";



CREATE TABLE IF NOT EXISTS "public"."note_access" (
    "id" integer NOT NULL,
    "note_id" "text" NOT NULL,
    "user_id" "uuid" NOT NULL,
    "tablo_id" "text",
    "is_active" boolean DEFAULT true,
    "created_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    "updated_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP
);


ALTER TABLE "public"."note_access" OWNER TO "postgres";


COMMENT ON TABLE "public"."note_access" IS 'Tracks which notes are shared with tablos. When tablo_id IS NULL and is_active = TRUE, the note is shared with all user tablos. Uses partial unique indexes to handle NULL values correctly.';



COMMENT ON COLUMN "public"."note_access"."tablo_id" IS 'Foreign key reference to tablos.id - NULL means shared with all user tablos. Partial unique indexes ensure only one NULL per (note_id, user_id) combination.';



COMMENT ON COLUMN "public"."note_access"."is_active" IS 'When TRUE, the sharing is active';



CREATE SEQUENCE IF NOT EXISTS "public"."note_access_id_seq"
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER TABLE "public"."note_access_id_seq" OWNER TO "postgres";


ALTER SEQUENCE "public"."note_access_id_seq" OWNED BY "public"."note_access"."id";



CREATE TABLE IF NOT EXISTS "public"."notes" (
    "id" "text" DEFAULT "public"."generate_random_string"(24) NOT NULL,
    "title" character varying(255) NOT NULL,
    "content" "text",
    "user_id" "uuid" NOT NULL,
    "created_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    "updated_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    "deleted_at" timestamp with time zone
);


ALTER TABLE "public"."notes" OWNER TO "postgres";


COMMENT ON TABLE "public"."notes" IS 'User notes with Row Level Security to ensure users can only access their own notes';



COMMENT ON COLUMN "public"."notes"."id" IS 'Primary key: random 24-character alphanumeric string';



COMMENT ON COLUMN "public"."notes"."title" IS 'Title of the note';



COMMENT ON COLUMN "public"."notes"."content" IS 'Content of the note (can be plain text or formatted text)';



COMMENT ON COLUMN "public"."notes"."user_id" IS 'Foreign key reference to auth.users.id - owner of the note';



COMMENT ON COLUMN "public"."notes"."deleted_at" IS 'Soft delete timestamp - when not NULL, the note is considered deleted';



CREATE TABLE IF NOT EXISTS "public"."profiles" (
    "id" "uuid" NOT NULL,
    "name" "text",
    "email" character varying,
    "avatar_url" "text",
    "short_user_id" "text" NOT NULL,
    "is_temporary" boolean DEFAULT false NOT NULL,
    "first_name" "text",
    "last_name" "text",
    "last_signed_in" timestamp with time zone,
    "plan" "public"."subscription_plan" DEFAULT 'none'::"public"."subscription_plan"
);


ALTER TABLE "public"."profiles" OWNER TO "postgres";


COMMENT ON COLUMN "public"."profiles"."is_temporary" IS 'Indicates if the user account was created with a temporary password and needs to be changed on first login';



COMMENT ON COLUMN "public"."profiles"."first_name" IS 'User''s first name';



COMMENT ON COLUMN "public"."profiles"."last_name" IS 'User''s last name';



COMMENT ON COLUMN "public"."profiles"."last_signed_in" IS 'Timestamp when the user last signed in, updated from auth.users.last_sign_in_at';



COMMENT ON COLUMN "public"."profiles"."plan" IS 'User subscription plan: none (free), trial, or standard';



CREATE TABLE IF NOT EXISTS "public"."shared_notes" (
    "note_id" "text" NOT NULL,
    "user_id" "uuid" NOT NULL,
    "is_public" boolean DEFAULT false,
    "created_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    "updated_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP
);


ALTER TABLE "public"."shared_notes" OWNER TO "postgres";


COMMENT ON TABLE "public"."shared_notes" IS 'Tracks which notes are shared publicly with Row Level Security';



COMMENT ON COLUMN "public"."shared_notes"."note_id" IS 'Foreign key reference to notes.id';



COMMENT ON COLUMN "public"."shared_notes"."user_id" IS 'Foreign key reference to auth.users.id - owner of the note';



COMMENT ON COLUMN "public"."shared_notes"."is_public" IS 'When TRUE, the note is publicly accessible via /notes/public/:noteId';



CREATE TABLE IF NOT EXISTS "public"."tablo_access" (
    "id" integer NOT NULL,
    "user_id" "uuid" NOT NULL,
    "granted_by" "uuid" NOT NULL,
    "is_active" boolean DEFAULT true,
    "is_admin" boolean DEFAULT false,
    "created_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    "tablo_id" "text" NOT NULL
);


ALTER TABLE "public"."tablo_access" OWNER TO "postgres";


COMMENT ON COLUMN "public"."tablo_access"."tablo_id" IS 'Foreign key reference to tablos.id (24-character string)';



CREATE SEQUENCE IF NOT EXISTS "public"."tablo_access_id_seq"
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER TABLE "public"."tablo_access_id_seq" OWNER TO "postgres";


ALTER SEQUENCE "public"."tablo_access_id_seq" OWNED BY "public"."tablo_access"."id";



CREATE TABLE IF NOT EXISTS "public"."tablo_invites" (
    "id" integer NOT NULL,
    "invited_email" character varying(255) NOT NULL,
    "invited_by" "uuid" NOT NULL,
    "invite_token" "text" NOT NULL,
    "tablo_id" "text" NOT NULL,
    "is_pending" boolean DEFAULT false NOT NULL,
    "created_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
);


ALTER TABLE "public"."tablo_invites" OWNER TO "postgres";


COMMENT ON COLUMN "public"."tablo_invites"."tablo_id" IS 'Foreign key reference to tablos.id (24-character string)';



COMMENT ON COLUMN "public"."tablo_invites"."is_pending" IS 'When TRUE, the invite is pending acceptance. When FALSE, the invite has been accepted or rejected.';



COMMENT ON COLUMN "public"."tablo_invites"."created_at" IS 'Timestamp when the invite was created';



CREATE SEQUENCE IF NOT EXISTS "public"."tablo_invites_id_seq"
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER TABLE "public"."tablo_invites_id_seq" OWNER TO "postgres";


ALTER SEQUENCE "public"."tablo_invites_id_seq" OWNED BY "public"."tablo_invites"."id";



CREATE TABLE IF NOT EXISTS "public"."user_introductions" (
    "user_id" "uuid" NOT NULL,
    "created_at" timestamp with time zone DEFAULT "now"(),
    "updated_at" timestamp with time zone DEFAULT "now"(),
    "config" "jsonb" DEFAULT '{}'::"jsonb" NOT NULL
);


ALTER TABLE "public"."user_introductions" OWNER TO "postgres";


COMMENT ON TABLE "public"."user_introductions" IS 'Stores user introduction email templates';



COMMENT ON COLUMN "public"."user_introductions"."user_id" IS 'Reference to the user';



COMMENT ON COLUMN "public"."user_introductions"."config" IS 'User introduction configuration stored as JSON';



CREATE OR REPLACE VIEW "public"."user_tablos" WITH ("security_invoker"='true') AS
 SELECT DISTINCT "t"."id",
    "ta"."user_id",
    "t"."name",
    "t"."image",
    "t"."color",
    "t"."status",
    "t"."position",
    "t"."created_at",
    "t"."deleted_at",
        CASE
            WHEN ("ta"."is_admin" = true) THEN 'admin'::"text"
            ELSE 'member'::"text"
        END AS "access_level",
    "ta"."is_admin"
   FROM ("public"."tablos" "t"
     LEFT JOIN "public"."tablo_access" "ta" ON (("t"."id" = "ta"."tablo_id")))
  WHERE (("ta"."is_active" = true) AND ("t"."deleted_at" IS NULL))
  ORDER BY "t"."position", "t"."created_at" DESC;


ALTER TABLE "public"."user_tablos" OWNER TO "postgres";


COMMENT ON VIEW "public"."user_tablos" IS 'View that returns all tablos accessible to the current authenticated user, including owned tablos and shared tablos with active access';



CREATE TABLE IF NOT EXISTS "stripe"."active_entitlements" (
    "id" "text" NOT NULL,
    "object" "text",
    "livemode" boolean,
    "feature" "text",
    "customer" "text",
    "lookup_key" "text",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."active_entitlements" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."charges" (
    "id" "text" NOT NULL,
    "object" "text",
    "paid" boolean,
    "order" "text",
    "amount" bigint,
    "review" "text",
    "source" "jsonb",
    "status" "text",
    "created" integer,
    "dispute" "text",
    "invoice" "text",
    "outcome" "jsonb",
    "refunds" "jsonb",
    "updated" integer,
    "captured" boolean,
    "currency" "text",
    "customer" "text",
    "livemode" boolean,
    "metadata" "jsonb",
    "refunded" boolean,
    "shipping" "jsonb",
    "application" "text",
    "description" "text",
    "destination" "text",
    "failure_code" "text",
    "on_behalf_of" "text",
    "fraud_details" "jsonb",
    "receipt_email" "text",
    "payment_intent" "text",
    "receipt_number" "text",
    "transfer_group" "text",
    "amount_refunded" bigint,
    "application_fee" "text",
    "failure_message" "text",
    "source_transfer" "text",
    "balance_transaction" "text",
    "statement_descriptor" "text",
    "payment_method_details" "jsonb",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."charges" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."checkout_session_line_items" (
    "id" "text" NOT NULL,
    "object" "text",
    "amount_discount" integer,
    "amount_subtotal" integer,
    "amount_tax" integer,
    "amount_total" integer,
    "currency" "text",
    "description" "text",
    "price" "text",
    "quantity" integer,
    "checkout_session" "text",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."checkout_session_line_items" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."checkout_sessions" (
    "id" "text" NOT NULL,
    "object" "text",
    "adaptive_pricing" "jsonb",
    "after_expiration" "jsonb",
    "allow_promotion_codes" boolean,
    "amount_subtotal" integer,
    "amount_total" integer,
    "automatic_tax" "jsonb",
    "billing_address_collection" "text",
    "cancel_url" "text",
    "client_reference_id" "text",
    "client_secret" "text",
    "collected_information" "jsonb",
    "consent" "jsonb",
    "consent_collection" "jsonb",
    "created" integer,
    "currency" "text",
    "currency_conversion" "jsonb",
    "custom_fields" "jsonb",
    "custom_text" "jsonb",
    "customer" "text",
    "customer_creation" "text",
    "customer_details" "jsonb",
    "customer_email" "text",
    "discounts" "jsonb",
    "expires_at" integer,
    "invoice" "text",
    "invoice_creation" "jsonb",
    "livemode" boolean,
    "locale" "text",
    "metadata" "jsonb",
    "mode" "text",
    "optional_items" "jsonb",
    "payment_intent" "text",
    "payment_link" "text",
    "payment_method_collection" "text",
    "payment_method_configuration_details" "jsonb",
    "payment_method_options" "jsonb",
    "payment_method_types" "jsonb",
    "payment_status" "text",
    "permissions" "jsonb",
    "phone_number_collection" "jsonb",
    "presentment_details" "jsonb",
    "recovered_from" "text",
    "redirect_on_completion" "text",
    "return_url" "text",
    "saved_payment_method_options" "jsonb",
    "setup_intent" "text",
    "shipping_address_collection" "jsonb",
    "shipping_cost" "jsonb",
    "shipping_details" "jsonb",
    "shipping_options" "jsonb",
    "status" "text",
    "submit_type" "text",
    "subscription" "text",
    "success_url" "text",
    "tax_id_collection" "jsonb",
    "total_details" "jsonb",
    "ui_mode" "text",
    "url" "text",
    "wallet_options" "jsonb",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."checkout_sessions" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."coupons" (
    "id" "text" NOT NULL,
    "object" "text",
    "name" "text",
    "valid" boolean,
    "created" integer,
    "updated" integer,
    "currency" "text",
    "duration" "text",
    "livemode" boolean,
    "metadata" "jsonb",
    "redeem_by" integer,
    "amount_off" bigint,
    "percent_off" double precision,
    "times_redeemed" bigint,
    "max_redemptions" bigint,
    "duration_in_months" bigint,
    "percent_off_precise" double precision,
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."coupons" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."credit_notes" (
    "id" "text" NOT NULL,
    "object" "text",
    "amount" integer,
    "amount_shipping" integer,
    "created" integer,
    "currency" "text",
    "customer" "text",
    "customer_balance_transaction" "text",
    "discount_amount" integer,
    "discount_amounts" "jsonb",
    "invoice" "text",
    "lines" "jsonb",
    "livemode" boolean,
    "memo" "text",
    "metadata" "jsonb",
    "number" "text",
    "out_of_band_amount" integer,
    "pdf" "text",
    "reason" "text",
    "refund" "text",
    "shipping_cost" "jsonb",
    "status" "text",
    "subtotal" integer,
    "subtotal_excluding_tax" integer,
    "tax_amounts" "jsonb",
    "total" integer,
    "total_excluding_tax" integer,
    "type" "text",
    "voided_at" "text",
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."credit_notes" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."customers" (
    "id" "text" NOT NULL,
    "object" "text",
    "address" "jsonb",
    "description" "text",
    "email" "text",
    "metadata" "jsonb",
    "name" "text",
    "phone" "text",
    "shipping" "jsonb",
    "balance" integer,
    "created" integer,
    "currency" "text",
    "default_source" "text",
    "delinquent" boolean,
    "discount" "jsonb",
    "invoice_prefix" "text",
    "invoice_settings" "jsonb",
    "livemode" boolean,
    "next_invoice_sequence" integer,
    "preferred_locales" "jsonb",
    "tax_exempt" "text",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "deleted" boolean DEFAULT false NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."customers" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."disputes" (
    "id" "text" NOT NULL,
    "object" "text",
    "amount" bigint,
    "charge" "text",
    "reason" "text",
    "status" "text",
    "created" integer,
    "updated" integer,
    "currency" "text",
    "evidence" "jsonb",
    "livemode" boolean,
    "metadata" "jsonb",
    "evidence_details" "jsonb",
    "balance_transactions" "jsonb",
    "is_charge_refundable" boolean,
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "payment_intent" "text",
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."disputes" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."early_fraud_warnings" (
    "id" "text" NOT NULL,
    "object" "text",
    "actionable" boolean,
    "charge" "text",
    "created" integer,
    "fraud_type" "text",
    "livemode" boolean,
    "payment_intent" "text",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."early_fraud_warnings" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."events" (
    "id" "text" NOT NULL,
    "object" "text",
    "data" "jsonb",
    "type" "text",
    "created" integer,
    "request" "text",
    "updated" integer,
    "livemode" boolean,
    "api_version" "text",
    "pending_webhooks" bigint,
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."events" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."features" (
    "id" "text" NOT NULL,
    "object" "text",
    "livemode" boolean,
    "name" "text",
    "lookup_key" "text",
    "active" boolean,
    "metadata" "jsonb",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."features" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."invoices" (
    "id" "text" NOT NULL,
    "object" "text",
    "auto_advance" boolean,
    "collection_method" "text",
    "currency" "text",
    "description" "text",
    "hosted_invoice_url" "text",
    "lines" "jsonb",
    "metadata" "jsonb",
    "period_end" integer,
    "period_start" integer,
    "status" "stripe"."invoice_status",
    "total" bigint,
    "account_country" "text",
    "account_name" "text",
    "account_tax_ids" "jsonb",
    "amount_due" bigint,
    "amount_paid" bigint,
    "amount_remaining" bigint,
    "application_fee_amount" bigint,
    "attempt_count" integer,
    "attempted" boolean,
    "billing_reason" "text",
    "created" integer,
    "custom_fields" "jsonb",
    "customer_address" "jsonb",
    "customer_email" "text",
    "customer_name" "text",
    "customer_phone" "text",
    "customer_shipping" "jsonb",
    "customer_tax_exempt" "text",
    "customer_tax_ids" "jsonb",
    "default_tax_rates" "jsonb",
    "discount" "jsonb",
    "discounts" "jsonb",
    "due_date" integer,
    "ending_balance" integer,
    "footer" "text",
    "invoice_pdf" "text",
    "last_finalization_error" "jsonb",
    "livemode" boolean,
    "next_payment_attempt" integer,
    "number" "text",
    "paid" boolean,
    "payment_settings" "jsonb",
    "post_payment_credit_notes_amount" integer,
    "pre_payment_credit_notes_amount" integer,
    "receipt_number" "text",
    "starting_balance" integer,
    "statement_descriptor" "text",
    "status_transitions" "jsonb",
    "subtotal" integer,
    "tax" integer,
    "total_discount_amounts" "jsonb",
    "total_tax_amounts" "jsonb",
    "transfer_data" "jsonb",
    "webhooks_delivered_at" integer,
    "customer" "text",
    "subscription" "text",
    "payment_intent" "text",
    "default_payment_method" "text",
    "default_source" "text",
    "on_behalf_of" "text",
    "charge" "text",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."invoices" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."payment_intents" (
    "id" "text" NOT NULL,
    "object" "text",
    "amount" integer,
    "amount_capturable" integer,
    "amount_details" "jsonb",
    "amount_received" integer,
    "application" "text",
    "application_fee_amount" integer,
    "automatic_payment_methods" "text",
    "canceled_at" integer,
    "cancellation_reason" "text",
    "capture_method" "text",
    "client_secret" "text",
    "confirmation_method" "text",
    "created" integer,
    "currency" "text",
    "customer" "text",
    "description" "text",
    "invoice" "text",
    "last_payment_error" "text",
    "livemode" boolean,
    "metadata" "jsonb",
    "next_action" "text",
    "on_behalf_of" "text",
    "payment_method" "text",
    "payment_method_options" "jsonb",
    "payment_method_types" "jsonb",
    "processing" "text",
    "receipt_email" "text",
    "review" "text",
    "setup_future_usage" "text",
    "shipping" "jsonb",
    "statement_descriptor" "text",
    "statement_descriptor_suffix" "text",
    "status" "text",
    "transfer_data" "jsonb",
    "transfer_group" "text",
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."payment_intents" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."payment_methods" (
    "id" "text" NOT NULL,
    "object" "text",
    "created" integer,
    "customer" "text",
    "type" "text",
    "billing_details" "jsonb",
    "metadata" "jsonb",
    "card" "jsonb",
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."payment_methods" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."payouts" (
    "id" "text" NOT NULL,
    "object" "text",
    "date" "text",
    "type" "text",
    "amount" bigint,
    "method" "text",
    "status" "text",
    "created" integer,
    "updated" integer,
    "currency" "text",
    "livemode" boolean,
    "metadata" "jsonb",
    "automatic" boolean,
    "recipient" "text",
    "description" "text",
    "destination" "text",
    "source_type" "text",
    "arrival_date" "text",
    "bank_account" "jsonb",
    "failure_code" "text",
    "transfer_group" "text",
    "amount_reversed" bigint,
    "failure_message" "text",
    "source_transaction" "text",
    "balance_transaction" "text",
    "statement_descriptor" "text",
    "statement_description" "text",
    "failure_balance_transaction" "text",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."payouts" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."plans" (
    "id" "text" NOT NULL,
    "object" "text",
    "active" boolean,
    "amount" bigint,
    "created" integer,
    "product" "text",
    "currency" "text",
    "interval" "text",
    "livemode" boolean,
    "metadata" "jsonb",
    "nickname" "text",
    "tiers_mode" "text",
    "usage_type" "text",
    "billing_scheme" "text",
    "interval_count" bigint,
    "aggregate_usage" "text",
    "transform_usage" "text",
    "trial_period_days" bigint,
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."plans" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."prices" (
    "id" "text" NOT NULL,
    "object" "text",
    "active" boolean,
    "currency" "text",
    "metadata" "jsonb",
    "nickname" "text",
    "recurring" "jsonb",
    "type" "stripe"."pricing_type",
    "unit_amount" integer,
    "billing_scheme" "text",
    "created" integer,
    "livemode" boolean,
    "lookup_key" "text",
    "tiers_mode" "stripe"."pricing_tiers",
    "transform_quantity" "jsonb",
    "unit_amount_decimal" "text",
    "product" "text",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."prices" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."products" (
    "id" "text" NOT NULL,
    "object" "text",
    "active" boolean,
    "description" "text",
    "metadata" "jsonb",
    "name" "text",
    "created" integer,
    "images" "jsonb",
    "livemode" boolean,
    "package_dimensions" "jsonb",
    "shippable" boolean,
    "statement_descriptor" "text",
    "unit_label" "text",
    "updated" integer,
    "url" "text",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "marketing_features" "jsonb",
    "default_price" "text",
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."products" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."refunds" (
    "id" "text" NOT NULL,
    "object" "text",
    "amount" integer,
    "balance_transaction" "text",
    "charge" "text",
    "created" integer,
    "currency" "text",
    "destination_details" "jsonb",
    "metadata" "jsonb",
    "payment_intent" "text",
    "reason" "text",
    "receipt_number" "text",
    "source_transfer_reversal" "text",
    "status" "text",
    "transfer_reversal" "text",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."refunds" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."reviews" (
    "id" "text" NOT NULL,
    "object" "text",
    "billing_zip" "text",
    "charge" "text",
    "created" integer,
    "closed_reason" "text",
    "livemode" boolean,
    "ip_address" "text",
    "ip_address_location" "jsonb",
    "open" boolean,
    "opened_reason" "text",
    "payment_intent" "text",
    "reason" "text",
    "session" "text",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."reviews" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."setup_intents" (
    "id" "text" NOT NULL,
    "object" "text",
    "created" integer,
    "customer" "text",
    "description" "text",
    "payment_method" "text",
    "status" "text",
    "usage" "text",
    "cancellation_reason" "text",
    "latest_attempt" "text",
    "mandate" "text",
    "single_use_mandate" "text",
    "on_behalf_of" "text",
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."setup_intents" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."subscription_items" (
    "id" "text" NOT NULL,
    "object" "text",
    "billing_thresholds" "jsonb",
    "created" integer,
    "deleted" boolean,
    "metadata" "jsonb",
    "quantity" integer,
    "price" "text",
    "subscription" "text",
    "tax_rates" "jsonb",
    "current_period_end" integer,
    "current_period_start" integer,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."subscription_items" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."subscription_schedules" (
    "id" "text" NOT NULL,
    "object" "text",
    "application" "text",
    "canceled_at" integer,
    "completed_at" integer,
    "created" integer NOT NULL,
    "current_phase" "jsonb",
    "customer" "text" NOT NULL,
    "default_settings" "jsonb",
    "end_behavior" "text",
    "livemode" boolean NOT NULL,
    "metadata" "jsonb" NOT NULL,
    "phases" "jsonb" NOT NULL,
    "released_at" integer,
    "released_subscription" "text",
    "status" "stripe"."subscription_schedule_status" NOT NULL,
    "subscription" "text",
    "test_clock" "text",
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."subscription_schedules" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."subscriptions" (
    "id" "text" NOT NULL,
    "object" "text",
    "cancel_at_period_end" boolean,
    "current_period_end" integer,
    "current_period_start" integer,
    "default_payment_method" "text",
    "items" "jsonb",
    "metadata" "jsonb",
    "pending_setup_intent" "text",
    "pending_update" "jsonb",
    "status" "stripe"."subscription_status",
    "application_fee_percent" double precision,
    "billing_cycle_anchor" integer,
    "billing_thresholds" "jsonb",
    "cancel_at" integer,
    "canceled_at" integer,
    "collection_method" "text",
    "created" integer,
    "days_until_due" integer,
    "default_source" "text",
    "default_tax_rates" "jsonb",
    "discount" "jsonb",
    "ended_at" integer,
    "livemode" boolean,
    "next_pending_invoice_item_invoice" integer,
    "pause_collection" "jsonb",
    "pending_invoice_item_interval" "jsonb",
    "start_date" integer,
    "transfer_data" "jsonb",
    "trial_end" "jsonb",
    "trial_start" "jsonb",
    "schedule" "text",
    "customer" "text",
    "latest_invoice" "text",
    "plan" "text",
    "updated_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL,
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."subscriptions" OWNER TO "postgres";


CREATE TABLE IF NOT EXISTS "stripe"."tax_ids" (
    "id" "text" NOT NULL,
    "object" "text",
    "country" "text",
    "customer" "text",
    "type" "text",
    "value" "text",
    "created" integer NOT NULL,
    "livemode" boolean,
    "owner" "jsonb",
    "last_synced_at" timestamp with time zone
);


ALTER TABLE "stripe"."tax_ids" OWNER TO "postgres";


ALTER TABLE ONLY "public"."availabilities" ALTER COLUMN "id" SET DEFAULT "nextval"('"public"."availabilities_id_seq"'::"regclass");



ALTER TABLE ONLY "public"."feedbacks" ALTER COLUMN "id" SET DEFAULT "nextval"('"public"."feedbacks_id_seq"'::"regclass");



ALTER TABLE ONLY "public"."note_access" ALTER COLUMN "id" SET DEFAULT "nextval"('"public"."note_access_id_seq"'::"regclass");



ALTER TABLE ONLY "public"."tablo_access" ALTER COLUMN "id" SET DEFAULT "nextval"('"public"."tablo_access_id_seq"'::"regclass");



ALTER TABLE ONLY "public"."tablo_invites" ALTER COLUMN "id" SET DEFAULT "nextval"('"public"."tablo_invites_id_seq"'::"regclass");



ALTER TABLE ONLY "graphile_worker"."_private_job_queues"
    ADD CONSTRAINT "job_queues_pkey1" PRIMARY KEY ("id");



ALTER TABLE ONLY "graphile_worker"."_private_job_queues"
    ADD CONSTRAINT "job_queues_queue_name_key" UNIQUE ("queue_name");



ALTER TABLE ONLY "graphile_worker"."_private_jobs"
    ADD CONSTRAINT "jobs_key_key1" UNIQUE ("key");



ALTER TABLE ONLY "graphile_worker"."_private_jobs"
    ADD CONSTRAINT "jobs_pkey1" PRIMARY KEY ("id");



ALTER TABLE ONLY "graphile_worker"."_private_known_crontabs"
    ADD CONSTRAINT "known_crontabs_pkey" PRIMARY KEY ("identifier");



ALTER TABLE ONLY "graphile_worker"."migrations"
    ADD CONSTRAINT "migrations_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "graphile_worker"."_private_tasks"
    ADD CONSTRAINT "tasks_identifier_key" UNIQUE ("identifier");



ALTER TABLE ONLY "graphile_worker"."_private_tasks"
    ADD CONSTRAINT "tasks_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."availabilities"
    ADD CONSTRAINT "availabilities_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."calendar_subscriptions"
    ADD CONSTRAINT "calendar_subscriptions_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."calendar_subscriptions"
    ADD CONSTRAINT "calendar_subscriptions_tablo_id_key" UNIQUE ("tablo_id");



ALTER TABLE ONLY "public"."calendar_subscriptions"
    ADD CONSTRAINT "calendar_subscriptions_token_key" UNIQUE ("token");



ALTER TABLE ONLY "public"."devis"
    ADD CONSTRAINT "devis_number_key" UNIQUE ("number");



ALTER TABLE ONLY "public"."devis"
    ADD CONSTRAINT "devis_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."event_types"
    ADD CONSTRAINT "event_types_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."events"
    ADD CONSTRAINT "events_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."feedbacks"
    ADD CONSTRAINT "feedbacks_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."note_access"
    ADD CONSTRAINT "note_access_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."notes"
    ADD CONSTRAINT "notes_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."profiles"
    ADD CONSTRAINT "profiles_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."shared_notes"
    ADD CONSTRAINT "shared_notes_pkey" PRIMARY KEY ("note_id");



ALTER TABLE ONLY "public"."tablo_access"
    ADD CONSTRAINT "tablo_access_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."tablo_invites"
    ADD CONSTRAINT "tablo_invites_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."tablos"
    ADD CONSTRAINT "tablos_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "public"."tablo_access"
    ADD CONSTRAINT "unique_tablo_access" UNIQUE ("tablo_id", "user_id");



ALTER TABLE ONLY "public"."tablo_invites"
    ADD CONSTRAINT "unique_tablo_invitation" UNIQUE ("tablo_id", "invited_email");



ALTER TABLE ONLY "public"."availabilities"
    ADD CONSTRAINT "unique_user_availabilities" UNIQUE ("user_id");



ALTER TABLE ONLY "public"."user_introductions"
    ADD CONSTRAINT "user_introductions_pkey" PRIMARY KEY ("user_id");



ALTER TABLE ONLY "stripe"."active_entitlements"
    ADD CONSTRAINT "active_entitlements_lookup_key_key" UNIQUE ("lookup_key");



ALTER TABLE ONLY "stripe"."active_entitlements"
    ADD CONSTRAINT "active_entitlements_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."charges"
    ADD CONSTRAINT "charges_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."checkout_session_line_items"
    ADD CONSTRAINT "checkout_session_line_items_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."checkout_sessions"
    ADD CONSTRAINT "checkout_sessions_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."coupons"
    ADD CONSTRAINT "coupons_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."credit_notes"
    ADD CONSTRAINT "credit_notes_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."customers"
    ADD CONSTRAINT "customers_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."disputes"
    ADD CONSTRAINT "disputes_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."early_fraud_warnings"
    ADD CONSTRAINT "early_fraud_warnings_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."events"
    ADD CONSTRAINT "events_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."features"
    ADD CONSTRAINT "features_lookup_key_key" UNIQUE ("lookup_key");



ALTER TABLE ONLY "stripe"."features"
    ADD CONSTRAINT "features_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."invoices"
    ADD CONSTRAINT "invoices_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."payment_intents"
    ADD CONSTRAINT "payment_intents_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."payment_methods"
    ADD CONSTRAINT "payment_methods_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."payouts"
    ADD CONSTRAINT "payouts_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."plans"
    ADD CONSTRAINT "plans_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."prices"
    ADD CONSTRAINT "prices_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."products"
    ADD CONSTRAINT "products_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."refunds"
    ADD CONSTRAINT "refunds_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."reviews"
    ADD CONSTRAINT "reviews_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."setup_intents"
    ADD CONSTRAINT "setup_intents_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."subscription_items"
    ADD CONSTRAINT "subscription_items_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."subscription_schedules"
    ADD CONSTRAINT "subscription_schedules_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."subscriptions"
    ADD CONSTRAINT "subscriptions_pkey" PRIMARY KEY ("id");



ALTER TABLE ONLY "stripe"."tax_ids"
    ADD CONSTRAINT "tax_ids_pkey" PRIMARY KEY ("id");



CREATE INDEX "jobs_main_index" ON "graphile_worker"."_private_jobs" USING "btree" ("priority", "run_at") INCLUDE ("id", "task_id", "job_queue_id") WHERE ("is_available" = true);



CREATE INDEX "jobs_no_queue_index" ON "graphile_worker"."_private_jobs" USING "btree" ("priority", "run_at") INCLUDE ("id", "task_id") WHERE (("is_available" = true) AND ("job_queue_id" IS NULL));



CREATE INDEX "idx_availabilities_user_id" ON "public"."availabilities" USING "btree" ("user_id");



CREATE INDEX "idx_calendar_subscriptions_token" ON "public"."calendar_subscriptions" USING "btree" ("token");



CREATE INDEX "idx_devis_user_id" ON "public"."devis" USING "btree" ("user_id");



CREATE INDEX "idx_event_types_config_gin" ON "public"."event_types" USING "gin" ("config");



CREATE INDEX "idx_event_types_deleted_at" ON "public"."event_types" USING "btree" ("deleted_at");



CREATE INDEX "idx_event_types_is_active" ON "public"."event_types" USING "btree" ("is_active");



CREATE INDEX "idx_event_types_user_id" ON "public"."event_types" USING "btree" ("user_id");



CREATE INDEX "idx_events_created_by" ON "public"."events" USING "btree" ("created_by");



CREATE INDEX "idx_events_deleted_at" ON "public"."events" USING "btree" ("deleted_at");



CREATE INDEX "idx_events_start_date" ON "public"."events" USING "btree" ("start_date");



CREATE INDEX "idx_events_tablo_id" ON "public"."events" USING "btree" ("tablo_id");



CREATE INDEX "idx_note_access_is_active" ON "public"."note_access" USING "btree" ("is_active");



CREATE INDEX "idx_note_access_note_id" ON "public"."note_access" USING "btree" ("note_id");



CREATE INDEX "idx_note_access_tablo_id" ON "public"."note_access" USING "btree" ("tablo_id");



CREATE INDEX "idx_note_access_user_id" ON "public"."note_access" USING "btree" ("user_id");



CREATE INDEX "idx_notes_created_at" ON "public"."notes" USING "btree" ("created_at");



CREATE INDEX "idx_notes_deleted_at" ON "public"."notes" USING "btree" ("deleted_at");



CREATE INDEX "idx_notes_user_id" ON "public"."notes" USING "btree" ("user_id");



CREATE INDEX "idx_profiles_short_user_id" ON "public"."profiles" USING "btree" ("short_user_id");



CREATE INDEX "idx_shared_notes_is_public" ON "public"."shared_notes" USING "btree" ("is_public");



CREATE INDEX "idx_shared_notes_user_id" ON "public"."shared_notes" USING "btree" ("user_id");



CREATE INDEX "idx_tablo_access_user_id" ON "public"."tablo_access" USING "btree" ("user_id");



CREATE INDEX "idx_tablo_invites_created_at" ON "public"."tablo_invites" USING "btree" ("created_at");



CREATE INDEX "idx_tablo_invites_is_pending" ON "public"."tablo_invites" USING "btree" ("is_pending");



CREATE UNIQUE INDEX "unique_note_access_all_tablos" ON "public"."note_access" USING "btree" ("note_id", "user_id") WHERE ("tablo_id" IS NULL);



CREATE UNIQUE INDEX "unique_note_access_with_tablo" ON "public"."note_access" USING "btree" ("note_id", "user_id", "tablo_id") WHERE ("tablo_id" IS NOT NULL);



CREATE INDEX "stripe_active_entitlements_customer_idx" ON "stripe"."active_entitlements" USING "btree" ("customer");



CREATE INDEX "stripe_active_entitlements_feature_idx" ON "stripe"."active_entitlements" USING "btree" ("feature");



CREATE INDEX "stripe_checkout_session_line_items_price_idx" ON "stripe"."checkout_session_line_items" USING "btree" ("price");



CREATE INDEX "stripe_checkout_session_line_items_session_idx" ON "stripe"."checkout_session_line_items" USING "btree" ("checkout_session");



CREATE INDEX "stripe_checkout_sessions_customer_idx" ON "stripe"."checkout_sessions" USING "btree" ("customer");



CREATE INDEX "stripe_checkout_sessions_invoice_idx" ON "stripe"."checkout_sessions" USING "btree" ("invoice");



CREATE INDEX "stripe_checkout_sessions_payment_intent_idx" ON "stripe"."checkout_sessions" USING "btree" ("payment_intent");



CREATE INDEX "stripe_checkout_sessions_subscription_idx" ON "stripe"."checkout_sessions" USING "btree" ("subscription");



CREATE INDEX "stripe_credit_notes_customer_idx" ON "stripe"."credit_notes" USING "btree" ("customer");



CREATE INDEX "stripe_credit_notes_invoice_idx" ON "stripe"."credit_notes" USING "btree" ("invoice");



CREATE INDEX "stripe_dispute_created_idx" ON "stripe"."disputes" USING "btree" ("created");



CREATE INDEX "stripe_early_fraud_warnings_charge_idx" ON "stripe"."early_fraud_warnings" USING "btree" ("charge");



CREATE INDEX "stripe_early_fraud_warnings_payment_intent_idx" ON "stripe"."early_fraud_warnings" USING "btree" ("payment_intent");



CREATE INDEX "stripe_invoices_customer_idx" ON "stripe"."invoices" USING "btree" ("customer");



CREATE INDEX "stripe_invoices_subscription_idx" ON "stripe"."invoices" USING "btree" ("subscription");



CREATE INDEX "stripe_payment_intents_customer_idx" ON "stripe"."payment_intents" USING "btree" ("customer");



CREATE INDEX "stripe_payment_intents_invoice_idx" ON "stripe"."payment_intents" USING "btree" ("invoice");



CREATE INDEX "stripe_payment_methods_customer_idx" ON "stripe"."payment_methods" USING "btree" ("customer");



CREATE INDEX "stripe_refunds_charge_idx" ON "stripe"."refunds" USING "btree" ("charge");



CREATE INDEX "stripe_refunds_payment_intent_idx" ON "stripe"."refunds" USING "btree" ("payment_intent");



CREATE INDEX "stripe_reviews_charge_idx" ON "stripe"."reviews" USING "btree" ("charge");



CREATE INDEX "stripe_reviews_payment_intent_idx" ON "stripe"."reviews" USING "btree" ("payment_intent");



CREATE INDEX "stripe_setup_intents_customer_idx" ON "stripe"."setup_intents" USING "btree" ("customer");



CREATE INDEX "stripe_tax_ids_customer_idx" ON "stripe"."tax_ids" USING "btree" ("customer");



CREATE OR REPLACE TRIGGER "handle_event_types_standard_name_trigger" BEFORE INSERT OR UPDATE ON "public"."event_types" FOR EACH ROW EXECUTE FUNCTION "public"."handle_event_types_standard_name"();



CREATE OR REPLACE TRIGGER "trigger_create_tablo_access" AFTER INSERT ON "public"."tablos" FOR EACH ROW EXECUTE FUNCTION "public"."create_tablo_access_for_owner"();



CREATE OR REPLACE TRIGGER "trigger_set_short_user_id" BEFORE INSERT ON "public"."profiles" FOR EACH ROW EXECUTE FUNCTION "public"."set_short_user_id"();



CREATE OR REPLACE TRIGGER "update_availabilities_updated_at" BEFORE UPDATE ON "public"."availabilities" FOR EACH ROW EXECUTE FUNCTION "public"."update_updated_at_column"();



CREATE OR REPLACE TRIGGER "update_devis_updated_at" BEFORE UPDATE ON "public"."devis" FOR EACH ROW EXECUTE FUNCTION "public"."update_updated_at_column"();



CREATE OR REPLACE TRIGGER "update_event_types_updated_at" BEFORE UPDATE ON "public"."event_types" FOR EACH ROW EXECUTE FUNCTION "public"."update_event_types_updated_at"();



CREATE OR REPLACE TRIGGER "update_tablos_updated_at" BEFORE UPDATE ON "public"."tablos" FOR EACH ROW EXECUTE FUNCTION "public"."update_tablos_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."active_entitlements" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."charges" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."checkout_session_line_items" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."checkout_sessions" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."coupons" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."customers" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."disputes" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."early_fraud_warnings" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."events" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."features" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."invoices" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."payouts" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."plans" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."prices" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."products" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."refunds" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."reviews" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "stripe"."subscriptions" FOR EACH ROW EXECUTE FUNCTION "public"."set_updated_at"();



CREATE OR REPLACE TRIGGER "update_profile_on_subscription_change" AFTER INSERT OR UPDATE ON "stripe"."subscriptions" FOR EACH ROW EXECUTE FUNCTION "public"."update_profile_subscription_status"();



CREATE OR REPLACE TRIGGER "update_profile_on_subscription_item_change" AFTER INSERT OR UPDATE ON "stripe"."subscription_items" FOR EACH ROW EXECUTE FUNCTION "public"."update_profile_subscription_status"();



ALTER TABLE ONLY "public"."availabilities"
    ADD CONSTRAINT "availabilities_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."calendar_subscriptions"
    ADD CONSTRAINT "calendar_subscriptions_tablo_id_fkey" FOREIGN KEY ("tablo_id") REFERENCES "public"."tablos"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."devis"
    ADD CONSTRAINT "devis_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id");



ALTER TABLE ONLY "public"."event_types"
    ADD CONSTRAINT "fk_event_types_user_id" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."events"
    ADD CONSTRAINT "fk_events_created_by" FOREIGN KEY ("created_by") REFERENCES "auth"."users"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."events"
    ADD CONSTRAINT "fk_events_tablo_id" FOREIGN KEY ("tablo_id") REFERENCES "public"."tablos"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."note_access"
    ADD CONSTRAINT "fk_note_access_note_id" FOREIGN KEY ("note_id") REFERENCES "public"."notes"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."note_access"
    ADD CONSTRAINT "fk_note_access_tablo_id" FOREIGN KEY ("tablo_id") REFERENCES "public"."tablos"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."note_access"
    ADD CONSTRAINT "fk_note_access_user_id" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."notes"
    ADD CONSTRAINT "fk_notes_user_id" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."shared_notes"
    ADD CONSTRAINT "fk_shared_notes_note_id" FOREIGN KEY ("note_id") REFERENCES "public"."notes"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."shared_notes"
    ADD CONSTRAINT "fk_shared_notes_user_id" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."tablo_access"
    ADD CONSTRAINT "fk_tablo_access_tablo_id" FOREIGN KEY ("tablo_id") REFERENCES "public"."tablos"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."tablo_access"
    ADD CONSTRAINT "fk_tablo_access_user_id" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."tablo_access"
    ADD CONSTRAINT "fk_tablo_access_user_id_from_profiles" FOREIGN KEY ("user_id") REFERENCES "public"."profiles"("id");



ALTER TABLE ONLY "public"."tablo_invites"
    ADD CONSTRAINT "fk_tablo_invitations_tablo_id" FOREIGN KEY ("tablo_id") REFERENCES "public"."tablos"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."profiles"
    ADD CONSTRAINT "profiles_id_fkey" FOREIGN KEY ("id") REFERENCES "auth"."users"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."user_introductions"
    ADD CONSTRAINT "user_introductions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "stripe"."checkout_session_line_items"
    ADD CONSTRAINT "checkout_session_line_items_checkout_session_fkey" FOREIGN KEY ("checkout_session") REFERENCES "stripe"."checkout_sessions"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "stripe"."checkout_session_line_items"
    ADD CONSTRAINT "checkout_session_line_items_price_fkey" FOREIGN KEY ("price") REFERENCES "stripe"."prices"("id") ON DELETE CASCADE;



ALTER TABLE "graphile_worker"."_private_job_queues" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "graphile_worker"."_private_jobs" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "graphile_worker"."_private_known_crontabs" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "graphile_worker"."_private_tasks" ENABLE ROW LEVEL SECURITY;


CREATE POLICY "Anyone can view public notes" ON "public"."shared_notes" FOR SELECT TO "authenticated", "anon" USING (("is_public" = true));



CREATE POLICY "Users can delete their own availabilities" ON "public"."availabilities" FOR DELETE TO "authenticated" USING (("user_id" = "auth"."uid"()));



CREATE POLICY "Users can delete their own devis" ON "public"."devis" FOR DELETE USING (("auth"."uid"() = "user_id"));



CREATE POLICY "Users can delete their own event types" ON "public"."event_types" FOR UPDATE TO "authenticated" USING ((("user_id" = "auth"."uid"()) AND ("deleted_at" IS NULL))) WITH CHECK (("user_id" = "auth"."uid"()));



CREATE POLICY "Users can delete their own introduction" ON "public"."user_introductions" FOR DELETE USING (("auth"."uid"() = "user_id"));



CREATE POLICY "Users can delete their own note access" ON "public"."note_access" FOR DELETE TO "authenticated" USING (("user_id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Users can delete their own notes (soft)" ON "public"."notes" FOR UPDATE TO "authenticated" USING ((("user_id" = "auth"."uid"()) AND ("deleted_at" IS NULL))) WITH CHECK (("user_id" = "auth"."uid"()));



CREATE POLICY "Users can delete their own profile" ON "public"."profiles" FOR DELETE USING (("auth"."uid"() = "id"));



CREATE POLICY "Users can delete their own shared notes" ON "public"."shared_notes" FOR DELETE TO "authenticated" USING (("user_id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Users can insert events into accessible tablos" ON "public"."events" FOR INSERT TO "authenticated" WITH CHECK (((( SELECT "auth"."uid"() AS "uid") = "created_by") AND (EXISTS ( SELECT 1
   FROM "public"."user_tablos" "ut"
  WHERE (("ut"."id" = "events"."tablo_id") AND ("ut"."deleted_at" IS NULL) AND ("ut"."user_id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can insert feedback." ON "public"."feedbacks" FOR INSERT TO "authenticated" WITH CHECK ((( SELECT "auth"."uid"() AS "uid") = "user_id"));



CREATE POLICY "Users can insert own tablos" ON "public"."tablos" FOR INSERT TO "authenticated" WITH CHECK ((( SELECT "auth"."uid"() AS "uid") = "owner_id"));



CREATE POLICY "Users can insert their own availabilities" ON "public"."availabilities" FOR INSERT TO "authenticated" WITH CHECK (("user_id" = "auth"."uid"()));



CREATE POLICY "Users can insert their own devis" ON "public"."devis" FOR INSERT WITH CHECK (("auth"."uid"() = "user_id"));



CREATE POLICY "Users can insert their own event types" ON "public"."event_types" FOR INSERT TO "authenticated" WITH CHECK (("user_id" = "auth"."uid"()));



CREATE POLICY "Users can insert their own introduction" ON "public"."user_introductions" FOR INSERT WITH CHECK (("auth"."uid"() = "user_id"));



CREATE POLICY "Users can insert their own note access" ON "public"."note_access" FOR INSERT TO "authenticated" WITH CHECK (("user_id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Users can insert their own notes" ON "public"."notes" FOR INSERT TO "authenticated" WITH CHECK (("user_id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Users can insert their own shared notes" ON "public"."shared_notes" FOR INSERT TO "authenticated" WITH CHECK (("user_id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Users can update own tablos" ON "public"."tablos" FOR UPDATE TO "authenticated" USING ((( SELECT "auth"."uid"() AS "uid") = "owner_id")) WITH CHECK ((( SELECT "auth"."uid"() AS "uid") = "owner_id"));



CREATE POLICY "Users can update their own availabilities" ON "public"."availabilities" FOR UPDATE TO "authenticated" USING (("user_id" = "auth"."uid"())) WITH CHECK (("user_id" = "auth"."uid"()));



CREATE POLICY "Users can update their own devis" ON "public"."devis" FOR UPDATE USING (("auth"."uid"() = "user_id"));



CREATE POLICY "Users can update their own event types" ON "public"."event_types" FOR UPDATE TO "authenticated" USING (("user_id" = "auth"."uid"())) WITH CHECK (("user_id" = "auth"."uid"()));



CREATE POLICY "Users can update their own events in accessible tablos" ON "public"."events" FOR UPDATE USING ((("created_by" = ( SELECT "auth"."uid"() AS "uid")) AND (EXISTS ( SELECT 1
   FROM "public"."user_tablos" "ut"
  WHERE (("ut"."id" = "events"."tablo_id") AND ("events"."deleted_at" IS NULL) AND ("ut"."user_id" = ( SELECT "auth"."uid"() AS "uid"))))))) WITH CHECK ((("created_by" = ( SELECT "auth"."uid"() AS "uid")) AND (EXISTS ( SELECT 1
   FROM "public"."user_tablos" "ut"
  WHERE (("ut"."id" = "events"."tablo_id") AND ("ut"."user_id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can update their own introduction" ON "public"."user_introductions" FOR UPDATE USING (("auth"."uid"() = "user_id"));



CREATE POLICY "Users can update their own note access" ON "public"."note_access" FOR UPDATE TO "authenticated" USING (("user_id" = ( SELECT "auth"."uid"() AS "uid"))) WITH CHECK (("user_id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Users can update their own notes" ON "public"."notes" FOR UPDATE TO "authenticated" USING (("user_id" = ( SELECT "auth"."uid"() AS "uid"))) WITH CHECK (("user_id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Users can update their own profile" ON "public"."profiles" FOR UPDATE USING (("auth"."uid"() = "id"));



CREATE POLICY "Users can update their own shared notes" ON "public"."shared_notes" FOR UPDATE TO "authenticated" USING (("user_id" = ( SELECT "auth"."uid"() AS "uid"))) WITH CHECK (("user_id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Users can view events from accessible tablos" ON "public"."events" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1
   FROM "public"."user_tablos" "ut"
  WHERE (("ut"."id" = "events"."tablo_id") AND ("ut"."deleted_at" IS NULL) AND ("ut"."user_id" = ( SELECT "auth"."uid"() AS "uid"))))));



CREATE POLICY "Users can view notes shared with their tablos" ON "public"."note_access" FOR SELECT TO "authenticated" USING ((("is_active" = true) AND (("tablo_id" IS NULL) OR (EXISTS ( SELECT 1
   FROM "public"."tablo_access"
  WHERE (("tablo_access"."tablo_id" = "note_access"."tablo_id") AND ("tablo_access"."user_id" = ( SELECT "auth"."uid"() AS "uid")) AND ("tablo_access"."is_active" = true)))))));



CREATE POLICY "Users can view tablos they have access to" ON "public"."tablos" FOR SELECT TO "authenticated" USING (((( SELECT "auth"."uid"() AS "uid") = "owner_id") OR (EXISTS ( SELECT 1
   FROM "public"."tablo_access"
  WHERE (("tablo_access"."tablo_id" = "tablos"."id") AND ("tablo_access"."user_id" = ( SELECT "auth"."uid"() AS "uid")))))));



CREATE POLICY "Users can view their own availabilities" ON "public"."availabilities" FOR SELECT TO "authenticated" USING (("user_id" = "auth"."uid"()));



CREATE POLICY "Users can view their own devis" ON "public"."devis" FOR SELECT USING (("auth"."uid"() = "user_id"));



CREATE POLICY "Users can view their own event types" ON "public"."event_types" FOR SELECT TO "authenticated" USING (("user_id" = "auth"."uid"()));



CREATE POLICY "Users can view their own introduction" ON "public"."user_introductions" FOR SELECT USING (("auth"."uid"() = "user_id"));



CREATE POLICY "Users can view their own note access" ON "public"."note_access" FOR SELECT TO "authenticated" USING (("user_id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Users can view their own notes and public notes" ON "public"."notes" FOR SELECT TO "authenticated", "anon" USING ((("user_id" = ( SELECT "auth"."uid"() AS "uid")) OR (EXISTS ( SELECT 1
   FROM "public"."shared_notes"
  WHERE (("shared_notes"."note_id" = "notes"."id") AND ("shared_notes"."is_public" = true))))));



CREATE POLICY "Users can view their own pending invites" ON "public"."tablo_invites" FOR SELECT USING ((("invited_by" = "auth"."uid"()) AND ("is_pending" = true)));



CREATE POLICY "Users can view their own profile" ON "public"."profiles" FOR SELECT USING (("auth"."uid"() = "id"));



CREATE POLICY "Users can view their own shared notes" ON "public"."shared_notes" FOR SELECT TO "authenticated" USING (("user_id" = ( SELECT "auth"."uid"() AS "uid")));



CREATE POLICY "Users can view their tablo access only if the access is active" ON "public"."tablo_access" FOR SELECT USING ((("user_id" = ( SELECT "auth"."uid"() AS "uid")) AND ("is_active" = true)));



ALTER TABLE "public"."availabilities" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."calendar_subscriptions" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."devis" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."event_types" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."events" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."feedbacks" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."note_access" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."notes" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."profiles" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."shared_notes" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."tablo_access" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."tablo_invites" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."tablos" ENABLE ROW LEVEL SECURITY;


ALTER TABLE "public"."user_introductions" ENABLE ROW LEVEL SECURITY;




ALTER PUBLICATION "supabase_realtime" OWNER TO "postgres";





GRANT USAGE ON SCHEMA "public" TO "postgres";
GRANT USAGE ON SCHEMA "public" TO "anon";
GRANT USAGE ON SCHEMA "public" TO "authenticated";
GRANT USAGE ON SCHEMA "public" TO "service_role";



GRANT USAGE ON SCHEMA "stripe" TO "service_role";






































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































GRANT ALL ON FUNCTION "public"."create_last_signed_in_on_profiles"() TO "anon";
GRANT ALL ON FUNCTION "public"."create_last_signed_in_on_profiles"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."create_last_signed_in_on_profiles"() TO "service_role";



GRANT ALL ON FUNCTION "public"."create_tablo_access_for_owner"() TO "anon";
GRANT ALL ON FUNCTION "public"."create_tablo_access_for_owner"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."create_tablo_access_for_owner"() TO "service_role";



GRANT ALL ON FUNCTION "public"."generate_random_string"("length" integer) TO "anon";
GRANT ALL ON FUNCTION "public"."generate_random_string"("length" integer) TO "authenticated";
GRANT ALL ON FUNCTION "public"."generate_random_string"("length" integer) TO "service_role";



GRANT ALL ON FUNCTION "public"."get_my_active_subscription"() TO "anon";
GRANT ALL ON FUNCTION "public"."get_my_active_subscription"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."get_my_active_subscription"() TO "service_role";



GRANT ALL ON FUNCTION "public"."get_stripe_prices"() TO "anon";
GRANT ALL ON FUNCTION "public"."get_stripe_prices"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."get_stripe_prices"() TO "service_role";



GRANT ALL ON FUNCTION "public"."get_stripe_products"() TO "anon";
GRANT ALL ON FUNCTION "public"."get_stripe_products"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."get_stripe_products"() TO "service_role";



GRANT ALL ON FUNCTION "public"."get_user_stripe_customer"() TO "anon";
GRANT ALL ON FUNCTION "public"."get_user_stripe_customer"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."get_user_stripe_customer"() TO "service_role";



GRANT ALL ON FUNCTION "public"."get_user_stripe_customer_id"("user_uuid" "uuid") TO "anon";
GRANT ALL ON FUNCTION "public"."get_user_stripe_customer_id"("user_uuid" "uuid") TO "authenticated";
GRANT ALL ON FUNCTION "public"."get_user_stripe_customer_id"("user_uuid" "uuid") TO "service_role";



GRANT ALL ON FUNCTION "public"."get_user_stripe_subscriptions"() TO "anon";
GRANT ALL ON FUNCTION "public"."get_user_stripe_subscriptions"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."get_user_stripe_subscriptions"() TO "service_role";



GRANT ALL ON FUNCTION "public"."get_user_subscription_status"("user_uuid" "uuid") TO "anon";
GRANT ALL ON FUNCTION "public"."get_user_subscription_status"("user_uuid" "uuid") TO "authenticated";
GRANT ALL ON FUNCTION "public"."get_user_subscription_status"("user_uuid" "uuid") TO "service_role";



GRANT ALL ON FUNCTION "public"."handle_event_types_standard_name"() TO "anon";
GRANT ALL ON FUNCTION "public"."handle_event_types_standard_name"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."handle_event_types_standard_name"() TO "service_role";



GRANT ALL ON FUNCTION "public"."handle_new_user"() TO "anon";
GRANT ALL ON FUNCTION "public"."handle_new_user"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."handle_new_user"() TO "service_role";



GRANT ALL ON FUNCTION "public"."is_paying_user"("user_uuid" "uuid") TO "anon";
GRANT ALL ON FUNCTION "public"."is_paying_user"("user_uuid" "uuid") TO "authenticated";
GRANT ALL ON FUNCTION "public"."is_paying_user"("user_uuid" "uuid") TO "service_role";



GRANT ALL ON FUNCTION "public"."set_short_user_id"() TO "anon";
GRANT ALL ON FUNCTION "public"."set_short_user_id"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."set_short_user_id"() TO "service_role";



GRANT ALL ON FUNCTION "public"."set_updated_at"() TO "anon";
GRANT ALL ON FUNCTION "public"."set_updated_at"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."set_updated_at"() TO "service_role";



GRANT ALL ON FUNCTION "public"."update_event_types_updated_at"() TO "anon";
GRANT ALL ON FUNCTION "public"."update_event_types_updated_at"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."update_event_types_updated_at"() TO "service_role";



GRANT ALL ON FUNCTION "public"."update_profile_subscription_status"() TO "anon";
GRANT ALL ON FUNCTION "public"."update_profile_subscription_status"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."update_profile_subscription_status"() TO "service_role";



GRANT ALL ON FUNCTION "public"."update_tablo_invites_on_login"() TO "anon";
GRANT ALL ON FUNCTION "public"."update_tablo_invites_on_login"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."update_tablo_invites_on_login"() TO "service_role";



GRANT ALL ON FUNCTION "public"."update_tablos_updated_at"() TO "anon";
GRANT ALL ON FUNCTION "public"."update_tablos_updated_at"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."update_tablos_updated_at"() TO "service_role";



GRANT ALL ON FUNCTION "public"."update_updated_at_column"() TO "anon";
GRANT ALL ON FUNCTION "public"."update_updated_at_column"() TO "authenticated";
GRANT ALL ON FUNCTION "public"."update_updated_at_column"() TO "service_role";




































GRANT ALL ON TABLE "public"."availabilities" TO "anon";
GRANT ALL ON TABLE "public"."availabilities" TO "authenticated";
GRANT ALL ON TABLE "public"."availabilities" TO "service_role";



GRANT ALL ON SEQUENCE "public"."availabilities_id_seq" TO "anon";
GRANT ALL ON SEQUENCE "public"."availabilities_id_seq" TO "authenticated";
GRANT ALL ON SEQUENCE "public"."availabilities_id_seq" TO "service_role";



GRANT ALL ON TABLE "public"."calendar_subscriptions" TO "anon";
GRANT ALL ON TABLE "public"."calendar_subscriptions" TO "authenticated";
GRANT ALL ON TABLE "public"."calendar_subscriptions" TO "service_role";



GRANT ALL ON TABLE "public"."devis" TO "anon";
GRANT ALL ON TABLE "public"."devis" TO "authenticated";
GRANT ALL ON TABLE "public"."devis" TO "service_role";



GRANT ALL ON TABLE "public"."event_types" TO "anon";
GRANT ALL ON TABLE "public"."event_types" TO "authenticated";
GRANT ALL ON TABLE "public"."event_types" TO "service_role";



GRANT ALL ON TABLE "public"."events" TO "anon";
GRANT ALL ON TABLE "public"."events" TO "authenticated";
GRANT ALL ON TABLE "public"."events" TO "service_role";



GRANT ALL ON TABLE "public"."tablos" TO "anon";
GRANT ALL ON TABLE "public"."tablos" TO "authenticated";
GRANT ALL ON TABLE "public"."tablos" TO "service_role";



GRANT ALL ON TABLE "public"."events_and_tablos" TO "anon";
GRANT ALL ON TABLE "public"."events_and_tablos" TO "authenticated";
GRANT ALL ON TABLE "public"."events_and_tablos" TO "service_role";



GRANT ALL ON TABLE "public"."feedbacks" TO "anon";
GRANT ALL ON TABLE "public"."feedbacks" TO "authenticated";
GRANT ALL ON TABLE "public"."feedbacks" TO "service_role";



GRANT ALL ON SEQUENCE "public"."feedbacks_id_seq" TO "anon";
GRANT ALL ON SEQUENCE "public"."feedbacks_id_seq" TO "authenticated";
GRANT ALL ON SEQUENCE "public"."feedbacks_id_seq" TO "service_role";



GRANT ALL ON TABLE "public"."note_access" TO "anon";
GRANT ALL ON TABLE "public"."note_access" TO "authenticated";
GRANT ALL ON TABLE "public"."note_access" TO "service_role";



GRANT ALL ON SEQUENCE "public"."note_access_id_seq" TO "anon";
GRANT ALL ON SEQUENCE "public"."note_access_id_seq" TO "authenticated";
GRANT ALL ON SEQUENCE "public"."note_access_id_seq" TO "service_role";



GRANT ALL ON TABLE "public"."notes" TO "anon";
GRANT ALL ON TABLE "public"."notes" TO "authenticated";
GRANT ALL ON TABLE "public"."notes" TO "service_role";



GRANT ALL ON TABLE "public"."profiles" TO "anon";
GRANT ALL ON TABLE "public"."profiles" TO "authenticated";
GRANT ALL ON TABLE "public"."profiles" TO "service_role";



GRANT ALL ON TABLE "public"."shared_notes" TO "anon";
GRANT ALL ON TABLE "public"."shared_notes" TO "authenticated";
GRANT ALL ON TABLE "public"."shared_notes" TO "service_role";



GRANT ALL ON TABLE "public"."tablo_access" TO "anon";
GRANT ALL ON TABLE "public"."tablo_access" TO "authenticated";
GRANT ALL ON TABLE "public"."tablo_access" TO "service_role";



GRANT ALL ON SEQUENCE "public"."tablo_access_id_seq" TO "anon";
GRANT ALL ON SEQUENCE "public"."tablo_access_id_seq" TO "authenticated";
GRANT ALL ON SEQUENCE "public"."tablo_access_id_seq" TO "service_role";



GRANT ALL ON TABLE "public"."tablo_invites" TO "anon";
GRANT ALL ON TABLE "public"."tablo_invites" TO "authenticated";
GRANT ALL ON TABLE "public"."tablo_invites" TO "service_role";



GRANT ALL ON SEQUENCE "public"."tablo_invites_id_seq" TO "anon";
GRANT ALL ON SEQUENCE "public"."tablo_invites_id_seq" TO "authenticated";
GRANT ALL ON SEQUENCE "public"."tablo_invites_id_seq" TO "service_role";



GRANT ALL ON TABLE "public"."user_introductions" TO "anon";
GRANT ALL ON TABLE "public"."user_introductions" TO "authenticated";
GRANT ALL ON TABLE "public"."user_introductions" TO "service_role";



GRANT ALL ON TABLE "public"."user_tablos" TO "anon";
GRANT ALL ON TABLE "public"."user_tablos" TO "authenticated";
GRANT ALL ON TABLE "public"."user_tablos" TO "service_role";



GRANT ALL ON TABLE "stripe"."active_entitlements" TO "service_role";



GRANT ALL ON TABLE "stripe"."charges" TO "service_role";



GRANT ALL ON TABLE "stripe"."checkout_session_line_items" TO "service_role";



GRANT ALL ON TABLE "stripe"."checkout_sessions" TO "service_role";



GRANT ALL ON TABLE "stripe"."coupons" TO "service_role";



GRANT ALL ON TABLE "stripe"."credit_notes" TO "service_role";



GRANT ALL ON TABLE "stripe"."customers" TO "service_role";



GRANT ALL ON TABLE "stripe"."disputes" TO "service_role";



GRANT ALL ON TABLE "stripe"."early_fraud_warnings" TO "service_role";



GRANT ALL ON TABLE "stripe"."events" TO "service_role";



GRANT ALL ON TABLE "stripe"."features" TO "service_role";



GRANT ALL ON TABLE "stripe"."invoices" TO "service_role";



GRANT ALL ON TABLE "stripe"."payment_intents" TO "service_role";



GRANT ALL ON TABLE "stripe"."payment_methods" TO "service_role";



GRANT ALL ON TABLE "stripe"."payouts" TO "service_role";



GRANT ALL ON TABLE "stripe"."plans" TO "service_role";



GRANT ALL ON TABLE "stripe"."prices" TO "service_role";



GRANT ALL ON TABLE "stripe"."products" TO "service_role";



GRANT ALL ON TABLE "stripe"."refunds" TO "service_role";



GRANT ALL ON TABLE "stripe"."reviews" TO "service_role";



GRANT ALL ON TABLE "stripe"."setup_intents" TO "service_role";



GRANT ALL ON TABLE "stripe"."subscription_items" TO "service_role";



GRANT ALL ON TABLE "stripe"."subscription_schedules" TO "service_role";



GRANT ALL ON TABLE "stripe"."subscriptions" TO "service_role";



GRANT ALL ON TABLE "stripe"."tax_ids" TO "service_role";









ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES  TO "postgres";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES  TO "anon";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES  TO "authenticated";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES  TO "service_role";






ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS  TO "postgres";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS  TO "anon";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS  TO "authenticated";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS  TO "service_role";






ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES  TO "postgres";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES  TO "anon";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES  TO "authenticated";
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES  TO "service_role";






ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "stripe" GRANT ALL ON SEQUENCES  TO "service_role";



ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "stripe" GRANT ALL ON FUNCTIONS  TO "service_role";



ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "stripe" GRANT ALL ON TABLES  TO "service_role";



























drop extension if exists "pg_net";

drop policy "Anyone can view public notes" on "public"."shared_notes";


  create policy "Anyone can view public notes"
  on "public"."shared_notes"
  as permissive
  for select
  to anon, authenticated
using ((is_public = true));


CREATE TRIGGER on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();

CREATE TRIGGER trigger_on_last_signed_in AFTER UPDATE ON auth.users FOR EACH ROW EXECUTE FUNCTION public.create_last_signed_in_on_profiles();

CREATE TRIGGER trigger_update_tablo_invites_on_login AFTER UPDATE ON auth.users FOR EACH ROW EXECUTE FUNCTION public.update_tablo_invites_on_login();


  create policy "Anyone can upload an avatar."
  on "storage"."objects"
  as permissive
  for insert
  to public
with check ((bucket_id = 'avatars'::text));



  create policy "Avatar images are publicly accessible."
  on "storage"."objects"
  as permissive
  for select
  to public
using ((bucket_id = 'avatars'::text));



