@agent-team-foundation/first-tree-hub 0.14.5 → 0.14.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bootstrap-BmeaRhRp.mjs +3 -0
- package/dist/{bootstrap-CQQGgIx1.mjs → bootstrap-CmkHQsnS.mjs} +24 -16
- package/dist/cli/index.mjs +6 -94
- package/dist/{dist-CrdnqZjv.mjs → feishu-BE7QRxnE.mjs} +170 -379
- package/dist/feishu-De9_bA91.mjs +3 -0
- package/dist/index.mjs +5 -12
- package/dist/saas-connect-CNY9Ve5V.mjs +13748 -0
- package/package.json +4 -12
- package/dist/chunk-BSw8zbkd.mjs +0 -37
- package/dist/client-BPRIfrOT-CoV_2o7e.mjs +0 -4230
- package/dist/client-CEdYVnoj-BGiGcJbH.mjs +0 -7
- package/dist/dist-LgF7LHpE.mjs +0 -430
- package/dist/drizzle/0000_shocking_darkhawk.sql +0 -92
- package/dist/drizzle/0001_v2_schema_updates.sql +0 -26
- package/dist/drizzle/0002_adapter_tables.sql +0 -64
- package/dist/drizzle/0003_feishu_adapter.sql +0 -21
- package/dist/drizzle/0004_adapter_refactor.sql +0 -13
- package/dist/drizzle/0005_delegate_mention.sql +0 -1
- package/dist/drizzle/0006_agent_tree_path.sql +0 -1
- package/dist/drizzle/0007_decouple_context_tree.sql +0 -2
- package/dist/drizzle/0008_uuid_identity.sql +0 -12
- package/dist/drizzle/0009_agent_runtime_m1.sql +0 -31
- package/dist/drizzle/0010_cloud_multi_tenancy.sql +0 -34
- package/dist/drizzle/0011_org_uuid_pk.sql +0 -22
- package/dist/drizzle/0012_session_level_state.sql +0 -19
- package/dist/drizzle/0013_hub_tasks.sql +0 -38
- package/dist/drizzle/0014_drop_task_fks.sql +0 -9
- package/dist/drizzle/0015_member_system.sql +0 -34
- package/dist/drizzle/0016_strange_havok.sql +0 -25
- package/dist/drizzle/0017_session_outputs_unique.sql +0 -1
- package/dist/drizzle/0018_agent_visibility.sql +0 -13
- package/dist/drizzle/0019_agent_configs.sql +0 -30
- package/dist/drizzle/0020_unified_user_token.sql +0 -154
- package/dist/drizzle/0021_drop_agents_profile.sql +0 -10
- package/dist/drizzle/0022_session_events.sql +0 -32
- package/dist/drizzle/0023_clients_org_scoping.sql +0 -40
- package/dist/drizzle/0024_display_name_not_null.sql +0 -31
- package/dist/drizzle/0025_inbox_silent_entries.sql +0 -53
- package/dist/drizzle/0026_saas_onboarding.sql +0 -153
- package/dist/drizzle/0027_runtime_provider.sql +0 -10
- package/dist/drizzle/0028_auth_identity_user_github_unique.sql +0 -12
- package/dist/drizzle/0029_direct_agent_only_mention_only.sql +0 -28
- package/dist/drizzle/0030_chat_first_workspace.sql +0 -129
- package/dist/drizzle/0031_drop_system_configs.sql +0 -11
- package/dist/drizzle/0032_organization_settings.sql +0 -36
- package/dist/drizzle/0033_onboarding_dismissed_at.sql +0 -13
- package/dist/drizzle/0034_pending_questions.sql +0 -34
- package/dist/drizzle/0035_drop_hub_tasks.sql +0 -7
- package/dist/drizzle/0036_github_entity_chat_mappings.sql +0 -47
- package/dist/drizzle/0037_github_app_installations.sql +0 -52
- package/dist/drizzle/0038_chat_membership_user_state.sql +0 -223
- package/dist/drizzle/0039_drop_chat_participants_subscriptions.sql +0 -26
- package/dist/drizzle/0040_chat_user_state_engagement.sql +0 -24
- package/dist/drizzle/0041_notifications_dedup_key.sql +0 -29
- package/dist/drizzle/0042_notifications_drop_legacy_types.sql +0 -36
- package/dist/drizzle/0043_onboarding_completed_at.sql +0 -32
- package/dist/drizzle/0044_agent_avatar_color.sql +0 -11
- package/dist/drizzle/0045_agent_avatar_image.sql +0 -17
- package/dist/drizzle/meta/0000_snapshot.json +0 -687
- package/dist/drizzle/meta/0001_snapshot.json +0 -687
- package/dist/drizzle/meta/0012_snapshot.json +0 -1451
- package/dist/drizzle/meta/0013_snapshot.json +0 -1771
- package/dist/drizzle/meta/0014_snapshot.json +0 -1717
- package/dist/drizzle/meta/0016_snapshot.json +0 -1917
- package/dist/drizzle/meta/0018_snapshot.json +0 -1938
- package/dist/drizzle/meta/_journal.json +0 -328
- package/dist/esm-iadMkGbV.mjs +0 -1516
- package/dist/execAsync-DUfRkc4a.mjs +0 -10
- package/dist/execAsync-YbEZSOYd.mjs +0 -10
- package/dist/feishu-DNoBroKK.mjs +0 -53
- package/dist/from-DQ7eNRwu.mjs +0 -3840
- package/dist/getMachineId-bsd-BmasEOJr.mjs +0 -27
- package/dist/getMachineId-bsd-Dh3h0DDE.mjs +0 -27
- package/dist/getMachineId-darwin-CuhM3hfZ.mjs +0 -24
- package/dist/getMachineId-darwin-D9wR0SLj.mjs +0 -24
- package/dist/getMachineId-linux-CYfb0oxZ.mjs +0 -20
- package/dist/getMachineId-linux-D8ZaSjAC.mjs +0 -20
- package/dist/getMachineId-unsupported-Cu3iisaD.mjs +0 -15
- package/dist/getMachineId-unsupported-DZqI4ZT5.mjs +0 -15
- package/dist/getMachineId-win-8ZJbtrdf.mjs +0 -26
- package/dist/getMachineId-win-DT-hqwVp.mjs +0 -26
- package/dist/invitation-C9m2gQx4-C_4f5VTs.mjs +0 -4
- package/dist/invitation-D_ENPHyj-5ETiae5r.mjs +0 -167
- package/dist/logger-core-BTmvdflj-DjW8FM4T.mjs +0 -146
- package/dist/multipart-parser-QRu3OKK4.mjs +0 -294
- package/dist/observability-BAScT_5S-BcW9HgkG.mjs +0 -96129
- package/dist/observability-eLA9iNK_.mjs +0 -5
- package/dist/saas-connect-CYp9TOB5.mjs +0 -21918
- package/dist/src-DFlbpJfU.mjs +0 -1176
- package/dist/src-DNBS5Yjj.mjs +0 -735
- package/dist/uuid-DbS_4vFh-iFghv4zA.mjs +0 -129
- package/dist/web/assets/index-9wK0udbH.js +0 -416
- package/dist/web/assets/index-C7x7O7dG.js +0 -11
- package/dist/web/assets/index-DE7Q3QWE.css +0 -1
- package/dist/web/favicon.svg +0 -9
- package/dist/web/fonts/inter-latin-ext.woff2 +0 -0
- package/dist/web/fonts/inter-latin.woff2 +0 -0
- package/dist/web/fonts/jetbrains-mono-latin-ext.woff2 +0 -0
- package/dist/web/fonts/jetbrains-mono-latin.woff2 +0 -0
- package/dist/web/index.html +0 -39
- /package/dist/{cli-fetch--tiwKm5S.mjs → cli-fetch-BGVItZxo.mjs} +0 -0
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
-- Agent identity refactoring: id → uuid (PK) + name (human-readable, per-org unique)
|
|
2
|
-
-- Run BEFORE the data migration script (scripts/migrate-uuid.ts).
|
|
3
|
-
|
|
4
|
-
-- 1. Add name column
|
|
5
|
-
ALTER TABLE "agents" ADD COLUMN "name" text;
|
|
6
|
-
|
|
7
|
-
-- 2. Rename id → uuid (PG auto-updates FK constraints referencing this column)
|
|
8
|
-
ALTER TABLE "agents" RENAME COLUMN "id" TO "uuid";
|
|
9
|
-
|
|
10
|
-
-- 3. Add composite unique constraint (org + name)
|
|
11
|
-
-- NULLs are distinct in PG unique constraints, so deleted agents (name=NULL) don't conflict
|
|
12
|
-
ALTER TABLE "agents" ADD CONSTRAINT "uq_agents_org_name" UNIQUE("organization_id", "name");
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
-- M1: Agent Runtime — Process Awareness
|
|
2
|
-
-- New clients table + agent_presence runtime columns
|
|
3
|
-
|
|
4
|
-
CREATE TABLE IF NOT EXISTS "clients" (
|
|
5
|
-
"id" text PRIMARY KEY NOT NULL,
|
|
6
|
-
"status" text DEFAULT 'disconnected' NOT NULL,
|
|
7
|
-
"sdk_version" text,
|
|
8
|
-
"hostname" text,
|
|
9
|
-
"os" text,
|
|
10
|
-
"instance_id" text,
|
|
11
|
-
"connected_at" timestamp with time zone,
|
|
12
|
-
"last_seen_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
13
|
-
"metadata" jsonb
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
ALTER TABLE "agent_presence" ADD COLUMN "client_id" text;
|
|
17
|
-
ALTER TABLE "agent_presence" ADD COLUMN "runtime_type" text;
|
|
18
|
-
ALTER TABLE "agent_presence" ADD COLUMN "runtime_version" text;
|
|
19
|
-
ALTER TABLE "agent_presence" ADD COLUMN "runtime_state" text;
|
|
20
|
-
ALTER TABLE "agent_presence" ADD COLUMN "runtime_description" text;
|
|
21
|
-
ALTER TABLE "agent_presence" ADD COLUMN "active_sessions" integer;
|
|
22
|
-
ALTER TABLE "agent_presence" ADD COLUMN "total_sessions" integer;
|
|
23
|
-
ALTER TABLE "agent_presence" ADD COLUMN "error_message" text;
|
|
24
|
-
ALTER TABLE "agent_presence" ADD COLUMN "task_ref" text;
|
|
25
|
-
ALTER TABLE "agent_presence" ADD COLUMN "runtime_updated_at" timestamp with time zone;
|
|
26
|
-
|
|
27
|
-
DO $$ BEGIN
|
|
28
|
-
ALTER TABLE "agent_presence" ADD CONSTRAINT "agent_presence_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE set null ON UPDATE no action;
|
|
29
|
-
EXCEPTION
|
|
30
|
-
WHEN duplicate_object THEN null;
|
|
31
|
-
END $$;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
-- Cloud Multi-Tenancy Phase 1: organizations table + agents/chats FK + new agent fields
|
|
2
|
-
|
|
3
|
-
-- 1. Create organizations table
|
|
4
|
-
CREATE TABLE IF NOT EXISTS "organizations" (
|
|
5
|
-
"id" text PRIMARY KEY NOT NULL,
|
|
6
|
-
"display_name" text NOT NULL,
|
|
7
|
-
"max_agents" integer NOT NULL DEFAULT 0,
|
|
8
|
-
"max_messages_per_minute" integer NOT NULL DEFAULT 0,
|
|
9
|
-
"features" jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
10
|
-
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
11
|
-
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
-- 2. Insert default organization (idempotent — skip if exists)
|
|
15
|
-
INSERT INTO "organizations" ("id", "display_name")
|
|
16
|
-
VALUES ('default', 'Default Organization')
|
|
17
|
-
ON CONFLICT ("id") DO NOTHING;
|
|
18
|
-
|
|
19
|
-
-- 3. Add FK from agents.organization_id → organizations.id
|
|
20
|
-
ALTER TABLE "agents"
|
|
21
|
-
ADD CONSTRAINT "agents_organization_id_organizations_id_fk"
|
|
22
|
-
FOREIGN KEY ("organization_id") REFERENCES "organizations"("id")
|
|
23
|
-
ON DELETE NO ACTION ON UPDATE NO ACTION;
|
|
24
|
-
|
|
25
|
-
-- 4. Add FK from chats.organization_id → organizations.id
|
|
26
|
-
ALTER TABLE "chats"
|
|
27
|
-
ADD CONSTRAINT "chats_organization_id_organizations_id_fk"
|
|
28
|
-
FOREIGN KEY ("organization_id") REFERENCES "organizations"("id")
|
|
29
|
-
ON DELETE NO ACTION ON UPDATE NO ACTION;
|
|
30
|
-
|
|
31
|
-
-- 5. Add new columns to agents
|
|
32
|
-
ALTER TABLE "agents" ADD COLUMN "source" text;
|
|
33
|
-
ALTER TABLE "agents" ADD COLUMN "cloud_user_id" text;
|
|
34
|
-
ALTER TABLE "agents" ADD COLUMN "public" boolean NOT NULL DEFAULT false;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
-- Organization UUID PK: add name column with unique constraint, drop old defaults
|
|
2
|
-
|
|
3
|
-
-- Step 1: Add name column
|
|
4
|
-
ALTER TABLE "organizations" ADD COLUMN "name" text;
|
|
5
|
-
--> statement-breakpoint
|
|
6
|
-
|
|
7
|
-
-- Step 2: Backfill name from id for existing rows
|
|
8
|
-
UPDATE "organizations" SET "name" = "id" WHERE "name" IS NULL;
|
|
9
|
-
--> statement-breakpoint
|
|
10
|
-
|
|
11
|
-
-- Step 3: Make name NOT NULL
|
|
12
|
-
ALTER TABLE "organizations" ALTER COLUMN "name" SET NOT NULL;
|
|
13
|
-
--> statement-breakpoint
|
|
14
|
-
|
|
15
|
-
-- Step 4: Add UNIQUE constraint on name
|
|
16
|
-
ALTER TABLE "organizations" ADD CONSTRAINT "organizations_name_unique" UNIQUE("name");
|
|
17
|
-
--> statement-breakpoint
|
|
18
|
-
|
|
19
|
-
-- Step 5: Drop old default values on organization_id columns (was 'default' slug)
|
|
20
|
-
ALTER TABLE "agents" ALTER COLUMN "organization_id" DROP DEFAULT;
|
|
21
|
-
--> statement-breakpoint
|
|
22
|
-
ALTER TABLE "chats" ALTER COLUMN "organization_id" DROP DEFAULT;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
-- Session-level state reporting: new session table + drop unused presence columns
|
|
2
|
-
|
|
3
|
-
CREATE TABLE "agent_chat_sessions" (
|
|
4
|
-
"agent_id" text NOT NULL,
|
|
5
|
-
"chat_id" text NOT NULL,
|
|
6
|
-
"state" text NOT NULL,
|
|
7
|
-
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
8
|
-
CONSTRAINT "agent_chat_sessions_agent_id_chat_id_pk" PRIMARY KEY("agent_id","chat_id")
|
|
9
|
-
);
|
|
10
|
-
--> statement-breakpoint
|
|
11
|
-
ALTER TABLE "agent_chat_sessions" ADD CONSTRAINT "agent_chat_sessions_agent_id_agents_uuid_fk" FOREIGN KEY ("agent_id") REFERENCES "public"."agents"("uuid") ON DELETE cascade ON UPDATE no action;
|
|
12
|
-
--> statement-breakpoint
|
|
13
|
-
ALTER TABLE "agent_chat_sessions" ADD CONSTRAINT "agent_chat_sessions_chat_id_chats_id_fk" FOREIGN KEY ("chat_id") REFERENCES "public"."chats"("id") ON DELETE cascade ON UPDATE no action;
|
|
14
|
-
--> statement-breakpoint
|
|
15
|
-
ALTER TABLE "agent_presence" DROP COLUMN IF EXISTS "runtime_description";
|
|
16
|
-
--> statement-breakpoint
|
|
17
|
-
ALTER TABLE "agent_presence" DROP COLUMN IF EXISTS "error_message";
|
|
18
|
-
--> statement-breakpoint
|
|
19
|
-
ALTER TABLE "agent_presence" DROP COLUMN IF EXISTS "task_ref";
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
-- Hub Task — lightweight work units (tasks + task_chats)
|
|
2
|
-
|
|
3
|
-
CREATE TABLE "tasks" (
|
|
4
|
-
"id" text PRIMARY KEY NOT NULL,
|
|
5
|
-
"organization_id" text NOT NULL,
|
|
6
|
-
"title" text NOT NULL,
|
|
7
|
-
"body" text DEFAULT '' NOT NULL,
|
|
8
|
-
"status" text NOT NULL,
|
|
9
|
-
"assignee_agent_id" text,
|
|
10
|
-
"created_by_type" text NOT NULL,
|
|
11
|
-
"created_by_id" text NOT NULL,
|
|
12
|
-
"origin_ref" text,
|
|
13
|
-
"result" text,
|
|
14
|
-
"metadata" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
|
15
|
-
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
16
|
-
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
17
|
-
"cancelled_at" timestamp with time zone,
|
|
18
|
-
"cancelled_by_type" text,
|
|
19
|
-
"cancelled_by_id" text
|
|
20
|
-
);
|
|
21
|
-
--> statement-breakpoint
|
|
22
|
-
CREATE TABLE "task_chats" (
|
|
23
|
-
"task_id" text NOT NULL,
|
|
24
|
-
"chat_id" text NOT NULL,
|
|
25
|
-
"linked_by_agent_id" text,
|
|
26
|
-
"linked_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
27
|
-
CONSTRAINT "task_chats_task_id_chat_id_pk" PRIMARY KEY("task_id","chat_id")
|
|
28
|
-
);
|
|
29
|
-
--> statement-breakpoint
|
|
30
|
-
ALTER TABLE "tasks" ADD CONSTRAINT "tasks_organization_id_organizations_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
|
31
|
-
ALTER TABLE "task_chats" ADD CONSTRAINT "task_chats_task_id_tasks_id_fk" FOREIGN KEY ("task_id") REFERENCES "public"."tasks"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
32
|
-
ALTER TABLE "task_chats" ADD CONSTRAINT "task_chats_chat_id_chats_id_fk" FOREIGN KEY ("chat_id") REFERENCES "public"."chats"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
33
|
-
ALTER TABLE "task_chats" ADD CONSTRAINT "task_chats_linked_by_agent_id_agents_uuid_fk" FOREIGN KEY ("linked_by_agent_id") REFERENCES "public"."agents"("uuid") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
|
34
|
-
CREATE INDEX "idx_tasks_org_status" ON "tasks" USING btree ("organization_id","status");--> statement-breakpoint
|
|
35
|
-
CREATE INDEX "idx_tasks_assignee_status" ON "tasks" USING btree ("assignee_agent_id","status");--> statement-breakpoint
|
|
36
|
-
CREATE INDEX "idx_tasks_origin_ref" ON "tasks" USING btree ("origin_ref");--> statement-breakpoint
|
|
37
|
-
CREATE INDEX "idx_tasks_org_created_at" ON "tasks" USING btree ("organization_id","created_at");--> statement-breakpoint
|
|
38
|
-
CREATE INDEX "idx_task_chats_chat" ON "task_chats" USING btree ("chat_id");
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
-- Drop all FK constraints from the Hub Task tables.
|
|
2
|
-
-- Referential integrity for tasks/task_chats is enforced in the service layer;
|
|
3
|
-
-- DB-level FKs transfer the cost (cascade surprises, migration friction, test
|
|
4
|
-
-- setup complexity) onto the database without adding value here.
|
|
5
|
-
|
|
6
|
-
ALTER TABLE "tasks" DROP CONSTRAINT IF EXISTS "tasks_organization_id_organizations_id_fk";--> statement-breakpoint
|
|
7
|
-
ALTER TABLE "task_chats" DROP CONSTRAINT IF EXISTS "task_chats_task_id_tasks_id_fk";--> statement-breakpoint
|
|
8
|
-
ALTER TABLE "task_chats" DROP CONSTRAINT IF EXISTS "task_chats_chat_id_chats_id_fk";--> statement-breakpoint
|
|
9
|
-
ALTER TABLE "task_chats" DROP CONSTRAINT IF EXISTS "task_chats_linked_by_agent_id_agents_uuid_fk";
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
-- Create users table (replaces admin_users)
|
|
2
|
-
CREATE TABLE "users" (
|
|
3
|
-
"id" text PRIMARY KEY NOT NULL,
|
|
4
|
-
"username" text NOT NULL,
|
|
5
|
-
"password_hash" text NOT NULL,
|
|
6
|
-
"display_name" text NOT NULL,
|
|
7
|
-
"avatar_url" text,
|
|
8
|
-
"status" text DEFAULT 'active' NOT NULL,
|
|
9
|
-
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
10
|
-
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
11
|
-
CONSTRAINT "users_username_unique" UNIQUE("username")
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
-- Create members table
|
|
15
|
-
CREATE TABLE "members" (
|
|
16
|
-
"id" text PRIMARY KEY NOT NULL,
|
|
17
|
-
"user_id" text NOT NULL REFERENCES "users"("id"),
|
|
18
|
-
"organization_id" text NOT NULL REFERENCES "organizations"("id"),
|
|
19
|
-
"agent_id" text NOT NULL REFERENCES "agents"("uuid"),
|
|
20
|
-
"role" text NOT NULL,
|
|
21
|
-
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
22
|
-
CONSTRAINT "members_agent_id_unique" UNIQUE("agent_id"),
|
|
23
|
-
CONSTRAINT "uq_members_user_org" UNIQUE("user_id", "organization_id")
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
CREATE INDEX "idx_members_user" ON "members" ("user_id");
|
|
27
|
-
CREATE INDEX "idx_members_org" ON "members" ("organization_id");
|
|
28
|
-
|
|
29
|
-
-- Add manager_id to agents with FK to members (FK in SQL only — not in Drizzle schema to avoid circular import)
|
|
30
|
-
ALTER TABLE "agents" ADD COLUMN "manager_id" text REFERENCES "members"("id") ON DELETE SET NULL;
|
|
31
|
-
CREATE INDEX "idx_agents_manager" ON "agents" ("manager_id");
|
|
32
|
-
|
|
33
|
-
-- Drop admin_users table
|
|
34
|
-
DROP TABLE "admin_users";
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
CREATE TABLE "notifications" (
|
|
2
|
-
"id" text PRIMARY KEY NOT NULL,
|
|
3
|
-
"organization_id" text NOT NULL,
|
|
4
|
-
"type" text NOT NULL,
|
|
5
|
-
"severity" text NOT NULL,
|
|
6
|
-
"agent_id" text,
|
|
7
|
-
"chat_id" text,
|
|
8
|
-
"message" text NOT NULL,
|
|
9
|
-
"read" boolean DEFAULT false NOT NULL,
|
|
10
|
-
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
11
|
-
);
|
|
12
|
-
--> statement-breakpoint
|
|
13
|
-
CREATE TABLE "session_outputs" (
|
|
14
|
-
"id" text PRIMARY KEY NOT NULL,
|
|
15
|
-
"agent_id" text NOT NULL,
|
|
16
|
-
"chat_id" text NOT NULL,
|
|
17
|
-
"content" text DEFAULT '' NOT NULL,
|
|
18
|
-
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
19
|
-
);
|
|
20
|
-
--> statement-breakpoint
|
|
21
|
-
ALTER TABLE "messages" ADD COLUMN "source" text;--> statement-breakpoint
|
|
22
|
-
CREATE INDEX "idx_notifications_org_created" ON "notifications" USING btree ("organization_id","created_at");--> statement-breakpoint
|
|
23
|
-
CREATE INDEX "idx_notifications_agent" ON "notifications" USING btree ("agent_id");--> statement-breakpoint
|
|
24
|
-
CREATE INDEX "idx_notifications_org_read" ON "notifications" USING btree ("organization_id","read");--> statement-breakpoint
|
|
25
|
-
CREATE INDEX "idx_session_outputs_agent_chat" ON "session_outputs" USING btree ("agent_id","chat_id");
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
ALTER TABLE "session_outputs" ADD CONSTRAINT "uq_session_outputs_agent_chat" UNIQUE("agent_id","chat_id");
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
-- Replace boolean "public" column with text "visibility" column
|
|
2
|
-
ALTER TABLE "agents" ADD COLUMN "visibility" text NOT NULL DEFAULT 'private';--> statement-breakpoint
|
|
3
|
-
|
|
4
|
-
-- Set defaults by agent type
|
|
5
|
-
UPDATE "agents" SET "visibility" = 'organization' WHERE "type" = 'human';--> statement-breakpoint
|
|
6
|
-
UPDATE "agents" SET "visibility" = 'organization' WHERE "type" = 'autonomous_agent';--> statement-breakpoint
|
|
7
|
-
UPDATE "agents" SET "visibility" = 'private' WHERE "type" = 'personal_assistant';--> statement-breakpoint
|
|
8
|
-
|
|
9
|
-
-- Drop old public column
|
|
10
|
-
ALTER TABLE "agents" DROP COLUMN "public";--> statement-breakpoint
|
|
11
|
-
|
|
12
|
-
-- Add index for visibility queries
|
|
13
|
-
CREATE INDEX "idx_agents_visibility_org" ON "agents" USING btree ("organization_id","visibility");
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
-- M1 agent configuration: Hub-managed runtime config table.
|
|
2
|
-
-- Creates `agent_configs` and back-fills one row per non-deleted agent so
|
|
3
|
-
-- Step 6 can flip Claude Code handler over to read prompt from config without
|
|
4
|
-
-- silently dropping the existing `agents.profile` text.
|
|
5
|
-
|
|
6
|
-
CREATE TABLE IF NOT EXISTS "agent_configs" (
|
|
7
|
-
"agent_id" text PRIMARY KEY NOT NULL,
|
|
8
|
-
"version" integer NOT NULL DEFAULT 1,
|
|
9
|
-
"payload" jsonb NOT NULL,
|
|
10
|
-
"updated_by" text NOT NULL,
|
|
11
|
-
"updated_at" timestamp with time zone NOT NULL DEFAULT now()
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
--> statement-breakpoint
|
|
15
|
-
INSERT INTO "agent_configs" ("agent_id", "version", "payload", "updated_by", "updated_at")
|
|
16
|
-
SELECT
|
|
17
|
-
"uuid",
|
|
18
|
-
1,
|
|
19
|
-
jsonb_build_object(
|
|
20
|
-
'prompt', jsonb_build_object('append', COALESCE("profile", '')),
|
|
21
|
-
'model', '',
|
|
22
|
-
'mcpServers', '[]'::jsonb,
|
|
23
|
-
'env', '[]'::jsonb,
|
|
24
|
-
'gitRepos', '[]'::jsonb
|
|
25
|
-
),
|
|
26
|
-
'system',
|
|
27
|
-
now()
|
|
28
|
-
FROM "agents"
|
|
29
|
-
WHERE "status" != 'deleted'
|
|
30
|
-
ON CONFLICT ("agent_id") DO NOTHING;
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
-- Unified user token milestone — retire agent tokens, authenticate every
|
|
2
|
-
-- caller as a user.
|
|
3
|
-
--
|
|
4
|
-
-- This migration collapses the two-track auth (member JWT + `aghub_*` agent
|
|
5
|
-
-- token) into a single member-JWT credential. Three structural changes:
|
|
6
|
-
-- 1. Drop `agent_tokens` (table + FK cascade).
|
|
7
|
-
-- 2. Add `clients.user_id` (nullable) — owning user of the physical client.
|
|
8
|
-
-- 3. Add `agents.client_id` (nullable FK) — pin an agent to the client that
|
|
9
|
-
-- runs it. `client_id` is backfilled from `agent_presence`. Rows that
|
|
10
|
-
-- cannot be backfilled stay NULL and bind on first WS connect (see
|
|
11
|
-
-- `api/agent/ws-client.ts` first-bind path). Originally this migration
|
|
12
|
-
-- raised an exception when any non-human agent was unbacked — that
|
|
13
|
-
-- gated startup on a data state the operator usually can't fix until
|
|
14
|
-
-- the server is up. Relaxed to NOTICE so the loop is broken; runtime
|
|
15
|
-
-- enforcement (Rule R-RUN in `services/agent.ts` + `agent-selector.ts`)
|
|
16
|
-
-- still rejects unclaimed agents on the request path.
|
|
17
|
-
-- 4. Make `agents.manager_id` NOT NULL after backfilling the first admin
|
|
18
|
-
-- member of each org onto the unmanaged rows.
|
|
19
|
-
--
|
|
20
|
-
-- There is no compatibility layer: operators stop SDK/CLI processes, run
|
|
21
|
-
-- `db:migrate`, then re-login via `first-tree-hub connect`. See the proposal
|
|
22
|
-
-- "unified-user-token.20260417" for the full upgrade runbook.
|
|
23
|
-
--
|
|
24
|
-
-- NOTE: Do NOT wrap this file in BEGIN;/COMMIT;. The Drizzle migrator already
|
|
25
|
-
-- runs every pending migration inside a single outer transaction, so a nested
|
|
26
|
-
-- BEGIN raises WARNING 25001 and the inner COMMIT prematurely closes the
|
|
27
|
-
-- outer transaction — which prevents the migration hash from being recorded
|
|
28
|
-
-- and causes the server to loop through the same failure on every restart.
|
|
29
|
-
|
|
30
|
-
DROP TABLE IF EXISTS "agent_tokens";
|
|
31
|
-
--> statement-breakpoint
|
|
32
|
-
|
|
33
|
-
-- ---------------------------------------------------------------------------
|
|
34
|
-
-- clients.user_id — nullable FK to users(id).
|
|
35
|
-
-- Nullable so legacy rows (created before handshake auth) keep existing;
|
|
36
|
-
-- the WS handshake claims them on first re-register under a JWT.
|
|
37
|
-
-- ---------------------------------------------------------------------------
|
|
38
|
-
ALTER TABLE "clients"
|
|
39
|
-
ADD COLUMN IF NOT EXISTS "user_id" text REFERENCES "users"("id") ON DELETE SET NULL;
|
|
40
|
-
--> statement-breakpoint
|
|
41
|
-
|
|
42
|
-
CREATE INDEX IF NOT EXISTS "idx_clients_user" ON "clients" ("user_id");
|
|
43
|
-
--> statement-breakpoint
|
|
44
|
-
|
|
45
|
-
-- ---------------------------------------------------------------------------
|
|
46
|
-
-- agents.client_id — pin an agent to the physical client that runs it.
|
|
47
|
-
-- ---------------------------------------------------------------------------
|
|
48
|
-
ALTER TABLE "agents"
|
|
49
|
-
ADD COLUMN IF NOT EXISTS "client_id" text REFERENCES "clients"("id") ON DELETE RESTRICT;
|
|
50
|
-
--> statement-breakpoint
|
|
51
|
-
|
|
52
|
-
-- Copy last-bound client from agent_presence.
|
|
53
|
-
UPDATE "agents" a
|
|
54
|
-
SET "client_id" = ap."client_id"
|
|
55
|
-
FROM "agent_presence" ap
|
|
56
|
-
WHERE ap."agent_id" = a."uuid"
|
|
57
|
-
AND ap."client_id" IS NOT NULL
|
|
58
|
-
AND a."client_id" IS NULL;
|
|
59
|
-
--> statement-breakpoint
|
|
60
|
-
|
|
61
|
-
-- Surface (do not block) any non-deleted non-human agent still missing a
|
|
62
|
-
-- client_id after the backfill. They will sit in an "unclaimed" state until
|
|
63
|
-
-- a client connects via WS and the first-bind path in
|
|
64
|
-
-- `api/agent/ws-client.ts` claims them. Runtime guards reject HTTP / WS
|
|
65
|
-
-- requests for those agents in the meantime.
|
|
66
|
-
DO $$
|
|
67
|
-
DECLARE
|
|
68
|
-
unpinned_count integer;
|
|
69
|
-
BEGIN
|
|
70
|
-
SELECT COUNT(*) INTO unpinned_count
|
|
71
|
-
FROM "agents"
|
|
72
|
-
WHERE "client_id" IS NULL
|
|
73
|
-
AND "type" <> 'human'
|
|
74
|
-
AND "status" <> 'deleted';
|
|
75
|
-
|
|
76
|
-
IF unpinned_count > 0 THEN
|
|
77
|
-
RAISE NOTICE
|
|
78
|
-
'unified-user-token migration: % non-human agents have no client_id after backfill; '
|
|
79
|
-
'they will be claimed on first WS bind (see ws-client.ts first-bind path)',
|
|
80
|
-
unpinned_count;
|
|
81
|
-
END IF;
|
|
82
|
-
END $$;
|
|
83
|
-
--> statement-breakpoint
|
|
84
|
-
|
|
85
|
-
CREATE INDEX IF NOT EXISTS "idx_agents_client" ON "agents" ("client_id");
|
|
86
|
-
--> statement-breakpoint
|
|
87
|
-
|
|
88
|
-
-- ---------------------------------------------------------------------------
|
|
89
|
-
-- agents.manager_id — backfill then enforce NOT NULL.
|
|
90
|
-
-- Human agents own their members row, so self-assign via members.
|
|
91
|
-
-- Non-human agents get the first admin member in their org.
|
|
92
|
-
-- ---------------------------------------------------------------------------
|
|
93
|
-
|
|
94
|
-
-- Human agents: self-assign to their own member row.
|
|
95
|
-
UPDATE "agents" a
|
|
96
|
-
SET "manager_id" = m."id"
|
|
97
|
-
FROM "members" m
|
|
98
|
-
WHERE m."agent_id" = a."uuid"
|
|
99
|
-
AND a."manager_id" IS NULL
|
|
100
|
-
AND a."type" = 'human';
|
|
101
|
-
--> statement-breakpoint
|
|
102
|
-
|
|
103
|
-
-- Non-human agents: first admin in org, ordered by created_at asc.
|
|
104
|
-
UPDATE "agents" a
|
|
105
|
-
SET "manager_id" = m."id"
|
|
106
|
-
FROM (
|
|
107
|
-
SELECT DISTINCT ON (m."organization_id")
|
|
108
|
-
m."id" AS id,
|
|
109
|
-
m."organization_id" AS organization_id
|
|
110
|
-
FROM "members" m
|
|
111
|
-
WHERE m."role" = 'admin'
|
|
112
|
-
ORDER BY m."organization_id", m."created_at" ASC
|
|
113
|
-
) m
|
|
114
|
-
WHERE a."organization_id" = m."organization_id"
|
|
115
|
-
AND a."manager_id" IS NULL;
|
|
116
|
-
--> statement-breakpoint
|
|
117
|
-
|
|
118
|
-
-- Fail loudly if any agent still lacks a manager.
|
|
119
|
-
DO $$
|
|
120
|
-
DECLARE
|
|
121
|
-
orphan_count integer;
|
|
122
|
-
BEGIN
|
|
123
|
-
SELECT COUNT(*) INTO orphan_count
|
|
124
|
-
FROM "agents"
|
|
125
|
-
WHERE "manager_id" IS NULL
|
|
126
|
-
AND "status" <> 'deleted';
|
|
127
|
-
|
|
128
|
-
IF orphan_count > 0 THEN
|
|
129
|
-
RAISE EXCEPTION
|
|
130
|
-
'unified-user-token migration: % non-deleted agents have no manager_id after backfill; '
|
|
131
|
-
'create at least one admin member per org, or set agents.manager_id manually, then retry',
|
|
132
|
-
orphan_count;
|
|
133
|
-
END IF;
|
|
134
|
-
END $$;
|
|
135
|
-
--> statement-breakpoint
|
|
136
|
-
|
|
137
|
-
ALTER TABLE "agents"
|
|
138
|
-
ALTER COLUMN "manager_id" SET NOT NULL;
|
|
139
|
-
--> statement-breakpoint
|
|
140
|
-
|
|
141
|
-
-- Recreate the manager_id FK as DEFERRABLE INITIALLY DEFERRED so the
|
|
142
|
-
-- bootstrap path for a new human agent + member row can run inside a
|
|
143
|
-
-- single transaction. The two rows reference each other (agents.manager_id
|
|
144
|
-
-- → members.id, members.agent_id → agents.uuid); without deferred FKs the
|
|
145
|
-
-- first INSERT always fails the sibling constraint.
|
|
146
|
-
ALTER TABLE "agents"
|
|
147
|
-
DROP CONSTRAINT IF EXISTS "agents_manager_id_fkey";
|
|
148
|
-
--> statement-breakpoint
|
|
149
|
-
|
|
150
|
-
ALTER TABLE "agents"
|
|
151
|
-
ADD CONSTRAINT "agents_manager_id_fkey"
|
|
152
|
-
FOREIGN KEY ("manager_id") REFERENCES "members"("id")
|
|
153
|
-
ON DELETE SET NULL
|
|
154
|
-
DEFERRABLE INITIALLY DEFERRED;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
-- PRD D7: remove `agents.profile` column and all dependent code paths.
|
|
2
|
-
-- The column was backfilled into `agent_configs.payload.prompt.append` by
|
|
3
|
-
-- migration 0018. After this migration, agent behavior instructions live
|
|
4
|
-
-- exclusively in `agent_configs`; the `profile` column is dead weight.
|
|
5
|
-
--
|
|
6
|
-
-- Callers that used to read/write `profile` have been updated in the same
|
|
7
|
-
-- release; operators must deploy this migration together with the matching
|
|
8
|
-
-- code change — no compatibility layer.
|
|
9
|
-
|
|
10
|
-
ALTER TABLE "agents" DROP COLUMN IF EXISTS "profile";
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
-- NC2 (workspace-redesign S10): drop `session_outputs`, add `session_events`.
|
|
2
|
-
--
|
|
3
|
-
-- The old table held one `content` row per (agent, chat) with string
|
|
4
|
-
-- concatenation on upsert. The new table captures structured events
|
|
5
|
-
-- (`tool_call` / `error`) with a monotonic per-chat `seq` and a jsonb
|
|
6
|
-
-- payload. Integrity is enforced in the service layer (Zod discriminated
|
|
7
|
-
-- union on insert), so no FK / CHECK here — matches the project rule for
|
|
8
|
-
-- new tables.
|
|
9
|
-
--
|
|
10
|
-
-- Discarding `session_outputs` data is intentional (tech plan decision):
|
|
11
|
-
-- no content-migration path, no compatibility shim.
|
|
12
|
-
|
|
13
|
-
DROP TABLE IF EXISTS "session_outputs" CASCADE;
|
|
14
|
-
|
|
15
|
-
--> statement-breakpoint
|
|
16
|
-
CREATE TABLE IF NOT EXISTS "session_events" (
|
|
17
|
-
"id" text PRIMARY KEY NOT NULL,
|
|
18
|
-
"agent_id" text NOT NULL,
|
|
19
|
-
"chat_id" text NOT NULL,
|
|
20
|
-
"seq" integer NOT NULL,
|
|
21
|
-
"kind" text NOT NULL,
|
|
22
|
-
"payload" jsonb NOT NULL,
|
|
23
|
-
"created_at" timestamp with time zone NOT NULL DEFAULT now()
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
--> statement-breakpoint
|
|
27
|
-
CREATE UNIQUE INDEX IF NOT EXISTS "uq_session_events_chat_seq"
|
|
28
|
-
ON "session_events" ("agent_id", "chat_id", "seq");
|
|
29
|
-
|
|
30
|
-
--> statement-breakpoint
|
|
31
|
-
CREATE INDEX IF NOT EXISTS "idx_session_events_chat_created"
|
|
32
|
-
ON "session_events" ("agent_id", "chat_id", "created_at" DESC);
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
-- Multi-tenancy hardening:
|
|
2
|
-
-- 1. Drop dead column `agents.cloud_user_id` (unused since introduction in
|
|
3
|
-
-- 0010; never written by any code path).
|
|
4
|
-
-- 2. Bind every client to exactly one organization via `clients.organization_id`.
|
|
5
|
-
--
|
|
6
|
-
-- A client is bound to one org for its lifetime — Rule R-RUN and the
|
|
7
|
-
-- `client:register` handshake reject cross-org reuse of a clientId. See
|
|
8
|
-
-- docs/multi-tenancy-hardening-design.md.
|
|
9
|
-
--
|
|
10
|
-
-- Backfill strategy (guarded for safety across environments):
|
|
11
|
-
-- * Current production: exactly one org → UPDATE fills every row.
|
|
12
|
-
-- * Fresh installs / empty DB: clients table is empty → UPDATE is a no-op,
|
|
13
|
-
-- SET NOT NULL succeeds on the empty table.
|
|
14
|
-
-- * Any environment reaching this migration with multi-org data but
|
|
15
|
-
-- unpopulated clients.organization_id: the guard skips the UPDATE, and
|
|
16
|
-
-- SET NOT NULL fails loudly rather than misassigning rows to an
|
|
17
|
-
-- arbitrary org. Operator must backfill manually, then re-run.
|
|
18
|
-
|
|
19
|
-
ALTER TABLE "agents" DROP COLUMN "cloud_user_id";
|
|
20
|
-
|
|
21
|
-
--> statement-breakpoint
|
|
22
|
-
ALTER TABLE "clients" ADD COLUMN "organization_id" text;
|
|
23
|
-
|
|
24
|
-
--> statement-breakpoint
|
|
25
|
-
ALTER TABLE "clients"
|
|
26
|
-
ADD CONSTRAINT "clients_organization_id_organizations_id_fk"
|
|
27
|
-
FOREIGN KEY ("organization_id") REFERENCES "organizations"("id")
|
|
28
|
-
ON DELETE no action ON UPDATE no action;
|
|
29
|
-
|
|
30
|
-
--> statement-breakpoint
|
|
31
|
-
UPDATE "clients"
|
|
32
|
-
SET "organization_id" = (SELECT "id" FROM "organizations" LIMIT 1)
|
|
33
|
-
WHERE "organization_id" IS NULL
|
|
34
|
-
AND (SELECT count(*) FROM "organizations") = 1;
|
|
35
|
-
|
|
36
|
-
--> statement-breakpoint
|
|
37
|
-
ALTER TABLE "clients" ALTER COLUMN "organization_id" SET NOT NULL;
|
|
38
|
-
|
|
39
|
-
--> statement-breakpoint
|
|
40
|
-
CREATE INDEX IF NOT EXISTS "idx_clients_org" ON "clients" ("organization_id");
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
-- Phase 2 of the agent-naming refactor (docs/agent-naming-design.md §4).
|
|
2
|
-
--
|
|
3
|
-
-- Before this migration, `display_name` was nullable and the web layer
|
|
4
|
-
-- silently fell back to `name` for rendering. CLI, server logs, and IM
|
|
5
|
-
-- bridges saw raw NULLs. This migration closes the gap in three steps:
|
|
6
|
-
--
|
|
7
|
-
-- 1. Backfill every NULL row with a non-empty label — the agent's `name`
|
|
8
|
-
-- when available, else the tombstone literal "[deleted agent]".
|
|
9
|
-
-- Important: the third branch must NOT be `uuid`, because UUIDs would
|
|
10
|
-
-- surface as human-visible strings in the chat roster and IM bridge.
|
|
11
|
-
-- Only `status = 'deleted'` rows can have both `name` and
|
|
12
|
-
-- `display_name` NULL (see `deleteAgent` in services/agent.ts), which
|
|
13
|
-
-- is why the literal refers to deletion.
|
|
14
|
-
--
|
|
15
|
-
-- 2. Add a temporary empty-string DEFAULT so any old server instance
|
|
16
|
-
-- still running during a rolling deploy — i.e. code that doesn't yet
|
|
17
|
-
-- default `display_name` in `createAgent` — can INSERT without
|
|
18
|
-
-- violating the upcoming NOT NULL. The application code treats an
|
|
19
|
-
-- empty string as "no display name" (the Zod read schema accepts it);
|
|
20
|
-
-- a follow-up migration can drop the default once the code is fully
|
|
21
|
-
-- rolled.
|
|
22
|
-
--
|
|
23
|
-
-- 3. Promote the column to NOT NULL. Combined with the service-level
|
|
24
|
-
-- default this closes the hole for new rows too.
|
|
25
|
-
|
|
26
|
-
UPDATE "agents"
|
|
27
|
-
SET "display_name" = COALESCE("display_name", "name", '[deleted agent]')
|
|
28
|
-
WHERE "display_name" IS NULL;
|
|
29
|
-
|
|
30
|
-
ALTER TABLE "agents" ALTER COLUMN "display_name" SET DEFAULT '';
|
|
31
|
-
ALTER TABLE "agents" ALTER COLUMN "display_name" SET NOT NULL;
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
-- Silent inbox entries for missed group-chat context.
|
|
2
|
-
--
|
|
3
|
-
-- Adds `inbox_entries.notify`, defaulting to true so existing rows continue to
|
|
4
|
-
-- behave as "active" deliverables. Group-chat fan-out now writes a row for
|
|
5
|
-
-- every non-sender participant — for `mention_only` participants who aren't
|
|
6
|
-
-- explicitly @mentioned in the triggering message we set `notify = false` so
|
|
7
|
-
-- the row is silently parked. Subsequent active deliveries to the same chat
|
|
8
|
-
-- pick up these silent rows and replay them as preceding context, then
|
|
9
|
-
-- bulk-ack them so they don't get re-replayed.
|
|
10
|
-
--
|
|
11
|
-
-- See proposals/group-chat-ux-improvements §1 (silent inbox).
|
|
12
|
-
--
|
|
13
|
-
-- ──────────────── Indexes ────────────────
|
|
14
|
-
--
|
|
15
|
-
-- idx_inbox_pending_notify — partial index used by pollInbox's claim.
|
|
16
|
-
-- The query is "WHERE inbox_id = ? AND status = 'pending' AND notify = true
|
|
17
|
-
-- ORDER BY created_at LIMIT N FOR UPDATE SKIP LOCKED". Without `notify` in
|
|
18
|
-
-- the index, a chat that accumulates silent rows (mention_only agent in a
|
|
19
|
-
-- chatty group) forces the planner to scan past them before finding the
|
|
20
|
-
-- next trigger. Partial index keeps it bounded.
|
|
21
|
-
--
|
|
22
|
-
-- idx_inbox_chat_silent — used by collectPrecedingContext to walk the
|
|
23
|
-
-- silent rows in a single (inbox, chat) bucket between two triggers.
|
|
24
|
-
--
|
|
25
|
-
-- ──────────────── Operator note ────────────────
|
|
26
|
-
--
|
|
27
|
-
-- Drizzle migrator wraps every migration file in a single transaction (see the
|
|
28
|
-
-- comment block in 0020_unified_user_token.sql), which means we can't use
|
|
29
|
-
-- `CREATE INDEX CONCURRENTLY` here — PG rejects it inside a tx. On a small
|
|
30
|
-
-- `inbox_entries` table the regular `CREATE INDEX` finishes in <1s and is
|
|
31
|
-
-- fine. For a large production table, the runbook is:
|
|
32
|
-
--
|
|
33
|
-
-- 1. Stop applying new migrations briefly.
|
|
34
|
-
-- 2. Manually run, OUTSIDE a transaction:
|
|
35
|
-
-- CREATE INDEX CONCURRENTLY idx_inbox_pending_notify
|
|
36
|
-
-- ON inbox_entries (inbox_id, created_at)
|
|
37
|
-
-- WHERE status = 'pending' AND notify = true;
|
|
38
|
-
-- CREATE INDEX CONCURRENTLY idx_inbox_chat_silent
|
|
39
|
-
-- ON inbox_entries (inbox_id, chat_id, notify, status);
|
|
40
|
-
-- 3. Re-run `pnpm db:migrate`. The `IF NOT EXISTS` clauses below detect
|
|
41
|
-
-- the pre-created indexes and skip them.
|
|
42
|
-
|
|
43
|
-
ALTER TABLE "inbox_entries"
|
|
44
|
-
ADD COLUMN "notify" boolean DEFAULT true NOT NULL;
|
|
45
|
-
|
|
46
|
-
--> statement-breakpoint
|
|
47
|
-
CREATE INDEX IF NOT EXISTS "idx_inbox_pending_notify"
|
|
48
|
-
ON "inbox_entries" ("inbox_id", "created_at")
|
|
49
|
-
WHERE status = 'pending' AND notify = true;
|
|
50
|
-
|
|
51
|
-
--> statement-breakpoint
|
|
52
|
-
CREATE INDEX IF NOT EXISTS "idx_inbox_chat_silent"
|
|
53
|
-
ON "inbox_entries" ("inbox_id", "chat_id", "notify", "status");
|