sojorn/go-backend/migrations/20260217_repost_and_layout.sql
Patrick Britton c3329a0893 feat: Implement repost/boost API, profile layout persistence, feed algorithm wiring, and legacy cleanup
Backend:
- Add repost_handler.go with full CRUD (create, boost, delete, report, trending, amplification analytics)
- Add profile_layout_handler.go for profile widget layout persistence (GET/PUT)
- Wire FeedAlgorithmService into main.go as 15-min background score refresh job
- Fix follow_handler.go (broken interface, dead query pattern, naming conflict)
- Add DB migration for reposts, repost_reports, profile_layouts, post_feed_scores tables
- Add engagement count columns to posts table for feed algorithm
- Remove stale Supabase comments from auth middleware
- Delete cmd/supabase-migrate/ directory (legacy migration tool)

Flutter:
- Fix all repost_service.dart API paths (were doubling /api/ prefix against base URL)
- Rename forceResetBrokenKeys() -> resetIdentityKeys() in E2EE services
- Remove dead _forceResetBrokenKeys method from secure_chat_screen.dart
- Implement _navigateToProfile(), _navigateToHashtag(), _navigateToUrl() in sojorn_rich_text.dart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 14:04:24 -06:00

76 lines
4.3 KiB
SQL

-- Migration: Add reposts, profile_layouts, and post_feed_scores tables
-- Also adds engagement count columns to posts for feed algorithm
-- ─── Engagement columns on posts ──────────────────────────────────────────────
ALTER TABLE public.posts
ADD COLUMN IF NOT EXISTS like_count INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS comment_count INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS share_count INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS repost_count INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS boost_count INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS amplify_count INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS view_count INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS video_url TEXT;
-- Backfill existing like/comment/view counts from post_metrics
UPDATE public.posts p
SET
like_count = COALESCE(m.like_count, 0),
comment_count = COALESCE(m.comment_count, 0),
view_count = COALESCE(m.view_count, 0)
FROM public.post_metrics m
WHERE p.id = m.post_id;
-- ─── Reposts ──────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS public.reposts (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
original_post_id UUID NOT NULL REFERENCES public.posts(id) ON DELETE CASCADE,
author_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE,
type TEXT NOT NULL CHECK (type IN ('standard', 'quote', 'boost', 'amplify')),
comment TEXT,
metadata JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- One repost per type per user per post
CREATE UNIQUE INDEX IF NOT EXISTS idx_reposts_unique
ON public.reposts (original_post_id, author_id, type);
CREATE INDEX IF NOT EXISTS idx_reposts_original_post_id ON public.reposts (original_post_id);
CREATE INDEX IF NOT EXISTS idx_reposts_author_id ON public.reposts (author_id);
CREATE INDEX IF NOT EXISTS idx_reposts_created_at ON public.reposts (created_at DESC);
-- ─── Repost reports ───────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS public.repost_reports (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
repost_id UUID NOT NULL REFERENCES public.reposts(id) ON DELETE CASCADE,
reporter_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE,
reason TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (repost_id, reporter_id)
);
-- ─── Profile widget layouts ───────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS public.profile_layouts (
user_id UUID PRIMARY KEY REFERENCES public.profiles(id) ON DELETE CASCADE,
widgets JSONB NOT NULL DEFAULT '[]',
theme VARCHAR(50) NOT NULL DEFAULT 'default',
accent_color VARCHAR(20),
banner_image_url TEXT,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ─── Post feed scores (feed algorithm) ───────────────────────────────────────
CREATE TABLE IF NOT EXISTS public.post_feed_scores (
post_id UUID PRIMARY KEY REFERENCES public.posts(id) ON DELETE CASCADE,
score DOUBLE PRECISION NOT NULL DEFAULT 0,
engagement_score DOUBLE PRECISION NOT NULL DEFAULT 0,
quality_score DOUBLE PRECISION NOT NULL DEFAULT 0,
recency_score DOUBLE PRECISION NOT NULL DEFAULT 0,
network_score DOUBLE PRECISION NOT NULL DEFAULT 0,
personalization DOUBLE PRECISION NOT NULL DEFAULT 0,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_post_feed_scores_score ON public.post_feed_scores (score DESC);