lunarstorm/laravel-ddd
A Laravel toolkit for domain-driven design: scaffold bounded contexts, aggregates, value objects, events, and commands with Artisan generators, plus conventions and service providers for keeping complex apps modular and maintainable.
Architecture fit
teylabs/laravel-ddd is a developer-tooling package, not a runtime dependency: it ships Artisan ddd:* generators that scaffold domain layers (aggregates, events, listeners, value objects) into a Laravel application. Architecture fit is therefore high but narrow — it complements Laravel's native make:* commands rather than replacing service-container, queue, or event-bus behavior. Value is realised at code-generation time and in enforcing a directory/namespace convention (e.g. Domain\Billing\Events\...) across a team. It does not impose runtime coupling, which keeps adoption reversible.
Integration feasibility Straightforward: Composer install, auto-discovered service provider, generators invoked ad hoc or in scaffolding scripts/CI. No database migrations or config publication appear in the release notes, though presence of publishable stubs/config should be confirmed. The main integration surface that matters for this release is scriptability — exit codes and CLI argument semantics — which is exactly what v3.3.0 changed.
Technical risk — v3.3.0 introduces two behavioural breaking changes (minor version, no deprecation path)
ddd:* generators now exit 0 when the target class already exists or the name is PHP-reserved, matching make:*. Any wrapper script, Makefile, CI job, or provisioning pipeline that branches on $? == 1 to detect "class already exists" will now silently treat a no-op as success. The file is still untouched and the error still printed, so the failure is quiet rather than destructive — but it can mask a genuine "I expected this generator to produce something" assertion.ddd:listener --event=InvoicePaid now targets Domain\...\Events\InvoicePaid rather than App\Events\InvoicePaid. Any existing scaffold script or documented runbook using bare event names will generate a listener bound to a different namespace, producing a listener that is syntactically valid but wired to the wrong event — a defect that typically surfaces at runtime or in integration tests, not at generation time. Passing a backslash-qualified FQCN is honoured verbatim, and interactive suggestions now emit qualified names, so the escape hatch exists but must be communicated.Both are low-severity individually and moderate in aggregate because they are silent for scripted consumers. Neither affects already-generated application code, so blast radius is bounded to build-time tooling.
Key questions
--legacy-exit-codes or config flag) available?--force/--overwrite flag, and does it interact with the new exit-0 path?ddd:* commands or only ddd:listener?Domain\<Context>\Events?Stack fit
Targets Laravel applications already pursuing a DDD or modular-monolith layout on PHP 8.x. Fits cleanly alongside native make:* because the exit-code convention is now consistent, which is a genuine ergonomic win for uniform scaffolding abstractions. No conflict with Laravel's event system: ddd:listener emits a standard listener class; the change is purely which event FQCN is written into the file.
Migration path
For teams on v3.2.x, this is a routine composer update for the application code, plus a targeted audit of build tooling:
composer.json scripts, and shell wrappers for ddd: invocations and any $?/||/set -e logic keyed on their exit status.--event= without a namespace separator; rewrite to fully-qualified names (--event="App\Events\InvoicePaid").Existing generated code requires no changes. Recommended: pin ^3.3 deliberately rather than floating, so the audit lands in a known commit.
Compatibility Minor-version bump with breaking CLI semantics — acceptable under semver only if CLI behavior is treated as non-public API, which is debatable for a package whose entire public surface is the CLI. Downstream impact is limited to automation, not runtime. No PHP or Laravel version constraints disclosed in the notes; verify against the project's supported matrix before rollout.
Sequencing
ddd:* call sites and event-name arguments (small effort, high value).Maintenance Low ongoing surface: a dev-only dependency with no runtime footprint and no data migration. The maintenance burden is concentrated in convention ownership — whoever owns the DDD directory standard must keep generator behaviour, docs, and team practice aligned. This release is a reminder that CLI output and exit codes are effectively a contract and should be pinned and tested like one.
Support Expect a short tail of "my scaffold script stopped failing" and "my listener isn't firing" tickets immediately after the bump. Both are diagnosable from the release notes; pre-empt them by broadcasting the two changes and the FQCN escape hatch. Support load should be a one-time step, not recurring.
Scaling Scales fine — generation cost is per-invocation and negligible; no shared state, no network calls. The scaling concern is organisational: with many services and a shared template repo, a silent namespace shift in generated listeners could propagate uniformly, so a single golden-path pipeline and one pinned version across repos is preferable to per-team version drift.
Failure modes
0 on an existing class; a pipeline step that assumed failure-on-exists now passes without producing new output.--event=Name resolves to the domain namespace, yielding a listener subscribed to an event that is never dispatched — passes static analysis, fails at runtime.0; a scripted rename that silently fails to regenerate leaves the old class in place.Ramp-up
Minimal for developers — the commands mirror make:* idioms and are learnable in under an hour. Plan roughly half a day for the tooling audit and docs update in a small team, more if many repositories carry bespoke scaffold scripts. The ddd:listener namespace convention deserves an explicit note in onboarding, since it is now implicit-by-default rather than opt-in.
How can I help you explore Laravel packages today?