# `MishkaDocument.EventLog`
[🔗](https://github.com/mishka-group/mishka_document/blob/v0.0.1/lib/mishka_document/resources/event_log.ex#L5)

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.

# `t`

```elixir
@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()
}
```

# `actor_label`

```elixir
@spec actor_label(map()) :: String.t()
```

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.

# `counts`

```elixir
@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`.

# `default_short_name`

# `input`

```elixir
@spec input(values :: map() | Keyword.t()) :: map() | no_return()
```

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

```elixir
Resource
|> Ash.Changeset.for_create(:create, %{embedded: EmbeddedResource.input(foo: 1, bar: 2)})
|> Ash.create()
```

# `input`

```elixir
@spec input(values :: map() | Keyword.t(), action :: atom()) :: map() | no_return()
```

Same as `input/1`, except restricts the keys to values accepted by the action provided.

# `logged`

```elixir
@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]

# `primary_key_matches?`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
