Architecture Overview
Wow expresses a business write as command → aggregate decision → domain event → sourced state. The framework connects that path to messaging, storage, waiting, and derived processing. The application still owns business boundaries, event semantics, external side effects, and operational evidence. That is the technical boundary of “Domain Model as a Service” from the Introduction, not a promise that everything outside the domain class is automatically correct.
This is a mechanism explanation. Use Configuration, the Spring Boot Starter, and Send Commands to select capabilities, configure backends, and send commands.
Layers and ownership
| Layer | Main modules | Owns | Does not own |
|---|---|---|---|
| Public contracts | wow-api | Commands, events, aggregate identity, annotations, and other public models | Runtime scheduling or backend implementations |
| Core runtime | wow-core | CommandGateway, aggregate processing, event sourcing, dispatchers, waiting, serialization, and Runtime | Spring bean discovery or a concrete broker/storage |
| Compile time | wow-compiler | Wow metadata, aggregate metadata accessors, and query-property constants derived from annotations | Runtime routing or the OpenAPI document itself |
| Container integration | wow-spring, wow-spring-boot-starter | Spring lifecycle bridge, conditional assembly, component discovery, and capability composition | Business rules or backend-native operations |
| Adapters | wow-kafka, wow-mongo, wow-redis, wow-elasticsearch, and others | Concrete Bus, EventStore, SnapshotStore, and query implementations | Redefining core public semantics |
| Verification | wow-test, wow-tck | Domain test DSL and adapter contract tests | Replacing real recovery, capacity, or failure evidence |
Dependencies flow from public contracts to the core, with Spring and adapters completing composition. A new backend should implement an existing narrow interface and retain its native consistency, acknowledgement, redelivery, and recovery semantics in the adapter instead of reproducing infrastructure in the domain model.
Runtime component view
Three ownership categories matter:
EventStoreholds authoritative event history. A stream becomes recovery input only after append succeeds.SnapshotStoreand projections hold derived data. They can be rebuilt and do not replace event history.- A Bus transports messages. Delivery, acknowledgement, retention, and redelivery strength depend on the selected implementation and configuration.
See Data Flow for cross-capability handoffs and Aggregate Lifecycle for aggregate-internal transitions.
Capability boundaries
| Boundary | Authoritative pages |
|---|---|
| Aggregate decisions, event history, snapshots, and restoration | Domain Model |
| Command definition, sending, completion, and reliability | Commands |
| Processors, sagas, compensation, and event dispatch | Events and Collaboration |
| Projections, queries, and data access | Projection, Query, Data Access Control |
Completing a write does not automatically mean an arbitrary read model is current. Completion Semantics owns the caller-visible contract; this page does not duplicate its stage table or call examples.
Ordering and concurrency boundary
Default dispatchers map messages by aggregate ID into a finite set of groups. A group is processed serially while different groups may run concurrently. An AggregateSchedulerSupplier caches a Reactor Scheduler per named aggregate. The supported scope is therefore that the same aggregate ID maps to the same group within the same dispatcher instance. It does not establish global order across processes, buses, handler functions, or external systems.
Concurrent writes still pass through EventStore version constraints. Scheduling reduces contention inside one instance; append rejects conflicting persistent writes. These are different controls. Backend redelivery also does not make an external side effect idempotent.
See Aggregate Scheduler, Event Dispatch Pipeline, and Event Sourcing.
Lifecycle boundary
WowRuntime is the single high-level owner of runtime components. Every component is prepared before any component starts. Graceful shutdown observes a continuous quiet period, closes global admission, quiesces component intake, and cleans up in reverse order. Fatal component failures and the global deadline enter the same whole-runtime termination path.
Spring adapts that ownership through one WowRuntimeLifecycle. A runtime component must not have a competing Spring lifecycle or destroy owner. See Runtime Lifecycle for the complete contract.
Compile-time and runtime responsibilities
KSP reads declarations such as @BoundedContext and @AggregateRoot, then produces packaged metadata and Kotlin constants. Runtime and interface modules consume those outputs to assemble aggregate discovery, routes, schemas, or OpenAPI. If KSP output is absent, the runtime does not reconstruct the complete contract from this documentation.
See Compiler for generated artifacts, paths, and checks. Serialization and Event Evolution own wire format and persisted-event changes.
Extension checklist
- Keep public models in
wow-api, runtime behavior inwow-core, and concrete backends in their adapters. - Do not introduce blocking calls into reactive command or event paths.
- Decide whether
WowRuntimeowns the new component; if it does, keep one lifecycle owner. - Verify source, binary, and wire impact separately; compilation does not prove historical-data compatibility.
- State only the ordering, retry, idempotency, and acknowledgement scope proven by implementation and tests.
- Verify adapters with their TCK/integration tests, then gather real-environment recovery and operational evidence.
Fact sources
Continue reading
- Core Concepts: stable vocabulary and value flow
- Module Dependencies: exact capabilities and Gradle boundaries
- Production Best Practices: turn component boundaries into release evidence