Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Activitylog Laravel Package

bolechen/nova-activitylog

A Laravel Nova integration for spatie/laravel-activitylog that lets you browse, filter, and inspect activity logs and model changes directly from your Nova dashboard.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • The package is a presentation layer only. It is a Laravel Nova tool that renders rows already written to the activity_log table by spatie/laravel-activitylog; it does not write, enrich, or govern logging. Every substantive architectural decision (what is logged, causer resolution, retention, schema) lives in the Spatie layer and in your application code, not in this package.
  • That is the right decomposition for us: the durable asset is the Spatie instrumentation and our conventions; the Nova screen is a disposable UI. It also means the package cannot be evaluated in isolation — its value is entirely contingent on an instrumentation program that does not yet exist.
  • Footprint is small (a tool class plus a Vue list component), single-purpose, and MIT-licensed. Forking or vendoring is cheap and should be planned for, not treated as an emergency.
  • Fit is conditional on being a Nova shop on a supported Nova major. If admin surface is Livewire/Filament/Inertia-based, this is a non-starter regardless of quality.

Integration feasibility

  • Mechanically trivial: composer require, publish, register in NovaServiceProvider::tools(), gate with canSee(). A developer can have it rendering in under an hour.
  • The real integration work is upstream and non-optional: install Spatie, publish migrations/config, migrate, instrument one model with logOnlyDirty() + dontSubmitEmptyLogs(), and prove rows exist in the table via tinker before installing the viewer. The documented failure mode is an empty panel caused by missing instrumentation, not a broken package.
  • Dependency chain is two-deep on volatile packages (Nova major × Spatie major) with a thin Vue wrapper in between. Zero dependents means we are the first integration test for any specific version pairing — there is no upstream community signal to lean on when something breaks.
  • Constraint risk is concentrated and cheap to neutralize: pin laravel/nova and spatie/laravel-activitylog exactly, and budget for vendoring.

Technical risk

  • Authorization (highest severity). The documented gate is tool-level canSee(), which is all-or-nothing. Whether row-level scoping exists — tenant isolation, subject-type restriction, causer filtering enforced server-side — is unknown and must be verified by reading the component's query, not the README. A low-privilege Nova user seeing cross-tenant activity is a security incident, not a bug report.
  • Query behavior at scale. Unverified whether pagination is server-side, whether causer/subject morph relations are eager-loaded, and whether filters hit the query or the client. Client-side filtering over a multi-million-row append-only table would be a hard blocker.
  • Upgrade fragility. Thin Nova Vue wrappers go stale silently between majors (Nova 4 → 5 broke a long tail of third-party tools). Expected failure mode is a blank or broken tool after an upgrade, with no upstream fix timeline we control.
  • Maintainer concentration. 99 stars, single maintainer, recent release but no downstream adoption. Bus factor is effectively one, and our fork is the mitigation.
  • Property rendering. Property diffs are rendered verbatim to anyone with panel access, which converts a logAll() mistake on a User model into password hashes and API tokens displayed in an admin UI.

Key questions to close before committing

  1. Read vendor/bolechen/nova-activitylog/src/ and resources/js/ — is pagination server-side? Are relations eager-loaded? Are filters applied in the query?
  2. What exactly does the tool pass to the Vue component as props, and is there any row-level scoping hook beyond canSee()?
  3. What Nova major and Spatie major are declared in composer.json?
  4. Is a config file publishable, and does it expose navigation label, authorization callback, and default filters?
  5. Does the subject filter work when a morph map is in use, and how does it behave for forceDelete()d subjects?
  6. What is the actual service provider name (must be confirmed from source, not assumed)?
  7. Does the panel resolve causer across multiple guards (Nova admin vs. customer API)? Wrong-guard resolution makes the entire panel misleading rather than merely incomplete.

Integration Approach

Stack fit

  • Requires Laravel + Laravel Nova + spatie/laravel-activitylog. No database engine constraints beyond what Spatie supports; no queue or cache dependency.
  • Best fit is an existing Nova admin already used by support, security, and operations staff — the package's value is that it puts audit answers where those people already work. Retrofitting Nova to get this screen would invert the cost/benefit.
  • The genuinely useful first workflow is record history for dispute triage: a support engineer filters by subject, sees status: pending → paid by a named causer at a timestamp, and closes a ticket without a DB console. Scope the pilot to that flow, not "browse all activity."

Migration path

Enforce the order of operations — it is not invertible:

  1. Install Spatie; publish migrations and config; migrate.
  2. Instrument one model with logOnlyDirty(), dontSubmitEmptyLogs(), logOnly([...]), and a domain-scoped useLogName(). Verify a row lands in activity_log.
  3. Only then install the viewer and register it with an explicit canSee() gate.
  4. Harden authorization (policy or scoped query) before any non-admin sees the menu item.

Adjacent migrations that must land at the same time or not at all:

  • Morph map decision on day one. Adopting Relation::enforceMorphMap() after logging begins creates a historical FQCN/alias split that silently mismatches the subject filter and requires a data migration.
  • log_name as domain axis, not model class. billing, auth, admin, integrations. Class-based names duplicate subject_type and waste the primary filter.
  • Import/seeder wrapping with Activity::withoutLogging(...) so test-data refreshes don't dump 200k rows into an audit table.
  • Retention window agreed with security/legal, with activitylog:clean scheduled alongside the initial migration rather than after the table grows.

Compatibility

  • Pin both laravel/nova and spatie/laravel-activitylog exactly. Treat any bump to either as a change requiring regression of this panel.
  • Assume we vendor the tool class and Vue component into the app proactively. Doing it as incident response is slower and more expensive than doing it up front.
  • Decide the causer resolution strategy centrally (default_causer config or a causer resolver) before multiple guards or queue workers enter the picture; retrofitting attribution means historical rows are permanently unattributed.

Sequencing

  • Phase 1 (spike, ~1 week): Spatie installed, one model instrumented, panel installed and gated, authorization behavior verified by hand with a low-privilege Nova user, load-tested against a realistic row count.
  • Phase 2 (hardening): Row-level authorization, domain log_name convention documented and applied, indexes created, pruning scheduled, correlation tap added for request_id/IP/impersonator.
  • Phase 3 (adoption): Resource detail-page history panel (Activity::forSubject($invoice)->latest()->limit(50)) — often more valuable day-to-day than the global browse screen — plus usage measurement.
  • Phase 4 (decision gate): Based on measured usage, either accept the fork as maintained internal tooling or replace the UI while keeping the Spatie layer and schema. Never replace the schema.

Operational Impact

Maintenance

  • Low code maintenance, non-trivial ownership overhead. Assign a named internal owner and a calendar reminder to re-verify the tool after every Nova upgrade — this is the single most likely breakage and it fails silently as a blank or erroring tool.
  • Maintain a fork branch with our authorization scoping and any property-diff normalization. It's a small surface; the cost of carrying it is far below the cost of being blocked on an unresponsive maintainer.
  • Our real maintenance burden is the instrumentation discipline: log_name taxonomy, snake_case event naming, from/to property conventions, and default_causer handling. That convention is what makes the filters usable six months in — the package cannot enforce it.

Support

  • Primary support consumers are support engineers and security/ops staff doing dispute triage and privileged-action review. Track whether they actually use it in week one; if the record-history workflow doesn't come up, neither will the rest, and the pilot should end.
  • Expect one recurring support ticket class: "the panel is empty." The answer is almost always missing instrumentation or a model bypassed by query-builder writes — document the diagnostic (DB::table('activity_log')->count()) in the runbook.
  • Document the diff-rendering quirks up front: cast dates appear as ISO timestamps, enums as backing values, forceDelete()d subjects render blank. Reviewers will report these as bugs otherwise.

Scaling

  • activity_log is append-only; a busy application reaches millions of rows within a year. Verify server-side pagination in the Vue component before rollout and load-test against realistic volume.
  • Ship indexes with the initial migration, not after degradation: (subject_type, subject_id), (causer_type, causer_id, created_at), (log_name, created_at), (created_at).
  • Prune from day one via activitylog:clean and delete_records_older_than_days. Retention is a policy decision requiring security/legal sign-off; the package cannot make it and will happily grow unbounded.
  • Bulk operations must be collapsed deliberately — aggregate one row for operational batch work, per-record for anything a customer could dispute — or 5,000-row loops bury the panel and the storage budget.

Failure modes

  • Silent audit gaps: DB::table()->update(), Model::query()->update(), and raw upserts bypass model events entirely — invisible holes exactly where imports, jobs, and reports live. Any custom Nova action using raw queries has the same problem and must log explicitly.
  • Unattributed rows: queued jobs have no authenticated user; console commands have no causer. Every row shows blank in the panel, which is worse than not logging because it looks like coverage.
  • Authorization exposure: if canSee() is the only gate, the panel is all-or-nothing and leaks cross-tenant or privileged activity to any Nova user with the menu item.
  • Secret leakage: logAll() on a User writes password hashes and tokens into an append-only table rendered to a wide internal audience. logOnly/logExcept is mandatory, not advisory.
  • Morph map retrofit: adopting a morph map after logging begins splits the subject filter across two identifier schemes.
  • Nova major upgrade breakage: expected, silent, and not fixable upstream on our timeline.
  • Scope creep into compliance: this is read-only convenience with no immutability, export, legal hold, or SLA. It must not become the answer to a customer contract or regulatory requirement — that is a separately scoped feature, and the durable assets we carry forward are the Spatie logging layer, the schema, and the retention policy.

Ramp-up

  • Developer ramp is hours, not days: composer install, publish, register, gate, verify.
  • Organizational ramp is the long pole: agreeing the log_name taxonomy, the event naming convention, the property snapshot rules, the retention window, and the authorization model across support, security, and legal. That work is what determines whether the panel is useful in six months, and it is independent of which viewer we use — another reason to time-box the package as a spike and fund the instrumentation program on its own merits.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource