# `Macaw.Host.Ctl.Description`
[🔗](https://github.com/dcoai/macaw_host/blob/v0.1.4/lib/macaw/host/ctl/description.ex#L1)

The app description `<app>-ctl` is generated from: the `:ctl` key of the
app's `mix.exs` project config, checked once here so the templates can
trust every value.

    ctl: [
      name: "astex",
      image: "gitlab.conet.yarina.org:5005/dco-tek/astex",
      env_prefix: "ASTEX",
      release: "Astex.Release",
      uid: "2060:2060",
      port: 4000
    ]

Required:

| Key | What it is |
|---|---|
| `:name` | the app's name: the script is `<name>-ctl`, its settings `<name>.conf` |
| `:image` | the image, without a tag |
| `:env_prefix` | the release protocol's prefix: `<PREFIX>_CTL_ARGS` and the like |
| `:release` | the release module whose `config/0` and `status/0` the script calls |
| `:uid` | the container user's fixed `"uid:gid"` |
| `:port` | the port the app listens on in the container, and the default PORT |

Optional, with their defaults:

| Key | Default | What it is |
|---|---|---|
| `:title` | the name, capitalized | the app's name in prose |
| `:otp_app` | the project's `:app` | names the release's start script |
| `:release_bin` | `"/app/bin/<otp_app>"` | the release's start script in the image |
| `:tag` | `"latest"` | the default TAG |
| `:network` | `"bridge"` | the default NETWORK; `"host"` shares the host's |
| `:container_data` | `"/data"` | where the data volume is mounted |
| `:docker_run_args` | `"--restart unless-stopped"` | the default DOCKER_RUN_ARGS |
| `:stop_timeout` | `30` | seconds `stop` gives the app |
| `:data_home` | `"/srv/<name>"` | the data directory `init` offers |
| `:seeds` | `[]` | app config `init` seeds: `[tz: :timezone, phx_host: :hostname, phx_scheme: "http"]` |
| `:migrate_keys` | `[]` | `{old key, config key, old default}` that `init --migrate` carries from `<name>-env` |
| `:settings` | `[]` | the app's own host settings: `{"KEY", "default", "help"}` |
| `:app_commands` | `"ctl/app_commands.ex"` | the file defining `Ctl.AppCommands`, or `false` for none |
| `:output` | `"container/<name>-ctl"` | where the script is written |

Any other key is an error: a misspelled optional key silently taking its
default is the bug this refuses.

# `t`

```elixir
@type t() :: %{required(atom()) =&gt; term()}
```

# `new`

```elixir
@spec new(keyword() | map() | nil, atom() | String.t() | nil) ::
  {:ok, t()} | {:error, String.t()}
```

The checked description, with every default filled in and the values the
templates derive (`:script`, `:ids`, the full `:settings`): `{:ok, map}`,
or `{:error, message}` naming the first fault. `otp_app` is the project's
`:app`, the default for `:otp_app`.

# `new!`

```elixir
@spec new!(keyword() | map(), atom() | String.t() | nil) :: t()
```

As `new/2`, raising `ArgumentError` with the message.

---

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