PhoenixKit.Module behaviour (phoenix_kit v1.7.102)

Copy Markdown View Source

Behaviour for PhoenixKit feature modules (internal and external).

Any module that implements this behaviour can register itself with PhoenixKit's tab registry, permission system, supervisor tree, and route system.

Usage

defmodule PhoenixKitHelloWorld do
  use PhoenixKit.Module

  @impl true
  def module_key, do: "hello_world"

  @impl true
  def module_name, do: "Hello World"

  @impl true
  def enabled?, do: PhoenixKit.Settings.get_boolean_setting("hello_world_enabled", false)

  @impl true
  def enable_system do
    PhoenixKit.Settings.update_boolean_setting_with_module("hello_world_enabled", true, "hello_world")
  end

  @impl true
  def disable_system do
    PhoenixKit.Settings.update_boolean_setting_with_module("hello_world_enabled", false, "hello_world")
  end

  @impl true
  def permission_metadata do
    %{
      key: "hello_world",
      label: "Hello World",
      icon: "hero-hand-raised",
      description: "A demo module"
    }
  end

  @impl true
  def admin_tabs do
    [%PhoenixKit.Dashboard.Tab{
      id: :admin_hello_world,
      label: "Hello World",
      icon: "hero-hand-raised",
      path: "hello-world",
      priority: 640,
      level: :admin,
      permission: "hello_world",
      match: :prefix,
      group: :admin_modules
    }]
  end
end

Required Callbacks

  • module_key/0 - Unique string key (e.g., "tickets", "billing")
  • module_name/0 - Human-readable display name
  • enabled?/0 - Whether the module is currently enabled
  • enable_system/0 - Enable the module system-wide
  • disable_system/0 - Disable the module system-wide

Optional Callbacks

All optional callbacks have sensible defaults provided by use PhoenixKit.Module:

  • get_config/0 - Module stats/config map (default: %{enabled: enabled?()}). The default calls enabled?() which may hit the database. External modules with expensive config should override this with a cached implementation.
  • permission_metadata/0 - Permission key, label, icon, description (default: nil)
  • admin_tabs/0 - Admin navigation tabs (default: [])
  • settings_tabs/0 - Settings subtabs (default: [])
  • user_dashboard_tabs/0 - User-facing dashboard tabs (default: [])
  • children/0 - Supervisor child specs (default: [])
  • route_module/0 - Module providing route macros (default: nil)
  • version/0 - Module version string (default: "0.0.0")
  • migration_module/0 - Module implementing versioned migrations (default: nil). When set, mix phoenix_kit.update will automatically run this module's migrations alongside the core PhoenixKit migrations.
  • required_integrations/0 - Integration provider keys this module needs (default: []). Used by the Integrations settings page to show relevant providers.
  • integration_providers/0 - Additional provider definitions this module contributes (default: []).

Summary

Types

Permission metadata for the module

Types

permission_meta()

@type permission_meta() :: %{
  key: String.t(),
  label: String.t(),
  icon: String.t(),
  description: String.t()
}

Permission metadata for the module

Callbacks

admin_tabs()

(optional)
@callback admin_tabs() :: [PhoenixKit.Dashboard.Tab.t()]

children()

(optional)
@callback children() :: [Supervisor.child_spec() | module() | {module(), term()}]

css_sources()

(optional)
@callback css_sources() :: [atom() | String.t()]

Returns Tailwind CSS source roots for scanning.

Each entry is either:

  • an atom — the OTP app name. The compiler resolves it via the parent app's mix.exs deps (deps/<app> for Hex, path: value for path deps).
  • a string — a literal path. Absolute paths (starting with /) emit as @source "<abs>"; verbatim; relative paths emit as @source "../../<path>"; (relative to assets/css/_phoenix_kit_sources.css). Useful when a module wants to add a path-dep absolute fallback alongside the OTP-app entry, so both Hex and path-dep installs work without parent-app toggles.

Examples

def css_sources, do: [:phoenix_kit_publishing]

# Path-dep friendly:
@source_root Path.expand(Path.join(__DIR__, "../.."))
def css_sources, do: [:phoenix_kit_publishing, @source_root]

Headless modules (no templates) can skip this callback — the default is [].

disable_system()

@callback disable_system() :: :ok | {:ok, term()} | {:error, term()}

enable_system()

@callback enable_system() :: :ok | {:ok, term()} | {:error, term()}

enabled?()

@callback enabled?() :: boolean()

get_config()

(optional)
@callback get_config() :: map()

integration_providers()

(optional)
@callback integration_providers() :: [map()]

migration_module()

(optional)
@callback migration_module() :: module() | nil

module_key()

@callback module_key() :: String.t()

module_name()

@callback module_name() :: String.t()

notification_types()

(optional)
@callback notification_types() :: [map()]

Returns a list of notification types this module contributes.

Each type is a map with:

  • :key — binary, stable identifier used in user prefs (e.g. "posts")
  • :label — binary, user-facing display (e.g. "Posts")
  • :description — binary, short explainer shown under the toggle
  • :actions — list of dotted action strings (["post.liked", "post.commented"])
  • :default — boolean, the toggle's default state for users who haven't set a preference

Types merge with core PhoenixKit types (account, posts, comments) and show up automatically in the UserSettings "Notifications" section. The filter in PhoenixKit.Notifications.maybe_create_from_activity/1 resolves each action to a type via :actions and skips the fan-out when the user has muted that type.

Headless modules (no user-facing actions) can skip this callback — the default is [].

Example

def notification_types do
  [
    %{
      key: "reviews",
      label: "Reviews",
      description: "When someone leaves you a review",
      actions: ["review.submitted", "review.edited"],
      default: true
    }
  ]
end

permission_metadata()

(optional)
@callback permission_metadata() :: permission_meta() | nil

required_integrations()

(optional)
@callback required_integrations() :: [String.t()]

required_modules()

(optional)
@callback required_modules() :: [String.t()]

route_module()

(optional)
@callback route_module() :: module() | nil

settings_tabs()

(optional)
@callback settings_tabs() :: [PhoenixKit.Dashboard.Tab.t()]

user_dashboard_tabs()

(optional)
@callback user_dashboard_tabs() :: [PhoenixKit.Dashboard.Tab.t()]

version()

(optional)
@callback version() :: String.t()