# `Ithibati.Schema.User`
[🔗](https://github.com/oliverandrich/ithibati/blob/v0.6.2/lib/ithibati/schema/user.ex#L1)

Adds an identifier and credential associations to an application-owned account schema.

    defmodule MyApp.Accounts.User do
      use Ecto.Schema
      alias Ithibati.Schema.Identifier
      alias Ithibati.Schema.User

      use User, identifier: :email, format: Identifier.email_format()

      import Ecto.Changeset

      schema "users" do
        ithibati_account()

        field :name, :string
        timestamps(type: :utc_datetime_usec)
      end

      def changeset(user, attrs) do
        user
        |> identifier_changeset(attrs)
        |> cast(attrs, [:name])
      end
    end

## Options

  * `:identifier` — required literal atom naming the account's identifier field.
  * `:format` — optional regex checked after normalization. See
    `Ithibati.Schema.Identifier.username_format/0` and `Ithibati.Schema.Identifier.email_format/0`.
  * `:format_message` — custom format-error message; requires `:format`.
    Defaults to Ecto's `"has invalid format"` message.
  * `:constraint_name` — optional identifier-index name. Used both when creating the index
    and when translating its constraint error into a changeset error.
  * `:unique_index` — defaults to `true`. Set `false` when the application creates the index;
    Ithibati still verifies that it guarantees uniqueness of the identifier column alone.

Except for `:identifier`, values can be module attributes declared before `use`. Explicit
`nil` values are rejected. See [Configuration and schemas](configuration.md) for examples.

## Generated fields and functions

Call `ithibati_account/0` inside the schema block. It declares the identifier as `:string` and
adds `:passkeys`, `:recovery_codes` and `:sessions` associations.

The macro generates `identifier_changeset/2`, the overridable `passkey_display_name/1`, and
`__ithibati__/1` for schema metadata. Identifier validation trims and lowercases the value,
requires it, checks any supplied format and limits it to 254 graphemes.

Compilation fails if the schema omits `ithibati_account/0` or defines its own
`identifier_changeset/2` or `__ithibati__/1`. The application creates the database column;
`Ithibati.Migration` creates or checks its unique index.

# `account_schema?`

Returns whether the module is loaded and exports the account-schema metadata function.

Use this predicate instead of checking Ithibati's generated marker directly. It identifies
the schema integration; it does not validate the database table or its indexes.

# `credential_user`

Returns `%{name: identifier, display_name: display_name}` for WebAuthn registration.

For an account using `Ithibati.Schema.User`, the identifier comes from its declared field.
The display name comes from `passkey_display_name/1`, falling back to the identifier when
that function returns `nil` or `false`.

For a string identifier, both values are that string. This function does not normalize it.
An account struct without the schema integration raises `ArgumentError`.

# `identifier_taken?`

Returns whether the changeset contains a unique-constraint error on the identifier field.

Use this after a failed repo insert or update to distinguish an identifier collision from
format errors or uniqueness errors on other application fields. The changeset must belong
to a schema using `Ithibati.Schema.User`; otherwise this raises `ArgumentError`.

A changeset that has not reached the database has no constraint error and returns `false`.
The predicate checks the field's error metadata; it does not perform a uniqueness query or
validate the index definition.

# `ithibati_account`
*macro* 

Declares the identifier field and the associations Ithibati needs. Call it inside your
`schema` block, in a module that has `use Ithibati.Schema.User` above it.

---

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