# `Ithibati.Migration`
[🔗](https://github.com/oliverandrich/ithibati/blob/v0.6.2/lib/ithibati/migration.ex#L1)

Creates or removes Ithibati's versioned database schema from an application migration.

    defmodule MyApp.Repo.Migrations.AddIthibati do
      use Ecto.Migration

      def up, do: Ithibati.Migration.up(version: 2)
      def down, do: Ithibati.Migration.down(version: 2)
    end

Use explicit `up/0` and `down/0`, not `change/0`: catalogue checks flush queued DDL and
cannot be reversed automatically by Ecto.

Create the account table and identifier column first. If invitations are configured, their
table must also exist when `up/1` validates the application tables.

## Options

  * `:version` — required target schema version supported by the installed release.
  * `:from` — existing version, exclusive; defaults to `0`. A later upgrade uses a new
    application migration with the original version as `:from`.

Keep versions pinned in applied migrations. `current_version/0` reports the newest version
this release supports. `down/1` removes the changes covered by the matching range.

Version 3 adds the operator-code digest table used by protected first claims.
Table names and account foreign-key types come from the configured schemas. `up/1` verifies
required columns, key types and unique indexes before creating its tables. The application
continues to own its account and invitation tables.

[Getting started](getting_started.md#4-the-migration) shows initial setup;
[Configuration and schemas](configuration.md#migrations) covers index ownership and upgrades.

# `current_version`

The newest schema version this release knows.

# `down`

Removes what the matching `up/1` built.

# `invitation_columns`

Adds the required invitation columns inside an application's `create table` block.

The configured invitation schema supplies the identifier field name. `version:` is required
and must name a supported schema version.

    create table(:invitations) do
      Ithibati.Migration.invitation_columns(version: 1)

      add :role, :string
      timestamps(type: :utc_datetime_usec)
    end

Declare `field :role, Ecto.Enum, values: [:admin, :author]` in the application's Ecto schema
when using that string column as an enum.

The helper adds:

  * the identifier, `:string` by default, `null: false`
  * `:token_hash`, `:binary`, `null: false`
  * `:expires_at`, `:utc_datetime_usec`, `null: false`
  * `:accepted_at`, `:utc_datetime_usec`, nullable for pending invitations

The schema's virtual `:token` is not stored. Add application-specific fields and timestamps
separately. `:type` overrides only the identifier's database type and is passed to
`Ecto.Migration.add/3`. For `type: :citext`, install the PostgreSQL extension first.
See the [invitation guide](invitations.md#2-configure-and-migrate) for setup and type choices.
`up/1` also validates existing invitation tables.

This function does not create the token index; use `invitation_index/1` when adding invitations
after Ithibati's initial migration.

# `invitation_index`

Creates or verifies the invitation table's unique `token_hash` index.

Use this when adding invitations after Ithibati's initial migration has already run.
`version:` is required, and the configured invitation table must exist.

    defmodule MyApp.Repo.Migrations.AddInvitations do
      use Ecto.Migration

      def change do
        create table(:invitations) do
          Ithibati.Migration.invitation_columns(version: 1)
          timestamps(type: :utc_datetime_usec)
        end

        Ithibati.Migration.invitation_index(version: 1)
      end
    end

`up/1` also maintains this index. Both paths create it only when absent and verify its
uniqueness. If the schema uses `unique_index: false`, the application must create the index;
this call checks it without creating it.

# `invitation_inviter_column`

Adds the inviter column to an invitation table that was created before version 4.

For an application that turned invitations on earlier. A table created with
`invitation_columns(version: 4)` already has it. The column type follows `users_key_type`,
which is why this exists rather than a line in the guide: an application that guessed
`:binary_id` against a `:id` account table would only find out at the first invitation.

    defmodule MyApp.Repo.Migrations.AddInvitedBy do
      use Ecto.Migration

      def change do
        alter table(:invitations) do
          Ithibati.Migration.invitation_inviter_column(version: 4)
        end
      end
    end

Nullable, and Ithibati writes no foreign key: rows written before the column existed have no
inviter, and whether one is enforced is the application's to decide about its own table.

# `up`

Builds Ithibati's tables. See the module documentation for options.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
