roundly-consulting/lifecycle-for-laravel
Lifecycle for Laravel adds configurable lifecycles to Eloquent models: define states, allowed transitions, guards, and hooks so business rules stay organized, predictable, and testable instead of scattered across controllers, observers, and service classes.
TransitionRecordResource and LifecycleResource.last_transition now emit actor: {id, type}, so "who did this" is a stable, renderable field in our API without exposing PHP internals (App\Models\User). This unblocks shipping history/activity endpoints as a product feature rather than an internal debug view.User, not App\Models\User, not the morph alias), and a swappable resource mean we do not write and maintain our own presenters for transition history. Buy the package; spend the sprint on our actor payload instead.lifecycle.resources.actor lets us point at our own JsonResource to add a name, avatar, or email — a product-visible decision (does the timeline show a name or a user ID?) that is now a config value, not a fork.TransitionRecord, so rendering history loads no actor and adds no query. That removes the usual N+1 risk before we commit to an unbounded or paginated audit feed — a real input to whether the feed can ship as-is or needs async/export treatment.lifecycle.resources.actor (blank string is treated as packaged default; a non-instantiable JsonResource throws InvalidLifecycleConfigurationException with notAResource) fails loudly at boot rather than silently degrading. That lowers the blast radius of a bad deploy on customer-facing history.Adopt when:
type to the basename of the mapped class, so aliases do not leak either.lifecycle.resources.actor swap and its validation give us that cheaply.Look elsewhere or defer when:
actor.type from morph class to class basename. Any consumer parsing the old value, including our own frontend or a partner integration, must be checked and versioned before we upgrade. Treat it as a breaking payload change and plan a coordinated rollout.JsonResource — until lifecycle.resources.actor points at ours, the API shows {id, type} only, which may be insufficient for a human-facing timeline.To executives: We can ship user-facing "who changed this and when" history using a maintained package instead of custom code. The cost is a small config change plus a review of what our API returns — not a build. One caveat: this release changes the actor type value our API emits, so we should sequence it as a deliberate API change rather than a routine bump.
To engineering: The release adds TransitionActorResource (renders {id, type} from the TransitionRecord, no actor load, no extra query) and a lifecycle.resources.actor config key accepting any instantiable JsonResource; blank or null keeps the packaged one, and invalid values throw InvalidLifecycleConfigurationException (notAResource) at configuration time. The actor.type output is now the actor class basename instead of the morph class, and with a morph map it is the basename of the mapped class rather than the alias — audit serializers, snapshots, and client parsers for dependency on the old string, and add a contract test pinning actor to {id, type}. Upgrade path: pin lifecycle.resources.actor, ship the resource swap and any payload change together, then verify query counts on the history endpoint remain flat. Also note the dev/CI maintenance items are non-functional.
How can I help you explore Laravel packages today?