Skip to main content

Actions

An action describes what happened in a Ledger Entry.
It is the most important part of an entry because it defines the event being recorded.

Examples:


billing.invoice.created
billing.invoice.updated
billing.payment.approved
auth.user.logged_in

Every ledger entry must include an action.


Why Structured Actions Matter

Using structured action names makes it possible to:

  • Filter entries easily
  • Build activity timelines
  • Generate reports
  • Aggregate events across services
  • Maintain consistency in large teams

Without structure, logs quickly become inconsistent and hard to query.


Action Format

Ledgerly enforces a structured format:


<domain>.<resource>.<verb>

Examples:


billing.invoice.created
billing.invoice.sent
auth.user.logged_in
payments.payment.failed

This format helps organize events logically.


Action Components

Domain

The domain groups related parts of the system.

Examples:


billing
auth
payments
subscriptions

Domains are optional but recommended for larger systems.


Resource

The resource represents the entity being acted upon.

Examples:


invoice
payment
user
subscription

Resources should usually match your model or business concept names.


Verb

The verb describes what happened.

Ledgerly validates verbs to encourage consistency.

Common verbs include:


created
updated
deleted
restored
attached
detached
enabled
disabled
sent
received
logged_in
logged_out
approved
rejected

Using consistent verbs makes filtering and reporting much easier.


Logging an Action

Example:

ledgerly()
->action('billing.invoice.created')
->log();

With actor and target:

ledgerly()
->actor(auth()->user())
->target($invoice)
->action('billing.invoice.updated')
->log();

Choosing Good Action Names

Good actions are:

  • Specific
  • Predictable
  • Consistent
  • Verb-based

Good examples:

billing.invoice.created
billing.invoice.sent
billing.invoice.marked_overdue
billing.subscription.cancelled
billing.payment.failed

Avoid:

invoice.changed
data.updated
action.performed
event.logged

These provide little useful information.


Naming Guidelines

Use Past Tense

Actions should describe something that already happened:

Good:

invoice.created
payment.failed

Avoid:

invoice.create
payment.fail

Avoid Technical Noise

Actions should describe business events, not implementation details.

Avoid:

model.saved
controller.executed
job.processed

Prefer:

invoice.created
invoice.updated
invoice.emailed

Be Consistent

If you use:

invoice.created

Do not later introduce:

invoice.create
invoice.was_created

Consistency is more important than perfection.


Action Validation

Ledgerly validates actions to ensure:

  • Correct format
  • Allowed verbs
  • Non-empty values

Invalid actions will throw an exception.

This protects data quality over time.


Using Custom Verbs

If your application needs custom verbs, you can extend validation rules in configuration or validators (depending on your setup).

Custom verbs should still follow naming guidelines:

Good:

invoice.marked_overdue
subscription.trial_started

Filtering by Action

Actions are easy to query:

LedgerEntry::forAction('invoice.created')->get();

You can also filter by prefixes:

invoice.*
billing.*

This makes analytics and reporting easier.


Actions and Severity

Actions can be combined with severity levels:

ledgerly()
->severity('warning')
->action('invoice.overdue')
->log();

This helps distinguish informational events from critical ones.


Best Practices

Recommended conventions:

  • Use lowercase
  • Use dots as separators
  • Use past tense verbs
  • Keep names short but descriptive
  • Prefer business terminology

Next Step

Continue to:

➡️ Metadata