rimba / jejak
System-wide activity log tracking actions, changes, and events for traceability and accountability.
Requires
- php: ^8.3
- rimba/asas: ^1.3
- rimba/orang: ^1.3
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
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.