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/ guardedDO $$ ... pg_constraint ... $$blocks for those nine all find their targets already in place and are no-ops. The oneADD COLUMN IF NOT EXISTSstatement 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 indexidx_crm_companies_user_uuidand thecrm_schema:1marker. 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.exin 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
@spec current_version() :: pos_integer()
Rolls back to target (:version in opts). Never drops a table — see the moduledoc.
@spec down_statements(String.t(), non_neg_integer()) :: [String.t()]
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.
@spec version_table() :: String.t()
The table carrying the crm_schema:<N> marker (auditor contract).