laravel-chronicle maintained by keshavmansure
Laravel Chronicle
Lightweight Eloquent change tracker for Laravel.
Add one trait to a model — creates, updates, and deletes are recorded automatically with before/after snapshots, optional request metadata, and almost zero configuration.
Package: keshavmansure/laravel-chronicle
Requirements
- PHP 8.2+
- Laravel 11 or 12
Installation
composer require keshavmansure/laravel-chronicle
Publish the config (optional):
php artisan vendor:publish --tag=chronicle-config
Publish the migration (optional — migrations also auto-load):
php artisan vendor:publish --tag=chronicle-migrations
Or publish both:
php artisan vendor:publish --tag=chronicle
Run migrations:
php artisan migrate
If you publish the migration and leave package auto-loading enabled, keep only one copy so the table is not created twice.
Quick start
use KeshavMansure\Chronicle\Traits\HasChronicle;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasChronicle;
}
That's it.
$post = Post::create(['title' => 'Hello', 'body' => 'World']);
$post->update(['title' => 'Updated']);
$post->delete();
Reading history
use KeshavMansure\Chronicle\Models\ChronicleEntry;
ChronicleEntry::query()
->where('model_type', Post::class)
->where('model_id', $post->id)
->latest()
->get();
// Via the model relationship
$post->chronicleEntries;
Excluding attributes
Global — config/chronicle.php:
'exclude' => [
'password',
'remember_token',
],
Per model — merged with the global list:
class User extends Model
{
use HasChronicle;
protected array $chronicleExclude = [
'api_token',
'two_factor_secret',
];
}
Per-model overrides
class User extends Model
{
use HasChronicle;
protected array $chronicleEvents = ['created', 'updated'];
protected array $chronicleExclude = ['api_token'];
protected array $chronicleOnly = ['name', 'email'];
protected string $chronicleSnapshot = 'changes'; // or "full"
}
| Property | Purpose |
|---|---|
$chronicleEvents |
Which events to track on this model |
$chronicleExclude |
Extra attributes to omit (merged with config) |
$chronicleOnly |
If set, only these attributes are stored |
$chronicleSnapshot |
full or changes |
Configuration
Publish to config/chronicle.php. Only enabled reads from the environment (CHRONICLE_ENABLED); everything else is config-only.
| Option | Default | Description |
|---|---|---|
enabled |
true (CHRONICLE_ENABLED) |
Globally enable/disable tracking |
connection |
null |
DB connection (app default if null) |
table |
chronicle_entries |
Table name |
snapshot |
full |
full or changes |
events |
created, updated, deleted |
Events to track |
exclude |
password, remember_token |
Attributes never stored |
only |
[] |
When set, only these attributes are stored |
metadata.user_id |
true |
Store authenticated user ID |
metadata.ip |
true |
Store request IP |
metadata.user_agent |
true |
Store user agent |
pretty_print |
false |
Pretty-print JSON snapshots |
What gets stored
| Column | Description |
|---|---|
model_type |
Eloquent morph class |
model_id |
Model primary key |
event |
created, updated, or deleted |
before |
JSON snapshot before the change |
after |
JSON snapshot after the change |
user_id |
Authenticated user (if available) |
ip_address |
Request IP (if available) |
user_agent |
User agent (if available) |
created_at / updated_at |
Timestamps |
Extensibility
Recording goes through the ChronicleRecorder contract. Bind your own implementation to swap storage or queue writes later without changing the public API:
$this->app->singleton(
\KeshavMansure\Chronicle\Contracts\ChronicleRecorder::class,
\App\Chronicle\QueuedChronicleRecorder::class,
);
Testing
composer install
composer test
CI runs on PHP 8.2 / 8.3 against Laravel 11 and 12 (SQLite in-memory).
If your local PHP has no pdo_sqlite:
cp .env.testing.example .env.testing
# set DB_* and create the database, then:
composer test
Or install SQLite: sudo apt install php8.2-sqlite3
Roadmap
Not in the current version:
- Rollback support
- Diff viewer / dashboard UI
- Soft delete & restore tracking
- Queue support
- Multi-tenant support
- Custom metadata providers
License
MIT © Keshav Mansure