defmodule PhoenixKit.Notifications.Notification do @moduledoc """ Schema for per-user notifications. One row per (activity, recipient_user). Generated by `PhoenixKit.Notifications.maybe_create_from_activity/1` whenever an activity targets a user other than the actor. ## Fields - `activity_uuid` — FK to `PhoenixKit.Activity.Entry` - `recipient_uuid` — FK to `PhoenixKit.Users.Auth.User` - `seen_at` — `NULL` until the user opens the notification or bulk-marks - `dismissed_at` — `NULL` until the user dismisses it from the inbox - `inserted_at` — creation timestamp (no `updated_at`) """ use Ecto.Schema import Ecto.Changeset @primary_key {:uuid, UUIDv7, autogenerate: true} @type t :: %__MODULE__{ uuid: UUIDv7.t() | nil, activity_uuid: UUIDv7.t() | nil, recipient_uuid: UUIDv7.t() | nil, seen_at: DateTime.t() | nil, dismissed_at: DateTime.t() | nil, metadata: map() | nil, inserted_at: DateTime.t() | nil, activity: PhoenixKit.Activity.Entry.t() | Ecto.Association.NotLoaded.t() | nil, recipient: PhoenixKit.Users.Auth.User.t() | Ecto.Association.NotLoaded.t() | nil } schema "phoenix_kit_notifications" do belongs_to :activity, PhoenixKit.Activity.Entry, foreign_key: :activity_uuid, references: :uuid, type: UUIDv7 belongs_to :recipient, PhoenixKit.Users.Auth.User, foreign_key: :recipient_uuid, references: :uuid, type: UUIDv7 field :seen_at, :utc_datetime field :dismissed_at, :utc_datetime # Display content for a standalone notification (no activity). Render # reads notification_text / notification_icon / notification_link from # here — the same override keys it honors on activity metadata. field :metadata, :map, default: %{} timestamps(type: :utc_datetime, updated_at: false) end @doc "Changeset for creating a notification." def changeset(notification, attrs) do notification |> cast(attrs, [:activity_uuid, :recipient_uuid, :seen_at, :dismissed_at, :metadata]) # Only recipient is required — `activity_uuid` is nil for standalone # notifications (V126), where `metadata` carries the display content. |> validate_required([:recipient_uuid]) |> foreign_key_constraint(:activity_uuid) |> foreign_key_constraint(:recipient_uuid) |> unique_constraint([:activity_uuid, :recipient_uuid], name: :phoenix_kit_notifications_activity_recipient_index ) end end