PhoenixKit β€” A Foundation for Building Your Elixir Phoenix Apps

Hex VersionCIcodecov

We are actively building PhoenixKit, a foundation for building your Elixir Phoenix apps β€” SaaS, social networks, ERP systems, marketplaces, internal tools, AI-powered apps, community platforms, and more. Our goal is to eliminate the need to reinvent the wheel every time you start a new project.

With PhoenixKit, you are able to create Elixir/Phoenix apps much faster and focus on your unique business logic instead of reimplementing common patterns.

πŸ“– Documentation

Installation

One command sets up the dependency, configuration, routes, mailer, and migrations:

mix igniter.install phoenix_kit

Prerequisite: the igniter_new archive (one-time setup, same as phx_new):

mix archive.install hex igniter_new

This will automatically:

See Installation Options below for advanced flags and fallback flows.

If the build fails on mdex / mdex_native

PhoenixKit renders markdown through mdex, which normally downloads a precompiled NIF. Two situations make it build from source instead, and both need rustler β€” which is a host dependency, because an optional dep is not resolved transitively:

# mix.exs
{:rustler, ">= 0.0.0", optional: true}

Without rustler present the build fails with a compilation error from mdex_native rather than anything naming PhoenixKit, which is why this is worth stating up front.

Upgrading to 2.0

New installs need nothing from this section.

2.0 consolidates the migration chain: V01..V134 no longer exist as individual modules, and V135 is a baseline that produces their cumulative schema in one step.

2.0 also repairs schema damage left by a long-standing migration-ordering defect that affected essentially every install created by mix phoenix_kit.install. One consequence changes behavior you may rely on: the comments foreign key is corrected from ON DELETE CASCADE to ON DELETE SET NULL, so deleting a user no longer deletes their comments.

Read the full guide before upgrading a production database: Upgrading to PhoenixKit 2.0.

πŸ“¦ What Ships With This Package (Core)

Everything below is part of the phoenix_kit Hex package itself β€” no extra dependency needed. (PhoenixKit also has a growing family of separately-versioned companion packages β€” see "Companion Modules" below.)

βœ… One-command install via Igniter (`mix igniter.install phoenix_kit`, updates via `mix phoenix_kit.update`)
βœ… Tailwind and DaisyUI integration
βœ… App layout integration
βœ… App database integration (Postgres only for now)
βœ… Custom slug prefix (default: `/phoenix_kit`)
βœ… Versioned migration chain shared across the whole PhoenixKit ecosystem
(170+ tables at V174 once every module is installed; core alone ships ~25)
βœ… Backend Admin module
βœ… Modules Manager β€” enable/disable installed modules at runtime, `/admin/modules`,
backed by a live Hex.pm catalog of known companion packages
βœ… Session Manager β€” active session listing/management, `/admin/users/sessions`
βœ… Activity Feed β€” audit trail of business-level actions, `/admin/activity`
βœ… Notifications β€” per-user inbox driven by the activity feed, mute-by-type
preferences, external delivery channels (Email, Telegram), digest cron
βœ… Integrations system β€” centralized OAuth/API-key/bot-token credential
storage, system-wide and per-user scopes, `/admin/settings/integrations`
βœ… Audit Log β€” tracks sensitive admin actions (password resets, user edits)
βœ… Mentions β€” cross-module `@`-mentions and `#`-record links
βœ… Annotations β€” shape overlays on media files (rectangle/circle/polygon/freehand)
βœ… Dashboard tab system β€” extensible admin + user-dashboard navigation,
`mix phoenix_kit.gen.admin.page` generator for custom pages
βœ… User Module
βœ… Registration
βœ… Login
βœ… Logout
βœ… Magic link
βœ… Email confirmation (enforced at every auth entry point; `require_email_confirmation` setting)
βœ… Rate limiting on public auth endpoints (Hammer-backed, per-endpoint)
βœ… New-login security alerts (unrecognized device/IP β†’ email + activity entry)
βœ… Password reset
βœ… User roles
βœ… Custom user fields
βœ… JSONB storage for flexibility
βœ… Location of registration (ip, country, region, city)
βœ… User's timezone (and mismatch detection)
βœ… User's locale
βœ… OAuth (Google, GitHub, Facebook β€” Apple sign-in was removed, see CHANGELOG)
βœ… Multi-session support, incl. admin "log in as user" (impersonation)
βœ… Users Module
βœ… Role management
βœ… Module-level, granular per-role permissions
βœ… Referral Program
βœ… Maintenance Mode Module
βœ… Email
βœ… Pluggable delivery via any Swoosh adapter (AWS SES, SMTP, SendGrid, Mailgun, ...)
βœ… AWS SES gets first-class setup assistance (IAM/credentials/region checklist)
βœ… Multiple named Send Profiles
βœ… Media / Storage Module
βœ… Photos and Videos
βœ… Local storage + cloud storage providers: AWS S3, Cloudflare R2,
Backblaze B2, Tigris β€” Azure/GCS/DigitalOcean Spaces not yet supported
βœ… Image resizing
βœ… Video resizing
βœ… Sitemap Module
βœ… Crawlers Module (robots.txt, llms.txt, bot-policy configuration)
βœ… Languages (Backend and frontend languages, broken down to countries and regions)
βœ… Backend languages
βœ… Frontend enduser languages, broken down and organized by countries and regions
βœ… Settings
βœ… General
βœ… App title
βœ… Global app timezone (native Elixir, no timex dependency)
βœ… Global time format (native Elixir, no timex dependency)
βœ… Language configuration
βœ… Core UI Component Library
βœ… [Draggable List](guides/draggable-list-component.md) - Drag-and-drop grid/list component
βœ… Sortable tables/grids, bulk-select, tree tables, reorder-strategy modal,
load-more & standalone pagination
βœ… Embeddable MediaBrowser (folder tree, grid/list, upload, search, trash)
βœ… Core form components (Input/Select/Textarea/Checkbox) and multilang
(translatable-field) form components

🧩 Companion Modules (separate Hex packages)

These extend PhoenixKit but ship as their own Hex packages with their own version/CHANGELOG β€” install them alongside phoenix_kit when you need them (extra_applications: [:phoenix_kit] wires them into module discovery automatically). Maturity varies by package; check each one's own CHANGELOG before relying on it in production. Representative examples from the BeamLabEU org:

πŸ“¦ phoenix_kit_ai β€” AI Module: OpenRouter + other provider integrations
πŸ“¦ phoenix_kit_entities β€” Dynamic content types, 13 field types, JSONB storage
πŸ“¦ phoenix_kit_publishing β€” Blog/article publishing: timed + slug-based, multilingual, timezone-aware
πŸ“¦ phoenix_kit_posts β€” User-generated posts (UGC)
πŸ“¦ phoenix_kit_billing β€” Invoices, orders, subscriptions; Stripe/PayPal payment providers
πŸ“¦ phoenix_kit_emails β€” Email logs, delivery dashboard/analytics, SQS/Brevo event polling
πŸ“¦ phoenix_kit_comments β€” Threaded comments (likes/dislikes/media)
πŸ“¦ phoenix_kit_newsletters β€” Mailing lists and broadcasts
πŸ“¦ phoenix_kit_legal β€” Cookie consent, ToS, GDPR/CCPA, privacy policy, data retention
πŸ“¦ phoenix_kit_ecommerce β€” Storefront, physical + digital products
πŸ“¦ phoenix_kit_customer_support β€” Support ticketing
πŸ“¦ phoenix_kit_crm β€” Companies, contacts, interactions, lists
πŸ“¦ phoenix_kit_bookings β€” Calendar-based booking
πŸ“¦ phoenix_kit_catalogue β€” Supplier/manufacturer catalogue, PDF extraction
πŸ“¦ phoenix_kit_document_creator β€” Document templates/generation
πŸ“¦ phoenix_kit_projects β€” Projects and tasks with dependencies
πŸ“¦ phoenix_kit_user_connections β€” User-to-user connections
πŸ“¦ phoenix_kit_sync β€” Cross-site data sync over WebSocket
πŸ“¦ phoenix_kit_staff β€” Departments, teams, skills
πŸ“¦ phoenix_kit_db β€” Database management tooling
... and more (open graph, SEO, web analytics, warehouse/manufacturing, calendar, message boards, and others) β€” see the BeamLabEU GitHub org for the current full list.

πŸ›£οΈ Roadmap / Ideas / Feature requests

Notifications, background jobs (Oban), newsletters, legal/compliance, customer support, and e-commerce are no longer just ideas β€” they've shipped, either built into core or as companion packages (see "Companion Modules" above). What's still genuinely open:

--- Next priority

--- To sort items

πŸ’‘ Send your ideas and suggestions about any existing modules and features our way. Start building your apps today!

Installation Options

The recommended path is mix igniter.install phoenix_kit (see the quick install at the top of this README). The sections below cover advanced options and fallback flows.

Installer options

# Specify custom repository
mix igniter.install phoenix_kit --repo MyApp.Repo
# Use PostgreSQL schema prefix for table isolation
mix igniter.install phoenix_kit --prefix "auth" --create-schema
# Specify custom router file path
mix igniter.install phoenix_kit --router-path lib/my_app_web/router.ex

The same flags work with mix phoenix_kit.install if the dep is already in your project.

Fallback: two-step install

If you'd rather not use the igniter_new archive, add the deps yourself and invoke the installer directly. You need both β€” PhoenixKit declares :igniter as optional: true (so it converges with the {:igniter, "~> 0.6", only: [:dev, :test]} that mix phx.new generates), and an optional dep is not resolved transitively:

# mix.exs
def deps do
[
{:phoenix_kit, "~> 2.0"},
{:igniter, "~> 0.7", only: [:dev, :test]}
]
end
mix deps.get
mix phoenix_kit.install

only: [:dev, :test] is deliberate β€” igniter is build-time tooling and never reaches production. Every reference to it in PhoenixKit lives in the mix phoenix_kit.* tasks and their installer helpers; nothing in the supervision tree or the request path touches it, and Mix tasks aren't part of a release.

Without :igniter, the two code-patching tasks β€” mix phoenix_kit.install and mix phoenix_kit.update β€” print these instructions instead of running. Tasks that don't generate or patch code (mix phoenix_kit.status, mix phoenix_kit.gen.migration, mix phoenix_kit.assets.rebuild) work without it. Adding the dep to an existing project is all that's needed: PhoenixKit detects the change and recompiles itself, so the tasks appear without a manual mix deps.compile phoenix_kit --force.

Manual Installation

For full control, skip the installer entirely:

  1. Add {:phoenix_kit, "~> 2.0"} to mix.exs
  2. Run mix deps.get && mix phoenix_kit.gen.migration
  3. Configure repository: config :phoenix_kit, repo: MyApp.Repo
  4. Add phoenix_kit_routes() to your router
  5. Run mix ecto.migrate

Quick Start

Visit these URLs after installation:

Where {prefix} is your configured PhoenixKit URL prefix (default: /phoenix_kit).

Configuration

Basic Setup

# config/config.exs (automatically added by installer)
config :phoenix_kit,
repo: YourApp.Repo,
from_email: "noreply@yourcompany.com", # Required for email notifications
from_name: "Your Company Name" # Optional, defaults to "PhoenixKit"
# Production mailer (see config/prod.exs for more options)
config :phoenix_kit, PhoenixKit.Mailer,
adapter: Swoosh.Adapters.SMTP,
relay: "smtp.your-provider.com",
username: System.get_env("SMTP_USERNAME"),
password: System.get_env("SMTP_PASSWORD"),
port: 587

Layout Integration

# Use your app's layout (optional)
config :phoenix_kit,
layout: {YourAppWeb.Layouts, :app},
root_layout: {YourAppWeb.Layouts, :root}

Email Configuration

PhoenixKit supports multiple email providers with automatic setup assistance:

AWS SES (Complete Setup)

For AWS SES, PhoenixKit automatically configures required dependencies and HTTP client:

# Add to mix.exs dependencies (done automatically by installer when needed)
{:gen_smtp, "~> 1.2"}
# Application supervisor includes Finch automatically
{Finch, name: Swoosh.Finch}
# Production configuration
config :phoenix_kit, PhoenixKit.Mailer,
adapter: Swoosh.Adapters.AmazonSES,
region: "eu-north-1" # or "eu-north-1", "eu-west-1", etc.

AWS SES Checklist:

Other Email Providers

# SendGrid
config :phoenix_kit, PhoenixKit.Mailer,
adapter: Swoosh.Adapters.Sendgrid,
api_key: System.get_env("SENDGRID_API_KEY")
# Mailgun
config :phoenix_kit, PhoenixKit.Mailer,
adapter: Swoosh.Adapters.Mailgun,
api_key: System.get_env("MAILGUN_API_KEY"),
domain: System.get_env("MAILGUN_DOMAIN")

Note: Run mix deps.compile phoenix_kit --force after changing configuration.

OAuth Configuration

Enable social authentication (Google, GitHub, Facebook) through admin UI at {prefix}/admin/settings. Built-in setup instructions included. For reverse proxy deployments, ensure X-Forwarded-Proto header is set:

proxy_set_header X-Forwarded-Proto $scheme;

See OAuth Setup Guide for details.

Advanced Options

Routes

User Authentication Routes

User Dashboard Routes

Admin Routes (Owner/Admin only)

Companion packages (if installed) register additional routes under {prefix}/admin/* automatically via module discovery β€” see "External Module Route Discovery" in this project's AGENTS.md.

API Usage

Current User Access

# In your controller or LiveView
user = conn.assigns[:phoenix_kit_current_user]
# Or using Scope system
scope = socket.assigns[:phoenix_kit_current_scope]
PhoenixKit.Users.Auth.Scope.authenticated?(scope)

Role-Based Access

# Check user roles
PhoenixKit.Users.Roles.user_has_role?(user, "Admin")
# Promote user to admin
{:ok, _} = PhoenixKit.Users.Roles.promote_to_admin(user)
# Use in LiveView sessions
on_mount: [{PhoenixKitWeb.Users.Auth, :phoenix_kit_ensure_admin}]

Authentication Helpers

# In your LiveView sessions
on_mount: [{PhoenixKitWeb.Users.Auth, :phoenix_kit_mount_current_scope}]
on_mount: [{PhoenixKitWeb.Users.Auth, :phoenix_kit_ensure_authenticated_scope}]

Database Schema

The versioned migration chain (lib/phoenix_kit/migrations/postgres/, currently at V174) is centralized in this package and shared across the whole PhoenixKit ecosystem: installing just phoenix_kit already creates the full current schema β€” 170+ tables covering every companion package's data model, not only core's own. This keeps tables ready the moment a companion package is added, at the cost of a wider schema than a core-only app strictly uses. Tables that matter without any companion package installed include:

The remaining tables (CRM, catalogue, publishing, warehouse, projects, newsletters, and more) sit dormant β€” unused, but present β€” until you add the matching companion package and enable it.

Role-Based Access Control

System Roles

Role Management

# Check roles
PhoenixKit.Users.Roles.get_user_roles(user)
# => ["Admin", "User"]
# Role promotion/demotion
PhoenixKit.Users.Roles.promote_to_admin(user)
PhoenixKit.Users.Roles.demote_to_user(user)
# Create custom roles
PhoenixKit.Users.Roles.create_role(%{name: "Manager", description: "Team lead"})

Module-Level Permissions

PhoenixKit includes a granular permission system that controls which roles can access which admin sections and feature modules.

5 core section keys ship fixed with this package: dashboard, users, media, settings, modules. Each installed companion package can register its own feature-module key (and dotted sub-permission keys, e.g. calendar.view_others) β€” the total key count grows as you add companion packages, not a fixed number. There's also a blanket "*" superadmin key, honored the same as Owner.

Access rules:

# Grant/revoke permissions for a role (role_uuid, granted_by_uuid are UUIDv7 strings)
Permissions.grant_permission(role_uuid, "billing", granted_by_uuid)
Permissions.revoke_permission(role_uuid, "billing", actor_uuid: granted_by_uuid)
Permissions.set_permissions(role_uuid, ["dashboard", "users", "billing"], granted_by_uuid)
# Query permissions
Permissions.get_permissions_for_role(role_uuid) # ["dashboard", "users", ...]
Permissions.role_has_permission?(role_uuid, "shop") # true/false
# Check access via Scope (in LiveViews)
Scope.has_module_access?(scope, "billing") # true/false
Scope.has_any_module_access?(scope, ["billing", "shop"])
Scope.system_role?(scope) # Owner or Admin?

Admin UI: Interactive permission matrix at {prefix}/admin/users/permissions and inline editor on the Roles page.

Route enforcement: phoenix_kit_ensure_admin and phoenix_kit_ensure_module_access on_mount hooks enforce permissions at the route level. Sidebar navigation is gated per-user based on granted permissions.

Module System

PhoenixKit uses a modular architecture where features can be enabled/disabled at runtime. All modules are disabled by default and must be enabled before use.

Enable via Admin UI: Visit {prefix}/admin/modules to toggle modules on/off.

Enable via Code:

Each companion package exposes enabled?/0 and enable_system/0 on its own top-level module β€” the name varies by package, so check that package's own docs. A few examples:

# Check if a module is enabled
PhoenixKitAI.enabled?() # => false (default, when installed)
PhoenixKitEntities.enabled?() # => false (default)
# Enable modules before use
PhoenixKitAI.enable_system()
PhoenixKitEntities.enable_system()
PhoenixKitPosts.enable_system()
PhoenixKit.Modules.Emails.enable_system()
PhoenixKitBilling.enable_system()
# Disable when no longer needed
PhoenixKitAI.disable_system()

Important: Attempting to use a disabled module's API functions or admin pages will result in errors or redirects. Always enable modules before:

Built-in Admin Interface

Core Administration (ships with this package):

Settings & Configuration (core):

The following require installing their companion package (see "Companion Modules" above) β€” they 404 until that package is added:

Architecture

PhoenixKit follows professional library patterns:

Contributing

See CONTRIBUTING.md for detailed instructions on setting up a development environment and contributing to PhoenixKit.

License

MIT License - see CHANGELOG.md for version history.


Built in πŸ‡ͺπŸ‡ΊπŸ‡ͺπŸ‡ͺ with ❀️ for the Elixir Phoenix community.