- Add 03-02-SUMMARY.md with execution results - Update STATE.md: advance plan, record metrics, add decisions, update session - Update ROADMAP.md: phase 03 complete (2/2 plans, all summaries present) - Update REQUIREMENTS.md: mark DB-02 complete
4.6 KiB
4.6 KiB
phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | |||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 03-postgresql-support | 02 | wiring |
|
|
|
|
|
|
Phase 03 Plan 02: Wire PostgreSQL Support and Deployment Infrastructure Summary
DATABASE_URL branching in main.go routes to PostgresStore or SQLiteStore at startup; Docker Compose postgres profile enables optional PostgreSQL; build-tagged test helper and cross-dialect UNIQUE detection complete the integration.
What Was Built
Updated main.go (cmd/diunwebhook/main.go)
DATABASE_URLenv var check: when set, opens pgx connection, runsRunPostgresMigrations, createsNewPostgresStore, logs"Using PostgreSQL database"- When absent: existing SQLite path using
RunSQLiteMigrations(renamed in Plan 01),NewSQLiteStore, logs"Using SQLite database at {path}" - Blank import
_ "github.com/jackc/pgx/v5/stdlib"registers the"pgx"driver name - All route wiring and graceful shutdown logic unchanged
Cross-dialect UNIQUE detection (pkg/diunwebhook/diunwebhook.go)
TagsHandlernow usesstrings.Contains(strings.ToLower(err.Error()), "unique")for 409 Conflict detection- SQLite errors:
UNIQUE constraint failed: tags.name(uppercase UNIQUE) - PostgreSQL errors:
duplicate key value violates unique constraint "tags_name_key"(lowercase unique) - Both backends now return 409 correctly
Docker Compose postgres profiles
compose.yml: postgres service added withprofiles: [postgres], healthcheck viapg_isready,DATABASE_URLenv var in app service, conditionaldepends_onwithrequired: false,postgres-datavolumecompose.dev.yml: same postgres service with port 5432 exposed on host for direct psql access during development- Default
docker compose up(no profile) unchanged — SQLite only, no new services start
Build-tagged test helper (pkg/diunwebhook/postgres_test.go)
//go:build postgrestag — only compiled withgo test -tags postgresNewTestPostgresServer()constructs a*Serverbacked by PostgreSQL usingTEST_DATABASE_URLenv var (defaults topostgres://diun:diun@localhost:5432/diundashboard_test?sslmode=disable)- Calls
RunPostgresMigrationsandNewPostgresStore— mirrors the production startup path
Decisions Made
| Decision | Rationale |
|---|---|
| DATABASE_URL presence-check (not a separate DB_DRIVER var) | Simpler UX; empty string = SQLite, any value = PostgreSQL |
| profiles: [postgres] in compose files | Standard Docker Compose pattern for optional services; default deploy unchanged |
| required: false in depends_on | App can start without postgres service (SQLite fallback); Docker Compose v2.20+ required |
| //go:build postgres tag on test helper | Prevents pgx import at test time for standard go test ./... runs; explicit opt-in |
| strings.ToLower for UNIQUE check | SQLite and PostgreSQL use different cases in constraint error messages |
Deviations from Plan
None — plan executed exactly as written. The export_test.go rename (RunMigrations -> RunSQLiteMigrations) was already completed as a deviation in Plan 01, as noted in the objective.
Verification Results
go build ./...exits 0go test -count=1 ./pkg/diunwebhook/passes (all 20+ SQLite tests, postgres_test.go skipped)docker compose configvalidates without errorsdocker compose --profile postgres configshows postgres servicegrep -c "DATABASE_URL" cmd/diunwebhook/main.goreturns 1grep "strings.ToLower" pkg/diunwebhook/diunwebhook.goshows case-insensitive UNIQUE check
Known Stubs
None — this plan wires implementation code, no UI stubs.