# 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.