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.
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
Restore comments soft-deleted by delete/1 and re-link them to a
newly-created annotation row. Used by the etcher restore (undo of
delete) flow: the original annotation uuid is gone, but the
soft-deleted comments are still in the DB carrying
metadata.annotation_uuid = original_uuid. We flip them back to
status: "published" and rewrite metadata.annotation_uuid to
point at the recreated row's uuid.
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 soft delete (status: "deleted") so reply chains stay
attached as [removed] placeholders rather than disappearing
silently. No-ops cleanly when PhoenixKitComments isn't installed.
@spec get(uuid()) :: PhoenixKit.Annotations.Annotation.t() | nil
Fetch a single annotation by UUID, or nil.
@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.
@spec restore_linked_comments(uuid(), uuid(), uuid()) :: non_neg_integer()
Restore comments soft-deleted by delete/1 and re-link them to a
newly-created annotation row. Used by the etcher restore (undo of
delete) flow: the original annotation uuid is gone, but the
soft-deleted comments are still in the DB carrying
metadata.annotation_uuid = original_uuid. We flip them back to
status: "published" and rewrite metadata.annotation_uuid to
point at the recreated row's uuid.
Returns the number of comments restored. No-ops cleanly when PhoenixKitComments isn't installed or when no soft-deleted matches are found.
@spec update(uuid(), attrs()) :: {:ok, PhoenixKit.Annotations.Annotation.t()} | {:error, :not_found | Ecto.Changeset.t()}
Update an annotation's geometry / style / metadata / position.