PhoenixKit.Migrations.Postgres.V125 (phoenix_kit v1.7.138)

Copy Markdown View Source

V125: Project workflow statuses (entities-backed, cement-at-start).

Adds a user-defined "workflow status" capability to phoenix_kit_projects, orthogonal to the computed Project.derived_status/2 lifecycle and the archived_at soft-hide. The status vocabulary is configured through the optional phoenix_kit_entities module (the "catalog"), and snapshotted into local projects-owned storage when a project starts (the "cement").

Two layers:

1. Catalog reference on phoenix_kit_projects

Two nullable columns let a project (or template) point at the catalog list it draws statuses from, and remember the currently-selected status:

  • status_entity_uuid UUID → FK phoenix_kit_entities(uuid) ON DELETE SET NULL — which entity (status vocabulary) this project/template uses. NULL = the shared default list. ON DELETE SET NULL so deleting a catalog entity degrades the project to the shared default, never cascades.
  • current_status_slug VARCHAR(255) — the selected status, addressed by its stable slug. The slug is the cross-boundary identity: pre-start it resolves against the live catalog rows; post-start against the cemented local rows below. Storing a slug (not a row UUID) avoids a foreign key whose target table changes at the cement boundary.

A partial index on (status_entity_uuid) WHERE status_entity_uuid IS NOT NULL backs the "Used by N projects" reverse-reference count and grouped lookups.

2. Local cemented copy: phoenix_kit_project_statuses

When a project starts, its chosen catalog statuses are copied into this table and the running project uses its own frozen, independently-editable copy — later edits to the catalog entity do NOT retroactively rewrite live projects. Mirrors the module's existing template→instance philosophy (an Assignment copies its Task template's fields at creation, then edits independently).

  • project_uuid → FK phoenix_kit_projects(uuid) ON DELETE CASCADE — the cemented statuses die with the project.
  • label / slug / position — the snapshotted status (primary-language label + stable slug + order).
  • data JSONB — per-status attributes (e.g. {"color": "#34d399"}). JSONB so colour and any future fields ride along without a migration.
  • translations JSONB — secondary-language label overrides, workspace shape %{"es-ES" => %{"label" => "…"}} (mirrors Project/Task/Assignment). Empty today; ready for status-label i18n.
  • source_entity_data_uuid UUID — provenance pointer back to the catalog phoenix_kit_entity_data row it was copied from. Intentionally NOT a foreign key: phoenix_kit_entities is an optional module, the cemented row must survive the catalog row being deleted, and the value is informational.

Unique (project_uuid, slug) so a project's cemented statuses are slug-addressable (matching current_status_slug); index on (project_uuid) for list reads.

3. External identifier on phoenix_kit_projects

A single nullable column lets a project be tied to a record in some external system, with no UI of its own (set programmatically):

  • external_id VARCHAR(255) — an arbitrary external reference. Deliberately a free-form string so it can hold a numeric id, a UUID, or a slug from whatever the project is being linked to. Not unique (several projects may reference the same external thing) and not a foreign key (the target lives outside this database). A partial index on (external_id) WHERE external_id IS NOT NULL backs lookup-by-external-id without indexing the common NULL case.

Idempotent: re-running is a no-op once the table + columns are in the post-V125 shape.

Summary

Functions

down(opts)

up(opts)