150 lines
5.4 KiB
PL/PgSQL
150 lines
5.4 KiB
PL/PgSQL
-- RIOTZ SUPABASE DATABASE SCHEMA
|
|
-- Tech Stack: PostgreSQL, Supabase Auth, Storage
|
|
|
|
-- 1. EXTENSIONS
|
|
create extension if not exists "uuid-ossp";
|
|
|
|
-- 2. TABLES
|
|
|
|
-- PROFILES: Core user identity
|
|
create table public.profiles (
|
|
user_id uuid references auth.users on delete cascade primary key,
|
|
username text unique not null,
|
|
bio text,
|
|
avatar_url text,
|
|
featured boolean default false,
|
|
banned boolean default false,
|
|
created_at timestamp with time zone default now(),
|
|
updated_at timestamp with time zone default now()
|
|
);
|
|
|
|
-- POSTS: Visual manifestations
|
|
create table public.posts (
|
|
id uuid default uuid_generate_v4() primary key,
|
|
user_id uuid references public.profiles(user_id) on delete cascade not null,
|
|
image_url text not null,
|
|
caption text,
|
|
likes_count int default 0,
|
|
featured boolean default false,
|
|
created_at timestamp with time zone default now()
|
|
);
|
|
|
|
-- POST LIKES: Engagement tracking
|
|
create table public.post_likes (
|
|
user_id uuid references public.profiles(user_id) on delete cascade not null,
|
|
post_id uuid references public.posts(id) on delete cascade not null,
|
|
created_at timestamp with time zone default now(),
|
|
primary key (user_id, post_id)
|
|
);
|
|
|
|
-- TRACKS: Sonic broadcasts
|
|
create table public.tracks (
|
|
id uuid default uuid_generate_v4() primary key,
|
|
user_id uuid references public.profiles(user_id) on delete cascade not null,
|
|
title text not null,
|
|
audio_url text not null,
|
|
genre_tag text default 'UNKNOWN',
|
|
plays int default 0,
|
|
featured boolean default false,
|
|
created_at timestamp with time zone default now()
|
|
);
|
|
|
|
-- COMMENTS: Chaos discourse
|
|
create table public.comments (
|
|
id uuid default uuid_generate_v4() primary key,
|
|
post_id uuid references public.posts(id) on delete cascade not null,
|
|
user_id uuid references public.profiles(user_id) on delete cascade not null,
|
|
content text not null,
|
|
created_at timestamp with time zone default now()
|
|
);
|
|
|
|
-- BANS: Network exclusion records
|
|
create table public.bans (
|
|
id uuid default uuid_generate_v4() primary key,
|
|
user_id uuid references public.profiles(user_id) on delete cascade not null,
|
|
reason text,
|
|
banned_by uuid references public.profiles(user_id),
|
|
created_at timestamp with time zone default now()
|
|
);
|
|
|
|
-- FEATURED CONTENT: Curated highlights
|
|
create table public.featured_content (
|
|
id uuid default uuid_generate_v4() primary key,
|
|
content_type text not null check (content_type in ('artist', 'post', 'track')),
|
|
content_id uuid not null,
|
|
priority int default 0,
|
|
created_at timestamp with time zone default now()
|
|
);
|
|
|
|
-- 3. FUNCTIONS & TRIGGERS
|
|
|
|
-- Automatically create profile on signup
|
|
create or replace function public.handle_new_user()
|
|
returns trigger as $$
|
|
begin
|
|
insert into public.profiles (user_id, username, avatar_url)
|
|
values (new.id, split_part(new.email, '@', 1), new.raw_user_meta_data->>'avatar_url');
|
|
return new;
|
|
end;
|
|
$$ language plpgsql security definer;
|
|
|
|
create trigger on_auth_user_created
|
|
after insert on auth.users
|
|
for each row execute procedure public.handle_new_user();
|
|
|
|
-- Auto-update likes_count on posts
|
|
create or replace function public.update_post_likes_count()
|
|
returns trigger as $$
|
|
begin
|
|
if (TG_OP = 'INSERT') then
|
|
update public.posts set likes_count = likes_count + 1 where id = new.post_id;
|
|
elsif (TG_OP = 'DELETE') then
|
|
update public.posts set likes_count = likes_count - 1 where id = old.post_id;
|
|
end if;
|
|
return null;
|
|
end;
|
|
$$ language plpgsql security definer;
|
|
|
|
create trigger on_like_changed
|
|
after insert or delete on public.post_likes
|
|
for each row execute procedure public.update_post_likes_count();
|
|
|
|
-- Increment plays RPC
|
|
create or replace function public.increment_track_plays(track_id uuid)
|
|
returns void as $$
|
|
begin
|
|
update public.tracks set plays = plays + 1 where id = track_id;
|
|
end;
|
|
$$ language plpgsql security definer;
|
|
|
|
-- 4. SECURITY (RLS)
|
|
|
|
alter table public.profiles enable row level security;
|
|
alter table public.posts enable row level security;
|
|
alter table public.tracks enable row level security;
|
|
alter table public.post_likes enable row level security;
|
|
alter table public.comments enable row level security;
|
|
|
|
-- Profiles: Public read, owner update
|
|
create policy "Public profiles are viewable by everyone." on public.profiles for select using (true);
|
|
create policy "Users can update own profile." on public.profiles for update using (auth.uid() = user_id);
|
|
|
|
-- Posts: Public read, Auth create, Owner delete
|
|
create policy "Posts are viewable by everyone." on public.posts for select using (true);
|
|
create policy "Authenticated users can create posts." on public.posts for insert with check (auth.role() = 'authenticated');
|
|
create policy "Users can delete own posts." on public.posts for delete using (auth.uid() = user_id);
|
|
|
|
-- Tracks: Public read, Auth create
|
|
create policy "Tracks are viewable by everyone." on public.tracks for select using (true);
|
|
create policy "Authenticated users can upload tracks." on public.tracks for insert with check (auth.role() = 'authenticated');
|
|
|
|
-- Likes: Authenticated management
|
|
create policy "Users can view likes." on public.post_likes for select using (true);
|
|
create policy "Users can manage own likes." on public.post_likes for all using (auth.uid() = user_id);
|
|
|
|
-- 5. INDEXES for Performance
|
|
create index idx_posts_user_id on public.posts(user_id);
|
|
create index idx_posts_created_at on public.posts(created_at desc);
|
|
create index idx_tracks_plays on public.tracks(plays desc);
|
|
create index idx_comments_post_id on public.comments(post_id);
|