The project uses feature-first grouping. Code that belongs to the same feature lives together regardless of what layer it is in. A developer working on fantasy mode should find everything they need inside the fantasy package without jumping across the codebase.
Adapters are the exception. They are shared infrastructure used by multiple features and do not belong to any single feature. They live in their own top-level package and are injected into whichever features need them.
The rule is simple: if it serves one feature, it lives in that feature. If it serves multiple features, it lives in adapters or domain.
com.zoltraak.gateway
features/ One package per product feature
adapters/ Shared infrastructure adapters only
domain/ Enums, shared contracts, internal models
config/ Spring configuration and bean definitions
security/ JWT filter chain and auth utilities
annotations/ Custom meta-annotations
Each feature package contains everything that feature owns: its controller, its service or orchestrator, its request and response DTOs, and any internal models specific to that feature. Nothing inside a feature package is referenced by another feature directly. Cross-feature communication goes through a service interface.
features/
fantasy/
FantasyController.java
FantasyOrchestrator.java
FantasyRequest.java
FantasyResponse.java
FantasyPipelineContext.java
proxy/
ChatProxyController.java
OllamaProxyService.java
OllamaProxyChatRequest.java
OllamaProxyGenerateRequest.java
OllamaProxyTagsResponse.java
code/
CodeAssistController.java
CodingAssistantService.java
CodeAssistRequest.java
CodeAssistResponse.java
gpu/
GpuController.java
GpuLifecycleManager.java
PodState.java
RequestQueue.java
QueuedRequest.java
bot/
BotController.java
TelegramBotService.java
IntentClassificationRequest.java
IntentClassificationResult.java
cost/
CostController.java
CostTracker.java
CostSession.java
CostLog.java
CostSummaryResponse.java
health/
HealthController.java
HealthService.java
HealthResponse.java
Adapters are concrete implementations of ports. Each adapter knows about one external system. They are not feature-specific. The GPU lifecycle manager, the fantasy orchestrator, and the proxy service all use the same Ollama adapter for example. Each adapter folder contains the port interface, the concrete adapter, and the integration models specific to that external system.
adapters/
gpu/
GpuProviderPort.java
RunPodAdapter.java
VastAiAdapter.java
model/
RunPodPodResponse.java
VastAiManageRequest.java
VastAiInstanceResponse.java
VastAiInstanceWrapper.java
ollama/
OllamaPort.java
OllamaAdapter.java
model/
OllamaGenerateRequest.java
OllamaGenerateResponse.java
OllamaChatRequest.java
OllamaChatResponse.java
OllamaMessage.java
OllamaTagsResponse.java
OllamaModel.java
comfyui/
ComfyUiPort.java
ComfyUiAdapter.java
model/
ComfyUIPromptRequest.java
ComfyUIPromptResponse.java
ComfyUIHistoryEntry.java
bot/
BotPort.java
TelegramAdapter.java
model/
TelegramUpdate.java
TelegramMessage.java
TelegramChat.java
TelegramUser.java
TelegramPhotoSize.java
TelegramDocument.java
Domain contains only what is truly shared across the entire system. Enums, the universal response envelope, shared contracts, and internal models that are not owned by any single feature. If a class is only used by one feature it belongs in that feature, not here.
domain/
enums/
PodStatus.java
GpuProvider.java
FantasyStage.java
GatewayErrorCode.java
BotIntent.java
ModelType.java
shared/
GatewayResponse.java
GatewayError.java
ResponseMeta.java
ChatMessage.java
PodConnectionDetails.java
auth/
ZoltraakClaims.java
RequestContext.java
Spring configuration classes and property binding classes. This package wires beans together and reads configuration into typed objects.
config/
WebClientConfig.java
SecurityConfig.java
SchedulingConfig.java
properties/
ZoltraakProperties.java
ProviderProperties.java
OllamaProperties.java
GpuProperties.java
QueueProperties.java
TelegramProperties.java
JWT validation filter chain and utility class. These apply globally across all requests and do not belong to any feature.
security/
JwtAuthFilter.java
JwtUtil.java