AshDispatch.Config (AshDispatch v0.5.0)

View Source

Centralized configuration access for AshDispatch.

This module provides a single source of truth for all configuration values, with consistent defaults and clear documentation of each option.

Why This Exists

Configuration lookups were scattered across 30+ files, each with potentially different default values. This module ensures:

  1. Consistent defaults - Each config key has one canonical default
  2. Single source of truth - Change defaults in one place
  3. Discoverability - All config options documented together
  4. Type safety - Functions return expected types

Usage

# Instead of:
Application.get_env(:ash_dispatch, :user_module)

# Use:
AshDispatch.Config.user_module()

Configuration

All options are configured under the :ash_dispatch application:

config :ash_dispatch,
  user_module: MyApp.Accounts.User,
  domains: [MyApp.Orders, MyApp.Tickets],
  otp_app: :my_app,
  # ... see individual functions for all options

Summary

Functions

The PubSub topic for admin/firehose broadcasts.

Audience configuration for recipient resolution (legacy).

Base URL for the application (fallback when endpoint not available).

The Phoenix channel topic prefix for user channels.

Whether to compile templates at build time.

The counter broadcast function (alternative to counter_broadcaster module).

The counter broadcaster module.

Default from email address.

Default from name (sender name displayed in email clients).

Default locale for template resolution and content.

The delivery receipt resource module.

List of Ash domains that have dispatch-enabled resources.

The email backend module for sending emails.

The Phoenix endpoint module for URL generation.

List of explicitly registered event modules.

Custom format extensions for template resolution.

Optional Gettext backend for translating content strings.

Default Gettext domain used to translate DSL content strings.

The notification resource module.

The OTP application name.

The permission checker module for policy checks.

The preference provider module (legacy, prefer user_preference).

The PubSub module for broadcasting notifications.

Recipient field configuration for extracting email/name from user structs.

The recipient resolver module.

The Ecto repo module.

Output path for generated SDK files.

Authorizer module for the send_now action on delivery receipts.

Whether to skip actual email delivery.

The SMS backend module — should implement AshDispatch.SMSBackend. Returns nil when no backend is configured, in which case the SMS transport marks receipts :skipped.

The Swoosh mailer module (when using Swoosh backend).

The URL builder module for generating admin/source URLs.

The domain containing the user resource.

The user module for recipient resolution and preferences.

The user preference checker module.

The user resource module (alias for user_module for clarity in some contexts).

Functions

admin_channel_topic()

@spec admin_channel_topic() :: String.t()

The PubSub topic for admin/firehose broadcasts.

Used by the :broadcast transport when audience is :admin.

Example

config :ash_dispatch,
  admin_channel_topic: "admin:firehose"

audiences()

@spec audiences() :: keyword()

Audience configuration for recipient resolution (legacy).

Maps audience atoms to filter configurations.

Note: If recipient_resolver is configured, this option is ignored. Prefer using recipient_resolver for new applications.

Example

config :ash_dispatch,
  audiences: [
    admin: [admin: true],
    user: :user,
    support: [role: :support]
  ]

base_url()

@spec base_url() :: String.t() | nil

Base URL for the application (fallback when endpoint not available).

channel_topic()

@spec channel_topic() :: String.t()

The Phoenix channel topic prefix for user channels.

Defaults to "user" which creates topics like "user:user_id". Configure to match your channel setup, e.g., "inbox" for "inbox:user_id".

Example

config :ash_dispatch,
  channel_topic: "inbox"

compile_templates?()

@spec compile_templates?() :: boolean()

Whether to compile templates at build time.

Defaults to false.

counter_broadcast_fn()

@spec counter_broadcast_fn() :: function() | nil

The counter broadcast function (alternative to counter_broadcaster module).

counter_broadcaster()

@spec counter_broadcaster() :: module() | nil

The counter broadcaster module.

Should implement broadcast/3 for counter updates.

default_from_email()

@spec default_from_email() :: String.t()

Default from email address.

Used when no from is specified in event module or inline DSL.

Defaults to "noreply@example.com".

default_from_name()

@spec default_from_name() :: String.t()

Default from name (sender name displayed in email clients).

Used when no from is specified in event module or inline DSL.

Defaults to the OTP app name (titlecased) or "System" if not configured.

Example

config :ash_dispatch,
  default_from_name: "Fyndgrossisten"

default_locale()

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

Default locale for template resolution and content.

Used as the ultimate fallback when no locale is specified. The full locale resolution priority is:

  1. Channel-level locale (static, e.g., locale: "sv")
  2. Channel-level locale_from (dynamic from record field)
  3. Event-level locale_from configuration
  4. Resource-level locale_from configuration
  5. Auto-detected common fields: visitor_locale, locale
  6. This config default

Template resolution then tries locale-specific templates first (e.g., email.sv.html.heex), falling back to non-localized templates.

Defaults to "en".

Example

config :ash_dispatch,
  default_locale: "sv"

See Also

delivery_receipt_resource()

@spec delivery_receipt_resource() :: module() | nil

The delivery receipt resource module.

Must be configured - returns nil if not set.

Example

config :ash_dispatch,
  delivery_receipt_resource: MyApp.Deliveries.DeliveryReceipt

domains()

@spec domains() :: [module()]

List of Ash domains that have dispatch-enabled resources.

Used for:

  • Event discovery via DSL introspection
  • Counter loading
  • SDK generation

Example

config :ash_dispatch,
  domains: [MyApp.Orders, MyApp.Tickets, MyApp.Requests]

email_backend()

@spec email_backend() :: module() | nil

The email backend module for sending emails.

Should implement the email backend behaviour.

Example

config :ash_dispatch,
  email_backend: AshDispatch.EmailBackend.Swoosh

endpoint()

@spec endpoint() :: module() | nil

The Phoenix endpoint module for URL generation.

event_modules()

@spec event_modules() :: [module()]

List of explicitly registered event modules.

These are discovered in addition to DSL-based events.

format_extensions()

@spec format_extensions() :: map()

Custom format extensions for template resolution.

gettext_backend()

@spec gettext_backend() :: module() | nil

Optional Gettext backend for translating content strings.

When configured, all content: block strings (notification_title, notification_message, etc.) are run through Gettext before variable interpolation. The locale is resolved via the dispatch locale chain.

The content string IS the gettext msgid. Translations are looked up in the "notifications" domain.

Example

config :ash_dispatch,
  gettext_backend: MyAppWeb.Gettext

Then content strings like notification_title: "Usage Alert" will be translated via Gettext.dgettext(MyAppWeb.Gettext, "notifications", "Usage Alert").

gettext_domain()

@spec gettext_domain() :: String.t()

Default Gettext domain used to translate DSL content strings.

When a channel's :notification_title, :notification_message, :subject, etc. is defined as a literal in dispatch do ... end, Dispatcher.translate_content/2 looks up the string via Gettext.dgettext(backend, gettext_domain(), msgid) before variable interpolation runs.

Defaults to "notifications" so existing projects keep working. Override per app:

config :ash_dispatch, :gettext_domain, "default"

Projects that already extract i18n strings to default.po (e.g. multi-locale Phoenix apps) can consolidate their DSL content alongside the rest of their translations.

notification_resource()

@spec notification_resource() :: module() | nil

The notification resource module.

Must be configured - returns nil if not set.

Example

config :ash_dispatch,
  notification_resource: MyApp.Notifications.Notification

otp_app()

@spec otp_app() :: atom() | nil

The OTP application name.

Used for:

  • Template resolution
  • Event module discovery

permission_checker()

@spec permission_checker() :: module() | nil

The permission checker module for policy checks.

preference_provider()

@spec preference_provider() :: module() | nil

The preference provider module (legacy, prefer user_preference).

pubsub_module()

@spec pubsub_module() :: module() | nil

The PubSub module for broadcasting notifications.

Contract

Must be an endpoint-shaped module exposing both:

  • subscribe(topic) — for server-side consumers (e.g. Mosis.Dispatch.Subscriber or any GenServer that reacts to AshDispatch broadcasts in-process)
  • broadcast(topic, event, payload) — used by AshDispatch.Transports.Broadcast to publish to user / admin channels and by Transports.InApp for new-notification pushes

Phoenix endpoints generate both functions automatically — set this to your application's endpoint module:

config :ash_dispatch, pubsub_module: MyAppWeb.Endpoint

Do NOT set this to a bare Phoenix.PubSub registered name (e.g. MyApp.PubSub). Those expose Phoenix.PubSub.subscribe/2 (arity 2) and Phoenix.PubSub.broadcast/3 as functions on the Phoenix.PubSub module itself, not on the registered-name atom — and consumers that call pubsub.subscribe(topic) or pubsub.broadcast(topic, …) directly would fail with UndefinedFunctionError.

recipient_fields()

@spec recipient_fields() :: keyword()

Recipient field configuration for extracting email/name from user structs.

Example

config :ash_dispatch,
  recipient_fields: [
    email: [
      default: :email,
      audiences: [admin: :work_email]
    ],
    name: [
      default: :display_name
    ]
  ]

recipient_resolver()

@spec recipient_resolver() :: module() | nil

The recipient resolver module.

When configured, this module is used for all recipient resolution, replacing the legacy audiences configuration.

Should implement AshDispatch.RecipientResolver behaviour.

Example

config :ash_dispatch,
  recipient_resolver: MyApp.RecipientResolver

repo()

@spec repo() :: module() | nil

The Ecto repo module.

Used for Oban job queries and other database operations.

sdk_output_path()

@spec sdk_output_path() :: String.t() | nil

Output path for generated SDK files.

send_now_authorizer()

@spec send_now_authorizer() :: module() | nil

Authorizer module for the send_now action on delivery receipts.

The module should implement authorize/1 which receives the actor and returns:

  • :ok if authorized
  • {:error, message} if not authorized

When nil (default), send_now is allowed for any authenticated actor. System calls (no actor) are always allowed regardless of this setting.

Example

# Define authorizer module
defmodule MyApp.SendNowAuthorizer do
  def authorize(nil), do: :ok  # System calls always allowed
  def authorize(%{super_admin: true}), do: :ok
  def authorize(_), do: {:error, "Only super admins can trigger send now"}
end

# Configure in config.exs
config :ash_dispatch,
  send_now_authorizer: MyApp.SendNowAuthorizer

skip_email_delivery?()

@spec skip_email_delivery?() :: boolean()

Whether to skip actual email delivery.

When true, emails will not be sent and delivery receipts will be marked as :skipped with reason "email delivery disabled". Useful for development to prevent sending real emails while still testing the full dispatch flow.

Defaults to false.

Example

# config/dev.exs
config :ash_dispatch,
  skip_email_delivery: true

sms_backend()

@spec sms_backend() :: module() | nil

The SMS backend module — should implement AshDispatch.SMSBackend. Returns nil when no backend is configured, in which case the SMS transport marks receipts :skipped.

Example

config :ash_dispatch,
  sms_backend: MyApp.SMS

swoosh_mailer()

@spec swoosh_mailer() :: module() | nil

The Swoosh mailer module (when using Swoosh backend).

url_builder()

@spec url_builder() :: module() | nil

The URL builder module for generating admin/source URLs.

Should implement admin_url/2, source_url/2, and optionally resource_label/1.

user_domain()

@spec user_domain() :: module() | nil

The domain containing the user resource.

user_module()

@spec user_module() :: module() | nil

The user module for recipient resolution and preferences.

Used by:

Example

config :ash_dispatch,
  user_module: MyApp.Accounts.User

user_preference()

@spec user_preference() :: module()

The user preference checker module.

Defaults to AshDispatch.UserPreference.Default which allows all notifications.

user_resource()

@spec user_resource() :: module() | nil

The user resource module (alias for user_module for clarity in some contexts).