panoscape/history
Eloquent model history tracking for Laravel. Add the HasOperations and HasHistories traits to record who changed which model, then browse a timeline of operations via the History facade. Includes migrations, config, and translations.
Architecture fit
panoscape/history is a bolt-on audit trail for Laravel Eloquent, implemented as two traits: HasOperations on the acting user and HasHistories on tracked models. It hooks Eloquent model events (created, updating, deleting, restored), plus a ModelChanged event for custom entries, and persists rows into a single published histories table exposed through polymorphic relationships ($model->histories(), $user->operations()). For a TPM, that means adoption is measured in hours per model, not weeks: no schema redesign, no service layer, no queue infrastructure required. It fits CRUD-centric admin domains (CMS, back-office, config management) where "who did what, when" is a compliance or support requirement. It is a poor fit for high-write, event-sourced, or ledger domains, where synchronous per-save inserts and a generic diff column become a bottleneck rather than an asset.
Integration feasibility
Low friction: Composer install, publish migrations/config/translations, add two traits, implement getModelLabel(). The package ships deliberate production guardrails that a TPM should treat as features to plan around: event whitelist, per-model attribute blacklist (password/PII redaction), user-type blacklist, environment blacklist, and global/runtime toggles including console_enabled and test_enabled (both default off). Multi-guard auth is supported via auth_guards (full scan or ordered array). Localization of model names and event messages is first-class, which matters for multi-locale products and non-English admin surfaces.
Technical risk
laravel-shift automation. No dependents and ~163 stars are weak adoption signals; budget for a fork-or-vendor contingency. Compare against spatie/laravel-activitylog and owen-it/laravel-auditing before committing.getOriginal() workaround exists but must be applied discipline-wide.Key questions
Stack fit
Strong for standard Laravel monoliths on Eloquent with default or multi-guard auth, MySQL/Postgres, and a Blade/Inertia admin surface. Weaker for multi-tenant apps (no tenant scoping in the schema — likely needs a global scope or tenant_id migration), and for apps where writes go through jobs/queues, since console_enabled defaults to false and would silently suppress worker-generated history.
Migration path
Additive and reversible: publish and run one migration, add one config file, add translations. No changes to existing tables or model schemas. The real work is policy, not code: agree which models are tracked, which attributes are blacklisted, which events are whitelisted, and whether to redact actors (user_blacklist) for system/admin operations. Enable in staging first, verify row volume and diff quality, then promote.
Compatibility
Advertised support spans Laravel 6.x–13.x, with a ^1.0 branch only for 5.6. That breadth is reassuring for long-lived apps but also signals a shim-style codebase; verify against our exact Laravel/PHP matrix in CI rather than trusting the badge. v2.9.0 added Laravel 13 and morph-map support, so pinning to ^2.9 is the sensible floor.
Sequencing
histories payload and message output.spatie/laravel-activitylog; document the rationale.Maintenance
Very low code-surface maintenance — one config, one migration, two traits. The genuine upkeep is policy drift: new models added without HasHistories, new sensitive attributes omitted from the blacklist, and the getModelLabel() original-value workaround forgotten on newly tracked models. Convert those into PR-checklist items and a periodic audit. Repository maintenance risk sits with a single maintainer; plan a quarterly "is upstream still healthy?" review and keep a vendored fork path warm.
Support No commercial SLA; MIT with GitHub issues. Expect to self-serve bugs. Mitigate with a pinned version, a regression test around the history contract, and an internal owner (one backend engineer) who can read the package source. Because the package is small and trait-based, the "debug by reading vendor code" cost is genuinely low.
Scaling
Cost is one insert per tracked write event, plus JSON meta. That is acceptable for back-office throughput (hundreds of writes/minute) and risky for high-volume tables (millions/day). Levers: whitelist events narrowly, blacklist noisy attributes, disable tracking in console/queue contexts where it isn't wanted, partition or archive histories by performed_at, and add composite indexes ahead of growth rather than after. The admin read path ($model->histories()->latest()) needs pagination and an index on (model_type, model_id, performed_at) from day one.
Failure modes
hasUser() false until auth_guards is configured.model() returns null; admin UI must handle orphans.Ramp-up Days, not weeks. A mid-level Laravel developer can be productive in under a day from the README alone; the learning curve is dominated by policy decisions (what to track, what to redact, how long to keep) rather than by the API. Budget roughly one engineer-week for the pilot plus policy definition, and one additional week for the admin read surface, retention job, and tenant scoping — the package is the cheap part of the initiative.
How can I help you explore Laravel packages today?