Context for phoenix_kit_annotations — drawn-on-image shapes created
via the Etcher overlay layer in the MediaBrowser modal.
Most callers won't use this directly — they go through
PhoenixKit.Modules.Storage.EtcherAdapter which implements the
Etcher.Storage behaviour and dispatches to this context. The module
is exposed so admin tooling, audits, or background workers can do
CRUD without reaching for the adapter.
Summary
Functions
Create an annotation for a file.
Delete an annotation by UUID.
Fetch a single annotation by UUID, or nil.
Returns true if the file has at least one annotation.
List annotations for a file, ordered by position then insertion time.
List annotations for a file together with a tooltip-friendly preview of their comment thread. Each element is a map
Resolves "file" comment resources for the comments moderation admin.
Update an annotation's geometry / style / metadata / position.
Types
Functions
@spec create(attrs()) :: {:ok, PhoenixKit.Annotations.Annotation.t()} | {:error, Ecto.Changeset.t()}
Create an annotation for a file.
attrs accepts both atom- and string-keyed maps (the latter is what
flows in from LiveView events). Keys: :file_uuid, :kind,
:geometry, optional :creator_uuid, :style, :metadata,
:position.
@spec delete(uuid()) :: :ok | {:error, :not_found | Ecto.Changeset.t()}
Delete an annotation by UUID.
Cascades to any linked comments — i.e. comments on the annotation's
file that carry metadata.annotation_uuid pointing at this row. The
cascade is a hard delete: annotation comments are conceptually owned
by their annotation, so they go with it instead of lingering as
[removed] placeholders in the file's thread. phoenix_kit_comment_media
rows fall away via their ON DELETE CASCADE; the underlying media
files (referenced via comment_media.file_uuid) stay untouched —
they're library assets, not comment-owned. No-ops cleanly when
PhoenixKitComments isn't installed.
@spec get(uuid()) :: PhoenixKit.Annotations.Annotation.t() | nil
Fetch a single annotation by UUID, or nil.
Returns true if the file has at least one annotation.
@spec list_for_file(uuid()) :: [PhoenixKit.Annotations.Annotation.t()]
List annotations for a file, ordered by position then insertion time.
List annotations for a file together with a tooltip-friendly preview of their comment thread. Each element is a map:
%{
annotation: %Annotation{},
first_comment: %{content, author, thumbnail_url} | nil,
comment_count: integer()
}Annotation comments are stored against the file (resource_type: "file",
resource_uuid: file_uuid) with metadata.annotation_uuid pointing at
the annotation, so they show up in the file's main comments thread
alongside non-annotated discussion. This loader pulls every file
comment in one query and groups by that metadata key.
If the comments package isn't installed, returns the same shape with
first_comment: nil and comment_count: 0 so callers always handle
one schema.
Resolves "file" comment resources for the comments moderation admin.
Comments on files — including annotation discussions, which are anchored to
the file with metadata.annotation_uuid — carry resource_type: "file" and
resource_uuid: file_uuid. This maps those file uuids to the file's display
name and admin media path so the moderation list links to the file instead
of showing a bare uuid.
Registered as the "file" handler by phoenix_kit_comments'
resolve_comment_resources/1 dispatch (gated on this module being loaded).
@spec update(uuid(), attrs()) :: {:ok, PhoenixKit.Annotations.Annotation.t()} | {:error, :not_found | Ecto.Changeset.t()}
Update an annotation's geometry / style / metadata / position.