diff --git a/docs/architecture-decisions/adr009-sagas-for-reactive-cross-domain-interactions.md b/docs/architecture-decisions/adr009-sagas-for-reactive-cross-domain-interactions.md new file mode 100644 index 00000000..09edfcc7 --- /dev/null +++ b/docs/architecture-decisions/adr009-sagas-for-reactive-cross-domain-interactions.md @@ -0,0 +1,64 @@ +# ADR010: Using NestJS Sagas for Cross-Domain Interactions (Reactive) + +## Status + +Accepted + +## Context + +As Kordis embraces loose coupling and an event-driven architecture, managing +interactions between bounded contexts is a critical topic. Traditional +approaches often involve direct integration between domains, leading to tight +coupling and reduced flexibility. The system requires a mechanism to react to +events from various domains and translate these events into appropriate actions +within a target domain without creating direct dependencies between them. + +## Decision + +We have decided to adopt NestJS Sagas to handle cross-domain interactions within +our system. NestJS Sagas will act as a mediator that listens to domain events +from various sources and translates them into domain-specific commands. This +approach leverages the strengths of NestJS's built-in support for event handling +and Sagas' ability to orchestrate complex sequences of operations across +different domains. + +Implementation involves the following steps: + +Listening to Events: Sagas will subscribe to events published by other domains +to the EventBus.
Data Enrichment and Transformation: Upon receiving an +event, the Saga may perform necessary queries to fetch additional data required +to process the event. It will also transform the event data into a format that +is understood by the target domain. You should use the +[rxjs operators](https://rxjs.dev/api/operators/) for this.
Command +Execution: The Saga then issues a command to the target domain, effectively +translating the event from the source domain into an actionable command in the +target domain.
By using Sagas in this manner, we create a layer that +abstracts the process of reacting to external events and invoking +domain-specific operations. This layer serves as the interface for interaction +with the domains.

**The Saga implementation CAN live in the domain of +the target domain (the domain that receives the commands), since, as described, +we believe it acts as an interface. But, it should never be part of the domains +module and therefore never use specific providers. It should only communicate +via Commands and Queries, as the whole idea is, the Saga could live somewhere +else in the system, and it should not depend on the domain module.** + +## Consequences + +**Benefits:**
Decoupling: This approach significantly reduces the coupling +between domains, as they only need to emit events and listen to commands, +without knowing the internals of other domains.
Flexibility: It becomes +easier to add new sources of events or change the logic of how events are +processed, as these changes are encapsulated within the Sagas.
+Maintainability: By centralizing the logic for cross-domain interactions within +Sagas, the system becomes more maintainable. Each Saga can be independently +developed, tested, and modified, and in the future also independently +deployed.

**Drawbacks:**
Complexity: Introducing Sagas adds a layer +of complexity to the system, requiring developers to understand the event-driven +model and the specifics of Saga implementation.
Debugging and Tracing: +Tracking the flow of events and commands through Sagas can be challenging, +especially in a system with many interacting domains. Effective logging and +tracing mechanisms are essential to mitigate this issue.

Adopting +NestJS Sagas for cross-domain interactions presents a strategic approach to +building scalable, maintainable, and decoupled systems. The benefits in terms of +flexibility and maintainability outweigh the challenges associated with the +added complexity and debugging difficulties. diff --git a/docs/architecture-decisions/adr010-managers-for-proactive-cross-domain-interactions.md b/docs/architecture-decisions/adr010-managers-for-proactive-cross-domain-interactions.md new file mode 100644 index 00000000..35f025eb --- /dev/null +++ b/docs/architecture-decisions/adr010-managers-for-proactive-cross-domain-interactions.md @@ -0,0 +1,57 @@ +# ADR010: Using Managers for Cross-Domain Interactions (Proactive) + +## Status + +Accepted + +## Context + +As Kordis embraces loose coupling and an event-driven architecture, managing +interactions between bounded contexts is a critical topic. Traditional +approaches often involve direct integration between domains, leading to tight +coupling and reduced flexibility. The system requires a mechanism to communicate +with multiple systems in order to manage cross domain related tasks. This is +analogous to the reactive part described in +[ADR009](./adr009-sagas-for-reactive-cross-domain-interactions.md), but the +difference is, that the system is not reacting to events, but proactively +communicating with other systems. + +## Decision + +We have decided to adopt the concept of Managers to handle cross-domain +interactions within our system. Managers will act as a mediator that +communicates with other systems and translates them into domain-specific +commands. By introducing a dedicated instance that communicates with each +domain, we decouple the domains from each other and create a layer that +abstracts the process of interacting with other domains. This layer serves as +the interface for interaction with the domains. + +Implementation involves the following steps:
Process managers will be +implemented as a distinct library and NestJS module. The manager will follow the +Clean Architecture approach, just as it is implemented in every Domain Module. +The Manager is allowed to implement actual Controllers (e.g. GraphQL resolvers) +in order to react to incoming request from the frontend/other systems. The +manager is allowed to throw "Domain"-specific events and implement reactive +components to these events, such as GraphQL Subscription Handlers. The +interaction with Domains should be done via Commands and Queries, as the whole +idea is, the Manager could live somewhere else in the system, and it should not +depend on the domain module. The Manager must not use specific providers from +the domain module. This makes sure that we can outsource the Manager and Domains +and let them interact through a Bus. + +## Consequences + +**Benefits:** + +Decoupling: This approach significantly reduces the coupling between domains, as +they only need to emit events and listen to commands, without knowing the +internals of other domains. + +**Drawbacks:** + +Complexity: Introducing Managers adds a layer of complexity to the system, +requiring developers to understand the specifics of Manager implementation. + +Debugging and Tracing: Tracking the flow of events and commands through Managers +can be challenging, especially in a system with many interacting domains. +Effective logging and tracing mechanisms are essential to mitigate this issue.