Skip to content
Examples

WirSchiffenDas arc42 section 9

Architecture Decisions

ADR Decision Considered alternatives Consequence
ADR-001: Choreography instead of central orchestration The coordinator starts only the anchor Fluids; Fluids starts Drivetrain and Mechanical, both report to EMS. The coordinator does not know the flow, but knows the expected result set (read model). central orchestration as orchestrator or saga process manager; completion report by the last step (“last step reports done”). Rejected: choreography required, coordinator otherwise a single point of failure, a reporting final step wires the order again. Happy path decentralised, order open, EMS needs local state; the run projection is observation.
ADR-002: Coexistence of REST and Kafka REST /analyze represents the transitions, Kafka transports status, results and retry, SSE the aggregated view. REST only with callback or polling; Kafka only, which would remove the immediate acceptance of a start; WebSocket instead of SSE. REST edges can be protected locally by breakers, Kafka decouples the UI projection; operations needs a broker.
ADR-003: Decentralised retry as Kafka command The coordinator cleans up its read model and publishes { runId, cluster } on analysis-retry; the service interprets it itself. executing the retry in the coordinator via REST; repeating the entire run; sending the command via REST. The coordinator remains the entry point; a retry of Fluids continues the choreography, EMS invalidates subsequent states.
ADR-004: Reduced AnalyzeRequest Only runId and optionally source for the EMS fan-in; the configuration stays in the config service. carrying the configuration in the request; passing on upstream results; letting every service load the configuration itself. The contract matches the data need; the results are simulated, not computed from equipment values (TS-6).
ADR-005: Circuit breaker at the caller with status fallback, without service registry Opossum breaker at the caller instead of at the target (Nygard, chapter 5); the fallback publishes failed, discovery via Compose DNS. Hystrix with Eureka (JVM, end of life); Resilience4j (JVM); breaker in the target; Consul as registry; dummy fallback. Resilience emerges locally per edge (§6.4); scaling requires a registry or service mesh (TS-4), publishing another service’s status is TS-5.
ADR-006: Business cut into four clusters, Fluids as anchor, EMS as fan-in Cut by physical assembly groups: Fluids (three groups), Drivetrain (two), Mechanical (four), EMS (two). eleven services, one per equipment (Nano Service); a single analysis service as in the as-is architecture (Mega Service); anchor in the coordinator. The call graph is a DAG; a new cluster costs one entry each in the cluster enum, in RETRY_PROJECTION_SCOPE and in Compose.
ADR-007: Persistence only for the configuration, runtime state volatile Database per service only for the config service (PostgreSQL 16); run projection and EMS fan-in are held process-locally in memory. shared database for all services (Shared Persistence); Redis for the projection; event sourcing with replay. Coordinator and EMS are not horizontally scalable, a restart loses running runs (TS-4).
ADR-008: Deployment with Docker Compose from a monorepo with a shared Dockerfile Eight containers: six NestJS applications, Kafka, PostgreSQL; all images from the same multi-stage Dockerfile via ARG APP. cloud platform such as SEPP or Kubernetes; separate repository and Dockerfile per service; schema registry instead of shared types. Reproducible start with one command; independent deployability limited by the shared library (TS-1).