Packages
phoenix_kit
1.7.21
1.7.208
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/modules/storage/schemas/file.ex
defmodule PhoenixKit.Modules.Storage.File do
@moduledoc """
Schema for original file uploads.
Represents the original uploaded file with metadata. Each file can have multiple
instances (variants) like thumbnails, resizes, or video quality variants.
## File Types
- **image** - JPEG, PNG, WebP, GIF, HEIC (scalable)
- **video** - MP4, WebM, MOV, AVI, MKV (scalable)
- **document** - PDF, DOC, DOCX, TXT, MD (non-scalable)
- **archive** - ZIP, RAR, 7Z, TAR, GZ (non-scalable)
## Status Flow
- `processing` - File is being processed (variants being generated)
- `active` - File is ready and available
- `failed` - Processing failed
## Fields
- `original_file_name` - User's original filename
- `file_name` - System filename (uuid_v7-original.ext)
- `mime_type` - MIME type (image/jpeg, video/mp4, etc.)
- `file_type` - High-level type (image, video, document, archive)
- `ext` - File extension (jpg, mp4, pdf, etc.)
- `file_checksum` - SHA256 hash of file content for integrity verification
- `user_file_checksum` - SHA256 hash of (user_id + file_checksum) for per-user deduplication
- `size` - File size in bytes
- `width` - Image/video width in pixels (nullable)
- `height` - Image/video height in pixels (nullable)
- `duration` - Video duration in seconds (nullable)
- `status` - Processing status
- `metadata` - JSONB with EXIF, codec info, etc.
- `user_id` - Owner of the file
## Examples
# Image file
%File{
id: "018e3c4a-9f6b-7890-abcd-ef1234567890",
original_file_name: "profile.jpg",
file_name: "018e3c4a-9f6b-7890-original.jpg",
mime_type: "image/jpeg",
file_type: "image",
ext: "jpg",
file_checksum: "abc123def456...",
user_file_checksum: "xyz789ghi012...",
size: 524_288, # 512 KB
width: 2000,
height: 2000,
status: "active",
metadata: %{"camera" => "Canon EOS"},
user_id: "..."
}
# Video file
%File{
original_file_name: "intro.mp4",
file_name: "018e3c4a-9f6b-7890-original.mp4",
mime_type: "video/mp4",
file_type: "video",
ext: "mp4",
file_checksum: "def456ghi789...",
user_file_checksum: "mno345pqr678...",
size: 10_485_760, # 10 MB
width: 1920,
height: 1080,
duration: 30, # 30 seconds
status: "processing",
metadata: %{"codec" => "h264"}
}
# Document file
%File{
original_file_name: "report.pdf",
file_name: "018e3c4a-9f6b-7890-original.pdf",
mime_type: "application/pdf",
file_type: "document",
ext: "pdf",
file_checksum: "ghi789jkl012...",
user_file_checksum: "stu901vwx234...",
size: 2_097_152, # 2 MB
status: "active"
}
"""
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, UUIDv7, autogenerate: true}
@foreign_key_type UUIDv7
@type t :: %__MODULE__{
id: UUIDv7.t() | nil,
original_file_name: String.t(),
file_name: String.t(),
file_path: String.t() | nil,
mime_type: String.t(),
file_type: String.t(),
ext: String.t(),
file_checksum: String.t(),
user_file_checksum: String.t(),
size: integer(),
width: integer() | nil,
height: integer() | nil,
duration: integer() | nil,
status: String.t(),
metadata: map() | nil,
user_id: integer() | nil,
user: PhoenixKit.Users.Auth.User.t() | Ecto.Association.NotLoaded.t(),
instances:
[PhoenixKit.Modules.Storage.FileInstance.t()] | Ecto.Association.NotLoaded.t(),
inserted_at: NaiveDateTime.t() | nil,
updated_at: NaiveDateTime.t() | nil
}
schema "phoenix_kit_files" do
field :original_file_name, :string
field :file_name, :string
field :file_path, :string
field :mime_type, :string
field :file_type, :string
field :ext, :string
field :file_checksum, :string
field :user_file_checksum, :string
field :size, :integer
field :width, :integer
field :height, :integer
field :duration, :integer
field :status, :string, default: "processing"
field :metadata, :map
belongs_to :user, PhoenixKit.Users.Auth.User, type: :integer
has_many :instances, PhoenixKit.Modules.Storage.FileInstance
timestamps(type: :naive_datetime)
end
@doc """
Changeset for creating or updating a file.
## Required Fields
- `original_file_name`
- `file_name`
- `mime_type`
- `file_type` (must be: "image", "video", "document", "archive")
- `ext`
- `file_checksum`
- `user_file_checksum`
- `size`
- `user_id`
## Validation Rules
- File type must be valid
- Status must be valid (processing, active, failed)
- Size must be positive
- Width/height must be positive (if provided)
- Duration must be positive (if provided)
"""
def changeset(file, attrs) do
file
|> cast(attrs, [
:original_file_name,
:file_name,
:file_path,
:mime_type,
:file_type,
:ext,
:file_checksum,
:user_file_checksum,
:size,
:width,
:height,
:duration,
:status,
:metadata,
:user_id
])
|> validate_required([
:original_file_name,
:file_name,
:mime_type,
:file_type,
:ext,
:file_checksum,
:user_file_checksum,
:size,
:user_id
])
|> validate_inclusion(:file_type, ["image", "video", "document", "archive"])
|> validate_inclusion(:status, ["processing", "active", "failed"])
|> validate_number(:size, greater_than: 0)
|> validate_number(:width, greater_than: 0)
|> validate_number(:height, greater_than: 0)
|> validate_number(:duration, greater_than: 0)
|> foreign_key_constraint(:user_id)
end
@doc """
Returns whether this file type supports variant generation (scalable).
"""
def scalable?(%__MODULE__{file_type: file_type}) when file_type in ["image", "video"],
do: true
def scalable?(_), do: false
@doc """
Returns whether this file is an image.
"""
def image?(%__MODULE__{file_type: "image"}), do: true
def image?(_), do: false
@doc """
Returns whether this file is a video.
"""
def video?(%__MODULE__{file_type: "video"}), do: true
def video?(_), do: false
@doc """
Returns whether this file is a document.
"""
def document?(%__MODULE__{file_type: "document"}), do: true
def document?(_), do: false
@doc """
Returns whether this file is an archive.
"""
def archive?(%__MODULE__{file_type: "archive"}), do: true
def archive?(_), do: false
end