fastapi_hf / supabase /supabase_setup.sql
looh2's picture
feat: Enhance document handling by adding doc_id to user documents table and updating upload logic to capture doc_id from insert response
c67278b
Raw
History Blame Contribute Delete
20.9 kB
-- =====================================================
-- 0. MASTER TABLE: m_synonym (HAS HEADER)
-- =====================================================
-- CSV columns: from, to
CREATE TABLE IF NOT EXISTS m_synonym (
"from" TEXT PRIMARY KEY,
"to" TEXT
);
-- =====================================================
-- SUPABASE DATABASE SETUP
-- =====================================================
-- Run these SQL commands in your Supabase SQL Editor
-- (Dashboard > SQL Editor > New Query)
-- =====================================================
-- 1. CREATE PROFILES TABLE
-- =====================================================
-- This table stores user profile information
-- It's linked to Supabase auth.users table
CREATE TABLE IF NOT EXISTS public.profiles (
id UUID REFERENCES auth.users(id) PRIMARY KEY,
email TEXT,
full_name TEXT,
avatar_url TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- =====================================================
-- 2. ENABLE ROW LEVEL SECURITY
-- =====================================================
-- This ensures users can only access their own data
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
-- =====================================================
-- 3. CREATE RLS POLICIES
-- =====================================================
-- Allow users to view their own profile
CREATE POLICY "Users can view their own profile"
ON public.profiles
FOR SELECT
USING (auth.uid() = id);
-- Allow users to insert their own profile
CREATE POLICY "Users can insert their own profile"
ON public.profiles
FOR INSERT
WITH CHECK (auth.uid() = id);
-- Allow users to update their own profile
CREATE POLICY "Users can update their own profile"
ON public.profiles
FOR UPDATE
USING (auth.uid() = id)
WITH CHECK (auth.uid() = id);
-- Allow users to delete their own profile (optional)
CREATE POLICY "Users can delete their own profile"
ON public.profiles
FOR DELETE
USING (auth.uid() = id);
-- =====================================================
-- 4. CREATE FUNCTION TO HANDLE NEW USER SIGNUPS
-- =====================================================
-- Automatically creates a profile when a new user signs up
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, email, full_name, avatar_url)
VALUES (
NEW.id,
NEW.email,
NEW.raw_user_meta_data->>'full_name',
NEW.raw_user_meta_data->>'avatar_url'
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- =====================================================
-- 5. CREATE TRIGGER FOR NEW USER SIGNUPS
-- =====================================================
-- Trigger the function whenever a new user is created
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION public.handle_new_user();
-- =====================================================
-- 6. CREATE FUNCTION TO UPDATE updated_at TIMESTAMP
-- =====================================================
CREATE OR REPLACE FUNCTION public.handle_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- =====================================================
-- 7. CREATE TRIGGER FOR updated_at
-- =====================================================
CREATE TRIGGER set_updated_at
BEFORE UPDATE ON public.profiles
FOR EACH ROW
EXECUTE FUNCTION public.handle_updated_at();
-- =====================================================
-- 8. EXAMPLE: CREATE A CUSTOM TABLE WITH RLS
-- =====================================================
-- Example of how to create your own tables with RLS
CREATE TABLE IF NOT EXISTS public.user_items (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
user_id UUID REFERENCES auth.users(id) NOT NULL,
title TEXT NOT NULL,
description TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Enable RLS
ALTER TABLE public.user_items ENABLE ROW LEVEL SECURITY;
-- Create policies
CREATE POLICY "Users can view their own items"
ON public.user_items
FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY "Users can insert their own items"
ON public.user_items
FOR INSERT
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update their own items"
ON public.user_items
FOR UPDATE
USING (auth.uid() = user_id);
CREATE POLICY "Users can delete their own items"
ON public.user_items
FOR DELETE
USING (auth.uid() = user_id);
-- Add updated_at trigger
CREATE TRIGGER set_user_items_updated_at
BEFORE UPDATE ON public.user_items
FOR EACH ROW
EXECUTE FUNCTION public.handle_updated_at();
-- =====================================================
-- 9. OPTIONAL: CREATE STORAGE BUCKET
-- =====================================================
-- For file uploads (avatars, documents, etc.)
-- Run this in the SQL Editor or create via Dashboard > Storage
INSERT INTO storage.buckets (id, name, public)
VALUES ('avatars', 'avatars', true)
ON CONFLICT (id) DO NOTHING;
-- Create storage policy for avatars
CREATE POLICY "Avatar images are publicly accessible"
ON storage.objects FOR SELECT
USING (bucket_id = 'avatars');
CREATE POLICY "Users can upload their own avatar"
ON storage.objects FOR INSERT
WITH CHECK (
bucket_id = 'avatars' AND
auth.uid()::text = (storage.foldername(name))[1]
);
CREATE POLICY "Users can update their own avatar"
ON storage.objects FOR UPDATE
USING (
bucket_id = 'avatars' AND
auth.uid()::text = (storage.foldername(name))[1]
);
CREATE POLICY "Users can delete their own avatar"
ON storage.objects FOR DELETE
USING (
bucket_id = 'avatars' AND
auth.uid()::text = (storage.foldername(name))[1]
);
-- =====================================================
-- 10. MASTER DATA AND FACT TABLES
-- =====================================================
-- SQL schema for master data and fact tables from CSV files
-- CSV Import Notes:
-- - Master tables (m_*) have headers: skip 1 row on import
-- - Fact tables have NO headers: import from row 1
-- - Keys with leading zeros are VARCHAR to preserve formatting
-- - Currency fields NUMERIC(18,2); volumes NUMERIC(18,3)
-- =====================================================
-- 1. MASTER DATA TABLES (HAS HEADER)
-- =====================================================
-- m_synonym
-- CSV columns: from, to
CREATE TABLE IF NOT EXISTS m_synonym (
"from" TEXT PRIMARY KEY,
"to" TEXT
);
-- m_country
-- CSV columns: Index,Country_code,Country,Region,Subregion,Country_key
CREATE TABLE IF NOT EXISTS m_country (
idx INTEGER NULL,
country_code VARCHAR(10) NOT NULL,
country VARCHAR(100) NOT NULL,
region VARCHAR(100) NULL,
subregion VARCHAR(100) NULL,
country_key VARCHAR(64) NOT NULL,
CONSTRAINT pk_m_country PRIMARY KEY (country_key)
);
CREATE INDEX IF NOT EXISTS ix_m_country_code ON m_country(country_code);
CREATE INDEX IF NOT EXISTS ix_m_country_region ON m_country(region);
-- m_customer_shipto
-- CSV columns: Customer_shipto_key,Customer_shipto
CREATE TABLE IF NOT EXISTS m_customer_shipto (
customer_shipto_key VARCHAR(10) NOT NULL,
customer_shipto VARCHAR(255) NOT NULL,
CONSTRAINT pk_m_customer_shipto PRIMARY KEY (customer_shipto_key)
);
-- m_customer_soldto
-- CSV columns: Customer_soldto_key,Customer_soldto,Customer_group
CREATE TABLE IF NOT EXISTS m_customer_soldto (
customer_soldto_key VARCHAR(10) NOT NULL,
customer_soldto VARCHAR(255) NOT NULL,
customer_group VARCHAR(100) NULL,
CONSTRAINT pk_m_customer_soldto PRIMARY KEY (customer_soldto_key)
);
-- m_product
-- CSV columns: Product_article_key,Product_article,Product_group_key,Product_group
CREATE TABLE IF NOT EXISTS m_product (
product_article_key VARCHAR(10) NOT NULL,
product_article VARCHAR(255) NOT NULL,
product_group_key VARCHAR(10) NOT NULL,
product_group VARCHAR(255) NOT NULL,
CONSTRAINT pk_m_product PRIMARY KEY (product_article_key)
);
CREATE INDEX IF NOT EXISTS ix_m_product_group_key ON m_product(product_group_key);
-- Fact Table: fact_inventory.csv (NO HEADER)
-- CSV columns: Country_key, Product_article_key, Inventory_volume, Source
CREATE TABLE fact_inventory (
country_key VARCHAR(64) NOT NULL,
product_article_key VARCHAR(10) NOT NULL,
inventory_volume NUMERIC(18,3) NOT NULL,
source VARCHAR(32) NOT NULL,
CONSTRAINT pk_fact_inventory PRIMARY KEY (country_key, product_article_key),
CONSTRAINT fk_inv_country FOREIGN KEY (country_key) REFERENCES m_country(country_key),
CONSTRAINT fk_inv_product FOREIGN KEY (product_article_key) REFERENCES m_product(product_article_key)
);
CREATE INDEX ix_inv_country ON fact_inventory(country_key);
CREATE INDEX ix_inv_product ON fact_inventory(product_article_key);
-- Fact Table: fact_orders.csv (NO HEADER)
-- CSV columns: Date, Country_key, Document_number, Customer_soldto_key, Customer_shipto_key,
-- Product_article_key, PO_number, Order_volume, Order_eur, Order_lc, Order_usd, Source
CREATE TABLE fact_orders (
date DATE NOT NULL,
country_key VARCHAR(64) NOT NULL,
document_number VARCHAR(40) NOT NULL,
customer_soldto_key VARCHAR(10) NOT NULL,
customer_shipto_key VARCHAR(10) NOT NULL,
product_article_key VARCHAR(10) NOT NULL,
po_number VARCHAR(40) NULL,
order_volume NUMERIC(18,3) NOT NULL,
order_eur NUMERIC(18,2) NULL,
order_lc NUMERIC(18,2) NULL,
order_usd NUMERIC(18,2) NULL,
source VARCHAR(32) NOT NULL,
CONSTRAINT pk_fact_orders PRIMARY KEY (document_number),
CONSTRAINT fk_ord_country FOREIGN KEY (country_key) REFERENCES m_country(country_key),
CONSTRAINT fk_ord_soldto FOREIGN KEY (customer_soldto_key) REFERENCES m_customer_soldto(customer_soldto_key),
CONSTRAINT fk_ord_shipto FOREIGN KEY (customer_shipto_key) REFERENCES m_customer_shipto(customer_shipto_key),
CONSTRAINT fk_ord_product FOREIGN KEY (product_article_key) REFERENCES m_product(product_article_key)
);
CREATE INDEX ix_ord_date ON fact_orders(date);
CREATE INDEX ix_ord_country ON fact_orders(country_key);
CREATE INDEX ix_ord_soldto ON fact_orders(customer_soldto_key);
CREATE INDEX ix_ord_shipto ON fact_orders(customer_shipto_key);
CREATE INDEX ix_ord_product ON fact_orders(product_article_key);
-- Fact Table: fact_overdues.csv (NO HEADER)
-- CSV columns: Country_key, Customer_soldto_key, Customer_shipto_key, Product_article_key,
-- Document_number, Due_date, Overdue_eur, Overdue_lc, Overdue_usd, Source
CREATE TABLE fact_overdues (
country_key VARCHAR(64) NOT NULL,
customer_soldto_key VARCHAR(10) NOT NULL,
customer_shipto_key VARCHAR(10) NOT NULL,
product_article_key VARCHAR(10) NOT NULL,
document_number VARCHAR(40) NOT NULL,
due_date DATE NOT NULL,
overdue_eur NUMERIC(18,2) NULL,
overdue_lc NUMERIC(18,2) NULL,
overdue_usd NUMERIC(18,2) NULL,
source VARCHAR(32) NOT NULL,
CONSTRAINT pk_fact_overdues PRIMARY KEY (document_number),
CONSTRAINT fk_ovd_country FOREIGN KEY (country_key) REFERENCES m_country(country_key),
CONSTRAINT fk_ovd_soldto FOREIGN KEY (customer_soldto_key) REFERENCES m_customer_soldto(customer_soldto_key),
CONSTRAINT fk_ovd_shipto FOREIGN KEY (customer_shipto_key) REFERENCES m_customer_shipto(customer_shipto_key),
CONSTRAINT fk_ovd_product FOREIGN KEY (product_article_key) REFERENCES m_product(product_article_key)
);
CREATE INDEX ix_ovd_due_date ON fact_overdues(due_date);
CREATE INDEX ix_ovd_country ON fact_overdues(country_key);
CREATE INDEX ix_ovd_soldto ON fact_overdues(customer_soldto_key);
CREATE INDEX ix_ovd_shipto ON fact_overdues(customer_shipto_key);
CREATE INDEX ix_ovd_product ON fact_overdues(product_article_key);
-- Fact Table: fact_sales.csv (NO HEADER)
-- CSV columns: Date, Country_key, Customer_soldto_key, Customer_shipto_key, Product_article_key,
-- Sales_volume, Sales_eur, Sales_lc, Sales_usd, Source
CREATE TABLE fact_sales (
date DATE NOT NULL,
country_key VARCHAR(64) NOT NULL,
customer_soldto_key VARCHAR(10) NOT NULL,
customer_shipto_key VARCHAR(10) NOT NULL,
product_article_key VARCHAR(10) NOT NULL,
sales_volume NUMERIC(18,3) NOT NULL,
sales_eur NUMERIC(18,2) NULL,
sales_lc NUMERIC(18,2) NULL,
sales_usd NUMERIC(18,2) NULL,
source VARCHAR(32) NOT NULL,
CONSTRAINT pk_fact_sales PRIMARY KEY (date, country_key, customer_soldto_key, customer_shipto_key, product_article_key),
CONSTRAINT fk_sal_country FOREIGN KEY (country_key) REFERENCES m_country(country_key),
CONSTRAINT fk_sal_soldto FOREIGN KEY (customer_soldto_key) REFERENCES m_customer_soldto(customer_soldto_key),
CONSTRAINT fk_sal_shipto FOREIGN KEY (customer_shipto_key) REFERENCES m_customer_shipto(customer_shipto_key),
CONSTRAINT fk_sal_product FOREIGN KEY (product_article_key) REFERENCES m_product(product_article_key)
);
CREATE INDEX ix_sal_date ON fact_sales(date);
CREATE INDEX ix_sal_country ON fact_sales(country_key);
CREATE INDEX ix_sal_soldto ON fact_sales(customer_soldto_key);
CREATE INDEX ix_sal_shipto ON fact_sales(customer_shipto_key);
CREATE INDEX ix_sal_product ON fact_sales(product_article_key);
-- =====================================================
-- 11. ENABLE RLS FOR MASTER DATA TABLES
-- =====================================================
-- Enable Row Level Security for master data tables
-- These policies allow all authenticated users to access master data
-- =====================================================
-- 2. ENABLE RLS FOR MASTER DATA TABLES
-- =====================================================
-- Enable RLS on master tables
ALTER TABLE m_synonym ENABLE ROW LEVEL SECURITY;
ALTER TABLE m_country ENABLE ROW LEVEL SECURITY;
ALTER TABLE m_customer_shipto ENABLE ROW LEVEL SECURITY;
ALTER TABLE m_customer_soldto ENABLE ROW LEVEL SECURITY;
ALTER TABLE m_product ENABLE ROW LEVEL SECURITY;
-- RLS Policies for m_synonym
CREATE POLICY "Authenticated users can view synonyms"
ON m_synonym FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "Authenticated users can insert synonyms"
ON m_synonym FOR INSERT
TO authenticated
WITH CHECK (true);
CREATE POLICY "Authenticated users can update synonyms"
ON m_synonym FOR UPDATE
TO authenticated
USING (true)
WITH CHECK (true);
CREATE POLICY "Authenticated users can delete synonyms"
ON m_synonym FOR DELETE
TO authenticated
USING (true);
-- RLS Policies for m_country
CREATE POLICY "Authenticated users can view countries"
ON m_country FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "Authenticated users can insert countries"
ON m_country FOR INSERT
TO authenticated
WITH CHECK (true);
CREATE POLICY "Authenticated users can update countries"
ON m_country FOR UPDATE
TO authenticated
USING (true)
WITH CHECK (true);
CREATE POLICY "Authenticated users can delete countries"
ON m_country FOR DELETE
TO authenticated
USING (true);
-- RLS Policies for m_customer_shipto
CREATE POLICY "Authenticated users can view ship-to customers"
ON m_customer_shipto FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "Authenticated users can insert ship-to customers"
ON m_customer_shipto FOR INSERT
TO authenticated
WITH CHECK (true);
CREATE POLICY "Authenticated users can update ship-to customers"
ON m_customer_shipto FOR UPDATE
TO authenticated
USING (true)
WITH CHECK (true);
CREATE POLICY "Authenticated users can delete ship-to customers"
ON m_customer_shipto FOR DELETE
TO authenticated
USING (true);
-- RLS Policies for m_customer_soldto
CREATE POLICY "Authenticated users can view sold-to customers"
ON m_customer_soldto FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "Authenticated users can insert sold-to customers"
ON m_customer_soldto FOR INSERT
TO authenticated
WITH CHECK (true);
CREATE POLICY "Authenticated users can update sold-to customers"
ON m_customer_soldto FOR UPDATE
TO authenticated
USING (true)
WITH CHECK (true);
CREATE POLICY "Authenticated users can delete sold-to customers"
ON m_customer_soldto FOR DELETE
TO authenticated
USING (true);
-- RLS Policies for m_product
CREATE POLICY "Authenticated users can view products"
ON m_product FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "Authenticated users can insert products"
ON m_product FOR INSERT
TO authenticated
WITH CHECK (true);
CREATE POLICY "Authenticated users can update products"
ON m_product FOR UPDATE
TO authenticated
USING (true)
WITH CHECK (true);
CREATE POLICY "Authenticated users can delete products"
ON m_product FOR DELETE
TO authenticated
USING (true);
-- =====================================================
-- DONE!
-- =====================================================
-- Your Supabase database is now set up with:
-- βœ… Profiles table with RLS
-- βœ… Automatic profile creation on signup
-- βœ… Example custom table (user_items)
-- βœ… Storage bucket for avatars
-- βœ… Master data tables with RLS policies
--
-- Next steps:
-- 1. Update your .env file with Supabase credentials
-- 2. Configure OAuth providers in Supabase Dashboard (optional)
-- 3. Test authentication from your frontend
-- 4. Import CSV data into master and fact tables
-- Table for storing embeddings and metadata for filter values and RAG vectors. This is a unified table that can be used for both purposes, differentiated by the 'type' column.
CREATE TABLE IF NOT EXISTS public.rag_vector (
id uuid not null default gen_random_uuid (),
embeddings public.vector not null,
value_to_be_embedded character varying(200) not null,
actual_value character varying(255) null,
column_name character varying(255) null,
type character varying(200) not null,
created_at timestamp with time zone null default now(),
updated_at timestamp with time zone null default now(),
constraint rag_vector_pkey primary key (id)
) TABLESPACE pg_default;
create index IF not exists ix_rag_vector_type on public.rag_vector using btree (type) TABLESPACE pg_default;
create index IF not exists ix_rag_vector_value on public.rag_vector using btree (value_to_be_embedded) TABLESPACE pg_default;
-- RLS Policies for profiles_rls
create table public.profiles_rls (
id bigint generated by default as identity not null,
email text not null,
source text not null,
country text not null,
customer_soldto text not null,
constraint profiles_rls_pkey primary key (id)
) TABLESPACE pg_default;
-- Supabase setup script for documents storage and metadata
-- 1) Create a Storage bucket named 'documents' via Supabase Dashboard -> Storage
-- (Set Public Access = false if you want private files.)
-- 2) Optional: ensure pgcrypto extension (for gen_random_uuid)
-- Run in SQL editor if your DB allows extensions
create extension if not exists pgcrypto;
-- 3) Create metadata table
create table if not exists documents (
id uuid primary key default gen_random_uuid(),
user_id uuid references auth.users(id) not null,
filename text not null,
storage_path text not null,
uploaded_at timestamp with time zone default now()
);
-- 4) Enable Row-Level Security (RLS)
alter table documents enable row level security;
-- 5) Policies
-- Users can only view their own documents
drop policy if exists "Users can view own documents" on documents;
create policy "Users can view own documents"
on documents for select
using (auth.uid() = user_id);
-- Users can only insert documents with their own user_id
drop policy if exists "Users can insert own documents" on documents;
create policy "Users can insert own documents"
on documents for insert
with check (auth.uid() = user_id);
-- Users can update only their own documents
drop policy if exists "Users can update own documents" on documents;
create policy "Users can update own documents"
on documents for update
using (auth.uid() = user_id)
with check (auth.uid() = user_id);
-- Users can delete only their own documents
drop policy if exists "Users can delete own documents" on documents;
create policy "Users can delete own documents"
on documents for delete
using (auth.uid() = user_id);
-- Notes:
-- - Create the storage bucket in the Supabase dashboard called `documents`.
-- - Make sure your service_role key or server-side client is used for storage uploads
-- from a trusted backend (do not embed the service_role key in frontend code).
create table public.rag_user_documents (
id uuid not null default gen_random_uuid (),
user_id uuid not null,
content text not null,
embedding double precision[] not null,
doc_id uuid null,
constraint rag_user_documents_pkey primary key (id),
constraint rag_user_documents_doc_id_fkey foreign KEY (doc_id) references documents (id) on update CASCADE on delete CASCADE
) TABLESPACE pg_default;