The handful of things the application decides and tells Ithibati.
Ithibati reads what a schema is built from at compile time, because a table name and a field's
type are fixed when the module is compiled. Application.compile_env/3 makes that safe: Elixir
records the value it saw and refuses to boot against a different one, rather than running with a
table name nobody meant.
Ithibati reads what it is handed at runtime: the account schema and the repo. The application's modules compile after the dependencies they use.
A setting that is a rule rather than a value lives with the rule. Ithibati.Identity.Sessions
reads config :ithibati, session_validity:, and it is also what decides that a validity is a
count and a unit.
account!/1 is here for the same reason in reverse. What counts as an account is the
user_schema setting, so the guard that refuses everything else belongs beside the setting it
reads.
Summary
Functions
An account struct, refused unless it is the configured schema.
The invitation schema an application owns, as a module, or nil when it invites nobody.
The same, for a caller that cannot do anything without one.
The repo Ithibati reads and writes through.
A table Ithibati owns. table("keys") is "ithibati_keys" under the default prefix.
The prefix every table Ithibati owns carries.
The account schema an application owns, as a module.
The type of that table's primary key, and therefore of every user_id here.
Functions
An account struct, refused unless it is the configured schema.
Every function that takes an account goes through this rather than matching %{id: id}. With
users_key_type: :id, a struct from somewhere else whose id happens to be 1 would otherwise
be accepted as account 1. With :binary_id, the foreign key catches it only afterwards and in
the database's words.
The invitation schema an application owns, as a module, or nil when it invites nobody.
This setting is optional, unlike the account schema. Ithibati has to be told which schema holds invitations before it can answer "who may be invited", but an application with no invitations configures nothing and never reaches the module that reads this.
Ithibati checks the identifier against the account schema's here rather than reading it from there. A schema's fields are fixed when its module compiles, and which module is the account's is read at runtime, so you state the two separately and this is the first moment both are known.
The same, for a caller that cannot do anything without one.
invitation_schema/0 answers nil because the migration has to know when there is no
invitation table to index. Everything else needs the module, and says so here rather than each
caller saying it in its own words.
The repo Ithibati reads and writes through.
Ithibati reads this at runtime for the same reason it reads user_schema/0 at runtime: the
application's repo module compiles after the dependencies it uses. The rejected alternative was
a repo argument on every public function, which makes every call site louder for a value that
never varies.
A table Ithibati owns. table("keys") is "ithibati_keys" under the default prefix.
The prefix every table Ithibati owns carries.
The account schema an application owns, as a module.
Ithibati reads this at runtime, and not because a migration runs at runtime: that is true of the
compile-time settings too. The application's schema module compiles after the dependencies it
uses, so there is nothing to read out of it while Ithibati is compiling. compile_env would pin
an atom from which nothing was derived, and force a recompile that protects nothing.
The type of that table's primary key, and therefore of every user_id here.