# `PhoenixKit.Migrations.Postgres.V123`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v1.7.165/lib/phoenix_kit/migrations/postgres/v123.ex#L1)

V123: Catalogue folders — a dedicated nesting layer for organizing
catalogues on the admin catalogue index.

Creates `phoenix_kit_cat_folders` (self-nesting via `parent_uuid`) and
adds a nullable `folder_uuid` FK to `phoenix_kit_cat_catalogues` so a
catalogue can live inside a folder (NULL = unfiled / root). These folders
are their own thing — unrelated to the media-folder system
(`phoenix_kit_media_folders`) — and never appear in the media browser.

Each folder carries `position` (manual order within its parent), `status`
(soft-delete sentinel, parity with catalogues/categories), and a `data`
JSONB blob for future metadata. `parent_uuid` is `ON DELETE :nilify_all`
so a hard-deleted parent orphan-promotes its children to root rather than
cascading; `phoenix_kit_cat_catalogues.folder_uuid` is `ON DELETE SET NULL`
for the same reason (removing a folder unfiles its catalogues, never
deletes them).

Also drops the global unique index on `phoenix_kit_cat_items.sku`
(created in V87): item SKUs are **not** unique by design — the same SKU
can legitimately appear on multiple items, even within one catalogue —
so the partial unique index (`WHERE sku IS NOT NULL`) was an
over-constraint that raised on duplicate SKUs. `down/1` restores it.

All operations are idempotent (`create_if_not_exists` / `IF NOT EXISTS`
guards) so re-running on a partially-applied schema is a no-op.

# `down`

# `up`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
