Threadline.OperatorSurface.Router (Threadline v1.0.0)

Copy Markdown View Source

Mounts Threadline's operator interface in a Phoenix router with host-owned authorization and query scoping.

This module enforces a secure-by-default mount by requiring either:

  1. A pipe_through directive in the enclosing router scope.
  2. An explicit :authorize_fn option.
  3. An explicit :adopter_acknowledges_unauthenticated option.

HTTP endpoints

When Phoenix is available at compile time, the macro emits a sibling POST <path>/theme route and a sibling scope <path>/exports block with GET routes for /changes.csv, /changes.json, /changes.ndjson, and completed export downloads. These HTTP endpoints use the mount's authorization callbacks independently from the LiveView session.

The HTTP scopes remain outside live_session :threadline because LiveView on_mount callbacks do not apply to controller routes. Route helper names and the host router's alias namespace remain untouched.

Summary

Functions

Adds the Threadline operator LiveView and sibling HTTP routes to the host router.

Functions

threadline_operator_surface(path, opts \\ [])

(macro)

Adds the Threadline operator LiveView and sibling HTTP routes to the host router.

The macro requires a secure enclosing pipeline, :authorize_fn, or an explicit acknowledgement that the mount is unauthenticated.

Mount options

  • :exports — boolean; defaults to true. Set to false to suppress the sibling export-controller scope (rare LV-only adopters).
  • :scope_query_fn — (Ecto.Query.t(), scope, %{surface: atom(), params: map()} -> Ecto.Query.t()); optional. This host-owned query transform is used when :authorize_fn returns {:ok, scope}. Threadline treats scope as opaque data and calls this function for timeline, actor-history, transaction, and export flows.
  • :export_authorize_fn — (Plug.Conn.t() -> :ok | true | {:ok, scope} | _); defaults to delegating to :authorize_fn via a synthetic %{assigns: conn.assigns} mirror. Use a separate callback when HTTP authorization needs more than the assigns inspected by the LiveView callback; the synthetic mirror is sufficient when authorization only reads values such as assigns.current_user.

  • :coverage_authorize_fn — (%{assigns: map()} -> boolean | :ok | {:ok, scope} | _); optional. Explicitly gates the coverage dashboard and related badge, and defaults to fail closed.

  • :policy_authorize_fn — (%{assigns: map()} -> boolean | :ok | {:ok, scope} | _); optional. Explicitly gates policy and retention surfaces, and defaults to fail closed.

  • :evidence_authorize_fn — (%{assigns: map()} -> boolean | :ok | {:ok, scope} | _); optional. Explicitly gates the mounted evidence surface, and defaults to fail closed.

  • :theme — :dark | :light | :system; defaults to :dark. Selects the default server-rendered operator-surface theme lane. :system follows the visitor's OS preference through scoped CSS only. A runtime dark/light/system theme picker is available in the shell (session-backed and resolved server-side; a response cookie mirrors the choice); Threadline adds no JavaScript and no local storage.