encapi's schema was a cumulative IF NOT EXISTS blob re-executed inline on every
start: it grows forever, records nothing, and cannot express a change that is
not a fresh CREATE. golib owns that mechanism now, so encapi keeps the SQL and
drops the runner.
- Move the DDL verbatim into migrations/0001_init.sql, embedded via
migrations.FS. It stays IF NOT EXISTS-guarded, so the first start against the
live database re-runs it as a no-op and only lands the schema_migrations row.
- Build the pool with pg.NewMigrated under the advisory lock named
encapi-migrations, and delete the inline migrate(). database.New now takes a
context and a logger; main.go hands it the signal context so a start blocked
on the migration lock still dies on SIGTERM.
- Render the DSN with pg.DSN. The env var contract is untouched — the fields are
still resolved by internal/config, because encapi defaults DBUSER and DBNAME
to "encapi" where pg.DSNFromEnv treats both as required.
- Guard the set: embedded files must match migrations/, every CREATE must be
idempotent, the derived lock key is pinned, and a container test proves the
adoption path over a database that predates schema_migrations.
- Plumb GOPRIVATE=git.unkin.net for the first cross-repo Go dependency:
exported by the Makefile, set in the Dockerfile and the woodpecker Go steps,
documented in the README.
Hard switch of the docker push target from the Gitea registry to the
artifactapi local docker registry (docker-internal); the Gitea VM and its
registry are being retired. Drops the droneci/DRONECI_PASSWORD creds since
artifactapi accepts unauthenticated in-cluster pushes. Also updates the README image path.
Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv