Files
DiunDashboard/.planning/phases/02-backend-refactor/02-02-SUMMARY.md
Jean-Luc Makiola 7004e7fb3e docs(02-02): complete Server struct refactor and test isolation plan
- Add 02-02-SUMMARY.md: Server struct methods, NewTestServer pattern, per-test in-memory databases
- Update STATE.md: advance plan to 2/2, record metrics and decisions
- Update ROADMAP.md: Phase 2 Backend Refactor complete (2/2 plans)
- Update REQUIREMENTS.md: mark REFAC-02 complete (REFAC-01 and REFAC-03 already marked)
2026-03-24 08:39:29 +01:00

5.6 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
02-backend-refactor 02 http-handlers
server-struct
dependency-injection
store-interface
test-isolation
in-memory-sqlite
refactor
phase provides
02-01 Store interface (9 methods), SQLiteStore, RunMigrations
Server struct with Store field and webhookSecret field
NewServer constructor wiring Store and secret
All 6 handlers converted to *Server methods calling s.store.X()
NewTestServer / NewTestServerWithSecret helpers for isolated per-test databases
main.go wiring
sql.Open -> RunMigrations -> NewSQLiteStore -> NewServer -> routes
03-postgresql (PostgreSQLStore will implement same Store interface; Server struct accepts any Store)
added patterns
Server struct pattern - all handler dependencies injected via constructor, no package-level globals
export_test.go internal helpers (TestUpsertEvent, TestGetUpdatesMap) - access unexported fields without exposing Store accessor
Per-test in-memory SQLite database via NewTestServer() - eliminates shared state between tests
NewTestServerWithSecret for auth-enabled test scenarios
created modified
pkg/diunwebhook/diunwebhook.go
pkg/diunwebhook/export_test.go
pkg/diunwebhook/diunwebhook_test.go
cmd/diunwebhook/main.go
Option B for test store access: internal helpers in export_test.go (TestUpsertEvent, TestGetUpdatesMap) instead of exported Store() accessor - keeps store field unexported
t.Errorf used inside goroutines in TestConcurrentUpdateEvent (t.Fatalf is not safe from non-test goroutines)
_ modernc.org/sqlite blank import moved from diunwebhook.go to main.go and migrate.go - driver registration happens where needed
Server struct: HTTP handlers as methods on *Server, all deps injected at construction
NewTestServer pattern: each test creates its own in-memory SQLite DB via RunMigrations + NewSQLiteStore + NewServer
export_test.go internal methods: (s *Server) TestUpsertEvent / TestGetUpdatesMap access s.store without exporting Store field
REFAC-01
REFAC-02
REFAC-03
3min 2026-03-23

Phase 02 Plan 02: Server Struct Refactor and Test Isolation Summary

*Server struct with Store injection, globals removed, all 6 handlers as Server methods calling s.store.X(), per-test in-memory databases via NewTestServer

Performance

  • Duration: ~3 min
  • Started: 2026-03-23T21:02:53Z
  • Completed: 2026-03-23T21:05:09Z
  • Tasks: 2
  • Files modified: 4

Accomplishments

  • Removed all package-level globals (db, mu, webhookSecret) from diunwebhook.go
  • Removed InitDB, SetWebhookSecret, UpdateEvent, GetUpdates functions (replaced by Store and Server)
  • Added Server struct with store Store and webhookSecret string fields
  • Added NewServer(store Store, webhookSecret string) *Server constructor
  • Converted all 6 handler functions to *Server methods using s.store.X() for all persistence
  • Rewrote export_test.go: NewTestServer, NewTestServerWithSecret, TestUpsertEvent, TestGetUpdatesMap helpers
  • Rewrote diunwebhook_test.go: every test creates its own isolated in-memory database (no shared global state)
  • Updated main.go: sql.Open -> RunMigrations -> NewSQLiteStore -> NewServer -> route registration
  • All 35 tests pass against the new Server/Store architecture

Task Commits

Each task was committed atomically:

  1. Task 1: Convert diunwebhook.go to Server struct and update main.go - 78543d7 (feat)
  2. Task 2: Rewrite export_test.go and update all tests for Server/Store - e35b4f8 (test)

Files Created/Modified

  • pkg/diunwebhook/diunwebhook.go - Server struct, NewServer constructor, all 6 handlers as *Server methods; globals and standalone functions removed
  • pkg/diunwebhook/export_test.go - NewTestServer, NewTestServerWithSecret, (s *Server) TestUpsertEvent, TestGetUpdates, TestGetUpdatesMap
  • pkg/diunwebhook/diunwebhook_test.go - All 35 tests rewritten to use NewTestServer per-test; no shared state; no TestMain
  • cmd/diunwebhook/main.go - Full replacement: sql.Open -> RunMigrations -> NewSQLiteStore -> NewServer -> route registration with srv.XHandler

Decisions Made

  • Test store access via internal helper methods in export_test.go (Option B) — avoids exposing Store field publicly while still letting tests call UpsertEvent/GetUpdates
  • t.Errorf used inside goroutine in TestConcurrentUpdateEvent — t.Fatalf is not safe from non-test goroutines (pre-existing issue resolved)
  • _ "modernc.org/sqlite" blank import moved to main.go (and already in migrate.go) — driver registered where *sql.DB is opened

Deviations from Plan

None - plan executed exactly as written.

Known Stubs

None.

Self-Check: PASSED

  • pkg/diunwebhook/diunwebhook.go: FOUND
  • pkg/diunwebhook/export_test.go: FOUND
  • pkg/diunwebhook/diunwebhook_test.go: FOUND
  • cmd/diunwebhook/main.go: FOUND
  • Commit 78543d7: FOUND
  • Commit e35b4f8: FOUND
  • All 35 tests pass: VERIFIED (go test -v -count=1 ./pkg/diunwebhook/)

Next Phase Readiness

  • Server struct accepts any Store implementation — PostgreSQL store can be introduced in Phase 3 without touching handlers
  • RunMigrations called in main.go before store creation — Phase 3 just needs to add a postgres migration variant
  • Per-test isolation via NewTestServer is the established pattern — Phase 3 tests can follow the same approach
  • All acceptance criteria verified: no globals, no SQL in handlers, s.store.X() pattern throughout, main.go wiring complete

Phase: 02-backend-refactor Completed: 2026-03-23