Brings Authority into §2.7 compliance. Previously AutoMigrate=true was set
in Program.cs but no runner was wired; 001_initial_schema.sql was
non-idempotent so wiring AddStartupMigrations against a pre-bootstrapped
DB crash-looped. Discovered during DEPRECATE-003 when the new drop
migration couldn't apply via Authority's own startup path.
Idempotency fixes in 001_initial_schema.sql:
- CREATE INDEX → CREATE INDEX IF NOT EXISTS (27 indexes)
- CREATE TRIGGER → DROP TRIGGER IF EXISTS + CREATE TRIGGER (3 triggers)
- CREATE POLICY → DROP POLICY IF EXISTS + CREATE POLICY (12 policies)
- CREATE TABLE / FUNCTION (OR REPLACE) / RLS ENABLE / role DO blocks were
already idempotent — left unchanged
Wiring:
- AddStartupMigrations("authority", "Authority", typeof(AuthorityDataSource)
.Assembly) called inside RegisterAuthorityServices (canonical
Signals/Scanner pattern).
- Stale options.AutoMigrate = true + options.MigrationsPath removed from
Program.cs.
- Migrations\_archived\** excluded from the EmbeddedResource glob.
Init script cleanup (migrations own schema authority now):
- 04-authority-schema.sql: 569 lines → 60 lines (schema shells + guarded
default-tenant seed fallback only; all DDL removed)
- 04b-authority-dedicated-schema.sql: same reduction for dedicated DB
Verification sequence — all PASS:
1. Green-field replay: 001 runs twice with zero semantic drift (pg_dump
diff shows only session restrict nonce).
2. Wire against pre-migrated volume: runner applies 001+002 in 209ms, no
crash-loop.
3. Wire + fresh schema: migrates 20 tables from empty in 395ms.
4. Idempotent restart: "Database is up to date", pure no-op.
Sprint SPRINT_20260422_003_Authority_auto_migration_compliance created
and archived in the same pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
64 lines
3.0 KiB
SQL
64 lines
3.0 KiB
SQL
-- Authority Schema: Bootstrap Fallback (NOT the migration authority).
|
|
--
|
|
-- AGENTS.md §2.7 / SPRINT_20260422_003 (AUTH-MIGRATE-003):
|
|
-- The Authority service now owns its schema via embedded SQL migrations in
|
|
-- `src/Authority/__Libraries/StellaOps.Authority.Persistence/Migrations/*.sql`
|
|
-- applied by `StellaOps.Infrastructure.Postgres.Migrations.AddStartupMigrations`
|
|
-- on service startup. This init script is retained only as a first-run fallback
|
|
-- for the shared `stellaops_platform` database; it creates the `authority`
|
|
-- namespace shells so compose health checks can start, but DDL authority lives
|
|
-- with the service migration runner.
|
|
--
|
|
-- Table/index/trigger/policy creation was removed in AUTH-MIGRATE-003. The
|
|
-- Authority service is responsible for applying all schema DDL. This file
|
|
-- only:
|
|
-- 1. Creates the `authority` and `authority_app` schemas so the service can
|
|
-- connect before its first migration run (migration 001 also does this
|
|
-- via CREATE SCHEMA IF NOT EXISTS, but having the schema pre-exist keeps
|
|
-- legacy bootstrap scripts that reference `authority.*` qualifiers safe).
|
|
-- 2. Seeds the `default` tenant row only if the `authority.tenants` table
|
|
-- already exists (guarded so the init script is a pure no-op when the
|
|
-- migration runner has not yet populated the schema).
|
|
--
|
|
-- First-party clients (stella-ops-ui, stellaops-cli) and demo seed data come
|
|
-- from migration `S001_demo_seed.sql` in the persistence assembly, not here.
|
|
|
|
-- ============================================================================
|
|
-- SECTION 1: Schema shells (idempotent)
|
|
-- ============================================================================
|
|
|
|
CREATE SCHEMA IF NOT EXISTS authority;
|
|
CREATE SCHEMA IF NOT EXISTS authority_app;
|
|
|
|
-- ============================================================================
|
|
-- SECTION 2: Guarded default tenant seed
|
|
-- ============================================================================
|
|
--
|
|
-- Only inserts if `authority.tenants` already exists (i.e. the migration
|
|
-- runner has already applied 001_initial_schema.sql in a previous boot).
|
|
-- On a fresh volume where Authority has not yet started, this block is a
|
|
-- no-op and the `default` tenant is seeded by the migration path instead.
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF EXISTS (
|
|
SELECT 1
|
|
FROM information_schema.tables
|
|
WHERE table_schema = 'authority'
|
|
AND table_name = 'tenants'
|
|
) THEN
|
|
INSERT INTO authority.tenants (tenant_id, name, display_name, status)
|
|
VALUES ('default', 'Default', 'Default Tenant', 'active')
|
|
ON CONFLICT (tenant_id) DO NOTHING;
|
|
END IF;
|
|
END
|
|
$$;
|
|
|
|
-- ============================================================================
|
|
-- Bootstrap Notes
|
|
-- ============================================================================
|
|
--
|
|
-- First-party clients are seeded by the Authority standard plugin at runtime
|
|
-- and by the S001_demo_seed.sql migration. The first administrator is created
|
|
-- through the setup wizard, not compose SQL.
|