# Wow **Repository Path**: bistulpf/Wow ## Basic Information - **Project Name**: Wow - **Description**: 领域模型即服务 - 基于 DDD & EventSourcing 的现代响应式 CQRS 架构微服务开发框架 - **Primary Language**: Kotlin - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: https://wow.ahoo.me/ - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 89 - **Created**: 2025-07-04 - **Last Updated**: 2025-07-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

Wow:A Modern Reactive CQRS Architecture Microservice development framework based on DDD and EventSourcing

# Wow : Modern Reactive CQRS Architecture Microservice development framework based on DDD and EventSourcing > [中文文档](https://wow.ahoo.me/) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://github.com/Ahoo-Wang/Wow/blob/main/LICENSE) [![GitHub release](https://img.shields.io/github/release/Ahoo-Wang/Wow.svg)](https://github.com/Ahoo-Wang/Wow/releases) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/me.ahoo.wow/wow-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/me.ahoo.wow/wow-core) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/cfc724df22db4f9387525258c8a59609)](https://app.codacy.com/gh/Ahoo-Wang/Wow/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![codecov](https://codecov.io/gh/Ahoo-Wang/Wow/branch/main/graph/badge.svg?token=uloJrLoQir)](https://codecov.io/gh/Ahoo-Wang/Wow) [![Integration Test Status](https://github.com/Ahoo-Wang/Wow/actions/workflows/integration-test.yml/badge.svg)](https://github.com/Ahoo-Wang/Wow) [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/Ahoo-Wang/Wow) **Domain-Driven** | **Event-Driven** | **Test-Driven** | **Declarative-Design** | **Reactive Programming** | **Command Query Responsibility Segregation** | **Event Sourcing** ## Quick Start Use [Wow Project Template](https://github.com/Ahoo-Wang/wow-project-template) to quickly create a DDD project based on the Wow framework. ## Features Overview

Wow-Features

## Architecture

Wow-Architecture

## Performance Test (Example) - Test Code: [Example](./example) - Test Case: Add To Shopping Cart / Create Order - Command `WaitStrategy`: `SENT`、`PROCESSED` ### Deployment - [Redis](deploy/example/perf/redis.yaml) - [MongoDB](deploy/example/perf/mongo.yaml) - [Kafka](deploy/example/perf/kafka.yaml) - [Application-Config](deploy/example/perf/config/mongo_kafka_redis.yaml) - [Application-Deployment](deploy/example/perf/deployment.yaml) ### Test Report #### Add To Shopping Cart - [Request](deploy/example/request/AddCartItem.http) - [Detailed Report(PDF)-SENT](./document/example/perf/Example.Cart.Add@SENT.pdf) - [Detailed Report(PDF)-PROCESSED](./document/example/perf/Example.Cart.Add@PROCESSED.pdf) > `WaitStrategy`:`SENT` Mode, The `AddCartItem` command write request API After 2 minutes of stress testing, the average TPS was *59625*, the peak was *82312*, and the average response time was *29* ms.

AddCartItem-SENT

> `WaitStrategy`:`PROCESSED` Mode, The `AddCartItem` command write request API After 2 minutes of stress testing, the average TPS was *18696*, the peak was *24141*, and the average response time was *239* ms.

AddCartItem-PROCESSED

#### Create Order - [Request](deploy/example/request/CreateOrder.http) - [Detailed Report(PDF)-SENT](./document/example/perf/Example.Order.Create@SENT.pdf) - [Detailed Report(PDF)-PROCESSED](./document/example/perf/Example.Order.Create@PROCESSED.pdf) > `WaitStrategy`:`SENT` Mode, The `CreateOrder` command write request API After 2 minutes of stress testing, the average TPS was *47838*, the peak was *86200*, and the average response time was *217* ms.

CreateOrder-SENT

> `WaitStrategy`:`PROCESSED` Mode, The `CreateOrder` command write request API After 2 minutes of stress testing, the average TPS was *18230*, the peak was *25506*, and the average response time was *268* ms.

CreateOrder-PROCESSED

## Event Sourcing

Wow-EventSourcing

## Observability

Wow-Observability

## OpenAPI (Spring WebFlux Integration) > Automatically register the `Command` routing processing function (`HandlerFunction`), and developers only need to > write the domain model to complete the service development.

Wow-Spring-WebFlux-Integration

## Test suite: 80%+ test coverage is very easy > Given -> When -> Expect .

Wow-CI-Flow

## Preconditions - Understanding **Domain Driven Design**:《Implementing Domain-Driven Design》,《Domain-Driven Design: Tackling Complexity in the Heart of Software》 - Understanding **Command Query Responsibility Segregation**(CQRS) - Understanding **EventSourcing** - Understanding **Reactive Programming** ### Order Service(Kotlin) [Example-Order](./example) ### Transfer(JAVA) [Example-Transfer](./example/transfer) ## Unit Test Suite ### 80%+ test coverage is very easy. ![Test Coverage](./document/example/example-domain-jococo.png) > Given -> When -> Expect . ### Aggregate Unit Test (`AggregateVerifier`) [Aggregate Test](./example/example-domain/src/test/kotlin/me/ahoo/wow/example/domain/order/OrderTest.kt) ```kotlin class CartTest { @Test fun addCartItem() { val ownerId = generateGlobalId() val addCartItem = AddCartItem( productId = "productId", quantity = 1, ) aggregateVerifier(ownerId) .givenOwnerId(ownerId) .whenCommand(addCartItem) .expectNoError() .expectEventType(CartItemAdded::class) .expectState { it.items.assert().hasSize(1) }.expectStateAggregate { it.ownerId.assert().isEqualTo(ownerId) } .verify() } @Test fun givenStateWhenAdd() { val addCartItem = AddCartItem( productId = "productId", quantity = 1, ) aggregateVerifier() .givenState(CartState(generateGlobalId()), 1) .whenCommand(addCartItem) .expectNoError() .expectEventType(CartItemAdded::class) .expectState { it.items.assert().hasSize(1) } .verify() } @Test fun addCartItemIfSameProduct() { val addCartItem = AddCartItem( productId = "productId", quantity = 1, ) aggregateVerifier() .given( CartItemAdded( added = CartItem( productId = addCartItem.productId, quantity = 1, ), ), ) .whenCommand(addCartItem) .expectNoError() .expectEventType(CartQuantityChanged::class) .expectState { it.items.assert().hasSize(1) it.items.first().quantity.assert().isEqualTo(2) } .verify() } @Test fun addCartItemIfUnCreated() { val addCartItem = AddCartItem( productId = "productId", quantity = 1, ) aggregateVerifier() .given() .whenCommand(addCartItem) .expectNoError() .expectEventType(CartItemAdded::class) .expectState { it.items.assert().hasSize(1) } .expectStateAggregate { it.version.assert().isEqualTo(1) } .verify() } @Test fun addCartItemGivenMax() { val events = buildList { for (i in 0..99) { add( CartItemAdded( added = CartItem( productId = "productId$i", quantity = 1, ), ), ) } }.toTypedArray() val addCartItem = AddCartItem( productId = "productId", quantity = 1, ) aggregateVerifier() .given(*events) .whenCommand(addCartItem) .expectErrorType(IllegalArgumentException::class) .expectState { it.items.assert().hasSize(MAX_CART_ITEM_SIZE) } .verify() } @Test fun removeCartItem() { val removeCartItem = RemoveCartItem( productIds = setOf("productId"), ) val added = CartItem( productId = "productId", quantity = 1, ) aggregateVerifier() .given( CartItemAdded( added = added, ), ) .whenCommand(removeCartItem) .expectEventType(CartItemRemoved::class) .expectState { it.items.assert().isEmpty() } .verify() } @Test fun changeQuantity() { val changeQuantity = ChangeQuantity( productId = "productId", quantity = 2, ) val added = CartItem( productId = "productId", quantity = 1, ) aggregateVerifier() .given( CartItemAdded( added = added, ), ) .whenCommand(changeQuantity) .expectEventType(CartQuantityChanged::class) .expectState { it.items.assert().hasSize(1) it.items.first().quantity.assert().isEqualTo(changeQuantity.quantity) } .verify() } @Test fun onCreateThenDeleteThenRecover() { val addCartItem = AddCartItem( productId = "productId", quantity = 1, ) aggregateVerifier() .whenCommand(addCartItem) .expectNoError() .expectEventType(CartItemAdded::class) .expectState { it.items.assert().hasSize(1) } .verify() .then() .whenCommand(DefaultDeleteAggregate) .expectEventType(DefaultAggregateDeleted::class) .expectStateAggregate { it.deleted.assert().isTrue() }.verify() .then() .whenCommand(DefaultDeleteAggregate::class) .expectErrorType(IllegalAccessDeletedAggregateException::class) .verify() .then() .whenCommand(DefaultRecoverAggregate) .expectStateAggregate { it.deleted.assert().isFalse() }.verify() .then() .whenCommand(DefaultRecoverAggregate) .expectErrorType(IllegalStateException::class) .verify() } } ``` ### Saga Unit Test (`SagaVerifier`) [Saga Test](./example/example-domain/src/test/kotlin/me/ahoo/wow/example/domain/cart/CartSagaTest.kt) ```kotlin class CartSagaTest { @Test fun onOrderCreated() { val ownerId = generateGlobalId() val orderItem = OrderItem( id = generateGlobalId(), productId = generateGlobalId(), price = BigDecimal.valueOf(10), quantity = 10, ) sagaVerifier() .whenEvent( event = mockk { every { items } returns listOf(orderItem) every { fromCart } returns true }, ownerId = ownerId ) .expectCommand { it.aggregateId.id.assert().isEqualTo(ownerId) it.body.productIds.assert().hasSize(1) it.body.productIds.assert().first().isEqualTo(orderItem.productId) } .verify() } } ``` ## Design ### Modeling | **Single Class** | **Inheritance Pattern** | **Aggregation Pattern** | |----------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------| | ![Single Class - Modeling](./document/design/assets/Modeling-Single-Class-Pattern.svg) | ![Inheritance Pattern- Modeling](./document/design/assets/Modeling-Inheritance-Pattern.svg) | ![Aggregation Pattern- Modeling](./document/design/assets/Modeling-Aggregation-Pattern.svg) | ### Load Aggregate

Load Aggregate

### Aggregate State Flow

Aggregate State Flow

### Send Command

Send Command

### Command And Event Flow

Command And Event Flow

## Event Compensation ### Use Case

Event-Compensation-UserCase

### Execution Sequence Diagram

Event-Compensation

### Dashboard

Compensation-Dashboard

Compensation-Dashboard

Compensation-Dashboard

Compensation-Dashboard-Error