Minimal event log for tracking activities in MishkaDocument.
Stores only essential information:
- What happened (resource, action)
- When it happened (timestamp)
- Who did it (actor)
- Which record (record_id)
- Minimal context (site_id, title/name for display)
Does NOT store full input data or changed attributes to keep storage minimal.
The gervaz table over it is the document event log at /admin/dashboard/document/event-logs, drawn
by the shared MishkaCmsCoreWeb.Templates.ActivityTimeline — the same timeline the unified log at
/admin/dashboard/runtime/activity uses, over the very same rows. Everything the timeline reads
off a record comes from here: :severity, the content-change :tone it tints a create/update/
destroy row by, the day marks (MishkaDocument.Resources.Helpers.DayMarks) and :occurred_at.
Tenant scoping is MishkaDocument.Resources.Helpers.TenantSiteFilter's, on the :table_read list
and :table_get single-row reads both roles use — site_id lives in JSONB, so Ash multitenancy
cannot apply.
Every read needs one of the two document areas, admin:<dashboard|api>:document:workspace or
admin:<dashboard|api>:document:section, and returns only the events of the records that area
holds: a workspace admin reads workspace and version events, a section admin the rest
(logged/1). A master (a user whose site_id is nil) reads every site;
a site admin only rows carrying its own site, whatever read or site_id argument it asks with.
Writes belong to the system and to masters. Calls made with authorize?: false are not checked.
Only :table_read carries the page-level day marks (MishkaDocument.Resources.Helpers.DayMarks);
:table_get deliberately omits them, since one isolated realtime row has no page to mark.
Summary
Functions
Who did event, for the reader whose read loaded its :actor and :actor_master?.
How many events the viewer can see, as %{total: n, info: n, warn: n} — the log's KPI row.
Validates that the keys in the provided input are valid for at least one action on the resource.
Same as input/1, except restricts the keys to values accepted by the action provided.
The resources whose events an area reads: :workspace for document:workspace, :section for
document:section. Every resource writing to the log is listed under exactly one area.
Types
@type t() :: %MishkaDocument.EventLog{ __lateral_join_source__: term(), __meta__: term(), __metadata__: term(), __order__: term(), action: term(), action_type: term(), actor: term(), actor_id: term(), actor_master?: term(), aggregates: term(), calculations: term(), changed_attributes: term(), data: term(), id: term(), metadata: term(), occurred_at: term(), record_id: term(), resource: term(), severity: term(), tone: term(), version: term() }
Functions
Who did event, for the reader whose read loaded its :actor and :actor_master?.
The email the reader may see, "Master" for a master, "System" for an event no user did (a replay, a seed, a job) and "Unknown" for an actor the reader's read did not return.
@spec counts(map() | nil) :: %{ total: non_neg_integer(), info: non_neg_integer(), warn: non_neg_integer() }
How many events the viewer can see, as %{total: n, info: n, warn: n} — the log's KPI row.
Counted through :table_read, the very action the table reads, so a figure can never disagree with
the list beside it: a master counts every site, a tenant only its own. There is no :error figure
— an event log records what a resource DID, never a failure, so
MishkaCmsCore.Activity.Helpers.severity_for/1 only ever reads one of these as :info or :warn.
Validates that the keys in the provided input are valid for at least one action on the resource.
Raises a KeyError error at compile time if not. This exists because generally a struct should only ever
be created by Ash as a result of a successful action. You should not be creating records manually in code,
e.g %MyResource{value: 1, value: 2}. Generally that is fine, but often with embedded resources it is nice
to be able to validate the keys that are being provided, e.g
Resource
|> Ash.Changeset.for_create(:create, %{embedded: EmbeddedResource.input(foo: 1, bar: 2)})
|> Ash.create()
Same as input/1, except restricts the keys to values accepted by the action provided.
@spec logged(:workspace | :section) :: [module()]
The resources whose events an area reads: :workspace for document:workspace, :section for
document:section. Every resource writing to the log is listed under exactly one area.
MishkaDocument.EventLog.logged(:workspace)
#=> [MishkaDocument.Workspace, MishkaDocument.WorkspaceVersion]