PHPackages                             mhamed/spatie-activitylog-browse - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Logging &amp; Monitoring](/categories/logging)
4. /
5. mhamed/spatie-activitylog-browse

Abandoned → [Package mhamed/spatie-activitylog-browse is abandoned, you should avoid using it. Use mahmoud-mhamed/spatie-activitylog-browse instead.](/?search=Package%20mhamed%2Fspatie-activitylog-browse%20is%20abandoned%2C%20%20you%20should%20avoid%20using%20it.%20Use%20mahmoud-mhamed%2Fspatie-activitylog-browse%20instead.)Library[Logging &amp; Monitoring](/categories/logging)

mhamed/spatie-activitylog-browse
================================

Auto-log all models, enrich with request/device data, and browse activity logs via a web UI

v2.0.1(5d ago)01.8k↓89.7%MITBladePHP ^8.1

Since Feb 14Pushed 5d agoCompare

[ Source](https://github.com/mahmoud-mhamed/spatie-activitylog-browse)[ Packagist](https://packagist.org/packages/mhamed/spatie-activitylog-browse)[ RSS](/packages/mhamed-spatie-activitylog-browse/feed)WikiDiscussions main Synced 3d ago

READMEChangelog (10)Dependencies (10)Versions (13)Used By (0)

Activity Log Browse
===================

[](#activity-log-browse)

[![Latest Version on Packagist](https://camo.githubusercontent.com/a84132f4f6920589752f55fb546f68b4a589705c99798ef9ddf4dbfa7b0f9a59/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d61686d6f75642d6d68616d65642f7370617469652d61637469766974796c6f672d62726f7773652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mahmoud-mhamed/spatie-activitylog-browse)[![License](https://camo.githubusercontent.com/9d164df4f25f7442c5964a342ad8f839d783e17a83b9cfe2315827dc408060e8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6d61686d6f75642d6d68616d65642f7370617469652d61637469766974796c6f672d62726f7773652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mahmoud-mhamed/spatie-activitylog-browse)[![PHP Version](https://camo.githubusercontent.com/1b33a6d3eae493291d39fc1551b2ef22f4bdac8c1d9aca27f5d85d01aab2ce83/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6d61686d6f75642d6d68616d65642f7370617469652d61637469766974796c6f672d62726f7773652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mahmoud-mhamed/spatie-activitylog-browse)

A Laravel package that extends [spatie/laravel-activitylog](https://github.com/spatie/laravel-activitylog) v4 with **automatic model logging**, **rich contextual enrichment**, a **web-based log browser**, a **statistics dashboard**, **automatic retention/cleanup**, and a **deletion audit trail** — all with English/Arabic UI, dark mode, and an optional password gate.

> Arabic version: [README.ar.md](README.ar.md)

Features
--------

[](#features)

### Logging

[](#logging)

- 🔁 **Auto-log all models** without the `LogsActivity` trait — opt-out via excluded list
- 📦 **Rich enrichment** — request, device, performance, app, session, and execution context attached to every log entry
- 🆔 **UUID-friendly** — morph ID columns automatically migrated to support UUIDs
- ⚡ **Performance-optimized** — per-class caching, request-scoped collectors, no per-event reflection

### Browsing &amp; Analytics

[](#browsing--analytics)

- 🌐 **Browse UI** — filter, search, popovers, color-coded diffs, related-model navigation
- 📊 **Statistics dashboard** — charts for hourly/daily/monthly activity, peak times, top models/causers/attributes
- 🌍 **Localized** — English &amp; Arabic with automatic RTL layout
- 🌙 **Dark mode** — system-aware with manual toggle, persisted in localStorage
- 📝 **Attribute translation** — uses Laravel's `validation.attributes`

### Cleanup &amp; Audit

[](#cleanup--audit)

- 🧹 **Manual cleanup page** — preview-then-delete with model and date filters
- ⏱ **Automatic retention** — age + size limits, per-model overrides (incl. `'forever'`), Laravel-scheduler integration
- 📜 **Deletion history** — JSON audit log of every cleanup with row-level diff (before/after, duration, trigger, user)

### Security

[](#security)

- 🛡 **Optional password gate** with rate-limited login (5/min)
- 🚪 **Authorization gate** support for fine-grained permissions
- 🏢 **Multi-tenancy** aware (works out of the box with [stancl/tenancy](https://tenancyforlaravel.com/))

Table of Contents
-----------------

[](#table-of-contents)

- [Requirements](#requirements)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Configuration](#configuration)
    - [Auto-Log](#auto-log)
    - [Enrichment](#enrichment)
    - [Browse UI](#browse-ui-config)
    - [Password Gate](#password-gate)
    - [Retention / Auto-Cleanup](#retention--auto-cleanup)
    - [Deletion History](#deletion-history-config)
- [Usage](#usage)
- [Browse UI](#browse-ui)
- [Statistics Dashboard](#statistics-dashboard)
- [Deletion History Page](#deletion-history-page)
- [Artisan Commands](#artisan-commands)
- [Localization](#localization)
- [Multi-Tenancy](#multi-tenancy)
- [Performance Notes](#performance-notes)
- [Architecture](#architecture)
- [License](#license)

Requirements
------------

[](#requirements)

- PHP **8.1+**
- Laravel **10**, **11**, or **12**
- spatie/laravel-activitylog **^4.0**

Installation
------------

[](#installation)

```
composer require mahmoud-mhamed/spatie-activitylog-browse
```

If auto-discovery doesn't work, register the provider manually in `bootstrap/providers.php` (Laravel 11+) or `config/app.php`:

```
Mhamed\SpatieActivitylogBrowse\ActivitylogBrowseServiceProvider::class,
```

Then run the install command — publishes the spatie migration, the package config, runs migrations, fixes UUID-friendly morph columns, adds performance indexes, and prepares the deletion-history storage:

```
php artisan activitylog-browse:install
```

> Re-running `install` after upgrading the package will offer to refresh your config so new options (e.g. `retention`, `deletion_history`) are picked up.

### Publishing individual assets

[](#publishing-individual-assets)

```
# Spatie migration
php artisan vendor:publish --provider="Spatie\Activitylog\ActivitylogServiceProvider" --tag="activitylog-migrations"
php artisan migrate

# Package config
php artisan vendor:publish --tag=activitylog-browse-config

# Views (optional)
php artisan vendor:publish --tag=activitylog-browse-views

# Language files (optional)
php artisan vendor:publish --tag=activitylog-browse-lang

# Migrations (optional — for multi-tenancy setups)
php artisan vendor:publish --tag=activitylog-browse-migrations
```

> **Tip:** Use `--force` to overwrite previously published files after upgrading the package:
>
> ```
> php artisan vendor:publish --tag=activitylog-browse-config --force
> ```

### Local Development

[](#local-development)

To install as a local path repository, add the following to your Laravel app's `composer.json`:

```
"repositories": [
    { "type": "path", "url": "../spatie-activitylog-browse" }
]
```

```
composer require mahmoud-mhamed/spatie-activitylog-browse:@dev
php artisan activitylog-browse:install
```

Quick Start
-----------

[](#quick-start)

After running `activitylog-browse:install`:

1. Open `/activity-log` in your browser — protected by `web` + `auth` middleware by default.
2. Trigger any model change — it'll appear with full enrichment.
3. (Optional) Enable retention in `config/activitylog-browse.php` so old logs prune themselves.
4. (Optional) Set `ACTIVITYLOG_BROWSE_PASSWORD` in `.env` to add a password gate.

Configuration
-------------

[](#configuration)

The published config file is at `config/activitylog-browse.php`. Key sections below.

### Auto-Log

[](#auto-log)

```
'auto_log' => [
    'enabled' => true,
    'events' => ['created', 'updated', 'deleted'],
    'models' => '*',                // '*' = all models, or array of specific classes
    'excluded_models' => [],
    'log_name' => 'default',
    'log_only_dirty' => true,
    'excluded_attributes' => [
        'password', 'remember_token',
        'two_factor_secret', 'two_factor_recovery_codes',
    ],
    'submit_empty_logs' => false,
    'exclude_null_on_create' => false,
],
```

Models that already use the `LogsActivity` trait are automatically skipped to prevent duplicate entries.

### Enrichment

[](#enrichment)

Each enrichment section can be enabled/disabled and has per-field toggles. Disabling an entire section removes all per-event overhead for that section.

**Show all enrichment options**```
'request_data' => [
    'enabled' => true,
    'fields' => [
        'url' => true, 'previous_url' => true,
        'method' => true, 'route_name' => true,
    ],
],

'device_data' => [
    'enabled' => true,
    'fields' => ['ip' => true, 'user_agent' => true, 'referrer' => true],
],

'performance_data' => [
    'enabled' => true,
    'fields' => [
        'request_duration' => true,  // ms since LARAVEL_START
        'memory_peak' => true,       // bytes
        'db_query_count' => true,    // requires DB::enableQueryLog() to be useful
    ],
],

'app_data' => [
    'enabled' => true,
    'fields' => [
        'environment' => true,
        'php_version' => true,
        'server_hostname' => true,
    ],
],

'session_data' => [
    'enabled' => true,
    'fields' => ['auth_guard' => true],
],

'execution_context' => [
    'enabled' => true,
    'fields' => [
        'source' => true,        // "web" | "console" | "queue" | "schedule"
        'job_name' => true,      // queue job class name
        'command_name' => true,  // artisan command name
    ],
],
```

All collectors gracefully return empty data when running outside their context (e.g. request data in console).

### Browse UI Config

[](#browse-ui-config)

```
'browse' => [
    'enabled' => true,
    'prefix' => 'activity-log',
    'middleware' => ['web', 'auth'],
    'per_page' => 25,
    'gate' => null,                 // e.g. 'view-activity-log'
    'password' => env('ACTIVITYLOG_BROWSE_PASSWORD'),
    'available_locales' => ['en', 'ar'],
],
```

Set `gate` to a Laravel Gate name to restrict access; the package will call `Gate::authorize($name)` on every browse request.

### Password Gate

[](#password-gate)

For environments where you want a shared password protecting the browse UI (in addition to whatever auth/middleware you've configured):

```
# .env
ACTIVITYLOG_BROWSE_PASSWORD=your-secret-here
```

When set, users hitting `/activity-log` are redirected to a login screen. The form is rate-limited to **5 attempts per minute per IP**. Authentication is stored in the session — a logout button appears in the navbar when a user is signed in via password.

Set the env variable to an empty value (or remove it) to disable the gate entirely.

### Retention / Auto-Cleanup

[](#retention--auto-cleanup)

Automatically prune old activity log entries based on age and table size limits, with per-model overrides for sensitive data that should be kept longer (or forever).

```
'retention' => [
    'enabled' => true,

    'default_days' => 90,           // catch-all age limit
    'max_rows'     => 1_000_000,    // null to disable
    'max_size_mb'  => 500,          // null to disable

    'per_model' => [
        App\Models\AuditLog::class => 'forever',
        App\Models\User::class     => 365,
    ],

    'per_log_name' => [
        'security' => 365,
    ],

    'chunk_size'     => 1000,
    'optimize_after' => true,

    'schedule'      => 'daily',     // 'daily' | 'weekly' | 'monthly' | null
    'schedule_time' => '03:00',     // 24-hour HH:MM
],
```

#### Priority hierarchy (strongest → weakest)

[](#priority-hierarchy-strongest--weakest)

1. **`per_model` / `per_log_name`** — always win.
    - `'forever'` is fully protected from both age and size pruning.
    - An int day count protects records younger than the configured days from BOTH age and size pruning.
2. **`max_rows` / `max_size_mb`** — hard size caps. They win over `default_days`: when the table is over the cap, the oldest records (not protected by a per-model rule) are deleted *even if they are still inside the `default_days` window*.
3. **`default_days`** — the catch-all rule. Applies only to records not covered by a higher-priority rule.

#### What happens at the size limit?

[](#what-happens-at-the-size-limit)

Per-model ruleAge-based pruneSize-based prune (when `max_rows` / `max_size_mb` is hit)Not configuredDeleted after `default_days`**Can be deleted** (oldest first)`365` (any int days)Deleted after 365 days**Protected** while younger than 365 days; older records can be deleted`'forever'`Never deleted**Never deleted** (fully protected)> **TL;DR:** Per-model retention is the authoritative rule. A model set to `365` days will keep its rows for the full 365 days even if the table is over its size cap — they only become eligible for size pruning after their own retention window expires. The size cap is therefore **best-effort**: if every record is still inside its per-model retention window, nothing is deleted and the table stays over the cap until the protections expire. Set realistic per-model values to keep the size cap effective.

#### How it runs

[](#how-it-runs)

TriggerWhen**Schedule**Automatically at `schedule_time` (frequency = `daily`/`weekly`/`monthly`). Requires `schedule:work` or a cron entry calling `schedule:run`.**CLI**`php artisan activitylog-browse:prune` — see [Artisan Commands](#artisan-commands)**UI**A **Run Cleanup Now** button on the cleanup page.### Deletion History Config

[](#deletion-history-config)

Every cleanup operation (manual, scheduled, CLI, dry-run) is recorded in an append-only JSON file:

```
'deletion_history' => [
    'enabled' => true,
    'path' => storage_path('activitylog-browse/deletion-history.json'),
    'max_entries' => 500,    // oldest are dropped first
    'max_size_mb' => 3,      // file is reset if exceeded
],
```

Each entry captures: timestamp, trigger (`schedule`/`cli`/`ui`/`manual`), operation type, deleted count + breakdown, duration, table state before/after (rows + size MB), config snapshot, and user/IP context. Empty operations (0 rows deleted) are skipped.

The package automatically creates the storage directory and a `.gitignore` to prevent committing the JSON file.

Usage
-----

[](#usage)

### Auto-Logging

[](#auto-logging)

Once installed, all Eloquent model events are logged automatically:

```
$user = User::create(['name' => 'John']);   // Logged
$user->update(['name' => 'Jane']);          // Logged
$user->delete();                            // Logged
```

To exclude specific models:

```
'excluded_models' => [
    App\Models\TemporaryFile::class,
],
```

### Enrichment payload

[](#enrichment-payload)

Every activity log entry — whether from auto-logging, the `LogsActivity` trait, or manual `activity()` calls — is enriched with contextual data:

**Example enriched `properties`**```
{
    "attributes": { "name": "Jane" },
    "old": { "name": "John" },
    "request_data": {
        "url": "https://example.com/users/1",
        "method": "PUT",
        "route_name": "users.update"
    },
    "device_data": {
        "ip": "192.168.1.1",
        "user_agent": "Mozilla/5.0 ..."
    },
    "performance_data": {
        "request_duration": 142,
        "memory_peak": 12582912,
        "db_query_count": 8
    },
    "app_data": {
        "environment": "production",
        "php_version": "8.3.0",
        "server_hostname": "web-01"
    },
    "session_data": { "auth_guard": "web" },
    "execution_context": {
        "source": "web",
        "job_name": null,
        "command_name": null
    }
}
```

Browse UI
---------

[](#browse-ui)

Visit `/activity-log` (or your configured prefix). Top navigation includes: **Activity Log**, **Statistics**, **Cleanup**, **Deletion History**, **About** — plus a language switcher, theme toggle, and (when password gate is on) logout.

The list view provides:

- **Filtering** — log name, event type, model type, model ID, causer, date range, description search
- **Changed-attribute filter** — select a model type, then filter by a specific attribute (e.g. only show logs where `name` changed)
- **Quick preview popover** — hover the info icon on a row to see the old/new diff inline
- **Current-attributes popover** — view the subject's live model data without leaving the list
- **Model info sidebar** — when a model type is selected, shows total logs, unique records, table name, table size, event-breakdown badges, and clickable attribute chips for quick filtering
- **Related model navigation** — jump to all logs for a related model instance
- **Detail view** — color-coded diff, request/device/performance/app/session/execution metadata, raw JSON

### Attribute translation

[](#attribute-translation)

Attribute names (column names like `first_name`, `email_verified_at`) are auto-translated using `lang/{locale}/validation.php`:

- If `validation.attributes.{key}` exists → **"First Name" (first\_name)**
- Otherwise → **"Email Verified At"** (auto-headlined) with the original key in small text

Define translations once and they appear everywhere in the UI:

```
'attributes' => [
    'first_name' => 'First Name',
    'email' => 'Email Address',
    'created_at' => 'Creation Date',
],
```

Statistics Dashboard
--------------------

[](#statistics-dashboard)

Visit `/activity-log/statistics`. Each section loads independently via AJAX with skeleton states for fast initial render.

A date-range filter at the top applies to all sections (cached for 60s when filtered, 120s for all-time).

**Sections:** Overview cards · Peak Hour chart · Daily Activity (30 days) · Activity by Day of Week · Peak Times · Monthly Activity · System vs User Actions · Events Breakdown · Log Names · Top Models · Top Causers · Most Changed Attributes (last 1000 updates).

Deletion History Page
---------------------

[](#deletion-history-page)

`/activity-log/deletion-history` — auditable record of every cleanup operation:

- **Stats cards** — total entries, file size, current path
- **Per-row** — when, trigger badge (color-coded: schedule/cli/ui/manual + dry-run flag), operation, deleted count + breakdown (age vs size), table size before → after with diff, duration in ms, user/IP/command
- **Expandable JSON** — click a row to see the full entry payload (config snapshot, table state, context)
- **Pagination** — 25 per page
- **Clear button** — wipes the JSON file (with confirmation)

Artisan Commands
----------------

[](#artisan-commands)

```
# Install / upgrade
php artisan activitylog-browse:install

# Retention / cleanup
php artisan activitylog-browse:prune                # full prune (age + size)
php artisan activitylog-browse:prune --dry-run      # report what would be deleted
php artisan activitylog-browse:prune --age          # age-based only
php artisan activitylog-browse:prune --size         # size-based only
```

The `prune` command is automatically registered with the Laravel scheduler when `retention.schedule` is set (and you have `schedule:work` or cron running).

Localization
------------

[](#localization)

The package ships with English and Arabic translations. The UI auto-adapts to RTL when locale is `ar`.

```
// config/app.php
'locale' => 'ar',
```

Or at runtime:

```
App::setLocale('ar');
```

The browse UI also includes a language switcher button that saves the preference in the session.

To customize translations:

```
php artisan vendor:publish --tag=activitylog-browse-lang
# Use --force to overwrite previously published files
php artisan vendor:publish --tag=activitylog-browse-lang --force
```

This copies the files to `lang/vendor/activitylog-browse/` where you can edit them or add new languages — then update `available_locales` in the config.

Multi-Tenancy
-------------

[](#multi-tenancy)

Works out of the box with [stancl/tenancy](https://tenancyforlaravel.com/) (multi-database tenancy):

- **Cache isolation** — keys are prefixed with the tenant ID (e.g. `activitylog-browse:t:1:stats:overview`).
- **Database connection** — queries use whatever connection your Activity model defines.
- **No hard dependency** — tenant detection uses `function_exists('tenant')`.

### Setup for multi-database tenancy

[](#setup-for-multi-database-tenancy)

1. Disable automatic migrations so they don't run on the central DB: ```
    'load_migrations' => false,
    ```
2. Publish migrations to your tenant migration path: ```
    php artisan vendor:publish --tag=activitylog-browse-migrations
    ```

    Then move them to `database/migrations/tenant/` (or wherever your tenant migrations live).
3. Add tenancy middleware to the browse routes: ```
    'browse' => [
        'middleware' => ['web', 'auth', \Stancl\Tenancy\Middleware\InitializeTenancyByDomain::class],
    ],
    ```

Without tenancy, no extra setup is needed — everything works as expected.

Performance Notes
-----------------

[](#performance-notes)

The package is designed for low-overhead operation even on high-traffic apps with auto-logging enabled:

- **Per-class caching** in `GlobalModelLogger` — `LogsActivity` trait detection runs **once per model class**, not per event
- **Request-scoped collectors** — `debug_backtrace`, auth guard enumeration, and source detection run **once per request**, results cached as static properties
- **Disabled-aware enrichment** — the observer only invokes collectors that are enabled in config; disabled sections add **zero per-event overhead**
- **Console-only schedule registration** — HTTP requests skip scheduler binding entirely
- **Bulk-friendly delete chunks** — retention pruning runs in chunks of 1000 (configurable) with `set_time_limit(30)` to avoid table-lock storms

For best results on high-throughput apps:

- Add high-frequency models to `excluded_models`
- Disable `execution_context.fields.job_name` if you don't need queue tracking (skips a `debug_backtrace` per request)
- Use `Model::withoutEvents(...)` around bulk imports

Architecture
------------

[](#architecture)

ComponentRole`ActivitylogBrowseServiceProvider`Registers everything: listener, observer, routes, scheduler`GlobalModelLogger`Listens to global Eloquent events; logs activity for models without `LogsActivity``ActivityEnrichmentObserver`Observes the Activity model's `creating` event; merges enrichment data into properties`RequestDataCollector` / `DeviceDataCollector` / ...Individual data collectors invoked by the observer`RelationDiscovery`Reflection-based auto-discovery of Eloquent relationships for related-model browsing`RetentionPruner`Implements the priority hierarchy — age, size, per-model, per-log-name pruning`DeletionLogger`Writes deletion entries to the JSON history file with size/count caps`ActivityLogHelpers`Shared helpers — connection name, table size, cache key prefix, stats cache invalidation`ActivityLogController`Handles the browse UI: filtering, AJAX endpoints, statistics API, attribute inspection, cleanup, deletion history`RequirePassword` middlewareEnforces the optional password gate (rate-limited login)`SetLocale` middlewareApplies the user's locale preference from the session`InstallCommand``activitylog-browse:install` — publishes assets, fixes UUID columns, adds indexes`PruneCommand``activitylog-browse:prune` — manual / scheduled retention runsLicense
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance99

Actively maintained with recent releases

Popularity16

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~12 days

Recently: every ~30 days

Total

12

Last Release

5d ago

Major Versions

v1.1.0 → v2.0.02026-05-23

### Community

Maintainers

![](https://www.gravatar.com/avatar/3d00c2f8ae29401e1b578e1435eae2629802a0c10e8322e5cb12d701538ff971?d=identicon)[mahmoud-mhamed](/maintainers/mahmoud-mhamed)

---

Top Contributors

[![mahmoud-mhamed](https://avatars.githubusercontent.com/u/45818696?v=4)](https://github.com/mahmoud-mhamed "mahmoud-mhamed (27 commits)")

---

Tags

spatielaravelAuditlog viewerbrowseactivitylog

### Embed Badge

![Health badge](/badges/mhamed-spatie-activitylog-browse/health.svg)

```
[![Health](https://phpackages.com/badges/mhamed-spatie-activitylog-browse/health.svg)](https://phpackages.com/packages/mhamed-spatie-activitylog-browse)
```

###  Alternatives

[spatie/laravel-health

Monitor the health of a Laravel application

87512.0M167](/packages/spatie-laravel-health)[muhammadsadeeq/laravel-activitylog-ui

A beautiful, modern UI for Spatie's Activity Log with advanced filtering, analytics, and real-time features.

17717.0k](/packages/muhammadsadeeq-laravel-activitylog-ui)[spatie/laravel-flare

Send Laravel errors to Flare

111.4M7](/packages/spatie-laravel-flare)[alizharb/filament-activity-log

A powerful, feature-rich activity logging solution for FilamentPHP v4 &amp; v5 with timeline views, dashboard widgets, and revert actions.

2871.8k3](/packages/alizharb-filament-activity-log)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
