What It Does
Collections are user-curated folders for organizing saved recipes and posts. They can be public (visible to everyone) or private (owner-only).
User Flow — Create
Navigate to app/collection/new.tsx → fill in name, description, public/private toggle (via ToggleSwitch) → supabase.from('collections').insert({...}).
User Flow — View
Tap collection → app/collection/[id].tsx → CollectionDetailView renders collection info + grid of saved items.
User Flow — Edit
Owner taps edit → app/collection/[id]/edit.tsx → pre-populated form → can modify name, description, public/private toggle → supabase.from('collections').update({...}).
Screens & Components
Screen/Component Purpose app/collection/new.tsxCollection creation app/collection/[id].tsxCollection detail app/collection/[id]/edit.tsxCollection edit flow CollectionDetailViewDetail view with item grid CollectionFormCreate/edit form
Hooks
useCollections (src/hooks/api/useCollections.ts)
Data Access Pattern
The mobile app calls Supabase directly. useCollection(id) uses supabase.rpc('get_collection_detail'), but useCollections does a direct table query: supabase.from('collections').select(...) with a JOIN to profiles — it does NOT use an RPC. Create, update, and delete also use direct table operations, not RPCs.
Mobile (Direct Supabase)
Hook Supabase Call Purpose useCollections(filters)supabase.from('collections').select(...)List collections (direct query, not RPC) useCollection(id)supabase.rpc('get_collection_detail')Collection detail with paginated items useCreateCollectionsupabase.from('collections').insert(...)Create collection useUpdateCollectionsupabase.from('collections').update(...)Update (with ownership check) useDeleteCollectionsupabase.from('collections').delete(...)Hard delete (CASCADE handles cleanup) useSavedPageDatasupabase.rpc('get_saved_page_data')Saved tab overview data useUserCollectionssupabase.from('collections').select(...)User’s collections for ContentSelector useUncategorizedSavedItemssupabase.rpc('get_uncategorized_saved_items')Items not in any collection useToggleSaveToCollectionsupabase.from('collection_saved_items').insert/deleteToggle collection membership
useDeleteCollection performs a HARD delete (supabase.from('collections').delete()), not a soft delete. The CASCADE constraint on collection_saved_items handles cleanup automatically.
Web API Routes (Phase 2)
Method Route Purpose POST/api/collectionsCreate collection GET/api/collections/[id]Get detail (calls get_collection_detail RPC) PUT/api/collections/[id]Update collection DELETE/api/collections/[id]Delete collection GET/api/collections/listList collections (calls get_collections_list RPC) POST/DELETE/api/collections/[id]/itemsAdd/remove items
RPC Functions
Function Parameters Returns get_collection_detailp_collection_id, p_current_user_id, p_item_limit (20), p_item_offset (0)JSON — collection with items, pagination get_collections_listp_limit, p_offset, p_current_user_idJSON — paginated collection list get_user_collections_for_save_modalp_user_id, p_saved_item_id (optional)TABLE(id, name, is_public, preview_image_url, item_count, is_in_collection) — used by SaveModal
Database Tables
Table Key Columns Notes collectionsid, user_id (FK→profiles), name, description, cover_recipe_id (text, nullable — loose reference, no FK), is_public (default false), is_deleted (default false), item_count (denormalized, default 0)is_public controls visibility. is_deleted exists for RLS filtering but mobile useDeleteCollection does a hard delete.collection_saved_itemscollection_id (FK→collections), saved_item_id (FK→saved_items), added_atComposite PK. Junction table.
collections.cover_recipe_id is typed as text (not uuid) and has no foreign key constraint — it’s a loose reference.
RLS Policies
collections:
SELECT: (is_deleted = false) OR (auth.uid() = user_id)
INSERT/UPDATE/DELETE: auth.uid() = user_id
collection_saved_items:
SELECT: true (public)
INSERT: Must own both the collection AND the saved_item (double ownership check)
DELETE: Must own the collection
Triggers
Trigger Table Events Function trigger_update_profile_collection_countcollectionsINSERT, UPDATE, DELETE update_profile_collection_count()trigger_update_collection_item_countcollection_saved_itemsINSERT, DELETE update_collection_item_count()update_collections_updated_atcollectionsUPDATE update_updated_at_column()
Saved Items Bookmark system that feeds collections
Profile Collections appear on user profiles