domain driven design – Where does a Process Manager live with a Hexagonal/Ports and Adapters Architecture?

Context: I initially asked this question. I lacked some understanding and phrasing to ask the actual question I wanted to ask. The answer though helped me understand the friction points a bit better to ask this question.


I have three separate Bounded Contexts, and have a new feature requirement that states that, based on an Event from the Upstream Context, two different Commands must be sent to the two Downstream Contexts. This is more appropriately described as a Process Manager (not a Saga, where one operation failure rolls back all operations).

In the book Implementing Domain-Driven Design, a number of packages are described.

  • root.package.(application)
  • root.package.(application.subconcept)
  • root.package.(domain.model)
  • root.package.(domain.model.subconcept)
  • root.package.(domain.service)
  • root.package.(infrastructure)
  • root.package.(infrastructure.persistence)

It also describes Hexagonal Architecture/Ports and Adapters with a pretty straightforward flow.

  • Adapters live in the Infrastructure Layer, and are the clients of the Application Layer/Services
  • Application Services are the clients of the Domain Model

So the code in the *.application package calls the code in the *.domain.* package (model or service).
The code in the *.infrastructure package calls the code in the *.application package.

I noticed a pattern, mechanically (not conceptually), between Aggregates, Projections, and Process Managers.

Projections

  • Consume Events to Produce Current State

Aggregates

  • Consume Events to Produce Current State (Event Sourcing), and
  • Consume Commands to Produce Events (modify Event Stream)

Process Managers

  • Consume Events to Produce Current State (Event Sourcing), and
  • Consume Events to Produce Commands (for other Applications/Aggregates/Contexts)

All three consume Events published by the Domain Model. The Aggregate (Command Model), lives inside the Domain Model, and is sourced from Domain Events. The Projections (Query Model), lives next to the Domain Model (*.projections), and is sourced from Domain Events. The Process Manager lives somewhere, and is sourced from Domain Events.


Based on this, where do the Process Managers live? Do they also live next to the Domain Model (in a *.process package)? Does it exist as an output Adapter, which might place it inside the *.infrastructure package? Remember that this particular Process Manager is not required for the Upstream Context to work, nor is it required for the Downstream Context to work; it is entirely an optional integration between the Upstream, and the two Downstream Contexts.

  • Do optional integrations exist in a separate Bounded Context, in a *.process package, as an Adapter in the Infrastructure?
  • Do required integrations that are sourced from Upstream Events belong in the Upstream Domain Model?
  • Do required integrations that are sourced from multiple Upstream Events, but interact only with one Downstream Context, belong in the Downstream Domain Model, maybe as an input Adapter?