diff --git a/drizzle/0003_circles.sql b/drizzle/0003_circles.sql index 048f13a..070ca75 100644 --- a/drizzle/0003_circles.sql +++ b/drizzle/0003_circles.sql @@ -9,7 +9,7 @@ CREATE TABLE circles ( 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), @@ -17,7 +17,7 @@ CREATE TABLE circle_members ( 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, @@ -27,7 +27,7 @@ CREATE TABLE circle_invites ( 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, @@ -37,7 +37,7 @@ CREATE TABLE circle_posts ( 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, @@ -45,14 +45,14 @@ CREATE TABLE circle_post_comments ( 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, @@ -60,28 +60,35 @@ CREATE TABLE post_reports ( reason text, created_at timestamptz NOT NULL DEFAULT now() ); - --- Indexes for common query patterns +--> 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); - --- Enable RLS (deny-by-default at DB layer). --- The app connects as tia_app which handles row visibility via --- explicit WHERE clauses in every query (requireFamily() pattern). +--> 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; - --- Grant app role full access (app enforces row visibility itself) +--> statement-breakpoint GRANT ALL ON circles, circle_members, circle_invites, circle_posts, circle_post_comments, circle_post_reactions, post_reports TO tia_app; diff --git a/src/db/migrate.ts b/src/db/migrate.ts index 258519d..2e167d3 100644 --- a/src/db/migrate.ts +++ b/src/db/migrate.ts @@ -16,9 +16,11 @@ import { migrate } from "drizzle-orm/postgres-js/migrator"; import postgres from "postgres"; async function main() { - const url = process.env.DATABASE_URL; + // Prefer DATABASE_URL_SUPERUSER for DDL (CREATE TABLE, RLS, etc). + // Falls back to DATABASE_URL so local dev with a single URL still works. + const url = process.env.DATABASE_URL_SUPERUSER ?? process.env.DATABASE_URL; if (!url) { - console.error("[migrate] DATABASE_URL is not set — aborting."); + console.error("[migrate] Neither DATABASE_URL_SUPERUSER nor DATABASE_URL is set — aborting."); process.exit(1); }