-- nightly — Fix migration: align DB with iOS app + add missing features -- Run after 001_schema.sql -- ── 1. Fix mood enum: replace old values with iOS app values ───────────────── -- Drop dependent objects first DROP VIEW IF EXISTS public.feed_posts; ALTER TABLE public.posts ALTER COLUMN mood TYPE text USING mood::text; DROP TYPE IF EXISTS public.post_mood; CREATE TYPE public.post_mood AS ENUM ('still', 'unruhig', 'schwer', 'geladen', 'zart', 'dunkel'); ALTER TABLE public.posts ALTER COLUMN mood TYPE public.post_mood USING mood::public.post_mood; -- ── 2. Increase content length from 280 to 420 ─────────────────────────────── ALTER TABLE public.posts DROP CONSTRAINT posts_content_check; ALTER TABLE public.posts ADD CONSTRAINT posts_content_check CHECK (LENGTH(TRIM(content)) BETWEEN 1 AND 420); -- ── 3. Add content warning columns to posts ───────────────────────────────── ALTER TABLE public.posts ADD COLUMN IF NOT EXISTS has_content_warning BOOLEAN DEFAULT FALSE NOT NULL; ALTER TABLE public.posts ADD COLUMN IF NOT EXISTS content_warning_type TEXT; -- ── 4. Recreate feed_posts view with content_warning fields ────────────────── CREATE OR REPLACE VIEW public.feed_posts AS SELECT p.id, p.content, p.mood, p.is_anonymous, p.created_at, p.has_content_warning, p.content_warning_type, CASE WHEN p.is_anonymous THEN NULL ELSE p.user_id END AS author_id, CASE WHEN p.is_anonymous THEN NULL ELSE pr.username END AS author_username, CASE WHEN p.is_anonymous THEN NULL ELSE pr.display_name END AS author_display_name, CASE WHEN p.is_anonymous THEN NULL ELSE pr.avatar_url END AS author_avatar_url, COALESCE(( SELECT COUNT(*) FROM public.resonances r WHERE r.post_id = p.id ), 0)::int AS resonance_count FROM public.posts p JOIN public.profiles pr ON pr.id = p.user_id WHERE p.deleted_at IS NULL AND p.review_status IN ('ok', 'approved') AND p.created_at > NOW() - INTERVAL '14 hours'; -- ── 5. Add get_streak RPC ──────────────────────────────────────────────────── CREATE OR REPLACE FUNCTION public.get_streak(p_user_id UUID) RETURNS TABLE(streak INT) LANGUAGE plpgsql STABLE AS $$ DECLARE v_streak INT := 0; v_check_date DATE := CURRENT_DATE; v_has_post BOOLEAN; BEGIN LOOP SELECT EXISTS( SELECT 1 FROM public.posts WHERE user_id = p_user_id AND deleted_at IS NULL AND (created_at AT TIME ZONE 'Europe/Berlin')::DATE = v_check_date ) INTO v_has_post; IF v_has_post THEN v_streak := v_streak + 1; v_check_date := v_check_date - 1; ELSE EXIT; END IF; END LOOP; -- Check if user posted today; if not, streak is 0 IF v_streak = 0 THEN RETURN NEXT; ELSE RETURN QUERY SELECT v_streak; END IF; END; $$; -- ── 6. Add get_resonance_count RPC ─────────────────────────────────────────── CREATE OR REPLACE FUNCTION public.get_resonance_count(p_user_id UUID) RETURNS TABLE(count INT) LANGUAGE plpgsql STABLE AS $$ BEGIN RETURN QUERY SELECT COUNT(*)::int AS count FROM public.resonances r JOIN public.posts p ON p.id = r.post_id WHERE p.user_id = p_user_id AND p.deleted_at IS NULL; END; $$; -- ── 7. Add public_profile view for other-user profile lookups ──────────────── CREATE OR REPLACE VIEW public.public_profile AS SELECT p.id, p.username, p.display_name, p.bio, p.avatar_url, p.is_pro, p.is_admin, p.created_at, (SELECT COUNT(*) FROM public.posts WHERE user_id = p.id AND deleted_at IS NULL)::int AS post_count, (SELECT COUNT(*) FROM public.resonances r JOIN public.posts p2 ON p2.id = r.post_id WHERE p2.user_id = p.id AND p2.deleted_at IS NULL)::int AS resonance_count, (SELECT COUNT(*) FROM public.follows WHERE following_id = p.id)::int AS follower_count, (SELECT COUNT(*) FROM public.follows WHERE follower_id = p.id)::int AS following_count FROM public.profiles p; -- ── 8. Add profile view RLS (public_profile is a view, inherits from profiles) ─ -- Allow updates to profiles row -- (already handled by existing policy, no change needed) -- ── 9. Enable Realtime for posts table ──────────────────────────────────────── ALTER PUBLICATION supabase_realtime ADD TABLE public.posts; -- ── 10. Fix RLS for posts: allow reading all non-deleted approved posts ─────── DROP POLICY IF EXISTS posts_select ON public.posts; CREATE POLICY "posts_select" ON public.posts FOR SELECT USING ( deleted_at IS NULL AND review_status IN ('ok', 'approved') );