A Spring Boot service for managing admin resources (players, etc.). It follows a clean layered architecture with domain-driven design concepts, OpenAPI-first contracts, and asynchronous integration via RabbitMQ.
- Language/Runtime: Java 21
- Framework: Spring Boot 3.5.3
- Data Store: MongoDB
- Messaging: RabbitMQ
- AuthN/Z: Keycloak (OIDC/JWT Resource Server)
- API Contract: OpenAPI 3 (codegen at build)
- Reverse Proxy: Traefik (local compose)
- Build: Gradle
- Testing: JUnit 5, Mockito, Testcontainers
The codebase is organized by vertical feature (player) and horizontal layers, embracing domain-driven design and ports/adapters.
- Application layer (
src/main/java/.../player/application)- Use-cases/services coordinate operations and apply application-level rules (e.g.,
CreatePlayerService). - Input is expressed as commands/DTOs (e.g.,
CreatePlayerCommand).
- Use-cases/services coordinate operations and apply application-level rules (e.g.,
- Domain layer (
src/main/java/.../player/domain)- Pure domain model (
Player, value objects likeEmail). - Domain events (
PlayerCreatedEvent) describe meaningful business occurrences. PlayerRepositoryis a port that the domain/application depend on.
- Pure domain model (
- Infrastructure layer (
src/main/java/.../player/infrastructure)- Adapters implementing ports, e.g., MongoDB repository (
PlayerMongodbRepository). - HTTP controllers (
PlayerRestController) mapping OpenAPI to application services. - Mappers between domain and persistence/transport (
PlayerDocumentMapper,PlayerResponseMapper).
- Adapters implementing ports, e.g., MongoDB repository (
- Shared (
src/main/java/.../shared)- Cross-cutting concerns: domain
EventPublisher, messaging (RabbitMQ), persistence config (MongoDB), controller exception handling, and base exceptions.
- Cross-cutting concerns: domain
- Domain events are published via an
EventPublisherimplementation that uses RabbitMQ (seeshared/infrastructure/messaging). - This enables loose coupling between write operations and downstream consumers.
- Resource server validates JWTs from Keycloak.
- Issuer and JWK set URIs are configured via
application.properties.
coomiix-admin/
├─ src/
│ ├─ main/
│ │ ├─ java/com/coomiix/admin/
│ │ │ ├─ AdminApplication.java
│ │ │ ├─ player/
│ │ │ │ ├─ application/ # use-cases (create, update, delete, search)
│ │ │ │ ├─ domain/ # entities, value objects, events, repository port
│ │ │ │ └─ infrastructure/ # controllers, repository adapters, mappers
│ │ │ └─ shared/ # common domain+infra (events, exceptions, config)
│ │ └─ resources/
│ │ ├─ application.properties
│ │ └─ openapi.yaml # API contract (OpenAPI 3)
│ └─ test/
│ └─ java/... # unit/integration tests (incl. Testcontainers)
├─ Dockerfile
├─ compose.yaml
├─ build.gradle
└─ settings.gradle
- Contract:
src/main/resources/openapi.yaml(title: "Admin API", version: 1.0.0) - Notable paths:
/players(POST create, GET search),/players/{id}(GET) - OpenAPI UI available when running locally via Springdoc (check
/swagger-ui.htmlor/v3/api-docsif enabled through Traefik path rules).
- Java 21, Gradle (or use the Gradle wrapper)
- Docker + Docker Compose (for full stack)
./gradlew clean bootRunDefaults:
- App listens on port 8080.
- Requires running dependencies (MongoDB, RabbitMQ, Keycloak). You can launch them via Docker Compose while running the app locally:
docker compose up -d mongodb rabbitmq keycloak postgres traefikdocker compose up --buildServices/ports:
- App behind Traefik on
http://localhostwith path prefix/api(per labels). The container listens on 8080 and is mapped to host127.0.0.1:8081. - Traefik:
http://localhost(web), dashboard at127.0.0.1:8083. - Keycloak:
http://localhost:8080(dev mode). - MongoDB:
127.0.0.1:27017. - RabbitMQ:
5672. - Postgres (for Keycloak):
127.0.0.1:5432.
Note: The Dockerfile exposes 8081 but the Spring app serves on 8080; Compose maps 8081:8080 for host access.
- Build:
./gradlew build - Run tests:
./gradlew test - OpenAPI code generation runs automatically before compilation (
openApiGeneratetask). Generated sources are placed inbuild/generated/src/main/javaand added to the main source set.
- Use MapStruct for DTO/entity/document mapping. Annotations are processed at build-time.
- Domain events should be raised from the domain model or application layer and published via the shared
EventPublisher. - Exception handling is centralized in
shared/infrastructure/controller/ControllerExceptionHandler.
- If JWT validation fails, ensure Keycloak realm
coomiixis running athttp://localhost:8080and the clientcoomiix-adminexists with the configured secret. - Verify
.envvalues match those expected bycompose.yamlandapplication.properties. - For MongoDB auth, ensure
authSource=adminif using root credentials.