AniDojo uses PostgreSQL through Supabase to store user data, anime entries, reviews, and more. The database schema includes Row Level Security (RLS) policies to ensure data privacy.
Extends Supabase Auth with additional user information.
CREATE TABLE public.profiles ( id UUID REFERENCES auth.users(id) ON DELETE CASCADE PRIMARY KEY, username TEXT UNIQUE NOT NULL, avatar_url TEXT, bio TEXT, created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL);
Profiles table details
Key Features:
Automatically created via trigger when user signs up
-- Everyone can view profilesCREATE POLICY "Users can view all profiles" ON public.profiles FOR SELECT USING (true);-- Users can update their own profileCREATE POLICY "Users can update their own profile" ON public.profiles FOR UPDATE USING (auth.uid() = id);
-- Users can only see their own entriesCREATE POLICY "Users can view their own anime entries" ON public.anime_entries FOR SELECT USING (auth.uid() = user_id);-- Users can insert their own entriesCREATE POLICY "Users can insert their own anime entries" ON public.anime_entries FOR INSERT WITH CHECK (auth.uid() = user_id);
-- Anyone can view published reviews, users can see their own draftsCREATE POLICY "Anyone can view published reviews" ON public.reviews FOR SELECT USING (status = 'published' OR auth.uid() = user_id);
RLS policies are enforced at the database level, providing security even if client code is compromised.
CREATE OR REPLACE FUNCTION public.handle_new_user()RETURNS TRIGGER AS $$BEGIN INSERT INTO public.profiles (id, username) VALUES ( NEW.id, COALESCE(NEW.raw_user_meta_data->>'username', split_part(NEW.email, '@', 1)) ); RETURN NEW;END;$$ LANGUAGE plpgsql SECURITY DEFINER;CREATE TRIGGER on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
CREATE OR REPLACE FUNCTION public.handle_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 public.handle_updated_at();
-- Anime entries indexesCREATE INDEX idx_anime_entries_user_id ON public.anime_entries(user_id);CREATE INDEX idx_anime_entries_anime_id ON public.anime_entries(anime_id);CREATE INDEX idx_anime_entries_status ON public.anime_entries(status);-- Reviews indexesCREATE INDEX idx_reviews_user_id ON public.reviews(user_id);CREATE INDEX idx_reviews_anime_id ON public.reviews(anime_id);CREATE INDEX idx_reviews_status ON public.reviews(status);-- Partial unique index for published reviewsCREATE UNIQUE INDEX idx_reviews_user_anime_publishedON public.reviews(user_id, anime_id) WHERE status = 'published';