This commit is contained in:
@@ -0,0 +1,511 @@
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "audit_events" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"occurred_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"actor_user_id" uuid,
|
||||
"workspace_id" uuid,
|
||||
"action" text NOT NULL,
|
||||
"resource_type" text NOT NULL,
|
||||
"resource_id" text,
|
||||
"request_id" text,
|
||||
"outcome" text NOT NULL,
|
||||
"metadata_json" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
CONSTRAINT "audit_events_outcome_check" CHECK ("audit_events"."outcome" in ('success', 'denied', 'failed'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "auth_sessions" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"token_hash" text NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"last_seen_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"idle_expires_at" timestamp with time zone NOT NULL,
|
||||
"absolute_expires_at" timestamp with time zone NOT NULL,
|
||||
"revoked_at" timestamp with time zone,
|
||||
"source_ip_hash" text,
|
||||
"user_agent_summary" text,
|
||||
CONSTRAINT "auth_sessions_token_hash_uq" UNIQUE("token_hash")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "collection_items" (
|
||||
"collection_id" uuid NOT NULL,
|
||||
"playbook_id" uuid NOT NULL,
|
||||
"position" integer DEFAULT 0 NOT NULL,
|
||||
"added_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "collection_items_pkey" PRIMARY KEY("collection_id","playbook_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "collections" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"workspace_id" uuid NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"description" text DEFAULT '' NOT NULL,
|
||||
"created_by" uuid NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "collections_workspace_name_uq" UNIQUE("workspace_id","name")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "composition_drafts" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"workspace_id" uuid NOT NULL,
|
||||
"playbook_version_id" uuid NOT NULL,
|
||||
"repository_profile_revision_id" uuid,
|
||||
"input_json" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
"scope_override_json" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
"autonomy_level" text NOT NULL,
|
||||
"work_mode" text NOT NULL,
|
||||
"last_render_digest" text,
|
||||
"created_by" uuid NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "evaluation_cases" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"playbook_version_id" uuid NOT NULL,
|
||||
"logical_case_id" text NOT NULL,
|
||||
"fixture_version" text NOT NULL,
|
||||
"case_json" jsonb NOT NULL,
|
||||
"case_digest" text NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "evaluation_cases_identity_uq" UNIQUE("playbook_version_id","logical_case_id","fixture_version")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "evaluation_results" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"evaluation_case_id" uuid NOT NULL,
|
||||
"environment_json" jsonb NOT NULL,
|
||||
"status" text NOT NULL,
|
||||
"dimension_scores_json" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
"evidence_artifact_id" uuid,
|
||||
"executed_by" uuid,
|
||||
"executed_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "evaluation_results_status_check" CHECK ("evaluation_results"."status" in ('passed', 'failed', 'error', 'skipped', 'stale'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "favorites" (
|
||||
"workspace_id" uuid NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"playbook_id" uuid NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "favorites_pkey" PRIMARY KEY("workspace_id","user_id","playbook_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "generated_artifacts" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"run_id" uuid NOT NULL,
|
||||
"artifact_type" text NOT NULL,
|
||||
"storage_key" text NOT NULL,
|
||||
"filename" text NOT NULL,
|
||||
"media_type" text NOT NULL,
|
||||
"size_bytes" bigint NOT NULL,
|
||||
"sha256" text NOT NULL,
|
||||
"expires_at" timestamp with time zone,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "generated_artifacts_storage_key_uq" UNIQUE("storage_key"),
|
||||
CONSTRAINT "generated_artifacts_type_check" CHECK ("generated_artifacts"."artifact_type" in ('prompt_text', 'markdown', 'run_pack_zip', 'agents_suggestion', 'support_bundle')),
|
||||
CONSTRAINT "generated_artifacts_size_check" CHECK ("generated_artifacts"."size_bytes" >= 0)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "generated_runs" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"workspace_id" uuid NOT NULL,
|
||||
"source_draft_id" uuid,
|
||||
"playbook_version_id" uuid NOT NULL,
|
||||
"playbook_snapshot_json" jsonb NOT NULL,
|
||||
"repository_profile_snapshot_json" jsonb,
|
||||
"normalized_input_json" jsonb NOT NULL,
|
||||
"policy_snapshot_json" jsonb NOT NULL,
|
||||
"provenance_json" jsonb NOT NULL,
|
||||
"lint_result_json" jsonb NOT NULL,
|
||||
"rendered_prompt" text NOT NULL,
|
||||
"render_digest" text NOT NULL,
|
||||
"idempotency_key" text,
|
||||
"generated_by" uuid NOT NULL,
|
||||
"generated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "generated_runs_workspace_idempotency_uq" UNIQUE("workspace_id","idempotency_key")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "instance_settings" (
|
||||
"singleton" boolean PRIMARY KEY DEFAULT true NOT NULL,
|
||||
"setup_completed_at" timestamp with time zone,
|
||||
"owner_user_id" uuid,
|
||||
"config_json" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
"config_digest" text,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "instance_settings_singleton_check" CHECK ("instance_settings"."singleton")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "integration_secrets" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"integration_id" uuid NOT NULL,
|
||||
"secret_kind" text NOT NULL,
|
||||
"envelope_version" integer NOT NULL,
|
||||
"key_version" text NOT NULL,
|
||||
"nonce" bytea NOT NULL,
|
||||
"ciphertext" bytea NOT NULL,
|
||||
"auth_tag" bytea NOT NULL,
|
||||
"last_four" text,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"rotated_at" timestamp with time zone,
|
||||
CONSTRAINT "integration_secrets_integration_kind_uq" UNIQUE("integration_id","secret_kind")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "integrations" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"workspace_id" uuid NOT NULL,
|
||||
"type" text NOT NULL,
|
||||
"display_name" text NOT NULL,
|
||||
"base_url" text NOT NULL,
|
||||
"status" text DEFAULT 'configured' NOT NULL,
|
||||
"capabilities_json" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
"last_checked_at" timestamp with time zone,
|
||||
"created_by" uuid NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "integrations_workspace_type_base_url_uq" UNIQUE("workspace_id","type","base_url"),
|
||||
CONSTRAINT "integrations_type_check" CHECK ("integrations"."type" in ('gitea')),
|
||||
CONSTRAINT "integrations_status_check" CHECK ("integrations"."status" in ('configured', 'healthy', 'degraded', 'disabled'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "invitations" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"email" text NOT NULL,
|
||||
"token_hash" text NOT NULL,
|
||||
"instance_role" text NOT NULL,
|
||||
"workspace_id" uuid,
|
||||
"workspace_role" text,
|
||||
"expires_at" timestamp with time zone NOT NULL,
|
||||
"accepted_at" timestamp with time zone,
|
||||
"created_by" uuid NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "invitations_token_hash_uq" UNIQUE("token_hash"),
|
||||
CONSTRAINT "invitations_instance_role_check" CHECK ("invitations"."instance_role" in ('instance_admin', 'user')),
|
||||
CONSTRAINT "invitations_workspace_role_check" CHECK ("invitations"."workspace_role" is null or "invitations"."workspace_role" in ('owner', 'editor', 'viewer'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "jobs" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"workspace_id" uuid,
|
||||
"type" text NOT NULL,
|
||||
"state" text NOT NULL,
|
||||
"idempotency_key" text,
|
||||
"payload_json" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
"progress_json" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
"attempt_count" integer DEFAULT 0 NOT NULL,
|
||||
"max_attempts" integer DEFAULT 3 NOT NULL,
|
||||
"lease_owner" text,
|
||||
"lease_expires_at" timestamp with time zone,
|
||||
"available_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"started_at" timestamp with time zone,
|
||||
"finished_at" timestamp with time zone,
|
||||
"error_code" text,
|
||||
"error_detail_redacted" text,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "jobs_state_check" CHECK ("jobs"."state" in ('queued', 'running', 'succeeded', 'failed', 'cancelled')),
|
||||
CONSTRAINT "jobs_attempt_count_check" CHECK ("jobs"."attempt_count" >= 0),
|
||||
CONSTRAINT "jobs_max_attempts_check" CHECK ("jobs"."max_attempts" > 0)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "password_reset_tokens" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"token_hash" text NOT NULL,
|
||||
"expires_at" timestamp with time zone NOT NULL,
|
||||
"used_at" timestamp with time zone,
|
||||
"created_by" uuid,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "password_reset_tokens_token_hash_uq" UNIQUE("token_hash")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "playbook_versions" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"playbook_id" uuid NOT NULL,
|
||||
"semantic_version" text NOT NULL,
|
||||
"lifecycle" text NOT NULL,
|
||||
"package_api_version" text NOT NULL,
|
||||
"title" text NOT NULL,
|
||||
"summary" text NOT NULL,
|
||||
"category" text NOT NULL,
|
||||
"risk_tier" text NOT NULL,
|
||||
"package_json" jsonb NOT NULL,
|
||||
"template_text" text NOT NULL,
|
||||
"content_digest" text NOT NULL,
|
||||
"search_document" tsvector,
|
||||
"published_at" timestamp with time zone,
|
||||
"supersedes_version_id" uuid,
|
||||
"created_by" uuid,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "playbook_versions_playbook_semver_uq" UNIQUE("playbook_id","semantic_version"),
|
||||
CONSTRAINT "playbook_versions_lifecycle_check" CHECK ("playbook_versions"."lifecycle" in ('draft', 'reviewed', 'validated', 'battle-tested', 'deprecated')),
|
||||
CONSTRAINT "playbook_versions_risk_tier_check" CHECK ("playbook_versions"."risk_tier" in ('low', 'moderate', 'high', 'critical'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "playbooks" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"workspace_id" uuid,
|
||||
"logical_id" text NOT NULL,
|
||||
"slug" text NOT NULL,
|
||||
"namespace" text NOT NULL,
|
||||
"source_type" text NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "playbooks_namespace_logical_id_uq" UNIQUE("namespace","logical_id"),
|
||||
CONSTRAINT "playbooks_namespace_slug_uq" UNIQUE("namespace","slug"),
|
||||
CONSTRAINT "playbooks_source_type_check" CHECK ("playbooks"."source_type" in ('built_in', 'private', 'imported', 'remote_registry'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "repositories" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"workspace_id" uuid NOT NULL,
|
||||
"display_name" text NOT NULL,
|
||||
"source_type" text NOT NULL,
|
||||
"external_owner" text,
|
||||
"external_name" text,
|
||||
"external_id" text,
|
||||
"integration_id" uuid,
|
||||
"default_branch" text,
|
||||
"archived" boolean DEFAULT false NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "repositories_source_type_check" CHECK ("repositories"."source_type" in ('manual', 'gitea'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "repository_findings" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"snapshot_id" uuid NOT NULL,
|
||||
"rule_id" text NOT NULL,
|
||||
"severity" text NOT NULL,
|
||||
"title" text NOT NULL,
|
||||
"rationale" text NOT NULL,
|
||||
"evidence_pointer" text NOT NULL,
|
||||
"recommended_playbook_slug" text,
|
||||
"status" text DEFAULT 'open' NOT NULL,
|
||||
"resolution_note" text,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "repository_findings_evidence_uq" UNIQUE("snapshot_id","rule_id","evidence_pointer"),
|
||||
CONSTRAINT "repository_findings_severity_check" CHECK ("repository_findings"."severity" in ('info', 'low', 'medium', 'high', 'critical')),
|
||||
CONSTRAINT "repository_findings_status_check" CHECK ("repository_findings"."status" in ('open', 'dismissed', 'resolved'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "repository_profile_revisions" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"repository_id" uuid NOT NULL,
|
||||
"revision_number" integer NOT NULL,
|
||||
"profile_json" jsonb NOT NULL,
|
||||
"source_snapshot_id" uuid,
|
||||
"content_digest" text NOT NULL,
|
||||
"created_by" uuid NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "repository_profile_revisions_repository_number_uq" UNIQUE("repository_id","revision_number"),
|
||||
CONSTRAINT "repository_profile_revisions_repository_digest_uq" UNIQUE("repository_id","content_digest")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "repository_snapshots" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"repository_id" uuid NOT NULL,
|
||||
"integration_id" uuid,
|
||||
"state" text NOT NULL,
|
||||
"captured_at" timestamp with time zone,
|
||||
"capability_snapshot_json" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
"evidence_json" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
"evidence_digest" text,
|
||||
"sync_job_id" uuid,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "repository_snapshots_state_check" CHECK ("repository_snapshots"."state" in ('collecting', 'complete', 'failed', 'cancelled'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "run_feedback" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"run_id" uuid NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"rating" text,
|
||||
"notes" text DEFAULT '' NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "run_feedback_run_user_uq" UNIQUE("run_id","user_id"),
|
||||
CONSTRAINT "run_feedback_rating_check" CHECK ("run_feedback"."rating" is null or "run_feedback"."rating" in ('helpful', 'mixed', 'unhelpful'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "users" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"email" text NOT NULL,
|
||||
"display_name" text NOT NULL,
|
||||
"password_hash" text NOT NULL,
|
||||
"instance_role" text NOT NULL,
|
||||
"status" text DEFAULT 'active' NOT NULL,
|
||||
"password_changed_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"deleted_at" timestamp with time zone,
|
||||
CONSTRAINT "users_instance_role_check" CHECK ("users"."instance_role" in ('instance_owner', 'instance_admin', 'user')),
|
||||
CONSTRAINT "users_status_check" CHECK ("users"."status" in ('active', 'disabled', 'pending_deletion'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "workspace_memberships" (
|
||||
"workspace_id" uuid NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"role" text NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "workspace_memberships_pkey" PRIMARY KEY("workspace_id","user_id"),
|
||||
CONSTRAINT "workspace_memberships_role_check" CHECK ("workspace_memberships"."role" in ('owner', 'editor', 'viewer'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "workspaces" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"type" text DEFAULT 'personal' NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"deleted_at" timestamp with time zone,
|
||||
CONSTRAINT "workspaces_type_check" CHECK ("workspaces"."type" in ('personal', 'team'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "audit_events" ADD CONSTRAINT "audit_events_actor_user_fk" FOREIGN KEY ("actor_user_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "audit_events" ADD CONSTRAINT "audit_events_workspace_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "auth_sessions" ADD CONSTRAINT "auth_sessions_user_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_collection_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."collections"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_playbook_fk" FOREIGN KEY ("playbook_id") REFERENCES "public"."playbooks"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "collections" ADD CONSTRAINT "collections_workspace_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "collections" ADD CONSTRAINT "collections_created_by_fk" FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "composition_drafts" ADD CONSTRAINT "composition_drafts_workspace_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "composition_drafts" ADD CONSTRAINT "composition_drafts_playbook_version_fk" FOREIGN KEY ("playbook_version_id") REFERENCES "public"."playbook_versions"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "composition_drafts" ADD CONSTRAINT "composition_drafts_profile_revision_fk" FOREIGN KEY ("repository_profile_revision_id") REFERENCES "public"."repository_profile_revisions"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "composition_drafts" ADD CONSTRAINT "composition_drafts_created_by_fk" FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_cases" ADD CONSTRAINT "evaluation_cases_playbook_version_fk" FOREIGN KEY ("playbook_version_id") REFERENCES "public"."playbook_versions"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_results" ADD CONSTRAINT "evaluation_results_case_fk" FOREIGN KEY ("evaluation_case_id") REFERENCES "public"."evaluation_cases"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_results" ADD CONSTRAINT "evaluation_results_artifact_fk" FOREIGN KEY ("evidence_artifact_id") REFERENCES "public"."generated_artifacts"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_results" ADD CONSTRAINT "evaluation_results_executed_by_fk" FOREIGN KEY ("executed_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "favorites" ADD CONSTRAINT "favorites_workspace_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "favorites" ADD CONSTRAINT "favorites_user_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "favorites" ADD CONSTRAINT "favorites_playbook_fk" FOREIGN KEY ("playbook_id") REFERENCES "public"."playbooks"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "generated_artifacts" ADD CONSTRAINT "generated_artifacts_run_fk" FOREIGN KEY ("run_id") REFERENCES "public"."generated_runs"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "generated_runs" ADD CONSTRAINT "generated_runs_workspace_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "generated_runs" ADD CONSTRAINT "generated_runs_source_draft_fk" FOREIGN KEY ("source_draft_id") REFERENCES "public"."composition_drafts"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "generated_runs" ADD CONSTRAINT "generated_runs_playbook_version_fk" FOREIGN KEY ("playbook_version_id") REFERENCES "public"."playbook_versions"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "generated_runs" ADD CONSTRAINT "generated_runs_generated_by_fk" FOREIGN KEY ("generated_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "instance_settings" ADD CONSTRAINT "instance_settings_owner_user_fk" FOREIGN KEY ("owner_user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "integration_secrets" ADD CONSTRAINT "integration_secrets_integration_fk" FOREIGN KEY ("integration_id") REFERENCES "public"."integrations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "integrations" ADD CONSTRAINT "integrations_workspace_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "integrations" ADD CONSTRAINT "integrations_created_by_fk" FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "invitations" ADD CONSTRAINT "invitations_workspace_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "invitations" ADD CONSTRAINT "invitations_created_by_fk" FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "jobs" ADD CONSTRAINT "jobs_workspace_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "password_reset_tokens" ADD CONSTRAINT "password_reset_tokens_user_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "password_reset_tokens" ADD CONSTRAINT "password_reset_tokens_created_by_fk" FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "playbook_versions" ADD CONSTRAINT "playbook_versions_playbook_fk" FOREIGN KEY ("playbook_id") REFERENCES "public"."playbooks"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "playbook_versions" ADD CONSTRAINT "playbook_versions_supersedes_fk" FOREIGN KEY ("supersedes_version_id") REFERENCES "public"."playbook_versions"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "playbook_versions" ADD CONSTRAINT "playbook_versions_created_by_fk" FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "playbooks" ADD CONSTRAINT "playbooks_workspace_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "repositories" ADD CONSTRAINT "repositories_workspace_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "repositories" ADD CONSTRAINT "repositories_integration_fk" FOREIGN KEY ("integration_id") REFERENCES "public"."integrations"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "repository_findings" ADD CONSTRAINT "repository_findings_snapshot_fk" FOREIGN KEY ("snapshot_id") REFERENCES "public"."repository_snapshots"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "repository_profile_revisions" ADD CONSTRAINT "repository_profile_revisions_repository_fk" FOREIGN KEY ("repository_id") REFERENCES "public"."repositories"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "repository_profile_revisions" ADD CONSTRAINT "repository_profile_revisions_snapshot_fk" FOREIGN KEY ("source_snapshot_id") REFERENCES "public"."repository_snapshots"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "repository_profile_revisions" ADD CONSTRAINT "repository_profile_revisions_created_by_fk" FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "repository_snapshots" ADD CONSTRAINT "repository_snapshots_repository_fk" FOREIGN KEY ("repository_id") REFERENCES "public"."repositories"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "repository_snapshots" ADD CONSTRAINT "repository_snapshots_integration_fk" FOREIGN KEY ("integration_id") REFERENCES "public"."integrations"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "repository_snapshots" ADD CONSTRAINT "repository_snapshots_job_fk" FOREIGN KEY ("sync_job_id") REFERENCES "public"."jobs"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "run_feedback" ADD CONSTRAINT "run_feedback_run_fk" FOREIGN KEY ("run_id") REFERENCES "public"."generated_runs"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "run_feedback" ADD CONSTRAINT "run_feedback_user_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "workspace_memberships" ADD CONSTRAINT "workspace_memberships_workspace_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "workspace_memberships" ADD CONSTRAINT "workspace_memberships_user_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX "audit_events_workspace_time_idx" ON "audit_events" USING btree ("workspace_id","occurred_at" DESC NULLS LAST);--> statement-breakpoint
|
||||
CREATE INDEX "audit_events_action_time_idx" ON "audit_events" USING btree ("action","occurred_at" DESC NULLS LAST);--> statement-breakpoint
|
||||
CREATE INDEX "auth_sessions_user_active_idx" ON "auth_sessions" USING btree ("user_id","absolute_expires_at") WHERE "auth_sessions"."revoked_at" is null;--> statement-breakpoint
|
||||
CREATE INDEX "composition_drafts_workspace_updated_idx" ON "composition_drafts" USING btree ("workspace_id","updated_at" DESC NULLS LAST);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "generated_runs_digest_actor_uq" ON "generated_runs" USING btree ("workspace_id","generated_by","render_digest","generated_at");--> statement-breakpoint
|
||||
CREATE INDEX "generated_runs_workspace_time_idx" ON "generated_runs" USING btree ("workspace_id","generated_at" DESC NULLS LAST);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "jobs_workspace_type_idempotency_uq" ON "jobs" USING btree ("workspace_id","type","idempotency_key") WHERE "jobs"."workspace_id" is not null and "jobs"."idempotency_key" is not null;--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "jobs_global_type_idempotency_uq" ON "jobs" USING btree ("type","idempotency_key") WHERE "jobs"."workspace_id" is null and "jobs"."idempotency_key" is not null;--> statement-breakpoint
|
||||
CREATE INDEX "jobs_claim_idx" ON "jobs" USING btree ("state","available_at","created_at") WHERE "jobs"."state" = 'queued';--> statement-breakpoint
|
||||
CREATE INDEX "jobs_lease_idx" ON "jobs" USING btree ("state","lease_expires_at") WHERE "jobs"."state" = 'running';--> statement-breakpoint
|
||||
CREATE INDEX "playbook_versions_search_idx" ON "playbook_versions" USING gin ("search_document");--> statement-breakpoint
|
||||
CREATE INDEX "playbook_versions_filters_idx" ON "playbook_versions" USING btree ("category","risk_tier","lifecycle","published_at" DESC NULLS LAST);--> statement-breakpoint
|
||||
CREATE INDEX "playbooks_workspace_idx" ON "playbooks" USING btree ("workspace_id");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "repositories_external_uq" ON "repositories" USING btree ("workspace_id","integration_id","external_id") WHERE "repositories"."external_id" is not null;--> statement-breakpoint
|
||||
CREATE INDEX "repository_snapshots_repo_time_idx" ON "repository_snapshots" USING btree ("repository_id","captured_at" DESC NULLS LAST);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "users_email_ci_uq" ON "users" USING btree (lower("email")) WHERE "users"."deleted_at" is null;--> statement-breakpoint
|
||||
CREATE INDEX "workspace_memberships_user_idx" ON "workspace_memberships" USING btree ("user_id");
|
||||
--> statement-breakpoint
|
||||
-- The singleton exists before setup so concurrent callers have a stable row to
|
||||
-- inspect after taking the transaction-scoped advisory lock.
|
||||
INSERT INTO "instance_settings" ("singleton") VALUES (true)
|
||||
ON CONFLICT ("singleton") DO NOTHING;
|
||||
--> statement-breakpoint
|
||||
CREATE FUNCTION devrunbook_try_setup_advisory_lock()
|
||||
RETURNS boolean
|
||||
LANGUAGE sql
|
||||
VOLATILE
|
||||
PARALLEL UNSAFE
|
||||
AS $$
|
||||
SELECT pg_try_advisory_xact_lock(hashtextextended('devrunbook:first-run-setup', 0));
|
||||
$$;
|
||||
--> statement-breakpoint
|
||||
COMMENT ON FUNCTION devrunbook_try_setup_advisory_lock() IS
|
||||
'Acquire the transaction-scoped first-run setup lock; call inside the setup transaction.';
|
||||
--> statement-breakpoint
|
||||
CREATE FUNCTION devrunbook_reject_immutable_update()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
-- Allow PostgreSQL referential actions (for example ON DELETE SET NULL) to
|
||||
-- preserve the deletion contract while rejecting direct application writes.
|
||||
IF pg_trigger_depth() > 1 THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
RAISE EXCEPTION USING
|
||||
ERRCODE = '55000',
|
||||
MESSAGE = format('%I is immutable', TG_TABLE_NAME);
|
||||
END;
|
||||
$$;
|
||||
--> statement-breakpoint
|
||||
CREATE FUNCTION devrunbook_reject_append_only_mutation()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
IF pg_trigger_depth() > 1 THEN
|
||||
RETURN CASE WHEN TG_OP = 'DELETE' THEN OLD ELSE NEW END;
|
||||
END IF;
|
||||
RAISE EXCEPTION USING
|
||||
ERRCODE = '55000',
|
||||
MESSAGE = format('%I is append-only', TG_TABLE_NAME);
|
||||
END;
|
||||
$$;
|
||||
--> statement-breakpoint
|
||||
CREATE TRIGGER playbook_versions_published_immutable_trg
|
||||
BEFORE UPDATE ON "playbook_versions"
|
||||
FOR EACH ROW
|
||||
WHEN (OLD."published_at" IS NOT NULL)
|
||||
EXECUTE FUNCTION devrunbook_reject_immutable_update();
|
||||
--> statement-breakpoint
|
||||
CREATE TRIGGER repository_profile_revisions_immutable_trg
|
||||
BEFORE UPDATE ON "repository_profile_revisions"
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION devrunbook_reject_immutable_update();
|
||||
--> statement-breakpoint
|
||||
CREATE TRIGGER repository_snapshots_complete_immutable_trg
|
||||
BEFORE UPDATE ON "repository_snapshots"
|
||||
FOR EACH ROW
|
||||
WHEN (OLD."state" = 'complete')
|
||||
EXECUTE FUNCTION devrunbook_reject_immutable_update();
|
||||
--> statement-breakpoint
|
||||
CREATE TRIGGER generated_runs_immutable_trg
|
||||
BEFORE UPDATE ON "generated_runs"
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION devrunbook_reject_immutable_update();
|
||||
--> statement-breakpoint
|
||||
CREATE TRIGGER evaluation_results_immutable_trg
|
||||
BEFORE UPDATE ON "evaluation_results"
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION devrunbook_reject_immutable_update();
|
||||
--> statement-breakpoint
|
||||
CREATE TRIGGER audit_events_append_only_trg
|
||||
BEFORE UPDATE OR DELETE ON "audit_events"
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION devrunbook_reject_append_only_mutation();
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE "users" ADD COLUMN "email_verified" boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "users" ADD COLUMN "image" text;
|
||||
@@ -0,0 +1,3 @@
|
||||
CREATE INDEX "repositories_workspace_updated_idx" ON "repositories" USING btree ("workspace_id","archived","updated_at" DESC NULLS LAST,"id");--> statement-breakpoint
|
||||
ALTER TABLE "repository_profile_revisions" ADD CONSTRAINT "repository_profile_revisions_revision_positive_check" CHECK ("repository_profile_revisions"."revision_number" > 0);--> statement-breakpoint
|
||||
ALTER TABLE "repository_profile_revisions" ADD CONSTRAINT "repository_profile_revisions_content_digest_check" CHECK ("repository_profile_revisions"."content_digest" ~ '^[0-9a-f]{64}$');
|
||||
@@ -0,0 +1,11 @@
|
||||
ALTER TABLE "composition_drafts" ADD COLUMN "policy_override_json" jsonb DEFAULT '{}'::jsonb NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "composition_drafts" ADD COLUMN "output_format" text DEFAULT 'prompt' NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "composition_drafts" ADD COLUMN "revision" integer DEFAULT 1 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "composition_drafts" ADD CONSTRAINT "composition_drafts_revision_positive_check" CHECK ("composition_drafts"."revision" > 0);--> statement-breakpoint
|
||||
ALTER TABLE "composition_drafts" ADD CONSTRAINT "composition_drafts_autonomy_check" CHECK ("composition_drafts"."autonomy_level" in ('observe', 'diagnose', 'plan', 'implement', 'verify', 'repair'));--> statement-breakpoint
|
||||
ALTER TABLE "composition_drafts" ADD CONSTRAINT "composition_drafts_work_mode_check" CHECK ("composition_drafts"."work_mode" in ('inspect', 'plan', 'guided', 'execute', 'recovery'));--> statement-breakpoint
|
||||
ALTER TABLE "composition_drafts" ADD CONSTRAINT "composition_drafts_output_format_check" CHECK ("composition_drafts"."output_format" in ('prompt', 'markdown', 'run-pack'));--> statement-breakpoint
|
||||
ALTER TABLE "composition_drafts" ADD CONSTRAINT "composition_drafts_last_render_digest_check" CHECK ("composition_drafts"."last_render_digest" is null or "composition_drafts"."last_render_digest" ~ '^[0-9a-f]{64}$');--> statement-breakpoint
|
||||
ALTER TABLE "generated_runs" ADD CONSTRAINT "generated_runs_render_digest_check" CHECK ("generated_runs"."render_digest" ~ '^[0-9a-f]{64}$');--> statement-breakpoint
|
||||
ALTER TABLE "generated_runs" ALTER COLUMN "idempotency_key" SET NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "generated_runs" ADD CONSTRAINT "generated_runs_idempotency_key_check" CHECK (length("generated_runs"."idempotency_key") between 1 and 255 and btrim("generated_runs"."idempotency_key") = "generated_runs"."idempotency_key");
|
||||
@@ -0,0 +1,19 @@
|
||||
ALTER TABLE "integrations" ADD COLUMN "allow_private_http" boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "integrations" ADD COLUMN "request_timeout_ms" integer DEFAULT 15000 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "integrations" ADD COLUMN "server_version" text;--> statement-breakpoint
|
||||
ALTER TABLE "integrations" ADD COLUMN "remote_identity_id" text;--> statement-breakpoint
|
||||
ALTER TABLE "integrations" ADD COLUMN "remote_identity_login" text;--> statement-breakpoint
|
||||
ALTER TABLE "integrations" ADD COLUMN "health_code" text;--> statement-breakpoint
|
||||
CREATE INDEX "integrations_workspace_status_idx" ON "integrations" USING btree ("workspace_id","status","updated_at" DESC NULLS LAST);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "repository_snapshots_sync_job_uq" ON "repository_snapshots" USING btree ("sync_job_id") WHERE "repository_snapshots"."sync_job_id" is not null;--> statement-breakpoint
|
||||
CREATE INDEX "repository_snapshots_integration_state_idx" ON "repository_snapshots" USING btree ("integration_id","state","created_at" DESC NULLS LAST);--> statement-breakpoint
|
||||
ALTER TABLE "integration_secrets" ADD CONSTRAINT "integration_secrets_envelope_version_check" CHECK ("integration_secrets"."envelope_version" = 1);--> statement-breakpoint
|
||||
ALTER TABLE "integration_secrets" ADD CONSTRAINT "integration_secrets_key_version_check" CHECK (length(btrim("integration_secrets"."key_version")) between 1 and 64);--> statement-breakpoint
|
||||
ALTER TABLE "integration_secrets" ADD CONSTRAINT "integration_secrets_secret_kind_check" CHECK ("integration_secrets"."secret_kind" = 'access_token');--> statement-breakpoint
|
||||
ALTER TABLE "integration_secrets" ADD CONSTRAINT "integration_secrets_nonce_length_check" CHECK (octet_length("integration_secrets"."nonce") = 12);--> statement-breakpoint
|
||||
ALTER TABLE "integration_secrets" ADD CONSTRAINT "integration_secrets_auth_tag_length_check" CHECK (octet_length("integration_secrets"."auth_tag") = 16);--> statement-breakpoint
|
||||
ALTER TABLE "integration_secrets" ADD CONSTRAINT "integration_secrets_last_four_check" CHECK ("integration_secrets"."last_four" is null or length("integration_secrets"."last_four") = 4);--> statement-breakpoint
|
||||
ALTER TABLE "integrations" ADD CONSTRAINT "integrations_request_timeout_check" CHECK ("integrations"."request_timeout_ms" between 1000 and 60000);--> statement-breakpoint
|
||||
ALTER TABLE "integrations" ADD CONSTRAINT "integrations_remote_identity_check" CHECK (("integrations"."remote_identity_id" is null) = ("integrations"."remote_identity_login" is null));--> statement-breakpoint
|
||||
ALTER TABLE "integrations" ADD CONSTRAINT "integrations_health_code_check" CHECK ("integrations"."health_code" is null or "integrations"."health_code" in ('AUTH_INVALID', 'PERMISSION_MISSING', 'CAPABILITY_UNSUPPORTED', 'RATE_LIMITED', 'NETWORK_BLOCKED', 'TLS_ERROR', 'REMOTE_UNAVAILABLE', 'CONTENT_TOO_LARGE'));--> statement-breakpoint
|
||||
ALTER TABLE "repository_snapshots" ADD CONSTRAINT "repository_snapshots_complete_integrity_check" CHECK ("repository_snapshots"."state" <> 'complete' or ("repository_snapshots"."captured_at" is not null and "repository_snapshots"."evidence_digest" ~ '^[0-9a-f]{64}$'));
|
||||
@@ -0,0 +1,74 @@
|
||||
CREATE TABLE "playbook_package_files" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"playbook_version_id" uuid NOT NULL,
|
||||
"path" text NOT NULL,
|
||||
"role" text NOT NULL,
|
||||
"content" "bytea" NOT NULL,
|
||||
"size_bytes" bigint NOT NULL,
|
||||
"sha256" text NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "playbook_package_files_version_path_uq" UNIQUE("playbook_version_id","path"),
|
||||
CONSTRAINT "playbook_package_files_path_check" CHECK (length("playbook_package_files"."path") between 1 and 512 and "playbook_package_files"."path" = btrim("playbook_package_files"."path") and "playbook_package_files"."path" !~ '(^/|\\|//|(^|/)\.\.?(/|$))'),
|
||||
CONSTRAINT "playbook_package_files_role_check" CHECK ("playbook_package_files"."role" in ('manifest', 'template', 'partial', 'documentation', 'changelog', 'example', 'evaluation', 'resource', 'run-pack-resource')),
|
||||
CONSTRAINT "playbook_package_files_size_check" CHECK ("playbook_package_files"."size_bytes" between 0 and 5242880 and octet_length("playbook_package_files"."content") = "playbook_package_files"."size_bytes"),
|
||||
CONSTRAINT "playbook_package_files_sha256_check" CHECK ("playbook_package_files"."sha256" ~ '^[0-9a-f]{64}$' and encode(digest("playbook_package_files"."content", 'sha256'), 'hex') = "playbook_package_files"."sha256")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "playbook_versions" ADD COLUMN "draft_revision" integer DEFAULT 1 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "playbook_versions" ADD COLUMN "draft_digest" text DEFAULT repeat('0', 64) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "playbook_versions" ADD COLUMN "draft_validation_json" jsonb DEFAULT '{"valid":true,"issues":[]}'::jsonb NOT NULL;--> statement-breakpoint
|
||||
DROP TRIGGER "playbook_versions_published_immutable_trg" ON "playbook_versions";--> statement-breakpoint
|
||||
UPDATE "playbook_versions" SET "draft_digest" = "content_digest";--> statement-breakpoint
|
||||
CREATE TRIGGER playbook_versions_published_immutable_trg
|
||||
BEFORE UPDATE ON "playbook_versions"
|
||||
FOR EACH ROW
|
||||
WHEN (OLD."published_at" IS NOT NULL)
|
||||
EXECUTE FUNCTION devrunbook_reject_immutable_update();--> statement-breakpoint
|
||||
ALTER TABLE "playbook_package_files" ADD CONSTRAINT "playbook_package_files_version_fk" FOREIGN KEY ("playbook_version_id") REFERENCES "public"."playbook_versions"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX "playbook_package_files_version_idx" ON "playbook_package_files" USING btree ("playbook_version_id");--> statement-breakpoint
|
||||
ALTER TABLE "playbook_versions" ADD CONSTRAINT "playbook_versions_draft_revision_check" CHECK ("playbook_versions"."draft_revision" > 0);--> statement-breakpoint
|
||||
ALTER TABLE "playbook_versions" ADD CONSTRAINT "playbook_versions_draft_digest_check" CHECK ("playbook_versions"."draft_digest" ~ '^[0-9a-f]{64}$');--> statement-breakpoint
|
||||
ALTER TABLE "playbook_versions" ADD CONSTRAINT "playbook_versions_draft_validation_check" CHECK (jsonb_typeof("playbook_versions"."draft_validation_json") = 'object');--> statement-breakpoint
|
||||
CREATE FUNCTION normalize_playbook_version_draft_digest() RETURNS trigger
|
||||
LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
IF NEW.draft_digest = repeat('0', 64) THEN
|
||||
NEW.draft_digest := NEW.content_digest;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;--> statement-breakpoint
|
||||
CREATE TRIGGER playbook_versions_normalize_draft_digest
|
||||
BEFORE INSERT ON playbook_versions
|
||||
FOR EACH ROW EXECUTE FUNCTION normalize_playbook_version_draft_digest();--> statement-breakpoint
|
||||
CREATE FUNCTION reject_published_playbook_file_mutation() RETURNS trigger
|
||||
LANGUAGE plpgsql AS $$
|
||||
DECLARE
|
||||
target_version_id uuid;
|
||||
target_published_at timestamptz;
|
||||
BEGIN
|
||||
target_version_id := CASE WHEN TG_OP = 'DELETE' THEN OLD.playbook_version_id ELSE NEW.playbook_version_id END;
|
||||
SELECT published_at INTO target_published_at
|
||||
FROM playbook_versions
|
||||
WHERE id = target_version_id
|
||||
FOR SHARE;
|
||||
IF target_published_at IS NOT NULL THEN
|
||||
RAISE EXCEPTION 'published playbook package files are immutable'
|
||||
USING ERRCODE = '55000';
|
||||
END IF;
|
||||
IF TG_OP = 'UPDATE' AND OLD.playbook_version_id <> NEW.playbook_version_id THEN
|
||||
SELECT published_at INTO target_published_at
|
||||
FROM playbook_versions
|
||||
WHERE id = OLD.playbook_version_id
|
||||
FOR SHARE;
|
||||
IF target_published_at IS NOT NULL THEN
|
||||
RAISE EXCEPTION 'published playbook package files are immutable'
|
||||
USING ERRCODE = '55000';
|
||||
END IF;
|
||||
END IF;
|
||||
RETURN CASE WHEN TG_OP = 'DELETE' THEN OLD ELSE NEW END;
|
||||
END;
|
||||
$$;--> statement-breakpoint
|
||||
CREATE TRIGGER playbook_package_files_immutable_when_published
|
||||
BEFORE INSERT OR UPDATE OR DELETE ON playbook_package_files
|
||||
FOR EACH ROW EXECUTE FUNCTION reject_published_playbook_file_mutation();
|
||||
@@ -0,0 +1,38 @@
|
||||
CREATE TABLE "playbook_review_attestations" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"playbook_version_id" uuid NOT NULL,
|
||||
"reviewed_by" uuid NOT NULL,
|
||||
"attested_digest" text NOT NULL,
|
||||
"schema_and_semantic_validation_passed" boolean NOT NULL,
|
||||
"blocking_lint_finding_count" integer NOT NULL,
|
||||
"limitations_documented" boolean NOT NULL,
|
||||
"unresolved_safety_regression" boolean NOT NULL,
|
||||
"review_json" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
"reviewed_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "playbook_review_attestations_lint_count_check" CHECK ("playbook_review_attestations"."blocking_lint_finding_count" >= 0),
|
||||
CONSTRAINT "playbook_review_attestations_digest_check" CHECK ("playbook_review_attestations"."attested_digest" ~ '^[0-9a-f]{64}$')
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_cases" ADD COLUMN "case_version" text;--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_cases" ADD COLUMN "target_digest" text;--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_cases" ADD COLUMN "fixture_id" text;--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_cases" ADD COLUMN "fixture_digest" text;--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_cases" ADD COLUMN "environment_digest" text;--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_results" ADD COLUMN "target_digest" text;--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_results" ADD COLUMN "fixture_digest" text;--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_results" ADD COLUMN "environment_digest" text;--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_results" ADD COLUMN "result_json" jsonb;--> statement-breakpoint
|
||||
ALTER TABLE "playbook_review_attestations" ADD CONSTRAINT "playbook_review_attestations_version_fk" FOREIGN KEY ("playbook_version_id") REFERENCES "public"."playbook_versions"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "playbook_review_attestations" ADD CONSTRAINT "playbook_review_attestations_reviewer_fk" FOREIGN KEY ("reviewed_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX "playbook_review_attestations_version_time_idx" ON "playbook_review_attestations" USING btree ("playbook_version_id","reviewed_at" DESC NULLS LAST);--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_cases" ADD CONSTRAINT "evaluation_cases_target_digest_check" CHECK ("evaluation_cases"."target_digest" is null or "evaluation_cases"."target_digest" ~ '^[0-9a-f]{64}$');--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_cases" ADD CONSTRAINT "evaluation_cases_fixture_digest_check" CHECK ("evaluation_cases"."fixture_digest" is null or "evaluation_cases"."fixture_digest" ~ '^[0-9a-f]{64}$');--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_cases" ADD CONSTRAINT "evaluation_cases_environment_digest_check" CHECK ("evaluation_cases"."environment_digest" is null or "evaluation_cases"."environment_digest" ~ '^[0-9a-f]{64}$');--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_results" ADD CONSTRAINT "evaluation_results_target_digest_check" CHECK ("evaluation_results"."target_digest" is null or "evaluation_results"."target_digest" ~ '^[0-9a-f]{64}$');--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_results" ADD CONSTRAINT "evaluation_results_fixture_digest_check" CHECK ("evaluation_results"."fixture_digest" is null or "evaluation_results"."fixture_digest" ~ '^[0-9a-f]{64}$');--> statement-breakpoint
|
||||
ALTER TABLE "evaluation_results" ADD CONSTRAINT "evaluation_results_environment_digest_check" CHECK ("evaluation_results"."environment_digest" is null or "evaluation_results"."environment_digest" ~ '^[0-9a-f]{64}$');
|
||||
--> statement-breakpoint
|
||||
CREATE TRIGGER playbook_review_attestations_immutable_trg
|
||||
BEFORE UPDATE OR DELETE ON "playbook_review_attestations"
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION devrunbook_reject_append_only_mutation();
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE "collections" DROP CONSTRAINT "collections_workspace_name_uq";--> statement-breakpoint
|
||||
ALTER TABLE "collections" ADD CONSTRAINT "collections_owner_name_uq" UNIQUE("workspace_id","created_by","name");--> statement-breakpoint
|
||||
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_position_check" CHECK ("collection_items"."position" >= 0);--> statement-breakpoint
|
||||
ALTER TABLE "collections" ADD CONSTRAINT "collections_name_check" CHECK (char_length("collections"."name") between 1 and 80 and "collections"."name" = btrim("collections"."name") and "collections"."name" !~ '[[:cntrl:]]');--> statement-breakpoint
|
||||
ALTER TABLE "collections" ADD CONSTRAINT "collections_description_check" CHECK (char_length("collections"."description") <= 500);
|
||||
@@ -0,0 +1,15 @@
|
||||
CREATE TABLE "repository_preferences" (
|
||||
"workspace_id" uuid NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"repository_id" uuid NOT NULL,
|
||||
"favorite" boolean DEFAULT false NOT NULL,
|
||||
"last_used_at" timestamp with time zone,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "repository_preferences_pkey" PRIMARY KEY("workspace_id","user_id","repository_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "repository_preferences" ADD CONSTRAINT "repository_preferences_workspace_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "repository_preferences" ADD CONSTRAINT "repository_preferences_user_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "repository_preferences" ADD CONSTRAINT "repository_preferences_repository_fk" FOREIGN KEY ("repository_id") REFERENCES "public"."repositories"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX "repository_preferences_user_rank_idx" ON "repository_preferences" USING btree ("workspace_id","user_id","favorite","last_used_at" DESC NULLS LAST);
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1785110204324,
|
||||
"tag": "0000_jittery_wind_dancer",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "7",
|
||||
"when": 1785111368997,
|
||||
"tag": "0001_daily_mystique",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "7",
|
||||
"when": 1785131801172,
|
||||
"tag": "0002_wild_wraith",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "7",
|
||||
"when": 1785137671077,
|
||||
"tag": "0003_polite_kronos",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 4,
|
||||
"version": "7",
|
||||
"when": 1785146174147,
|
||||
"tag": "0004_gitea_persistence_hardening",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 5,
|
||||
"version": "7",
|
||||
"when": 1785152317539,
|
||||
"tag": "0005_luxuriant_changeling",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 6,
|
||||
"version": "7",
|
||||
"when": 1785153820590,
|
||||
"tag": "0006_worried_prodigy",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 7,
|
||||
"version": "7",
|
||||
"when": 1785159158743,
|
||||
"tag": "0007_lean_jack_power",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 8,
|
||||
"version": "7",
|
||||
"when": 1785359005075,
|
||||
"tag": "0008_third_menace",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user