MailglassAdmin.Router (MailglassAdmin v1.0.0)

Copy Markdown View Source

Preview and operator dashboard mounts.

This module is the stable v1.x admin router seam. The contract covers the two mount macros and their documented options. It does not freeze internal LiveView module names, DOM shape, CSS classes, or internal mount-hook implementation details.

Usage

import MailglassAdmin.Router

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

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",
      recent_auth_at: "recent_auth_at"
    ]
end

Restart mix phx.server, visit /dev/mail, done. Zero endpoint.ex edits.

Options

  • mailglass_admin_routes/2

    • :mailables:auto_scan (default) or explicit list [MyApp.UserMailer, ...]. :auto_scan walks :application.get_key/2 across loaded apps and keeps modules that use Mailglass.Mailable. Explicit lists bypass the scan.
    • :on_mount — Extra on_mount hooks appended BEFORE the internal MailglassAdmin.Preview.Mount hook.
    • :live_session_name — Name of the preview live_session (default :mailglass_admin_preview). Rename to resolve collisions with an adopter live_session of the same name.
    • :as — Route helper prefix (default :mailglass_admin).
  • mailglass_operator_routes/2

    • :auth — adopter-owned module that implements MailglassAdmin.Auth
    • :session — explicit session-key whitelist for :subject_id, :tenant_id, :auth_method, and :recent_auth_at
    • :on_mount — Extra on_mount hooks appended BEFORE the internal MailglassAdmin.Operator.Mount hook
    • :live_session_name — Name of the operator live_session (default :mailglass_admin_operator)
    • :unauthorized_path — redirect target when operator access is denied
    • :as — Route helper prefix (default :mailglass_admin)

Every documented opt is part of the stable router contract once shipped; the rest of the implementation remains internal.

Dev-only enforcement

mailglass_admin_routes/2 does NOT enforce :dev — wrapping the mount in if Application.compile_env(:my_app, :dev_routes) do ... end is the ADOPTER's job, matching the Phoenix 1.8 mix phx.new-generated router idiom. Mix.env() is unreliable in release builds (always :prod); keeping dev-enforcement in adopter code means preview remains a README concern rather than a breaking macro change.

Does NOT do

  • Mix.env() checks in the macro body (unreliable in releases)
  • Pass conn.private.plug_session into LiveView assigns (would leak adopter cookies; __session__/2 builds a whitelisted map)
  • Register any named GenServer (name: __MODULE__ is banned in library code per CLAUDE.md)

Summary

Functions

Mounts the preview dashboard at path.

Mounts the production operator dashboard at path.

Functions

mailglass_admin_routes(path, opts \\ [])

(since 0.1.0) (macro)

Mounts the preview dashboard at path.

Expands to a scope containing asset routes (compile-time served via MailglassAdmin.Controllers.Assets) and a live_session with MailglassAdmin.PreviewLive. Session isolation is provided by the whitelisted __preview_session__/2 callback.

Example

scope "/dev" do
  pipe_through :browser
  mailglass_admin_routes "/mail"
end

Unknown opts

Raises ArgumentError at compile time with a message starting invalid opts for mailglass_admin_routes/2.

mailglass_operator_routes(path, opts \\ [])

(since 0.1.0) (macro)

Mounts the production operator dashboard at path.

The operator surface has its own live_session, its own whitelisted session callback, and an internal MailglassAdmin.Operator.Mount authorization seam. Adopter-owned auth hooks may run before the internal mount hook via :on_mount.

Stable contract:

  • :auth points to an adopter-owned MailglassAdmin.Auth implementation
  • :session is an explicit whitelist, not a pass-through of the whole Plug session
  • authorization semantics are stable, but the internal mount module and UI implementation are not