Search by

rimba / jejak

bites

System-wide activity log tracking actions, changes, and events for traceability and accountability.

v1.5.1 2026-10-15 07:47 UTC

README

Below is the recommended package README.

Rimba Jejak

Jejak provides a small application audit trail for Rimba packages and Laravel models.

It records a meaningful action together with its actor, result, optional reason, optional referenced model, and structured metadata.

Concepts

An audit record contains:

Field Meaning
actor Human-readable actor snapshot
user_id Authenticated user, when available
staff_id Associated staff record, when available
action Stable machine-readable action name
result success, failure, denied, or skipped
reason Optional explanation
ref Optional polymorphic referenced model
metadata Optional structured context

Jejak records application/domain events. It is not intended to mirror every Eloquent model mutation automatically.

Basic usage

Inject AuditTrail into the operation performing the business action:

use Rimba\Trail\Enums\AuditResult;
use Rimba\Trail\Services\AuditTrail;

final class ApproveRequest
{
    public function __construct(
        private AuditTrail $auditTrail,
    ) {}

    public function execute(Request $request): void
    {
        // Perform the business operation.

        $this->auditTrail->record(
            action: 'request.approved',
            ref: $request,
            result: AuditResult::Success,
        );
    }
}

Record a reason

$this->auditTrail->record(
    action: 'request.rejected',
    ref: $request,
    result: AuditResult::Denied,
    reason: 'Required approval was not present.',
);

Record metadata

Metadata should contain useful structured context, not arbitrary duplicated model state.

$this->auditTrail->record(
    action: 'work-order.status-changed',
    ref: $workOrder,
    metadata: [
        'from' => 'open',
        'to' => 'completed',
    ],
);

The resulting record conceptually contains:

action     work-order.status-changed
result     success
ref        WorkOrder #123
metadata   { from: open, to: completed }

Record an operation not tied to a model

ref is optional:

$this->auditTrail->record(
    action: 'calendar.imported',
    metadata: [
        'format' => 'ics',
        'records' => $count,
    ],
);

Failure logging

If the failure is caught by the application and is meaningful to the audit history:

try {
    $service->execute($request);

    $this->auditTrail->record(
        action: 'request.processed',
        ref: $request,
    );
} catch (Throwable $exception) {
    $this->auditTrail->record(
        action: 'request.processed',
        ref: $request,
        result: AuditResult::Failure,
        reason: $exception->getMessage(),
    );

    throw $exception;
}

Do not use Jejak as a replacement for Laravel exception logging. The audit event records business context; operational exceptions should still follow the application's normal logging/monitoring path.

Using the model trait

A model may opt into the convenience trait:

use Rimba\Trail\Traits\HasAuditTrail;

class WorkOrder extends Model
{
    use HasAuditTrail;
}

Then:

$workOrder->audit(
    action: 'work-order.completed',
    metadata: [
        'previous_status' => 'in-progress',
    ],
);

The trait delegates to the same AuditTrail service.

Action naming convention

Use stable, lower-case domain action names:

request.created
request.approved
request.rejected
work-order.completed
workflow.started
workflow.completed
version.released
calendar.imported

Prefer the business action being audited rather than UI wording such as:

clicked-button
submitted-form
opened-modal

Result values

Use AuditResult:

AuditResult::Success
AuditResult::Failure
AuditResult::Denied
AuditResult::Skipped

Do not introduce new free-form result strings unless the enum is intentionally extended.

Actor resolution

When no actor is passed explicitly, AuditTrail attempts to use:

current authenticated user
        -> associated staff record
        -> actor display value

If there is no authenticated actor, the stored actor becomes:

system

For a system process, you may also pass an explicit actor:

$this->auditTrail->record(
    action: 'calendar.synchronized',
    actor: 'scheduler',
);

Referenced models

Any Eloquent model can be associated through the polymorphic ref relationship:

$this->auditTrail->record(
    action: 'version.released',
    ref: $version,
);

This stores the reference type and ID while keeping Jejak independent from the domain package.

Reading audit history

The Filament AuditLogResource is intentionally read-only.

Administrators can:

list audit events
filter by result
search actor/action
view an event
inspect its reference
inspect metadata

Audit records are not normally created, edited, or deleted through Filament.

Querying in code

use Rimba\Trail\Models\AuditLog;

$logs = AuditLog::query()
    ->where('action', 'version.released')
    ->latest()
    ->get();

For one referenced record:

$logs = AuditLog::query()
    ->whereMorphedTo('ref', $version)
    ->latest()
    ->get();

What belongs in metadata?

Good metadata is small and explains the action:

[
    'from' => 'draft',
    'to' => 'released',
]

or:

[
    'workflow' => 'purchase-request',
    'step' => 'manager-approval',
]

Avoid dumping entire model payloads, credentials, authentication tokens, passwords, or other secrets into audit metadata.

Recommended usage across Rimba

Examples of appropriate integrations:

Versi
    version.created
    version.released

Kerja
    workflow.started
    workflow.completed
    work-package.completed

Boleh
    permission.sync.completed
    access.denied

Waktu
    calendar.imported
    shift.override.created

Sifat
    attribute.changed
    abac-role.synchronized

These are suggested naming examples. Each package should record only actions that are useful as durable audit history.

Design rule

Package performs meaningful action
        |
        v
AuditTrail::record(...)
        |
        v
AuditLog
        |
        v
Read-only Filament inspection

Jejak should remain small. It stores audit facts; it should not become the owner of workflows, authorization, versioning, or domain business logic.