Loading
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.Clientwith a singleARTIFACT_REGISTRY_DATABASE_DSN(internal/datastore/postgres.go) - Migration framework — goose v3 provider with embedded SQL
(
internal/datastore/migrations/), session-level advisory locking, SQL files insql/subdirectory - Datastore conventions — flat
internal/datastore/package per ADR-023:datastore.go(interfaces, sharedErrNotFound) +postgres.go(PostgreSQL implementation), withmigrations/andjet/as subpackages - Developer workflow —
mise run db:setup(one-command bootstrap),db:migrate,db:rollback,db:status,db:create-migration,db:jet-gen,db:lint,db:reset - CI validation —
lint:migrations(squawk),test:integration(real PostgreSQL + Cobertura coverage),jet:generate-check(drift detection) - Integration testing —
//go:build integrationtag separation, testcontainers-go for local dev, sharedtestutil.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 wiring —
Configstruct shape lands here; wiring the proto loader (per docs/dev/configuration.md) intomain.gobelongs 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