gesmuni / laravel-audit-db
Database implementation of Gesmuni Audit Store using Laravel Eloquent ORM
Package info
gitlab.gitlab.videoatencion.com/gesmuni/php-laravel/laravel-audit-db.git
pkg:composer/gesmuni/laravel-audit-db
Requires
- php: ^8.2
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- ramsey/uuid: ^4.7
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0
This package is not auto-updated.
Last update: 2026-05-08 11:11:45 UTC
README
Database implementation of the Gesmuni Audit Store — persists and queries audit events using Laravel Eloquent ORM.
This package implements the AuditEventStore and AuditEventSink interfaces from laravel-audit-base with a relational database backend. It provides immutable event storage, paginated queries, SHA-256 integrity verification, and configurable retention with policy-enforced purging.
Features
- Full AuditEventStore implementation: receive, query, count, purge, verify
- Immutable storage: events cannot be modified or deleted (only retention-based purge)
- SHA-256 integrity checksums: tamper detection per event and per date range
- Paginated queries: filter by actor, action, resource, outcome, source, date range, and metadata
- Retention policy: configurable maximum retention with purge safety validation
- Batch writes: transactional batch inserts via
receiveBatch() - Auto-discovery: Laravel auto-registers the service provider
Installation
composer require gesmuni/laravel-audit-db
Publish and run the migrations:
php artisan vendor:publish --tag=gesmuni-audit-migrations
php artisan migrate
Alternatively, the migrations are auto-loaded by the service provider — publishing is optional if you don't need to customize them.
Configuration
Set the retention period in your application config (e.g. config/audit.php or via .env):
// config/audit.php
return [
'retention_days' => 365, // default: 365 days
];
The service provider reads config('audit.retention_days', 365) and injects a RetentionPolicy into the store.
Usage
Storing events
The package binds AuditEventStore and AuditEventSink as singletons in the Laravel container. Inject them wherever you need:
use Gesmuni\Audit\Contracts\AuditEventStore;
use Gesmuni\Audit\Entities\AuditEvent;
use Gesmuni\Audit\ValueObjects\Actor;
use Gesmuni\Audit\ValueObjects\Action;
class OrderService
{
public function __construct(
private AuditEventStore $auditStore,
) {}
public function cancelOrder(string $orderId, string $userId): void
{
// ... cancel logic ...
$event = new AuditEvent(
id: \Ramsey\Uuid\Uuid::uuid4()->toString(),
actor: new Actor($userId, 'HUMAN', 'Jane Doe'),
action: new Action('cancel', 'order', $orderId, 'SUCCESS'),
occurredAt: new \DateTimeImmutable('now', new \DateTimeZone('UTC')),
);
$this->auditStore->receive($event);
}
}
Querying events
use Gesmuni\Audit\Contracts\AuditQuery;
$query = new AuditQuery();
$query->actorId = 'user_01';
$query->resource = 'order';
$query->fromDate = new \DateTimeImmutable('-30 days', new \DateTimeZone('UTC'));
$query->limit = 20;
$page = $auditStore->query($query);
foreach ($page->items as $event) {
echo $event->who()->id . ' ' . $event->what()->verb . ' ' . $event->what()->resource;
}
echo "Total: {$page->total}, Has more: " . ($page->hasMore ? 'yes' : 'no');
Integrity verification
// Single event
$result = $auditStore->verify($eventId);
// $result->valid, $result->method ('SHA-256'), $result->detail
// Date range
$report = $auditStore->verifyRange(
new \DateTimeImmutable('2026-01-01', new \DateTimeZone('UTC')),
new \DateTimeImmutable('2026-01-31', new \DateTimeZone('UTC')),
);
// $report->total, $report->valid, $report->invalid, $report->failures
Purging expired events
// Purge events older than the configured retention period
$result = $auditStore->purge();
// $result->purgedCount, $result->oldestRemoved, $result->newestRemoved
// Purge events older than a specific date (must respect retention policy)
$result = $auditStore->purge(
new \DateTimeImmutable('-400 days', new \DateTimeZone('UTC'))
);
Attempting to purge events that haven't exceeded the retention period throws PurgeNotAllowed.
Database schema
The package creates an audit_events table with indexed columns for efficient querying:
| Column | Type | Notes |
|---|---|---|
id | UUID (PK) | |
actor_id | string | indexed |
actor_type | string | |
actor_name | string? | |
action | string | indexed |
resource | string | indexed |
resource_id | string? | indexed |
outcome | string? | indexed |
outcome_detail | string? | |
occurred_at | timestamp | indexed, UTC |
source | string? | indexed |
source_ip | string? | |
source_detail | string? | |
reason | string? | |
correlation_id | string? | indexed |
triggered_by | string? | |
metadata | JSON? | supports key/value filtering |
recorded_at | timestamp? | set by the store at write time |
checksum | string? | SHA-256 for integrity verification |
Package structure
src/
├── AuditDbServiceProvider.php # Service provider with DI bindings
├── EloquentAuditEventStore.php # AuditEventStore implementation
└── Models/
└── AuditEventModel.php # Eloquent model
database/
└── migrations/
└── 2026_01_01_000001_create_audit_events_table.php
Examples
The examples/ directory contains sample applications demonstrating how to use this package. These examples are excluded from the Composer distribution — to access them, clone the repository directly.
Minimal App
A minimal Laravel application with a public dashboard that shows audit events stored in SQLite. It provides buttons to generate sample events of different types and displays them in a table with the 5W model (Who, What, When, Where, Why).
See examples/minimal-app/README.md for setup instructions.
Requirements
- PHP ^8.1
- Laravel 10.x or 11.x
- gesmuni/laravel-audit-base
License
AGPL-3.0-or-later — see LICENSE