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"). Seeget_admin_path/0— compile-time,config.exsonly.:admin_panel_label- What the admin area is called in the admin header and the account menu. A preset atom (translated in every locale) or a string (verbatim). Unset derives it from:admin_path. Seeadmin_panel_label/0andadmin_label_presets/0.:user_dashboard_enabled- Enable/disable the deprecated user dashboard (/dashboard). Default:false. Seeuser_dashboard_enabled?/0.: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: falseAdmin 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 validationget_boolean/2- Gets configuration values with boolean type validationget_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.
Summary
Functions
The preset names the admin area can be called by, as {preset, url_segment}.
What the admin area is called — a translated preset, or a host's own string.
Clears the cached admin segment.
Clears the cached URL prefix.
Returns the default locale for the application.
Gets a specific configuration value.
Gets a specific configuration value with a default.
The top-level URL segment for the admin area — "/admin" unless configured.
Gets all PhoenixKit configuration.
Gets configured host with an optional port or default value.
Gets a configuration value as a boolean with type validation.
Gets the base URL dynamically from the parent Phoenix Endpoint if available, otherwise falls back to the static configuration.
Gets a configuration value as a list with type validation.
Gets the configured mailer module.
Gets the parent application name that is using PhoenixKit.
Gets configuration from the parent application.
Gets the parent application's Phoenix Endpoint module.
Gets the parent Phoenix Endpoint URL if the endpoint is available and running.
Gets the configured repository module.
Gets the configured repository module, raising an error if not found.
Gets a configuration value as a string with type validation.
Gets configured prefix for urls or default value.
Gets the configured users module.
Checks whether outgoing mail will actually land in the local dev mailbox.
Gets the configured PubSub server for broadcasting messages.
Sets a configuration value.
Whether the host has said anything at all about :user_dashboard_enabled.
Whether the deprecated user dashboard (/dashboard) is routed.
Validates that required configuration is present.
Functions
The preset names the admin area can be called by, as {preset, url_segment}.
| Preset | Reads as | Pairs with |
|---|---|---|
:admin_panel | Admin Panel (default) | admin_path: "/admin" |
:dashboard | Dashboard | admin_path: "/dashboard" |
:backoffice | Backoffice | admin_path: "/backoffice" |
:console | Console | admin_path: "/console" |
:control_panel | Control Panel | admin_path: "/control_panel" |
:workspace | Workspace | admin_path: "/workspace" |
:portal | Portal | admin_path: "/portal" |
:my_account | My Account | admin_path: "/my_account" |
:management | Management | admin_path: "/management" |
:studio | Studio | admin_path: "/studio" |
"Reads as" is the ENGLISH rendering. Each is a gettext/1 msgid translated
in every shipped locale — that is the point of the list being closed, and
what a free-typed string cannot do. Rendered by
PhoenixKitWeb.Components.Core.AdminLabel.preset_text/1.
mix phoenix_kit.install and mix phoenix_kit.update write this same list
into the host's config/config.exs as a comment block
(PhoenixKit.Install.AdminLabelConfig), so it is in front of a developer at
the moment they go to change it.
iex> PhoenixKit.Config.admin_label_presets() |> Keyword.keys() |> Enum.take(3)
[:admin_panel, :dashboard, :backoffice]
What the admin area is called — a translated preset, or a host's own string.
Returns {:preset, atom} (rendered through gettext/1, so every visitor
reads it in their own language) or {:custom, binary} (shown verbatim to
everyone). Never nil: the fallback is {:preset, :admin_panel}.
Resolution order
config :phoenix_kit, admin_panel_label: :console— an explicit preset fromadmin_label_presets/0.config :phoenix_kit, admin_panel_label: "Acme HQ"— free text. The escape hatch for a brand name no preset covers. ⚠️ Not translated: one string, shown to every visitor whatever their language.Unset — derived from
:admin_path, so the URL and the wording stay aligned by construction rather than by the host remembering to set two keys:config :phoenix_kit, admin_path: "/backoffice" #=> {:preset, :backoffice} — URL /backoffice, header "Backoffice"-and_are equivalent in the segment (/control-paneland/control_panelboth derive:control_panel).
A segment that matches no preset — /x7q, or any deliberately obscure
rename — derives {:preset, :admin_panel} rather than inventing a label
from the URL.
Unrecognised values fall back, they do not raise
Unlike get_admin_path/0, a bad value here is cosmetic: a typo must not take
the admin area down in production. An unknown atom, a blank string or a
non-string, non-atom value falls through to the derivation in step 3.
Examples
iex> PhoenixKit.Config.admin_panel_label()
{:preset, :admin_panel}
# With `config :phoenix_kit, admin_panel_label: :console`:
iex> PhoenixKit.Config.admin_panel_label()
{:preset, :console}
@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).
@spec clear_url_prefix_cache() :: :ok
Clears the cached URL prefix.
Call this if you change the url_prefix config at runtime (rare).
@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"
Gets a specific configuration value.
Uses direct Application.get_env lookup for performance (avoids iterating all config keys on every call).
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
@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 fromRoutes.path/2andRoutes.admin_path/2, and from the router's own route table viaPhoenixKitWeb.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.
@spec get_all() :: Keyword.t()
Gets all PhoenixKit configuration.
@spec get_base_url() :: String.t()
Gets configured host with an optional port or default value.
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
@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
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]
@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
@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.
Gets configuration from the parent application.
This is useful for accessing parent app mailer, endpoint, or other configurations that PhoenixKit needs to integrate with.
@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.
@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.
@spec get_repo() :: module() | nil
Gets the configured repository module.
@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
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"
@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.
@spec get_users_module() :: module()
Gets the configured users module.
@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
@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
Sets a configuration value.
Examples
iex> PhoenixKit.Config.set(:repo, MyApp.Repo)
:ok
iex> PhoenixKit.Config.set(:custom_option, "custom_value")
:ok
@spec user_dashboard_configured?() :: boolean()
Whether the host has said anything at all about :user_dashboard_enabled.
Distinguishes "took the new default" from "explicitly chose false", which
user_dashboard_enabled?/0 cannot: both answer false. mix phoenix_kit.update
uses it to tell an upgrading host that the default flipped under them — a
host that already wrote the key made a choice and needs no notice.
@spec user_dashboard_enabled?() :: boolean()
Whether the deprecated user dashboard (/dashboard) is routed.
Defaults to false. The user dashboard is deprecated — its job has moved
into the unified admin panel at /admin, which shows each visitor the
sections their permissions allow (and greets a permission-less visitor rather
than bouncing them, see PhoenixKitWeb.Users.Auth.landing_view?/1). Core
therefore stopped routing it by default; nothing in core links to it any more.
It is not deleted. A host that still wants it turns it back on:
config :phoenix_kit, user_dashboard_enabled: trueand gets /dashboard, /dashboard/settings and the confirm-email compat
redirects back, exactly as before.
Read at macro-expansion time by the route macros in
PhoenixKitWeb.Integration, so it is compile-time config — config.exs,
never runtime.exs. phoenix_kit_routes/0 folds it into
__mix_recompile__?/0, so flipping it re-expands the host router instead of
leaving it serving the old route table.
Examples
iex> PhoenixKit.Config.user_dashboard_enabled?()
false
# With `config :phoenix_kit, user_dashboard_enabled: true`:
iex> PhoenixKit.Config.user_dashboard_enabled?()
true
Validates that required configuration is present.
Raises an exception if any required keys are missing.
Examples
PhoenixKit.Config.validate_required!([:repo, :secret_key_base])