The single authoritative write site for "set the active organization".
Every Phase 14+ call site that needs to set, clear, or change the active
organization funnels through this function: login (Plan 03), the switcher
controller (Phase 16), invitation accept (Phase 17), stale-pointer recovery
inside Sigra.Plug.LoadActiveOrganization, and the backfill upgrade
(Phase 18). No ad-hoc Plug-session writes. No direct ecto updates on
user_sessions. No shortcuts.
This function is not a Plug call/2 — it is a function-call contract
invoked from controllers, other plugs, and the login entry point. It takes
a Plug.Conn, an Organization struct (or nil to clear), and an opts
keyword list, and returns {:ok, updated_conn} or {:error, reason}.
Writes performed
user_sessions.active_organization_idcolumn (via the configuredSigra.SessionStoreimplementation'supdate_active_organization/3callback).conn.private[:sigra_session](refreshed with the updated struct).conn.assigns[:current_scope](via the host scope module'sput_active_organization/3— D-15).
Writes explicitly NOT performed
- Plug session cookie writes — no mirror of the DB column into the cookie session (D-03/D-17).
- Session token rotation / session renewal — a scope transition is NOT a trust transition (D-18).
Authorization (T-14-06)
Before any write, call/3 verifies the user's membership in the target
organization via Sigra.Organizations.get_membership/3. If nil, the
function returns {:error, :not_a_member} without calling the
SessionStore's update_active_organization/3 callback. The SessionStore
callback itself does not enforce authz (see Phase 14 T-14-04).
Options
:organizations— required. The host'suse Sigra.Organizationsmodule exposing__sigra_org_config__/0.:session_store— required. Module implementingSigra.SessionStore.:scope_module— required. The host scope module whoseput_active_organization/3builds the updated scope struct (D-15).:session_store_opts— optional keyword list forwarded to the session store callback (e.g.[repo: MyApp.Repo]). Defaults to[].
Summary
Functions
Set, change, or clear the active organization on the caller's session.
Returns {:ok, updated_conn} on success or {:error, reason} on failure.
Types
@type call_error() :: :not_a_member | :no_session | :no_scope | term()
Functions
@spec call(Plug.Conn.t(), struct() | nil, keyword()) :: {:ok, Plug.Conn.t()} | {:error, call_error()}
Set, change, or clear the active organization on the caller's session.
Returns {:ok, updated_conn} on success or {:error, reason} on failure.
Returns {:error, :no_session} if no %Sigra.Session{} has been stashed
at conn.private[:sigra_session] (the FetchSession plug has not run, or
the user is not logged in). Returns {:error, :no_scope} if
conn.assigns[:current_scope] is missing or has a nil :user. Both
errors are fail-closed: the request does not crash and no write is
performed.