Overview
AniDojo uses Supabase (PostgreSQL) for data storage with Row Level Security (RLS) enabled for all tables. The schema supports anime tracking, reviews, comments, custom lists, and user profiles.Core Tables
profiles
Extends Supabase Auth users with additional profile information.Primary key, references
auth.users(id) with CASCADE deleteUnique username for the user
URL to user’s avatar image in storage
User biography/description
Timestamp when profile was created (default: NOW())
Timestamp when profile was last updated (auto-updated by trigger)
- Primary Key:
id - Unique:
username - Foreign Key:
id→auth.users(id)ON DELETE CASCADE
- Primary key index on
id
anime_entries
Stores user’s anime list entries with watch status, progress, and ratings.Primary key, auto-generated with
uuid_generate_v4()References
profiles(id) with CASCADE deleteID from external anime API (e.g., Jikan/MyAnimeList)
Primary title of the anime
English title translation
Original Japanese title
URL to anime cover image
Anime type (TV, Movie, OVA, etc.)
Total number of episodes
Watch status. Must be one of:
watchingcompletedon-holddroppedplan-to-watch
Number of episodes watched (default: 0)
User rating from 1-10
Date when user started watching
Date when user finished watching
Personal notes about the anime
Custom tags (default: empty array)
Whether anime is marked as favorite (default: false)
Number of times rewatched (default: 0)
Priority level:
low, medium, or highAnime genres (default: empty array)
Release year
Content rating (G, PG, PG-13, R, etc.)
Timestamp when entry was created (default: NOW())
Timestamp when entry was last updated (auto-updated by trigger)
- Primary Key:
id - Unique:
(user_id, anime_id)- one entry per user per anime - Foreign Key:
user_id→profiles(id)ON DELETE CASCADE - Check:
statusIN (‘watching’, ‘completed’, ‘on-hold’, ‘dropped’, ‘plan-to-watch’) - Check:
scoreBETWEEN 1 AND 10 - Check:
priorityIN (‘low’, ‘medium’, ‘high’)
idx_anime_entries_user_idonuser_ididx_anime_entries_anime_idonanime_ididx_anime_entries_statusonstatus
reviews
Detailed anime reviews with ratings, recommendations, and draft support.Primary key, auto-generated with
uuid_generate_v4()References
profiles(id) with CASCADE deleteID from external anime API
Overall rating from 1-10
Story/plot rating from 1-10
Animation quality rating from 1-10
Sound/music rating from 1-10
Character development rating from 1-10
Personal enjoyment rating from 1-10
Review title/headline
Full review text content
Whether review contains spoilers (default: false)
Watch status when review was written:
completedwatchingdroppedplan-to-watch
Episodes watched at time of review
Review tags (default: empty array)
Positive aspects of the anime
Negative aspects of the anime
Recommendation level:
highly-recommendrecommendmixednot-recommendstrongly-not-recommend
Publication status:
draft or published (default: draft)Net helpful votes count (default: 0, auto-updated by trigger)
Timestamp when review was created (default: NOW())
Timestamp when review was last updated (auto-updated by trigger)
- Primary Key:
id - Foreign Key:
user_id→profiles(id)ON DELETE CASCADE - Check:
ratingBETWEEN 1 AND 10 - Check:
story_rating,animation_rating,sound_rating,character_rating,enjoyment_ratingBETWEEN 1 AND 10 - Check:
watch_statusIN (‘completed’, ‘watching’, ‘dropped’, ‘plan-to-watch’) - Check:
recommendationIN (‘highly-recommend’, ‘recommend’, ‘mixed’, ‘not-recommend’, ‘strongly-not-recommend’) - Check:
statusIN (‘draft’, ‘published’) - Unique:
(user_id, anime_id)WHEREstatus = 'published'(one published review per user per anime)
idx_reviews_user_idonuser_ididx_reviews_anime_idonanime_ididx_reviews_statusonstatusidx_reviews_user_anime_publishedon(user_id, anime_id)WHEREstatus = 'published'
review_votes
Tracks helpful/not helpful votes on reviews.Primary key, auto-generated with
uuid_generate_v4()References
reviews(id) with CASCADE deleteReferences
profiles(id) with CASCADE deleteTrue for helpful vote, false for not helpful
Timestamp when vote was created (default: NOW())
- Primary Key:
id - Unique:
(review_id, user_id)- one vote per user per review - Foreign Key:
review_id→reviews(id)ON DELETE CASCADE - Foreign Key:
user_id→profiles(id)ON DELETE CASCADE
idx_review_votes_review_idonreview_ididx_review_votes_user_idonuser_id
comments
Comments on reviews with support for threaded replies.Primary key, auto-generated with
uuid_generate_v4()References
reviews(id) with CASCADE deleteReferences
profiles(id) with CASCADE deleteReferences
comments(id) with CASCADE delete for nested repliesComment text content
Timestamp when comment was created (default: NOW())
Timestamp when comment was last updated (auto-updated by trigger)
Soft delete timestamp (null if not deleted)
- Primary Key:
id - Foreign Key:
review_id→reviews(id)ON DELETE CASCADE - Foreign Key:
user_id→profiles(id)ON DELETE CASCADE - Foreign Key:
parent_id→comments(id)ON DELETE CASCADE
idx_comments_review_idonreview_ididx_comments_user_idonuser_ididx_comments_parent_idonparent_id
comment_votes
Upvote/downvote system for comments.Primary key, auto-generated with
uuid_generate_v4()References
comments(id) with CASCADE deleteReferences
profiles(id) with CASCADE deleteTrue for upvote, false for downvote
Timestamp when vote was created (default: NOW())
- Primary Key:
id - Unique:
(comment_id, user_id)- one vote per user per comment - Foreign Key:
comment_id→comments(id)ON DELETE CASCADE - Foreign Key:
user_id→profiles(id)ON DELETE CASCADE
idx_comment_votes_comment_idoncomment_id
custom_lists
User-created custom anime lists.Primary key, auto-generated with
uuid_generate_v4()References
profiles(id) with CASCADE deleteList name/title
List description
Whether list is publicly visible (default: false)
Timestamp when list was created (default: NOW())
Timestamp when list was last updated (auto-updated by trigger)
- Primary Key:
id - Foreign Key:
user_id→profiles(id)ON DELETE CASCADE
idx_custom_lists_user_idonuser_id
custom_list_entries
Anime entries within custom lists.Primary key, auto-generated with
uuid_generate_v4()References
custom_lists(id) with CASCADE deleteID from external anime API
Timestamp when entry was added (default: NOW())
- Primary Key:
id - Unique:
(list_id, anime_id)- one entry per anime per list - Foreign Key:
list_id→custom_lists(id)ON DELETE CASCADE
idx_custom_list_entries_list_idonlist_id
Database Functions
handle_new_user()
Automatically creates a profile when a new user signs up via Supabase Auth.auth.users
handle_updated_at()
Automatically updates theupdated_at timestamp on table updates.
profilesanime_entriesreviewscommentscustom_lists
update_review_helpful_votes()
Automatically maintains thehelpful_votes count on reviews based on votes.
review_votes
Row Level Security (RLS)
All tables have RLS enabled with the following policies:profiles
- SELECT: Anyone can view all profiles
- INSERT: Users can insert their own profile
- UPDATE: Users can update only their own profile
anime_entries
- SELECT: Users can view only their own entries
- INSERT: Users can insert only their own entries
- UPDATE: Users can update only their own entries
- DELETE: Users can delete only their own entries
reviews
- SELECT: Anyone can view published reviews; users can view their own drafts
- INSERT: Users can insert their own reviews
- UPDATE: Users can update only their own reviews
- DELETE: Users can delete only their own reviews
review_votes
- SELECT: Anyone can view all votes
- INSERT: Authenticated users can insert their own votes
- UPDATE: Users can update only their own votes
- DELETE: Users can delete only their own votes
comments
- SELECT: Anyone can view non-deleted comments
- INSERT: Authenticated users can insert comments
- UPDATE: Users can update only their own comments
- DELETE: Users can delete only their own comments
comment_votes
- SELECT: Anyone can view all votes
- INSERT: Authenticated users can insert their own votes
- UPDATE: Users can update only their own votes
- DELETE: Users can delete only their own votes
custom_lists
- SELECT: Users can view public lists or their own private lists
- INSERT: Users can insert only their own lists
- UPDATE: Users can update only their own lists
- DELETE: Users can delete only their own lists
custom_list_entries
- SELECT: Users can view entries for public lists or their own lists
- INSERT: Users can insert entries only to their own lists
- DELETE: Users can delete entries only from their own lists