Event Log

What It Is

The Event Log is a tenant-wide ledger of noteworthy activity that has happened inside the platform. It is not an access log, not a debug trace, and not an audit transcript of every database write. It is a curated stream of events that the platform and tenant configuration have explicitly decided are worth preserving for operators, administrators, and compliance reviewers.

An event is written to the ledger whenever the platform or a tenant-configured automation calls the event log facility. Each event carries:

  • a category that classifies what kind of activity it is
  • a title and optional content — either plain text or a translation key
  • a subject user the event is about
  • an owner — the acting user at the time the event was recorded
  • a created-by user — the real person behind the act when impersonation is in use
  • an optional object reference (type + object id) identifying the carrier record
  • an optional data payload with structured context
  • a timestamp

The Event Log surface is the operator-facing view that turns this ledger into a filterable, paginated list with a detail modal per event.

Why It Matters

The platform exposes many surfaces where the question "what actually happened here" matters: an account is reset, a record is touched by an automation, an email is sent, a cron job runs. Without a single inspection surface, these questions scatter across separate logs, separate audits, and separate UI panels.

The Event Log answers them in one place:

  • "did the password reset email actually go out?"
  • "which automation touched this record last night?"
  • "who activated this user account — an admin or the user themselves?"
  • "what did the scheduler do during the weekend window?"
  • "is there a pattern to these failed account activations?"

Because events are filterable by user, by actor, by object, by category, by date, and by full-text search over title and content, operators can slice activity along whichever axis matters for the question at hand.

Conceptual Model

There are three concerns to keep distinct.

  1. Events are explicit. An event exists only because something in the platform or in the tenant configuration chose to log it. The ledger is not a firehose.
  2. Events are descriptive, not transactional. An event records that something meaningful happened. It is not the underlying data change, it is a note about the change.
  3. Events are read-only to operators. The Event Log view lets operators inspect and filter. It does not let them edit or delete events from the UI. Events accrete; they are not manually curated.

Keeping these three ideas separate is what lets the Event Log serve simultaneously as an operational inspection tool, a governance trail, and a lightweight compliance reference.

Event Shape

Every event carries the same shape. Understanding each field is what makes filtering and reading the log productive.

Category

A short string identifier that groups events into families. Common platform-provided categories include:

  • General Activity — a catch-all for ad-hoc events logged from automations or custom code
  • Messaging — sent emails, push notifications, SMS
  • Account lifecycle — creation, activation request, activation completed, password reset by admin, password reset by user
  • Object lifecycle — object created, updated, accessed, deleted, restored
  • Cron action — scheduled work executed by the scheduler

Categories are the primary navigation axis for the log. Filtering by category is how an operator narrows the stream to "just the emails last month" or "just the account changes".

Title And Content

Both are free-form text, with one convention. If the string is prefixed with __, the log treats it as a translation key and resolves it at render time using the tenant's translation files. This is how platform-generated events display in the operator's chosen language rather than hard-coding English or Czech.

In the table view, the log displays the resolved text, and the raw key remains available as a tooltip. In the detail modal, both the resolved text and the raw key are shown side by side, making localization gaps easy to spot.

Subject User, Owner, And Created-By

Three user references live on every event, and they answer different questions.

  • Subject userwho the event is about. For account events, this is the affected account. For explicit logEvent calls that name a user, this is that user. Often null on object-only events.
  • Ownerwhich user was acting at the time. Captured as the current effective user when the event was recorded.
  • Created-bywhich real person was behind the act. When a tenant admin is impersonating another user, the platform distinguishes the apparent actor (owner) from the real actor (created-by). In normal sessions, these are the same.

The combination lets operators answer both "what was done to this user?" and "what did this user do?" and, crucially, "did an admin do this while impersonating someone?".

Object Reference

If an event is associated with a specific record (a typed object or a user resource), the event carries the object's type id and id. The Event Log UI resolves these to the object's display title at render time using the object's canonical title property — the same label the rest of the platform uses — so events read as domain events rather than as numeric references.

If the underlying object is later renamed, the log reflects the new name automatically, because resolution happens at render time.

Data Payload

An optional structured payload, stored as JSON. This is the place for event-specific detail that does not fit into title or content: the recipient of an email, the parameters of a cron job, the key/value pair that changed on an object. The detail modal renders the payload pretty-printed so that operators can scan it without leaving the log.

Timestamp

Every event has a precise creation time. The log orders events newest first and exposes a date range filter so operators can scope to a specific incident window.

How Events Enter The Ledger

Events enter in three ways. Operators do not create events from the Event Log view — the log is a readout, not an entry surface.

Platform-generated events

The platform logs events at significant lifecycle points. Example points include:

  • account activation requested
  • account activated
  • password reset requested by admin
  • password reset requested by user
  • object created, updated, accessed, deleted, restored (when the corresponding per-type flag is enabled)

Account- and messaging-class events are always written. Object-lifecycle events are written only when the object's Type has the corresponding flag enabled — see the subsection below.

These are written automatically as part of the surrounding operation. The category and title are standardized so the same event category is produced by the same action regardless of where it was triggered.

Object lifecycle logging (per-type opt-in)

The five object categories — Object Created, Object Updated, Object Accessed, Object Deleted, Object Restored — are controlled on the Logging form group of each type. Four flags govern them: Object Deleted and Object Restored share a single flag, because the two are halves of one lifecycle and it doesn't make sense to log deletions without restorations (or vice versa).

Flag (on the type)Fires onCustom message field
log_create_enabledsuccessful object creationlog_create_message
log_read_enabledoperator-visible single-object retrieval — object detail page, REST single-resource fetch, MCP get tool calllog_read_message
log_update_enabledpersisted updates with at least one actually changed propertylog_update_message
log_delete_enabledobject deletion (captures pre-delete state) and restoration of a soft-deleted record from the Trash surfacelog_delete_message

Every flag defaults to off. Turn them on deliberately per type.

When log_delete_enabled is on, both Object Deleted and Object Restored events are emitted, and both reuse log_delete_message as their custom content. The platform's default message distinguishes "has been deleted." from "has been restored." automatically based on the event category, so leaving the message field empty yields correctly-worded defaults for both halves. When a custom message is provided, phrase it neutrally if it needs to cover both cases.

When a custom message field is empty, the platform writes a neutral default naming the type, its id, the object id, and the operation. When the field has content, it is passed through the expression layer (Expressions) so property shortcodes resolve against the object in scope — e.g. "{$this.invoice_number} archived by {$this.owner.user_name}.".

Read logging has a deliberately narrow scope. It fires on operator-visible single-object retrievals — the detail page's initial render, the REST single-resource fetch, and the MCP single-object tool call — and not on list views, snippet redraws, signal handlers, batch sub-requests, background AJAX side-tasks, or internal object resolution (permission checks, expression evaluation, form rendering, cache warm-up, etc.). This keeps the ledger meaningful: one event per deliberate "show me this record" interaction, not one per partial redraw or framework-internal lookup. Even so, enable it only when read traceability is a governance requirement (sensitive personal data, financial records under audit, regulatory records).

The Types chapter documents each flag and its recommended use in full.

Automation-generated events

The built-in Log event automation action calls the event log facility with inputs taken from the automation's scope. Tenant implementers add this action to an automation whenever they want a specific workflow step to be traceable in the operator-facing log.

Typical uses:

  • record that a business process reached a milestone
  • capture what happened when an approval decision was applied
  • track external integration side effects (for example: "webhook fired to vendor X")

Automation-generated events can populate any field on the event, so implementers can tailor categorization to the tenant's domain vocabulary.

Scheduler-generated events

Cron work executed by the scheduler can log events using the same mechanism. This is how operators correlate "cron fired at 02:00" with "this is what it did".

The Operator Surface

The Event Log presenter gives access to the ledger through three concerns layered together: filtering, listing, and detail inspection.

Filtering

A persistent filter panel on the left sits alongside the list. It narrows by:

  • Category — one of the registered categories
  • Subject user — who the event is about
  • Created-by user — the real actor behind the event, especially useful when auditing impersonation
  • Object type — restrict to events on a specific type of record
  • Object id — restrict to events on a specific record
  • Date from / date to — scope to an incident window
  • Search — full-text substring match on title and content (including translation keys, so operators can search by raw key as well as by resolved text)

Filters compose. Every applied filter is reflected in the URL, so a filtered view is shareable and bookmarkable. Pagination and filter state are preserved across each other.

The filter panel itself is resizable — operators working on wider screens can give filters more room; operators who want more table width can collapse filters. This preference is remembered per session.

Listing

The list is paginated (100 events per page by default), sorted newest first, and shows the signal that operators typically scan for:

  • when it happened
  • what category it was
  • which users were involved (subject, owner, created-by — each icon-distinguished and each clickable to open the user record)
  • which object it was about (clickable to open the object record)
  • the resolved title

A summary above the table shows page position and total event count so operators can tell immediately whether a filter has narrowed the result set usefully.

The user and object links open inside the same page using the platform's modal stack, so operators can drill into an affected record and return to the list without losing filter state.

Detail Modal

Clicking a row opens a detail modal with every field of the event in full:

  • resolved and raw title
  • resolved and raw content
  • all three user references with their labels
  • the object reference as a clickable record link
  • the structured data payload pretty-printed as JSON
  • the exact timestamp

The modal is where compliance-style "I need to see everything on this event" work happens. The list is the scanning surface; the modal is the inspection surface.

Who Can See The Event Log

Access to the operator surface is gated by a dedicated permission:

  • View Event Log (system-level, under the Management group in the permissions admin)

Without this permission, the navigation entry is hidden, the URL redirects back to the homepage with an access-denied flash, and the surface is not reachable.

This is deliberately a narrow permission. The event log is readable activity about the whole tenant, including user lifecycle and object access. It should be granted only to roles whose job legitimately requires cross-tenant inspection — typically tenant administrators, compliance reviewers, and a small set of power users. It should not be granted to ordinary users.

Writing events is not gated by this permission. Automations and platform lifecycle hooks write events regardless of who triggered them.

Typical Uses

  • Incident investigation. A user reports they cannot log in. Filter by the user, inspect account events, identify whether a password reset was initiated, by whom, and when.
  • Impersonation oversight. Filter by the created-by user to surface every event produced while a specific admin was impersonating other users.
  • Automation introspection. Filter by category General Activity with a free-text search on the automation's signature title. Scan the resulting feed to verify the automation fired as expected.
  • Messaging verification. Filter by a messaging category to confirm that notifications actually went out over the last day.
  • Object lifecycle trace. Filter by object type and object id to reconstruct the meaningful touches to a specific record.
  • Cron audit. Filter by Cron Action and a date range to review scheduled work for a given window.

How The Event Log Fits With Other Governance Surfaces

The Event Log complements rather than replaces other governance tooling.

  • Version Management tracks implementation releases. Use it to ask "which version was deployed when this event happened".
  • Application Management tracks tenant-wide state and totals. Use it for health and storage reporting.
  • Tenant Synchronization applies configuration packages. Cron events and general-activity events from the sync can be read in the log to see what was applied.
  • Roles And Permissions governs who can view the log, and governs whose activity is worth logging via automations.

The Event Log is the activity surface; the other governance chapters are the state and configuration surfaces.

Best Practices

  • Log deliberately. Events are meant to be readable signal. Prefer a small number of well-categorized events to a flood of debug-style entries.
  • Use translation keys for platform and recurring events. Prefixing title and content with __ lets operators read the log in their configured language. The raw key stays visible as a tooltip for exact grepability.
  • Reuse categories. When adding automation-generated events, pick an existing category when one fits, or introduce a stable new category rather than inventing unique strings per event.
  • Attach the object reference when possible. Events without a type and id are harder to filter and correlate.
  • Treat the data payload as the overflow field. Anything not in title, content, category, or the user/object references belongs there. Keep it JSON-serializable and modest in size.
  • Grant the view permission sparingly. The log is a cross-tenant readout; it belongs to roles whose job requires it.
  • Use the detail modal for compliance work, the list for triage. Scanning in the list; deep reading in the modal.

Anti-Patterns

Avoid these patterns.

  • Using events for business state. Events are descriptions of what happened; they are not a place to record the current state of a domain entity. State belongs in properties and objects, not in the log.
  • Logging on every tick of every loop. The log becomes unreadable and the filter surface loses value. Log milestones, not iterations.
  • Reinventing categories per automation. Categories are navigational. A hundred singleton categories is the same as no categories at all.
  • Relying on the log as the primary alerting channel. The log is an inspection surface, not a real-time alert pipeline. Use messaging automations for alerting and use the log to audit them afterward.
  • Granting View Event Log to ordinary users. The log contains system-wide activity, including other users' lifecycle events. Keep its readership narrow.

Example

Suppose a tenant operator is investigating a user complaint: "I tried to reset my password yesterday and never got the email".

A workable approach:

  1. Open the Event Log.
  2. Filter Subject user to the complaining user.
  3. Set Date from to the previous day's start.
  4. In the narrowed list, look for an Account Password Reset by User event.
  5. If present, inspect the event detail modal to confirm the reset link was generated and note the timestamp.
  6. Filter Category to a messaging category and the same date range.
  7. Look for a messaging event whose subject or recipient data payload matches the user.
  8. If there is no matching messaging event, the email was not sent — the problem lies in the messaging pipeline, not in the reset flow.
  9. If the messaging event exists, the reset flow and messaging ran correctly — the issue is downstream (delivery, spam, wrong address).

In this scenario the log is used as the diagnostic lens across two independent concerns (account lifecycle and messaging) that would otherwise require separate tools.