-- C0: Circle multi-tenant social tables -- Security model: RLS enabled (deny-by-default at DB layer). -- App-level enforcement via requireFamily() + WHERE family_id checks -- mirrors the existing pattern used for all other tables in this codebase. CREATE TABLE circles ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), name text NOT NULL, created_by uuid NOT NULL REFERENCES families(id), created_at timestamptz NOT NULL DEFAULT now() ); --> statement-breakpoint CREATE TABLE circle_members ( circle_id uuid NOT NULL REFERENCES circles(id) ON DELETE CASCADE, family_id uuid NOT NULL REFERENCES families(id), role text NOT NULL DEFAULT 'member', -- admin | member joined_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (circle_id, family_id) ); --> statement-breakpoint CREATE TABLE circle_invites ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), circle_id uuid NOT NULL REFERENCES circles(id) ON DELETE CASCADE, token text NOT NULL UNIQUE, -- crypto-random, unguessable created_by uuid NOT NULL REFERENCES families(id), expires_at timestamptz NOT NULL, consumed_at timestamptz, created_at timestamptz NOT NULL DEFAULT now() ); --> statement-breakpoint CREATE TABLE circle_posts ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), circle_id uuid NOT NULL REFERENCES circles(id) ON DELETE CASCADE, author_family_id uuid NOT NULL REFERENCES families(id), body text, image_key text, -- R2 key under circle-posts/{id}/ prefix source_kind text, -- NULL | 'milestone' | 'memory' created_at timestamptz NOT NULL DEFAULT now() ); --> statement-breakpoint CREATE TABLE circle_post_comments ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), post_id uuid NOT NULL REFERENCES circle_posts(id) ON DELETE CASCADE, author_family_id uuid NOT NULL REFERENCES families(id), body text NOT NULL, created_at timestamptz NOT NULL DEFAULT now() ); --> statement-breakpoint CREATE TABLE circle_post_reactions ( post_id uuid NOT NULL REFERENCES circle_posts(id) ON DELETE CASCADE, family_id uuid NOT NULL REFERENCES families(id), emoji text NOT NULL, PRIMARY KEY (post_id, family_id, emoji) ); --> statement-breakpoint CREATE TABLE post_reports ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), post_id uuid NOT NULL REFERENCES circle_posts(id) ON DELETE CASCADE, reported_by uuid NOT NULL REFERENCES families(id), reason text, created_at timestamptz NOT NULL DEFAULT now() ); --> statement-breakpoint CREATE INDEX circle_members_family_idx ON circle_members(family_id); --> statement-breakpoint CREATE INDEX circle_members_circle_idx ON circle_members(circle_id); --> statement-breakpoint CREATE INDEX circle_posts_circle_idx ON circle_posts(circle_id); --> statement-breakpoint CREATE INDEX circle_posts_author_idx ON circle_posts(author_family_id); --> statement-breakpoint CREATE INDEX circle_comments_post_idx ON circle_post_comments(post_id); --> statement-breakpoint CREATE INDEX circle_reactions_post_idx ON circle_post_reactions(post_id); --> statement-breakpoint CREATE INDEX circle_invites_token_idx ON circle_invites(token); --> statement-breakpoint ALTER TABLE circles ENABLE ROW LEVEL SECURITY; --> statement-breakpoint ALTER TABLE circle_members ENABLE ROW LEVEL SECURITY; --> statement-breakpoint ALTER TABLE circle_invites ENABLE ROW LEVEL SECURITY; --> statement-breakpoint ALTER TABLE circle_posts ENABLE ROW LEVEL SECURITY; --> statement-breakpoint ALTER TABLE circle_post_comments ENABLE ROW LEVEL SECURITY; --> statement-breakpoint ALTER TABLE circle_post_reactions ENABLE ROW LEVEL SECURITY; --> statement-breakpoint ALTER TABLE post_reports ENABLE ROW LEVEL SECURITY; --> statement-breakpoint GRANT ALL ON circles, circle_members, circle_invites, circle_posts, circle_post_comments, circle_post_reactions, post_reports TO tia_app;