feat(authority): seed default + installation tenants via migration (SPRINT_20260422_005)

Closes the bootstrap gap two parallel QA agents surfaced on 2026-04-22:
fresh Authority DBs lacked the `default` tenant row so setup-wizard admin
creation failed with users_tenant_id_fkey and /connect/token returned
invalid_grant. Fix is on the migration path per AGENTS.md §2.7; the init
script stays seeds-only as established in SPRINT_20260422_003.

- New embedded migration 003_seed_default_tenants.sql performs
  `INSERT ... ON CONFLICT (tenant_id) DO NOTHING` for `default` and
  `installation`. Numeric prefix (not S-prefix) so the migration runner's
  Startup category auto-applies it; S-prefix files route to Seed category
  which is intentionally manual-only per
  StartupMigrationHost.cs:158.
- `default` is strictly required (Authority's
  StandardPluginBootstrapper.DefaultTenantId; /internal/users bootstrap
  inserts under this FK). `installation` is not Authority-FK-referenced
  today but matches the empirical workaround both QA agents converged on
  and serves as defense for cross-service inserts that join
  authority.tenants.tenant_id.

Fresh-volume verification (docs/qa/authority-default-tenant-20260422/):
1. docker compose down -v (20 volumes removed incl. compose_postgres-data)
2. docker compose up -d — 62 containers, Authority healthy in ~15s.
3. Startup log: applying 001 (144ms) → 002 (13ms) → 003 (7ms).
   authority.tenants contains default + installation.
4. POST /api/v1/setup/sessions → 201; database/valkey/migrations prereqs
   ran; admin/execute with admin/Admin@Stella2026! → 200 "Bootstrap
   administrator 'admin' ensured successfully."
5. POST /connect/token (password, stellaops-cli, ui.admin openid) → 200
   + JWT carrying role=admin, stellaops:tenant=default.
6. docker compose restart authority → "Database is up to date for
   Authority." Clean no-op.

Docs: docs/modules/authority/architecture.md §1.1 "Seeded bootstrap
tenants (migration-owned)". Cross-link added to the archived prior
sprint's Decisions & Risks so the lineage is traceable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-04-22 17:41:23 +03:00
parent 51f9b798ed
commit 47665927ab
14 changed files with 298 additions and 12 deletions

View File

@@ -1,75 +0,0 @@
# Sprint 20260422-005 — Authority default-tenant bootstrap
## Topic & Scope
- Close the bootstrap gap that forces setup-wizard Admin creation to fail with `users_tenant_id_fkey (tenant_id)=(default)` on any fresh Authority DB.
- The previous Authority §2.7 compliance sprint (`SPRINT_20260422_003_Authority_auto_migration_compliance`, archived) trimmed `devops/compose/postgres-init/04-authority-schema.sql` to "seeds only". In doing so, the guarded `default` tenant seed now runs only when the schema exists at init-script time — which, for migration-owned schemas, it doesn't. Result: freshly-migrated Authority DBs have zero tenants, the setup wizard fails, admin login returns `invalid_grant`.
- Two parallel QA agents (`fe-qa-006-relsec` and `fe-qa-007-evidops` in SPRINT_20260421_006/007 closeouts on 2026-04-22) independently hit this bug and worked around it by manually inserting the `default` + `installation` tenant rows and calling `POST /api/v1/setup/sessions/{id}/steps/admin/execute`.
- Working directory: `src/Authority/` (primary); `devops/compose/postgres-init/04-authority-schema.sql` + `04b-authority-dedicated-schema.sql` only if the seed fallback needs tightening.
- Expected evidence: fresh-volume bring-up (`docker compose down -v && docker compose up -d`) produces a working Authority with `default` tenant present and setup-wizard Admin bootstrap succeeding without manual intervention.
## Dependencies & Concurrency
- Follow-up to `SPRINT_20260422_003_Authority_auto_migration_compliance` (archived). Migration wiring and schema ownership contract established there are the baseline.
- No cross-module dependencies; safe to run alongside any non-Authority sprint.
## Documentation Prerequisites
- `CLAUDE.md` §2.7 — auto-migration + init script contract.
- `docs-archived/implplan/SPRINT_20260422_003_Authority_auto_migration_compliance.md` — the Decisions & Risks from the prior sprint explain why the init script was trimmed.
- `src/Authority/__Libraries/StellaOps.Authority.Persistence/Migrations/001_initial_schema.sql` — where a seed migration could live.
- `src/Authority/__Libraries/StellaOps.Authority.Persistence/Migrations/S001_demo_seed.sql` (if present) — pattern reference for seed-category migrations.
## Delivery Tracker
### AUTH-SEED-001 — Seed `default` tenant through the migration path
Status: TODO
Dependency: none
Owners: Developer (backend)
Task description:
- Add the `default` (and `installation`, if the setup wizard expects both) tenant rows as an embedded seed migration under `src/Authority/__Libraries/StellaOps.Authority.Persistence/Migrations/`. Seed-category filename so it runs after the DDL migrations and is idempotent (`INSERT ... ON CONFLICT (id) DO NOTHING` or equivalent).
- The migration runner established in AUTH-MIGRATE-002 applies all embedded SQL resources on startup; placing the seed here means both fresh-volume and already-provisioned environments converge to the same state.
- Do NOT add the seed to `04-authority-schema.sql` — that script stays pure-fallback per the prior sprint's Decision.
Completion criteria:
- [ ] Seed migration is an embedded resource in the persistence assembly.
- [ ] `default` tenant row exists after Authority startup on any fresh DB.
- [ ] Migration is idempotent — re-running against an already-seeded DB is a no-op.
- [ ] Migration applies cleanly after `001_initial_schema.sql` + `002_drop_deprecated_audit_tables.sql`.
### AUTH-SEED-002 — Verify setup-wizard admin bootstrap succeeds without manual intervention
Status: TODO
Dependency: AUTH-SEED-001
Owners: Developer (backend), QA
Task description:
- On a fresh volume (`docker compose down -v && docker compose up -d`), drive the setup-wizard admin-creation flow end-to-end using the documented credentials (`admin / Admin@Stella2026!`). Capture the happy path: first-run wizard → admin execute step → `POST /connect/token` succeeds.
- Regression test: `docker compose stop authority && docker compose rm -f authority && docker compose up -d authority` (recreate against existing volume) — must remain healthy with no tenant FK violations.
Completion criteria:
- [ ] Fresh-volume `docker compose up -d` produces a working admin login with zero manual SQL inserts.
- [ ] Authority startup logs show the seed migration applied once; restart shows "up to date".
- [ ] Integration or targeted test captures this path (or at minimum a run evidence document in `docs/qa/`).
### AUTH-SEED-003 — Document the bootstrap contract
Status: TODO
Dependency: AUTH-SEED-002
Owners: Documentation author
Task description:
- Update Authority's module dossier or operations guide to document that the `default` tenant is a migration-owned seed, not a user-modifiable row; note the relationship between `authority.tenants` and the setup-wizard admin flow.
- If the `installation` tenant was previously a migration-owned seed, explain its meaning too.
Completion criteria:
- [ ] Dossier or operations guide describes the seeded tenants and their purpose.
- [ ] Cross-link from `docs-archived/implplan/SPRINT_20260422_003` Decisions & Risks so the follow-up lineage is obvious.
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-04-22 | Sprint created to unpark the bootstrap gap surfaced independently by two FE QA agents during SPRINT_20260421_006/007 closeouts. The `default` tenant seed disappeared when §2.7 compliance trimmed the init scripts; it needs to come back as a migration-owned seed. | Claude |
## Decisions & Risks
- **Decision**: the seed belongs in the migration path, not the init scripts. This matches the §2.7 contract established in SPRINT_20260422_003 (migrations own schema + canonical seeds; init scripts are pure fallbacks).
- **Risk**: if an operator had already customized the `default` tenant row, an idempotent INSERT-on-conflict is safe; but if they've renamed or deleted it, the wizard will still fail on a different constraint. Mitigation: the seed is additive and conservative; it does not reconcile existing operator modifications.
- **Risk**: the setup wizard may expect additional bootstrap rows (e.g., default roles, default OIDC client) that are similarly missing after the init-script trim. If AUTH-SEED-002 surfaces more FK violations, extend the seed migration rather than reverting to init-script DDL.
## Next Checkpoints
- AUTH-SEED-001 DONE: fresh-DB `\dt authority.tenants` + `SELECT * FROM authority.tenants` shows the seeded rows.
- AUTH-SEED-002 DONE: fresh-volume stack brings up and `admin / Admin@Stella2026!` logs in without manual SQL.
- AUTH-SEED-003 DONE: dossier updated, sprint archivable.