-- Release module full schema bootstrap for local dev compose. -- Includes schemas, tenants, integration hub, environments, release management, -- workflow, promotion, deployment, agents, trust/signing, and read models. -- All statements are idempotent (IF NOT EXISTS / ON CONFLICT). -- Shared tenants (required by release.integrations FK) CREATE SCHEMA IF NOT EXISTS shared; CREATE TABLE IF NOT EXISTS shared.tenants ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id TEXT NOT NULL UNIQUE, name TEXT NOT NULL, display_name TEXT, is_default BOOLEAN NOT NULL DEFAULT false, status TEXT NOT NULL DEFAULT 'active', settings JSONB NOT NULL DEFAULT '{}', metadata JSONB NOT NULL DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE UNIQUE INDEX IF NOT EXISTS uq_shared_tenants_single_default ON shared.tenants (is_default) WHERE is_default; -- Seed shared tenant for local dev INSERT INTO shared.tenants (tenant_id, name, display_name, status) VALUES ('demo-prod', 'Production', 'Demo Production', 'active') ON CONFLICT (tenant_id) DO NOTHING; -- Release schemas CREATE SCHEMA IF NOT EXISTS release; CREATE SCHEMA IF NOT EXISTS release_app; -- Helper function for updated_at triggers CREATE OR REPLACE FUNCTION release.update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$ LANGUAGE plpgsql; -- Tenant isolation function CREATE OR REPLACE FUNCTION release_app.require_current_tenant() RETURNS UUID LANGUAGE plpgsql STABLE SECURITY DEFINER AS $$ DECLARE v_tenant TEXT; BEGIN v_tenant := current_setting('app.tenant_id', true); IF v_tenant IS NULL OR v_tenant = '' THEN RAISE EXCEPTION 'app.tenant_id session variable not set'; END IF; RETURN v_tenant::UUID; END; $$; -- Analytics schema CREATE SCHEMA IF NOT EXISTS analytics;