Packages

phoenix_kit

1.7.118
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
phoenix_kit lib phoenix_kit migrations postgres v117.ex
Raw

lib/phoenix_kit/migrations/postgres/v117.ex

defmodule PhoenixKit.Migrations.Postgres.V117 do
@moduledoc """
V117: Document composition — template category, document sections, template presets.
Three schema changes for the document composition feature:
1. ALTER `phoenix_kit_doc_templates` — adds a nullable `category :: varchar`
column and an index on `(category)` for category-filtered queries.
2. CREATE `phoenix_kit_doc_document_sections` — join table between documents
and templates for multi-section composed documents. Each row represents one
template-backed section at a specific position within a document. Supports
per-section variable overrides (`variable_values`) and image configuration
(`image_params`). Positions are unique per document; deleting a document
cascades to its sections. Nullifying a template FK on delete allows the
section to survive template removal (content would need regeneration).
3. CREATE `phoenix_kit_doc_template_presets` — named, reusable compositions of
template sections. Presets are scoped via `scope_type` + `scope_id` (e.g.
`"organization"` + org uuid) and optionally categorized. The `sections`
JSONB column stores an ordered array of section descriptors
(`[%{template_uuid, position, variable_values, image_params}]`).
All operations use `IF NOT EXISTS` guards so re-running `up/1` on a
partially-applied schema is a no-op.
`down/1` is destructive for the `category` column: dropping it deletes any
values users have assigned. The two new tables drop cleanly (re-running
`up/1` recreates them empty), but column data is lost on rollback by
design — `Ecto.Migration`'s rollback contract has no way to preserve it.
"""
use Ecto.Migration
def up(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
# 1. Add category column + index to templates
execute("ALTER TABLE #{p}phoenix_kit_doc_templates ADD COLUMN IF NOT EXISTS category VARCHAR")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_doc_templates_category_index
ON #{p}phoenix_kit_doc_templates (category)
""")
# 2. Create document sections table
create_if_not_exists table(:phoenix_kit_doc_document_sections,
primary_key: false,
prefix: prefix
) do
add(:uuid, :uuid,
primary_key: true,
default: fragment("uuid_generate_v7()"),
null: false
)
add(
:document_uuid,
references(:phoenix_kit_doc_documents,
column: :uuid,
type: :uuid,
on_delete: :delete_all,
prefix: prefix
),
null: false
)
add(
:template_uuid,
references(:phoenix_kit_doc_templates,
column: :uuid,
type: :uuid,
on_delete: :nilify_all,
prefix: prefix
)
)
add(:position, :integer, null: false)
add(:variable_values, :map, null: false, default: %{})
add(:image_params, :map, null: false, default: %{})
add(:created_by_uuid, :uuid, null: false)
timestamps(type: :utc_datetime)
end
create_if_not_exists(
unique_index(:phoenix_kit_doc_document_sections, [:document_uuid, :position],
name: :phoenix_kit_doc_document_sections_doc_position_index,
prefix: prefix
)
)
create_if_not_exists(
index(:phoenix_kit_doc_document_sections, [:document_uuid], prefix: prefix)
)
# 3. Create template presets table
# `sections` is a JSONB array (default '[]'::jsonb), which Ecto's
# `:map` DSL can't express — use raw SQL for that column's default.
execute("""
CREATE TABLE IF NOT EXISTS #{p}phoenix_kit_doc_template_presets (
uuid UUID PRIMARY KEY DEFAULT uuid_generate_v7() NOT NULL,
name VARCHAR NOT NULL,
description TEXT,
category VARCHAR,
scope_type VARCHAR,
scope_id VARCHAR,
sections JSONB NOT NULL DEFAULT '[]'::jsonb,
created_by_uuid UUID NOT NULL,
inserted_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL DEFAULT NOW()
)
""")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_doc_template_presets_scope_index
ON #{p}phoenix_kit_doc_template_presets (scope_type, scope_id, category)
""")
execute("COMMENT ON TABLE #{p}phoenix_kit IS '117'")
end
def down(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
drop_if_exists(table(:phoenix_kit_doc_template_presets, prefix: prefix))
drop_if_exists(table(:phoenix_kit_doc_document_sections, prefix: prefix))
execute("DROP INDEX IF EXISTS #{p}phoenix_kit_doc_templates_category_index")
execute("ALTER TABLE #{p}phoenix_kit_doc_templates DROP COLUMN IF EXISTS category")
execute("COMMENT ON TABLE #{p}phoenix_kit IS '116'")
end
defp prefix_str("public"), do: "public."
defp prefix_str(prefix), do: "#{prefix}."
end