5 min readCalm pace · scan the outline anytime

Ordering ↔ Warehouse

Place order with ACL stock check; fulfill with Domain Event that deducts reserved stock.

Cookbook — Ordering ↔ Warehouse

Two collaborating modules, zero Application/Domain imports across the boundary.

Story

  1. Place order — Ordering must know stock is available now → sync ACL (validate before commit).
  2. Fulfill order — Warehouse must deduct reserved stock after success → async Domain Event (idempotent consumer).

Module sketches

Ordering/
├── Application/
│   ├── DTO/Order/PlaceOrderDTO.php
│   └── UseCases/Order/PlaceOrderUseCase.php
│                    MarkOrderFulfilledUseCase.php
├── Domain/
│   ├── Entities/OrderEntity.php
│   ├── Events/OrderFulfilled.php          # eventId, schemaVersion, rich payload
│   └── Ports/
│       ├── Order/OrderRepositoryInterface.php
│       └── Acl/WarehouseAvailabilityPortInterface.php
└── Infrastructure/
    └── ExternalServices/WarehouseAvailabilityAclAdapter.php

Warehouse/
├── Application/
│   ├── DTO/.../DeductStockForFulfilledOrderDTO.php
│   └── UseCases/.../DeductStockForFulfilledOrderUseCase.php
├── Domain/
│   └── Ports/Module/WarehouseAvailabilityModuleInterface.php   # thin façade
└── Infrastructure/
    ├── Messaging/OrderFulfilledTranslationListener.php
    └── Persistence/…/ProcessedEventStore (eventId idempotency)

Flow A — place order (ACL)

Port names only: Ordering Use Cases never see the Warehouse *ModuleInterface.

Flow B — fulfill (Event)

Payload: lines, quantities, item codes, order reference — enough that Warehouse does not call back into Ordering Domain on the happy path.

Replaceability checkpoints

ChangeWhat you rewriteWhat stays
Warehouse becomes HTTPWarehouseAvailabilityAclAdapter (+ listener ingress)Ordering Use Cases, local port, Warehouse inbound Use Case
Ordering becomes external publisherWarehouse listener becomes webhook/message consumerDeductStockForFulfilledOrderUseCase

Do not

  • Import Catalog/Sales/Inventory (or any product-app) trees into this story
  • Treat another repository’s class dump as the architecture standard
  • Put stock enums into Shared “for convenience”
  • Span one DB transaction across Ordering + Warehouse tables

Related Core: ACL · Events · Contracts · Event delivery · Decision tree.

Modular Hexagonal Domain-Driven Design
Core 1.0.0-draft