From bca486c079941c567b3cd9a7d85178d9cc02c977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Emre=20Kabakc=C4=B1?= Date: Sat, 25 Apr 2026 02:29:55 +0100 Subject: [PATCH 1/2] feat(db): add template-mirror tracking columns to schema tables Adds managed_by_template_agent_id and source_template_org_id to entity_types, entity_relationship_types, event_classifiers, and watchers. When a user installs a template agent, the install flow mirrors that agent's canonical entity types, relationship types, classifiers and watcher definitions from the template org into the user's personal org. The two new columns record the provenance of those mirrored rows so they can be re-synced on template updates and treated as read-only by the user-org owner. Partial indexes only cover non-NULL rows so user-authored entity types/relationships/classifiers/watchers stay un-indexed (the common case). --- ...425120000_add_template_mirror_tracking.sql | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 db/migrations/20260425120000_add_template_mirror_tracking.sql diff --git a/db/migrations/20260425120000_add_template_mirror_tracking.sql b/db/migrations/20260425120000_add_template_mirror_tracking.sql new file mode 100644 index 000000000..cabde264b --- /dev/null +++ b/db/migrations/20260425120000_add_template_mirror_tracking.sql @@ -0,0 +1,69 @@ +-- migrate:up + +-- The schema-mirror feature lets a template agent (e.g. examples/personal-finance) +-- own a canonical set of entity types, relationship types, classifiers and +-- watcher definitions in its template org and mirror them into each user's +-- personal org when they install the agent. The two new columns record the +-- provenance of mirrored rows so they can be re-synced on template updates and +-- treated as read-only by the user-org owner. +-- +-- managed_by_template_agent_id: the agents.id (in the template org) that owns +-- this row. NULL for rows authored by the user themselves. +-- source_template_org_id: the organization.id of the template org. Pairs with +-- the agent_id so a user can re-sync against the right source even if the +-- template agent is later renamed. + +ALTER TABLE public.entity_types + ADD COLUMN managed_by_template_agent_id text, + ADD COLUMN source_template_org_id text; + +ALTER TABLE public.entity_relationship_types + ADD COLUMN managed_by_template_agent_id text, + ADD COLUMN source_template_org_id text; + +ALTER TABLE public.event_classifiers + ADD COLUMN managed_by_template_agent_id text, + ADD COLUMN source_template_org_id text; + +ALTER TABLE public.watchers + ADD COLUMN managed_by_template_agent_id text, + ADD COLUMN source_template_org_id text; + +CREATE INDEX idx_entity_types_managed_by_template + ON public.entity_types (managed_by_template_agent_id) + WHERE managed_by_template_agent_id IS NOT NULL; + +CREATE INDEX idx_entity_relationship_types_managed_by_template + ON public.entity_relationship_types (managed_by_template_agent_id) + WHERE managed_by_template_agent_id IS NOT NULL; + +CREATE INDEX idx_event_classifiers_managed_by_template + ON public.event_classifiers (managed_by_template_agent_id) + WHERE managed_by_template_agent_id IS NOT NULL; + +CREATE INDEX idx_watchers_managed_by_template + ON public.watchers (managed_by_template_agent_id) + WHERE managed_by_template_agent_id IS NOT NULL; + +-- migrate:down + +DROP INDEX IF EXISTS public.idx_watchers_managed_by_template; +DROP INDEX IF EXISTS public.idx_event_classifiers_managed_by_template; +DROP INDEX IF EXISTS public.idx_entity_relationship_types_managed_by_template; +DROP INDEX IF EXISTS public.idx_entity_types_managed_by_template; + +ALTER TABLE public.watchers + DROP COLUMN IF EXISTS source_template_org_id, + DROP COLUMN IF EXISTS managed_by_template_agent_id; + +ALTER TABLE public.event_classifiers + DROP COLUMN IF EXISTS source_template_org_id, + DROP COLUMN IF EXISTS managed_by_template_agent_id; + +ALTER TABLE public.entity_relationship_types + DROP COLUMN IF EXISTS source_template_org_id, + DROP COLUMN IF EXISTS managed_by_template_agent_id; + +ALTER TABLE public.entity_types + DROP COLUMN IF EXISTS source_template_org_id, + DROP COLUMN IF EXISTS managed_by_template_agent_id; From fd7468b3e73edd059412b9590f44d12b11b6f0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Emre=20Kabakc=C4=B1?= Date: Sat, 25 Apr 2026 15:26:24 +0100 Subject: [PATCH 2/2] fix(db): make template-mirror migration idempotent + tighten index names - Add IF NOT EXISTS to ALTER TABLE ADD COLUMN so a rollback + re-apply doesn't fail on column-exists. - Rename indexes from idx_*_managed_by_template to idx_*_template_agent_id to match the existing idx__ convention (cf. idx_cc_watcher_id). --- ...425120000_add_template_mirror_tracking.sql | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/db/migrations/20260425120000_add_template_mirror_tracking.sql b/db/migrations/20260425120000_add_template_mirror_tracking.sql index cabde264b..4daa21bb3 100644 --- a/db/migrations/20260425120000_add_template_mirror_tracking.sql +++ b/db/migrations/20260425120000_add_template_mirror_tracking.sql @@ -14,43 +14,43 @@ -- template agent is later renamed. ALTER TABLE public.entity_types - ADD COLUMN managed_by_template_agent_id text, - ADD COLUMN source_template_org_id text; + ADD COLUMN IF NOT EXISTS managed_by_template_agent_id text, + ADD COLUMN IF NOT EXISTS source_template_org_id text; ALTER TABLE public.entity_relationship_types - ADD COLUMN managed_by_template_agent_id text, - ADD COLUMN source_template_org_id text; + ADD COLUMN IF NOT EXISTS managed_by_template_agent_id text, + ADD COLUMN IF NOT EXISTS source_template_org_id text; ALTER TABLE public.event_classifiers - ADD COLUMN managed_by_template_agent_id text, - ADD COLUMN source_template_org_id text; + ADD COLUMN IF NOT EXISTS managed_by_template_agent_id text, + ADD COLUMN IF NOT EXISTS source_template_org_id text; ALTER TABLE public.watchers - ADD COLUMN managed_by_template_agent_id text, - ADD COLUMN source_template_org_id text; + ADD COLUMN IF NOT EXISTS managed_by_template_agent_id text, + ADD COLUMN IF NOT EXISTS source_template_org_id text; -CREATE INDEX idx_entity_types_managed_by_template +CREATE INDEX IF NOT EXISTS idx_entity_types_template_agent_id ON public.entity_types (managed_by_template_agent_id) WHERE managed_by_template_agent_id IS NOT NULL; -CREATE INDEX idx_entity_relationship_types_managed_by_template +CREATE INDEX IF NOT EXISTS idx_entity_relationship_types_template_agent_id ON public.entity_relationship_types (managed_by_template_agent_id) WHERE managed_by_template_agent_id IS NOT NULL; -CREATE INDEX idx_event_classifiers_managed_by_template +CREATE INDEX IF NOT EXISTS idx_event_classifiers_template_agent_id ON public.event_classifiers (managed_by_template_agent_id) WHERE managed_by_template_agent_id IS NOT NULL; -CREATE INDEX idx_watchers_managed_by_template +CREATE INDEX IF NOT EXISTS idx_watchers_template_agent_id ON public.watchers (managed_by_template_agent_id) WHERE managed_by_template_agent_id IS NOT NULL; -- migrate:down -DROP INDEX IF EXISTS public.idx_watchers_managed_by_template; -DROP INDEX IF EXISTS public.idx_event_classifiers_managed_by_template; -DROP INDEX IF EXISTS public.idx_entity_relationship_types_managed_by_template; -DROP INDEX IF EXISTS public.idx_entity_types_managed_by_template; +DROP INDEX IF EXISTS public.idx_watchers_template_agent_id; +DROP INDEX IF EXISTS public.idx_event_classifiers_template_agent_id; +DROP INDEX IF EXISTS public.idx_entity_relationship_types_template_agent_id; +DROP INDEX IF EXISTS public.idx_entity_types_template_agent_id; ALTER TABLE public.watchers DROP COLUMN IF EXISTS source_template_org_id,