mailglass_admin

Mountable LiveView surfaces for mailglass. Today that means:

The operator surface is delivery-centric. It helps an authenticated operator inspect provider lifecycle facts, replay facts, and reconcile facts for one selected delivery. The canonical support runbook lives in guides/operator-incident-support.md.

API Stability

The canonical operator trust contract lives in docs/operator-trust.md.

The canonical v1.x admin surface inventory lives in docs/api_stability.md.

The canonical matched-sibling compatibility and deprecation policy lives in the core repo guide ../guides/compatibility-and-deprecations.md and is re-exposed here through docs/compatibility-and-deprecations.md.

The trust contract is intentionally narrow:

Do not treat ExDoc visibility, public function reachability, or framework callback exports as the contract by themselves.

Use docs/operator-trust.md for the stable router/auth/session/replay semantics. Use the compatibility guide for release-line matching, support-matrix truth, retained compatibility bridges, and upgrade posture. Use the admin stability page only for the package surface inventory.

Installation

Add mailglass_admin to your adopter app's mix.exs:

def deps do
  [
    {:mailglass, "~> 0.3"},
    {:mailglass_admin, "~> 0.3", only: :dev}
  ]
end

Then mix deps.get.

Mount the dev preview

Add four lines to lib/my_app_web/router.ex:

import MailglassAdmin.Router

if Application.compile_env(:my_app, :dev_routes) do
  scope "/dev" do
    pipe_through :browser
    mailglass_admin_routes "/mail"
  end
end

Restart mix phx.server, visit /dev/mail. Done.

The if Application.compile_env(:my_app, :dev_routes) do ... end wrapper is the Phoenix 1.8 convention (same gate that protects live_dashboard and Plug.Swoosh.MailboxPreview). mailglass_admin does not check Mix.env() itself — dev-only is the adopter's responsibility.

Mount the production operator surface

Import the same router helpers, but mount the operator surface inside your normal authenticated browser scope:

import MailglassAdmin.Router

scope "/ops" do
  pipe_through [:browser, :require_authenticated_user]

  mailglass_operator_routes "/mail",
    auth: MyApp.MailglassAdminAuth,
    session: [
      subject_id: "current_user_id",
      tenant_id: "current_tenant_id",
      auth_method: "auth_method",
      recent_auth_at: "recent_auth_at"
    ],
    on_mount: [{MyAppWeb.UserAuth, :require_authenticated_user}],
    unauthorized_path: "/users/log-in"
end

auth: stays adopter-owned. mailglass_admin does not ship a login system, session schema, or recent-auth prompt. It expects your app to decide who may enter the operator surface and how "recent authentication" is satisfied.

Operator replay contract

The operator surface now supports targeted webhook replay from the selected delivery detail pane.

Operator support boundary

LiveReload setup (optional)

When your adopter app runs under :phoenix_live_reload, mailglass_admin can refresh the preview automatically on file save. Add a live_reload.notify entry to your endpoint:

config :my_app, MyAppWeb.Endpoint,
  live_reload: [
    notify: [
      "mailglass:admin:reload": [~r"lib/.*mailer.*\.ex$"]
    ]
  ]

The topic is prefixed mailglass:admin:reload (not bare mailglass_admin_reload) to match the package's mailglass:-prefixed PubSub naming convention. When LiveReload is not configured the preview still works — the adopter just refreshes the browser manually.

preview_props/0 contract

Each Mailglass.Mailable module can declare preview scenarios by defining preview_props/0:

defmodule MyApp.UserMailer do
  use Mailglass.Mailable, stream: :transactional

  def preview_props do
    [
      welcome_default: %{user: %User{name: "Ada"}, team: %Team{name: "Analytical Engines"}},
      welcome_enterprise: %{user: %User{name: "Ada"}, team: %Team{name: "Analytical Engines"}, plan: :enterprise}
    ]
  end

  def welcome(assigns), do: ...
end

Each tuple is a discrete scenario; the sidebar nests scenarios under the mailable module name (MyApp.UserMailer -> welcome_default). Scenarios appear in insertion order. Mailables without preview_props/0 still show up in the sidebar as No previews defined — they remain discoverable even before you write any scenarios.

What this ships

What this does NOT ship

License

MIT. Released alongside mailglass via coordinated linked-version Release Please tags.