feat(projects): projects table + owner_project FK; ProjectId/Project types

First commit of §7 multi-repo ownership. A 'project' is a repo-root that
declaratively manages a slice of the shared group tree; each group node is
owned by exactly one project (single-owner-per-node). This lands the registry
+ shared types and wires the inert 0047 `owner_project` seam — no behavior
change yet (claim logic is the next commit).

- migration 0066: `projects` table (UUID pk, unique slug, name, created_by →
  admin_users ON DELETE SET NULL); `groups.owner_project` gains its FK →
  projects(id) ON DELETE SET NULL (un-claim, never cascade-destroy a tree) +
  an index.
- shared: `ProjectId` (id_type! macro) + `Project` struct; `Group` gains
  `owner_project: Option<ProjectId>`.
- group_repo: GROUP_COLS + the ancestors recursive-CTE term now carry
  `owner_project`, so `ancestors()` surfaces ownership for the nearest-claimed
  fold; GroupRow + From updated.
- schema snapshot re-blessed; /version schema assertion 65 → 66.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-06 20:01:57 +02:00
parent f1730a1ba0
commit ba97c35aaf
8 changed files with 106 additions and 9 deletions

View File

@@ -318,6 +318,13 @@ table: outbox
claimed_by: text NULL
created_at: timestamp with time zone NOT NULL default=now()
table: projects
id: uuid NOT NULL default=gen_random_uuid()
slug: text NOT NULL
name: text NOT NULL
created_by: uuid NULL
created_at: timestamp with time zone NOT NULL default=now()
table: pubsub_trigger_details
trigger_id: uuid NOT NULL
topic_pattern: text NOT NULL
@@ -579,6 +586,7 @@ indexes on group_queue_messages:
idx_group_queue_messages_group_collection: public.group_queue_messages USING btree (group_id, collection)
indexes on groups:
groups_owner_project_idx: public.groups USING btree (owner_project)
groups_parent_id_idx: public.groups USING btree (parent_id)
groups_pkey: public.groups USING btree (id)
groups_slug_key: public.groups USING btree (slug)
@@ -595,6 +603,10 @@ indexes on outbox:
idx_outbox_due: public.outbox USING btree (next_attempt_at) WHERE (claimed_at IS NULL)
outbox_pkey: public.outbox USING btree (id)
indexes on projects:
projects_pkey: public.projects USING btree (id)
projects_slug_key: public.projects USING btree (slug)
indexes on pubsub_trigger_details:
pubsub_trigger_details_pkey: public.pubsub_trigger_details USING btree (trigger_id)
@@ -817,6 +829,7 @@ constraints on group_queue_messages:
[PRIMARY KEY] group_queue_messages_pkey: PRIMARY KEY (id)
constraints on groups:
[FOREIGN KEY] groups_owner_project_fk: FOREIGN KEY (owner_project) REFERENCES projects(id) ON DELETE SET NULL
[FOREIGN KEY] groups_parent_id_fkey: FOREIGN KEY (parent_id) REFERENCES groups(id) ON DELETE RESTRICT
[PRIMARY KEY] groups_pkey: PRIMARY KEY (id)
[UNIQUE] groups_slug_key: UNIQUE (slug)
@@ -834,6 +847,11 @@ constraints on outbox:
[FOREIGN KEY] outbox_app_id_fkey: FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE
[PRIMARY KEY] outbox_pkey: PRIMARY KEY (id)
constraints on projects:
[FOREIGN KEY] projects_created_by_fkey: FOREIGN KEY (created_by) REFERENCES admin_users(id) ON DELETE SET NULL
[PRIMARY KEY] projects_pkey: PRIMARY KEY (id)
[UNIQUE] projects_slug_key: UNIQUE (slug)
constraints on pubsub_trigger_details:
[FOREIGN KEY] pubsub_trigger_details_trigger_id_fkey: FOREIGN KEY (trigger_id) REFERENCES triggers(id) ON DELETE CASCADE
[PRIMARY KEY] pubsub_trigger_details_pkey: PRIMARY KEY (trigger_id)
@@ -973,3 +991,4 @@ constraints on vars:
0063: materialized unique
0064: shared topic queue kinds
0065: group queues
0066: projects