# `Mediate`
[🔗](https://github.com/mrmeku/mediate/blob/v0.1.0/lib/mediate.ex#L1)

The port: the one place an application asks whether a subject can perform
an operation on an object. It is also the contract every adapter
implements. The words are NIST SP 800-162's: subject, object, operation,
and environment.

- `authorize/4` when the call reaches the repo: it answers the decision
  the seam accepts under `mediate:`.
- `check/4` when a branch needs a yes or no and reaches no repo.
- `scope/4` when a query covers a whole type: it answers a `dynamic` the
  query carries, which can only narrow, and a decision whose object id is
  `nil`.
- `review/5` when a reviewer asks who can do what today: one `scope` per
  subject under the reviewer's operation id, with `nil` ids alike.

This module is the top-layer boundary. Everything under `Mediate` that is
not `Mediate.Test` belongs to it. It can reach `Ecto` and `NimbleOptions`.
It reaches nothing from `ecto_sql` or `postgrex`, because the port decides
and does not query.

# `environment`

```elixir
@type environment() :: %{:now =&gt; DateTime.t(), optional(atom()) =&gt; term()}
```

Under what conditions the subject asks: the facts only the caller knows,
by name, with `now` from the configured clock beside them. The port
stamps `now`, so a decider reads the moment of the request from the
environment rather than from a clock of its own.

# `object`

```elixir
@type object() :: {atom(), Mediate.Id.t() | nil}
```

What the subject asks about: an object type and an id. A decision over a
whole type, which `scope/4` makes, carries `nil` for the id.

# `subject`

```elixir
@type subject() :: {subject_kind(), Mediate.Id.t()}
```

Who asks: a kind and an account id. The kind travels with every decision
record. The port refuses a kind it does not know.

# `subject_kind`

```elixir
@type subject_kind() :: :user | :non_person_entity | :privileged
```

A person, software that acts alone, or a person who can change the system.

# `authorize`

```elixir
@spec authorize(subject(), atom(), object(), Mediate.Port.options()) ::
  {:ok, Mediate.Decision.t()} | {:error, Mediate.Error.t()}
```

Decide for one object: the decision to hand the seam, or why not.

# `check`

```elixir
@spec check(subject(), atom(), object(), Mediate.Port.options()) :: boolean()
```

The verdict alone for one object.

# `review`

```elixir
@spec review(subject(), [subject()], atom(), atom(), Mediate.Port.options()) ::
  Mediate.Port.reviewed()
```

The review a reviewer asks: a rule and a decision per subject over an object type.

# `scope`

```elixir
@spec scope(subject(), atom(), atom(), Mediate.Port.options()) ::
  {Ecto.Query.dynamic_expr(), Mediate.Decision.t()}
```

The rule a row must satisfy and the decision the query carries.

---

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