ADR-004: Architecture Style — Modular Monolith First
Status: Accepted Date: 2026-03-16
Context
The PowerBuilder desktop app is a monolith — all business logic runs in a single process. For the SaaS rebuild, the team considered whether to jump directly to microservices or start with a modular approach.
Options considered:
- Microservices from day one: Each bounded context is a separate service with its own database
- Modular monolith: Bounded contexts as separate .NET projects sharing a single process, extracted to services only when needed
- Traditional monolith: Everything in one project, refactor later
Decision
Modular monolith with separate .NET projects per bounded context sharing a single process and database. Extract services only when scale, team autonomy, or deployment velocity demands it.
Key design rules:
- Each bounded context is a separate .NET class library project
- Contexts communicate through well-defined interfaces (not direct class references)
- No circular dependencies between contexts
- The API host project references all contexts and wires them up via dependency injection
- Database access is scoped per context (each context owns its tables)
Consequences
Positive:
- Simpler operations — one deployment, one process, easier debugging
- Cheaper hosting initially — no service mesh, no inter-service networking
- Easier refactoring — rename and move within a single solution
- Natural extraction path — when a context needs independence, its interface is already defined
Negative:
- All contexts share the same deployment cycle (a change in Pricing requires redeploying everything)
- Performance-intensive contexts (Pricing, Risk) cannot scale independently without extraction
- Discipline required to maintain module boundaries — easy to take shortcuts in a monolith
Candidates for future extraction: Pricing and Risk modules are the most likely candidates due to computational intensity and potential need for independent scaling.