analytics

package
v1.786.112 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 6, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package analytics mounts the Hanzo Cloud /v1/analytics/* surface: a native-Go, per-org analytics read API over the `hanzo` ClickHouse warehouse (the `datastore` cluster). It is the backend for the console Native Analytics module (unified-analytics.md §5) — two read lenses over one warehouse:

  • LLM lens (REAL today): hanzo.cloud_usage, the live per-org usage ledger the cloud o11y path already writes (requests, tokens, spend, models, errors).
  • Web/commerce lens (honest-empty until the collector emits): hanzo.events.

ONE ClickHouse client. This package does NOT open a second connection: it rides the SAME clickhouse-go/v2 client the ai subsystem's o11y ledger opens in the shared Bootstrap (ai/object.InitDatastore → object.DatastoreQuery). DRY: one transport, one pool, one set of KMS-injected DATASTORE_* creds — never hard-coded, never a second design.

TENANT ISOLATION is the security bar and is enforced SERVER-SIDE on every request. The org is c.Org() — the value SanitizeIdentity minted from the VALIDATED bearer owner claim (HIP-0026), never a client header — AND every request must carry a validated principal (c.User() set, which SanitizeIdentity sets ONLY for a verified bearer). This closes the Phase-1 "no-bearer + forged X-Org-Id direct-to-pod" cross-tenant read exactly as clients/s3 does. Every ClickHouse query binds the org POSITIONALLY (query.go llmWhere/eventsWhere), so a maxpower token can NEVER read another org's analytics.

Surface (all org-scoped; /v1 only; read-only):

GET /v1/analytics/overview     per-org KPIs (llm real; web/commerce honest-empty)
GET /v1/analytics/timeseries   requests/tokens/spend over time (hour|day buckets)
GET /v1/analytics/top          top models (real) + top products (honest-empty)
GET /v1/analytics/health       subsystem health (datastore connectivity + lens tables)

Registered as "analyticssvc" (NOT "analytics") + order 132: the name diverges from the /v1/analytics route prefix so serve.go's generic GET /v1/<name>/health liveness route parks at /v1/analyticssvc/health and our REAL /v1/analytics/health (below) owns the probe — the same health-shadow-avoidance the kmssvc/s3svc subsystems use. Order 132 binds /v1/analytics/* before the ai subsystem's /v1/* catch-all (150).

Pure core of the analytics lens: SQL predicate builders, ClickHouse value coercers, and the pure assemblers that turn raw ClickHouse rows into the response structs. Everything here is I/O-free so the tests drive it with mock rows — no ClickHouse needed — exactly as ai/object/cloud_usage.go proves out its Overview assembler. The handlers (analytics.go) are the thin orchestration that fetches the rows and calls these.

THE ONE TENANCY INVARIANT lives here: llmWhere / eventsWhere ALWAYS emit "… = ?" with the org bound POSITIONALLY (never interpolated), so no query this package builds can read a tenant other than the caller's, and a hostile org slug can never escape into SQL. The isolation test asserts this directly.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Mount

func Mount(app *zip.App, deps cloud.Deps) error

Mount wires the analytics surface onto app per HIP-0106.

Types

type CommerceOverview

type CommerceOverview struct {
	Available bool    `json:"available"`
	Reason    string  `json:"reason,omitempty"`
	Orders    int64   `json:"orders"`
	Revenue   float64 `json:"revenue"`
	AOV       float64 `json:"aov"` // revenue/orders
	Source    string  `json:"source"`
}

CommerceOverview is the commerce lens over hanzo.events. Honest-empty until commerce emits order events.

type LLMOverview

type LLMOverview struct {
	Available        bool    `json:"available"`
	Requests         int64   `json:"requests"`
	Tokens           int64   `json:"tokens"`
	PromptTokens     int64   `json:"promptTokens"`
	CompletionTokens int64   `json:"completionTokens"`
	SpendCents       int64   `json:"spendCents"`
	Models           int64   `json:"models"`
	Providers        int64   `json:"providers"`
	Errors           int64   `json:"errors"`
	ErrorRate        float64 `json:"errorRate"` // 0..1, errors/requests
	Source           string  `json:"source"`
}

LLMOverview is the flagship lens: real per-org KPIs from hanzo.cloud_usage.

type ModelRow

type ModelRow struct {
	Model      string  `json:"model"`
	Provider   string  `json:"provider"`
	Requests   int64   `json:"requests"`
	Tokens     int64   `json:"tokens"`
	SpendCents int64   `json:"spendCents"`
	Pct        float64 `json:"pct"` // share of total spend, 0..100
}

type Overview

type Overview struct {
	Range    string           `json:"range"`
	Start    string           `json:"start"`
	End      string           `json:"end"`
	Interval string           `json:"interval"`
	Scope    Scope            `json:"scope"`
	LLM      LLMOverview      `json:"llm"`
	Web      WebOverview      `json:"web"`
	Commerce CommerceOverview `json:"commerce"`
}

type ProductRow

type ProductRow struct {
	ProductID string  `json:"productId"`
	Orders    int64   `json:"orders"`
	Revenue   float64 `json:"revenue"`
	Units     int64   `json:"units"`
}

type Scope

type Scope struct {
	Org string `json:"org"`
}

type SeriesPoint

type SeriesPoint struct {
	T          string `json:"t"` // RFC3339 bucket start (UTC)
	Requests   int64  `json:"requests"`
	Tokens     int64  `json:"tokens"`
	SpendCents int64  `json:"spendCents"`
}

type Timeseries

type Timeseries struct {
	Range    string        `json:"range"`
	Start    string        `json:"start"`
	End      string        `json:"end"`
	Interval string        `json:"interval"`
	Scope    Scope         `json:"scope"`
	Series   []SeriesPoint `json:"series"`
	Source   string        `json:"source"`
}

type Top

type Top struct {
	Range    string      `json:"range"`
	Start    string      `json:"start"`
	End      string      `json:"end"`
	Scope    Scope       `json:"scope"`
	Models   TopModels   `json:"models"`
	Products TopProducts `json:"products"`
}

type TopModels

type TopModels struct {
	Available bool       `json:"available"`
	Items     []ModelRow `json:"items"`
	Source    string     `json:"source"`
}

type TopProducts

type TopProducts struct {
	Available bool         `json:"available"`
	Reason    string       `json:"reason,omitempty"`
	Items     []ProductRow `json:"items"`
	Source    string       `json:"source"`
}

type WebOverview

type WebOverview struct {
	Available bool   `json:"available"`
	Reason    string `json:"reason,omitempty"`
	Pageviews int64  `json:"pageviews"`
	Visitors  int64  `json:"visitors"`
	Sessions  int64  `json:"sessions"`
	Source    string `json:"source"`
}

WebOverview is the web lens over hanzo.events. Honest-empty (Available=false) until the collector emits web events.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL