chore(database): add foundation schema migrations

Summary

Foundation database schema for the Artifact Registry. Tooling infrastructure (pgFormatter, PG version matrix, CI jobs, dump-structure.sh) shipped in !249 (merged); this MR adds the migrations that exercise it.

Migrations

6 DDL migrations implementing the foundation tables from ADR-007 and ADR-022, plus the partitions schema and a slug immutability trigger.

Table Partitioned Notes
namespaces No Root entity, UUIDv7 PK, immutable slug, billing entity columns, delivery mode override
repository_collections HASH(namespace_id), 64 Logical grouping within namespaces
repositories HASH(namespace_id), 64 Unified parent for all formats/kinds
repository_collection_repositories HASH(namespace_id), 64 Join table

One migration per table, FK targets ordered first (per S04 conventions). All partitioned tables use NO TRANSACTION to stay within max_locks_per_transaction. Partition children live in the partitions schema per S04.

Also included

  • structure.sql: deterministic schema snapshot generated by scripts/db/dump-structure.sh, validated by db:structure-check CI job.

ADR alignment

  • namespaces.delivery_mode_override: from ADR-007 (handbook !19821).
  • namespaces.billing_entity_type, namespaces.billing_entity_id: from ADR-022 (handbook !19789).
  • repositories partial index on (namespace_id, visibility) WHERE soft_deleted_at IS NULL: from ADR-007 (handbook !19766).
  • No schema-level defaults on externally-provided columns (platform, entity_type, billing_entity_type, billing_entity_id). The Core Module (Rails) must supply every value at namespace creation time. ADR amendment: handbook !19860.

Test plan

  • CI green (all matrix jobs)
  • mise run db:setup applies all migrations successfully

Database Review Evidence

Note

Timings are from CI (db:migrate matrix jobs, goose verbose mode) against an empty database, in apply / rollback order per supported PostgreSQL version. Production-scale validation via Database Lab is not yet available. See Database review evidence in the dev docs for the matrix rationale, how to read the numbers, and the current limitations.

Migrations

Migration PG 16 PG 17 PG 18
20260519155255_create_partitions_schema.sql OK (1.23ms / 1.41ms) OK (2.32ms / 1.28ms) OK (1.53ms / 1.38ms)
20260519155257_create_namespaces.sql OK (17.63ms / 5.37ms) OK (10.12ms / 6ms) OK (11.44ms / 6.11ms)
20260519155258_add_namespaces_slug_immutability_trigger.sql OK (3.35ms / 2.96ms) OK (2.59ms / 2.77ms) OK (5.75ms / 2.82ms)
20260519155259_create_repository_collections.sql OK (732.74ms / 147.92ms) OK (297.01ms / 152.63ms) OK (321.08ms / 194.03ms)
20260519155301_create_repositories.sql OK (1.83s / 332.23ms) OK (654.28ms / 431.41ms) OK (830.16ms / 417.52ms)
20260519155303_create_repository_collection_repositories.sql OK (568.1ms / 166.7ms) OK (350.06ms / 165.2ms) OK (408.82ms / 210.45ms)

Notes:

  • create_repositories.sql: PG 16 up (1.83s) is ~2.8x slower than PG 17 (654ms) and ~2.2x slower than PG 18 (830ms). Exceeds the 1s threshold on an empty database. Consistent with PG 16 partition DDL overhead.
  • create_repository_collections.sql: PG 16 up (733ms) is ~2.5x slower than PG 17 (297ms) and ~2.3x slower than PG 18 (321ms). Same PG 16 partition pattern.
Edited by João Pereira

Merge request reports

Loading
Loading