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

Statamic Activity Laravel Package

goldnead/statamic-activity

Goldnead/Statamic Activity adds an activity log to Statamic, letting you record and review user actions and content changes across your site. A lightweight way to track what happens in the control panel and keep an audit trail of edits, publishes, and other events.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package remains a Statamic addon with brand-awareness via statamic-brand-context. Two releases are now in scope. v1.5.0 was a declaration-only nav change (settingsNavParent() returning a [section, name] tuple, consumed by brand-context ≥ 1.16 to nest settings under "Einstellungen" or a shared "Addon-Suite" page). v1.6.0 is materially different in kind: it moves retention from a per-brand Settings field to a single installation-wide config value (retention.days, overridable via ACTIVITY_RETENTION_DAYS), makes activity:prune fail closed on non-positive/non-numeric windows, and fixes a bug where the prune window varied by which brand the run started under. That last fix confirms the prior architecture was incoherent—the Settings UI wrote a per-brand value that nothing read, while the command deleted across all brands using one number. v1.6.0 removes the dead field and aligns storage with actual behavior. This is a correctness fix, not a feature.

Integration feasibility. Mechanically still easy—no migration, no schema change, no new required config key—but "easy" is no longer the same as "safe." The headline change is a destructive default: unset ACTIVITY_RETENTION_DAYS now means 365 days, so the next activity:prune run deletes everything older than a year. Previously an unset value pruned nothing by age. There is a second-order trap: installs that published config/activity.php earlier still read env('ACTIVITY_RETENTION_DAYS') with no default and therefore keep everything. Two installs on the identical package version will behave differently based on whether a config file was published years ago. Adoption is composer update plus a config audit, not composer update.

Technical risk. Medium, concentrated in one place. The deletion itself is irreversible; the guardrails are procedural (--dry-run) rather than automatic. Risk factors: (1) the prune command is almost certainly scheduled, so the window between composer update and the next scheduled run is the entire safety margin—there is no "opt-in" step; (2) config drift means the team cannot infer behavior from version alone; (3) the ≤ 0 / non-numeric refusal is a genuine safety improvement and should be treated as a reason to upgrade, not a side note—subDays(0) is "now" and the guard prevents a full-store wipe from a typo'd env var or a --days=0 invocation; (4) orphaned brand_settings rows for retention.days are now dead data, manually removable, and will linger as misleading artifacts; (5) the acknowledged gap—retention.anonymize_after_days still stored per brand while activity:anonymize operates store-wide—is the exact same class of bug that v1.6.0 just fixed for prune, left in place. Expect it to be the next breaking release.

Key questions.

  • Is there an existing published config/activity.php in each environment, and does its days key have a default? This single fact determines whether the upgrade is a no-op or a deletion event.
  • What is the actual scheduled cadence and next-run time of activity:prune relative to any planned deploy? Can the schedule be paused during rollout?
  • Does any internal or customer-facing policy promise per-brand retention? The Settings field implied per-brand control that never existed; if a contract or DPA says otherwise, this is a disclosure problem, not just a config change.
  • Is a 365-day default defensible for this data (audit log? security events? GDPR minimization argument?) or should the estate standardize on null?
  • Has activity:anonymize ever been relied on per brand, given it has always been store-wide? The known gap says the setting is still stored per brand and unread across brands—who set those values and what did they believe they were getting?
  • Prior questions still open: does the addon own a CP nav section or land on shared "Addon-Suite"; is "Einstellungen" a hardcoded German string; what is the pinned floor for statamic-brand-context; how does a dangling settingsNavParent() tuple resolve?
  • Shipping a destructive default in a minor version bump—is that acceptable to this team's upgrade policy, and does it warrant pinning rather than floating?

Integration Approach

Stack fit. Laravel scheduler + Statamic addon + statamic-brand-context ≥ 1.16 for the nav nesting from v1.5.0. v1.6.0 adds no runtime dependency; it changes a command's default semantics and removes a Settings field. The nav change from v1.5.0 is cosmetic and optional by comparison—v1.6.0 is the release that requires planning.

Migration path. No data migration, but three preparatory steps are mandatory before the version bump: (1) run php artisan activity:prune --dry-run in each environment and record the deletion volume; (2) inspect the deployed config/activity.php for the presence/absence of a default on days; (3) decide the intended policy (365, an explicit other number, or null to retain indefinitely) and encode it explicitly rather than relying on either code default. Then upgrade, then delete the orphaned brand_settings rows for retention.days by hand. Ordering matters here in a way it did not in v1.5.0: the dry run must precede the deploy, or the first scheduled run after deploy becomes the dry run.

Compatibility. Backwards compatible at the code level, not at the behavior level. No migration, no removed API, existing published configs keep working—but they keep working differently from unpubished installs. The ≤ 0 refusal is a strict improvement and may surface previously silent misconfigurations as hard errors; anyone running --days=0 or a per-event-type window under 1 will now get a non-zero exit and no deletion. The per-brand Settings field removal is a UI regression for anyone who believed they had per-brand control, and orphaned rows will persist in brand_settings indefinitely.

Sequencing. (1) Dry-run audit across all environments and record counts. (2) Decide and document the retention policy, including whether any brand has a differing obligation. (3) Pause or delay the scheduled activity:prune for the deploy window if the estate is large and the dry run shows material volume. (4) Set ACTIVITY_RETENTION_DAYS or re-publish/adjust config/activity.php explicitly—do not leave the value implicit. (5) Deploy v1.6.0 (bundle the v1.5.0 nav change here if not already shipped; upgrade statamic-brand-context to ≥ 1.16 first if the nested nav should land together). (6) Re-run --dry-run, confirm it matches expectations, then re-enable the schedule. (7) Clean up orphaned brand_settings rows. (8) Smoke-test nav rendering and the Settings page copy.

Operational Impact

Maintenance. Low code burden, but v1.6.0 converts a dormant feature into a live scheduled job with irreversible effects. The ongoing obligation is config hygiene: every install must now carry an explicit retention decision, and that decision must survive re-publishes. The known anonymize_after_days gap should be tracked as scheduled technical debt with an expected breaking change.

Support. Expect two distinct ticket classes. First, "my activity history disappeared"—caused by the new 365-day default firing on the first scheduled run post-upgrade, and hardest to diagnose because nothing in the release is a failure. Support must be able to answer "what was your published config state and when did prune last run?" Second, "where is the retention setting?"—the Settings field is gone and replaced by prose pointing at config/activity.php. Both need pre-written docs and screenshots. The v1.5.0 version-dependent nav placement ("Einstellungen" nested vs. legacy flat, or the shared "Addon-Suite" page) remains a second axis of screenshot drift, and the German label is still a localization question worth resolving while the Settings page is being touched.

Scaling. Two dimensions. Data volume: a 365-day default will materially shrink stores over time, which reduces DB size and query cost but also reduces the window for investigations—an availability/forensics trade-off, not a pure win. Fleet scale: the config-drift fork (published vs. unpublished config) scales badly across many installs, because identical versions behave differently and there is no way to tell from a version string. Standardize on explicit configuration in the deployment template. The "Addon-Suite" aggregation page remains a discoverability concern as more addons adopt settingsNavParent().

Failure modes. (1) Silent mass deletion on first scheduled run after upgrade—highest severity, no error surfaced, irreversible. (2) Config drift—published configs retain indefinitely while unpublished ones prune at 365 days; behavior is not inferable from version. (3) Guard surfacing as an outage: a misconfigured env var or per-event window now makes activity:prune exit non-zero; if it is wrapped in a scheduled chain, downstream tasks may be skipped. (4) Deploy-window race: composer update completing just before a scheduled run eliminates the dry-run safety margin. (5) Orphaned brand_settings data misleading future maintainers into thinking per-brand retention exists. (6) Anonymize gap—per-brand anonymize_after_days values are stored but ignored store-wide, so anonymization may not match any brand's stated policy. (7) Prior nav failure modes carry forward at low severity: dangling settingsNavParent() tuple, and label collisions on the shared "Addon-Suite" page.

Ramp-up. Trivial for the code change, non-trivial for the decision. An engineer can ship this in an afternoon; a team needs someone empowered to answer "how long do we keep this data, and does that answer differ per brand?" before the scheduled job runs. Budget the dry-run review and the policy decision as the real cost, and treat the composer update as the last step rather than the first. Support and QA need both branches of the config fork and both branches of the brand-context version in their test matrix.

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.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json