Skip to content
CAI
Software that uses CAICheck a score

schneisn/ddd-cqrs-es

53.3

Adequate · 22 September 2026

4.7k

lines of production code

Java

primary language

6

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

This system is a Java-based microservice implementing a CQRS and Event Sourcing architecture, centered around a 'User' domain. It manages user creation and profile updates by persisting state changes as domain events in a PostgreSQL-backed event store, while simultaneously maintaining a MongoDB read model for queries. The service exposes REST APIs and processes asynchronous events via Kafka to trigger downstream notifications, all supported by a comprehensive suite of integration and unit tests.

Features

Add event store subscription with advisory locking and dynamic polling

The event store subscription mechanism is introduced, enabling subscribers to poll for new events from the event store. This implementation includes an AdvisoryLockManager to manage database advisory locks for safe concurrent polling, and a dynamic polling interval that increases when no new events are found, optimizing resource usage during low event volume. The subscription state and offsets are persisted via a new JpaSubscriptionRepository.

_src/main/java/xx/schneisn/ddd\_cqrs\es/lib/es · high confidence

Add synchronous event bus alongside existing asynchronous Kafka integration

The project now supports both asynchronous and synchronous event propagation. An asynchronous Kafka-based event bus is configured via environment variables (e.g., SPRING\_KAFKA\BOOTSTRAP\...), while a new synchronous event bus using Spring's ApplicationEventPublisher is introduced. This allows domain events to be handled via Spring's internal event mechanism in addition to the existing Kafka-based external event publishing and projection listeners.

(repo-wide) · high confidence

Add user query handler for finding users

A new query handler, FindUserQueryHandler, has been added to the application layer. This component implements the QueryHandler interface to process FindUserQuery requests, delegating to the UserViewRepositoryPort to retrieve user data as a UserViewV1 object.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/application/query · high confidence

Added Kafka event listener and command handler for user notifications

The notification module now includes a new Kafka listener (NotificationKafkaEventListener) that deserializes user creation events and dispatches a NotifyUserCommand via the command bus. A corresponding command handler (NotificationCommandHandler) processes this command to trigger user notifications. A DTO (UserCreatedDtoV1) is introduced to map incoming Kafka messages.

_src/main/java/xx/schneisn/ddd\_cqrs\es/notification/adapter · high confidence

Added command handlers for user creation and name updates

Users can now have their name changed and be created through new command handlers (ChangeUserNameCommandHandler and CreateUserCommandHandler) that interact with the event store to persist user data.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/application/command · high confidence

Added notification domain models and command structure

Introduced new domain classes for the notification feature: a NotificationId value object extending DomainEntityId, and a NotifyUserCommand class containing userId, name, and email fields. This establishes the foundational data structures for the notification domain.

_src/main/java/xx/schneisn/ddd\_cqrs\es/notification/domain · high confidence

Centralized configuration for event store, Kafka, and command bus

A new application.properties file has been added to src/main/resources, consolidating configuration for the PostgreSQL database, Kafka event bus, MongoDB read model, and command handling. The file defines connection details for the event store and Kafka, sets up adaptive polling parameters for event subscription, configures retry behavior via Resilience4j, and defines Kafka topic and group IDs for user and notification projections.

src/main/resources · high confidence

Initial database schema and migration setup

The database layer is initialized with a Flyway migration (V1\_\_initial\_setup.sql) that creates the core CQRS/Event Sourcing tables: 'event' (partitioned by hash on aggregate\_id), 'snapshot', and 'subscription'. The 'event' table includes fields for event\_id, aggregate\_id, aggregate\_type, aggregate\_version, event\_type, data, metadata, and timestamp. The 'snapshot' table stores aggregate state, and the 'subscription' table tracks subscriber names and stream offsets. A docker-compose.yaml file is added to configure the Flyway migration service, connecting to a PostgreSQL database named 'microservices' with schema 'ddd-cqrs-es'.

db · high confidence

Introduce dedicated Kafka listener for user projection processing

A new \UserProjectionListener\ component has been added to handle incoming Kafka events for the user projection. This listener deserializes raw Kafka messages, maps them to domain events using the \EventMapperRegistry\, and forwards them to the \UserViewV1Projection\ service for processing. The implementation includes explicit acknowledgment handling, logging, and error management, ensuring that user-related events are correctly routed and processed within the event-driven architecture.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/adapter/in/eventlistener · medium confidence

Introduce versioned user view projection

Added a new versioned user view projection (UserViewV1) that subscribes to the event store and updates a read model. The projection handles UserCreatedV2 and UserNameChangedV1 events to populate the user view, with logic to ignore stale events based on aggregate version.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/application/projection · high confidence

Introduces comprehensive configuration for event sourcing, Kafka, and async processing

The application now includes a full suite of configuration classes that enable event-driven architecture features. This adds support for asynchronous task execution with context propagation, configurable Kafka producer and consumer settings, and a JPA-based event store subscription with distributed locking. Additionally, the system now supports command retry logic on failure and exposes OpenAPI documentation. These changes allow the application to reliably process events via Kafka and the database, while maintaining traceability across async boundaries.

_src/main/java/xx/schneisn/ddd\_cqrs\es/config · high confidence

New domain-specific exception types for event sourcing

The codebase now includes a set of new exception classes in the \xx.schneisn.ddd\_cqrs\_es.lib.es.exceptions\ package to handle specific failure scenarios in the event sourcing library. These include \AggregateNotFoundException\ and \NotFoundException\ for missing entities, \CommandExecutionFailedException\ to wrap execution failures with detailed results, \ConstraintException\ for validation errors, \EventDeserializationException\ and \EventSerializationException\ for data format issues, \InvalidEventException\ and \InvalidEventTypeException\ for bad event data, and \OptimisticLockingException\ for concurrency conflicts. These changes provide more granular error handling for developers using the library.

_src/main/java/xx/schneisn/ddd\_cqrs\es/lib/es/exceptions · high confidence

NotifyUserPolicy subscribes to UserCreatedV2 events via EventStoreSubscription

The new NotifyUserPolicy component registers a listener for UserCreatedV2 events using the EventStoreSubscription abstraction. Upon application startup, it subscribes to the User aggregate type and, when a UserCreatedV2 event is received, invokes the NotificationPort to send the user a notification.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/application/policy · high confidence

Behavioural changes

Added FindUserQuery for user lookups

A new FindUserQuery class has been added to the application's in-port layer, enabling the system to process queries for retrieving user information by ID.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/application/port/in · high confidence

Added event transformer for user creation

A new transformer, UserCreatedEventV1ToV2Transformer, was added to the user adapter's output layer. This component converts UserCreatedV1 domain events into UserCreatedV2, specifically adding a default Age value of 18 during the transformation process.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/adapter/out · high confidence

Enforce non-null constraints on user commands

The user domain commands (CreateUserCommand, ChangeUserNameCommand) now enforce non-null constraints on their fields using requireNonNull, ensuring that critical attributes like name, email, and userId cannot be null at construction time.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/domain/command · medium confidence

Introduce user domain model with value objects

The user domain now includes new value objects for Age, Email, and UserName, alongside a refactored User aggregate that uses these value objects and domain events (UserCreatedV2, UserNameChangedV1) to manage state. This change simplifies event handling and enforces immutability through value objects.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/domain · medium confidence

Introduce value objects for user domain events and DTOs

The user module now uses value objects (UserId, UserName, Email, Age) within its domain events (UserCreatedV1, UserCreatedV2, UserNameChangedV1) and their corresponding DTOs (UserCreatedV1Dto, UserCreatedV2Dto, UserNameChangedV1Dto). A new UserEventMapper is added to handle the mapping between domain events and DTOs, ensuring that value objects are properly encapsulated and transformed for external communication.

_src/main/java/xx/schneisn/ddd\_cqrs\_es/user/adapter/out/mapper, src/main/java/xx/schneisn/ddd\_cqrs\es/user/domain/event · medium confidence

Introduces reactive and synchronous MongoDB repositories for the user view

The user view persistence layer now includes both reactive and synchronous Spring Data MongoDB repositories (ReactiveUserViewV1MongoRepository, UserViewV1MongoRepository) along with a new adapter (UserViewRepositoryAdapter) that implements the UserViewRepositoryPort. This adapter provides methods for finding, saving, and deleting user views by aggregate ID, as well as streaming changes via MongoDB change streams, enabling the application to interact with the user view data in both blocking and non-blocking ways.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/adapter/out/user · medium confidence

Kafka-based notification adapter for user events

The system now sends user notifications via Kafka. A new \NotificationAdapter\ serializes \UserCreatedV2\ events into a \UserCreatedDtoV1\ record and publishes them to the \user-notification\ topic. This replaces the previous in-memory or alternative notification mechanism, introducing a timeout of 3000ms for message delivery and logging at the debug level for successful publishes.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/adapter/out/notification · high confidence

New ports for user notifications and view persistence

The application now exposes two new ports in the user module: a NotificationPort interface for sending user notifications (specifically for UserCreatedV2 events) and a UserViewRepositoryPort interface for persisting and querying UserViewV1 data, including methods for saving, deleting, finding by ID, and streaming changes.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/application/port/out · high confidence

Standardize API response and error handling for user operations

The user API now returns a structured CommandResultDto for all command endpoints, providing consistent success, failure, and payload-wrapped responses. A new GlobalExceptionHandler intercepts CommandExecutionFailedException, NotFoundException, and generic exceptions, mapping them to standardized ErrorResponseDto payloads with appropriate HTTP status codes. Request and response DTOs (CreateUserRequestDtoV1, ChangeUserNameRequestDtoV1, UserDtoV1) and their mappers are introduced to decouple the API layer from internal domain models.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/adapter/in/api · high confidence

Updated Maven Wrapper to version 3.9.9

The project's Maven wrapper has been updated to version 3.9.9, ensuring that builds use a consistent and modern version of Apache Maven. This change standardizes the build environment and may improve build performance and compatibility.

.mvn · high confidence

User view model moved to domain package

The UserViewV1 class, which represents the user's profile data (including name, email, age, and timestamps), has been moved from a general location into the user domain package. This reorganization aligns the view model with the domain layer, reflecting a structural change in how user data is organized within the application's architecture.

_src/main/java/xx/schneisn/ddd\_cqrs\es/user/domain/view · low confidence

Test coverage

Added integration test for user creation flow; Added integration tests for user command handlers; Added test configuration and utility scripts; Added test configuration for Event Store and Kafka topics; Added test factory for UserViewV1; Added test infrastructure for integration and service tests; Added tests for the event store, command bus, and domain entities; Added tests for user view projection and projector; Added unit tests for User domain object; Integration tests for the user controller.

Dependencies

Initial Maven build configuration for Spring Boot project

The project's build is now defined by a new pom.xml file, establishing a Spring Boot 3.4.1 base with Java 23. The configuration includes dependencies for web, security, and actuator, alongside integrations for Kafka, PostgreSQL, and MongoDB. It also adds testing support via Testcontainers and includes libraries for resilience (Resilience4j) and distributed tracing (OpenTelemetry, Micrometer).

(dependencies) · high confidence

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

How this codebase got here

Score

  • CAI 57 → 53 (-4.1)
  • Rubric changed (rubric-2026.08.19 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 98 → 98 (-0.7)
  • Architecture 98 → 88 (-10.0)
  • Maturity 57 → 58 (+0.5)
  • Readiness 32 → 35 (+2.8)
  • Security 98 → 93 (-5.4)
  • Domain Modelling 100 → 66 (-33.5)

Resolved (15)

  • Change coupling: Event.java ↔ SnapshotUtils.java (src/main/java/xx/schneisn/ddd_cqrs_es/lib/es/Event.java)
  • Change coupling: JpaEventStore.java ↔ KafkaEventBus.java (src/main/java/xx/schneisn/ddd_cqrs_es/lib/es/JpaEventStore.java)
  • Change coupling: KafkaEventBus.java ↔ SnapshotUtils.java (src/main/java/xx/schneisn/ddd_cqrs_es/lib/es/KafkaEventBus.java)
  • Coverage not included — suite not readable by the collector
  • Dependency hygiene not measured — dependency manifest found but not parsed for hygiene
  • Duplicated block (6 lines × 2) (src/main/java/xx/schneisn/ddd_cqrs_es/lib/es/Event.java)
  • Duplicated block (7 lines × 2) (src/main/java/xx/schneisn/ddd_cqrs_es/lib/es/JpaEventStoreSubscription.java)
  • Duplicated block (8 lines × 3) (src/main/java/xx/schneisn/ddd_cqrs_es/lib/es/JpaEventStore.java)
  • Duplicated block (9 lines × 2) (src/main/java/xx/schneisn/ddd_cqrs_es/lib/es/JpaEventStoreSubscription.java)
  • Medium IaC: CKV_DOCKER_3 (Dockerfile)
  • No exposed public API
  • Scanner failed to run — not a clean result
  • Test reliability not included
  • There is no link to an event store implementation or snapshots guide. (README.md)
  • single-maintainer — knowledge-concentration (bus factor) risk

New (41)

  • Change coupling: JpaEventStore.java ↔ User.java (src/main/java/xx/schneisn/ddd_cqrs_es/lib/es/JpaEventStore.java)
  • Dependency hygiene PARTLY measured — Maven/Gradle declarations read, no dependency graph resolved
  • Documentation: no installation or build instructions (README.md)
  • Documentation: no usage examples (README.md)
  • Duplicated block (12–13 lines × 3) (src/main/java/xx/schneisn/ddd_cqrs_es/lib/es/JpaEventStore.java)
  • Duplicated block (8 lines × 2) (src/main/java/xx/schneisn/ddd_cqrs_es/lib/es/JpaEventStoreSubscription.java)
  • FixmeComment (src/test/java/xx/schneisn/ddd_cqrs_es/lib/es/TransformerChainTest.java)
  • High IaC: WD-COMPOSE-0002 (docker/docker-compose.yaml)
  • Medium IaC: WD-COMPOSE-0002 (db/docker-compose.yaml)
  • Medium IaC: WD-COMPOSE-0002 (docker/docker-compose.yaml)
  • Medium IaC: WD-COMPOSE-0002 (docker/docker-compose.yaml)
  • Medium IaC: WD-COMPOSE-0002 (docker/docker-compose.yaml)
  • Medium IaC: WD-COMPOSE-0002 (docker/docker-compose.yaml)
  • Medium IaC: WD-COMPOSE-0002 (docker/docker-compose.yaml)
  • Medium IaC: WD-COMPOSE-0002 (docker/docker-compose.yaml)
  • Medium IaC: WD-COMPOSE-0002 (docker/docker-compose.yaml)
  • Medium IaC: WD-COMPOSE-0002 (docker/docker-compose.yaml)
  • Medium IaC: WD-COMPOSE-0002 (docker/docker-compose.yaml)
  • Medium IaC: WD-COMPOSE-0002 (docker/docker-compose.yaml)
  • Medium IaC: WD-COMPOSE-0002 (docker/docker-compose.yaml)
  • …and 21 more

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

schneisn/ddd-cqrs-es was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.

About this page

  • The score is its most recent published measurement, taken on 22 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
  • Measured at commit a610c75141181ade06db24b68b3a55747746752d — the exact code this score is about.
  • Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
  • Measured by watchdog.canine.dev using codehealth-analyzer preprod-821afab8930d.