A practical case study showing how an e-commerce platform can evolve from an overloaded monolith toward stronger boundaries around catalog, checkout, billing, inventory, and fulfillment.
An e-commerce platform is one of the best decomposition case studies because it contains several capabilities that are clearly related but not identical: catalog, checkout, billing, inventory, fulfillment, notifications, and reporting. It also contains many opportunities to make bad boundary choices. Teams often over-centralize around one huge order service, or they over-fragment into entity-based services that chat constantly. The interesting work is not naming the services. It is deciding which responsibilities truly belong together and which interactions should stay synchronous, become asynchronous, or move into read models.
This case study shows one plausible evolution rather than one universal answer.
flowchart LR
C["Catalog"] --> CH["Checkout"]
CH --> B["Billing"]
CH --> I["Inventory"]
CH --> F["Fulfillment"]
C --> R["Search and reporting read models"]
B --> R
I --> R
F --> R
What to notice:
Many teams begin in one of two unhealthy ways:
order service owns ordering, payment status, inventory status, shipment status, and customer notificationsThe first approach centralizes too much workflow and domain meaning into one service. The second spreads one business workflow across too many low-value boundaries. Both create coordination pain, just in different shapes.
A stronger architecture usually treats these as distinct concerns:
Notification and reporting concerns often become:
This keeps the core domain services closer to business meaning.
The main user-facing flow often needs:
That mix matters. If the team makes everything synchronous, the checkout path becomes fragile. If it makes every step asynchronous without clear states, the user experience becomes ambiguous.
1ecommerce_boundary_review:
2 catalog:
3 role: browse_and_discovery
4 source_of_truth: product_data
5 checkout:
6 role: customer_facing_order_flow
7 source_of_truth: order_workflow_state
8 billing:
9 role: payment_and_invoice_logic
10 source_of_truth: payment_state
11 inventory:
12 role: stock_and_reservation_state
13 source_of_truth: availability
14 fulfillment:
15 role: shipment_execution
16 source_of_truth: delivery_progress
What this demonstrates:
Even after a good first design, the system often regresses through:
This is why decomposition is not finished once the first diagram is drawn.
A team says checkout should own payment, inventory, and fulfillment status permanently because “that is the customer journey.” What is the stronger challenge?
The stronger challenge is that customer journey ownership does not automatically equal domain ownership. Checkout should present and coordinate the user-facing flow, but if it becomes the authoritative owner of payment, inventory, and shipment logic too, the architecture is likely recreating one centralized workflow monolith under a more modern name.