DDD

Clean domain boundaries, built for scalable Laravel apps.

Bring Domain-Driven Design (DDD) to Laravel. Segregate presentation from business logic using self-contained domain boundaries, validated DTOs, single-purpose Actions, and fluid read Queries.

$ composer require obelaw/framework
// Unified Fluent access to your application domains
$stock = ium()->inventory()->stock()->available($productId);

// Mutations run via single-purpose Actions accept validated DTOs
$invoice = ium()->billing()->invoice()->generate(InvoiceData::from($payload));

DDD Framework by numbers

3
Strict Layers
100%
Isolated Logic
0
Presentation Bloat
9
Domain Directories

What are Bounded Contexts?

Enforce boundaries. Prevent architectural drift.

Organize business applications into explicit modules that stay clean, testable, and completely segregated from presentations.

Strict Layering

Presentation, Domain logic, and Persistence are strictly partitioned. Presentation components cannot bypass the domain boundaries to touch the database.

Bounded Isolation

Each business module acts as a self-contained Bounded Context. Internals (like Eloquent models or internal DTOs) are hidden from other contexts.

CQRS Segregation

Write mutations (Actions) and read pipelines (Queries) stay completely isolated. Write operations never yield database queries without validation.

Unified Bounded Gateway

Register domain managers in a centralized registry, exposing business contexts through one cohesive, fluent access point.

Type-Safe Inputs

Boundaries are protected by immutable Data Transfer Objects (DTOs), validating payload structures before logic runs.

What Domains are not

Not Eloquent wrappers — logic lives in Actions/Queries, not database models.
Not delivery channels — they don't know about HTTP routes, queues, or CLI commands.
Not monolithic — domains can run inside any standard Laravel package.
Architectural Blueprint

Pure logic, isolated inside context walls.

Expose business boundaries via clean manager abstractions, backed by specialized execution classes.

class InventoryManager
{
    public function adjustStock(StockData $data)
    {
        return app(AdjustStock::class)->execute($data);
    }

    public function query(): StockQuery
    {
        return new StockQuery();
    }
}
DDD Structure

Your domain, laid out layer by layer.

Each domain module is organized into specialized directories matching Domain-Driven Design layout principles.

src/
├── Actions/     # Single-purpose write operations
├── Data/        # Type-safe, immutable Data Transfer Objects (DTOs)
├── Events/      # Domain lifecycle events
├── Exceptions/  # Domain-specific exceptions
├── Managers/    # Context entry points / Services orchestration
├── Models/      # Persistence-only Eloquent Models
├── Providers/   # Service provider hooks
├── Queries/     # Fluent query pipeline builders
└── Traits/      # Reusable model hooks / behaviors
              
Directory Concern
Actions/ Write operations. Receives a validated DTO, performs one unit of work.
Queries/ Read pipelines. Intermediate methods return $this; terminal methods materialize results.
Data/ Immutable DTOs. Type-safe, structured input at every domain boundary.
Models/ Eloquent definitions. Persistence only — no business logic. Extends ModelBase (auto-prefixes ium_ tables).
Managers/ Domain entry points. Orchestrates sub-services.
Events/ Domain events fired during lifecycle transitions.
Exceptions/ Domain-specific exceptions for invalid states.
Traits/ Cross-cutting model behaviors (e.g. traits binding attributes or media).
FAQ

Questions, answered.

Everything you need to know about how Obelaw implements Domain-Driven Design.

What is Domain-Driven Design (DDD) in Obelaw?
It's a way to structure complex business logic into isolated, self-contained domain folders (like Billing, Inventory, Customers) rather than mixing everything in standard Laravel directories.
How is business logic separated from presentation?
Obelaw uses a three-layer architecture (Presentation/Delivery, Domain, Infrastructure/Persistence). Models only represent data persistence, while Actions (write mutations) and Queries (read pipelines) hold all logical rules.
What is the role of DTOs (Data Transfer Objects)?
DTOs enforce type-safety and integrity at the domain boundaries. They ensure that any data entering a domain is valid and immutable.
How do domains communicate with each other?
All cross-domain calls go through explicit registered gateway managers. Domains cannot access other domains' models or internal action classes directly, which guarantees strict isolation.
Is Obelaw Domains compatible with standard Laravel projects?
Yes. You can run composer require obelaw/framework and start defining your bounded contexts inside an existing Laravel app.

Ready to build with Domain-Driven Design?

Start organizing your enterprise applications into decoupled business domains today.

$ composer require obelaw/framework