1.6 KiB
ADR-0002: Modular monolith, not microservices
- Status: Accepted
- Date: 2026-08-11
Context
The system will eventually need order processing, inventory, payments, search and notifications. That list reads like a microservice diagram, and the temptation is to start there. But on day one there is no traffic, no team boundary and no independent scaling requirement — only the cost of distributed transactions, network failure modes and per-service CI.
Decision
One NestJS process, internally partitioned into modules that own their tables
exclusively. Cross-module access happens two ways only: a synchronous call to the other
module's public/ service when an answer is needed now, or a domain event when something
merely needs to react.
Four modules — inventory, orders, payments, search — are marked EXTRACTION CANDIDATE
and additionally forbidden from sharing transactions with the rest of the monolith.
Consequences
A single deploy, a single database, real foreign keys and real transactions — which is exactly what an order/inventory/payment flow wants. Extraction stays possible because the boundaries are enforced now, while they are cheap to enforce.
The risk is boundary erosion: one "quick" cross-module join and the seam is gone. This is why the rule is an ESLint error rather than a paragraph in a wiki.
Alternatives considered
Microservices from day one — rejected as premature: it buys independent scaling nobody needs and pays in distributed-transaction complexity that a checkout flow can least afford. A single unstructured application — rejected: retrofitting boundaries after the fact is the expensive path.