All of the open-source agent projects follow the same Java 21 / Spring Boot structure. Here is the pattern and why each decision was made.
The Package Layout
com.vaishnavi.{project}/
api/ # REST controllers, request/response DTOs
config/ # Spring configuration, security, properties
domain/ # Records, enums, value objects (no framework deps)
entity/ # JPA entities (database-bound)
repository/ # Spring Data JPA repositories
service/ # Business logic (the core of the application)
util/ # Small helpers (JSON support, formatting)
The key constraint: domain/ has zero framework dependencies. Domain records are plain Java. They can be tested without Spring, serialized without Jackson annotations, and understood without knowing Spring Boot. This makes the core logic framework-agnostic and easy to reason about.
Java 21 Features Used Everywhere
Records for DTOs and value objects. Every request, response, and domain object is a record. Immutable, concise, and automatically generates equals(), hashCode(), and toString(). This eliminates Lombok for most use cases.
Sealed interfaces for type safety. When a service returns one of several result types, sealed interfaces make the compiler enforce exhaustive handling.
Pattern matching in switch. The switch expression with pattern matching replaces most if-else chains. Remediation action dispatching, for example, becomes a single switch expression over the action type enum.
The Testing Pattern
Every service class has a corresponding test class. Tests use constructor injection (not field injection) so they are framework-independent. Integration tests use Testcontainers for PostgreSQL and embedded Kafka for messaging. No mocks for infrastructure. If the service talks to a database, the test talks to a real database.
This structure is consistent across all projects. An engineer who understands one project can navigate any of them.