206 lines
4.4 KiB
Markdown
206 lines
4.4 KiB
Markdown
Delivery Adapters vs App Code (Strict Clean Architecture)
|
|
|
|
This document clarifies where Controllers live, why they are adapters, and how to structure them cleanly in large systems.
|
|
|
|
It resolves the common confusion between:
|
|
• architectural role (what something is)
|
|
• physical placement (where something lives in the repo)
|
|
|
|
This document is framework-agnostic in its principles and feature-based in its structure.
|
|
|
|
⸻
|
|
|
|
1. Clean Architecture Layers (Authoritative)
|
|
|
|
Clean Architecture defines roles, not folders.
|
|
|
|
ENTITIES
|
|
USE CASES
|
|
INTERFACE ADAPTERS
|
|
FRAMEWORKS & DRIVERS
|
|
|
|
Everything that follows maps code to these roles.
|
|
|
|
⸻
|
|
|
|
2. What a Controller Is (Architecturally)
|
|
|
|
A Controller is an Interface Adapter.
|
|
|
|
Why:
|
|
• It receives external input (HTTP)
|
|
• It translates that input into Use Case input
|
|
• It invokes a Use Case
|
|
• It performs no business logic
|
|
|
|
By definition:
|
|
|
|
Anything that translates between external input and the application boundary is an adapter.
|
|
|
|
So:
|
|
|
|
✅ Controllers are Interface Adapters
|
|
|
|
⸻
|
|
|
|
3. Why Controllers Do NOT Live in adapters/
|
|
|
|
Although Controllers are adapters by role, they are also:
|
|
• Framework-specific
|
|
• Delivery-specific
|
|
• Not reusable outside their app
|
|
|
|
They:
|
|
• use routing decorators
|
|
• depend on HTTP concepts
|
|
• depend on a specific framework
|
|
|
|
Therefore:
|
|
|
|
Controllers belong to the delivery application, not to shared adapters.
|
|
|
|
⸻
|
|
|
|
4. Adapter vs App — The Key Distinction
|
|
|
|
Concept Meaning
|
|
Adapter Architectural role (translator)
|
|
App Delivery mechanism (HTTP, UI, CLI)
|
|
|
|
“Adapter” answers what it does.
|
|
“App” answers where it runs.
|
|
|
|
Both are correct at the same time.
|
|
|
|
⸻
|
|
|
|
5. Feature-Based Structure (Mandatory for Scale)
|
|
|
|
Flat technical folders do not scale.
|
|
|
|
Everything is organized by feature / bounded context.
|
|
|
|
⸻
|
|
|
|
6. Canonical Project Structure (Strict)
|
|
|
|
Root
|
|
|
|
core/ # Application + Domain (pure)
|
|
adapters/ # Reusable infrastructure adapters
|
|
apps/ # Delivery applications
|
|
|
|
|
|
⸻
|
|
|
|
Core (Feature-Based)
|
|
|
|
core/
|
|
└── racing/
|
|
├── domain/
|
|
│ ├── entities/
|
|
│ ├── value-objects/
|
|
│ └── services/
|
|
└── application/
|
|
├── use-cases/
|
|
├── inputs/
|
|
├── results/
|
|
└── ports/
|
|
├── gateways/
|
|
└── output/
|
|
|
|
• No framework imports
|
|
• No DTOs
|
|
• No controllers
|
|
|
|
⸻
|
|
|
|
Reusable Adapters (Framework-Agnostic Implementations)
|
|
|
|
adapters/
|
|
└── racing/
|
|
├── persistence/
|
|
│ ├── TypeOrmRaceRepository.ts
|
|
│ └── TypeOrmDriverRepository.ts
|
|
├── presentation/
|
|
│ └── presenters/
|
|
│ └── GetDashboardOverviewPresenter.ts
|
|
├── messaging/
|
|
│ └── EventPublisher.ts
|
|
└── logging/
|
|
└── StructuredLogger.ts
|
|
|
|
These adapters:
|
|
• implement Core ports
|
|
• are reusable across apps
|
|
• do not depend on routing or UI
|
|
|
|
⸻
|
|
|
|
API App (Delivery Application)
|
|
|
|
apps/api/
|
|
└── racing/
|
|
├── controllers/
|
|
│ └── DashboardController.ts
|
|
├── services/
|
|
│ └── DashboardApplicationService.ts
|
|
├── dto/
|
|
│ └── DashboardOverviewResponseDto.ts
|
|
└── module.ts
|
|
|
|
Responsibilities:
|
|
• Controllers translate HTTP → Input
|
|
• Application Services orchestrate Use Case + Presenter
|
|
• DTOs represent HTTP contracts
|
|
• Module wires dependencies
|
|
|
|
⸻
|
|
|
|
7. Responsibilities by Layer (No Overlap)
|
|
|
|
Controllers
|
|
• HTTP only
|
|
• No business logic
|
|
• No mapping logic
|
|
• Call Application Services only
|
|
|
|
Application Services (API)
|
|
• Instantiate Output Adapters
|
|
• Invoke Use Cases
|
|
• Return response DTOs
|
|
|
|
Presenters
|
|
• Implement Output Ports
|
|
• Map Result → DTO/ViewModel
|
|
• Hold state per execution
|
|
|
|
⸻
|
|
|
|
8. Forbidden Patterns
|
|
|
|
❌ Controllers inside adapters/
|
|
❌ Use Cases inside apps/api
|
|
❌ DTOs inside core
|
|
❌ Controllers calling Use Cases directly
|
|
❌ Business logic in Controllers or Services
|
|
|
|
⸻
|
|
|
|
9. Final Mental Model
|
|
|
|
Controllers are adapters by responsibility.
|
|
Apps define where adapters live.
|
|
|
|
This separation allows:
|
|
• strict Clean Architecture
|
|
• multiple delivery mechanisms
|
|
• feature-level scalability
|
|
|
|
⸻
|
|
|
|
10. One-Line Summary
|
|
|
|
Controller = Adapter (role), App = Delivery (location).
|
|
|
|
This document is the authoritative reference for controller placement and adapter roles. |