---
title: DDD Layering & Clean Architecture
type: concept
created: 2026-09-06
updated: 2026-09-06
sources: [codebase snapshot 2026-09-06]
tags: [ddd, clean-architecture, hexagonal, layering, architecture]
---

# DDD Layering & Clean Architecture

Project-Board organizes its backend as concentric rings, with dependencies always pointing **inward**. This is a Clean/Hexagonal Architecture applied to a Laravel app, with the DDD layers placed outside the conventional `app/` directory under `src/`.

> **Note on provenance:** reflects the code as of 2026-09-06; no written ADR exists.

## The rings

| Ring           | Namespace         | Location              | May depend on                                     | May NOT use                                 |
| -------------- | ----------------- | --------------------- | ------------------------------------------------- | ------------------------------------------- |
| Domain         | `Domain\`         | `src/Domain/`         | PHP itself, other Domain classes                  | `Illuminate\*`, Application, Infrastructure |
| Application    | `Application\`    | `src/Application/`    | Domain                                            | Infrastructure, Eloquent, facades, HTTP     |
| Infrastructure | `Infrastructure\` | `src/Infrastructure/` | Domain + Application (implements their contracts) | — (it is the outward port)                  |
| Presentation   | `App\`            | `app/Http/`           | Application only                                  | Domain logic, repository/Eloquent access    |

The dependency rules are enforced by convention through a **header docblock repeated at the top of every base file** in each layer (e.g. `src/Domain/Shared/Entity.php`, `src/Infrastructure/Persistence/Eloquent/Models/BoardModel.php`). These blocks state the ring and its rules, acting as a self-documenting lint for the boundary.

## Key conventions

- **Domain is pure PHP.** No `Illuminate\*` imports anywhere in `src/Domain/`. Exceptions extend native PHP exceptions (e.g. `InvalidUserException extends \Exception`).
- **Application orchestrates a single use case.** It depends only on the Domain and on its own Ports. It never imports Infrastructure.
- **Infrastructure is the only outward-facing ring.** It implements the Domain repository interfaces and the Application Ports.
- **`app/Http` is thin.** Controllers build a Command/Query from the request, invoke it, and hand the result to Inertia or a JSON resource. No business logic, no Eloquent.

## How layers are wired together

`bootstrap/providers.php` registers three service providers:

- `AppServiceProvider` — framework defaults (immutable dates, production hardening).
- `DomainServiceProvider` — binds repository interfaces and ports to concrete Infrastructure implementations (see [repository-mapper-pattern](repository-mapper-pattern.md)).
- `ConsoleServiceProvider` — registers the custom `make:*` generators (see [custom-generators](custom-generators.md)).

`composer.json` maps the namespaces:

```json
"psr-4": {
    "App\\": "app/",
    "Domain\\": "src/Domain/",
    "Application\\": "src/Application/",
    "Infrastructure\\": "src/Infrastructure/"
}
```

## Relationship to other pages

- [repository-mapper-pattern](repository-mapper-pattern.md) — how Infrastructure satisfies Domain contracts
- [cqrs](cqrs.md) — how Application use cases are shaped
- [domain-events](domain-events.md) — event flow across the rings
- [validation-strategy](validation-strategy.md) — where validation lives
- [identity-value-objects](identity-value-objects.md) — the identity model used by Domain entities