jooservices / laravel-events
EventSourcing and EventLog for Laravel with MongoDB storage
Requires
- php: ^8.5
- laravel/framework: ^12.0
- mongodb/laravel-mongodb: ^5.6
Requires (Dev)
- captainhook/captainhook: ^5.23
- captainhook/plugin-composer: ^5.3
- larastan/larastan: ^3.9
- laravel/pint: ^1.27
- orchestra/testbench: ^10.0
- phpmd/phpmd: ^2.15
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.0
- squizlabs/php_codesniffer: ^4.0
This package is auto-updated.
Last update: 2026-05-09 09:49:08 UTC
README
Lightweight Event Sourcing and Event Log persistence for Laravel with MongoDB storage. Store domain event payloads by aggregate and/or model change audit trails (prev/changed/diff) via Laravel's native event dispatcher.
Package name: jooservices/laravel-events
- Laravel 12 · PHP 8.5+
- MongoDB via mongodb/laravel-mongodb
Introduction
This package adds two persistence features on top of Laravel's event system:
- Event Sourcing — Events implementing
EventSourcingInterfaceare stored in astored_eventsMongoDB collection (payload, aggregate id, metadata, user, time). Use for aggregate history, replay-oriented records, or audit by aggregate. - Event Log — Events implementing
LoggableModelInterfaceare stored in anevent_logscollection with previous/changed state and a per-field diff. Use for audit trails and compliance.
You dispatch events as usual; package subscribers persist them to MongoDB. No custom bus or queue required.
Scope
Use this package when you need a reusable Laravel-standard base library for persisting event records or audit logs.
This package does not:
- replace Laravel's event dispatcher
- provide a projection/read-model framework
- provide a business analytics or reporting layer
- provide dashboards, projections, or analytics/reporting workflows
- provide AI agents, AI data fetching, or an AI runtime
When to Use
| Need | Use |
|---|---|
| Persist domain events by aggregate for historical inspection or replay-aware workflows | Event Sourcing |
| Persist model/entity changes with previous/current values and field diff | Event Log |
| Need both domain history and field-level audit | Use both, with separate focused events |
| Need dashboards, projections, analytics, or AI retrieval | Build that in the application layer |
Quick Start
Install
composer require jooservices/laravel-events
Publish config (optional)
php artisan vendor:publish --tag=laravel-events-config
Environment
MONGODB_URI=mongodb://127.0.0.1:27017 MONGODB_DATABASE=your_db EVENTS_EVENTSOURCING_ENABLED=true EVENTS_EVENT_LOG_ENABLED=true
Ensure a mongodb connection exists in config/database.php (see mongodb/laravel-mongodb).
Indexes
php artisan events:install-indexes
Basic Usage
Event Sourcing
Implement EventSourcingInterface and dispatch:
use JooServices\LaravelEvents\EventSourcing\Contracts\EventSourcingInterface; class OrderCreated implements EventSourcingInterface { public function __construct(public string $orderId, public array $items) {} public function payload(): array { return ['order_id' => $this->orderId, 'items' => $this->items]; } public function aggregateId(): ?string { return $this->orderId; } } event(new OrderCreated('ORD-001', [['sku' => 'X', 'qty' => 2]]));
Events are stored in the stored_events collection. Optional: occurredAt(): ?\Carbon\CarbonInterface, metadata(): array. Use the HasEventSourcingDefaults trait to implement only payload() and aggregateId().
Recommended metadata keys include request_id, correlation_id, causation_id, source, channel, reason_code, schema_version, event_version, and optional tenant_id. The EventMetadata helper exposes constants and small factory methods for those conventions.
Event Log (Audit)
Implement LoggableModelInterface (and optionally HasLogAction) and dispatch with prev/changed state. Use the DefaultsToUpdatedAction trait when the action is always updated:
use JooServices\LaravelEvents\EventLog\Concerns\DefaultsToUpdatedAction; use JooServices\LaravelEvents\EventLog\Contracts\LoggableModelInterface; use JooServices\LaravelEvents\EventLog\Contracts\HasLogAction; class OrderUpdated implements LoggableModelInterface, HasLogAction { use DefaultsToUpdatedAction; public function __construct(public Order $model, public array $prev) {} public function getLoggableType(): string { return $this->model->getMorphClass(); } public function getLoggableId(): string { return (string) $this->model->getKey(); } public function getPrev(): array { return $this->prev; } public function getChanged(): array { return $this->model->getAttributes(); } }
Changes are stored in event_logs with a computed diff. Query by entity_type + entity_id.
Recommended action names are available from JooServices\LaravelEvents\EventLog\EventLogAction: created, updated, deleted, restored, status_changed, corrected, synchronized, and imported.
Querying
use JooServices\LaravelEvents\Query\EventLogQueryService; use JooServices\LaravelEvents\Query\StoredEventQueryService; $events = app(StoredEventQueryService::class)->byAggregateId('ORD-001'); $audit = app(EventLogQueryService::class)->byEntity('orders', 'ORD-001');
Query services return typed package data records and intentionally stay small. Build dashboards, projections, and reporting in your application.
Redaction
Recursive redaction is enabled by default for common secret keys:
'redaction' => [ 'enabled' => true, 'keys' => ['password', 'token', 'authorization'], 'replacement' => '[REDACTED]', ],
This masks stored event payload/metadata and event log prev, changed,
diff, and meta. It is defensive masking, not a replacement for avoiding
secrets in dispatched events.
Retention
Optional MongoDB TTL indexes are configured with:
EVENTS_STORED_EVENTS_RETENTION_DAYS= EVENTS_EVENT_LOGS_RETENTION_DAYS=365
Run php artisan events:install-indexes after changing retention settings.
MongoDB TTL deletion is asynchronous.
Bulk Records
use JooServices\LaravelEvents\Data\StoredEventData; use JooServices\LaravelEvents\EventService; app(EventService::class)->recordManyStoredEvents([ new StoredEventData('OrderImported', ['order_id' => 'ORD-001'], 'ORD-001'), ]);
Bulk APIs normalize and redact each record before MongoDB batch insert.
Documentation
Full documentation is in the ./docs folder:
| Document | Description |
|---|---|
| docs/README.md | Documentation index |
| Architecture | Design, data flow, diagrams |
| Code structure | Package layout and namespaces |
| Installation | Requirements and setup |
| Configuration | Config and context provider |
| Decision Guide | Event Sourcing vs Event Log |
| Event Sourcing | Stored events and aggregates |
| Event Log | Audit trail and diff |
| Metadata | Metadata keys, versioning, corrections |
| Operations | Indexes, query patterns, retention, production safety |
| AI Integration | Optional app-layer AI export examples |
| Development | Composer commands, CI, release, and contributor workflow |
| Samples | Complete code examples |
| API Reference | EventService, interfaces, commands |
Testing & Linting
composer test composer test:coverage composer lint # Pint, PHPCS, PHPStan composer lint:all # lint + PHPMD composer lint:fix composer check # lint:all + test composer ci # lint:all + test:coverage
Git Hooks
Composer installs Git hooks automatically on dependency install and update:
composer install composer update
The hooks are managed by CaptainHook and enforce:
commit-msg: Conventional Commits, for examplefix: Correct event metadata mergepre-commit: PHP syntax linting, staged secret scanning with gitleaks, Pint, PHPCS, PHPStan, PHPMD, and PHP-CS-Fixerpre-push: gitleaks history scan when available, thencomposer test
If hooks need to be reinstalled manually:
vendor/bin/captainhook install --force --skip-existing
Install gitleaks locally to pass the pre-commit secret scan:
brew install gitleaks
AI Contributor Support
AI contributor guidance is intentionally documentation-only:
The package does not include AI runtime code, AI data fetching, authorization, redaction, or tool execution.
DTO-Style Records
The package uses small typed data records for normalized stored event and audit
log data. It follows jooservices/dto as a maturity baseline for repository
quality and docs structure, without depending on DTO domain internals.
GitHub Actions
Configured workflows:
CI: Composer audit, Pint, PHPCS, PHPStan, PHPMD, PHPUnit coverage with a MongoDB service, a 95% minimum statement coverage gate, and non-blocking dependency review for pull requestsRelease: validate version tags, create GitHub releases, and trigger Packagist updates when Packagist secrets are configuredPR Labeler: apply labels based on changed filesSemantic PR Title: enforce Conventional Commit-style PR titlesOpenSSF Scorecard: publish security posture results as SARIFSecret Scanning: run Gitleaks on pushes, pull requests, and manual dispatches
Coverage is archived as a workflow artifact. Codecov and SonarQube Cloud are optional and only run when repository secrets are configured, so README badges do not claim those services as mandatory package support.
License
This project is licensed under the MIT License.