# `Cairnloop.Router`
[🔗](https://github.com/szTheory/cairnloop/blob/main/lib/cairnloop/router.ex#L1)

Host-router macros for mounting Cairnloop's operator surfaces.

Cairnloop is host-owned: you mount its operations endpoints and operator dashboard into
*your* router, under *your* pipelines, so auth, session, layout, and route placement stay
yours. See `cairnloop_operations/1` and `cairnloop_dashboard/2`.

# `cairnloop_dashboard`
*macro* 

Mounts the Cairnloop operator dashboard (inbox, conversations, knowledge base, settings, and
the audit-log timeline) under `path` as a single `Phoenix.LiveView` `live_session`.

Wrap it in your own `scope` so auth/session/layout stay host-owned — Cairnloop does not embed
auth:

    scope "/support" do
      pipe_through [:browser, :require_admin]

      cairnloop_dashboard "/",
        on_mount: [{MyAppWeb.UserAuth, :ensure_admin}],
        session: {MyAppWeb.UserAuth, :cairnloop_session, []}
    end

## Operator identity (`host_user_id`)

Cairnloop uses the `host_user_id` value in the live session as the **operator's identity** — it
is the actor recorded on governed audit events and the scope key for operator search. Provide it
through the `:session` option, and use the **MFA form** so each request carries the *actually
signed-in* operator:

    def cairnloop_session(conn) do
      %{"host_user_id" => to_string(conn.assigns.current_user.id)}
    end

A static `session: %{"host_user_id" => "demo_operator"}` map is fine for a single-operator demo,
but it is frozen at compile time and is identical for every request — ship it and your audit log
attributes every operator's actions to one placeholder id. See the
[Auth & Operator Identity](07-auth-and-operator-identity.html) guide for the full pattern.

Any option other than the Cairnloop-specific ones below is forwarded verbatim to
`Phoenix.LiveView.Router.live_session/3` (e.g. `:session`, `:on_mount`, `:root_layout`,
`:layout`).

## Options

* `:live_session_name` (`t:atom/0`) - Name of the generated `live_session`. Override when mounting the dashboard more than once in a single host router, so the two `live_session` names do not collide. The default value is `:cairnloop_dashboard`.

# `cairnloop_operations`
*macro* 

Mounts the operations endpoints a host needs for monitoring (OPS-01, OPS-02):

  - `GET /health` → `Cairnloop.Web.HealthPlug` (liveness/readiness probe, 200 JSON).
  - `GET /metrics` → `Cairnloop.Web.MetricsPlug` (Prometheus text; 501 until
    `:telemetry_metrics_prometheus_core` is added).

Call it from your host router, typically outside any authentication pipeline so
infrastructure can reach the probes:

    scope "/" do
      cairnloop_operations()
    end

## Options

* `:health_path` (`t:String.t/0`) - Path the `/health` liveness probe is mounted at. The default value is `"/health"`.

* `:metrics_path` (`t:String.t/0`) - Path the `/metrics` Prometheus scrape endpoint is mounted at. The default value is `"/metrics"`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
