PhoenixKitBilling.Migrations (PhoenixKitBilling v0.10.0)

Copy Markdown View Source

Module-owned versioned migrations for phoenix_kit_billing — the decentralized-migrations protocol that 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_legal (over phoenix_kit_consent_logs) is the closest sibling example of this exact situation — a core-created table whose future shape a module chain adopts.

Ownership situation — read before touching

phoenix_kit_payment_provider_configs is one of core's V135 baseline tables. Nothing in this package's lib/ reads or writes it today — it is currently orphaned application-code-wise, though core still creates it (and can still roll it back on its own baseline down). Payment provider credentials this package actually reads and writes today live in phoenix_kit_settings, via PhoenixKitBilling.Providers — this version changes NONE of that.

V1 is purely an ADOPTION step:

  • on existing installs the table is already there (core V135), the CREATE TABLE IF NOT EXISTS finds it, and the only new object is the pkb_schema:1 marker — from then on this chain owns the table's future shape;
  • on a hypothetical future install whose core baseline no longer creates the table, the same statements create it — shape-identical to core's V135, with core's exact index and constraint names.

Because V1 changes no shape, core's ExpectedSchema manifest (which still audits the V135 shape of this table) stays accurate and NO core release is required for this version.

What down/1 is NOT

down/1 unstamps the version marker; it NEVER drops phoenix_kit_payment_provider_configs. The table is core-created, and rolling back this module's chain must not destroy it — only core's own baseline rollback does that. The same invariant holds for V2 below — down/1 never drops a core-created table, even one whose shape this chain now owns.

The migrated version is tracked as a pkb_schema:<N> COMMENT on phoenix_kit_payment_provider_configs (the marker convention from the projects/legal chains, namespaced). A marker-less table reads as version 0 — the core-baseline shape before this chain existed.

V2 — phoenix_kit_currencies gets a shape

phoenix_kit_currencies is likewise a core-created table (V31 baseline), and likewise untouched by V1 above (an unrelated table). V2 is this chain's first shape-CHANGING step, entirely on phoenix_kit_currencies:

  • a partial unique index phoenix_kit_currencies_default_uidx on (is_default) WHERE is_default — today uniqueness of the default currency is held only by the transaction in set_default_currency/1, not by the database: two is_default = true rows raise Ecto.MultipleResultsError out of get_default_currency/0 (Ecto.Repo.one/2). This index is also a prerequisite for a LIMIT-less WHERE is_default backfill a future chain runs against this table, so it must exist before that backfill runs, not merely by the time it finishes. A host can already BE in the two-default state the index forbids, so V2 demotes every default but one (lowest sort_order, then oldest) immediately before creating the index — otherwise CREATE UNIQUE INDEX aborts the whole chain on exactly those databases. That UPDATE is the one row-level write this chain makes to a core-created table, and it only repairs a state no reader can handle: get_default_currency/0 raises on it today.
  • rounding_rule character varying(16) NOT NULL DEFAULT 'exact' and rate_updated_at timestamp with time zone — both additions with no reader anywhere in this version; the default reproduces today's rounding behavior exactly, so nothing observable changes for any host that migrates to V2.

Both ride in the same chain version because this chain moves one version per module per release, not one version per column. down/1 to below V2 drops the index and both columns — never the table.

Summary

Functions

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

The SQL down/1 executes, as data. Below V2 this also drops the phoenix_kit_currencies index and columns V2 added — never the phoenix_kit_payment_provider_configs table itself.

The chain version currently applied in the database, read OUTSIDE a migration (the protocol shape core's update task calls — opts with :prefix): the pkb_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 target (:version in opts, default current_version/0); idempotent.

The SQL up/1 executes, as data — the testable single source. The ownership test parses these statements to prove that the object names are core's V135 names, that the CREATE TABLE stays shape-identical to core's ExpectedSchema manifest, and that nothing here can drop the table.

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

Functions

current_version()

@spec current_version() :: pos_integer()

down(opts \\ [])

Rolls back to target (:version in opts). Never drops the 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. Below V2 this also drops the phoenix_kit_currencies index and columns V2 added — never the phoenix_kit_payment_provider_configs table itself.

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 pkb_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 target (:version in opts, default current_version/0); idempotent.

up_statements(prefix \\ "public", target \\ 2)

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

The SQL up/1 executes, as data — the testable single source. The ownership test parses these statements to prove that the object names are core's V135 names, that the CREATE TABLE stays shape-identical to core's ExpectedSchema manifest, and that nothing here can drop the table.

target selects how much of the chain to emit (default current_version/0): 1 is the pure V135-adoption step on phoenix_kit_payment_provider_configs; 2 additionally shapes phoenix_kit_currencies (partial unique default-currency index, rounding_rule, rate_updated_at — see the moduledoc).

version_table()

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

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