Skip to content

L3: Orders extraction example — standalone service using same domain code#6

Open
maurcarvalho wants to merge 6 commits intomainfrom
feature/l3-extraction-example
Open

L3: Orders extraction example — standalone service using same domain code#6
maurcarvalho wants to merge 6 commits intomainfrom
feature/l3-extraction-example

Conversation

@maurcarvalho
Copy link
Owner

@maurcarvalho maurcarvalho commented Feb 24, 2026

L3: Selective Extraction — Orders as Independent Service

Demonstrates the L3 level of progressive scalability: extracting the Orders module into a fully independent service while the monolith continues serving inventory, payments, and shipments.

What's added

Orders Service (apps/orders-service/)

  • Standalone HTTP server with own API routes (place, list, get, cancel)
  • Own database connection (dedicated PostgreSQL instance)
  • Own event listeners (Orders-related subset)
  • Uses the exact same domain logic from libs/modules/orders/ — zero code duplication

Monolith Extraction Support

  • EXTRACTED_MODULES env var controls which modules are extracted
  • Next.js middleware rejects extracted module routes with 410 Gone
  • register-listeners.ts skips extracted module listeners
  • Extraction is a configuration change, not a code change

Docker Compose (docker-compose.l3.yml)

  • orders-service: standalone process (port 3001) with dedicated DB
  • monolith: remaining modules (port 3000) with EXTRACTED_MODULES=orders
  • orders-db: dedicated PostgreSQL for Orders
  • main-db: shared PostgreSQL for remaining modules
  • redis: shared infrastructure (cache + queues)

Key design decisions

  • No code duplication: orders-service imports from @tiny-store/modules-orders
  • No code deletion: monolith still has orders code, just deactivated via env var
  • Reversible: remove EXTRACTED_MODULES=orders and the monolith serves orders again
  • Same event contracts: EventBus pattern unchanged (Kafka adapter would be next step)

Testing

All 33 existing tests pass. No domain logic was changed.

Mauricio Carvalho added 6 commits February 24, 2026 16:40
…ain code

- apps/orders-service/src/main.ts: standalone HTTP server using libs/modules/orders
- apps/orders-service/Dockerfile: multi-stage build for the extracted service
- apps/orders-service/tsconfig.json: extends root, includes shared libs
- apps/orders-service/project.json: Nx project config
- Dockerfile (root): monolith build
- docker-compose.l3.yml: both services running (orders-db + main-db + redis)

Zero domain code duplication. The handlers, entities, and value objects are
identical to the monolith. Only infrastructure wiring differs.
The extracted Orders process is a worker that listens for events
and publishes events. The monolith (or API gateway) continues to
serve REST endpoints. An HTTP layer can be added later if the module
needs an independent API surface (separate team, SLA, deployment cadence).
L3 means fully independent: the extracted Orders service serves
its own HTTP API on port 3001, owns its database, and registers
its own event listeners. This is the whole point of extraction.
- Add Next.js middleware: rejects /api/orders/* with 410 Gone when
  EXTRACTED_MODULES=orders is set
- Update register-listeners.ts: skip orders listeners when extracted
- Set EXTRACTED_MODULES=orders in docker-compose.l3.yml monolith service

Extraction is a configuration change, not a code change.
Each module defines its own registerXxxListeners() function.
The orchestrator loops MODULE_REGISTRARS, skipping any module
listed in EXTRACTED_MODULES. Adding or extracting a module is
a one-line change in one place.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant