PhoenixKit.Migrations.Postgres.V182 (phoenix_kit v2.15.1)

Copy Markdown View Source

V182: removes PhoenixKit's own internal keys from the custom user field definitions.

What was wrong

custom_fields is one free-form JSONB column shared by two very different kinds of value: admin-defined profile fields, and per-user state written by features — the media browser's view mode, the etcher's colour palette and stroke defaults, notification preferences, the language a user picked.

Until every internal writer started passing ensure_definitions: false, the first write of any of those keys auto-registered a field definition for it, inferring the type from the value. infer_field_type/1 answers "text" for anything it does not recognise, so a map (etcher_line_params) and a list (etcher_colors, media_expanded_folders) each became an admin-editable text field. Nothing downstream can render either one: the admin user edit form hands the stored value to an <input>, where Phoenix.HTML.Safe raises on a map — a 500 on /admin/users/edit/:id for every affected user — and silently flattens a list into one concatenated run that the next save writes back over the stored value.

Why the code fix is not enough

The writers were fixed, so nothing registers these keys any more. The definitions they already wrote are another matter: they sit in the custom_user_fields_definitions settings row, and no code path has ever removed one. An install upgraded from a version that registered them carries the broken page forward even though the code that created the rows is gone. This migration is what clears them.

It removes only definitions whose key is one PhoenixKit itself writes (the list below, plus the notification_channel: family). Values in phoenix_kit_users.custom_fields are deliberately left untouched — the features that own them keep reading them; only the claim that they are admin-editable profile fields goes away.

A host-app or module key holding a map is not enumerable here, so it is handled in code instead: CustomFields.ensure_definitions_exist/1 no longer registers a structured value, and the edit form renders one read-only rather than into an input.

What it does not reach

Only value_json is rewritten. save_field_definitions/1 has always written the definitions there; the string value column is a read-side backward compatibility path only, and parsing an arbitrary varchar as JSON in SQL would abort the whole migration on one malformed row — a much worse trade than leaving a shape the code fixes already keep from crashing.

The settings cache

Settings caches this row in ETS, and a migration writes underneath that cache. Nothing here can invalidate it: the chain runs in its own OS process (mix phoenix_kit.update, a release migration step), not in the node serving requests. An install that migrates and then restarts — the ordinary deployment — never sees a stale list; one that migrates a live node keeps serving the old definitions until the entry is evicted or the node restarts. Nothing breaks in the meantime, because the page-level fixes that ship with this version render a structured value read-only either way.

down/1

Deleted definitions cannot be reconstructed: the setting held the only copy. Rolling back therefore only moves the version marker. That loses nothing an operator wants back — a re-registered definition is exactly the broken state this version exists to clear, and the values themselves were never touched.

Summary

Functions

down(opts)

up(opts)