Files
DiunDashboard/.planning/phases/03-postgresql-support/03-02-SUMMARY.md
Jean-Luc Makiola cf788930e0 docs(03-02): complete wire postgresql support plan
- 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
2026-03-24 09:14:50 +01:00

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
postgresql
sqlite
database
docker-compose
branching
requires provides affects
03-01
DATABASE_URL branching
postgres docker profile
NewTestPostgresServer
cmd/diunwebhook/main.go
compose.yml
compose.dev.yml
pkg/diunwebhook/diunwebhook.go
added patterns
DATABASE_URL env var branching
Docker Compose profiles
build-tagged test helpers
created modified
pkg/diunwebhook/postgres_test.go
cmd/diunwebhook/main.go
pkg/diunwebhook/diunwebhook.go
compose.yml
compose.dev.yml
DATABASE_URL present activates PostgreSQL path; absent falls back to SQLite with DB_PATH
postgres Docker service uses profiles: [postgres] so default compose up remains SQLite-only
UNIQUE detection uses strings.ToLower for case-insensitive matching across SQLite and PostgreSQL
Build tag //go:build postgres gates postgres_test.go so standard test runs have no pgx dependency
duration completed tasks_completed files_changed
~2 minutes 2026-03-24T08:13:21Z 2 5

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_URL env var check: when set, opens pgx connection, runs RunPostgresMigrations, creates NewPostgresStore, 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)

  • TagsHandler now uses strings.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 with profiles: [postgres], healthcheck via pg_isready, DATABASE_URL env var in app service, conditional depends_on with required: false, postgres-data volume
  • compose.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 postgres tag — only compiled with go test -tags postgres
  • NewTestPostgresServer() constructs a *Server backed by PostgreSQL using TEST_DATABASE_URL env var (defaults to postgres://diun:diun@localhost:5432/diundashboard_test?sslmode=disable)
  • Calls RunPostgresMigrations and NewPostgresStore — 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 0
  • go test -count=1 ./pkg/diunwebhook/ passes (all 20+ SQLite tests, postgres_test.go skipped)
  • docker compose config validates without errors
  • docker compose --profile postgres config shows postgres service
  • grep -c "DATABASE_URL" cmd/diunwebhook/main.go returns 1
  • grep "strings.ToLower" pkg/diunwebhook/diunwebhook.go shows case-insensitive UNIQUE check

Known Stubs

None — this plan wires implementation code, no UI stubs.

Self-Check: PASSED