feat(store): SQLite with embedded migrations (forgejo-mcp-broker-9jh)

Implements internal/store on top of modernc.org/sqlite (pure-Go, no CGO).
Open applies any pending migrations, Close releases the handle, Ping
underpins /healthz.

Migration design:
- Files embedded via embed.FS under migrations/NNNN_name.sql
- schema_migrations table tracks applied versions; re-open is a no-op
- Each migration runs in its own transaction: no partial commits
- loadMigrations takes an fs.FS so tests can inject synthetic migration
  sets to exercise rollback and conflict paths

Connection pragmas (set via DSN so they apply to every pooled conn):
- journal_mode=WAL — better reader/writer concurrency
- foreign_keys=ON — off by default in SQLite, we always want them
- busy_timeout=5000 — absorb brief contention without surfacing SQLITE_BUSY
- synchronous=NORMAL — standard WAL pairing

Phase 1 schema (0001_initial.sql) is minimal: a broker_meta table with a
schema_version row. Real OAuth tables ship in phase 2.

Tests: 90.1% coverage across public API and internal migration runner,
including bad SQL rollback, PK-conflict record-step failure, and scan
errors on malformed schema_migrations rows.

Closes forgejo-mcp-broker-9jh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2026-04-24 17:22:47 +02:00
commit df2253398b
10 changed files with 738 additions and 8 deletions

14
go.mod
View file

@ -1,3 +1,17 @@
module kode.naiv.no/olemd/forgejo-mcp-broker
go 1.26
require modernc.org/sqlite v1.49.1
require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
golang.org/x/sys v0.42.0 // indirect
modernc.org/libc v1.72.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
)