Status: Accepted Date: 2025-12-10 Context: Standardize Java package structure across modules using Clean Architecture principles.
The codebase had inconsistent package structures across modules:
This inconsistency made the codebase harder to navigate, understand, and maintain. New developers had to learn different patterns for each module.
We will adopt Clean Architecture package structure standards across all modules. All services, applications, and libraries must follow these standards.
libs/domain-dtos, not duplicated in servicesservices/{service-name})io.forge.services.{service}/
├── domain/ # Business logic
│ ├── dto/ # Domain DTOs (if service-specific)
│ ├── exception/ # Domain exceptions
│ └── [Domain services/interfaces]
├── infrastructure/ # External concerns
│ ├── config/ # Configuration producers
│ ├── persistence/ # Database repositories
│ ├── mapper/ # Entity/DTO mappers
│ └── [Other infrastructure]
├── presentation/ # HTTP/REST layer
│ └── rest/ # JAX-RS resources
│ ├── exception/ # Exception mappers
│ └── [REST resources]
├── adapters/ # External system adapters (optional)
│ └── [Adapter implementations]
└── runtime/ # Runtime utilities
└── StartupBanner.java
application/{app-name})io.forge.application.{app}/
├── presentation/ # HTTP/REST layer
│ └── rest/ # JAX-RS controllers
│ └── [REST controllers]
└── runtime/ # Runtime utilities
└── StartupBanner.java
libs/{library-name})For libraries that provide infrastructure concerns (aws-api):
io.forge.{library}/
├── infrastructure/
│ ├── config/ # Client producers
│ ├── client/ # Client implementations
│ └── persistence/ # Repository implementations
└── domain/ # Interfaces (if any)
└── [Domain interfaces]
libs/domain-clients)For REST client interfaces:
io.forge.client.{service}/
└── {Service}Client.java
libs/domain-*)For shared domain concerns:
io.forge.domain.{concern}/
└── [Domain types, DTOs, interfaces]
{Service}Resource.java suffix, place in presentation/rest/{Feature}Controller.java suffix, place in presentation/rest/oidc/){Purpose}Service.javaCandidateService, DocumentService{Entity}Repository.javaCandidateRepository, ResumeRepository{Service}ClientProducer.javaS3ClientProducer, DynamoDbClientProducer{Entity}Mapper.javaCandidateMapper, ResumeMapperAll shared DTOs must be defined in libs/domain-dtos:
io.forge.domain.dto.auth.* - Authentication DTOsio.forge.domain.dto.user.* - User DTOsio.forge.domain.dto.document.* - Document DTOsService-specific DTOs can be defined in services/{service}/domain/dto/:
services/document-service/domain/dto/ParseJobResponseWrapper.javaRule: If a DTO is used by multiple services or the frontend, it must be in libs/domain-dtos.
io.forge.services.actor/
├── domain/
│ └── ActorService.java
├── infrastructure/
│ └── persistence/
│ └── ActorRepository.java
└── presentation/
└── rest/
└── ActorResource.java
io.forge.security/
├── domain/
│ ├── dto/
│ ├── exception/
│ ├── TokenValidator.java
│ └── UserAuthenticationProvider.java
├── infrastructure/
│ └── config/
│ └── CognitoClientProducer.java
├── presentation/
│ └── rest/
│ ├── exception/
│ ├── Secured.java
│ └── [Other presentation classes]
└── adapters/
└── cognito/
└── CognitoUserAuthenticationProvider.java
Positive:
All new modules must follow these standards from creation.
Existing modules should be refactored to follow these standards when:
Note: Not all modules need immediate refactoring. Standards apply to new code and major changes.
Code reviews should verify:
presentation/rest/domain/infrastructure/Decision Owner: Architecture Team
Review Cycle: Review annually or when new module types are introduced