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.

High-traffic applications often cannot afford to mix the audit trail for orders, invoices, and user activity in a single table — query performance degrades, indexes bloat, and compliance requirements may demand physical separation. ModelScribe’s named stores feature lets you route each model’s audit entries to its own table, its own database connection, or both, with zero changes to your application code beyond a one-line model property.

How routing works

1

Define named stores in config

Under drivers.database.stores, add an entry for each logical destination. Each store declares the target tables array and, optionally, a connection override.
2

Set $auditLogName on the model

In any Eloquent model that uses the HasAuditLog trait, set the $auditLogName property to match a store key defined in the config. The default value is 'default', which falls through to the driver’s global table.
3

ModelScribe routes at runtime

When an auditable event fires, DatabaseDriver::resolveStore() looks up the entry’s logName in config('model-scribe.drivers.database.stores'). If a match is found, it uses that store’s tables and connection. If no match is found, it falls back to the global table and connection values.

Configuration example

// config/model-scribe.php

'drivers' => [
    'database' => [
        'driver'     => 'database',
        'table'      => 'model_scribe_logs',
        'stores' => [
            'invoices' => [
                'tables'     => ['invoice_scribe_logs'],
                'connection' => 'mysql_audit',
            ],
            'orders' => [
                'tables' => ['order_scribe_logs'],
            ],
        ],
    ],
],

Model configuration

Set $auditLogName on each model to the matching store key:
use HypathBel\ModelScribe\Traits\HasAuditLog;
use Illuminate\Database\Eloquent\Model;

class Invoice extends Model
{
    use HasAuditLog;

    protected string $auditLogName = 'invoices'; // routes to invoice_scribe_logs
}

class Order extends Model
{
    use HasAuditLog;

    protected string $auditLogName = 'orders'; // routes to order_scribe_logs
}
Models that do not declare $auditLogName (or leave it as 'default') continue to write to the top-level table value — model_scribe_logs by default — so adopting named stores is completely incremental.

Writing to multiple tables simultaneously

A single store can write one log entry to multiple tables at the same time using an array of names in the tables key. DatabaseDriver iterates the list and inserts an identical record into each table within the same request:
'stores' => [
    'invoices' => [
        'tables' => ['invoice_error_logs', 'invoice_scribe_logs'],
    ],
],
This is useful when a separate pipeline reads from invoice_error_logs for alerting while invoice_scribe_logs serves the compliance archive — both are kept in sync without any application-level fanout logic.

Guard-based routing

When you cannot — or do not want to — set $auditLogName explicitly on a model, ModelScribe can determine the destination store from the currently active authentication guard instead. Configure the guard_stores map at the top level of config/model-scribe.php:
// config/model-scribe.php

'guard_stores' => [
    'api'  => 'invoices',
    'web'  => 'orders',
],
At runtime, if a model’s logName is 'default' (the trait default), the observer checks guard_stores for the active guard and rewrites the log name before it reaches the driver. API requests therefore land in invoice_scribe_logs and web requests in order_scribe_logs, with no per-model code changes.

Generating migrations for new stores

Every named store needs its own migration. Use the model-scribe:make-table Artisan command to scaffold one from the package stub:
# Generates: database/migrations/{timestamp}_create_invoices_scribe_logs_table.php
php artisan model-scribe:make-table invoices

# Override the generated table name
php artisan model-scribe:make-table invoices --table=invoice_audit_trail
The command replaces the config-driven table name in the stub with the literal table name you specify, producing a standalone migration that can be run independently of the default model_scribe_logs migration. After generating the migration, run:
php artisan migrate
For models that receive a very high write rate, place their store on a dedicated database connection (e.g. a read-replica-free secondary MySQL instance or a separate PostgreSQL schema). This keeps audit I/O from contending with your primary application workload and allows you to scale the audit store independently.
Every named store requires its own migration before you can write to it. Running the application with a store configured but its table missing will cause a database error on the first auditable event for that model. Always generate and run the migration — via model-scribe:make-table — before deploying a new store to production.

Build docs developers (and LLMs) love