altek/eventually
Eventually is a Laravel event sourcing package for modeling applications around domain events. It offers aggregates, event storage, projectors, and reactors, giving you an expressive way to persist state changes as an append-only event log.
Architecture fit. altek/eventually is a narrow, single-responsibility Eloquent extension: it adds lifecycle events to many-to-many pivot operations (attach/detach/sync and pivot-row saves) that older Laravel versions did not dispatch natively. Architecturally it is a leaf dependency — it does not shape the domain model, and it should never become load-bearing for core business logic. Its real value is as a cross-cutting hook point: it lets teams express pivot side-effects (audit logging, cache invalidation, search-index sync, notifications) declaratively instead of scattering them across service methods. That is a legitimate pattern, but it is a convenience layer, not architecture.
Integration feasibility. The integration surface is likely small (a service provider plus a trait applied to models, or a replacement relationship class), so the effort to try it is low. The gating question is composer compatibility: this package appears to originate in the Laravel 5.x era, and a modern Laravel 10/11 application will almost certainly reject its illuminate/* constraints without a fork. Feasibility is therefore not "can we install it" but "is it worth forking an unmaintained package to reproduce behavior the framework now ships natively."
Technical risk. Low blast radius, high uncertainty. All the usual signals are absent: zero stars, zero dependents, no community validation, no visible maintenance cadence. More importantly, Laravel has offered native pivot events (pivotAttaching, pivotAttached, pivotDetaching, pivotDetached, pivotUpdating, pivotUpdated) via custom pivot models and the AsPivot trait since the 8.x line. That creates a strong obsolescence risk: adopting this package means adopting a dead-end that duplicates framework behavior and will need to be unwound at the next major upgrade. Secondary risks are behavioral rather than structural — event-semantics mismatches and conflicts with other packages that override BelongsToMany (soft-deleting pivots, enhanced many-to-many packages, custom pivot models).
Key questions.
attach, detach, sync, syncWithoutDetaching, toggle, updateExistingPivot, updateOrCreate? Are events per-row or per-batch?Pivot/AsPivot classes — double dispatch, silent override, or clean coexistence?Stack fit. Only a fit if the application is on a Laravel version predating native pivot events and there is a genuine, documented need for pivot-level side-effects. On Laravel 8+ this package is redundant, and the correct stack fit is "do not adopt." If the team is on an older LTS and cannot upgrade soon, the package is a reasonable stopgap — provided it is wrapped.
Migration path. Adopting it should be treated as a one-way door until a planned exit. The exit is well-defined: replace the package trait with AsPivot on pivot models, and rename listeners from the package's event names to Laravel's pivot* names. That migration is mechanical if — and only if — the application dispatches through an internal abstraction rather than referencing package events directly. If the team is already on Laravel 8+, there is no migration into this package worth doing; the migration is away from the legacy pattern, and this package should be recorded in the ADR as "considered and rejected."
Compatibility. Verify three things before writing code: composer constraint resolution against the pinned framework and PHP version; coexistence with any package that subclasses or decorates BelongsToMany; and behavior under pivot soft deletes, custom pivot columns, and polymorphic many-to-many. Compatibility failures here tend to surface at runtime in specific relationship code paths, not at install time, so a spike must exercise every distinct relationship shape in the app.
Sequencing.
Maintenance. Treat this as at-risk, effectively vendored code. There is no meaningful upstream maintenance signal, so the internal team owns it from day one. That means a pinned version, a README note explaining why it exists, and a tested fork path. The total surface is small enough that forking is cheap — which is the main argument in its favor if the legacy constraint is real.
Support. No community to escalate to and no dependents to observe for failure patterns; every incident is first-occurrence. Internal ownership needs to be explicit — a named team, not "whoever wrote it." Budget for the fact that debugging "why didn't my listener fire" requires knowing which code paths the package instruments, which is tribal knowledge unless documented.
Scaling. The package itself is not a throughput concern; event dispatch is cheap relative to the writes it accompanies. The scaling risk is in the listeners. sync() on a large collection can fire one event per row, and if each listener issues a query, a bulk relationship update becomes an N+1 storm inside a single request. Any listener attached to pivot events should be queued or batched, and bulk operations should be load-tested rather than assumed.
Failure modes.
BelongsToMany wins the boot order and the package quietly stops functioning.Ramp-up. Learning the API is trivial — an hour for a mid-level developer. The real ramp-up cost is conceptual: understanding event timing, transaction semantics, and which operations are instrumented. That is roughly a half-day of onboarding plus a one-page internal note. Given the zero-traction signals, the 55.25 opportunity score reads correctly as "cheap to try, low strategic value." The right posture is a time-boxed spike and an ADR, not a roadmap commitment — and on any modern Laravel baseline, the likely verdict is to adopt the framework-native equivalent and skip this dependency entirely.
How can I help you explore Laravel packages today?