WIP: lokalen Stand vor dem Aufräumen sichern
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
-- 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')
|
||||
);
|
||||
@@ -0,0 +1,112 @@
|
||||
-- nightly — Seed data: realistic German users and posts for testing
|
||||
-- Run manually or via supabase db reset --seed
|
||||
|
||||
-- ── Cleanup (idempotent) ────────────────────────────────────────────────────
|
||||
|
||||
DELETE FROM resonances;
|
||||
DELETE FROM whispers;
|
||||
DELETE FROM follows;
|
||||
DELETE FROM reports;
|
||||
DELETE FROM posts;
|
||||
DELETE FROM profiles WHERE id != auth.uid(); -- keep own account
|
||||
-- Note: we can't delete from auth.users easily, so we'll create new ones
|
||||
|
||||
-- ── Create test users via Supabase Auth ──────────────────────────────────────
|
||||
-- These must be created via auth.users first (or signup), then profiles get auto-created.
|
||||
-- For seeding we insert directly into profiles with UUIDs.
|
||||
|
||||
INSERT INTO profiles (id, username, display_name, bio, is_pro) VALUES
|
||||
('a0000000-0000-0000-0000-000000000001', 'nachtvogel_', 'Nachtvogel', '3 Uhr ist meine goldene Stunde', true),
|
||||
('a0000000-0000-0000-0000-000000000002', 'insomniac_', 'can''t sleep', NULL, false),
|
||||
('a0000000-0000-0000-0000-000000000003', 'felix.nacht', 'Felix', NULL, false),
|
||||
('a0000000-0000-0000-0000-000000000004', '4am_thoughts', 'Lena', 'Nachtgedanken auf Deutsch', false),
|
||||
('a0000000-0000-0000-0000-000000000005', 'mondkind', 'Mondkind', NULL, true),
|
||||
('a0000000-0000-0000-0000-000000000006', 'keinschlaf_', 'k.einschlaf', 'Aufgewacht und nicht mehr müde', false),
|
||||
('a0000000-0000-0000-0000-000000000007', 'sterne_sehn', 'Sternesehende', 'Liege auf dem Dach und schaue hoch', false),
|
||||
('a0000000-0000-0000-0000-000000000008', 'dunkelheit_', 'Dunkelheit', NULL, false),
|
||||
('a0000000-0000-0000-0000-000000000009', 'leise.stimme', 'Leise Stimme', 'Ich schreibe nachts am besten', false),
|
||||
('a0000000-0000-0000-0000-000000000010', 'wolkenzug_', 'Wolkenzug', 'Gedanken die wie Wolken vorbeiziehen', false)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- ── Posts ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
INSERT INTO posts (id, user_id, content, mood, is_anonymous, has_content_warning, content_warning_type, created_at) VALUES
|
||||
-- User 1: nachtvogel_
|
||||
('b0000000-0000-0000-0000-000000000001', 'a0000000-0000-0000-0000-000000000001', 'manchmal ist die stille nachts lauter als alle geräusche tagsüber', 'still', false, false, NULL, NOW() - INTERVAL '5 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000002', 'a0000000-0000-0000-0000-000000000001', 'regentropfen am fenster sind das einzige was mich gerade noch companie macht', 'still', false, false, NULL, NOW() - INTERVAL '30 minutes'),
|
||||
|
||||
-- User 2: insomniac_
|
||||
('b0000000-0000-0000-0000-000000000003', 'a0000000-0000-0000-0000-000000000002', 'das licht vom handy macht alles schlimmer aber ich leg es trotzdem nicht weg', 'unruhig', false, false, NULL, NOW() - INTERVAL '15 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000004', 'a0000000-0000-0000-0000-000000000002', '3 uhr und ich rechne vor allem leb ich noch wenn ich aufwache', 'unruhig', false, false, NULL, NOW() - INTERVAL '2 hours'),
|
||||
|
||||
-- User 3: felix.nacht
|
||||
('b0000000-0000-0000-0000-000000000005', 'a0000000-0000-0000-0000-000000000003', 'hab gerade realisiert dass ich seit 4 stunden auf tiktok bin und morgen um 7 aufstehen muss', 'geladen', false, false, NULL, NOW() - INTERVAL '1 minute'),
|
||||
('b0000000-0000-0000-0000-000000000006', 'a0000000-0000-0000-0000-000000000003', 'hab mein zimmer aufgeräumt statt zu schlafen. zumindest irgendetwas produktives heute nacht', 'geladen', false, true, 'other', NOW() - INTERVAL '45 minutes'),
|
||||
|
||||
-- User 4: 4am_thoughts
|
||||
('b0000000-0000-0000-0000-000000000007', 'a0000000-0000-0000-0000-000000000004', 'traum von einer stadt in der niemand schläft und alle auf den dächern sitzen und in den himmel schauen', 'zart', false, false, NULL, NOW() - INTERVAL '2 hours'),
|
||||
('b0000000-0000-0000-0000-000000000008', 'a0000000-0000-0000-0000-000000000004', 'die nacht hat eine andere sprache als der tag', 'still', false, false, NULL, NOW() - INTERVAL '4 hours'),
|
||||
|
||||
-- User 5: mondkind
|
||||
('b0000000-0000-0000-0000-000000000009', 'a0000000-0000-0000-0000-000000000005', 'wenn der mond hell genug ist brauch ich kein licht auf dem handy', 'zart', false, false, NULL, NOW() - INTERVAL '20 minutes'),
|
||||
|
||||
-- Anonymous posts
|
||||
('b0000000-0000-0000-0000-000000000010', 'a0000000-0000-0000-0000-000000000001', 'ich warte irgendwie immer noch auf eine nachricht von dir obwohl ich weiß dass sie nicht kommt', 'schwer', true, false, NULL, NOW() - INTERVAL '5 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000011', 'a0000000-0000-0000-0000-000000000002', 'ich hab meiner besten freundin gesagt dass ich sie vermisse und sie hat nur geantwortet mit einem smiley', 'zart', true, false, NULL, NOW() - INTERVAL '90 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000012', 'a0000000-0000-0000-0000-000000000003', 'ich kann nicht aufhören an ihn zu denken und das schlimmste ist ich weiß dass es falsch ist', 'dunkel', true, true, 'other', NOW() - INTERVAL '3 hours'),
|
||||
('b0000000-0000-0000-0000-000000000013', 'a0000000-0000-0000-0000-000000000004', 'warum denk ich um 3 uhr morgens noch an das was ich 2019 gesagt hab', 'schwer', true, false, NULL, NOW() - INTERVAL '3 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000014', 'a0000000-0000-0000-0000-000000000005', 'manchmal wünsch ich mir jemand würde einfach nur nachts bei mir sein ohne dass wir reden müssen', 'zart', true, false, NULL, NOW() - INTERVAL '1 hour'),
|
||||
|
||||
-- More diverse posts
|
||||
('b0000000-0000-0000-0000-000000000015', 'a0000000-0000-0000-0000-000000000006', 'kopfhörer auf. playlist die nur nachts funktioniert. welt draußen geht weiter aber hier drinnen ist sie gestoppt', 'still', false, false, NULL, NOW() - INTERVAL '10 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000016', 'a0000000-0000-0000-0000-000000000007', 'lieber allein wach als in gesellschaft die mich nicht versteht', 'dunkel', false, false, NULL, NOW() - INTERVAL '40 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000017', 'a0000000-0000-0000-0000-000000000008', 'ich hab so viel energie um 3 uhr aber null motivation um 15 uhr', 'geladen', true, false, NULL, NOW() - INTERVAL '55 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000018', 'a0000000-0000-0000-0000-000000000009', 'die nacht ist der einzige ort wo ich ehrlich sein kann', 'dunkel', false, false, NULL, NOW() - INTERVAL '1 hour 20 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000019', 'a0000000-0000-0000-0000-000000000010', 'wolken ziehen vorbei und ich frage mich ob sie auch nachts nicht schlafen können', 'still', false, false, NULL, NOW() - INTERVAL '2 hours 30 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000020', 'a0000000-0000-0000-0000-000000000001', 'jeder irgendwo auf der welt ist gerade auch wach und das tröstet mich mehr als es sollte', 'zart', false, false, NULL, NOW() - INTERVAL '8 minutes'),
|
||||
|
||||
-- Content warning posts
|
||||
('b0000000-0000-0000-0000-000000000021', 'a0000000-0000-0000-0000-000000000004', 'heute nacht war das erste mal seit langem dass ich dachte vielleicht wird es doch noch besser', 'zart', false, true, 'other', NOW() - INTERVAL '25 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000022', 'a0000000-0000-0000-0000-000000000006', 'das problem ist nicht dass ich nicht schlafen kann. das problem ist dass ich nicht aufhören kann zu denken', 'unruhig', false, false, NULL, NOW() - INTERVAL '50 minutes')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- ── Resonances ────────────────────────────────────────────────────────────────
|
||||
|
||||
INSERT INTO resonances (post_id, user_id, created_at) VALUES
|
||||
('b0000000-0000-0000-0000-000000000001', 'a0000000-0000-0000-0000-000000000002', NOW() - INTERVAL '4 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000001', 'a0000000-0000-0000-0000-000000000003', NOW() - INTERVAL '3 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000001', 'a0000000-0000-0000-0000-000000000004', NOW() - INTERVAL '2 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000003', 'a0000000-0000-0000-0000-000000000001', NOW() - INTERVAL '10 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000005', 'a0000000-0000-0000-0000-000000000005', NOW() - INTERVAL '30 seconds'),
|
||||
('b0000000-0000-0000-0000-000000000010', 'a0000000-0000-0000-0000-000000000007', NOW() - INTERVAL '4 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000010', 'a0000000-0000-0000-0000-000000000008', NOW() - INTERVAL '3 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000011', 'a0000000-0000-0000-0000-000000000009', NOW() - INTERVAL '45 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000011', 'a0000000-0000-0000-0000-000000000010', NOW() - INTERVAL '40 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000012', 'a0000000-0000-0000-0000-000000000001', NOW() - INTERVAL '2 hours'),
|
||||
('b0000000-0000-0000-0000-000000000013', 'a0000000-0000-0000-0000-000000000005', NOW() - INTERVAL '2 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000013', 'a0000000-0000-0000-0000-000000000006', NOW() - INTERVAL '1 minute'),
|
||||
('b0000000-0000-0000-0000-000000000009', 'a0000000-0000-0000-0000-000000000004', NOW() - INTERVAL '15 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000020', 'a0000000-0000-0000-0000-000000000002', NOW() - INTERVAL '5 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000020', 'a0000000-0000-0000-0000-000000000009', NOW() - INTERVAL '3 minutes'),
|
||||
('b0000000-0000-0000-0000-000000000007', 'a0000000-0000-0000-0000-000000000001', NOW() - INTERVAL '1 hour')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- ── Follows ──────────────────────────────────────────────────────────────────
|
||||
|
||||
INSERT INTO follows (follower_id, following_id, created_at) VALUES
|
||||
('a0000000-0000-0000-0000-000000000001', 'a0000000-0000-0000-0000-000000000002', NOW() - INTERVAL '3 days'),
|
||||
('a0000000-0000-0000-0000-000000000001', 'a0000000-0000-0000-0000-000000000005', NOW() - INTERVAL '1 day'),
|
||||
('a0000000-0000-0000-0000-000000000002', 'a0000000-0000-0000-0000-000000000003', NOW() - INTERVAL '5 days'),
|
||||
('a0000000-0000-0000-0000-000000000004', 'a0000000-0000-0000-0000-000000000001', NOW() - INTERVAL '2 days'),
|
||||
('a0000000-0000-0000-0000-000000000005', 'a0000000-0000-0000-0000-000000000006', NOW() - INTERVAL '12 hours'),
|
||||
('a0000000-0000-0000-0000-000000000006', 'a0000000-0000-0000-0000-000000000007', NOW() - INTERVAL '6 hours'),
|
||||
('a0000000-0000-0000-0000-000000000009', 'a0000000-0000-0000-0000-000000000001', NOW() - INTERVAL '4 days'),
|
||||
('a0000000-0000-0000-0000-000000000010', 'a0000000-0000-0000-0000-000000000005', NOW() - INTERVAL '1 day')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- ── Whispers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
INSERT INTO whispers (id, from_user_id, to_user_id, content, read_at, created_at) VALUES
|
||||
('c0000000-0000-0000-0000-000000000001', 'a0000000-0000-0000-0000-000000000002', 'a0000000-0000-0000-0000-000000000001', 'dein post hat mir gerade alles gesagt was ich fühle', NULL, NOW() - INTERVAL '20 minutes'),
|
||||
('c0000000-0000-0000-0000-000000000002', 'a0000000-0000-0000-0000-000000000005', 'a0000000-0000-0000-0000-000000000001', 'wollte dir nur sagen dass du nicht allein bist diese nacht', NOW() - INTERVAL '10 minutes', NOW() - INTERVAL '2 hours')
|
||||
ON CONFLICT DO NOTHING;
|
||||
Reference in New Issue
Block a user