Runbooks/Admin Hub

Admin Hub — Real-time SignalR Push to the Admin UI

The Admin Hub is a SignalR fan-out channel that lets the Admin UI surface operator-relevant events the moment they happen, instead of waiting for the next page refresh or scheduled poll. It complements the Notification Center (bell-icon dropdown + transient toaster): incoming push events are translated into notifications, so the bell counter, dropdown list, and toaster all light up automatically with no per-component wiring.

This document is the operator-side reference for the channel.

Phase status

Endpoint

GET (negotiate) wss://<api>/hubs/admin

Event types

run.completed

Fires when a RunHistory row transitions to Completed or Failed.

{
  "runId":          "<guid>",
  "connectorId":    "<guid>",
  "connectorName":  "Entra Production",
  "status":         "Completed",        // or "Failed"
  "addedCount":     12,
  "updatedCount":   3,
  "deletedCount":   0,
  "errorMessage":   null                // populated on Failed
}

UI behaviour: success notification when status === "Completed", error notification when status === "Failed". Click-through goes to /identity/connectors?id=<connectorId>.

audit.appended

Fires when a new row is appended to IM_AdminAudit or IM_ObjectAudit.

{
  "table":    "admin",                 // or "object"
  "auditId":  4711,
  "when":     "2026-04-26T14:32:09Z",
  "action":   "ConnectorCreate",
  "actor":    "CONTOSO\\jdoe"
}

UI behaviour: info notification; click-through goes to /identity/audit.

relay.status_changed

Fires when a relay agent connects, disconnects, or its heartbeat times out (the Admin API’s relay monitor marks a relay offline after RelayAgents:HeartbeatTimeoutSeconds).

{
  "agentId":   "<guid>",
  "agentName": "London-DC1",
  "status":    "Online",                // or "Offline"
  "timestamp": "2026-04-26T14:32:09Z"
}

UI behaviour: info on Online, warning on Offline; click-through goes to /identity/operations (the Ops Center page that hosts the relay-agent table).

connector.error

Fires when a connector run hits a terminal error (i.e. the engine short-circuits before producing a run.completed).

{
  "connectorId":   "<guid>",
  "connectorName": "Workday HR",
  "error":         "Token endpoint returned 401",
  "occurredAt":    "2026-04-26T14:32:09Z"
}

UI behaviour: error notification, sticky by default — operator must acknowledge it in the bell dropdown before it dismisses, so a transient connector failure can’t be missed by an inattentive eye. Click-through goes to /identity/connectors?id=<connectorId>.

End-to-end verification

A small operator-only test endpoint lets you confirm the channel works without waiting for a real run:

POST /api/admin/hub/test
Authorization: Negotiate <ticket>     # or Bearer <jwt>

Returns {"fired": true} and emits a single synthetic connector.error event. Any UI client currently subscribed to /hubs/admin will pop a sticky red toast titled “Connector error — DEMO” and add a matching entry to the bell dropdown.

curl example (Negotiate)

curl -X POST --negotiate -u : \
  https://identitymesh.contoso.com/api/admin/hub/test

curl example (Bearer / JWT)

curl -X POST \
  -H "Authorization: Bearer $TOKEN" \
  https://identitymesh.contoso.com/api/admin/hub/test

If you get a 401 or 403, the calling identity doesn’t have the audit.read permission — assign it through Roles or via the Roles mapping config and retry.

Auth model

The hub mirrors the rest of the API surface; there’s no separate configuration:

CORS

The Admin API’s CORS policy covers /hubs/* already (credentials allowed + the configured origin list); no hub-specific CORS configuration is needed. Update IdentityMesh:CorsOrigins in appsettings.json when deploying the UI to a new origin.

Operational notes

Cross-references