What Happened
The choco-consumers service had 7 handler interfaces (AnalyticsWriter, SearchIndexer, LedgerWriter, etc.) all backed by log-only stubs. Replaced all 7 with real PostgreSQL-backed adapters in a single TASKSET without modifying any handler code.Key Insight
Define interfaces in the handler package, implement in the adapter package. The handler owns the contract (Write(ctx, eventType, data)) — it doesn’t know or care whether the adapter writes to PostgreSQL, ClickHouse, or /dev/null. This made the swap a main.go-only change: replace &stubAnalyticsWriter{} with adapters.NewPgAnalyticsWriter(pool).
The Fallback Rule
WhenDATABASE_URL is empty, the service falls back to stub implementations automatically. This means:
- Local dev works without PostgreSQL
- CI tests run without infrastructure
- Production uses real adapters with no code path difference