MishkaCmsCore.Notify.Notification (Mishka CMS Core v0.0.1)

Copy Markdown View Source

A single, per-recipient, read/unread notification row (cms_notifications).

One row per recipient (fan-out on write), so privacy is a one-line policy (user_id == actor(:id)) and the feed is a single indexed lookup. Notifications are transient personal state — no archival, no PaperTrail versions (like Accounts.Token).

Tenancy: site_id is the recipient's site (nil for master users, who read unscoped and are still confined to their own rows by the policy). The site an event concerns is carried in metadata for display, never in site_id.

Two nullable timestamps drive the standard UX with zero extra machinery:

  • seen_at — nil counts toward the bell badge; cleared when the dropdown opens.
  • read_at — nil renders bold/unread; cleared per item or via "mark all read".

type is an open string validated by format (like a permission name), not an enum — so a new extension can deliver an unknown type without a code change. Whether a site receives a given type is a per-site boolean Setting (MishkaCmsCore.Notify.setting_key/1), checked once at delivery — not stored here.

Delivered exclusively through MishkaCmsCore.Notify.deliver/3 (system-internal, authorize?: false). See MishkaCmsCore.Notify, MishkaCmsCore.Notify.Delivery.

Summary

Functions

Apply the full GuardedStruct pipeline (sanitize → validate → derive → main_validator) to attrs and return either {:ok, transformed_attrs} or {:error, errors}. Wire this into an Ash.Resource.Change to plug guardedstruct rules into Ash's changeset pipeline.

O(1) lookup of a field's compile-time metadata by name. Returns nil for unknown fields.

Compile-time-baked MapSet of every field name owned by the guardedstruct block. Used by GuardedStruct.AshResource.Change to decide, in O(1), whether a key in changeset.atomics belongs to the pipeline.

Validate + sanitize notification attrs through the GuardedStruct pipeline (strip HTML, trim, validate) WITHOUT a DB write — the same pipeline :deliver runs on write. Returns {:ok, sanitized_map} or {:error, errors}; producers can call it to check/clean a notification before Notify.deliver/3. GuardedStruct.AshResource omits the Codegen transformer (Ash uses changesets), so this exposes the pipeline under the usual builder/1 name.

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.

Types

t()

@type t() :: %MishkaCmsCore.Notify.Notification{
  __lateral_join_source__: term(),
  __meta__: term(),
  __metadata__: term(),
  __order__: term(),
  actor: term(),
  actor_id: term(),
  aggregates: term(),
  body: term(),
  calculations: term(),
  icon: term(),
  id: term(),
  inserted_at: term(),
  link: term(),
  metadata: term(),
  read?: term(),
  read_at: term(),
  seen_at: term(),
  severity: term(),
  site: term(),
  site_id: term(),
  source: term(),
  title: term(),
  type: term(),
  updated_at: term(),
  user: term(),
  user_id: term()
}

Functions

__guarded_change__(attrs, error? \\ false)

Apply the full GuardedStruct pipeline (sanitize → validate → derive → main_validator) to attrs and return either {:ok, transformed_attrs} or {:error, errors}. Wire this into an Ash.Resource.Change to plug guardedstruct rules into Ash's changeset pipeline.

The function is named __guarded_change__ because it does more than validate — it can also transform values (trim, downcase, slugify, auto-fill, etc.) before they reach the data layer.

__guarded_field_meta__(name)

O(1) lookup of a field's compile-time metadata by name. Returns nil for unknown fields.

__guarded_field_name_set__()

Compile-time-baked MapSet of every field name owned by the guardedstruct block. Used by GuardedStruct.AshResource.Change to decide, in O(1), whether a key in changeset.atomics belongs to the pipeline.

builder(attrs, error? \\ false)

Validate + sanitize notification attrs through the GuardedStruct pipeline (strip HTML, trim, validate) WITHOUT a DB write — the same pipeline :deliver runs on write. Returns {:ok, sanitized_map} or {:error, errors}; producers can call it to check/clean a notification before Notify.deliver/3. GuardedStruct.AshResource omits the Codegen transformer (Ash uses changesets), so this exposes the pipeline under the usual builder/1 name.

Notification.builder(%{type: "blog:x", title: "  <b>Hi</b> "})  #=> {:ok, %{title: "Hi", …}}

default_short_name()

input(opts)

@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

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

input(opts, action)

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

primary_key_matches?(left, right)