Skip to main content

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

ModuleWhat it covers
OverviewProcess-local counters: events processed, notification attempts, distinct active actors since server start. Not delivery receipts, and reset on restart.
App registryRegister/edit/delete publishers, view public keys, confirm key rotation.
PoliciesNotification intent, delivery lane, channels, extra recipients per event_type.
Event catalogDescriptions and JSON Schemas, with the current ingestion-validation limitation stated in the UI.
Delivery log & feed inspectorFiltered event browsing, cursor pagination, event detail, confirmed replay. Requires explicit tenant-admin.
AccessTenant-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.
TenantsPlatform-operator only: registration/edit/delete, with non-cascading deletion explained in the UI.
Deployment profileAdapter implementation names only — raw settings are never rendered, by design.
Activity / AuditActor-keyed timeline and filterable admin-action log, each with opaque cursor pagination. Both require explicit tenant-admin.

Permission matrix

CapabilityTenant adminPlatform operator only
Publisher keys, event catalog, notification policiesOwn tenantCurrent token-derived tenant
Aggregate process metrics and adapter namesReadRead
Employee activity, feeds, event detail/replay, auditOwn tenantHidden, not requested
Tenant-admin and group grantsOwn tenantDenied
Platform-operator grantsDeniedAllowed
Tenant registryHiddenManage

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. :::