diff --git a/supabase/migrations/002_rls_policies.sql b/supabase/migrations/002_rls_policies.sql new file mode 100644 index 0000000..933c1bb --- /dev/null +++ b/supabase/migrations/002_rls_policies.sql @@ -0,0 +1,180 @@ +-- Migration: Row Level Security Policies +-- Created: 2026-02-09 +-- Issue: #14 +-- Description: Enables RLS and creates security policies for all tables + +-- ====================== +-- ENABLE RLS +-- ====================== + +ALTER TABLE inventory_items ENABLE ROW LEVEL SECURITY; +ALTER TABLE products ENABLE ROW LEVEL SECURITY; +ALTER TABLE tags ENABLE ROW LEVEL SECURITY; +ALTER TABLE item_tags ENABLE ROW LEVEL SECURITY; +ALTER TABLE units ENABLE ROW LEVEL SECURITY; +ALTER TABLE user_profiles ENABLE ROW LEVEL SECURITY; + +-- ====================== +-- INVENTORY_ITEMS POLICIES +-- ====================== + +-- Everyone can read (shared household inventory) +CREATE POLICY "inventory_items_select_all" ON inventory_items + FOR SELECT + USING (true); + +-- Authenticated users can insert items +CREATE POLICY "inventory_items_insert_auth" ON inventory_items + FOR INSERT + WITH CHECK (auth.uid() IS NOT NULL); + +-- Authenticated users can update any item +CREATE POLICY "inventory_items_update_auth" ON inventory_items + FOR UPDATE + USING (auth.uid() IS NOT NULL); + +-- Authenticated users can delete any item +CREATE POLICY "inventory_items_delete_auth" ON inventory_items + FOR DELETE + USING (auth.uid() IS NOT NULL); + +-- ====================== +-- PRODUCTS POLICIES +-- ====================== + +-- Everyone can read cached products +CREATE POLICY "products_select_all" ON products + FOR SELECT + USING (true); + +-- Only service role can write (via Edge Functions) +-- No user-level INSERT/UPDATE/DELETE policies + +-- ====================== +-- TAGS POLICIES +-- ====================== + +-- Everyone can read all tags +CREATE POLICY "tags_select_all" ON tags + FOR SELECT + USING (true); + +-- Authenticated users can create tags +CREATE POLICY "tags_insert_auth" ON tags + FOR INSERT + WITH CHECK (auth.uid() IS NOT NULL); + +-- Users can update their own tags OR system tags (created_by IS NULL) +CREATE POLICY "tags_update_own" ON tags + FOR UPDATE + USING ( + created_by = auth.uid() OR created_by IS NULL + ); + +-- Users can only delete their own custom tags +CREATE POLICY "tags_delete_own" ON tags + FOR DELETE + USING (created_by = auth.uid()); + +-- ====================== +-- ITEM_TAGS POLICIES +-- ====================== + +-- Everyone can read +CREATE POLICY "item_tags_select_all" ON item_tags + FOR SELECT + USING (true); + +-- Authenticated users can add tags to items +CREATE POLICY "item_tags_insert_auth" ON item_tags + FOR INSERT + WITH CHECK (auth.uid() IS NOT NULL); + +-- Authenticated users can remove tags from items +CREATE POLICY "item_tags_delete_auth" ON item_tags + FOR DELETE + USING (auth.uid() IS NOT NULL); + +-- ====================== +-- UNITS POLICIES +-- ====================== + +-- Everyone can read all units +CREATE POLICY "units_select_all" ON units + FOR SELECT + USING (true); + +-- Authenticated users can create custom units (not default ones) +CREATE POLICY "units_insert_auth" ON units + FOR INSERT + WITH CHECK ( + auth.uid() IS NOT NULL AND is_default = false + ); + +-- Users can update their own custom units only +CREATE POLICY "units_update_own" ON units + FOR UPDATE + USING ( + created_by = auth.uid() AND is_default = false + ); + +-- Users can delete their own custom units only +CREATE POLICY "units_delete_own" ON units + FOR DELETE + USING ( + created_by = auth.uid() AND is_default = false + ); + +-- ====================== +-- USER_PROFILES POLICIES +-- ====================== + +-- Users can read all profiles (for display names, avatars) +CREATE POLICY "user_profiles_select_all" ON user_profiles + FOR SELECT + USING (true); + +-- Users can insert their own profile +CREATE POLICY "user_profiles_insert_own" ON user_profiles + FOR INSERT + WITH CHECK (auth.uid() = id); + +-- Users can update only their own profile +CREATE POLICY "user_profiles_update_own" ON user_profiles + FOR UPDATE + USING (auth.uid() = id); + +-- Users can delete only their own profile +CREATE POLICY "user_profiles_delete_own" ON user_profiles + FOR DELETE + USING (auth.uid() = id); + +-- ====================== +-- COMMENTS +-- ====================== + +COMMENT ON POLICY "inventory_items_select_all" ON inventory_items IS 'Allow all users to view shared household inventory'; +COMMENT ON POLICY "inventory_items_insert_auth" ON inventory_items IS 'Authenticated users can add items'; +COMMENT ON POLICY "inventory_items_update_auth" ON inventory_items IS 'Authenticated users can update any item (shared inventory)'; +COMMENT ON POLICY "inventory_items_delete_auth" ON inventory_items IS 'Authenticated users can delete any item'; + +COMMENT ON POLICY "products_select_all" ON products IS 'Allow all users to view cached product data'; + +COMMENT ON POLICY "tags_select_all" ON tags IS 'Allow all users to view tags (system and custom)'; +COMMENT ON POLICY "tags_insert_auth" ON tags IS 'Authenticated users can create custom tags'; +COMMENT ON POLICY "tags_update_own" ON tags IS 'Users can update their own tags or system tags'; +COMMENT ON POLICY "tags_delete_own" ON tags IS 'Users can only delete their own custom tags'; + +COMMENT ON POLICY "item_tags_select_all" ON item_tags IS 'Allow all users to view item tag associations'; +COMMENT ON POLICY "item_tags_insert_auth" ON item_tags IS 'Authenticated users can tag items'; +COMMENT ON POLICY "item_tags_delete_auth" ON item_tags IS 'Authenticated users can remove tags from items'; + +COMMENT ON POLICY "units_select_all" ON units IS 'Allow all users to view all units'; +COMMENT ON POLICY "units_insert_auth" ON units IS 'Authenticated users can create custom units'; +COMMENT ON POLICY "units_update_own" ON units IS 'Users can only update their own custom units'; +COMMENT ON POLICY "units_delete_own" ON units IS 'Users can only delete their own custom units'; + +COMMENT ON POLICY "user_profiles_select_all" ON user_profiles IS 'Allow users to view all profiles for display purposes'; +COMMENT ON POLICY "user_profiles_insert_own" ON user_profiles IS 'Users can create their own profile'; +COMMENT ON POLICY "user_profiles_update_own" ON user_profiles IS 'Users can only update their own profile'; +COMMENT ON POLICY "user_profiles_delete_own" ON user_profiles IS 'Users can only delete their own profile';