mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
delete supabase migrations
This commit is contained in:
parent
31d3ac8c97
commit
b983bd06ef
@ -1,52 +0,0 @@
|
||||
---
|
||||
# Specify the following for Cursor rules
|
||||
description: Guidelines for writing Postgres migrations
|
||||
globs: "supabase/migrations/**/*.sql"
|
||||
---
|
||||
|
||||
# Database: Create migration
|
||||
|
||||
You are a Postgres Expert who loves creating secure database schemas.
|
||||
|
||||
This project uses the migrations provided by the Supabase CLI.
|
||||
|
||||
## Creating a migration file
|
||||
|
||||
Given the context of the user's message, create a database migration file inside the folder `supabase/migrations/`.
|
||||
|
||||
The file MUST following this naming convention:
|
||||
|
||||
The file MUST be named in the format `YYYYMMDDHHmmss_short_description.sql` with proper casing for months, minutes, and seconds in UTC time:
|
||||
|
||||
1. `YYYY` - Four digits for the year (e.g., `2024`).
|
||||
2. `MM` - Two digits for the month (01 to 12).
|
||||
3. `DD` - Two digits for the day of the month (01 to 31).
|
||||
4. `HH` - Two digits for the hour in 24-hour format (00 to 23).
|
||||
5. `mm` - Two digits for the minute (00 to 59).
|
||||
6. `ss` - Two digits for the second (00 to 59).
|
||||
7. Add an appropriate description for the migration.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
20240906123045_create_profiles.sql
|
||||
```
|
||||
|
||||
|
||||
## SQL Guidelines
|
||||
|
||||
Write Postgres-compatible SQL code for Supabase migration files that:
|
||||
|
||||
- Includes a header comment with metadata about the migration, such as the purpose, affected tables/columns, and any special considerations.
|
||||
- Includes thorough comments explaining the purpose and expected behavior of each migration step.
|
||||
- Write all SQL in lowercase.
|
||||
- Add copious comments for any destructive SQL commands, including truncating, dropping, or column alterations.
|
||||
- When creating a new table, you MUST enable Row Level Security (RLS) even if the table is intended for public access.
|
||||
- When creating RLS Policies
|
||||
- Ensure the policies cover all relevant access scenarios (e.g. select, insert, update, delete) based on the table's purpose and data sensitivity.
|
||||
- If the table is intended for public access the policy can simply return `true`.
|
||||
- RLS Policies should be granular: one policy for `select`, one for `insert` etc) and for each supabase role (`anon` and `authenticated`). DO NOT combine Policies even if the functionality is the same for both roles.
|
||||
- Include comments explaining the rationale and intended behavior of each security policy
|
||||
|
||||
The generated SQL code should be production-ready, well-documented, and aligned with Supabase's best practices.
|
||||
|
||||
@ -1,170 +0,0 @@
|
||||
-- Create problems table
|
||||
CREATE TABLE IF NOT EXISTS problems (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
title TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
status TEXT NOT NULL CHECK (status IN ('pending', 'solved', 'unsolved')),
|
||||
keywords TEXT[] NOT NULL DEFAULT '{}',
|
||||
repository_contents JSONB NOT NULL DEFAULT '{}',
|
||||
user_id UUID REFERENCES auth.users(id)
|
||||
);
|
||||
|
||||
-- Create problem_comments table
|
||||
CREATE TABLE IF NOT EXISTS problem_comments (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
problem_id UUID NOT NULL REFERENCES problems(id) ON DELETE CASCADE,
|
||||
content TEXT NOT NULL,
|
||||
username TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Create updated_at trigger for problems table
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = now();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
CREATE TRIGGER update_problems_updated_at
|
||||
BEFORE UPDATE ON problems
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- Create RLS policies
|
||||
ALTER TABLE problems ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE problem_comments ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Allow public read access to problems and comments
|
||||
CREATE POLICY "Allow public read access to problems"
|
||||
ON problems FOR SELECT
|
||||
TO public
|
||||
USING (true);
|
||||
|
||||
CREATE POLICY "Allow public read access to problem comments"
|
||||
ON problem_comments FOR SELECT
|
||||
TO public
|
||||
USING (true);
|
||||
|
||||
-- Allow anyone to create problems (including anonymous users)
|
||||
DROP POLICY IF EXISTS "Allow authenticated users to create problems" ON problems;
|
||||
DROP POLICY IF EXISTS "Allow anyone to create problems" ON problems;
|
||||
CREATE POLICY "Allow anyone to create problems"
|
||||
ON problems FOR INSERT
|
||||
TO public
|
||||
WITH CHECK (true);
|
||||
|
||||
-- Allow anyone to update problems
|
||||
DROP POLICY IF EXISTS "Allow authenticated users to update problems" ON problems;
|
||||
DROP POLICY IF EXISTS "Allow anyone to update problems" ON problems;
|
||||
CREATE POLICY "Allow anyone to update problems"
|
||||
ON problems FOR UPDATE
|
||||
TO public
|
||||
USING (true)
|
||||
WITH CHECK (true);
|
||||
|
||||
-- Allow anyone to create comments
|
||||
DROP POLICY IF EXISTS "Allow authenticated users to create comments" ON problem_comments;
|
||||
DROP POLICY IF EXISTS "Allow anyone to create comments" ON problem_comments;
|
||||
CREATE POLICY "Allow anyone to create comments"
|
||||
ON problem_comments FOR INSERT
|
||||
TO public
|
||||
WITH CHECK (true);
|
||||
|
||||
-- Create function to get problem with comments
|
||||
CREATE OR REPLACE FUNCTION get_problem_with_comments(problem_id UUID)
|
||||
RETURNS TABLE (
|
||||
id UUID,
|
||||
created_at TIMESTAMPTZ,
|
||||
updated_at TIMESTAMPTZ,
|
||||
title TEXT,
|
||||
description TEXT,
|
||||
status TEXT,
|
||||
keywords TEXT[],
|
||||
repository_contents JSONB,
|
||||
user_id UUID,
|
||||
problem_comments JSON
|
||||
) AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
p.id,
|
||||
p.created_at,
|
||||
p.updated_at,
|
||||
p.title,
|
||||
p.description,
|
||||
p.status,
|
||||
p.keywords,
|
||||
p.repository_contents,
|
||||
p.user_id,
|
||||
COALESCE(
|
||||
json_agg(
|
||||
json_build_object(
|
||||
'id', c.id,
|
||||
'created_at', c.created_at,
|
||||
'problem_id', c.problem_id,
|
||||
'content', c.content,
|
||||
'username', c.username
|
||||
)
|
||||
) FILTER (WHERE c.id IS NOT NULL),
|
||||
'[]'::json
|
||||
) as problem_comments
|
||||
FROM problems p
|
||||
LEFT JOIN problem_comments c ON c.problem_id = p.id
|
||||
WHERE p.id = problem_id
|
||||
GROUP BY p.id;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Create profiles for existing users who don't have one
|
||||
DO $$
|
||||
DECLARE
|
||||
user_record RECORD;
|
||||
BEGIN
|
||||
-- Loop through all users in auth.users who don't have a profile
|
||||
FOR user_record IN
|
||||
SELECT au.id, au.email
|
||||
FROM auth.users au
|
||||
LEFT JOIN public.profiles p ON p.id = au.id
|
||||
WHERE p.id IS NULL
|
||||
LOOP
|
||||
-- Insert a new profile for each user
|
||||
INSERT INTO public.profiles (
|
||||
id,
|
||||
username,
|
||||
full_name,
|
||||
avatar_url,
|
||||
is_admin
|
||||
) VALUES (
|
||||
user_record.id,
|
||||
user_record.email,
|
||||
NULL,
|
||||
NULL,
|
||||
FALSE
|
||||
);
|
||||
|
||||
RAISE NOTICE 'Created profile for user %', user_record.email;
|
||||
END LOOP;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Output the number of profiles created
|
||||
SELECT 'Profiles created for existing users: ' || COUNT(*)::text as result
|
||||
FROM (
|
||||
SELECT au.id
|
||||
FROM auth.users au
|
||||
LEFT JOIN public.profiles p ON p.id = au.id
|
||||
WHERE p.id IS NULL
|
||||
) as missing_profiles;
|
||||
|
||||
-- List all profiles
|
||||
SELECT
|
||||
p.id,
|
||||
p.username,
|
||||
p.is_admin,
|
||||
p.created_at
|
||||
FROM public.profiles p
|
||||
ORDER BY p.created_at DESC;
|
||||
@ -1,55 +0,0 @@
|
||||
-- Create feedback table
|
||||
CREATE TABLE IF NOT EXISTS public.feedback (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
user_id UUID REFERENCES auth.users(id),
|
||||
description TEXT NOT NULL,
|
||||
status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'reviewed', 'resolved')),
|
||||
metadata JSONB DEFAULT '{}'
|
||||
);
|
||||
|
||||
-- Create updated_at trigger for feedback table
|
||||
CREATE TRIGGER update_feedback_updated_at
|
||||
BEFORE UPDATE ON public.feedback
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- Enable Row Level Security
|
||||
ALTER TABLE public.feedback ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Create policies for feedback table
|
||||
-- Allow public read access to feedback for admins
|
||||
CREATE POLICY "Allow admin read access to all feedback"
|
||||
ON public.feedback FOR SELECT
|
||||
TO public
|
||||
USING (
|
||||
auth.uid() IN (SELECT id FROM public.profiles WHERE is_admin = true)
|
||||
);
|
||||
|
||||
-- Allow users to read their own feedback
|
||||
CREATE POLICY "Allow users to read their own feedback"
|
||||
ON public.feedback FOR SELECT
|
||||
TO public
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
-- Allow anyone to create feedback (including anonymous users)
|
||||
CREATE POLICY "Allow anyone to create feedback"
|
||||
ON public.feedback FOR INSERT
|
||||
TO public
|
||||
WITH CHECK (true);
|
||||
|
||||
-- Allow admins to update any feedback
|
||||
CREATE POLICY "Allow admins to update any feedback"
|
||||
ON public.feedback FOR UPDATE
|
||||
TO public
|
||||
USING (
|
||||
auth.uid() IN (SELECT id FROM public.profiles WHERE is_admin = true)
|
||||
);
|
||||
|
||||
-- Allow users to update their own feedback
|
||||
CREATE POLICY "Allow users to update their own feedback"
|
||||
ON public.feedback FOR UPDATE
|
||||
TO public
|
||||
USING (auth.uid() = user_id)
|
||||
WITH CHECK (auth.uid() = user_id);
|
||||
@ -1,49 +0,0 @@
|
||||
-- Create profiles for existing users who don't have one
|
||||
DO $$
|
||||
DECLARE
|
||||
user_record RECORD;
|
||||
BEGIN
|
||||
-- Loop through all users in auth.users who don't have a profile
|
||||
FOR user_record IN
|
||||
SELECT au.id, au.email
|
||||
FROM auth.users au
|
||||
LEFT JOIN public.profiles p ON p.id = au.id
|
||||
WHERE p.id IS NULL
|
||||
LOOP
|
||||
-- Insert a new profile for each user
|
||||
INSERT INTO public.profiles (
|
||||
id,
|
||||
username,
|
||||
full_name,
|
||||
avatar_url,
|
||||
is_admin
|
||||
) VALUES (
|
||||
user_record.id,
|
||||
user_record.email,
|
||||
NULL,
|
||||
NULL,
|
||||
FALSE
|
||||
);
|
||||
|
||||
RAISE NOTICE 'Created profile for user %', user_record.email;
|
||||
END LOOP;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Output the number of profiles created
|
||||
SELECT 'Profiles created for existing users: ' || COUNT(*)::text as result
|
||||
FROM (
|
||||
SELECT au.id
|
||||
FROM auth.users au
|
||||
LEFT JOIN public.profiles p ON p.id = au.id
|
||||
WHERE p.id IS NULL
|
||||
) as missing_profiles;
|
||||
|
||||
-- List all profiles
|
||||
SELECT
|
||||
p.id,
|
||||
p.username,
|
||||
p.is_admin,
|
||||
p.created_at
|
||||
FROM public.profiles p
|
||||
ORDER BY p.created_at DESC;
|
||||
@ -1,49 +0,0 @@
|
||||
-- Create profiles for existing users who don't have one
|
||||
DO $$
|
||||
DECLARE
|
||||
user_record RECORD;
|
||||
BEGIN
|
||||
-- Loop through all users in auth.users who don't have a profile
|
||||
FOR user_record IN
|
||||
SELECT au.id, au.email
|
||||
FROM auth.users au
|
||||
LEFT JOIN public.profiles p ON p.id = au.id
|
||||
WHERE p.id IS NULL
|
||||
LOOP
|
||||
-- Insert a new profile for each user
|
||||
INSERT INTO public.profiles (
|
||||
id,
|
||||
username,
|
||||
full_name,
|
||||
avatar_url,
|
||||
is_admin
|
||||
) VALUES (
|
||||
user_record.id,
|
||||
user_record.email,
|
||||
NULL,
|
||||
NULL,
|
||||
FALSE
|
||||
);
|
||||
|
||||
RAISE NOTICE 'Created profile for user %', user_record.email;
|
||||
END LOOP;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Output the number of profiles created
|
||||
SELECT 'Profiles created for existing users: ' || COUNT(*)::text as result
|
||||
FROM (
|
||||
SELECT au.id
|
||||
FROM auth.users au
|
||||
LEFT JOIN public.profiles p ON p.id = au.id
|
||||
WHERE p.id IS NULL
|
||||
) as missing_profiles;
|
||||
|
||||
-- List all profiles
|
||||
SELECT
|
||||
p.id,
|
||||
p.username,
|
||||
p.is_admin,
|
||||
p.created_at
|
||||
FROM public.profiles p
|
||||
ORDER BY p.created_at DESC;
|
||||
@ -1,92 +0,0 @@
|
||||
-- Create profiles table
|
||||
CREATE TABLE IF NOT EXISTS public.profiles (
|
||||
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
|
||||
username TEXT UNIQUE,
|
||||
full_name TEXT,
|
||||
avatar_url TEXT,
|
||||
is_admin BOOLEAN DEFAULT FALSE NOT NULL
|
||||
);
|
||||
|
||||
-- Create a trigger to update the updated_at column
|
||||
CREATE OR REPLACE FUNCTION update_profiles_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER update_profiles_updated_at
|
||||
BEFORE UPDATE ON public.profiles
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_profiles_updated_at();
|
||||
|
||||
-- Create a policy to allow users to read all profiles
|
||||
CREATE POLICY "Profiles are viewable by everyone"
|
||||
ON public.profiles FOR SELECT
|
||||
USING (true);
|
||||
|
||||
-- Drop the existing policies if they exist
|
||||
DROP POLICY IF EXISTS "Users can update their own profile" ON public.profiles;
|
||||
DROP POLICY IF EXISTS "Only admins can update is_admin field" ON public.profiles;
|
||||
|
||||
-- Create a policy to allow users to update their own non-admin fields
|
||||
CREATE OR REPLACE FUNCTION check_is_admin_unchanged(is_admin_new boolean, user_id uuid)
|
||||
RETURNS boolean AS $$
|
||||
DECLARE
|
||||
is_admin_old boolean;
|
||||
BEGIN
|
||||
SELECT p.is_admin INTO is_admin_old FROM public.profiles p WHERE p.id = user_id;
|
||||
RETURN is_admin_new = is_admin_old;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Create a policy to allow users to update their own profile EXCEPT the is_admin field
|
||||
CREATE POLICY "Users can update their own non-admin fields"
|
||||
ON public.profiles FOR UPDATE
|
||||
USING (auth.uid() = id)
|
||||
WITH CHECK (
|
||||
check_is_admin_unchanged(is_admin, id)
|
||||
);
|
||||
|
||||
-- Create a policy to allow only admins to update any profile including the is_admin field
|
||||
CREATE POLICY "Admins can update any profile"
|
||||
ON public.profiles FOR UPDATE
|
||||
USING (
|
||||
auth.uid() IN (SELECT id FROM public.profiles WHERE is_admin = true)
|
||||
);
|
||||
|
||||
-- Create a policy to 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 AND
|
||||
(is_admin = false OR auth.uid() IN (SELECT id FROM public.profiles WHERE is_admin = true))
|
||||
);
|
||||
|
||||
-- Enable RLS on the profiles table
|
||||
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Create a function to handle new user signups
|
||||
CREATE OR REPLACE FUNCTION public.handle_new_user()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
-- Insert a row into public.profiles
|
||||
INSERT INTO public.profiles (id, username, is_admin)
|
||||
VALUES (NEW.id, NEW.email, FALSE);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Create a trigger to automatically create a profile for new users
|
||||
CREATE OR REPLACE TRIGGER on_auth_user_created
|
||||
AFTER INSERT ON auth.users
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_new_user();
|
||||
|
||||
-- Set the first user as an admin (optional - uncomment and modify as needed)
|
||||
-- UPDATE public.profiles
|
||||
-- SET is_admin = TRUE
|
||||
-- WHERE id = '[YOUR_USER_ID]';
|
||||
Loading…
Reference in New Issue
Block a user