ci/woodpecker/pr/ci Pipeline was successful
Implements docs/requirements/hierarchy-schema.md sections 2-4 and the schema-layer half of section 6: - Five class tables (companies, estates, platform_projects, workspaces, hierarchy_grants) with the section 2.7 exhaustive column sets: child node tables carry no timestamps (renames are audited via events), no owner_id anywhere (section 4.4 - ownership is computed from grants). - Grant constraints per section 3: exactly-one-subject and exactly-one-target num_nonnulls CHECKs, six-column UNIQUE NULLS NOT DISTINCT, target FKs CASCADE / principal FKs RESTRICT, six btree indexes. - Migration 0018 generated by drizzle-kit; SQL verified against the contract text and applied on PGlite. - hierarchy-schema.witness.test.ts: dual-leg witness suite (PGlite always; real PostgreSQL under DATABASE_URL, the section 6.8 binding leg in CI). Covers parent-FK integrity + catalog assertion, slug scoping, column allowlist (6.2), all six grant subject/target forms, CHECK refusals, NULLS NOT DISTINCT duplicates, NOT NULL refusals, and deletion semantics (6.6): fail-closed parent delete, leaf cascade of exactly its grants, principal RESTRICT. - hierarchy-writer-coverage.test.ts: section 6.3(b) three-prong static assertion (alias-aware symbol writes, class-table names in SQL literals, raw-execution primitives) with empty writer allowlist, closed infrastructure register, and closed importer enumerations for the migration runner and migrate-tier. All prongs proven able to fire via a planted-violation control. Command family, audit events, and route inventory land in M4-1b.
63 lines
4.4 KiB
SQL
63 lines
4.4 KiB
SQL
CREATE TABLE "companies" (
|
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
"name" text NOT NULL,
|
|
"slug" text NOT NULL,
|
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
CONSTRAINT "companies_slug_unique" UNIQUE("slug")
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE TABLE "estates" (
|
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
"name" text NOT NULL,
|
|
"slug" text NOT NULL,
|
|
"company_id" uuid NOT NULL,
|
|
CONSTRAINT "estates_company_slug_uniq" UNIQUE("company_id","slug")
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE TABLE "hierarchy_grants" (
|
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
"user_id" text,
|
|
"team_id" uuid,
|
|
"company_id" uuid,
|
|
"estate_id" uuid,
|
|
"platform_project_id" uuid,
|
|
"role" text NOT NULL,
|
|
"granted_by" text NOT NULL,
|
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
CONSTRAINT "hierarchy_grants_subject_target_role_uniq" UNIQUE NULLS NOT DISTINCT("user_id","team_id","company_id","estate_id","platform_project_id","role"),
|
|
CONSTRAINT "hierarchy_grants_subject_check" CHECK (num_nonnulls(user_id, team_id) = 1),
|
|
CONSTRAINT "hierarchy_grants_target_check" CHECK (num_nonnulls(company_id, estate_id, platform_project_id) = 1)
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE TABLE "platform_projects" (
|
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
"name" text NOT NULL,
|
|
"slug" text NOT NULL,
|
|
"estate_id" uuid NOT NULL,
|
|
CONSTRAINT "platform_projects_estate_slug_uniq" UNIQUE("estate_id","slug")
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE TABLE "workspaces" (
|
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
"name" text NOT NULL,
|
|
"slug" text NOT NULL,
|
|
"platform_project_id" uuid NOT NULL,
|
|
CONSTRAINT "workspaces_platform_project_slug_uniq" UNIQUE("platform_project_id","slug")
|
|
);
|
|
--> statement-breakpoint
|
|
ALTER TABLE "estates" ADD CONSTRAINT "estates_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "hierarchy_grants" ADD CONSTRAINT "hierarchy_grants_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "hierarchy_grants" ADD CONSTRAINT "hierarchy_grants_team_id_teams_id_fk" FOREIGN KEY ("team_id") REFERENCES "public"."teams"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "hierarchy_grants" ADD CONSTRAINT "hierarchy_grants_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "hierarchy_grants" ADD CONSTRAINT "hierarchy_grants_estate_id_estates_id_fk" FOREIGN KEY ("estate_id") REFERENCES "public"."estates"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "hierarchy_grants" ADD CONSTRAINT "hierarchy_grants_platform_project_id_platform_projects_id_fk" FOREIGN KEY ("platform_project_id") REFERENCES "public"."platform_projects"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "hierarchy_grants" ADD CONSTRAINT "hierarchy_grants_granted_by_users_id_fk" FOREIGN KEY ("granted_by") REFERENCES "public"."users"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "platform_projects" ADD CONSTRAINT "platform_projects_estate_id_estates_id_fk" FOREIGN KEY ("estate_id") REFERENCES "public"."estates"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "workspaces" ADD CONSTRAINT "workspaces_platform_project_id_platform_projects_id_fk" FOREIGN KEY ("platform_project_id") REFERENCES "public"."platform_projects"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
CREATE INDEX "hierarchy_grants_company_id_idx" ON "hierarchy_grants" USING btree ("company_id");--> statement-breakpoint
|
|
CREATE INDEX "hierarchy_grants_estate_id_idx" ON "hierarchy_grants" USING btree ("estate_id");--> statement-breakpoint
|
|
CREATE INDEX "hierarchy_grants_platform_project_id_idx" ON "hierarchy_grants" USING btree ("platform_project_id");--> statement-breakpoint
|
|
CREATE INDEX "hierarchy_grants_user_id_idx" ON "hierarchy_grants" USING btree ("user_id");--> statement-breakpoint
|
|
CREATE INDEX "hierarchy_grants_team_id_idx" ON "hierarchy_grants" USING btree ("team_id");--> statement-breakpoint
|
|
CREATE INDEX "hierarchy_grants_granted_by_idx" ON "hierarchy_grants" USING btree ("granted_by"); |