Docs
Database
Supabase Configuration

Supabase Configuration for StartupBolt

Overview

In this guide, we'll walk you through the process of configuring Supabase for StartupBolt. You'll learn how to create tables to manage customer data, set up essential RPC functions, and configure triggers to handle payments and subscriptions.

To get started, navigate to Supabase > SQL Editor > New Query, paste the provided SQL queries, and execute them.

supabase_config

Creating the Customers Table

First, let's create the customers table to store customer information.

CREATE TABLE customers (
  id UUID NOT NULL REFERENCES auth.users ON DELETE CASCADE,
  customer TEXT,
  name TEXT,
  price_id TEXT,
  credits INTEGER NOT NULL DEFAULT 0,
  email TEXT,
  provider TEXT,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT (now() AT TIME ZONE 'UTC'),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT (now() AT TIME ZONE 'UTC'),
  PRIMARY KEY (id)
);

Enabling RLS on the Customers Table

To enhance security and ensure users can only access their own data, enable Row-Level Security (RLS) on the customers table:

-- Enable RLS on the customers table
ALTER TABLE public.customers ENABLE ROW LEVEL SECURITY;

Creating RLS Policies for the Customers Table

Next, we'll create RLS policies to manage data access. These policies will ensure that authenticated users can only interact with their own data.

-- Policy for inserting own data
CREATE POLICY insert_own_customer ON public.customers
FOR INSERT WITH CHECK (auth.uid() = id);
 
-- Policy for reading own data
CREATE POLICY read_own_customer ON public.customers
FOR SELECT USING (auth.uid() = id);
 
-- Policy for updating own data
CREATE POLICY update_own_customer ON public.customers
FOR UPDATE USING (auth.uid() = id);
 
-- Policy for deleting own data
CREATE POLICY delete_own_customer ON public.customers
FOR DELETE USING (auth.uid() = id);

Tracking Last Update Timestamps

We'll create a function to automatically update the updated_at timestamp whenever a record is modified.

First, create the function:

-- First, create the function that will update the timestamp
CREATE OR REPLACE FUNCTION public.update_customer_timestamp()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
BEGIN
    NEW.updated_at = now() AT TIME ZONE 'UTC';
    RETURN NEW;
END;
$$;

Then, set up the trigger to call this function before every update on the customers table:

-- Trigger to update the timestamp
CREATE TRIGGER update_customer_timestamp_trigger
BEFORE UPDATE ON public.customers
FOR EACH ROW
EXECUTE FUNCTION update_customer_timestamp();

Saving Processed Events

To ensure idempotency and prevent double-processing of webhook events, we'll create a processed_events table to record processed events.

CREATE TABLE processed_events (
  id TEXT,
  processed_at TIMESTAMP WITH TIME ZONE DEFAULT (now() AT TIME ZONE 'UTC'),
  PRIMARY KEY (id)
);
 
ALTER TABLE processed_events ENABLE ROW LEVEL SECURITY;

Note: RLS policies are not needed for this table as it will only be accessed by server-side service roles.

Cleaning Up Processed Events (Optional)

To prevent the processed_events table from growing too large, we'll set up a cron job to delete records older than 30 days. The cron job will run daily at 3:00 AM UTC.

First, ensure the pg_cron extension is installed:

-- First, ensure pg_cron extension is installed
CREATE EXTENSION IF NOT EXISTS pg_cron;

Next, create a function to delete old records:

-- Create a function to delete old records
CREATE OR REPLACE FUNCTION public.delete_old_processed_events()
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
BEGIN
    DELETE FROM public.processed_events
    WHERE processed_at < ((now() AT TIME ZONE 'UTC') - INTERVAL '30 days');
END;
$$;

Finally, schedule the cron job:

-- Schedule the job to run daily at 3:00 AM UTC
SELECT cron.schedule('0 3 * * *', 'SELECT delete_old_processed_events()');

Function to Increment Credits

Credits are incremented when a user makes a payment via Stripe or LemonSqueezy webhook. Create function to update the credits:

CREATE OR REPLACE FUNCTION public.increment_credits(user_id uuid, increment_value int)
RETURNS void 
LANGUAGE plpgsql 
SECURITY DEFINER
SET search_path = ''
AS $$
BEGIN
    UPDATE public.customers
    SET credits = COALESCE(credits, 0) + increment_value
    WHERE id = user_id;
END;
$$;

Function to Get User ID from Email

This function allows you to retrieve a user ID based on their email, which is required for managing non-authenticated payments.

CREATE OR REPLACE FUNCTION public.get_user_id_email(p_email TEXT)
RETURNS JSON
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
    user_data JSON;
BEGIN
    SELECT json_build_object(
        'id', id,
        'email', email
    ) INTO user_data
    FROM auth.users
    WHERE email = p_email;
    
    IF user_data IS NULL THEN
        RETURN json_build_object('error', 'User not found');
    END IF;
    
    RETURN user_data;
END;
$$;

This concludes the Supabase configuration for StartupBolt. With these tables, functions, and triggers in place, your application will be equipped to manage customer data and handle payments.