Packages
phoenix_kit
1.7.176
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit/annotations/annotation.ex
defmodule PhoenixKit.Annotations.Annotation do
@moduledoc """
Ecto schema for `phoenix_kit_annotations`.
Stores user-drawn shapes (rectangle, circle, polygon, freehand) tied to
a `PhoenixKit.Modules.Storage.File` via `file_uuid`. All geometry is
in image-pixel coordinates; Fresco's coordinate adapter rescales for
pan/zoom at render time.
## Comment thread linkage
An annotation's discussion lives in `phoenix_kit_comments` anchored to
the **file** (`resource_type = "file"`, `resource_uuid = file_uuid`)
with `metadata.annotation_uuid` carrying the back-reference. This lets
annotation-rooted comments appear in the file's main comments thread
alongside non-annotated discussion. There is no `comment_uuid` column
on annotations — the relationship is one-directional from the comment
side, and a thread is created lazily when the first comment is posted.
"""
use Ecto.Schema
import Ecto.Changeset
@primary_key {:uuid, UUIDv7, autogenerate: true}
@foreign_key_type UUIDv7
@kinds ~w(rectangle circle polygon freehand callout text dimension line marker)
@type t :: %__MODULE__{
uuid: UUIDv7.t() | nil,
file_uuid: UUIDv7.t(),
creator_uuid: UUIDv7.t() | nil,
kind: String.t(),
geometry: map(),
style: map() | nil,
metadata: map() | nil,
position: integer(),
title: String.t() | nil,
inserted_at: DateTime.t() | nil,
updated_at: DateTime.t() | nil
}
schema "phoenix_kit_annotations" do
field :file_uuid, UUIDv7
field :creator_uuid, UUIDv7
field :kind, :string
field :geometry, :map
field :style, :map
field :metadata, :map
field :position, :integer, default: 0
field :title, :string
timestamps(type: :utc_datetime)
end
@cast_fields ~w(uuid file_uuid creator_uuid kind geometry style metadata position title)a
@required_fields ~w(file_uuid kind geometry)a
# Fields the storage adapter is allowed to accept from event payloads.
# `file_uuid` is set server-side from `target_uuid`, not by the client,
# so it's excluded here — the adapter's `create/1` puts it on the
# changeset after the whitelist filter. `creator_uuid` is set server-
# side from the actor (`adapter`'s `create/1` resolves it from the
# actor opts), so it's excluded for the same reason — a forged event
# payload shouldn't be able to claim authorship.
@adapter_writable_fields @cast_fields -- [:file_uuid, :creator_uuid]
@doc false
def changeset(annotation, attrs) do
annotation
|> cast(attrs, @cast_fields)
|> validate_required(@required_fields)
|> validate_inclusion(:kind, @kinds)
|> validate_length(:title, max: 200)
|> foreign_key_constraint(:file_uuid)
|> foreign_key_constraint(:creator_uuid)
|> check_constraint(:kind, name: :phoenix_kit_annotations_kind_check)
end
@doc "List of allowed kind strings."
def kinds, do: @kinds
@doc """
Fields the Etcher storage adapter is allowed to take from event
payloads. Single source of truth so the adapter's whitelist doesn't
drift from the schema's `@cast_fields`. `file_uuid` is excluded —
the adapter sets it server-side from the Etcher `target_uuid`.
"""
@spec adapter_writable_fields() :: [atom()]
def adapter_writable_fields, do: @adapter_writable_fields
end