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
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
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();
}
} // Actions implement single-purpose write mutations
class AdjustStock
{
public function execute(StockData $data): Stock
{
$stock = Stock::where('product_id', $data->productId)->firstOrFail();
$stock->increment('quantity', $data->quantity);
return $stock;
}
} // Queries handle read pipelines flently
class StockQuery
{
protected $query;
public function inWarehouse(int $warehouseId): self
{
$this->query->where('warehouse_id', $warehouseId);
return $this;
}
public function get(): Collection
{
return $this->query->get();
}
} 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
class Stock extends ModelBase
{
protected ?string $module = 'inventory';
protected $fillable = ['product_id', 'quantity', 'warehouse_id'];
} | 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). |
Questions, answered.
Everything you need to know about how Obelaw implements Domain-Driven Design.
What is Domain-Driven Design (DDD) in Obelaw?
How is business logic separated from presentation?
What is the role of DTOs (Data Transfer Objects)?
How do domains communicate with each other?
Is Obelaw Domains compatible with standard Laravel projects?
composer require obelaw/framework and start defining your bounded contexts inside an existing Laravel app.
Pick up where the code left off.
Dive into the docs and start building your first bounded context domain.
Introduction
What Obelaw Domains is, why isolation matters, and how it aligns with DDD.
Read the docsGetting Started
Installation, context layout, and service provider registration setup.
Read the docsDomain Architecture
In-depth details on Actions, Queries, Managers, DTOs, and Persistence Models.
Read the docsReady to build with Domain-Driven Design?
Start organizing your enterprise applications into decoupled business domains today.
composer require obelaw/framework