Skip to content

Overview

The analytics layer exposes six reports. Each report is computed from the in-memory index on every request. No SDK calls occur after the initial fetch.

Reports

ReportEndpointPurpose
Blast radiusGET /api/v1/analytics/blast-radius?id=&type=Impact set of a connector group or server group.
Policy shadowsGET /api/v1/analytics/policy-shadowsPolicy pairs covering the same (SCIM group, segment) pair.
Orphan clustersGET /api/v1/analytics/orphan-clustersSegments with no policy coverage, grouped by segment group.
Domain overlapsGET /api/v1/analytics/domain-overlapsHostnames that appear in more than one segment.
Connector loadGET /api/v1/analytics/connector-loadPer-connector-group counts of policies, segments, and SCIM groups served.
SCIM reachGET /api/v1/analytics/scim-reachPer-SCIM-group counts of policies, segment groups, and segments granted.

Common shape

Most reports use NamedRef:

type NamedRef struct {
ID string `json:"id"`
Name string `json:"name"`
}

When a referenced name cannot be resolved (deleted or stale reference), Name falls back to ID. Entries are never dropped silently.

Refresh model

Reports run against the memoized *index.Index on *Server. A background warmer (StartIndexWarmer) rebuilds the index every 4 minutes on a 5-minute TTL, so handlers almost always hit a warm index. singleflight coalesces concurrent rebuilds.

Each BuildIndex reads through the per-resource caches in internal/fetcher. Each resource has its own TTL (5 minutes for volatile resources, 1 hour for stable ones). Fetcher cache misses trigger an SDK refetch on the request that hits the miss; concurrent callers after expiry collapse to one fetch via double-checked locking.

POST /api/v1/refresh forces both layers to reload on demand (30-second global throttle). See Architecture for layer detail and Roadmap for remaining proactive-refresh work at the fetcher layer.