Using the admin portal
The admin portal (admin/) is a React/TypeScript SPA against the
Admin API — publisher/key management, policies, event catalog,
delivery and subject feeds, RBAC, the tenant registry (platform operators only),
process-local metrics, and a redacted-by-design view of the deployment's adapter
profile. Build output is static (dist/).
Running it
cd admin
npm ci
npm run build # static output in dist/
npm test # unit/component tests
npx playwright install chromium
npm run test:e2e # browser tests (fixture-based)
For local development against a running cns-server:
CNS_DEV_API=http://127.0.0.1:8080 npm run dev
The dev server proxies /admin/v1 to that API — this is a development convenience,
not a production deployment path.
Hosting
Serve dist/ on an HTTPS origin with /admin/v1/* reverse-proxied to CNS. Never put
API secrets, SSO signing secrets, or tenant overrides into the browser build — the
portal is a thin client over the Admin API; every authorization decision is
re-checked server-side. API requests are same-origin only, with redirect-following
and browser cookies disabled; tokens live in memory only, and a 401 response
invalidates the active session immediately.
GET /admin/v1/me is the portal's source of truth for the signed-in caller's
subject_id/tenant_id/roles — the UI never infers permissions by decoding the
JWT client-side. UI-level restrictions are supplemental; the API is the actual
authority.
Embedding in another product
The standalone entry provides its own token-entry screen. To embed the portal inside
an existing authenticated product instead, obtain that product's already-authenticated
access token, construct new ApiClient(accessToken), call
validateSession(await api.get('/me')), and mount
<App api={api} session={session} onLogout={signOut} /> (import src/styles.css
once). CNS's identity adapter must actually be configured to verify that token's
issuer/signature and map its claims to the right tenant/subject first — a working
sign-in flow in the host product does not, by itself, configure this server-side
integration. See Wiring a non-native IdP if the host product
authenticates via something other than CNS's default SSO-JWT shape.
Modules
| Module | What it covers |
|---|---|
| Overview | Process-local counters: events processed, notification attempts, distinct active actors since server start. Not delivery receipts, and reset on restart. |
| App registry | Register/edit/delete publishers, view public keys, confirm key rotation. |
| Policies | Notification intent, delivery lane, channels, extra recipients per event_type. |
| Event catalog | Descriptions and JSON Schemas, with the current ingestion-validation limitation stated in the UI. |
| Delivery log & feed inspector | Filtered event browsing, cursor pagination, event detail, confirmed replay. Requires explicit tenant-admin. |
| Access | Tenant-admin and subscribe-group grants (by tenant-admins); platform-operator grants (platform-operators only — holding platform-operator alone does not let you delegate tenant-admin or manage groups). Publish permissions live in the app registry, not here. |
| Tenants | Platform-operator only: registration/edit/delete, with non-cascading deletion explained in the UI. |
| Deployment profile | Adapter implementation names only — raw settings are never rendered, by design. |
| Activity / Audit | Actor-keyed timeline and filterable admin-action log, each with opaque cursor pagination. Both require explicit tenant-admin. |
Permission matrix
| Capability | Tenant admin | Platform operator only |
|---|---|---|
| Publisher keys, event catalog, notification policies | Own tenant | Current token-derived tenant |
| Aggregate process metrics and adapter names | Read | Read |
| Employee activity, feeds, event detail/replay, audit | Own tenant | Hidden, not requested |
| Tenant-admin and group grants | Own tenant | Denied |
| Platform-operator grants | Denied | Allowed |
| Tenant registry | Hidden | Manage |
Holding both roles grants both capability sets. A platform operator can never choose a different tenant in an ordinary request body — the one exception is the tenant registry itself.
:::caution Verification scope The portal's own test suite verifies real browser interactions against contract fixtures — it does not by itself certify a deployed SSO integration, real AWS key provisioning, ClickHouse delivery, or production authorization. Treat a green test suite as "the UI does what the contract says," not as an end-to-end production readiness signal. :::