incoder / laravel-ddd
Domain-Driven Design (DDD) Library for Laravel
Requires
- php: ^8.3
- illuminate/auth: ^12.21
- illuminate/console: ^12.21
- illuminate/database: ^12.21
- illuminate/filesystem: ^12.21
- illuminate/http: ^12.21
- illuminate/routing: ^12.21
- illuminate/support: ^12.21
- ramsey/uuid: ^4.7 || ^5.0
- spatie/laravel-activitylog: ^4.10
- spatie/laravel-data: ^4.17
- symfony/finder: ^7.0
- symfony/process: ^7.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.17
- orchestra/testbench: ^10.0
- phpunit/phpunit: ^11.5
Suggests
- ext-soap: Required to use SSRS reporting support.
- spatie/laravel-permission: Recommended when using the RequiresPermission attribute.
README
Reusable Laravel DDD / Clean Architecture building blocks packaged for Composer.
Overview
incoder-ddd provides shared foundations for Laravel applications that use a Domain / Application / Infrastructure split. The package includes:
- base entities and aggregate roots
- repository abstractions and Eloquent repository bases
- application service and DTO bases
- attribute-based route scanning
- AppService auto-route registration
- OpenAPI / Swagger generation
- TypeScript proxy generation
- Flutter OpenAPI proxy generation
- SSRS reporting helpers
The package is installable as a standalone Composer library and registers itself through Laravel package auto-discovery.
Developer Manual
For a fuller consumer guide, see docs/DEVELOPER-MANUAL.md.
Package Name
Current composer.json package name:
composer require incoder/laravel-ddd
Requirements
- PHP
^8.3 illuminate/support^12.21illuminate/database^12.21ramsey/uuidspatie/laravel-dataspatie/laravel-activitylog
Installation
Install the package in a Laravel application:
composer require incoder/laravel-ddd
Laravel will discover Incoder\DDD\Support\IncoderDDDServiceProvider automatically.
Optional publish steps:
php artisan vendor:publish --tag=api-docs php artisan vendor:publish --tag=incoder-ddd-config
This publishes:
config/incoder-ddd.phpconfig/api-docs.phpconfig/reporting.php
What The Package Actually Assumes
Some features are generic. Some are opinionated and default to conventions already encoded in this package.
Those defaults now live in config/incoder-ddd.php.
Default conventions:
- AppService discovery expects classes under
Core\Application\... - DI auto-binding expects
Core\Domain\...andCore\Infrastructure\Eloquent\Repositories\... - controller route scanning reads
app/Http/Controllers - scaffold commands generate files into
core/... - AppService HTTP routes are registered under
/app/api/{service}
If your application does not follow those conventions, you can override the package defaults in config/incoder-ddd.php. The generic base classes remain reusable even when you disable or replace convention-based scanning.
Core Building Blocks
Domain Entities
Use Entity, AggregateRoot, or AuthenticableAggregateRoot as base classes for domain models.
use Incoder\DDD\Domain\Entities\Entity; use Incoder\DDD\Support\Attributes\FillableAttribute; class Department extends Entity { protected $table = 'departments'; public $incrementing = true; protected $keyType = 'int'; #[FillableAttribute] protected string $name; }
Confirmed behavior from the codebase:
- soft deletes are enabled on
Entity #[FillableAttribute]drives fillable-property detection- string keys generate UUIDs on create
- activity logging is wired through
spatie/laravel-activitylog
DTO Base
Incoder\DDD\Application\DTOs\DTOBase extends Spatie\LaravelData\Data and provides toDTO() / toDTOs() helpers for Eloquent models.
Repository Base
Repository contracts extend Incoder\DDD\Domain\Repositories\IRepository. Eloquent implementations can build on:
Incoder\DDD\Infrastructure\Repositories\EloquentRepositoryIncoder\DDD\Infrastructure\Repositories\EloquentRepositoryBase
AppService Base
Incoder\DDD\Application\Services\AppServiceBase provides CRUD-oriented application service helpers and is the base type used by AppService route / OpenAPI / proxy scanning.
The inherited default AppService middleware comes from AppServiceBase:
apiauth:sanctum
You can override class-wide route middleware with #[AppServiceMiddleware(...)].
Routing
Controller Attribute Routing
#[RouteAttribute] can be used on controller methods. If no middleware is supplied:
/api/...and/app/api/...routes default toapi- other routes default to
web
Example:
use Incoder\DDD\Support\Attributes\RouteAttribute; #[RouteAttribute(methods: ['GET'], uri: '/reports', name: 'reports.index')] public function index() { }
AppService Auto-Routes
Classes that:
- are in the Composer classmap
- live under
Core\Application\... - end with
AppService - extend
AppServiceBase
are auto-registered at boot under /app/api/{service}.
Supported patterns:
- CRUD conventions:
getAll,getPaged,getById,create,update,delete - custom routes with
#[RouteAttribute] - convention routes based on HTTP verb prefixes like
getActiveUsersorpostArchive
Permission integration is available through #[RequiresPermission(...)] if your app provides a compatible permission middleware alias such as the one from spatie/laravel-permission.
More detail: docs/features/APPSERVICE-ROUTES.md
OpenAPI / Swagger
The package can generate an OpenAPI spec from auto-registered AppServices and exposes Swagger UI in non-production environments when config('api-docs.enabled') is true.
Default routes:
- UI:
/api/docs - spec:
/api/docs/spec
Generate a spec file:
php artisan api:generate-spec php artisan api:generate-spec --format=yaml --output=public/api-docs.yaml php artisan api:generate-spec --stdout
More detail: docs/features/OPENAPI-DOCS.md
Proxy Generation
TypeScript
Generate TypeScript service proxies and DTO/schema models from the discovered AppServices:
php artisan proxy:generate php artisan proxy:generate --output=resources/js/proxies
Default output path is resources/js/proxies. You can also override it in config/incoder-ddd.php.
Flutter
Generate Flutter/Dart OpenAPI sources via the OpenAPI Generator CLI:
php artisan proxy:generate-flutter \ --flutter-root=../flutter \ --output=../flutter/lib/src/generated/openapi \ --config=../flutter/tool/openapi-generator-config.yaml \ --jar=../flutter/.tooling/openapi-generator/openapi-generator-cli-7.21.0.jar
The Flutter generator expects:
- a sibling Flutter project by default
- Java
- an OpenAPI Generator CLI JAR at the configured path
Scaffolding Commands
Create a Domain Model Scaffold
php artisan make:domain-model User --type=aggregate --format=string --incrementing=false --schema=admin
Create Model Only
php artisan make:domain-model Employee --type=entity --format=int --incrementing=true --schema=admin --only-model
Create CRUD Around an Existing Model
php artisan make:domain-crud User --schema=admin --format=string --incrementing=false
Important: these commands currently generate into core/... directories and Core\... namespaces in the consuming application.
Reporting
The package includes SSRS reporting support through:
Incoder\DDD\Support\Reporting\Contracts\IReportServiceIncoder\DDD\Support\Reporting\Facades\Report
Supported operations:
generatePdfReport()streamPdfReport()getReportInfo()testConnection()
Required environment variables for reporting:
SSRS_BASE_URL=http://your-ssrs-server/ReportServer SSRS_USERNAME=your_username SSRS_PASSWORD=your_password SSRS_TIMEOUT=120 SSRS_CACHE_TTL=0
More detail: docs/features/README-REPORTING.md
Development Notes
- This repository is a Composer package, not a full Laravel app.
- Package behavior should remain stable for Composer consumers.
- If you change command names, config keys, publish tags, route conventions, generated output, or service-provider behavior, treat that as a public API change.
Useful checks:
composer validate --no-check-publish composer dump-autoload
License
MIT