# `PhoenixKit.Module`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v1.7.87/lib/phoenix_kit/module.ex#L1)

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.

# `permission_meta`

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

Permission metadata for the module

# `admin_tabs`
*optional* 

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

# `children`
*optional* 

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

# `css_sources`
*optional* 

```elixir
@callback css_sources() :: [String.t()]
```

Returns the OTP app name for Tailwind CSS source scanning.

The installer uses this to generate the correct `@source` directive in the
parent app's `app.css`. It automatically resolves the right path based on
whether the dep is installed from Hex (`deps/`) or as a path dep.

## Example

    def css_sources, do: [:phoenix_kit_publishing]

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

# `disable_system`

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

# `enable_system`

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

# `enabled?`

```elixir
@callback enabled?() :: boolean()
```

# `get_config`
*optional* 

```elixir
@callback get_config() :: map()
```

# `migration_module`
*optional* 

```elixir
@callback migration_module() :: module() | nil
```

# `module_key`

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

# `module_name`

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

# `permission_metadata`
*optional* 

```elixir
@callback permission_metadata() :: permission_meta() | nil
```

# `required_modules`
*optional* 

```elixir
@callback required_modules() :: [String.t()]
```

# `route_module`
*optional* 

```elixir
@callback route_module() :: module() | nil
```

# `settings_tabs`
*optional* 

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

# `user_dashboard_tabs`
*optional* 

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

# `version`
*optional* 

```elixir
@callback version() :: String.t()
```

---

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