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/drizzle/0000_baseline.sql b/drizzle/0000_baseline.sql new file mode 100644 index 00000000..7b50b0d0 --- /dev/null +++ b/drizzle/0000_baseline.sql @@ -0,0 +1,306 @@ +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_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_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 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 +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 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 +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_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 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 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 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))))) + 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 +-- 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 "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..1a8f1b4d 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,7 +1155,295 @@ "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": {}, 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..83f4aecc 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -6,42 +6,7 @@ "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", + "tag": "0000_baseline", "breakpoints": true } ] 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" } } 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)))))`, - }), - ] -);