# `MishkaCmsCore.Runtime.PageBuilder.Comment`
[🔗](https://github.com/mishka-group/mishka_cms_core/blob/v0.0.1/lib/mishka_cms_core/runtime/page_builder/comment.ex#L5)

The shape and the wording of a review note — what the storage layer is built around.

## What this is now

Notes live in the database: `MishkaCmsCore.Runtime.PageComment`. This module is what that resource
was built from, and what is left of it is the two things a struct is better at than a table:

  * `new/1` — the validated constructor, including the id shape and the sanitising of a note's
    text. Still the only place a note's fields are described in one piece.
  * `ago/2` — "now" / "4m ago" / "3h ago" / "yesterday", in the reader's language. Coarse on purpose: a review is read in the order it
    was written, and a timestamp to the second is noise beside a sentence.

It used to be the storage as well: a list on the `EditorSession` in ETS, swept after a day idle.
Its own moduledoc said the next step was an Ash resource, and that is what happened. The field
names were kept, so the swap was storage rather than a rewrite of the panel.

# `t`

```elixir
@type t() :: %MishkaCmsCore.Runtime.PageBuilder.Comment{
  at: any() | nil,
  author: String.t() | nil,
  author_id: String.t() | nil,
  id: String.t(),
  node_id: String.t() | nil,
  node_label: String.t() | nil,
  resolved?: boolean() | nil,
  text: String.t()
}
```

# `ago`

```elixir
@spec ago(t() | map(), DateTime.t()) :: String.t()
```

A short, human relative time for the sheet, in the reader's language — "now", "4m ago", "3h ago",
"yesterday" (`MishkaCmsCore.Localized.ago/2`).

Deliberately coarse: a review thread wants "roughly when", and a coarse label does not need the
page to re-render every second to stay honest.

# `builder`

# `enforce_keys`

# `enforce_keys`

# `example`

A sample %MishkaCmsCore.Runtime.PageBuilder.Comment{} populated from defaults + type-based fallbacks.

# `generate_id`

```elixir
@spec generate_id() :: String.t()
```

A fresh comment id — the same shape the tree uses for nodes, with a `c` prefix.

# `keys`

# `keys`

# `new`

```elixir
@spec new(map()) :: {:ok, t()} | {:error, term()}
```

Builds a comment, minting the id and timestamp.

Returns `{:error, _}` when the note is blank, so the caller can leave the composer alone instead of
posting nothing.

# `open`

```elixir
@spec open([t()]) :: [t()]
```

The comments still awaiting attention, newest first.

# `resolve`

```elixir
@spec resolve(t()) :: t()
```

Marks a comment resolved, or leaves it alone when it already is.

---

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