chore(db): bootstrap database tooling (goose + jet + LabKit v2)

Pure tooling and library MR — no runtime (main.go) changes. Establishes the database foundation that feature specs (S10-S18) build on.

What this MR adds

  • PostgreSQL connectivity via LabKit v2 postgres.Client with a single ARTIFACT_REGISTRY_DATABASE_DSN (internal/datastore/postgres.go)
  • Migration framework — goose v3 provider with embedded SQL (internal/datastore/migrations/), session-level advisory locking, SQL files in sql/ subdirectory
  • Datastore conventions — flat internal/datastore/ package per ADR-023: datastore.go (interfaces, shared ErrNotFound) + postgres.go (PostgreSQL implementation), with migrations/ and jet/ as subpackages
  • Developer workflowmise run db:setup (one-command bootstrap), db:migrate, db:rollback, db:status, db:create-migration, db:jet-gen, db:lint, db:reset
  • CI validationlint:migrations (squawk), test:integration (real PostgreSQL + Cobertura coverage), jet:generate-check (drift detection)
  • Integration testing//go:build integration tag separation, testcontainers-go for local dev, shared testutil.SetupTestDB() helper
  • Documentation — CLAUDE.md, getting-started, database, database-migrations, database-query-patterns, go-libraries, go-testing

What this MR does NOT touch

  • main.go — unchanged from main. App lifecycle (startup goroutine, readiness gating) deferred to S01.
  • Domain tables — no-op bootstrap migration only. First real migration comes from a feature spec.
  • Jet generated code — no tables to generate from yet.
  • Config loader wiringConfig struct shape lands here; wiring the proto loader (per docs/dev/configuration.md) into main.go belongs to S01.

Spec

S04 merged via !46 (merged). This is infrastructure bootstrap — the plan file serves as the historical record: docs/plans/2026-04-08-bootstrap-db-tooling.md

Key design decisions

Decision Rationale
Single DSN (no PgBouncer split) No PgBouncer at bootstrap. TODO(pgbouncer-split) marks where to split; tracked in #11.
Config populated by caller (no os.Getenv) Application runtime config follows the protobuf-first pattern in docs/dev/configuration.md. S01 wires the loader. Dev tooling (mise, goose/jet CLIs, CI integration tests) still reads env vars — those are tooling inputs, not runtime config.
ARTIFACT_REGISTRY_DATABASE_DSN naming Mirrors future config nesting (database.host, database.port, etc. in YAML).
Migrations as library, not startup hook App lifecycle belongs to S01. Library works from any context.
goose/jet CLIs via mise tools, not go.mod Avoids pulling 50+ unnecessary DB drivers into module graph.
squawk version in .gitlab-ci-other-versions.yml npm package, cannot use .tool-versions auto-sync.
Flat datastore package (ADR-023) Domain interfaces + PostgreSQL implementation co-located; entity methods added to both files in the same package.
Edited by João Pereira

Merge request reports

Loading
Loading