From 708e52ef49ee9fe062205f5ae9f6ebdbd97e6487 Mon Sep 17 00:00:00 2001 From: Urjit Chakraborty <135136842+urjitc@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:55:39 -0400 Subject: [PATCH 1/3] chore(db): squash Drizzle migrations into single baseline Replace the prior migration chain with 0000_baseline.sql and a single journal entry so new environments apply one migration from schema.ts. Made-with: Cursor --- drizzle/0000_baseline.sql | 264 +++ drizzle/0000_sad_wallflower.sql | 291 --- drizzle/0001_add_realtime_collaboration.sql | 156 -- drizzle/0002_add_workspace_share_links.sql | 27 - drizzle/0002_deep_shadowcat.sql | 35 - drizzle/0003_elite_harrier.sql | 17 - .../0004_add_chat_threads_head_message_id.sql | 2 - ...dd_chat_messages_thread_message_unique.sql | 3 - drizzle/meta/0000_snapshot.json | 880 +++++++- drizzle/meta/0001_snapshot.json | 1547 ------------- drizzle/meta/0002_snapshot.json | 1823 ---------------- drizzle/meta/0003_snapshot.json | 1918 ----------------- drizzle/meta/_journal.json | 39 +- 13 files changed, 1128 insertions(+), 5874 deletions(-) create mode 100644 drizzle/0000_baseline.sql delete mode 100644 drizzle/0000_sad_wallflower.sql delete mode 100644 drizzle/0001_add_realtime_collaboration.sql delete mode 100644 drizzle/0002_add_workspace_share_links.sql delete mode 100644 drizzle/0002_deep_shadowcat.sql delete mode 100644 drizzle/0003_elite_harrier.sql delete mode 100644 drizzle/0004_add_chat_threads_head_message_id.sql delete mode 100644 drizzle/0005_add_chat_messages_thread_message_unique.sql delete mode 100644 drizzle/meta/0001_snapshot.json delete mode 100644 drizzle/meta/0002_snapshot.json delete mode 100644 drizzle/meta/0003_snapshot.json diff --git a/drizzle/0000_baseline.sql b/drizzle/0000_baseline.sql new file mode 100644 index 00000000..607a20d1 --- /dev/null +++ b/drizzle/0000_baseline.sql @@ -0,0 +1,264 @@ +CREATE TABLE "account" ( + "id" text PRIMARY KEY NOT NULL, + "account_id" text NOT NULL, + "provider_id" text NOT NULL, + "user_id" text NOT NULL, + "access_token" text, + "refresh_token" text, + "id_token" text, + "access_token_expires_at" timestamp, + "refresh_token_expires_at" timestamp, + "scope" text, + "password" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp NOT NULL +); +--> statement-breakpoint +CREATE TABLE "chat_messages" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "thread_id" uuid NOT NULL, + "message_id" text NOT NULL, + "parent_id" text, + "format" text NOT NULL, + "content" jsonb NOT NULL, + "created_at" timestamp with time zone DEFAULT now(), + CONSTRAINT "chat_messages_thread_message_key" UNIQUE("thread_id","message_id") +); +--> statement-breakpoint +CREATE TABLE "chat_threads" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "workspace_id" uuid NOT NULL, + "user_id" text NOT NULL, + "title" text, + "is_archived" boolean DEFAULT false, + "external_id" text, + "created_at" timestamp with time zone DEFAULT now(), + "updated_at" timestamp with time zone DEFAULT now(), + "last_message_at" timestamp with time zone DEFAULT now(), + "head_message_id" text +); +--> statement-breakpoint +ALTER TABLE "chat_threads" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +CREATE TABLE "session" ( + "id" text PRIMARY KEY NOT NULL, + "expires_at" timestamp NOT NULL, + "token" text NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp NOT NULL, + "ip_address" text, + "user_agent" text, + "user_id" text NOT NULL, + CONSTRAINT "session_token_unique" UNIQUE("token") +); +--> statement-breakpoint +CREATE TABLE "user" ( + "id" text PRIMARY KEY NOT NULL, + "name" text, + "email" text NOT NULL, + "email_verified" boolean DEFAULT false NOT NULL, + "image" text, + "is_anonymous" boolean DEFAULT false, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "user_email_unique" UNIQUE("email") +); +--> statement-breakpoint +CREATE TABLE "user_profiles" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "user_id" text NOT NULL, + "onboarding_completed" boolean DEFAULT false, + "onboarding_completed_at" timestamp with time zone, + "created_at" timestamp with time zone DEFAULT now(), + "updated_at" timestamp with time zone DEFAULT now(), + CONSTRAINT "user_profiles_user_id_key" UNIQUE("user_id") +); +--> statement-breakpoint +ALTER TABLE "user_profiles" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +CREATE TABLE "verification" ( + "id" text PRIMARY KEY NOT NULL, + "identifier" text NOT NULL, + "value" text NOT NULL, + "expires_at" timestamp NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE "workspace_collaborators" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "workspace_id" uuid NOT NULL, + "user_id" text NOT NULL, + "permission_level" text DEFAULT 'editor' NOT NULL, + "invite_token" text, + "last_opened_at" timestamp with time zone, + "created_at" timestamp with time zone DEFAULT now(), + CONSTRAINT "workspace_collaborators_invite_token_unique" UNIQUE("invite_token"), + CONSTRAINT "workspace_collaborators_workspace_user_unique" UNIQUE("workspace_id","user_id") +); +--> statement-breakpoint +ALTER TABLE "workspace_collaborators" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +CREATE TABLE "workspace_events" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "workspace_id" uuid NOT NULL, + "event_id" text NOT NULL, + "event_type" text NOT NULL, + "payload" jsonb NOT NULL, + "timestamp" bigint NOT NULL, + "user_id" text NOT NULL, + "version" integer NOT NULL, + "created_at" timestamp with time zone DEFAULT now(), + "user_name" text, + CONSTRAINT "workspace_events_event_id_key" UNIQUE("event_id") +); +--> statement-breakpoint +ALTER TABLE "workspace_events" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +CREATE TABLE "workspace_invites" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "workspace_id" uuid NOT NULL, + "email" text NOT NULL, + "token" text NOT NULL, + "inviter_id" text NOT NULL, + "permission_level" text DEFAULT 'editor' NOT NULL, + "expires_at" timestamp with time zone NOT NULL, + "created_at" timestamp with time zone DEFAULT now(), + CONSTRAINT "workspace_invites_token_key" UNIQUE("token") +); +--> statement-breakpoint +ALTER TABLE "workspace_invites" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +CREATE TABLE "workspace_item_reads" ( + "thread_id" uuid NOT NULL, + "item_id" text NOT NULL, + "last_modified" bigint NOT NULL, + "read_at" timestamp with time zone DEFAULT now() NOT NULL, + CONSTRAINT "workspace_item_reads_thread_item_key" UNIQUE("thread_id","item_id") +); +--> statement-breakpoint +ALTER TABLE "workspace_item_reads" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +CREATE TABLE "workspace_share_links" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "workspace_id" uuid NOT NULL, + "token" text NOT NULL, + "permission_level" text DEFAULT 'editor' NOT NULL, + "created_at" timestamp with time zone DEFAULT now(), + "expires_at" timestamp with time zone NOT NULL, + CONSTRAINT "workspace_share_links_token_key" UNIQUE("token"), + CONSTRAINT "workspace_share_links_workspace_key" UNIQUE("workspace_id") +); +--> statement-breakpoint +ALTER TABLE "workspace_share_links" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +CREATE TABLE "workspace_snapshots" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "workspace_id" uuid NOT NULL, + "snapshot_version" integer NOT NULL, + "state" jsonb NOT NULL, + "event_count" integer NOT NULL, + "created_at" timestamp with time zone DEFAULT now(), + CONSTRAINT "workspace_snapshots_workspace_id_snapshot_version_key" UNIQUE("workspace_id","snapshot_version") +); +--> statement-breakpoint +ALTER TABLE "workspace_snapshots" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +CREATE TABLE "workspaces" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "user_id" text NOT NULL, + "name" text NOT NULL, + "description" text DEFAULT '', + "template" text DEFAULT 'blank', + "is_public" boolean DEFAULT false, + "created_at" timestamp with time zone DEFAULT now(), + "updated_at" timestamp with time zone DEFAULT now(), + "slug" text, + "icon" text, + "sort_order" integer, + "color" text, + "last_opened_at" timestamp with time zone +); +--> statement-breakpoint +ALTER TABLE "workspaces" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "chat_messages" ADD CONSTRAINT "chat_messages_thread_id_chat_threads_id_fk" FOREIGN KEY ("thread_id") REFERENCES "public"."chat_threads"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "chat_threads" ADD CONSTRAINT "chat_threads_workspace_id_workspaces_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "chat_threads" ADD CONSTRAINT "chat_threads_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "workspace_collaborators" ADD CONSTRAINT "workspace_collaborators_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "workspace_events" ADD CONSTRAINT "workspace_events_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "workspace_invites" ADD CONSTRAINT "workspace_invites_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "workspace_item_reads" ADD CONSTRAINT "workspace_item_reads_thread_id_chat_threads_id_fk" FOREIGN KEY ("thread_id") REFERENCES "public"."chat_threads"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "workspace_share_links" ADD CONSTRAINT "workspace_share_links_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "workspace_snapshots" ADD CONSTRAINT "workspace_snapshots_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "idx_account_user_id" ON "account" USING btree ("user_id" text_ops);--> statement-breakpoint +CREATE INDEX "idx_chat_messages_thread" ON "chat_messages" USING btree ("thread_id" uuid_ops);--> statement-breakpoint +CREATE INDEX "idx_chat_messages_thread_created" ON "chat_messages" USING btree ("thread_id" uuid_ops,"created_at" timestamptz_ops);--> statement-breakpoint +CREATE INDEX "idx_chat_threads_workspace" ON "chat_threads" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint +CREATE INDEX "idx_chat_threads_user" ON "chat_threads" USING btree ("user_id" text_ops);--> statement-breakpoint +CREATE INDEX "idx_chat_threads_last_message" ON "chat_threads" USING btree ("workspace_id" uuid_ops,"last_message_at" timestamptz_ops);--> statement-breakpoint +CREATE INDEX "idx_session_user_id" ON "session" USING btree ("user_id" text_ops);--> statement-breakpoint +CREATE INDEX "idx_session_token" ON "session" USING btree ("token" text_ops);--> statement-breakpoint +CREATE INDEX "idx_user_email" ON "user" USING btree ("email" text_ops);--> statement-breakpoint +CREATE INDEX "idx_user_profiles_user_id" ON "user_profiles" USING btree ("user_id" text_ops);--> statement-breakpoint +CREATE INDEX "idx_verification_identifier" ON "verification" USING btree ("identifier" text_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_collaborators_lookup" ON "workspace_collaborators" USING btree ("user_id" text_ops,"workspace_id" uuid_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_collaborators_workspace" ON "workspace_collaborators" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_collaborators_last_opened_at" ON "workspace_collaborators" USING btree ("user_id" text_ops,"last_opened_at" timestamptz_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_events_event_id" ON "workspace_events" USING btree ("event_id" text_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_events_timestamp" ON "workspace_events" USING btree ("workspace_id" uuid_ops,"timestamp" int8_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_events_user_name" ON "workspace_events" USING btree ("user_name" text_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_events_workspace" ON "workspace_events" USING btree ("workspace_id" uuid_ops,"version" int4_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_invites_token" ON "workspace_invites" USING btree ("token" text_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_invites_email" ON "workspace_invites" USING btree ("email" text_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_invites_workspace" ON "workspace_invites" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_item_reads_thread_item" ON "workspace_item_reads" USING btree ("thread_id" uuid_ops,"item_id" text_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_share_links_token" ON "workspace_share_links" USING btree ("token" text_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_share_links_workspace" ON "workspace_share_links" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_snapshots_version" ON "workspace_snapshots" USING btree ("workspace_id" uuid_ops,"snapshot_version" int4_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_snapshots_workspace" ON "workspace_snapshots" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint +CREATE INDEX "idx_workspaces_created_at" ON "workspaces" USING btree ("created_at" timestamptz_ops);--> statement-breakpoint +CREATE INDEX "idx_workspaces_slug" ON "workspaces" USING btree ("slug" text_ops);--> statement-breakpoint +CREATE INDEX "idx_workspaces_user_id" ON "workspaces" USING btree ("user_id" text_ops);--> statement-breakpoint +CREATE UNIQUE INDEX "idx_workspaces_user_slug" ON "workspaces" USING btree ("user_id" text_ops,"slug" text_ops);--> statement-breakpoint +CREATE INDEX "idx_workspaces_user_sort_order" ON "workspaces" USING btree ("user_id" text_ops,"sort_order" int4_ops);--> statement-breakpoint +CREATE INDEX "idx_workspaces_last_opened_at" ON "workspaces" USING btree ("last_opened_at" timestamptz_ops);--> statement-breakpoint +CREATE POLICY "chat_threads_user_scoped" ON "chat_threads" AS PERMISSIVE FOR ALL TO "authenticated" USING (((chat_threads.user_id = (auth.jwt() ->> 'sub'::text)) + AND ((EXISTS ( SELECT 1 FROM workspaces w + WHERE ((w.id = chat_threads.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) + OR (EXISTS ( SELECT 1 FROM workspace_collaborators c + WHERE ((c.workspace_id = chat_threads.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text))))))));--> statement-breakpoint +CREATE POLICY "Users can insert their own profile" ON "user_profiles" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK ((( SELECT (auth.jwt() ->> 'sub'::text)) = user_id));--> statement-breakpoint +CREATE POLICY "Users can update their own profile" ON "user_profiles" AS PERMISSIVE FOR UPDATE TO "authenticated";--> statement-breakpoint +CREATE POLICY "Users can view their own profile" ON "user_profiles" AS PERMISSIVE FOR SELECT TO "authenticated";--> statement-breakpoint +CREATE POLICY "Owners can manage collaborators" ON "workspace_collaborators" AS PERMISSIVE FOR ALL TO "authenticated" USING ((EXISTS ( SELECT 1 + FROM workspaces w + WHERE ((w.id = workspace_collaborators.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))));--> statement-breakpoint +CREATE POLICY "Collaborators can view their access" ON "workspace_collaborators" AS PERMISSIVE FOR SELECT TO "authenticated" USING ((user_id = (auth.jwt() ->> 'sub'::text)));--> statement-breakpoint +CREATE POLICY "Users can insert workspace events they have write access to" ON "workspace_events" AS PERMISSIVE FOR INSERT TO public WITH CHECK ((EXISTS ( SELECT 1 + FROM workspaces + WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1 + FROM workspace_collaborators c + WHERE ((c.workspace_id = workspace_events.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text)))));--> statement-breakpoint +CREATE POLICY "Users can read workspace events they have access to" ON "workspace_events" AS PERMISSIVE FOR SELECT TO public USING ((EXISTS ( SELECT 1 + FROM workspaces + WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1 + FROM workspace_collaborators c + WHERE ((c.workspace_id = workspace_events.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text))))));--> statement-breakpoint +CREATE POLICY "Public can view invite by token" ON "workspace_invites" AS PERMISSIVE FOR SELECT TO public USING (true);--> statement-breakpoint +CREATE POLICY "Users can insert invites for workspaces they own/edit" ON "workspace_invites" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 + FROM workspaces w + WHERE ((w.id = workspace_invites.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1 + FROM workspace_collaborators c + WHERE ((c.workspace_id = workspace_invites.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text)))));--> statement-breakpoint +CREATE POLICY "workspace_item_reads_user_scoped" ON "workspace_item_reads" AS PERMISSIVE FOR ALL TO "authenticated" USING ((EXISTS ( SELECT 1 FROM chat_threads ct + JOIN workspaces w ON w.id = ct.workspace_id + WHERE ((ct.id = workspace_item_reads.thread_id) AND (ct.user_id = (auth.jwt() ->> 'sub'::text)) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) + OR (EXISTS ( SELECT 1 FROM chat_threads ct + JOIN workspace_collaborators c ON c.workspace_id = ct.workspace_id + WHERE ((ct.id = workspace_item_reads.thread_id) AND (ct.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.user_id = (auth.jwt() ->> 'sub'::text))))));--> statement-breakpoint +CREATE POLICY "Public can view share link by token" ON "workspace_share_links" AS PERMISSIVE FOR SELECT TO public USING (true);--> statement-breakpoint +CREATE POLICY "Owners and editors can manage share links" ON "workspace_share_links" AS PERMISSIVE FOR ALL TO "authenticated" USING ((EXISTS ( SELECT 1 + FROM workspaces w + WHERE ((w.id = workspace_share_links.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1 + FROM workspace_collaborators c + WHERE ((c.workspace_id = workspace_share_links.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text)))));--> statement-breakpoint +CREATE POLICY "Service role can insert workspace snapshots" ON "workspace_snapshots" AS PERMISSIVE FOR INSERT TO public WITH CHECK (true);--> statement-breakpoint +CREATE POLICY "Users can read workspace snapshots they have access to" ON "workspace_snapshots" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint +CREATE POLICY "Users can delete their own workspaces" ON "workspaces" AS PERMISSIVE FOR DELETE TO "authenticated" USING ((( SELECT (auth.jwt() ->> 'sub'::text)) = user_id));--> statement-breakpoint +CREATE POLICY "Users can insert their own workspaces" ON "workspaces" AS PERMISSIVE FOR INSERT TO "authenticated";--> statement-breakpoint +CREATE POLICY "Users can update their own workspaces" ON "workspaces" AS PERMISSIVE FOR UPDATE TO "authenticated";--> statement-breakpoint +CREATE POLICY "Users can view their own workspaces" ON "workspaces" AS PERMISSIVE FOR SELECT TO "authenticated"; \ No newline at end of file diff --git a/drizzle/0000_sad_wallflower.sql b/drizzle/0000_sad_wallflower.sql deleted file mode 100644 index fc0d0f5b..00000000 --- a/drizzle/0000_sad_wallflower.sql +++ /dev/null @@ -1,291 +0,0 @@ -CREATE TABLE "account" ( - "id" text PRIMARY KEY NOT NULL, - "account_id" text NOT NULL, - "provider_id" text NOT NULL, - "user_id" text NOT NULL, - "access_token" text, - "refresh_token" text, - "id_token" text, - "access_token_expires_at" timestamp, - "refresh_token_expires_at" timestamp, - "scope" text, - "password" text, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp NOT NULL -); ---> statement-breakpoint -CREATE TABLE "session" ( - "id" text PRIMARY KEY NOT NULL, - "expires_at" timestamp NOT NULL, - "token" text NOT NULL, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp NOT NULL, - "ip_address" text, - "user_agent" text, - "user_id" text NOT NULL, - CONSTRAINT "session_token_unique" UNIQUE("token") -); ---> statement-breakpoint -CREATE TABLE "user" ( - "id" text PRIMARY KEY NOT NULL, - "name" text, - "email" text NOT NULL, - "email_verified" boolean DEFAULT false NOT NULL, - "image" text, - "is_anonymous" boolean DEFAULT false, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL, - CONSTRAINT "user_email_unique" UNIQUE("email") -); ---> statement-breakpoint -CREATE TABLE "user_profiles" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "user_id" text NOT NULL, - "onboarding_completed" boolean DEFAULT false, - "onboarding_completed_at" timestamp with time zone, - "created_at" timestamp with time zone DEFAULT now(), - "updated_at" timestamp with time zone DEFAULT now(), - CONSTRAINT "user_profiles_user_id_key" UNIQUE("user_id") -); ---> statement-breakpoint -ALTER TABLE "user_profiles" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint -CREATE TABLE "verification" ( - "id" text PRIMARY KEY NOT NULL, - "identifier" text NOT NULL, - "value" text NOT NULL, - "expires_at" timestamp NOT NULL, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL -); ---> statement-breakpoint -CREATE TABLE "workspace_events" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "workspace_id" uuid NOT NULL, - "event_id" text NOT NULL, - "event_type" text NOT NULL, - "payload" jsonb NOT NULL, - "timestamp" bigint NOT NULL, - "user_id" text NOT NULL, - "version" integer NOT NULL, - "created_at" timestamp with time zone DEFAULT now(), - "user_name" text, - CONSTRAINT "workspace_events_event_id_key" UNIQUE("event_id") -); ---> statement-breakpoint -ALTER TABLE "workspace_events" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint -CREATE TABLE "workspace_snapshots" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "workspace_id" uuid NOT NULL, - "snapshot_version" integer NOT NULL, - "state" jsonb NOT NULL, - "event_count" integer NOT NULL, - "created_at" timestamp with time zone DEFAULT now(), - CONSTRAINT "workspace_snapshots_workspace_id_snapshot_version_key" UNIQUE("workspace_id","snapshot_version") -); ---> statement-breakpoint -ALTER TABLE "workspace_snapshots" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint -CREATE TABLE "workspaces" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "user_id" text NOT NULL, - "name" text NOT NULL, - "description" text DEFAULT '', - "template" text DEFAULT 'blank', - "is_public" boolean DEFAULT false, - "created_at" timestamp with time zone DEFAULT now(), - "updated_at" timestamp with time zone DEFAULT now(), - "slug" text, - "icon" text, - "sort_order" integer, - "color" text, - "last_opened_at" timestamp with time zone -); ---> statement-breakpoint -ALTER TABLE "workspaces" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint -ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "workspace_events" ADD CONSTRAINT "workspace_events_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "workspace_snapshots" ADD CONSTRAINT "workspace_snapshots_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -CREATE INDEX "idx_account_user_id" ON "account" USING btree ("user_id" text_ops);--> statement-breakpoint -CREATE INDEX "idx_session_user_id" ON "session" USING btree ("user_id" text_ops);--> statement-breakpoint -CREATE INDEX "idx_session_token" ON "session" USING btree ("token" text_ops);--> statement-breakpoint -CREATE INDEX "idx_user_email" ON "user" USING btree ("email" text_ops);--> statement-breakpoint -CREATE INDEX "idx_user_profiles_user_id" ON "user_profiles" USING btree ("user_id" text_ops);--> statement-breakpoint -CREATE INDEX "idx_verification_identifier" ON "verification" USING btree ("identifier" text_ops);--> statement-breakpoint -CREATE INDEX "idx_workspace_events_event_id" ON "workspace_events" USING btree ("event_id" text_ops);--> statement-breakpoint -CREATE INDEX "idx_workspace_events_timestamp" ON "workspace_events" USING btree ("workspace_id" uuid_ops,"timestamp" int8_ops);--> statement-breakpoint -CREATE INDEX "idx_workspace_events_user_name" ON "workspace_events" USING btree ("user_name" text_ops);--> statement-breakpoint -CREATE INDEX "idx_workspace_events_workspace" ON "workspace_events" USING btree ("workspace_id" uuid_ops,"version" int4_ops);--> statement-breakpoint -CREATE INDEX "idx_workspace_snapshots_version" ON "workspace_snapshots" USING btree ("workspace_id" uuid_ops,"snapshot_version" DESC NULLS FIRST);--> statement-breakpoint -CREATE INDEX "idx_workspace_snapshots_workspace" ON "workspace_snapshots" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint -CREATE INDEX "idx_workspaces_created_at" ON "workspaces" USING btree ("created_at" DESC NULLS FIRST);--> statement-breakpoint -CREATE INDEX "idx_workspaces_slug" ON "workspaces" USING btree ("slug" text_ops);--> statement-breakpoint -CREATE INDEX "idx_workspaces_user_id" ON "workspaces" USING btree ("user_id" text_ops);--> statement-breakpoint -CREATE UNIQUE INDEX "idx_workspaces_user_slug" ON "workspaces" USING btree ("user_id" text_ops,"slug" text_ops);--> statement-breakpoint -CREATE INDEX "idx_workspaces_user_sort_order" ON "workspaces" USING btree ("user_id" text_ops,"sort_order" int4_ops);--> statement-breakpoint -CREATE INDEX "idx_workspaces_last_opened_at" ON "workspaces" USING btree ("last_opened_at" DESC NULLS FIRST);--> statement-breakpoint -CREATE POLICY "Users can insert their own profile" ON "user_profiles" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK ((( SELECT (auth.jwt() ->> 'sub'::text)) = user_id));--> statement-breakpoint -CREATE POLICY "Users can update their own profile" ON "user_profiles" AS PERMISSIVE FOR UPDATE TO "authenticated";--> statement-breakpoint -CREATE POLICY "Users can view their own profile" ON "user_profiles" AS PERMISSIVE FOR SELECT TO "authenticated";--> statement-breakpoint -CREATE POLICY "Users can insert workspace events they have write access to" ON "workspace_events" AS PERMISSIVE FOR INSERT TO public WITH CHECK ((EXISTS ( SELECT 1 - FROM workspaces - WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text))))));--> statement-breakpoint -CREATE POLICY "Users can read workspace events they have access to" ON "workspace_events" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint -CREATE POLICY "Service role can insert workspace snapshots" ON "workspace_snapshots" AS PERMISSIVE FOR INSERT TO public WITH CHECK (true);--> statement-breakpoint -CREATE POLICY "Users can read workspace snapshots they have access to" ON "workspace_snapshots" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint -CREATE POLICY "Users can delete their own workspaces" ON "workspaces" AS PERMISSIVE FOR DELETE TO "authenticated" USING ((( SELECT (auth.jwt() ->> 'sub'::text)) = user_id));--> statement-breakpoint -CREATE POLICY "Users can insert their own workspaces" ON "workspaces" AS PERMISSIVE FOR INSERT TO "authenticated";--> statement-breakpoint -CREATE POLICY "Users can update their own workspaces" ON "workspaces" AS PERMISSIVE FOR UPDATE TO "authenticated";--> statement-breakpoint -CREATE POLICY "Users can view their own workspaces" ON "workspaces" AS PERMISSIVE FOR SELECT TO "authenticated";--> statement-breakpoint - --- ============================================================================= --- Database Functions --- ============================================================================= - -CREATE OR REPLACE FUNCTION get_workspace_version(p_workspace_id uuid) -RETURNS integer -LANGUAGE sql -SECURITY INVOKER -AS $$ - SELECT COALESCE(MAX(version), 0) - FROM workspace_events - WHERE workspace_id = p_workspace_id; -$$;--> statement-breakpoint - -CREATE OR REPLACE FUNCTION append_workspace_event( - p_workspace_id uuid, - p_event_id text, - p_event_type text, - p_payload jsonb, - p_timestamp bigint, - p_user_id text, - p_expected_version integer, - p_user_name text DEFAULT NULL -) -RETURNS TABLE(version integer, conflict boolean) -LANGUAGE plpgsql -SECURITY INVOKER -AS $$ -DECLARE - v_current_version INTEGER; - v_new_version INTEGER; -BEGIN - PERFORM 1 FROM workspaces WHERE id = p_workspace_id FOR UPDATE; - SELECT get_workspace_version(p_workspace_id) INTO v_current_version; - IF v_current_version != p_expected_version THEN - RETURN QUERY SELECT v_current_version, TRUE; - RETURN; - END IF; - v_new_version := v_current_version + 1; - INSERT INTO workspace_events ( - workspace_id, event_id, event_type, payload, timestamp, user_id, user_name, version - ) VALUES ( - p_workspace_id, p_event_id, p_event_type, p_payload, p_timestamp, p_user_id, p_user_name, v_new_version - ); - RETURN QUERY SELECT v_new_version, FALSE; -END; -$$;--> statement-breakpoint - -CREATE OR REPLACE FUNCTION create_workspace_snapshot( - p_workspace_id uuid, - p_state jsonb, - p_snapshot_version integer, - p_event_count integer -) -RETURNS uuid -LANGUAGE plpgsql -SECURITY INVOKER -AS $$ -DECLARE - v_snapshot_id UUID; -BEGIN - INSERT INTO workspace_snapshots (workspace_id, snapshot_version, state, event_count) - VALUES (p_workspace_id, p_snapshot_version, p_state, p_event_count) - ON CONFLICT (workspace_id, snapshot_version) - DO UPDATE SET state = EXCLUDED.state, event_count = EXCLUDED.event_count, created_at = NOW() - RETURNING id INTO v_snapshot_id; - - DELETE FROM workspace_snapshots - WHERE workspace_id = p_workspace_id - AND snapshot_version < ( - SELECT snapshot_version FROM workspace_snapshots - WHERE workspace_id = p_workspace_id - ORDER BY snapshot_version DESC OFFSET 3 LIMIT 1 - ); - RETURN v_snapshot_id; -END; -$$;--> statement-breakpoint - -CREATE OR REPLACE FUNCTION get_latest_snapshot(p_workspace_id uuid) -RETURNS TABLE(snapshot_version integer, state jsonb, event_count integer) -LANGUAGE sql -SECURITY INVOKER -AS $$ - SELECT snapshot_version, state, event_count - FROM workspace_snapshots - WHERE workspace_id = p_workspace_id - ORDER BY snapshot_version DESC - LIMIT 1; -$$;--> statement-breakpoint - -CREATE OR REPLACE FUNCTION get_latest_snapshot_fast(p_workspace_id uuid) -RETURNS TABLE(id uuid, snapshot_version integer, state jsonb, event_count integer, created_at timestamptz) -LANGUAGE plpgsql -SECURITY DEFINER -AS $$ -BEGIN - RETURN QUERY - SELECT ws.id, ws.snapshot_version, ws.state, ws.event_count, ws.created_at - FROM workspace_snapshots ws - WHERE ws.workspace_id = p_workspace_id - ORDER BY ws.snapshot_version DESC - LIMIT 1; -END; -$$;--> statement-breakpoint - -CREATE OR REPLACE FUNCTION get_workspace_events_fast( - p_workspace_id uuid, - p_from_version integer DEFAULT 0, - p_limit integer DEFAULT 1000 -) -RETURNS TABLE(event_id text, event_type text, payload jsonb, "timestamp" bigint, user_id text, user_name text, version integer) -LANGUAGE plpgsql -SECURITY DEFINER -AS $$ -BEGIN - RETURN QUERY - SELECT we.event_id, we.event_type, we.payload, we.timestamp, we.user_id, we.user_name, we.version - FROM workspace_events we - WHERE we.workspace_id = p_workspace_id AND we.version > p_from_version - ORDER BY we.version ASC - LIMIT p_limit; -END; -$$;--> statement-breakpoint - -CREATE OR REPLACE FUNCTION needs_snapshot( - p_workspace_id uuid, - p_snapshot_threshold integer DEFAULT 100 -) -RETURNS TABLE(needs_snapshot boolean, current_version integer, last_snapshot_version integer, events_since_snapshot integer) -LANGUAGE plpgsql -SECURITY INVOKER -AS $$ -DECLARE - v_current_version INTEGER; - v_last_snapshot_version INTEGER; - v_events_since INTEGER; -BEGIN - SELECT COALESCE(MAX(version), 0) INTO v_current_version - FROM workspace_events WHERE workspace_id = p_workspace_id; - - SELECT COALESCE(MAX(snapshot_version), 0) INTO v_last_snapshot_version - FROM workspace_snapshots WHERE workspace_id = p_workspace_id; - - v_events_since := v_current_version - v_last_snapshot_version; - - RETURN QUERY SELECT - v_events_since >= p_snapshot_threshold, - v_current_version, - v_last_snapshot_version, - v_events_since; -END; -$$; \ No newline at end of file diff --git a/drizzle/0001_add_realtime_collaboration.sql b/drizzle/0001_add_realtime_collaboration.sql deleted file mode 100644 index 61908122..00000000 --- a/drizzle/0001_add_realtime_collaboration.sql +++ /dev/null @@ -1,156 +0,0 @@ --- ============================================================================= --- Workspace Collaborators Table for Real-Time Collaboration --- ============================================================================= - -CREATE TABLE "workspace_collaborators" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "workspace_id" uuid NOT NULL, - "user_id" text NOT NULL, - "permission_level" text DEFAULT 'editor' NOT NULL, - "invite_token" text, - "created_at" timestamp with time zone DEFAULT now(), - CONSTRAINT "workspace_collaborators_invite_token_unique" UNIQUE("invite_token"), - CONSTRAINT "workspace_collaborators_workspace_user_unique" UNIQUE("workspace_id", "user_id") -); ---> statement-breakpoint -ALTER TABLE "workspace_collaborators" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint -ALTER TABLE "workspace_collaborators" ADD CONSTRAINT "workspace_collaborators_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -CREATE INDEX "idx_workspace_collaborators_lookup" ON "workspace_collaborators" USING btree ("user_id" text_ops, "workspace_id" uuid_ops);--> statement-breakpoint -CREATE INDEX "idx_workspace_collaborators_workspace" ON "workspace_collaborators" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint - --- RLS Policies for workspace_collaborators -CREATE POLICY "Owners can manage collaborators" ON "workspace_collaborators" AS PERMISSIVE FOR ALL TO "authenticated" -USING (EXISTS ( - SELECT 1 FROM workspaces w - WHERE w.id = workspace_collaborators.workspace_id - AND w.user_id = (auth.jwt() ->> 'sub'::text) -));--> statement-breakpoint - -CREATE POLICY "Collaborators can view their access" ON "workspace_collaborators" AS PERMISSIVE FOR SELECT TO "authenticated" -USING (user_id = (auth.jwt() ->> 'sub'::text));--> statement-breakpoint - --- ============================================================================= --- Broadcast Trigger for workspace_events --- Automatically broadcasts when an event is inserted --- ============================================================================= - -CREATE OR REPLACE FUNCTION workspace_events_broadcast_trigger() -RETURNS TRIGGER -LANGUAGE plpgsql -SECURITY DEFINER -AS $$ -BEGIN - -- Broadcast the event to the workspace channel - -- All clients subscribed to workspace::events will receive this - PERFORM realtime.broadcast_changes( - 'workspace:' || NEW.workspace_id::text || ':events', - TG_OP, -- operation type: INSERT - TG_OP, -- event name: INSERT - TG_TABLE_NAME, -- table name - TG_TABLE_SCHEMA, -- schema - NEW, -- new row data - OLD -- old row data (null for INSERT) - ); - RETURN NEW; -END; -$$;--> statement-breakpoint - -CREATE TRIGGER workspace_events_realtime_broadcast - AFTER INSERT ON workspace_events - FOR EACH ROW EXECUTE FUNCTION workspace_events_broadcast_trigger();--> statement-breakpoint - --- ============================================================================= --- RLS Policies for realtime.messages --- Authorizes who can subscribe/publish to workspace channels --- ============================================================================= - --- Allow workspace owner OR collaborators to receive events -CREATE POLICY "workspace_access_can_read" ON realtime.messages -FOR SELECT TO authenticated -USING ( - topic LIKE 'workspace:%:events' - AND ( - -- Owner access - EXISTS ( - SELECT 1 FROM public.workspaces w - WHERE w.id = (SPLIT_PART(topic, ':', 2))::uuid - AND w.user_id = (auth.jwt() ->> 'sub'::text) - ) - OR - -- Collaborator access - EXISTS ( - SELECT 1 FROM public.workspace_collaborators c - WHERE c.workspace_id = (SPLIT_PART(topic, ':', 2))::uuid - AND c.user_id = (auth.jwt() ->> 'sub'::text) - ) - ) -);--> statement-breakpoint - --- Allow workspace owner OR editor collaborators to send events (presence) -CREATE POLICY "workspace_access_can_write" ON realtime.messages -FOR INSERT TO authenticated -WITH CHECK ( - topic LIKE 'workspace:%:events' - AND ( - -- Owner access - EXISTS ( - SELECT 1 FROM public.workspaces w - WHERE w.id = (SPLIT_PART(topic, ':', 2))::uuid - AND w.user_id = (auth.jwt() ->> 'sub'::text) - ) - OR - -- Editor collaborator access - EXISTS ( - SELECT 1 FROM public.workspace_collaborators c - WHERE c.workspace_id = (SPLIT_PART(topic, ':', 2))::uuid - AND c.user_id = (auth.jwt() ->> 'sub'::text) - AND c.permission_level = 'editor' - ) - ) -);--> statement-breakpoint - --- ============================================================================= --- Update existing RLS policies on workspace_events to include collaborators --- ============================================================================= - --- Drop old policy that only allows owner -DROP POLICY IF EXISTS "Users can insert workspace events they have write access to" ON "workspace_events";--> statement-breakpoint - --- New policy: owners AND editor collaborators can insert events -CREATE POLICY "Users can insert workspace events they have write access to" ON "workspace_events" AS PERMISSIVE FOR INSERT TO public -WITH CHECK ( - -- Owner access - EXISTS ( - SELECT 1 FROM workspaces - WHERE workspaces.id = workspace_events.workspace_id - AND workspaces.user_id = (auth.jwt() ->> 'sub'::text) - ) - OR - -- Editor collaborator access - EXISTS ( - SELECT 1 FROM workspace_collaborators c - WHERE c.workspace_id = workspace_events.workspace_id - AND c.user_id = (auth.jwt() ->> 'sub'::text) - AND c.permission_level = 'editor' - ) -);--> statement-breakpoint - --- Update select policy to include collaborators -DROP POLICY IF EXISTS "Users can read workspace events they have access to" ON "workspace_events";--> statement-breakpoint - -CREATE POLICY "Users can read workspace events they have access to" ON "workspace_events" AS PERMISSIVE FOR SELECT TO public -USING ( - -- Owner access - EXISTS ( - SELECT 1 FROM workspaces - WHERE workspaces.id = workspace_events.workspace_id - AND workspaces.user_id = (auth.jwt() ->> 'sub'::text) - ) - OR - -- Collaborator access (viewer or editor) - EXISTS ( - SELECT 1 FROM workspace_collaborators c - WHERE c.workspace_id = workspace_events.workspace_id - AND c.user_id = (auth.jwt() ->> 'sub'::text) - ) -); diff --git a/drizzle/0002_add_workspace_share_links.sql b/drizzle/0002_add_workspace_share_links.sql deleted file mode 100644 index ac0d4c7e..00000000 --- a/drizzle/0002_add_workspace_share_links.sql +++ /dev/null @@ -1,27 +0,0 @@ --- Multi-use share links: anyone with the link can join workspace (no email restriction) -CREATE TABLE "workspace_share_links" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "workspace_id" uuid NOT NULL, - "token" text NOT NULL, - "permission_level" text DEFAULT 'editor' NOT NULL, - "created_at" timestamp with time zone DEFAULT now(), - "expires_at" timestamp with time zone NOT NULL, - CONSTRAINT "workspace_share_links_token_key" UNIQUE("token"), - CONSTRAINT "workspace_share_links_workspace_key" UNIQUE("workspace_id") -); ---> statement-breakpoint -ALTER TABLE "workspace_share_links" ENABLE ROW LEVEL SECURITY; ---> statement-breakpoint -ALTER TABLE "workspace_share_links" ADD CONSTRAINT "workspace_share_links_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action; ---> statement-breakpoint -CREATE INDEX "idx_workspace_share_links_token" ON "workspace_share_links" USING btree ("token" text_ops); ---> statement-breakpoint -CREATE INDEX "idx_workspace_share_links_workspace" ON "workspace_share_links" USING btree ("workspace_id" uuid_ops); ---> statement-breakpoint -CREATE POLICY "Public can view share link by token" ON "workspace_share_links" AS PERMISSIVE FOR SELECT TO public USING (true); ---> statement-breakpoint -CREATE POLICY "Owners and editors can manage share links" ON "workspace_share_links" AS PERMISSIVE FOR ALL TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM workspaces w - WHERE ((w.id = workspace_share_links.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1 - FROM workspace_collaborators c - WHERE ((c.workspace_id = workspace_share_links.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))); diff --git a/drizzle/0002_deep_shadowcat.sql b/drizzle/0002_deep_shadowcat.sql deleted file mode 100644 index eb03c2f7..00000000 --- a/drizzle/0002_deep_shadowcat.sql +++ /dev/null @@ -1,35 +0,0 @@ -CREATE TABLE "chat_messages" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "thread_id" uuid NOT NULL, - "message_id" text NOT NULL, - "parent_id" text, - "format" text NOT NULL, - "content" jsonb NOT NULL, - "created_at" timestamp with time zone DEFAULT now() -); ---> statement-breakpoint -CREATE TABLE "chat_threads" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "workspace_id" uuid NOT NULL, - "user_id" text NOT NULL, - "title" text, - "is_archived" boolean DEFAULT false, - "external_id" text, - "created_at" timestamp with time zone DEFAULT now(), - "updated_at" timestamp with time zone DEFAULT now(), - "last_message_at" timestamp with time zone DEFAULT now() -); ---> statement-breakpoint -ALTER TABLE "chat_threads" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint -ALTER TABLE "chat_messages" ADD CONSTRAINT "chat_messages_thread_id_chat_threads_id_fk" FOREIGN KEY ("thread_id") REFERENCES "public"."chat_threads"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "chat_threads" ADD CONSTRAINT "chat_threads_workspace_id_workspaces_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "chat_threads" ADD CONSTRAINT "chat_threads_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -CREATE INDEX "idx_chat_messages_thread" ON "chat_messages" USING btree ("thread_id" uuid_ops);--> statement-breakpoint -CREATE INDEX "idx_chat_messages_thread_created" ON "chat_messages" USING btree ("thread_id" uuid_ops,"created_at" timestamptz_ops);--> statement-breakpoint -CREATE INDEX "idx_chat_threads_workspace" ON "chat_threads" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint -CREATE INDEX "idx_chat_threads_user" ON "chat_threads" USING btree ("user_id" text_ops);--> statement-breakpoint -CREATE INDEX "idx_chat_threads_last_message" ON "chat_threads" USING btree ("workspace_id" uuid_ops,"last_message_at" timestamptz_ops);--> statement-breakpoint -CREATE POLICY "Users can manage threads in their workspaces" ON "chat_threads" AS PERMISSIVE FOR ALL TO "authenticated" USING ((EXISTS ( SELECT 1 FROM workspaces w - WHERE ((w.id = chat_threads.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) - OR (EXISTS ( SELECT 1 FROM workspace_collaborators c - WHERE ((c.workspace_id = chat_threads.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))); \ No newline at end of file diff --git a/drizzle/0003_elite_harrier.sql b/drizzle/0003_elite_harrier.sql deleted file mode 100644 index 36963ed3..00000000 --- a/drizzle/0003_elite_harrier.sql +++ /dev/null @@ -1,17 +0,0 @@ -CREATE TABLE "workspace_item_reads" ( - "thread_id" uuid NOT NULL, - "item_id" text NOT NULL, - "last_modified" bigint NOT NULL, - "read_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "workspace_item_reads_thread_item_key" UNIQUE("thread_id","item_id") -); ---> statement-breakpoint -ALTER TABLE "workspace_item_reads" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint -ALTER TABLE "workspace_item_reads" ADD CONSTRAINT "workspace_item_reads_thread_id_chat_threads_id_fk" FOREIGN KEY ("thread_id") REFERENCES "public"."chat_threads"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -CREATE INDEX "idx_workspace_item_reads_thread_item" ON "workspace_item_reads" USING btree ("thread_id" uuid_ops,"item_id" text_ops);--> statement-breakpoint -CREATE POLICY "Users can manage reads for threads in their workspaces" ON "workspace_item_reads" AS PERMISSIVE FOR ALL TO "authenticated" USING ((EXISTS ( SELECT 1 FROM chat_threads ct - JOIN workspaces w ON w.id = ct.workspace_id - WHERE ((ct.id = workspace_item_reads.thread_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) - OR (EXISTS ( SELECT 1 FROM chat_threads ct - JOIN workspace_collaborators c ON c.workspace_id = ct.workspace_id - WHERE ((ct.id = workspace_item_reads.thread_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))); \ No newline at end of file diff --git a/drizzle/0004_add_chat_threads_head_message_id.sql b/drizzle/0004_add_chat_threads_head_message_id.sql deleted file mode 100644 index 48ab58cb..00000000 --- a/drizzle/0004_add_chat_threads_head_message_id.sql +++ /dev/null @@ -1,2 +0,0 @@ --- Persist current branch tip for threaded conversations; used when loading history. -ALTER TABLE "chat_threads" ADD COLUMN "head_message_id" text; diff --git a/drizzle/0005_add_chat_messages_thread_message_unique.sql b/drizzle/0005_add_chat_messages_thread_message_unique.sql deleted file mode 100644 index 764dee70..00000000 --- a/drizzle/0005_add_chat_messages_thread_message_unique.sql +++ /dev/null @@ -1,3 +0,0 @@ --- Ensure headMessageId maps to exactly one row; prevent duplicate (thread_id, message_id). --- Note: If duplicates exist, run a de-dupe (e.g. keep earliest created_at) before migrating. -ALTER TABLE "chat_messages" ADD CONSTRAINT "chat_messages_thread_message_key" UNIQUE ("thread_id", "message_id"); diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json index 4c4db162..bc87620c 100644 --- a/drizzle/meta/0000_snapshot.json +++ b/drizzle/meta/0000_snapshot.json @@ -1,5 +1,5 @@ { - "id": "9c4d6810-bb7c-4f01-be08-61eb46e059ed", + "id": "a4f859f9-1fa2-42e1-ab7d-bfc9a4b3491f", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", @@ -127,6 +127,297 @@ "checkConstraints": {}, "isRLSEnabled": false }, + "public.chat_messages": { + "name": "chat_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "thread_id": { + "name": "thread_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "format": { + "name": "format", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_chat_messages_thread": { + "name": "idx_chat_messages_thread", + "columns": [ + { + "expression": "thread_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "uuid_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_chat_messages_thread_created": { + "name": "idx_chat_messages_thread_created", + "columns": [ + { + "expression": "thread_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "uuid_ops" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "timestamptz_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "chat_messages_thread_id_chat_threads_id_fk": { + "name": "chat_messages_thread_id_chat_threads_id_fk", + "tableFrom": "chat_messages", + "tableTo": "chat_threads", + "columnsFrom": [ + "thread_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "chat_messages_thread_message_key": { + "name": "chat_messages_thread_message_key", + "nullsNotDistinct": false, + "columns": [ + "thread_id", + "message_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.chat_threads": { + "name": "chat_threads", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_archived": { + "name": "is_archived", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "last_message_at": { + "name": "last_message_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "head_message_id": { + "name": "head_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_chat_threads_workspace": { + "name": "idx_chat_threads_workspace", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "uuid_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_chat_threads_user": { + "name": "idx_chat_threads_user", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "text_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_chat_threads_last_message": { + "name": "idx_chat_threads_last_message", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "uuid_ops" + }, + { + "expression": "last_message_at", + "isExpression": false, + "asc": false, + "nulls": "first", + "opclass": "timestamptz_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "chat_threads_workspace_id_workspaces_id_fk": { + "name": "chat_threads_workspace_id_workspaces_id_fk", + "tableFrom": "chat_threads", + "tableTo": "workspaces", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chat_threads_user_id_user_id_fk": { + "name": "chat_threads_user_id_user_id_fk", + "tableFrom": "chat_threads", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": { + "chat_threads_user_scoped": { + "name": "chat_threads_user_scoped", + "as": "PERMISSIVE", + "for": "ALL", + "to": [ + "authenticated" + ], + "using": "((chat_threads.user_id = (auth.jwt() ->> 'sub'::text))\n AND ((EXISTS ( SELECT 1 FROM workspaces w\n WHERE ((w.id = chat_threads.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text)))))\n OR (EXISTS ( SELECT 1 FROM workspace_collaborators c\n WHERE ((c.workspace_id = chat_threads.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))))" + } + }, + "checkConstraints": {}, + "isRLSEnabled": false + }, "public.session": { "name": "session", "schema": "", @@ -506,8 +797,8 @@ "checkConstraints": {}, "isRLSEnabled": false }, - "public.workspace_events": { - "name": "workspace_events", + "public.workspace_collaborators": { + "name": "workspace_collaborators", "schema": "", "columns": { "id": { @@ -523,29 +814,199 @@ "primaryKey": false, "notNull": true }, - "event_id": { - "name": "event_id", + "user_id": { + "name": "user_id", "type": "text", "primaryKey": false, "notNull": true }, - "event_type": { - "name": "event_type", + "permission_level": { + "name": "permission_level", "type": "text", "primaryKey": false, - "notNull": true + "notNull": true, + "default": "'editor'" }, - "payload": { - "name": "payload", - "type": "jsonb", + "invite_token": { + "name": "invite_token", + "type": "text", "primaryKey": false, - "notNull": true + "notNull": false }, - "timestamp": { - "name": "timestamp", - "type": "bigint", - "primaryKey": false, - "notNull": true + "last_opened_at": { + "name": "last_opened_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_workspace_collaborators_lookup": { + "name": "idx_workspace_collaborators_lookup", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "text_ops" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "uuid_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_workspace_collaborators_workspace": { + "name": "idx_workspace_collaborators_workspace", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "uuid_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_workspace_collaborators_last_opened_at": { + "name": "idx_workspace_collaborators_last_opened_at", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "text_ops" + }, + { + "expression": "last_opened_at", + "isExpression": false, + "asc": false, + "nulls": "first", + "opclass": "timestamptz_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_collaborators_workspace_id_fkey": { + "name": "workspace_collaborators_workspace_id_fkey", + "tableFrom": "workspace_collaborators", + "tableTo": "workspaces", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workspace_collaborators_invite_token_unique": { + "name": "workspace_collaborators_invite_token_unique", + "nullsNotDistinct": false, + "columns": [ + "invite_token" + ] + }, + "workspace_collaborators_workspace_user_unique": { + "name": "workspace_collaborators_workspace_user_unique", + "nullsNotDistinct": false, + "columns": [ + "workspace_id", + "user_id" + ] + } + }, + "policies": { + "Owners can manage collaborators": { + "name": "Owners can manage collaborators", + "as": "PERMISSIVE", + "for": "ALL", + "to": [ + "authenticated" + ], + "using": "(EXISTS ( SELECT 1\n FROM workspaces w\n WHERE ((w.id = workspace_collaborators.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text)))))" + }, + "Collaborators can view their access": { + "name": "Collaborators can view their access", + "as": "PERMISSIVE", + "for": "SELECT", + "to": [ + "authenticated" + ], + "using": "(user_id = (auth.jwt() ->> 'sub'::text))" + } + }, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_events": { + "name": "workspace_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "bigint", + "primaryKey": false, + "notNull": true }, "user_id": { "name": "user_id", @@ -686,7 +1147,7 @@ "to": [ "public" ], - "withCheck": "(EXISTS ( SELECT 1\n FROM workspaces\n WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text)))))" + "withCheck": "(EXISTS ( SELECT 1\n FROM workspaces\n WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_events.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))" }, "Users can read workspace events they have access to": { "name": "Users can read workspace events they have access to", @@ -694,9 +1155,392 @@ "for": "SELECT", "to": [ "public" + ], + "using": "(EXISTS ( SELECT 1\n FROM workspaces\n WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_events.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))" + } + }, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_invites": { + "name": "workspace_invites", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission_level": { + "name": "permission_level", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'editor'" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_workspace_invites_token": { + "name": "idx_workspace_invites_token", + "columns": [ + { + "expression": "token", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "text_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_workspace_invites_email": { + "name": "idx_workspace_invites_email", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "text_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_workspace_invites_workspace": { + "name": "idx_workspace_invites_workspace", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "uuid_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_invites_workspace_id_fkey": { + "name": "workspace_invites_workspace_id_fkey", + "tableFrom": "workspace_invites", + "tableTo": "workspaces", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workspace_invites_token_key": { + "name": "workspace_invites_token_key", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": { + "Public can view invite by token": { + "name": "Public can view invite by token", + "as": "PERMISSIVE", + "for": "SELECT", + "to": [ + "public" + ], + "using": "true" + }, + "Users can insert invites for workspaces they own/edit": { + "name": "Users can insert invites for workspaces they own/edit", + "as": "PERMISSIVE", + "for": "INSERT", + "to": [ + "authenticated" + ], + "withCheck": "(EXISTS ( SELECT 1\n FROM workspaces w\n WHERE ((w.id = workspace_invites.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_invites.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))" + } + }, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_item_reads": { + "name": "workspace_item_reads", + "schema": "", + "columns": { + "thread_id": { + "name": "thread_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_modified": { + "name": "last_modified", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "read_at": { + "name": "read_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_workspace_item_reads_thread_item": { + "name": "idx_workspace_item_reads_thread_item", + "columns": [ + { + "expression": "thread_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "uuid_ops" + }, + { + "expression": "item_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "text_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_item_reads_thread_id_chat_threads_id_fk": { + "name": "workspace_item_reads_thread_id_chat_threads_id_fk", + "tableFrom": "workspace_item_reads", + "tableTo": "chat_threads", + "columnsFrom": [ + "thread_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workspace_item_reads_thread_item_key": { + "name": "workspace_item_reads_thread_item_key", + "nullsNotDistinct": false, + "columns": [ + "thread_id", + "item_id" + ] + } + }, + "policies": { + "workspace_item_reads_user_scoped": { + "name": "workspace_item_reads_user_scoped", + "as": "PERMISSIVE", + "for": "ALL", + "to": [ + "authenticated" + ], + "using": "(EXISTS ( SELECT 1 FROM chat_threads ct\n JOIN workspaces w ON w.id = ct.workspace_id\n WHERE ((ct.id = workspace_item_reads.thread_id) AND (ct.user_id = (auth.jwt() ->> 'sub'::text)) AND (w.user_id = (auth.jwt() ->> 'sub'::text)))))\n OR (EXISTS ( SELECT 1 FROM chat_threads ct\n JOIN workspace_collaborators c ON c.workspace_id = ct.workspace_id\n WHERE ((ct.id = workspace_item_reads.thread_id) AND (ct.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))" + } + }, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_share_links": { + "name": "workspace_share_links", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission_level": { + "name": "permission_level", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'editor'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "idx_workspace_share_links_token": { + "name": "idx_workspace_share_links_token", + "columns": [ + { + "expression": "token", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "text_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_workspace_share_links_workspace": { + "name": "idx_workspace_share_links_workspace", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "uuid_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_share_links_workspace_id_fkey": { + "name": "workspace_share_links_workspace_id_fkey", + "tableFrom": "workspace_share_links", + "tableTo": "workspaces", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workspace_share_links_token_key": { + "name": "workspace_share_links_token_key", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + }, + "workspace_share_links_workspace_key": { + "name": "workspace_share_links_workspace_key", + "nullsNotDistinct": false, + "columns": [ + "workspace_id" ] } }, + "policies": { + "Public can view share link by token": { + "name": "Public can view share link by token", + "as": "PERMISSIVE", + "for": "SELECT", + "to": [ + "public" + ], + "using": "true" + }, + "Owners and editors can manage share links": { + "name": "Owners and editors can manage share links", + "as": "PERMISSIVE", + "for": "ALL", + "to": [ + "authenticated" + ], + "using": "(EXISTS ( SELECT 1\n FROM workspaces w\n WHERE ((w.id = workspace_share_links.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_share_links.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))" + } + }, "checkConstraints": {}, "isRLSEnabled": false }, diff --git a/drizzle/meta/0001_snapshot.json b/drizzle/meta/0001_snapshot.json deleted file mode 100644 index d5848ca7..00000000 --- a/drizzle/meta/0001_snapshot.json +++ /dev/null @@ -1,1547 +0,0 @@ -{ - "id": "1fc3e75d-4a15-4c00-ad92-4edde926b371", - "prevId": "9c4d6810-bb7c-4f01-be08-61eb46e059ed", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.account": { - "name": "account", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "account_id": { - "name": "account_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "provider_id": { - "name": "provider_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "access_token": { - "name": "access_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "id_token": { - "name": "id_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "access_token_expires_at": { - "name": "access_token_expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "refresh_token_expires_at": { - "name": "refresh_token_expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "scope": { - "name": "scope", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "idx_account_user_id": { - "name": "idx_account_user_id", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "account_user_id_user_id_fk": { - "name": "account_user_id_user_id_fk", - "tableFrom": "account", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.session": { - "name": "session", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "ip_address": { - "name": "ip_address", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "user_agent": { - "name": "user_agent", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "idx_session_user_id": { - "name": "idx_session_user_id", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_session_token": { - "name": "idx_session_token", - "columns": [ - { - "expression": "token", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "session_user_id_user_id_fk": { - "name": "session_user_id_user_id_fk", - "tableFrom": "session", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "session_token_unique": { - "name": "session_token_unique", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "email_verified": { - "name": "email_verified", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "image": { - "name": "image", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "is_anonymous": { - "name": "is_anonymous", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "idx_user_email": { - "name": "idx_user_email", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_email_unique": { - "name": "user_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_profiles": { - "name": "user_profiles", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "onboarding_completed": { - "name": "onboarding_completed", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "onboarding_completed_at": { - "name": "onboarding_completed_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_user_profiles_user_id": { - "name": "idx_user_profiles_user_id", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_profiles_user_id_key": { - "name": "user_profiles_user_id_key", - "nullsNotDistinct": false, - "columns": [ - "user_id" - ] - } - }, - "policies": { - "Users can insert their own profile": { - "name": "Users can insert their own profile", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "authenticated" - ], - "withCheck": "(( SELECT (auth.jwt() ->> 'sub'::text)) = user_id)" - }, - "Users can update their own profile": { - "name": "Users can update their own profile", - "as": "PERMISSIVE", - "for": "UPDATE", - "to": [ - "authenticated" - ] - }, - "Users can view their own profile": { - "name": "Users can view their own profile", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "authenticated" - ] - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.verification": { - "name": "verification", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "identifier": { - "name": "identifier", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "value": { - "name": "value", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "idx_verification_identifier": { - "name": "idx_verification_identifier", - "columns": [ - { - "expression": "identifier", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_collaborators": { - "name": "workspace_collaborators", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "permission_level": { - "name": "permission_level", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'editor'" - }, - "invite_token": { - "name": "invite_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "last_opened_at": { - "name": "last_opened_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_workspace_collaborators_lookup": { - "name": "idx_workspace_collaborators_lookup", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - }, - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_collaborators_workspace": { - "name": "idx_workspace_collaborators_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_collaborators_last_opened_at": { - "name": "idx_workspace_collaborators_last_opened_at", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - }, - { - "expression": "last_opened_at", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_collaborators_workspace_id_fkey": { - "name": "workspace_collaborators_workspace_id_fkey", - "tableFrom": "workspace_collaborators", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_collaborators_invite_token_unique": { - "name": "workspace_collaborators_invite_token_unique", - "nullsNotDistinct": false, - "columns": [ - "invite_token" - ] - }, - "workspace_collaborators_workspace_user_unique": { - "name": "workspace_collaborators_workspace_user_unique", - "nullsNotDistinct": false, - "columns": [ - "workspace_id", - "user_id" - ] - } - }, - "policies": { - "Owners can manage collaborators": { - "name": "Owners can manage collaborators", - "as": "PERMISSIVE", - "for": "ALL", - "to": [ - "authenticated" - ], - "using": "(EXISTS ( SELECT 1\n FROM workspaces w\n WHERE ((w.id = workspace_collaborators.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text)))))" - }, - "Collaborators can view their access": { - "name": "Collaborators can view their access", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "authenticated" - ], - "using": "(user_id = (auth.jwt() ->> 'sub'::text))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_events": { - "name": "workspace_events", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "event_id": { - "name": "event_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "event_type": { - "name": "event_type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "payload": { - "name": "payload", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "timestamp": { - "name": "timestamp", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "version": { - "name": "version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "user_name": { - "name": "user_name", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "idx_workspace_events_event_id": { - "name": "idx_workspace_events_event_id", - "columns": [ - { - "expression": "event_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_events_timestamp": { - "name": "idx_workspace_events_timestamp", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "timestamp", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "int8_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_events_user_name": { - "name": "idx_workspace_events_user_name", - "columns": [ - { - "expression": "user_name", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_events_workspace": { - "name": "idx_workspace_events_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "version", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "int4_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_events_workspace_id_fkey": { - "name": "workspace_events_workspace_id_fkey", - "tableFrom": "workspace_events", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_events_event_id_key": { - "name": "workspace_events_event_id_key", - "nullsNotDistinct": false, - "columns": [ - "event_id" - ] - } - }, - "policies": { - "Users can insert workspace events they have write access to": { - "name": "Users can insert workspace events they have write access to", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "public" - ], - "withCheck": "(EXISTS ( SELECT 1\n FROM workspaces\n WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_events.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))" - }, - "Users can read workspace events they have access to": { - "name": "Users can read workspace events they have access to", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "public" - ], - "using": "(EXISTS ( SELECT 1\n FROM workspaces\n WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_events.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_invites": { - "name": "workspace_invites", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "inviter_id": { - "name": "inviter_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "permission_level": { - "name": "permission_level", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'editor'" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_workspace_invites_token": { - "name": "idx_workspace_invites_token", - "columns": [ - { - "expression": "token", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_invites_email": { - "name": "idx_workspace_invites_email", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_invites_workspace": { - "name": "idx_workspace_invites_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_invites_workspace_id_fkey": { - "name": "workspace_invites_workspace_id_fkey", - "tableFrom": "workspace_invites", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_invites_token_key": { - "name": "workspace_invites_token_key", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - } - }, - "policies": { - "Public can view invite by token": { - "name": "Public can view invite by token", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "public" - ], - "using": "true" - }, - "Users can insert invites for workspaces they own/edit": { - "name": "Users can insert invites for workspaces they own/edit", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "authenticated" - ], - "withCheck": "(EXISTS ( SELECT 1\n FROM workspaces w\n WHERE ((w.id = workspace_invites.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_invites.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_share_links": { - "name": "workspace_share_links", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "permission_level": { - "name": "permission_level", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'editor'" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "idx_workspace_share_links_token": { - "name": "idx_workspace_share_links_token", - "columns": [ - { - "expression": "token", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_share_links_workspace": { - "name": "idx_workspace_share_links_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_share_links_workspace_id_fkey": { - "name": "workspace_share_links_workspace_id_fkey", - "tableFrom": "workspace_share_links", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_share_links_token_key": { - "name": "workspace_share_links_token_key", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - }, - "workspace_share_links_workspace_key": { - "name": "workspace_share_links_workspace_key", - "nullsNotDistinct": false, - "columns": [ - "workspace_id" - ] - } - }, - "policies": { - "Public can view share link by token": { - "name": "Public can view share link by token", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "public" - ], - "using": "true" - }, - "Owners and editors can manage share links": { - "name": "Owners and editors can manage share links", - "as": "PERMISSIVE", - "for": "ALL", - "to": [ - "authenticated" - ], - "using": "(EXISTS ( SELECT 1\n FROM workspaces w\n WHERE ((w.id = workspace_share_links.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_share_links.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_snapshots": { - "name": "workspace_snapshots", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "snapshot_version": { - "name": "snapshot_version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "state": { - "name": "state", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "event_count": { - "name": "event_count", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_workspace_snapshots_version": { - "name": "idx_workspace_snapshots_version", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "snapshot_version", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "int4_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_snapshots_workspace": { - "name": "idx_workspace_snapshots_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_snapshots_workspace_id_fkey": { - "name": "workspace_snapshots_workspace_id_fkey", - "tableFrom": "workspace_snapshots", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_snapshots_workspace_id_snapshot_version_key": { - "name": "workspace_snapshots_workspace_id_snapshot_version_key", - "nullsNotDistinct": false, - "columns": [ - "workspace_id", - "snapshot_version" - ] - } - }, - "policies": { - "Service role can insert workspace snapshots": { - "name": "Service role can insert workspace snapshots", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "public" - ], - "withCheck": "true" - }, - "Users can read workspace snapshots they have access to": { - "name": "Users can read workspace snapshots they have access to", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "public" - ] - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspaces": { - "name": "workspaces", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "''" - }, - "template": { - "name": "template", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'blank'" - }, - "is_public": { - "name": "is_public", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "slug": { - "name": "slug", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "icon": { - "name": "icon", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sort_order": { - "name": "sort_order", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "color": { - "name": "color", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "last_opened_at": { - "name": "last_opened_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "idx_workspaces_created_at": { - "name": "idx_workspaces_created_at", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_slug": { - "name": "idx_workspaces_slug", - "columns": [ - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_user_id": { - "name": "idx_workspaces_user_id", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_user_slug": { - "name": "idx_workspaces_user_slug", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - }, - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_user_sort_order": { - "name": "idx_workspaces_user_sort_order", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - }, - { - "expression": "sort_order", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "int4_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_last_opened_at": { - "name": "idx_workspaces_last_opened_at", - "columns": [ - { - "expression": "last_opened_at", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": { - "Users can delete their own workspaces": { - "name": "Users can delete their own workspaces", - "as": "PERMISSIVE", - "for": "DELETE", - "to": [ - "authenticated" - ], - "using": "(( SELECT (auth.jwt() ->> 'sub'::text)) = user_id)" - }, - "Users can insert their own workspaces": { - "name": "Users can insert their own workspaces", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "authenticated" - ] - }, - "Users can update their own workspaces": { - "name": "Users can update their own workspaces", - "as": "PERMISSIVE", - "for": "UPDATE", - "to": [ - "authenticated" - ] - }, - "Users can view their own workspaces": { - "name": "Users can view their own workspaces", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "authenticated" - ] - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/drizzle/meta/0002_snapshot.json b/drizzle/meta/0002_snapshot.json deleted file mode 100644 index c7678de5..00000000 --- a/drizzle/meta/0002_snapshot.json +++ /dev/null @@ -1,1823 +0,0 @@ -{ - "id": "208b0e93-f789-49c6-abc8-e9328aab88b5", - "prevId": "1fc3e75d-4a15-4c00-ad92-4edde926b371", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.account": { - "name": "account", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "account_id": { - "name": "account_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "provider_id": { - "name": "provider_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "access_token": { - "name": "access_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "id_token": { - "name": "id_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "access_token_expires_at": { - "name": "access_token_expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "refresh_token_expires_at": { - "name": "refresh_token_expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "scope": { - "name": "scope", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "idx_account_user_id": { - "name": "idx_account_user_id", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "account_user_id_user_id_fk": { - "name": "account_user_id_user_id_fk", - "tableFrom": "account", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.chat_messages": { - "name": "chat_messages", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "thread_id": { - "name": "thread_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "message_id": { - "name": "message_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "parent_id": { - "name": "parent_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "format": { - "name": "format", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "content": { - "name": "content", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_chat_messages_thread": { - "name": "idx_chat_messages_thread", - "columns": [ - { - "expression": "thread_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_chat_messages_thread_created": { - "name": "idx_chat_messages_thread_created", - "columns": [ - { - "expression": "thread_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "chat_messages_thread_id_chat_threads_id_fk": { - "name": "chat_messages_thread_id_chat_threads_id_fk", - "tableFrom": "chat_messages", - "tableTo": "chat_threads", - "columnsFrom": [ - "thread_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.chat_threads": { - "name": "chat_threads", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "is_archived": { - "name": "is_archived", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "external_id": { - "name": "external_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "last_message_at": { - "name": "last_message_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_chat_threads_workspace": { - "name": "idx_chat_threads_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_chat_threads_user": { - "name": "idx_chat_threads_user", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_chat_threads_last_message": { - "name": "idx_chat_threads_last_message", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "last_message_at", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "chat_threads_workspace_id_workspaces_id_fk": { - "name": "chat_threads_workspace_id_workspaces_id_fk", - "tableFrom": "chat_threads", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "chat_threads_user_id_user_id_fk": { - "name": "chat_threads_user_id_user_id_fk", - "tableFrom": "chat_threads", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": { - "Users can manage threads in their workspaces": { - "name": "Users can manage threads in their workspaces", - "as": "PERMISSIVE", - "for": "ALL", - "to": [ - "authenticated" - ], - "using": "(EXISTS ( SELECT 1 FROM workspaces w\n WHERE ((w.id = chat_threads.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text)))))\n OR (EXISTS ( SELECT 1 FROM workspace_collaborators c\n WHERE ((c.workspace_id = chat_threads.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.session": { - "name": "session", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "ip_address": { - "name": "ip_address", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "user_agent": { - "name": "user_agent", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "idx_session_user_id": { - "name": "idx_session_user_id", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_session_token": { - "name": "idx_session_token", - "columns": [ - { - "expression": "token", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "session_user_id_user_id_fk": { - "name": "session_user_id_user_id_fk", - "tableFrom": "session", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "session_token_unique": { - "name": "session_token_unique", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "email_verified": { - "name": "email_verified", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "image": { - "name": "image", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "is_anonymous": { - "name": "is_anonymous", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "idx_user_email": { - "name": "idx_user_email", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_email_unique": { - "name": "user_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_profiles": { - "name": "user_profiles", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "onboarding_completed": { - "name": "onboarding_completed", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "onboarding_completed_at": { - "name": "onboarding_completed_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_user_profiles_user_id": { - "name": "idx_user_profiles_user_id", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_profiles_user_id_key": { - "name": "user_profiles_user_id_key", - "nullsNotDistinct": false, - "columns": [ - "user_id" - ] - } - }, - "policies": { - "Users can insert their own profile": { - "name": "Users can insert their own profile", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "authenticated" - ], - "withCheck": "(( SELECT (auth.jwt() ->> 'sub'::text)) = user_id)" - }, - "Users can update their own profile": { - "name": "Users can update their own profile", - "as": "PERMISSIVE", - "for": "UPDATE", - "to": [ - "authenticated" - ] - }, - "Users can view their own profile": { - "name": "Users can view their own profile", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "authenticated" - ] - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.verification": { - "name": "verification", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "identifier": { - "name": "identifier", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "value": { - "name": "value", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "idx_verification_identifier": { - "name": "idx_verification_identifier", - "columns": [ - { - "expression": "identifier", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_collaborators": { - "name": "workspace_collaborators", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "permission_level": { - "name": "permission_level", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'editor'" - }, - "invite_token": { - "name": "invite_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "last_opened_at": { - "name": "last_opened_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_workspace_collaborators_lookup": { - "name": "idx_workspace_collaborators_lookup", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - }, - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_collaborators_workspace": { - "name": "idx_workspace_collaborators_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_collaborators_last_opened_at": { - "name": "idx_workspace_collaborators_last_opened_at", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - }, - { - "expression": "last_opened_at", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_collaborators_workspace_id_fkey": { - "name": "workspace_collaborators_workspace_id_fkey", - "tableFrom": "workspace_collaborators", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_collaborators_invite_token_unique": { - "name": "workspace_collaborators_invite_token_unique", - "nullsNotDistinct": false, - "columns": [ - "invite_token" - ] - }, - "workspace_collaborators_workspace_user_unique": { - "name": "workspace_collaborators_workspace_user_unique", - "nullsNotDistinct": false, - "columns": [ - "workspace_id", - "user_id" - ] - } - }, - "policies": { - "Owners can manage collaborators": { - "name": "Owners can manage collaborators", - "as": "PERMISSIVE", - "for": "ALL", - "to": [ - "authenticated" - ], - "using": "(EXISTS ( SELECT 1\n FROM workspaces w\n WHERE ((w.id = workspace_collaborators.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text)))))" - }, - "Collaborators can view their access": { - "name": "Collaborators can view their access", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "authenticated" - ], - "using": "(user_id = (auth.jwt() ->> 'sub'::text))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_events": { - "name": "workspace_events", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "event_id": { - "name": "event_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "event_type": { - "name": "event_type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "payload": { - "name": "payload", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "timestamp": { - "name": "timestamp", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "version": { - "name": "version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "user_name": { - "name": "user_name", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "idx_workspace_events_event_id": { - "name": "idx_workspace_events_event_id", - "columns": [ - { - "expression": "event_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_events_timestamp": { - "name": "idx_workspace_events_timestamp", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "timestamp", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "int8_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_events_user_name": { - "name": "idx_workspace_events_user_name", - "columns": [ - { - "expression": "user_name", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_events_workspace": { - "name": "idx_workspace_events_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "version", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "int4_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_events_workspace_id_fkey": { - "name": "workspace_events_workspace_id_fkey", - "tableFrom": "workspace_events", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_events_event_id_key": { - "name": "workspace_events_event_id_key", - "nullsNotDistinct": false, - "columns": [ - "event_id" - ] - } - }, - "policies": { - "Users can insert workspace events they have write access to": { - "name": "Users can insert workspace events they have write access to", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "public" - ], - "withCheck": "(EXISTS ( SELECT 1\n FROM workspaces\n WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_events.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))" - }, - "Users can read workspace events they have access to": { - "name": "Users can read workspace events they have access to", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "public" - ], - "using": "(EXISTS ( SELECT 1\n FROM workspaces\n WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_events.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_invites": { - "name": "workspace_invites", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "inviter_id": { - "name": "inviter_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "permission_level": { - "name": "permission_level", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'editor'" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_workspace_invites_token": { - "name": "idx_workspace_invites_token", - "columns": [ - { - "expression": "token", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_invites_email": { - "name": "idx_workspace_invites_email", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_invites_workspace": { - "name": "idx_workspace_invites_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_invites_workspace_id_fkey": { - "name": "workspace_invites_workspace_id_fkey", - "tableFrom": "workspace_invites", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_invites_token_key": { - "name": "workspace_invites_token_key", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - } - }, - "policies": { - "Public can view invite by token": { - "name": "Public can view invite by token", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "public" - ], - "using": "true" - }, - "Users can insert invites for workspaces they own/edit": { - "name": "Users can insert invites for workspaces they own/edit", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "authenticated" - ], - "withCheck": "(EXISTS ( SELECT 1\n FROM workspaces w\n WHERE ((w.id = workspace_invites.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_invites.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_share_links": { - "name": "workspace_share_links", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "permission_level": { - "name": "permission_level", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'editor'" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "idx_workspace_share_links_token": { - "name": "idx_workspace_share_links_token", - "columns": [ - { - "expression": "token", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_share_links_workspace": { - "name": "idx_workspace_share_links_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_share_links_workspace_id_fkey": { - "name": "workspace_share_links_workspace_id_fkey", - "tableFrom": "workspace_share_links", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_share_links_token_key": { - "name": "workspace_share_links_token_key", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - }, - "workspace_share_links_workspace_key": { - "name": "workspace_share_links_workspace_key", - "nullsNotDistinct": false, - "columns": [ - "workspace_id" - ] - } - }, - "policies": { - "Public can view share link by token": { - "name": "Public can view share link by token", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "public" - ], - "using": "true" - }, - "Owners and editors can manage share links": { - "name": "Owners and editors can manage share links", - "as": "PERMISSIVE", - "for": "ALL", - "to": [ - "authenticated" - ], - "using": "(EXISTS ( SELECT 1\n FROM workspaces w\n WHERE ((w.id = workspace_share_links.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_share_links.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_snapshots": { - "name": "workspace_snapshots", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "snapshot_version": { - "name": "snapshot_version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "state": { - "name": "state", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "event_count": { - "name": "event_count", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_workspace_snapshots_version": { - "name": "idx_workspace_snapshots_version", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "snapshot_version", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "int4_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_snapshots_workspace": { - "name": "idx_workspace_snapshots_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_snapshots_workspace_id_fkey": { - "name": "workspace_snapshots_workspace_id_fkey", - "tableFrom": "workspace_snapshots", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_snapshots_workspace_id_snapshot_version_key": { - "name": "workspace_snapshots_workspace_id_snapshot_version_key", - "nullsNotDistinct": false, - "columns": [ - "workspace_id", - "snapshot_version" - ] - } - }, - "policies": { - "Service role can insert workspace snapshots": { - "name": "Service role can insert workspace snapshots", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "public" - ], - "withCheck": "true" - }, - "Users can read workspace snapshots they have access to": { - "name": "Users can read workspace snapshots they have access to", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "public" - ] - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspaces": { - "name": "workspaces", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "''" - }, - "template": { - "name": "template", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'blank'" - }, - "is_public": { - "name": "is_public", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "slug": { - "name": "slug", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "icon": { - "name": "icon", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sort_order": { - "name": "sort_order", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "color": { - "name": "color", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "last_opened_at": { - "name": "last_opened_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "idx_workspaces_created_at": { - "name": "idx_workspaces_created_at", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_slug": { - "name": "idx_workspaces_slug", - "columns": [ - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_user_id": { - "name": "idx_workspaces_user_id", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_user_slug": { - "name": "idx_workspaces_user_slug", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - }, - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_user_sort_order": { - "name": "idx_workspaces_user_sort_order", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - }, - { - "expression": "sort_order", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "int4_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_last_opened_at": { - "name": "idx_workspaces_last_opened_at", - "columns": [ - { - "expression": "last_opened_at", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": { - "Users can delete their own workspaces": { - "name": "Users can delete their own workspaces", - "as": "PERMISSIVE", - "for": "DELETE", - "to": [ - "authenticated" - ], - "using": "(( SELECT (auth.jwt() ->> 'sub'::text)) = user_id)" - }, - "Users can insert their own workspaces": { - "name": "Users can insert their own workspaces", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "authenticated" - ] - }, - "Users can update their own workspaces": { - "name": "Users can update their own workspaces", - "as": "PERMISSIVE", - "for": "UPDATE", - "to": [ - "authenticated" - ] - }, - "Users can view their own workspaces": { - "name": "Users can view their own workspaces", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "authenticated" - ] - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/drizzle/meta/0003_snapshot.json b/drizzle/meta/0003_snapshot.json deleted file mode 100644 index f74c0463..00000000 --- a/drizzle/meta/0003_snapshot.json +++ /dev/null @@ -1,1918 +0,0 @@ -{ - "id": "4ff977d6-4f70-49fe-a07e-c39bf93e134e", - "prevId": "208b0e93-f789-49c6-abc8-e9328aab88b5", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.account": { - "name": "account", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "account_id": { - "name": "account_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "provider_id": { - "name": "provider_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "access_token": { - "name": "access_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "id_token": { - "name": "id_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "access_token_expires_at": { - "name": "access_token_expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "refresh_token_expires_at": { - "name": "refresh_token_expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "scope": { - "name": "scope", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "idx_account_user_id": { - "name": "idx_account_user_id", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "account_user_id_user_id_fk": { - "name": "account_user_id_user_id_fk", - "tableFrom": "account", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.chat_messages": { - "name": "chat_messages", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "thread_id": { - "name": "thread_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "message_id": { - "name": "message_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "parent_id": { - "name": "parent_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "format": { - "name": "format", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "content": { - "name": "content", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_chat_messages_thread": { - "name": "idx_chat_messages_thread", - "columns": [ - { - "expression": "thread_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_chat_messages_thread_created": { - "name": "idx_chat_messages_thread_created", - "columns": [ - { - "expression": "thread_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "chat_messages_thread_id_chat_threads_id_fk": { - "name": "chat_messages_thread_id_chat_threads_id_fk", - "tableFrom": "chat_messages", - "tableTo": "chat_threads", - "columnsFrom": [ - "thread_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.chat_threads": { - "name": "chat_threads", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "is_archived": { - "name": "is_archived", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "external_id": { - "name": "external_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "last_message_at": { - "name": "last_message_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_chat_threads_workspace": { - "name": "idx_chat_threads_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_chat_threads_user": { - "name": "idx_chat_threads_user", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_chat_threads_last_message": { - "name": "idx_chat_threads_last_message", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "last_message_at", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "chat_threads_workspace_id_workspaces_id_fk": { - "name": "chat_threads_workspace_id_workspaces_id_fk", - "tableFrom": "chat_threads", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "chat_threads_user_id_user_id_fk": { - "name": "chat_threads_user_id_user_id_fk", - "tableFrom": "chat_threads", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": { - "Users can manage threads in their workspaces": { - "name": "Users can manage threads in their workspaces", - "as": "PERMISSIVE", - "for": "ALL", - "to": [ - "authenticated" - ], - "using": "(EXISTS ( SELECT 1 FROM workspaces w\n WHERE ((w.id = chat_threads.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text)))))\n OR (EXISTS ( SELECT 1 FROM workspace_collaborators c\n WHERE ((c.workspace_id = chat_threads.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.session": { - "name": "session", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "ip_address": { - "name": "ip_address", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "user_agent": { - "name": "user_agent", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "idx_session_user_id": { - "name": "idx_session_user_id", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_session_token": { - "name": "idx_session_token", - "columns": [ - { - "expression": "token", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "session_user_id_user_id_fk": { - "name": "session_user_id_user_id_fk", - "tableFrom": "session", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "session_token_unique": { - "name": "session_token_unique", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "email_verified": { - "name": "email_verified", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "image": { - "name": "image", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "is_anonymous": { - "name": "is_anonymous", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "idx_user_email": { - "name": "idx_user_email", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_email_unique": { - "name": "user_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_profiles": { - "name": "user_profiles", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "onboarding_completed": { - "name": "onboarding_completed", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "onboarding_completed_at": { - "name": "onboarding_completed_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_user_profiles_user_id": { - "name": "idx_user_profiles_user_id", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_profiles_user_id_key": { - "name": "user_profiles_user_id_key", - "nullsNotDistinct": false, - "columns": [ - "user_id" - ] - } - }, - "policies": { - "Users can insert their own profile": { - "name": "Users can insert their own profile", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "authenticated" - ], - "withCheck": "(( SELECT (auth.jwt() ->> 'sub'::text)) = user_id)" - }, - "Users can update their own profile": { - "name": "Users can update their own profile", - "as": "PERMISSIVE", - "for": "UPDATE", - "to": [ - "authenticated" - ] - }, - "Users can view their own profile": { - "name": "Users can view their own profile", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "authenticated" - ] - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.verification": { - "name": "verification", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "identifier": { - "name": "identifier", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "value": { - "name": "value", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "idx_verification_identifier": { - "name": "idx_verification_identifier", - "columns": [ - { - "expression": "identifier", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_collaborators": { - "name": "workspace_collaborators", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "permission_level": { - "name": "permission_level", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'editor'" - }, - "invite_token": { - "name": "invite_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "last_opened_at": { - "name": "last_opened_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_workspace_collaborators_lookup": { - "name": "idx_workspace_collaborators_lookup", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - }, - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_collaborators_workspace": { - "name": "idx_workspace_collaborators_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_collaborators_last_opened_at": { - "name": "idx_workspace_collaborators_last_opened_at", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - }, - { - "expression": "last_opened_at", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_collaborators_workspace_id_fkey": { - "name": "workspace_collaborators_workspace_id_fkey", - "tableFrom": "workspace_collaborators", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_collaborators_invite_token_unique": { - "name": "workspace_collaborators_invite_token_unique", - "nullsNotDistinct": false, - "columns": [ - "invite_token" - ] - }, - "workspace_collaborators_workspace_user_unique": { - "name": "workspace_collaborators_workspace_user_unique", - "nullsNotDistinct": false, - "columns": [ - "workspace_id", - "user_id" - ] - } - }, - "policies": { - "Owners can manage collaborators": { - "name": "Owners can manage collaborators", - "as": "PERMISSIVE", - "for": "ALL", - "to": [ - "authenticated" - ], - "using": "(EXISTS ( SELECT 1\n FROM workspaces w\n WHERE ((w.id = workspace_collaborators.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text)))))" - }, - "Collaborators can view their access": { - "name": "Collaborators can view their access", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "authenticated" - ], - "using": "(user_id = (auth.jwt() ->> 'sub'::text))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_events": { - "name": "workspace_events", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "event_id": { - "name": "event_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "event_type": { - "name": "event_type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "payload": { - "name": "payload", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "timestamp": { - "name": "timestamp", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "version": { - "name": "version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "user_name": { - "name": "user_name", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "idx_workspace_events_event_id": { - "name": "idx_workspace_events_event_id", - "columns": [ - { - "expression": "event_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_events_timestamp": { - "name": "idx_workspace_events_timestamp", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "timestamp", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "int8_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_events_user_name": { - "name": "idx_workspace_events_user_name", - "columns": [ - { - "expression": "user_name", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_events_workspace": { - "name": "idx_workspace_events_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "version", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "int4_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_events_workspace_id_fkey": { - "name": "workspace_events_workspace_id_fkey", - "tableFrom": "workspace_events", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_events_event_id_key": { - "name": "workspace_events_event_id_key", - "nullsNotDistinct": false, - "columns": [ - "event_id" - ] - } - }, - "policies": { - "Users can insert workspace events they have write access to": { - "name": "Users can insert workspace events they have write access to", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "public" - ], - "withCheck": "(EXISTS ( SELECT 1\n FROM workspaces\n WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_events.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))" - }, - "Users can read workspace events they have access to": { - "name": "Users can read workspace events they have access to", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "public" - ], - "using": "(EXISTS ( SELECT 1\n FROM workspaces\n WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_events.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_invites": { - "name": "workspace_invites", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "inviter_id": { - "name": "inviter_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "permission_level": { - "name": "permission_level", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'editor'" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_workspace_invites_token": { - "name": "idx_workspace_invites_token", - "columns": [ - { - "expression": "token", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_invites_email": { - "name": "idx_workspace_invites_email", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_invites_workspace": { - "name": "idx_workspace_invites_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_invites_workspace_id_fkey": { - "name": "workspace_invites_workspace_id_fkey", - "tableFrom": "workspace_invites", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_invites_token_key": { - "name": "workspace_invites_token_key", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - } - }, - "policies": { - "Public can view invite by token": { - "name": "Public can view invite by token", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "public" - ], - "using": "true" - }, - "Users can insert invites for workspaces they own/edit": { - "name": "Users can insert invites for workspaces they own/edit", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "authenticated" - ], - "withCheck": "(EXISTS ( SELECT 1\n FROM workspaces w\n WHERE ((w.id = workspace_invites.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_invites.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_item_reads": { - "name": "workspace_item_reads", - "schema": "", - "columns": { - "thread_id": { - "name": "thread_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "item_id": { - "name": "item_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "last_modified": { - "name": "last_modified", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "read_at": { - "name": "read_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "idx_workspace_item_reads_thread_item": { - "name": "idx_workspace_item_reads_thread_item", - "columns": [ - { - "expression": "thread_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "item_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_item_reads_thread_id_chat_threads_id_fk": { - "name": "workspace_item_reads_thread_id_chat_threads_id_fk", - "tableFrom": "workspace_item_reads", - "tableTo": "chat_threads", - "columnsFrom": [ - "thread_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_item_reads_thread_item_key": { - "name": "workspace_item_reads_thread_item_key", - "nullsNotDistinct": false, - "columns": [ - "thread_id", - "item_id" - ] - } - }, - "policies": { - "Users can manage reads for threads in their workspaces": { - "name": "Users can manage reads for threads in their workspaces", - "as": "PERMISSIVE", - "for": "ALL", - "to": [ - "authenticated" - ], - "using": "(EXISTS ( SELECT 1 FROM chat_threads ct\n JOIN workspaces w ON w.id = ct.workspace_id\n WHERE ((ct.id = workspace_item_reads.thread_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text)))))\n OR (EXISTS ( SELECT 1 FROM chat_threads ct\n JOIN workspace_collaborators c ON c.workspace_id = ct.workspace_id\n WHERE ((ct.id = workspace_item_reads.thread_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_share_links": { - "name": "workspace_share_links", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "permission_level": { - "name": "permission_level", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'editor'" - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "idx_workspace_share_links_token": { - "name": "idx_workspace_share_links_token", - "columns": [ - { - "expression": "token", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_share_links_workspace": { - "name": "idx_workspace_share_links_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_share_links_workspace_id_fkey": { - "name": "workspace_share_links_workspace_id_fkey", - "tableFrom": "workspace_share_links", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_share_links_token_key": { - "name": "workspace_share_links_token_key", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - }, - "workspace_share_links_workspace_key": { - "name": "workspace_share_links_workspace_key", - "nullsNotDistinct": false, - "columns": [ - "workspace_id" - ] - } - }, - "policies": { - "Public can view share link by token": { - "name": "Public can view share link by token", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "public" - ], - "using": "true" - }, - "Owners and editors can manage share links": { - "name": "Owners and editors can manage share links", - "as": "PERMISSIVE", - "for": "ALL", - "to": [ - "authenticated" - ], - "using": "(EXISTS ( SELECT 1\n FROM workspaces w\n WHERE ((w.id = workspace_share_links.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1\n FROM workspace_collaborators c\n WHERE ((c.workspace_id = workspace_share_links.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspace_snapshots": { - "name": "workspace_snapshots", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workspace_id": { - "name": "workspace_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "snapshot_version": { - "name": "snapshot_version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "state": { - "name": "state", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "event_count": { - "name": "event_count", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": { - "idx_workspace_snapshots_version": { - "name": "idx_workspace_snapshots_version", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "snapshot_version", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "int4_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspace_snapshots_workspace": { - "name": "idx_workspace_snapshots_workspace", - "columns": [ - { - "expression": "workspace_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_snapshots_workspace_id_fkey": { - "name": "workspace_snapshots_workspace_id_fkey", - "tableFrom": "workspace_snapshots", - "tableTo": "workspaces", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_snapshots_workspace_id_snapshot_version_key": { - "name": "workspace_snapshots_workspace_id_snapshot_version_key", - "nullsNotDistinct": false, - "columns": [ - "workspace_id", - "snapshot_version" - ] - } - }, - "policies": { - "Service role can insert workspace snapshots": { - "name": "Service role can insert workspace snapshots", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "public" - ], - "withCheck": "true" - }, - "Users can read workspace snapshots they have access to": { - "name": "Users can read workspace snapshots they have access to", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "public" - ] - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.workspaces": { - "name": "workspaces", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "''" - }, - "template": { - "name": "template", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'blank'" - }, - "is_public": { - "name": "is_public", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "slug": { - "name": "slug", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "icon": { - "name": "icon", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sort_order": { - "name": "sort_order", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "color": { - "name": "color", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "last_opened_at": { - "name": "last_opened_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "idx_workspaces_created_at": { - "name": "idx_workspaces_created_at", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_slug": { - "name": "idx_workspaces_slug", - "columns": [ - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_user_id": { - "name": "idx_workspaces_user_id", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_user_slug": { - "name": "idx_workspaces_user_slug", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - }, - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_user_sort_order": { - "name": "idx_workspaces_user_sort_order", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - }, - { - "expression": "sort_order", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "int4_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "idx_workspaces_last_opened_at": { - "name": "idx_workspaces_last_opened_at", - "columns": [ - { - "expression": "last_opened_at", - "isExpression": false, - "asc": false, - "nulls": "first", - "opclass": "timestamptz_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": { - "Users can delete their own workspaces": { - "name": "Users can delete their own workspaces", - "as": "PERMISSIVE", - "for": "DELETE", - "to": [ - "authenticated" - ], - "using": "(( SELECT (auth.jwt() ->> 'sub'::text)) = user_id)" - }, - "Users can insert their own workspaces": { - "name": "Users can insert their own workspaces", - "as": "PERMISSIVE", - "for": "INSERT", - "to": [ - "authenticated" - ] - }, - "Users can update their own workspaces": { - "name": "Users can update their own workspaces", - "as": "PERMISSIVE", - "for": "UPDATE", - "to": [ - "authenticated" - ] - }, - "Users can view their own workspaces": { - "name": "Users can view their own workspaces", - "as": "PERMISSIVE", - "for": "SELECT", - "to": [ - "authenticated" - ] - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 8b5c51d8..2103412e 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -5,43 +5,8 @@ { "idx": 0, "version": "7", - "when": 1768802558046, - "tag": "0000_sad_wallflower", - "breakpoints": true - }, - { - "idx": 1, - "version": "7", - "when": 1771377459878, - "tag": "0002_add_workspace_share_links", - "breakpoints": true - }, - { - "idx": 2, - "version": "7", - "when": 1771631691687, - "tag": "0002_deep_shadowcat", - "breakpoints": true - }, - { - "idx": 3, - "version": "7", - "when": 1771686859689, - "tag": "0003_elite_harrier", - "breakpoints": true - }, - { - "idx": 4, - "version": "7", - "when": 1771800000000, - "tag": "0004_add_chat_threads_head_message_id", - "breakpoints": true - }, - { - "idx": 5, - "version": "7", - "when": 1771800001000, - "tag": "0005_add_chat_messages_thread_message_unique", + "when": 1775677707017, + "tag": "0000_baseline", "breakpoints": true } ] From 6e1c953d1be0228622609a2054ad05dcdce69fc8 Mon Sep 17 00:00:00 2001 From: Urjit Chakraborty <135136842+urjitc@users.noreply.github.com> Date: Wed, 8 Apr 2026 16:20:59 -0400 Subject: [PATCH 2/3] chore: Oxlint + tsgo typecheck and TypeScript 6 Replace ESLint with Oxlint; run tsgo for pnpm tc; keep tsc as tc:tsc. Bump typescript to 6.x and add @typescript/native-preview. Made-with: Cursor --- .oxlintrc.json | 43 +++++++++++++++++++++++++++++++++++++++++++ eslint.config.mjs | 20 -------------------- package.json | 14 +++++++------- 3 files changed, 50 insertions(+), 27 deletions(-) create mode 100644 .oxlintrc.json delete mode 100644 eslint.config.mjs diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 00000000..a46d5c32 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,43 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": [ + "eslint", + "typescript", + "unicorn", + "oxc", + "react", + "nextjs", + "import" + ], + "categories": { + "correctness": "error" + }, + "rules": { + "eslint/no-unused-vars": "warn", + "typescript/no-unused-vars": "warn", + "react-hooks/exhaustive-deps": "warn", + "nextjs/no-img-element": "warn", + "nextjs/no-html-link-for-pages": "warn", + "eslint/no-control-regex": "warn", + "eslint/no-useless-escape": "warn", + "eslint/no-cond-assign": "warn", + "unicorn/prefer-string-starts-ends-with": "warn", + "unicorn/no-new-array": "warn", + "unicorn/no-invalid-fetch-options": "warn" + }, + "env": { + "builtin": true + }, + "ignorePatterns": [ + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + "assistant-ui-main/**", + "node_modules/**", + ".pnpm-store/**", + "tmp/**", + "dist/**", + "coverage/**" + ] +} diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index 596f1005..00000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,20 +0,0 @@ -import { defineConfig, globalIgnores } from "eslint/config"; -import nextVitals from "eslint-config-next/core-web-vitals"; -import nextTs from "eslint-config-next/typescript"; -import prettier from "eslint-config-prettier/flat"; - -export default defineConfig([ - ...nextVitals, - ...nextTs, - prettier, - globalIgnores([ - ".next/**", - "out/**", - "build/**", - "next-env.d.ts", - "assistant-ui-main/**", - "node_modules/**", - ".pnpm-store/**", - "tmp/**", - ]), -]); diff --git a/package.json b/package.json index 2286881f..646cbed8 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,10 @@ "dev": "concurrently \"next dev\" \"npx @ai-sdk/devtools\"", "build": "next build", "start": "next start", - "lint": "eslint .", - "lint:fix": "eslint . --fix", - "tc": "tsc --noEmit", + "lint": "oxlint", + "lint:fix": "oxlint --fix", + "tc": "tsgo --noEmit", + "tc:tsc": "tsc --noEmit", "clean": "rm -rf .next out dist", "clean:all": "rm -rf .next out dist node_modules .pnpm-store && pnpm install", "analyze": "cross-env ANALYZE=true next build", @@ -167,18 +168,17 @@ "@types/react-color": "^3.0.13", "@types/react-dom": "19.2.3", "@types/react-speech-recognition": "^3.9.6", + "@typescript/native-preview": "7.0.0-dev.20260408.1", "babel-plugin-react-compiler": "^1.0.0", "concurrently": "^9.2.1", "cross-env": "^10.1.0", - "eslint": "^9.39.4", - "eslint-config-next": "16.2.2", - "eslint-config-prettier": "^10.1.8", "knip": "^6.0.6", + "oxlint": "^1.59.0", "prettier": "^3.8.1", "sass": "^1.98.0", "tailwindcss": "^4.2.1", "tw-animate-css": "^1.4.0", - "typescript": "^5.9.3", + "typescript": "^6.0.2", "vitest": "^4.1.2" } } From fb9822d59ef494690c5db76479606552892d58d1 Mon Sep 17 00:00:00 2001 From: Urjit Chakraborty <135136842+urjitc@users.noreply.github.com> Date: Wed, 8 Apr 2026 16:37:48 -0400 Subject: [PATCH 3/3] fix(db): align squashed baseline with live schema Restore the realtime objects new databases still need and remove the dead workspace item reads table so the baseline matches how the app and prod actually behave. Made-with: Cursor --- drizzle/0000_baseline.sql | 86 +++++++++++++++++++++-------- drizzle/meta/0000_snapshot.json | 95 --------------------------------- drizzle/meta/_journal.json | 2 +- src/lib/db/relations.ts | 9 ---- src/lib/db/schema.ts | 33 ------------ 5 files changed, 65 insertions(+), 160 deletions(-) diff --git a/drizzle/0000_baseline.sql b/drizzle/0000_baseline.sql index 607a20d1..7b50b0d0 100644 --- a/drizzle/0000_baseline.sql +++ b/drizzle/0000_baseline.sql @@ -124,15 +124,6 @@ CREATE TABLE "workspace_invites" ( ); --> statement-breakpoint ALTER TABLE "workspace_invites" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint -CREATE TABLE "workspace_item_reads" ( - "thread_id" uuid NOT NULL, - "item_id" text NOT NULL, - "last_modified" bigint NOT NULL, - "read_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "workspace_item_reads_thread_item_key" UNIQUE("thread_id","item_id") -); ---> statement-breakpoint -ALTER TABLE "workspace_item_reads" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint CREATE TABLE "workspace_share_links" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "workspace_id" uuid NOT NULL, @@ -181,7 +172,6 @@ ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY (" ALTER TABLE "workspace_collaborators" ADD CONSTRAINT "workspace_collaborators_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "workspace_events" ADD CONSTRAINT "workspace_events_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "workspace_invites" ADD CONSTRAINT "workspace_invites_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "workspace_item_reads" ADD CONSTRAINT "workspace_item_reads_thread_id_chat_threads_id_fk" FOREIGN KEY ("thread_id") REFERENCES "public"."chat_threads"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "workspace_share_links" ADD CONSTRAINT "workspace_share_links_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "workspace_snapshots" ADD CONSTRAINT "workspace_snapshots_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint CREATE INDEX "idx_account_user_id" ON "account" USING btree ("user_id" text_ops);--> statement-breakpoint @@ -189,7 +179,7 @@ CREATE INDEX "idx_chat_messages_thread" ON "chat_messages" USING btree ("thread_ CREATE INDEX "idx_chat_messages_thread_created" ON "chat_messages" USING btree ("thread_id" uuid_ops,"created_at" timestamptz_ops);--> statement-breakpoint CREATE INDEX "idx_chat_threads_workspace" ON "chat_threads" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint CREATE INDEX "idx_chat_threads_user" ON "chat_threads" USING btree ("user_id" text_ops);--> statement-breakpoint -CREATE INDEX "idx_chat_threads_last_message" ON "chat_threads" USING btree ("workspace_id" uuid_ops,"last_message_at" timestamptz_ops);--> statement-breakpoint +CREATE INDEX "idx_chat_threads_last_message" ON "chat_threads" USING btree ("workspace_id" uuid_ops,"last_message_at" timestamptz_ops DESC NULLS FIRST);--> statement-breakpoint CREATE INDEX "idx_session_user_id" ON "session" USING btree ("user_id" text_ops);--> statement-breakpoint CREATE INDEX "idx_session_token" ON "session" USING btree ("token" text_ops);--> statement-breakpoint CREATE INDEX "idx_user_email" ON "user" USING btree ("email" text_ops);--> statement-breakpoint @@ -197,7 +187,7 @@ CREATE INDEX "idx_user_profiles_user_id" ON "user_profiles" USING btree ("user_i CREATE INDEX "idx_verification_identifier" ON "verification" USING btree ("identifier" text_ops);--> statement-breakpoint CREATE INDEX "idx_workspace_collaborators_lookup" ON "workspace_collaborators" USING btree ("user_id" text_ops,"workspace_id" uuid_ops);--> statement-breakpoint CREATE INDEX "idx_workspace_collaborators_workspace" ON "workspace_collaborators" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint -CREATE INDEX "idx_workspace_collaborators_last_opened_at" ON "workspace_collaborators" USING btree ("user_id" text_ops,"last_opened_at" timestamptz_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_collaborators_last_opened_at" ON "workspace_collaborators" USING btree ("user_id" text_ops,"last_opened_at" timestamptz_ops DESC NULLS FIRST);--> statement-breakpoint CREATE INDEX "idx_workspace_events_event_id" ON "workspace_events" USING btree ("event_id" text_ops);--> statement-breakpoint CREATE INDEX "idx_workspace_events_timestamp" ON "workspace_events" USING btree ("workspace_id" uuid_ops,"timestamp" int8_ops);--> statement-breakpoint CREATE INDEX "idx_workspace_events_user_name" ON "workspace_events" USING btree ("user_name" text_ops);--> statement-breakpoint @@ -205,17 +195,16 @@ CREATE INDEX "idx_workspace_events_workspace" ON "workspace_events" USING btree CREATE INDEX "idx_workspace_invites_token" ON "workspace_invites" USING btree ("token" text_ops);--> statement-breakpoint CREATE INDEX "idx_workspace_invites_email" ON "workspace_invites" USING btree ("email" text_ops);--> statement-breakpoint CREATE INDEX "idx_workspace_invites_workspace" ON "workspace_invites" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint -CREATE INDEX "idx_workspace_item_reads_thread_item" ON "workspace_item_reads" USING btree ("thread_id" uuid_ops,"item_id" text_ops);--> statement-breakpoint CREATE INDEX "idx_workspace_share_links_token" ON "workspace_share_links" USING btree ("token" text_ops);--> statement-breakpoint CREATE INDEX "idx_workspace_share_links_workspace" ON "workspace_share_links" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint -CREATE INDEX "idx_workspace_snapshots_version" ON "workspace_snapshots" USING btree ("workspace_id" uuid_ops,"snapshot_version" int4_ops);--> statement-breakpoint +CREATE INDEX "idx_workspace_snapshots_version" ON "workspace_snapshots" USING btree ("workspace_id" uuid_ops,"snapshot_version" int4_ops DESC NULLS FIRST);--> statement-breakpoint CREATE INDEX "idx_workspace_snapshots_workspace" ON "workspace_snapshots" USING btree ("workspace_id" uuid_ops);--> statement-breakpoint -CREATE INDEX "idx_workspaces_created_at" ON "workspaces" USING btree ("created_at" timestamptz_ops);--> statement-breakpoint +CREATE INDEX "idx_workspaces_created_at" ON "workspaces" USING btree ("created_at" timestamptz_ops DESC NULLS FIRST);--> statement-breakpoint CREATE INDEX "idx_workspaces_slug" ON "workspaces" USING btree ("slug" text_ops);--> statement-breakpoint CREATE INDEX "idx_workspaces_user_id" ON "workspaces" USING btree ("user_id" text_ops);--> statement-breakpoint CREATE UNIQUE INDEX "idx_workspaces_user_slug" ON "workspaces" USING btree ("user_id" text_ops,"slug" text_ops);--> statement-breakpoint CREATE INDEX "idx_workspaces_user_sort_order" ON "workspaces" USING btree ("user_id" text_ops,"sort_order" int4_ops);--> statement-breakpoint -CREATE INDEX "idx_workspaces_last_opened_at" ON "workspaces" USING btree ("last_opened_at" timestamptz_ops);--> statement-breakpoint +CREATE INDEX "idx_workspaces_last_opened_at" ON "workspaces" USING btree ("last_opened_at" timestamptz_ops DESC NULLS FIRST);--> statement-breakpoint CREATE POLICY "chat_threads_user_scoped" ON "chat_threads" AS PERMISSIVE FOR ALL TO "authenticated" USING (((chat_threads.user_id = (auth.jwt() ->> 'sub'::text)) AND ((EXISTS ( SELECT 1 FROM workspaces w WHERE ((w.id = chat_threads.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) @@ -238,18 +227,71 @@ CREATE POLICY "Users can read workspace events they have access to" ON "workspac WHERE ((workspaces.id = workspace_events.workspace_id) AND (workspaces.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1 FROM workspace_collaborators c WHERE ((c.workspace_id = workspace_events.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text))))));--> statement-breakpoint +-- Preserve realtime collaboration objects that were previously created outside the journal +CREATE OR REPLACE FUNCTION workspace_events_broadcast_trigger() +RETURNS TRIGGER +LANGUAGE plpgsql +SECURITY DEFINER +AS $$ +BEGIN + PERFORM realtime.broadcast_changes( + 'workspace:' || NEW.workspace_id::text || ':events', + TG_OP, + TG_OP, + TG_TABLE_NAME, + TG_TABLE_SCHEMA, + NEW, + OLD + ); + RETURN NEW; +END; +$$;--> statement-breakpoint +CREATE TRIGGER workspace_events_realtime_broadcast + AFTER INSERT ON workspace_events + FOR EACH ROW EXECUTE FUNCTION workspace_events_broadcast_trigger();--> statement-breakpoint +CREATE POLICY "workspace_access_can_read" ON realtime.messages +FOR SELECT TO authenticated +USING ( + topic LIKE 'workspace:%:events' + AND ( + EXISTS ( + SELECT 1 FROM public.workspaces w + WHERE w.id = (SPLIT_PART(topic, ':', 2))::uuid + AND w.user_id = (auth.jwt() ->> 'sub'::text) + ) + OR + EXISTS ( + SELECT 1 FROM public.workspace_collaborators c + WHERE c.workspace_id = (SPLIT_PART(topic, ':', 2))::uuid + AND c.user_id = (auth.jwt() ->> 'sub'::text) + ) + ) +);--> statement-breakpoint +CREATE POLICY "workspace_access_can_write" ON realtime.messages +FOR INSERT TO authenticated +WITH CHECK ( + topic LIKE 'workspace:%:events' + AND ( + EXISTS ( + SELECT 1 FROM public.workspaces w + WHERE w.id = (SPLIT_PART(topic, ':', 2))::uuid + AND w.user_id = (auth.jwt() ->> 'sub'::text) + ) + OR + EXISTS ( + SELECT 1 FROM public.workspace_collaborators c + WHERE c.workspace_id = (SPLIT_PART(topic, ':', 2))::uuid + AND c.user_id = (auth.jwt() ->> 'sub'::text) + AND c.permission_level = 'editor' + ) + ) +);--> statement-breakpoint CREATE POLICY "Public can view invite by token" ON "workspace_invites" AS PERMISSIVE FOR SELECT TO public USING (true);--> statement-breakpoint CREATE POLICY "Users can insert invites for workspaces they own/edit" ON "workspace_invites" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 FROM workspaces w WHERE ((w.id = workspace_invites.workspace_id) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) OR (EXISTS ( SELECT 1 FROM workspace_collaborators c WHERE ((c.workspace_id = workspace_invites.workspace_id) AND (c.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.permission_level = 'editor'::text)))));--> statement-breakpoint -CREATE POLICY "workspace_item_reads_user_scoped" ON "workspace_item_reads" AS PERMISSIVE FOR ALL TO "authenticated" USING ((EXISTS ( SELECT 1 FROM chat_threads ct - JOIN workspaces w ON w.id = ct.workspace_id - WHERE ((ct.id = workspace_item_reads.thread_id) AND (ct.user_id = (auth.jwt() ->> 'sub'::text)) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) - OR (EXISTS ( SELECT 1 FROM chat_threads ct - JOIN workspace_collaborators c ON c.workspace_id = ct.workspace_id - WHERE ((ct.id = workspace_item_reads.thread_id) AND (ct.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.user_id = (auth.jwt() ->> 'sub'::text))))));--> statement-breakpoint CREATE POLICY "Public can view share link by token" ON "workspace_share_links" AS PERMISSIVE FOR SELECT TO public USING (true);--> statement-breakpoint CREATE POLICY "Owners and editors can manage share links" ON "workspace_share_links" AS PERMISSIVE FOR ALL TO "authenticated" USING ((EXISTS ( SELECT 1 FROM workspaces w diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json index bc87620c..1a8f1b4d 100644 --- a/drizzle/meta/0000_snapshot.json +++ b/drizzle/meta/0000_snapshot.json @@ -1316,101 +1316,6 @@ "checkConstraints": {}, "isRLSEnabled": false }, - "public.workspace_item_reads": { - "name": "workspace_item_reads", - "schema": "", - "columns": { - "thread_id": { - "name": "thread_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "item_id": { - "name": "item_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "last_modified": { - "name": "last_modified", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "read_at": { - "name": "read_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "idx_workspace_item_reads_thread_item": { - "name": "idx_workspace_item_reads_thread_item", - "columns": [ - { - "expression": "thread_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "uuid_ops" - }, - { - "expression": "item_id", - "isExpression": false, - "asc": true, - "nulls": "last", - "opclass": "text_ops" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "workspace_item_reads_thread_id_chat_threads_id_fk": { - "name": "workspace_item_reads_thread_id_chat_threads_id_fk", - "tableFrom": "workspace_item_reads", - "tableTo": "chat_threads", - "columnsFrom": [ - "thread_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "workspace_item_reads_thread_item_key": { - "name": "workspace_item_reads_thread_item_key", - "nullsNotDistinct": false, - "columns": [ - "thread_id", - "item_id" - ] - } - }, - "policies": { - "workspace_item_reads_user_scoped": { - "name": "workspace_item_reads_user_scoped", - "as": "PERMISSIVE", - "for": "ALL", - "to": [ - "authenticated" - ], - "using": "(EXISTS ( SELECT 1 FROM chat_threads ct\n JOIN workspaces w ON w.id = ct.workspace_id\n WHERE ((ct.id = workspace_item_reads.thread_id) AND (ct.user_id = (auth.jwt() ->> 'sub'::text)) AND (w.user_id = (auth.jwt() ->> 'sub'::text)))))\n OR (EXISTS ( SELECT 1 FROM chat_threads ct\n JOIN workspace_collaborators c ON c.workspace_id = ct.workspace_id\n WHERE ((ct.id = workspace_item_reads.thread_id) AND (ct.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))" - } - }, - "checkConstraints": {}, - "isRLSEnabled": false - }, "public.workspace_share_links": { "name": "workspace_share_links", "schema": "", diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 2103412e..83f4aecc 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -5,7 +5,7 @@ { "idx": 0, "version": "7", - "when": 1775677707017, + "when": 1768802558046, "tag": "0000_baseline", "breakpoints": true } diff --git a/src/lib/db/relations.ts b/src/lib/db/relations.ts index 1bf2a106..b442377d 100644 --- a/src/lib/db/relations.ts +++ b/src/lib/db/relations.ts @@ -5,7 +5,6 @@ import { workspaceEvents, chatThreads, chatMessages, - workspaceItemReads, } from "./schema"; // workspace_shares removed - sharing is now fork-based (users import copies) @@ -35,14 +34,6 @@ export const chatThreadsRelations = relations(chatThreads, ({ one, many }) => ({ references: [workspaces.id], }), messages: many(chatMessages), - workspaceItemReads: many(workspaceItemReads), -})); - -export const workspaceItemReadsRelations = relations(workspaceItemReads, ({ one }) => ({ - thread: one(chatThreads, { - fields: [workspaceItemReads.threadId], - references: [chatThreads.id], - }), })); export const chatMessagesRelations = relations(chatMessages, ({ one }) => ({ diff --git a/src/lib/db/schema.ts b/src/lib/db/schema.ts index 37417bc6..0d01c8cf 100644 --- a/src/lib/db/schema.ts +++ b/src/lib/db/schema.ts @@ -343,36 +343,3 @@ export const chatMessages = pgTable("chat_messages", { ), ]); -// Read-before-write tracking for workspace items (FileTime pattern) -export const workspaceItemReads = pgTable( - "workspace_item_reads", - { - threadId: uuid("thread_id") - .notNull() - .references(() => chatThreads.id, { onDelete: "cascade" }), - itemId: text("item_id").notNull(), - lastModified: bigint("last_modified", { mode: "number" }).notNull(), - readAt: timestamp("read_at", { withTimezone: true, mode: "string" }) - .defaultNow() - .notNull(), - }, - (table) => [ - unique("workspace_item_reads_thread_item_key").on(table.threadId, table.itemId), - index("idx_workspace_item_reads_thread_item").using( - "btree", - table.threadId.asc().nullsLast().op("uuid_ops"), - table.itemId.asc().nullsLast().op("text_ops") - ), - pgPolicy("workspace_item_reads_user_scoped", { - as: "permissive", - for: "all", - to: ["authenticated"], - using: sql`(EXISTS ( SELECT 1 FROM chat_threads ct - JOIN workspaces w ON w.id = ct.workspace_id - WHERE ((ct.id = workspace_item_reads.thread_id) AND (ct.user_id = (auth.jwt() ->> 'sub'::text)) AND (w.user_id = (auth.jwt() ->> 'sub'::text))))) - OR (EXISTS ( SELECT 1 FROM chat_threads ct - JOIN workspace_collaborators c ON c.workspace_id = ct.workspace_id - WHERE ((ct.id = workspace_item_reads.thread_id) AND (ct.user_id = (auth.jwt() ->> 'sub'::text)) AND (c.user_id = (auth.jwt() ->> 'sub'::text)))))`, - }), - ] -);