spatie/laravel-activitylog
Easily log user activities in your Laravel app and automatically track model events. Store everything in the activity_log table, then retrieve and query activities with the Activity model and a fluent API.
Architecture fit
activity_log table with a polymorphic subject (the model acted upon) and causer (typically the authenticated user), plus a description, log_name, and a JSON properties payload.activity()->performedOn($m)->causedBy($u)->log(...)) and automatic model-event logging via the LogsActivity trait, which records created/updated/deleted with an attribute_changes diff (attributes vs old).Integration feasibility
composer require, publish migration, php artisan migrate, optionally publish config. Auto-registration means no service provider wiring.subject_id/causer_id column types before migrating. This is a one-time, cheap, but easy-to-miss gate — it is the single most common integration defect class for this package.Technical risk
attribute_changes captures raw model attributes. Logging a User model with default logAll() will persist emails, phone numbers, and potentially password hashes or tokens into a JSON column that is often readable by far more staff than the source table. LogOptions (logOnly, logExcept, logOnlyDirty) exists precisely to mitigate this and should be a mandatory review gate, not an optional nicety.subject resolves to null; the subject_id and causer remain. Whether that satisfies an audit requirement is a product decision that should be made explicitly rather than discovered.Key questions
activity_log table plus a tenant-scoped admin UI is a leak vector requiring deliberate query scoping.Stack fit
subject_type is a class-string and cross-service class names will not resolve.Migration path
activity_log buys little and creates schema-shape and semantics mismatches (your old rows have no old/attributes split, no causer polymorphic type). Run the two in parallel, cut over per-feature, then decommission the old table.Activity — treat this as a small, well-scoped frontend task, not free.Compatibility
composer.json — a floating constraint on a package with aggressive major increments is an avoidable outage class.subject_id/causer_id column types must match your key strategy; the config-driven table name supports environment separation.tapActivity firing twice, subject resolution on non-SoftDeletes models). Recent patch releases address several of these — another argument for staying current within your pinned major.Sequencing
LogOptions (logOnly/logExcept, dirty-only) rather than default logAll(). This is the PII control point.Maintenance
LogOptions decisions per model, and the retention schedule.Support
Scaling
(subject_type, subject_id) and (causer_type, causer_id), indexes on log_name and created_at, and time-based archival or partitioning.logOnlyDirty, and consider deferring writes via queued listeners — while accepting that queued logging introduces ordering and loss-on-failure tradeoffs.activity_log table (especially JSON properties searches) will be the first thing to page. Design the read queries against indexes from day one.Failure modes
LogOptions review; unrecoverable after the fact without a purge.subject_type unresolvable and subject null. Plan for rendering "record deleted" states in the UI and for class renames during refactors.Ramp-up
How can I help you explore Laravel packages today?