V202: storage libraries, the partition (phase 1 of
dev_docs/plans/2026-09-22-storage-libraries.md).
Every stored file belongs to exactly one library: a partition of the file store with its own members, settings and, later, its own storage. This version adds the partition and puts everything that exists into one system library, Media, so nothing changes for anyone:
phoenix_kit_storage_libraries—kind(system|user),owner_uuid(NULL for a system library),visibility(site|private),key_prefix(object-key prefix for NEW files; NULL keeps today's layout),slug(the library's URL name,/admin/media/library/<slug>; unique per owner, NULL for the default),settings,is_default,trashed_at. One row is seeded: Media, the default system library, under the fixed uuid00000000-0000-7000-8000-000000000001(Storage.Libraries.media_uuid/0).library_uuidonphoenix_kit_files,phoenix_kit_media_foldersandphoenix_kit_media_folder_links: NOT NULL,ON DELETE RESTRICT, and a column DEFAULT of Media's uuid. The default is what makes this invisible: existing rows read it without a table rewrite (a constant default is metadata-only), and every writer that does not name a library — core's and every module's — keeps landing in Media.UNIQUE (uuid, library_uuid)on files, the target of the folder-link FK(file_uuid, library_uuid): a link cannot cross libraries.- Folder names are unique per
(library_uuid, parent)instead of per parent:phoenix_kit_media_folders_name_parent_idxgains a leadinglibrary_uuid. With every folder in Media this is the same rule. phoenix_kit_files_library_capture_date_index, the capture-date index keyed by library. V200's user-keyed index stays for now.
Deliberately NOT here (the plan's later phases): user libraries and
members, any change to dedup, and the uploader FK moving to SET NULL —
that one changes what deleting a user does, so it ships with the phase
that needs it.
Locks
NOT NULL goes through CHECK … NOT VALID → VALIDATE → SET NOT NULL
→ drop the check (the V164 pattern): the validation scan holds only a
SHARE UPDATE EXCLUSIVE lock, and SET NOT NULL then skips its own scan.
FKs are added NOT VALID and validated separately for the same reason.
Indexes are plain builds, not CONCURRENTLY (see V193 for why), so writes
to phoenix_kit_files wait while they build.
Re-runnable.
Summary
Functions
Rolls V202 back: drops the three library_uuid columns, their keys and
indexes, restores the per-parent folder-name index and drops the libraries
table. Which library a file was in is lost (everything is Media until a
second library exists).