lmc/cqrs-types
Lightweight CQRS type definitions for Laravel/PHP applications, offering command, query, and handler contracts that help separate write and read concerns. Keeps business actions explicit, consistent, and easy to organize across projects.
Architecture fit. lmc/cqrs-types is not a CQRS framework; it is the contract layer of the LMC CQRS stack. It ships interfaces and value objects (commands, queries, handlers, bus contracts, command/query identifiers) plus a minimal base implementation. It is therefore meaningful only as a companion to lmc/cqrs (runtime buses/handlers) and typically lmc/cqrs-bundle (Laravel/Symfony wiring). Architecturally it slots cleanly into a hexagonal/clean-architecture Laravel app: controllers dispatch commands, handlers own application logic, queries return read models. It is a poor fit for teams wanting batteries-included event sourcing, sagas, or projections — none of that lives here.
Integration feasibility. Composer-installable, PSR-4, MIT, with namespaces that are easy to autoload and easy to isolate. Technically trivial to add. The real integration is adoption of the sibling packages; installed alone, this package provides interfaces with no runtime and no value.
Technical risk.
lmc/cqrs itself is alive before committing.Key questions.
lmc/cqrs (the implementation) actively maintained and compatible with our Laravel/PHP targets, and does it require Symfony Messenger or support our queue of choice?lmc/cqrs-bundle for container wiring, or will we compose buses ourselves?App\Cqrs ports so a fork or replacement is a contained change?Stack fit. Composer + PSR-4 + Laravel service provider (via the bundle) is a native fit. The stack gives us a lightweight command/query bus without forcing event sourcing, which matches a pragmatic Laravel monolith. It is a good fit if we want CQRS discipline (one handler per command, explicit intent objects, separate read paths) and a poor fit if we need durable messaging, projections, and replay out of the box.
Migration path. Adopt incrementally, context by context:
lmc/cqrs-types + lmc/cqrs (+ bundle), write one hello-world command and one query end to end, and run PHPStan at our strictest level.App\Cqrs\CommandBus etc. wrapping the LMC contracts). Legacy controllers keep working; new endpoints go through the bus.No database migration or schema change is involved — it is a types package with no persistence of its own. Data migration is limited to any read-model tables we choose to introduce later.
Compatibility. Verify resolution against our PHP 8.2/8.3, Symfony console/messenger components, and Laravel 10–12 in a throwaway branch before any commitment. Treat the absence of dependents as a signal to write our own contract tests and pin exact versions.
Sequencing. Dependency audit → spike → internal port wrapper → single-context pilot → team conventions doc → broader rollout. Do not adopt this before deciding how handlers are discovered and how transactions are bounded; those decisions are ours, not the package's.
Exit strategy. Because the contract surface is small, forking the interfaces or replacing them with in-house equivalents is a 1–2 day exercise. Encapsulate behind our own namespace from day one so that option stays cheap.
Maintenance. Expect low churn (types packages age well) but near-zero upstream activity. Budget a small recurring owner: quarterly dependency review, version pinning, and a watch on lmc/cqrs releases. If we fork, we inherit trivial security surface — there is almost no executable logic — and the maintenance cost stays low.
Support. No commercial support and effectively no community. Documentation is thin; expect to read the source, which is feasible given its size. We need one internal subject-matter expert, and we should capture conventions in an ADR so knowledge does not sit with one person.
Scaling. The types package contributes zero runtime overhead; scaling is a property of the bus implementation and our topology. Synchronous dispatch scales with the web tier; asynchronous dispatch requires serializable command DTOs, a queue, and careful handling of transaction boundaries and retries. The command ID value object is useful as an idempotency and correlation key. Query-side scaling is a read-model concern outside this package.
Failure modes.
Ramp-up. A senior developer can read the source and wire a working command/query in one to two days. Team-wide productivity takes roughly one sprint, and the binding constraint is CQRS literacy (handler boundaries, transactions, async, read models), not the package itself. Plan a short internal workshop and a reference implementation before wider rollout.
Overall. Technically low-risk to integrate, strategically thin as a standalone dependency, and only credible as part of the LMC CQRS stack. Given the near-dormant upstream, the recommendation is: proceed only behind an internal abstraction, pilot in one bounded context, and be prepared to own or replace the contracts.
How can I help you explore Laravel packages today?