diff --git a/internal-packages/dashboard-agent-db/drizzle.config.ts b/internal-packages/dashboard-agent-db/drizzle.config.ts index 6c057cfdad..ddaddb9fd8 100644 --- a/internal-packages/dashboard-agent-db/drizzle.config.ts +++ b/internal-packages/dashboard-agent-db/drizzle.config.ts @@ -13,5 +13,9 @@ export default defineConfig({ dialect: "postgresql", // Only manage our schema — never introspect or diff Prisma's `public` schema. schemaFilter: ["trigger_dashboard_agent"], + // Own journal table so dev (`drizzle-kit migrate`) and deploy (migrate.mjs) + // share one history and we don't cross-poison the default + // drizzle.__drizzle_migrations when the DB is shared. See migrate.mjs. + migrations: { table: "__dashboard_agent_migrations", schema: "drizzle" }, dbCredentials: { url }, }); diff --git a/internal-packages/dashboard-agent-db/drizzle/0000_magenta_lilandra.sql b/internal-packages/dashboard-agent-db/drizzle/0000_magenta_lilandra.sql index 2429b1f29d..0eb2c72b98 100644 --- a/internal-packages/dashboard-agent-db/drizzle/0000_magenta_lilandra.sql +++ b/internal-packages/dashboard-agent-db/drizzle/0000_magenta_lilandra.sql @@ -1,6 +1,6 @@ -CREATE SCHEMA "trigger_dashboard_agent"; +CREATE SCHEMA IF NOT EXISTS "trigger_dashboard_agent"; --> statement-breakpoint -CREATE TABLE "trigger_dashboard_agent"."chat_sessions" ( +CREATE TABLE IF NOT EXISTS "trigger_dashboard_agent"."chat_sessions" ( "chat_id" text PRIMARY KEY NOT NULL, "public_access_token" text NOT NULL, "last_event_id" text, @@ -8,7 +8,7 @@ CREATE TABLE "trigger_dashboard_agent"."chat_sessions" ( "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); --> statement-breakpoint -CREATE TABLE "trigger_dashboard_agent"."chats" ( +CREATE TABLE IF NOT EXISTS "trigger_dashboard_agent"."chats" ( "id" text PRIMARY KEY NOT NULL, "organization_id" text NOT NULL, "user_id" text NOT NULL, @@ -22,4 +22,4 @@ CREATE TABLE "trigger_dashboard_agent"."chats" ( "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); --> statement-breakpoint -CREATE INDEX "chats_org_user_last_msg_idx" ON "trigger_dashboard_agent"."chats" USING btree ("organization_id","user_id","last_message_at" DESC NULLS LAST) WHERE "trigger_dashboard_agent"."chats"."deleted_at" is null; \ No newline at end of file +CREATE INDEX IF NOT EXISTS "chats_org_user_last_msg_idx" ON "trigger_dashboard_agent"."chats" USING btree ("organization_id","user_id","last_message_at" DESC NULLS LAST) WHERE "trigger_dashboard_agent"."chats"."deleted_at" is null; \ No newline at end of file diff --git a/internal-packages/dashboard-agent-db/drizzle/0001_slimy_living_tribunal.sql b/internal-packages/dashboard-agent-db/drizzle/0001_slimy_living_tribunal.sql index fe696d8138..4c9afe5f6c 100644 --- a/internal-packages/dashboard-agent-db/drizzle/0001_slimy_living_tribunal.sql +++ b/internal-packages/dashboard-agent-db/drizzle/0001_slimy_living_tribunal.sql @@ -1,4 +1,4 @@ -CREATE TABLE "trigger_dashboard_agent"."chat_turn_evals" ( +CREATE TABLE IF NOT EXISTS "trigger_dashboard_agent"."chat_turn_evals" ( "chat_id" text NOT NULL, "turn" integer NOT NULL, "organization_id" text NOT NULL, @@ -34,5 +34,5 @@ CREATE TABLE "trigger_dashboard_agent"."chat_turn_evals" ( CONSTRAINT "chat_turn_evals_chat_id_turn_pk" PRIMARY KEY("chat_id","turn") ); --> statement-breakpoint -CREATE INDEX "chat_turn_evals_org_created_idx" ON "trigger_dashboard_agent"."chat_turn_evals" USING btree ("organization_id","created_at" DESC NULLS LAST);--> statement-breakpoint -CREATE INDEX "chat_turn_evals_org_opps_idx" ON "trigger_dashboard_agent"."chat_turn_evals" USING btree ("organization_id","created_at" DESC NULLS LAST) WHERE "trigger_dashboard_agent"."chat_turn_evals"."capability_gap" or "trigger_dashboard_agent"."chat_turn_evals"."docs_gap" or "trigger_dashboard_agent"."chat_turn_evals"."support_opportunity" or "trigger_dashboard_agent"."chat_turn_evals"."feature_request"; \ No newline at end of file +CREATE INDEX IF NOT EXISTS "chat_turn_evals_org_created_idx" ON "trigger_dashboard_agent"."chat_turn_evals" USING btree ("organization_id","created_at" DESC NULLS LAST);--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "chat_turn_evals_org_opps_idx" ON "trigger_dashboard_agent"."chat_turn_evals" USING btree ("organization_id","created_at" DESC NULLS LAST) WHERE "trigger_dashboard_agent"."chat_turn_evals"."capability_gap" or "trigger_dashboard_agent"."chat_turn_evals"."docs_gap" or "trigger_dashboard_agent"."chat_turn_evals"."support_opportunity" or "trigger_dashboard_agent"."chat_turn_evals"."feature_request"; \ No newline at end of file diff --git a/internal-packages/dashboard-agent-db/migrate.mjs b/internal-packages/dashboard-agent-db/migrate.mjs index 48699b23cc..d840707ddd 100644 --- a/internal-packages/dashboard-agent-db/migrate.mjs +++ b/internal-packages/dashboard-agent-db/migrate.mjs @@ -44,13 +44,23 @@ const sql = postgres(normalizeConnectionString(connectionString), { }); try { - // Journal lives in Drizzle's default `drizzle` schema (matching `drizzle-kit - // migrate`, so dev and deploy track migrations the same way). It must not be - // our data schema: the first migration runs `CREATE SCHEMA - // "trigger_dashboard_agent"`, which would collide with the journal schema the - // migrator pre-creates. The dashboard agent is the only Drizzle user of its - // database, so the `drizzle` schema stays exclusively ours. - await migrate(drizzle(sql), { migrationsFolder }); + // Track our history in a DEDICATED journal table. Drizzle's migrator reads the + // latest row from . by created_at and skips any journal entry + // dated at or before it. The default `drizzle.__drizzle_migrations` is shared + // by every Drizzle app, so when this DB is shared (OSS single-database fallback + // and the enterprise-image E2E gate) billing's journal rows poison ours: a + // billing row dated between our 0000 and 0001 makes the migrator skip 0000 (the + // CREATE SCHEMA) and run 0001 against a schema that never got created. An own + // table keeps our history independent (enterprise/db does the same with + // __enterprise_migrations; billing keeps the default). + // + // The table stays in the `drizzle` schema, not our data schema, so 0000's + // `CREATE SCHEMA "trigger_dashboard_agent"` doesn't collide with the schema the + // migrator pre-creates for its journal. + await migrate(drizzle(sql), { + migrationsFolder, + migrationsTable: "__dashboard_agent_migrations", + }); console.log("[dashboard-agent-db] migrations complete"); } finally { await sql.end();