Skip to content

Activity Log

Audits who changed what across Volāre models using spatie/laravel-activitylog (v5), with an attribute-driven per-model configuration, a Filament viewer, and an Artisan health check.

  • Trace who changed a record and what the before/after values were
  • Decide whether a new model should be activity-logged or excluded
  • Audit non-model events (impersonation, flight searches, product duplication)

Models opt in with the #[ActivityLog] attribute plus the ConfiguresActivityLog trait (which wraps Spatie’s LogsActivity). Around 87 models are configured this way.

Defaults on the attribute are audit-friendly (since #2164):

  • Only changed attributes are recorded (logOnlyDirty) — an update stores just the dirty fields, with the diff in Spatie v5’s attribute_changes column.
  • No-op saves are skipped (dontLogEmptyChanges).
  • Both are overridable per model via the attribute’s parameters (logName, logFillable, submitEmptyLogs, logAttributes, logOnlyDirty, dontLogAttributes).

A PHPStan rule (backend/phpstan/Rules/RequireActivityLogOnModelsRule.php) enforces that every Eloquent model is either configured or explicitly listed as excluded, so logging can’t be forgotten silently.

Besides model events, a few flows write custom entries via the activity() helper with their own log names: impersonation (UserImpersonation), flight-searches (CascadeFlightSearchForDateJob, FlightSearchActivityLogger), product-duplication (ProductDuplicationService), and ai_tour_parser (TCAI tour parsing).

High-volume machine-churn models were removed from logging in #2162 to control table bloat — their state lives in their own tables and no consumer read it from the log (a PipedriveSync retry loop alone was the largest share of the table):

  • PipedriveSync, CurrencyExchangeRate, OfferFlight, OfferFlightBinding, OfferPriceSnapshot, ProductByMarketFlightLeg

Also excluded (cache/metrics/transient data): BudgetEntry, ProductSlugAlias, DynamicFlightCache, DynamicFlightCacheRoute, DynamicFlightCacheSegment, DynamicFlightProvider, DynamicFlightRefreshSchedule, FlightSearchResult, L2bMetric.

The full exclusion list is RequireActivityLogOnModelsRule::EXCLUDED_MODELS.

ActivityLogs (System → Activity Logs, admin-only) lists all entries with:

  • Filters for event (built dynamically so custom events are filterable), subject type, user, and date range
  • A slide-over detail view showing a side-by-side before/after diff for updates, initial values for creates, and last-held values for deletes. The diff is read from the v5 attribute_changes column with a fallback to properties so pre-v5 rows and custom diff logs still render
  • A Go to Element link that resolves the subject’s Filament edit page when one exists

Source: backend/app/Filament/Pages/ActivityLogs.php

Terminal window
vendor/bin/sail artisan activity-log:check [--json]

Scans every class in app/Models and reports three buckets: configured (attribute + trait), misconfigured (attribute without the ConfiguresActivityLog trait — exits non-zero), and not configured. Use -v to list unconfigured models.

Source: backend/app/Console/Commands/ActivityLogCheckCommand.php

Config file: backend/config/activitylog.php

  • enabled — kill switch (ACTIVITYLOG_ENABLED, defaults to true)
  • clean_after_days — 365-day retention used by Spatie’s activitylog:clean command. Note: the command is not scheduled; the automatic prune was dropped from #2162 as too risky to run on deploy, so historical cleanup is a manual operation.
  • Health Monitoring
  • Source: backend/app/Attributes/ActivityLog.php
  • Source: backend/app/Traits/ConfiguresActivityLog.php