39 lines
1.6 KiB
Markdown
39 lines
1.6 KiB
Markdown
# 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.
|