This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
./mvnw clean install- Clean build with all tests./mvnw install -DskipTests- Fast build without tests./mvnw spring-boot:run- Run the application locally./mvnw test- Run all tests./mvnw test -Dtest=ClassName- Run specific test class./mvnw test -Dtest=ClassName#methodName- Run specific test method
docker compose up- Start Axon Server and PostgreSQL containersdocker compose down- Stop containers- Application runs on default Spring Boot port (8080)
- Axon Server UI available at http://localhost:8024
- PostgreSQL accessible at localhost:6446
- Tests use real PostgreSQL Event Store via Testcontainers
- All tests follow BDD pattern: given(events) → when(command) → then(events/state)
- Use
AxonUtilsandEventStoreAssertionshelper classes for test setup
This is a Domain-Driven Design implementation using Event Sourcing with Axon Framework and Spring Modulith. The application models a Heroes of Might & Magic III domain with four main bounded contexts.
- Event Sourcing: All state changes captured as domain events
- CQRS: Separate write (command) and read (query) models
- Vertical Slice Architecture: Features organized by capability, not technical layer
- Spring Modulith: Module boundaries enforced at compile time
- Event Modeling: System design follows Event Modeling nomenclature
Each domain module follows a consistent structure with three slice types:
com.dddheroes.heroesofddd/
├── armies/ # Army management
├── astrologers/ # Week symbols and creature bonuses
├── calendar/ # Game time progression
├── creaturerecruitment/ # Building dwellings and recruiting creatures
├── resourcespool/ # Player resources management
├── maintenance/ # Event store operations
└── shared/ # Common domain concepts
- write/: Commands → Aggregates → Events (business logic)
- read/: Event projections → Read models → Queries (data access)
- automation/: Event processors implementing business policies
- events/: Domain events (contracts between slices)
Army- manages creature stacks (max 7)Dwelling- creature recruitment buildingsCalendar- game time progressionAstrologers- weekly creature bonusesResourcesPool- player resources (gold, wood, etc.)
- Uses Axon Framework event processors with game-specific sequencing
- All processors use
gameIdSequencingPolicyfor consistency - Dead Letter Queue (DLQ) enabled for automation processors
- Event store backed by PostgreSQL with JPA
- Armies limited to 7 creature stacks (
CanHaveMax7CreatureStacksInArmy) - Cannot recruit more creatures than available (
RecruitCreaturesNotExceedAvailableCreatures) - Days must be started in sequence (
CannotSkipDays) - One week symbol per week (
OnlyOneSymbolPerWeek)
Tests focus on observable behavior using Axon Test Fixture:
- Write slice tests: given(events) → when(command) → then(events)
- Read slice tests: given(events) → then(read model state)
- Automation tests: when(event) → then(command issued)
- Swagger UI available at
/swagger-ui.html - API docs at
/api-docs - Maintenance endpoints for event stream operations
- Axon Server disabled by default (uses JPA event store)
- Virtual threads enabled for better concurrency
- Jackson serialization for events and messages
- Game metadata correlation for event sequencing
- Always consult Context7 MCP server for latest library versions and documentation before using any external libraries
- Keep dependencies up-to-date and verify compatibility with existing codebase
- Framework: Always use JUnit 5 for all unit tests
- Assertions: Use AssertJ for fluent assertions
- Async Testing: Use Awaitility for testing asynchronous operations
- Structure: Use
// given/// when/// thencomments (with spaces) to separate test sections - Organization: Use JUnit 5
@Nestedclasses to group logically connected test cases:- Group by method under test
- Group by shared given conditions
- Group by feature/scenario variations
@Nested
class WhenRecruitingCreatures {
@Nested
class GivenDwellingHasAvailableCreatures {
@Test
void shouldSuccessfullyRecruitCreatures() {
// given
// when
// then
}
}
}