2 min readCalm pace · scan the outline anytime

Philosophy

Domain-centric Modular Hexagonal DDD — ports, adapters, and replaceable bounded contexts.

Philosophy

The primary goal is to decouple business logic (the Domain) from technical implementation (Infrastructure and UI), while keeping each bounded context independently replaceable.

Three pillars

  1. Domain-centricity — Business rules stay pure. Domain code carries zero dependencies on a host framework, database driver, or third-party SDK.
  2. Modularity (bounded contexts) — The application is divided into independent modules (e.g. Ordering, Warehouse, Directory). Each module is a self-contained unit with its own Application, Domain, Infrastructure, and UI.
  3. Dependency inversion — The Domain defines ports (interfaces); Infrastructure provides adapters (implementations). Application orchestrates; it never reaches past a port into a concrete driver.

The composition root binds each Domain port to an Infrastructure adapter. Domain never imports the host container API. How that wiring is expressed is a host detail — still no business rules in the composition root.

Illustrative host mappings — not Core MUST

Composition root (wiring only — no business rules)

HostTypical place
LaravelModule `ServiceProvider` + `bootstrap/providers.php`
Symfony`config/services*.yaml` + bundle Extension
YiiDI config / provider classes (Yii3)
CodeIgniter`Config/Services.php` + module bootstrap
CakePHPPlugin `services()` / container definitions
SpiralBootloaders
SlimPHP-DI (or PSR-11) definitions + thin `index.php`
Mezzio`ConfigProvider` + chosen DI container

Full topic pages: Adapters overview

Hexagonal Architecture in one sentence

Use Cases talk to the outside world only through ports. Adapters implement those ports for databases, HTTP peers, queues, clocks, and UI delivery mechanisms.

Domain-Driven Design in this standard

  • Entities / value objects / domain services express invariants inside a module.
  • Application Use Cases orchestrate a single user intention.
  • Bounded contexts are module boundaries — not namespace cosmetics.
  • Anti-Corruption Layers and Domain Events are the only sanctioned bridges between modules.

What Core is not

Not CoreWhere it belongs
ORM models, query buildersAdapter → persistence
Framework service providers / DI container APIsAdapter → composition root
Admin panel widgetsAdapter → UI
Linters, arch-test runners, generatorsAdapter → tooling
Product feature catalogsYour application roadmap

Replaceability is the product

A module that can only work when another module’s Domain is on the classpath is not modular — it is a distributed monolith with folders.

Core optimizes for this outcome:

  • Extract a module into an internal package later.
  • Replace a peer with an HTTP API without rewriting Use Cases.
  • Swap persistence drivers behind the same repository port.

Continue with module layout.

Modular Hexagonal Domain-Driven Design
Core 1.0.0-draft