PhoenixKitCRM.Migrations (PhoenixKitCRM v0.8.0)

Copy Markdown View Source

Module-owned versioned migrations for phoenix_kit_crm — the decentralized-migrations protocol core's mix phoenix_kit.update discovers via migration_module/0: current_version/0 + migrated_version_runtime/1 + idempotent up/1 + version-aware down/1. phoenix_kit_projects is the reference implementation; PhoenixKit.Modules.Legal.Migrations is the closest precedent — this chain is the same shape, scaled up to ten adopted tables instead of one.

What V01 is

V01 is an ADOPTION step for the nine pre-existing phoenix_kit_crm_* tables, plus one genuinely new column on a tenth:

  • on existing installs every table is already there (core's V135 / V138 / V148 / V151 / V152) — the CREATE TABLE IF NOT EXISTS / guarded DO $$ ... pg_constraint ... $$ blocks for those nine all find their targets already in place and are no-ops. The one ADD COLUMN IF NOT EXISTS statement in this chain is NOT one of those no-ops: it is the sole genuinely new object, phoenix_kit_crm_companies.user_uuid (nullable FK → phoenix_kit_users, ON DELETE SET NULL), which does not exist on any pre-chain install — along with its partial unique index idx_crm_companies_user_uuid and the crm_schema:1 marker. From then on this chain owns every adopted table's future shape;
  • on a hypothetical fresh install whose core baseline no longer creates these tables, the same statements create them — shape-identical to core's current live DDL, with core's exact table/constraint/index names (verified against lib/phoenix_kit/migrations/postgres/v135.ex, v138.ex, v148.ex, v151.ex, v152.ex in core).

Because V01 changes no shape of the nine adopted tables, core's ExpectedSchema manifest (which still audits those tables' shapes) stays accurate and no core release is required for this version. The first version that changes shape (V2+) must follow the excluded-object protocol described in the Legal chain's extraction report before it ships.

CREATE TABLE IF NOT EXISTS adoption is a presence check only — it does not repair a table whose columns/constraints have drifted from core's current shape on a host stuck before core V151/V152. That risk is contained, not eliminated: core's own migration chain always runs ahead of this one (mix phoenix_kit.update applies core's chain first), so by the time V01 runs, every adopted table is already at core's current shape on any host this chain actually executes against.

What down/1 is NOT

down/1 unstamps the version marker; it NEVER drops any of the ten tables. Nine are adopted (core-created on most installs; CRM data — contacts, companies, interactions — is not this chain's to destroy), and the tenth (phoenix_kit_crm_companies.user_uuid) is a link column a rollback should not delete either — the mirror it points at is a live user record. The ownership test pins this by asserting no statement this module can emit matches DROP or TRUNCATE.

The migrated version is tracked as a crm_schema:<N> COMMENT ON TABLE marker on phoenix_kit_crm_contacts (the marker convention from the projects/Legal chains). A marker-less table reads as version 0 — the core-baseline shape before this chain existed.

Summary

Functions

Rolls back to target (:version in opts). Never drops a table — see the moduledoc.

The SQL down/1 executes, as data (marker bookkeeping only).

The chain version currently applied in the database, read OUTSIDE a migration (the protocol shape core's update task calls — opts with :prefix): the crm_schema:<N> marker when present; a marker-less or foreign-comment table reads as 0 (core-baseline shape — V1 is purely adoptive, there is no pre-chain content to defend).

Applies every chain version up to current_version/0 (idempotent).

The SQL up/1 executes, as data — the testable single source. Every statement is idempotent (IF NOT EXISTS / guarded DO $$ block / COMMENT) so it is safe to replay on an install where core already created some or all of these tables, and on a fresh install with none of them.

The table carrying the crm_schema:<N> marker (auditor contract).

Functions

current_version()

@spec current_version() :: pos_integer()

down(opts \\ [])

Rolls back to target (:version in opts). Never drops a table — see the moduledoc.

down_statements(prefix \\ "public", target \\ 0)

@spec down_statements(String.t(), non_neg_integer()) :: [String.t()]

The SQL down/1 executes, as data (marker bookkeeping only).

migrated_version_runtime(opts \\ [])

The chain version currently applied in the database, read OUTSIDE a migration (the protocol shape core's update task calls — opts with :prefix): the crm_schema:<N> marker when present; a marker-less or foreign-comment table reads as 0 (core-baseline shape — V1 is purely adoptive, there is no pre-chain content to defend).

up(opts \\ [])

Applies every chain version up to current_version/0 (idempotent).

up_statements(prefix \\ "public")

@spec up_statements(String.t()) :: [String.t()]

The SQL up/1 executes, as data — the testable single source. Every statement is idempotent (IF NOT EXISTS / guarded DO $$ block / COMMENT) so it is safe to replay on an install where core already created some or all of these tables, and on a fresh install with none of them.

version_table()

@spec version_table() :: String.t()

The table carrying the crm_schema:<N> marker (auditor contract).