Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/HypathStack/model-scribe/llms.txt

Use this file to discover all available pages before exploring further.

A driver is the component responsible for the final step in the audit pipeline: taking a fully-assembled LogEntry DTO and persisting or dispatching it somewhere. ModelScribe ships with three built-in drivers, each implementing the DriverInterface contract, so they are all interchangeable and composable. The active driver is resolved at runtime by the DriverManager singleton, which caches each resolved instance for the lifetime of the request.

Built-in Drivers

The database driver inserts a row into a database table for each audit event. It is the default driver and the most feature-rich, supporting multi-table routing, multiple DB connections, and configurable retention policies.

Store Resolution

When log() is called, the driver calls its internal resolveStore() method with the entry’s logName. Resolution follows this order:
  1. Named store match. If a key under drivers.database.stores matches the logName, the driver uses that store’s tables (or table) and optional connection.
  2. Global fallback. If no named store matches, the driver writes to the default table on the default connection.
A single named store can target multiple tables via the tables key — the entry is inserted into each table in the list. This is useful for writing the same audit record into both a partitioned archive table and a recent-events table.

Configuration

// config/model-scribe.php
'drivers' => [
    'database' => [
        'driver'     => 'database',
        'connection' => env('MODEL_SCRIBE_DB_CONNECTION', null),
        'table'      => env('MODEL_SCRIBE_TABLE', 'model_scribe_logs'),

        'stores' => [
            'invoices' => [
                'tables'     => ['invoice_scribe_logs', 'invoice_archive_logs'],
                'connection' => 'mysql_audit',
            ],
            'orders' => [
                'tables' => ['order_scribe_logs'],
            ],
        ],

        'retention' => [
            // 'permanent' — never prune automatically
            // 'days'      — delete records older than `days` days
            // 'rotating'  — keep only the latest `keep` records
            'type' => env('MODEL_SCRIBE_RETENTION', 'permanent'),
            'days' => (int) env('MODEL_SCRIBE_RETENTION_DAYS', 90),
            'keep' => (int) env('MODEL_SCRIBE_RETENTION_KEEP', 500),
        ],
    ],
],

Retention Policies

The database driver supports three retention modes, configured under retention.type:
TypeBehaviour
permanentRecords are never deleted automatically. This is the default.
daysRecords older than retention.days days are deleted when prune() is called.
rotatingOnly the most recent retention.keep records are kept per table managed by this driver.
Pruning is triggered by the model-scribe:prune Artisan command or by calling ModelScribe::prune() from a scheduled job.

Configuring the Default Driver

Set the default key to the name of the driver you want used for all models that do not specify their own:
// config/model-scribe.php
'default' => env('MODEL_SCRIBE_DRIVER', 'database'),
You can also set it via the MODEL_SCRIBE_DRIVER environment variable without touching the config file, which is useful for switching drivers per environment.

Overriding the Driver Per Model

A model can opt into a different driver by setting the $auditDriver property in the HasAuditLog trait:
use HypathBel\ModelScribe\Traits\HasAuditLog;

class PaymentTransaction extends Model
{
    use HasAuditLog;

    // Use the stack driver for this model, regardless of the global default.
    protected ?string $auditDriver = 'stack';
}
When $auditDriver is null (the default), the global default driver from config is used.

Custom Drivers

If the three built-in drivers do not cover your requirements — for example, you want to ship audit events to Elasticsearch, a message queue, or a webhook — you can register a custom driver using DriverManager::extend().

1. Implement DriverInterface

Your driver must implement the two-method DriverInterface contract:
use HypathBel\ModelScribe\Contracts\DriverInterface;
use HypathBel\ModelScribe\DTOs\LogEntry;

class ElasticsearchDriver implements DriverInterface
{
    public function __construct(protected array $config) {}

    public function log(LogEntry $entry): void
    {
        // Dispatch $entry to Elasticsearch using $this->config.
    }

    public function prune(): int
    {
        // Delete old entries and return the count, or return 0 if unsupported.
        return 0;
    }
}

2. Register via extend()

Call extend() on the DriverManager inside a service provider’s boot() method. The closure receives the driver’s config array and the DriverManager instance, and must return a DriverInterface implementation:
use HypathBel\ModelScribe\DriverManager;

public function boot(DriverManager $manager): void
{
    $manager->extend('elasticsearch', function (array $config, DriverManager $manager) {
        return new ElasticsearchDriver($config);
    });
}

3. Add the Driver Config Block

Add a matching entry under drivers in config/model-scribe.php:
'drivers' => [
    // ... built-in drivers ...

    'elasticsearch' => [
        'driver' => 'elasticsearch',
        'host'   => env('ELASTICSEARCH_HOST', 'localhost'),
        'port'   => env('ELASTICSEARCH_PORT', 9200),
        'index'  => env('MODEL_SCRIBE_ES_INDEX', 'model-scribe'),
    ],
],
The driver key inside the config block tells the DriverManager which registered creator to invoke when building this named driver instance. You can then set 'default' => 'elasticsearch' or use protected ?string $auditDriver = 'elasticsearch' on individual models.

Build docs developers (and LLMs) love