# `PhoenixKit.Install.StatusReport`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v2.13.7/lib/phoenix_kit/install/status_report.ex#L1)

Decides what `mix phoenix_kit.status` should tell the operator to do next.

Extracted from the status task for the same reason `PhoenixKit.Install.StatusTree`
was: it is pure decision logic that could otherwise only be observed by
pointing the task at a live database in each of five states, so in practice
it went unverified.

The task keeps the ANSI styling; this module returns plain data.

## Why the wording matters

`status` compares the schema in the database against the version compiled
into the **running release** (`PhoenixKit.Migrations.Postgres.current_version/0`).
It never asks Hex what exists. So it can never report "a newer PhoenixKit is
available" — it can only report that the database disagrees with the code
already querying it, which surfaces as runtime errors on whatever the newer
version added.

That is why nothing here says "update available": there is no optional
upgrade being offered, only a mismatch to reconcile.

# `action`

```elixir
@type action() ::
  {:install, String.t()}
  | {:fix_connection, String.t()}
  | {:fix_version_comment, String.t()}
  | {:update, String.t(), [String.t()]}
  | {:check_modules, [String.t()]}
  | {:ready, String.t()}
```

What the operator should do.

  * `{:install, command}` — PhoenixKit has never been installed
  * `{:fix_connection, message}` — the database could not be reached
  * `{:fix_version_comment, message}` — installed, but the version comment is
    missing or unreadable; the fix is a restamp by hand, not an update
  * `{:update, command, reasons}` — schema behind the code; `reasons` says how
  * `{:check_modules, names}` — a module's version could not be read
  * `{:ready, message}` — database and code agree

# `command`

```elixir
@spec command(action()) :: String.t() | nil
```

The command an action asks for, or `nil` when it isn't a command.

    iex> PhoenixKit.Install.StatusReport.command({:update, "mix phoenix_kit.update", []})
    "mix phoenix_kit.update"

# `describe`

```elixir
@spec describe(action()) :: String.t()
```

Plain-text rendering, no ANSI — what the task colours and prints.

    iex> PhoenixKit.Install.StatusReport.describe({:ready, "Ready"})
    "Ready"

    iex> PhoenixKit.Install.StatusReport.describe(
    ...>   {:update, "mix phoenix_kit.update", ["database is V159, code expects V160"]}
    ...> )
    "mix phoenix_kit.update — database is V159, code expects V160"

# `next_action`

```elixir
@spec next_action(tuple(), [map()] | :not_queried, String.t()) :: action()
```

Picks the action for a given installation status and module list.

`modules` is a `PhoenixKit.Migrations.Modules.list/1` result, or
`:not_queried` when the database was unreachable and nothing was asked.

## Examples

    iex> alias PhoenixKit.Install.StatusReport
    iex> StatusReport.next_action({:up_to_date, 159}, [], "public")
    {:ready, "Ready"}

    iex> alias PhoenixKit.Install.StatusReport
    iex> StatusReport.next_action({:needs_update, 159, 160}, [], "public")
    {:update, "mix phoenix_kit.update", ["database is V159, code expects V160"]}

# `update_command`

```elixir
@spec update_command(String.t()) :: String.t()
```

The `mix phoenix_kit.update` invocation for a prefix.

---

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