# `PhoenixKit.Config`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v2.14.2/lib/phoenix_kit/config/config.ex#L1)

Configuration management system for PhoenixKit.

This module provides a centralized way to manage PhoenixKit configuration
with type-safe getter functions for different data types.

## Usage

    # Get all configuration
    config = PhoenixKit.Config.get_all()

    # Get specific values
    repo = PhoenixKit.Config.get(:repo)
    mailer = PhoenixKit.Config.get(:mailer, PhoenixKit.Mailer)

    # Type-safe getters
    options = PhoenixKit.Config.get_list(:options, [])
    enabled = PhoenixKit.Config.get_boolean(:enabled, false)
    host = PhoenixKit.Config.get_string(:host, "localhost")

## Configuration Keys

- `:repo` - Ecto repository module (required)
- `:mailer` - Mailer module for sending emails
- `:host` - Application hostname
- `:port` - Application port
- `:layout_module` - Custom layout configuration
- `:from_email` - Default sender email address for notifications
- `:from_name` - Default sender name for notifications (default: "PhoenixKit")
- `:users_module` - User schema module (default: PhoenixKit.Users.Auth.User)
- `:project_title` - Project/application name displayed in dashboard header (default: "PhoenixKit")
- `:project_title_suffix` - Suffix appended to title (default: "Dashboard", set to "" to remove)
- `:project_logo` - URL or path to logo image for dashboard header (optional, use SVG with currentColor for theme support)
- `:project_icon` - Heroicon name when no logo image (default: "hero-home")
- `:project_logo_height` - Logo height CSS class (default: "h-8")
- `:project_logo_class` - Additional CSS classes for logo image (optional)
- `:project_home_url` - URL the logo links to (default: "/", use "~/" prefix for URL prefix)
- `:show_title_with_logo` - Show title text alongside logo (default: true)
- `:dashboard_themes` - Themes available in dashboard theme switcher (default: `:all`)
- `:dashboard_subtab_style` - Default styling for subtabs (indent, icon_size, text_size, animation)
- `:admin_path` - Top-level URL segment for the admin area (default: "/admin").
  See `get_admin_path/0` — compile-time, `config.exs` only.
- `:user_dashboard_enabled` - Enable/disable user dashboard (default: true)
- `:user_dashboard_tabs` - List of custom tabs for the user dashboard sidebar
- `:user_dashboard_tab_groups` - List of tab groups for organizing dashboard tabs
- `:dashboard_presence` - Presence tracking settings for dashboard tabs
- `:admin_dashboard_categories` - List of custom admin dashboard categories with subsections

## User Dashboard Tabs

Configure custom tabs in the user dashboard sidebar:

    config :phoenix_kit, :user_dashboard_tabs, [
      %{
        id: :orders,
        label: "My Orders",
        icon: "hero-shopping-bag",
        path: "orders",
        priority: 100
      },
      %{
        id: :notifications,
        label: "Notifications",
        icon: "hero-bell",
        path: "notifications",
        priority: 200,
        badge: %{type: :count, value: 0, color: :error}
      }
    ]

Tab options:
- `:id` - Unique atom identifier (required)
- `:label` - Display text (required)
- `:icon` - Heroicon name, e.g., "hero-home" (optional)
- `:path` - URL path (required)
- `:priority` - Sort order, lower = higher (default: 500)
- `:group` - Group ID for organizing (optional)
- `:match` - Path matching: :exact, :prefix (default: :prefix)
- `:visible` - Boolean or function(scope) -> boolean (default: true)
- `:badge` - Badge config map (optional)
- `:tooltip` - Hover text (optional)
- `:attention` - Animation: :pulse, :bounce, :shake, :glow (optional)

## User Dashboard Tab Groups

Organize tabs into labeled sections:

    config :phoenix_kit, :user_dashboard_tab_groups, [
      %{id: :main, label: nil, priority: 100},
      %{id: :farm, label: "Farm Management", priority: 200, icon: "hero-cube"},
      %{id: :account, label: "Account", priority: 900}
    ]

## Dashboard Presence

Configure presence tracking for dashboard tabs:

    config :phoenix_kit, :dashboard_presence,
      enabled: true,
      show_user_count: true,
      show_user_names: false,
      track_anonymous: false

## Admin Dashboard Categories

For detailed information about configuring custom admin dashboard categories,
see `PhoenixKit.Config.AdminDashboardCategories`.

## Type-Safe Functions

- `get_list/2` - Gets configuration values with list type validation
- `get_boolean/2` - Gets configuration values with boolean type validation
- `get_string/2` - Gets configuration values with string type validation

These functions provide automatic type validation and fallback to defaults
when the configuration value is missing or has the wrong type.

# `clear_admin_path_cache`

```elixir
@spec clear_admin_path_cache() :: :ok
```

Clears the cached admin segment.

Call this if you change the `admin_path` config at runtime (rare, and it does
NOT move the routes — those were compiled into the host router).

# `clear_url_prefix_cache`

```elixir
@spec clear_url_prefix_cache() :: :ok
```

Clears the cached URL prefix.

Call this if you change the url_prefix config at runtime (rare).

# `default_locale`

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

Returns the default locale for the application.

Parent apps can override via config:

    config :phoenix_kit,
      default_locale: "es-ES"

Defaults to "en-US" if not configured.

## Examples

    iex> PhoenixKit.Config.default_locale()
    "en-US"

    # With custom config:
    iex> PhoenixKit.Config.default_locale()
    "es-ES"

# `get`

```elixir
@spec get(atom()) :: {:ok, any()} | :not_found
```

Gets a specific configuration value.

Uses direct Application.get_env lookup for performance (avoids iterating
all config keys on every call).

# `get`

```elixir
@spec get(atom(), any()) :: any()
```

Gets a specific configuration value with a default.

## Examples

    iex> PhoenixKit.Config.get(:mailer, PhoenixKit.Mailer)
    MyApp.Mailer

    iex> PhoenixKit.Config.get(:nonexistent, :default)
    :default

# `get_admin_path`

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

The top-level URL segment for the admin area — `"/admin"` unless configured.

    config :phoenix_kit, admin_path: "/backoffice"

This renames the segment *inside* the mount prefix, so the example above
serves the admin area at `/phoenix_kit/backoffice/...`. It is independent of
`:url_prefix`, which names the mount itself.

## `/admin` stays the canonical name in code

Nothing in core (or in a module package) is written against the configured
value. Call sites keep saying `Routes.path("/admin/users")`; the substitution
happens in exactly two places, and they are inverses:

  * **emitting** a URL — `PhoenixKit.Utils.Routes.apply_admin_segment/1`,
    reached from `Routes.path/2` and `Routes.admin_path/2`, and from the
    router's own route table via `PhoenixKitWeb.Integration`
  * **reading** one back — `PhoenixKit.Utils.Routes.canonical_admin_path/1`,
    used wherever a real request path is matched against a canonical one
    (tab active state, the admin nav, the language switcher)

So a module package needs no changes to honour a renamed admin area, and a
grep for `"/admin"` in core stays meaningful.

## Compile-time

Read while the host router is compiled, so it belongs in `config.exs` —
**never** `runtime.exs`. `phoenix_kit_routes()` folds it into
`__mix_recompile__?/0`, so changing it re-expands the host router rather than
leaving it serving the old segment.

## Validation

Exactly one path segment, lowercase `[a-z0-9]` plus `_` and `-`, and not one
of the segments core already owns. A bad value raises here rather than
producing a router that compiles and then 404s.

# `get_all`

```elixir
@spec get_all() :: Keyword.t()
```

Gets all PhoenixKit configuration.

# `get_base_url`

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

Gets configured host with an optional port or default value.

# `get_boolean`

```elixir
@spec get_boolean(atom(), boolean()) :: boolean()
```

Gets a configuration value as a boolean with type validation.

## Examples

    iex> PhoenixKit.Config.get_boolean(:enabled, false)
    true

    iex> PhoenixKit.Config.get_boolean(:nonexistent, true)
    true

# `get_dynamic_base_url`

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

Gets the base URL dynamically from the parent Phoenix Endpoint if available,
otherwise falls back to the static configuration.

This function automatically detects the correct URL from the running Phoenix
application, which is especially useful in development mode where the port
might be different from the default configuration.

## Examples

    iex> PhoenixKit.Config.get_dynamic_base_url()
    "http://localhost:4001"  # from Phoenix Endpoint

    iex> PhoenixKit.Config.get_dynamic_base_url()
    "http://localhost:4000"  # fallback to static config

# `get_list`

```elixir
@spec get_list(atom(), list()) :: list()
```

Gets a configuration value as a list with type validation.

## Examples

    iex> PhoenixKit.Config.get_list(:options, [])
    []

    iex> PhoenixKit.Config.get_list(:nonexistent, [:default])
    [:default]

# `get_mailer`

```elixir
@spec get_mailer() :: module()
```

Gets the configured mailer module.

Returns the configured mailer or falls back to PhoenixKit.Mailer.

## Examples

    iex> PhoenixKit.Config.get_mailer()
    MyApp.Mailer

# `get_parent_app`

```elixir
@spec get_parent_app() :: atom() | nil
```

Gets the parent application name that is using PhoenixKit.

This function attempts to detect the main application that has included
PhoenixKit as a dependency.

# `get_parent_app_config`

```elixir
@spec get_parent_app_config(atom(), any()) :: any()
```

Gets configuration from the parent application.

This is useful for accessing parent app mailer, endpoint, or other configurations
that PhoenixKit needs to integrate with.

# `get_parent_endpoint`

```elixir
@spec get_parent_endpoint() :: {:ok, module()} | :error
```

Gets the parent application's Phoenix Endpoint module.

This function attempts to detect the main application's endpoint that is using
PhoenixKit as a dependency.

Returns `{:ok, endpoint_module}` if found, `:error` otherwise.

# `get_parent_endpoint_url`

```elixir
@spec get_parent_endpoint_url() :: {:ok, String.t()} | :error
```

Gets the parent Phoenix Endpoint URL if the endpoint is available and running.

Returns `{:ok, url}` if successful, `:error` if the endpoint cannot be found
or accessed.

# `get_repo`

```elixir
@spec get_repo() :: module() | nil
```

Gets the configured repository module.

# `get_repo!`

```elixir
@spec get_repo!() :: module()
```

Gets the configured repository module, raising an error if not found.

## Examples

    iex> PhoenixKit.Config.get_repo!()
    MyApp.Repo

    iex> PhoenixKit.Config.get_repo!()
    ** (ArgumentError) PhoenixKit repository not configured. Please set config :phoenix_kit, repo: YourApp.Repo

# `get_string`

```elixir
@spec get_string(atom(), String.t()) :: String.t()
```

Gets a configuration value as a string with type validation.

## Examples

    iex> PhoenixKit.Config.get_string(:host, "localhost")
    "example.com"

    iex> PhoenixKit.Config.get_string(:nonexistent, "default")
    "default"

# `get_url_prefix`

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

Gets configured prefix for urls or default value.

This value is cached using :persistent_term for performance since it's
called on every tab path match during dashboard renders.

# `get_users_module`

```elixir
@spec get_users_module() :: module()
```

Gets the configured users module.

# `mailer_local?`

```elixir
@spec mailer_local?() :: boolean()
```

Checks whether outgoing mail will actually land in the local dev mailbox.

True iff the send path `deliver_email/2` would take resolves to
`Swoosh.Adapters.Local`. Resolution order (via
`PhoenixKit.Mailer.resolved_send_path/0`): the operator's default send
integration, then the delegated host mailer (`config :phoenix_kit, :mailer`,
adapter read from the parent app's env), then the built-in mailer's own
config. A raw read of `config :phoenix_kit, PhoenixKit.Mailer` answered for
a mailer that may not be the one sending — false negative under delegation,
false positive when the installer-written Local block coexists with a real
delegated mailer (issue #687).

This renders on public pages, so a dead database (the integration lookup
reads Settings) means `false`, never a raise or exit.

## Examples

    iex> PhoenixKit.Config.mailer_local?
    true  # when the resolved send path uses Swoosh.Adapters.Local

    iex> PhoenixKit.Config.mailer_local?
    false  # when a send integration or a real adapter (SMTP, SES, ...) sends

# `pubsub_server`

```elixir
@spec pubsub_server() :: atom() | nil
```

Gets the configured PubSub server for broadcasting messages.

Returns the internal PhoenixKit PubSub server or configured custom server.

## Examples

    iex> PhoenixKit.Config.pubsub_server()
    :phoenix_kit_internal_pubsub

# `set`

```elixir
@spec set(atom(), any()) :: :ok
```

Sets a configuration value.

## Examples

    iex> PhoenixKit.Config.set(:repo, MyApp.Repo)
    :ok

    iex> PhoenixKit.Config.set(:custom_option, "custom_value")
    :ok

# `user_dashboard_enabled?`

```elixir
@spec user_dashboard_enabled?() :: boolean()
```

Gets the user dashboard enabled flag.

Returns true if the user dashboard is enabled, false otherwise.
This can be used to conditionally show/hide dashboard routes and navigation.

## Examples

    iex> PhoenixKit.Config.user_dashboard_enabled?()
    true

    iex> PhoenixKit.Config.user_dashboard_enabled?()
    false

# `validate_required!`

Validates that required configuration is present.

Raises an exception if any required keys are missing.

## Examples

    PhoenixKit.Config.validate_required!([:repo, :secret_key_base])

---

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