Skip to main content

ADR-003: Monolith-first backend

Context

The 5-layer pipeline (Generation → Execution → Analysis → Decision → Reporting) could be deployed as microservices from day one. However, with fewer than 10 customers expected in the first 6 months, the operational overhead of managing multiple services, service mesh, inter-service auth, and distributed tracing would slow development significantly.

The interface + adapter pattern (see .context/AI_RULES.md) ensures the monolith is extraction-ready: each layer communicates through interfaces with Local and Remote implementations. Switching from Local (in-process) to Remote (network call) is a config flag change, not a rewrite.

Decision

Start with a monolith backend where all 5 pipeline layers run in a single JVM process. Use the interface + adapter pattern so any layer can be extracted to its own service when scale demands it.

Alternatives considered

OptionProsCons
Monolith-first (chosen)Simple deployment, no network overhead, faster iteration, one DB connection poolRisk of tight coupling if discipline lapses
Microservices from day oneIndependent scaling, technology diversity per layerOperational complexity, distributed debugging, inter-service latency, premature for fewer than 10 customers
Modular monolith (no extraction path)Simplest architectureRisky if one layer needs independent scaling later

Consequences

What becomes easier

  • Single deployment unit: one Docker image, one Helm release
  • Debugging is local — stack traces span all layers
  • No inter-service auth, no service mesh, no distributed tracing (yet)
  • Database transactions can span layers when needed

What becomes harder

  • Must maintain interface boundaries with discipline (CI lint helps)
  • All layers scale together — can't scale Analysis independently
  • A bug in one layer can affect all layers
  • Team must resist the temptation to take shortcuts across layer boundaries

Extraction trigger

Extract a layer to its own service when: (1) it needs independent scaling, or (2) the team grows to 5+ engineers working on different layers simultaneously.