avocet-shores/laravel-rewind
Laravel Rewind gives your Eloquent models full version control: rewind, fast-forward, restore, diff, and query point-in-time state. It stores partial diffs with periodic snapshots for efficient storage and fast reconstruction, plus thread-safe locking, queued versioning, and automatic pruning.
Architecture fit
Rewindable), one current_version column per tracked table, and a central rewind_versions table. That means it slots into existing Eloquent domain models without rewriting repositories or introducing a new persistence layer.spatie/laravel-activitylog (event log, no state reconstruction) and versus manual *_history tables (full-row copies, storage-heavy). If our requirement is "reconstruct and query point-in-time state" rather than "record that something happened," Rewind is closer to fit than the common alternatives.Rewind::batch) plus withMeta is the piece that makes this viable for multi-aggregate business transactions (order + line items + shipment), where a per-row audit log is useless for compliance review.$rewindStateFields, whereStateTransition, stateHistory) is a genuine architectural accelerator if our roadmap includes status-lifecycle analytics — it is otherwise a bespoke table we would build ourselves.Integration feasibility
composer require, publish provider (migrations + config), rewind:add-version to generate the per-model migration, add trait. A single engineer can pilot on one model in under a day.initVersion() for baselines. Any "we need history from day one of the contract" requirement must be handled by a backfill job we own.file or array cache in multi-node deployments will silently lose the concurrency guarantee.snapshot_interval, listener_should_queue, on_lock_timeout, max_versions, prune_*, version_model) — everything a TPM would want tunable per-environment is tunable.Technical risk
old_values on the previous head, which is defensible but surprising; auditors and support engineers will need that explained once, correctly, in our runbook.goTo() (moves pointer, no record) versus restore() (creates an audited version) is exactly the kind of distinction product teams get wrong. A compliance officer reviewing history will not accept a "pointer move."listener_should_queue: true buys write throughput but means version rows lag the model update and can arrive out of order relative to the lock window. Acceptable for high-write telemetry-ish tables, unacceptable for the tables feeding the audit trail.Key questions
composer.json, and is there an LTS-aligned support policy?rewind_versions table expected to be indexed and partitioned at 10M+ rows?Stack fit
Migration path
current_version column, versions accrue from first insert.current_version, default handling for existing rows), then a one-off initVersion() backfill so navigation has an anchor. The backfill must run before users are told "history exists."Compatibility
old_values/new_values/meta.DB::update, bulk upsert, queue workers using withoutEvents) — those paths will not version, silently. Enumerate them.version_model) is our escape hatch if we need tenancy columns or additional indexes; verify it doesn't conflict with future package upgrades.Sequencing
excludedFromVersioning) for secrets and derived fields; confirm snapshot_interval against measured reconstruction latency.Rewind::batch so we prove cross-aggregate history before promising it.diff / stateHistory in the admin UI behind a feature flag — this is where the package earns its keep or doesn't.rewind:prune, set max_versions defaults, alert on RewindVersionLockTimeout.Maintenance
--keep / --days combination with --pretend gives us a safe tuning loop.goTo vs restore distinction and the rebase-on-edit behavior in internal runbooks. That is product-team work, not library work, and it is unavoidable.Support
Scaling
getVersionAttributes / replay reconstruct from the nearest snapshot. snapshot_interval is the direct knob between storage cost and reconstruction latency; the default of 10 is reasonable but should be measured against our largest expected diff (wide rows with JSON columns).rewind_versions table will become one of the largest in the schema. Index plan and retention policy are prerequisites, not follow-ups.replay reconstructs incrementally across a range, so analytics over wide ranges stay linear rather than quadratic — this is the strongest scaling claim in the README and worth verifying in the pilot.Failure modes
log (silent — dangerous default for us), event (dispatch and handle), throw (retry-friendly with queued listeners). Recommend event or throw in production; log risks invisible history gaps that only surface during an audit.withoutEvents, and excluded attributes create gaps. Any compliance claim resting on this package must state those gaps.deleted is a tracked event type, but soft-delete vs. hard-delete semantics for history retrieval after delete need to be confirmed before we promise "nothing is ever lost."Ramp-up
goTo vs restore, snapshot interval, and what is excluded from tracking. Budget an internal brown-bag and a one-page decision record.How can I help you explore Laravel packages today?