PhoenixKit.Migrations.Postgres.V114 (phoenix_kit v1.7.115)

Copy Markdown View Source

V114: Switch integration storage rows to uuid-only keys.

Before V113, each integration row in phoenix_kit_settings had a composite key of the shape integration:<provider>:<name> (e.g. "integration:google:default"). That key construction baked the human-chosen name into the row's identity, which forced two unfortunate constraints:

  • Names had to match a strict regex ([a-zA-Z0-9][a-zA-Z0-9\-_]*) because they were path-style segments in the key column.
  • Names had to be unique per provider — the key column has a unique index, so two integration:openrouter:work rows would collide at insert time.

Both restrictions were storage-layout artifacts, not product decisions. Operators wanted "My Company Drive" and a second OpenRouter account also called "personal" without the system pushing back.

V114 lifts both by collapsing the storage key to just the row's UUID. The module column (already set to "integrations" for every integration row via @settings_module) becomes the sole row-class discriminator, and provider + name live purely in value_json.

Migration steps

  1. For every row in phoenix_kit_settings whose key starts with integration::

    a. Parse provider and name from the key (handling the legacy V0 shape integration:google without a name as provider=google, name="default"). b. Ensure value_json has "provider" and "name" populated (idempotent — leaves correct values alone). c. Ensure module = 'integrations' (was already set for integrations created via add_connection/3, but legacy rows pre-@settings_module may have it NULL). d. Rewrite the key column to the row's uuid.

  2. Stamp the table comment with '114'.

All work happens in a single transaction (handled by the outer migrator). Per-row updates use only the row's uuid for routing — the new shape is key = uuid, so the row's PK is what we touch.

Down migration

The down path is best-effort: duplicate (provider, name) pairs cannot be represented in the old shape, so on a name collision we suffix -<8-char-tail> to keep the rewrite well-defined. The tail is taken from UUIDv7's random segment (substring(uuid::text from 25 for 8)), not the leading timestamp prefix — multiple rows inserted in the same millisecond would otherwise produce identical prefixes and collide on the supposedly-unique suffixed key. Round-trip down → up therefore changes those names by a suffix. Acceptable for a one-shot data migration that operators rarely roll back.

Summary

Functions

down(opts)

up(opts)