gesmuni/laravel-audit-db

Database implementation of Gesmuni Audit Store using Laravel Eloquent ORM

Maintainers

Package info

gitlab.gitlab.videoatencion.com/gesmuni/php-laravel/laravel-audit-db.git

pkg:composer/gesmuni/laravel-audit-db

Statistics

Installs: 92

Dependents: 1

Suggesters: 0

1.1.0 2026-03-27 10:01 UTC

This package is not auto-updated.

Last update: 2026-05-08 11:11:45 UTC


README

License: AGPL v3 PHP Version

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:

ColumnTypeNotes
idUUID (PK)
actor_idstringindexed
actor_typestring
actor_namestring?
actionstringindexed
resourcestringindexed
resource_idstring?indexed
outcomestring?indexed
outcome_detailstring?
occurred_attimestampindexed, UTC
sourcestring?indexed
source_ipstring?
source_detailstring?
reasonstring?
correlation_idstring?indexed
triggered_bystring?
metadataJSON?supports key/value filtering
recorded_attimestamp?set by the store at write time
checksumstring?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

License

AGPL-3.0-or-later — see LICENSE