core

package
v1.801.470 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package core is the shared kernel of the admin subsystem: the resolved upstream clients (State) plus the one-copy business primitives every admin domain composes — the two-tier gate, the /v1 envelope writers, the tenant-scope predicate, the IAM fan-in, the single credit-grant path, the tamper-evident audit emit, and the fleet activity/time-series model. Each primitive lives EXACTLY once here; the domain packages (audit/customer/revenue/finance) and the top-level admin Mount import it, never duplicating a helper — there is one path to grant, one read, one scope rule.

Index

Constants

View Source
const (
	OK  = "ok"
	Err = "error"
)

The two states of the /v1 envelope every admin op answers with ({ status, msg, data, total } — the operator transport's get<T>/getList<T> shape). The transport surfaces anything that is not OK as an error, never a value, so a failed read is a 200 carrying Err — NOT an HTTP error status.

View Source
const (
	EvSubscriptionCreated     = "subscription_created"
	EvSubscriptionRenewed     = "subscription_renewed"
	EvSubscriptionPlanChanged = "subscription_plan_changed"
	EvSubscriptionCanceled    = "subscription_canceled"
	EvInvoiceFinalized        = "invoice_finalized"
	EvInvoicePaid             = "invoice_paid"
	EvInvoiceVoid             = "invoice_void"
	EvAPIUsageDebit           = "api_usage_debit"
)

Canonical customer-activity event names — the CONTRACT with the commerce emitters (events/client.go). These are server-side constants (never user input), so rendering them into an IN (...) list is injection-safe.

View Source
const BillingEventsTable = "commerce.events"

BillingEventsTable is the collector-owned warehouse table the commerce customer-activity emitters land in (events/client.go → analytics-collector → commerce.events). admin only READS it (never creates it — the collector owns its writes), exactly as o11y reads hanzo.cloud_usage.

View Source
const MaxCustomerConcurrency = 8

MaxCustomerConcurrency bounds the per-org enrichment fan-out so a large fleet does not open one upstream connection per org at once. Admin is low-QPS; 8 keeps latency low without hammering IAM/commerce.

Variables

SubscriptionEvents / InvoiceEvents are the lifecycle sets each fleet view folds over (latest-event-wins per entity). Closed server-side constants.

View Source
var ErrPartialRevenue = errors.New("partial: one or more org revenue reads failed")

ErrPartialRevenue marks a revenue read that succeeded at the org-list level but had one or more per-org failures — the fleet total is real but PARTIAL. SrcOf reports it as a not-ok source so the console shows a degraded state rather than presenting an under-count as authoritative.

Functions

func Admit

func Admit(ctx context.Context) (*zip.Ctx, error)

Admit is the SuperAdmin gate, called once at the top of every PLATFORM op. It is the same fail-closed predicate the old Guard wrapper applied: a request whose validated identity is not a SuperAdmin (principal.IsSuperAdmin — X-User-IsAdmin, which SanitizeIdentity sets only for owner == AdminOrg) is refused 403 before any upstream is touched.

It gates on that ONE fact, not the platform's cloud.Super scope, which also requires principal.Validated: the cockpit's second tier (AdmitScoped) and its org-scoped reads resolve a SuperAdmin off the admin bit alone, so requiring the conjunct here would give one surface two admin rules.

It returns the request because an admitted op almost always needs it — to replay the caller's credential to IAM, or to read the body a passthrough forwards verbatim.

func AdmitScoped

func AdmitScoped(ctx context.Context, s *cloud.Service[State]) (*zip.Ctx, error)

AdmitScoped is the gate for the ORG-SCOPED panels, called once at the top of each. It admits a SuperAdmin (principal.IsSuperAdmin) OR an admin of an ENABLED WHITE-LABEL TENANT org — three facts, ALL required for that second tier:

  • X-User-IsOrgAdmin (principal.IsOrgAdmin — "admin of my own org", unforgeable because SanitizeIdentity strips it on ingress and re-mints it only from a validated isAdmin claim), AND
  • a validated principal pinned to its own org (principal.Org: validated X-User-Id + non-empty in-bounds X-Org-Id, never client-chosen), AND
  • that org is an ENABLED WL tenant (State.IsWhiteLabelTenant — the fail-closed allowlist; empty/unset ⇒ SuperAdmins only).

Passing this gate is not the end of the scoping: the handler then folds every read through ResolveScope/ScopedOrgs, which hard-limits a non-super caller to their own org subtree whatever the request says.

func BillingEventsReady

func BillingEventsReady(ctx context.Context) bool

BillingEventsReady reports whether the warehouse is connected AND the collector's commerce.events table is provisioned — the two-part gate every billing fleet view opens with, so an unwired collector degrades to an honest empty aggregate rather than an error.

func BucketKeyOf

func BucketKeyOf(t time.Time, interval string) string

func CHFirstRow

func CHFirstRow(rows []map[string]any) map[string]any

CHFirstRow returns the first row or an empty map (never nil), so a parser reads honest zeros from an empty result instead of panicking.

func CHInt64

func CHInt64(v any) int64

func CHStr

func CHStr(v any) string

func CHTableExists

func CHTableExists(ctx context.Context, qualified string) bool

CHTableExists probes the datastore for a table's presence. The name is a package constant (never user input), so EXISTS TABLE is safe. Any error → false (honest "not available yet"), mirroring compute.computeTableExists.

func CHTime

func CHTime(v any) string

CHTime coerces a datastore DateTime (time.Time) to an RFC3339 UTC string.

func CHTimeLit

func CHTimeLit(t time.Time) string

CHTimeLit formats a time as a datastore DateTime literal (UTC), bound as a POSITIONAL string arg (never interpolated).

func CallerCreds

func CallerCreds(c *zip.Ctx) iam.Creds

CallerCreds captures the caller's replayed authorization context for the IAM fan-out: the raw Cookie header (session model) and the Authorization bearer.

func DayKey

func DayKey(t time.Time) string

func Descendants

func Descendants(s *cloud.Service[State], org string) []string

Descendants returns org + every sub-org it owns — the subtree the caller administers. See the RECURSION SEAM note above: today the singleton {org}; the ONE place a future IAM parent-org index is walked.

func Display

func Display(displayName, fallback string) string

Display returns displayName when non-blank, else the fallback.

func EmitAudit

func EmitAudit(s *cloud.Service[State], c *zip.Ctx, action, resType, resID string, before, after any, outcome audit.Outcome)

EmitAudit writes ONE compliance record for a management action to cloud's tamper-evident trail: who (the validated SuperAdmin from the sanitized identity — the gate already proved it), what (action + resource), the redacted before/after, and the outcome. This is the "before/after on a config-affecting change" the request-level middleware record cannot carry (it never reads bodies). Best-effort: a failure here is logged loud, never silent, and never double-fails the response. A nil store (unconfigured deployment) is a no-op, like the middleware.

func EnumerateBuckets

func EnumerateBuckets(since, now time.Time, interval string) []string

EnumerateBuckets lists every bucket key from since..now inclusive so a series has a continuous axis (a zero-usage bucket is an honest 0, not a gap).

func FindOrg

func FindOrg(s *cloud.Service[State], ctx context.Context, cr iam.Creds, org string) (*iam.Org, error)

FindOrg returns the IAM org by slug (nil, nil when it does not exist) so a management action can validate its target before acting — never credit or suspend an org that isn't real.

func IndexOf

func IndexOf(buckets []string) map[string]int

IndexOf maps each bucket key to its position for O(1) fold-in.

func ListOrgs

func ListOrgs(s *cloud.Service[State], ctx context.Context, cr iam.Creds) ([]iam.Org, error)

ListOrgs reads the org directory (owner = admin org) as the typed shape the overview/orgs/usage/customer/revenue/finance aggregators fold over.

func MonthKey

func MonthKey(t time.Time) string

func OrgMoney

func OrgMoney(s *cloud.Service[State], ctx context.Context, org string) (spend, credits int64, ok bool)

OrgMoney returns (spendCents, creditsCents, ok) for one org — the ONE per-org money read every fleet aggregator (overview, orgs, revenue) folds over. ok is false ONLY when a read FAILED, so a caller folds the per-org failure into a PARTIAL/degraded source rather than presenting the resulting undercount as authoritative. An org that simply has no money yet reads a clean (0, 0, true), never a failure.

CO-RESIDENCE (the money-plane trap). Commerce's own /v1/billing/* routes are behind `//go:build cloud` and are NOT compiled into this binary, so the admin commerce client's S2S reads self-dispatch by PATH into cloud's OWN handlers: GET /v1/billing/balance re-enters the customer balance handler with no principal (401) and GET /v1/billing/usage/rollup is unrouted (404). Reading commerce over HTTP would therefore fail for EVERY org and falsely mark the money source DOWN while real money sits in the co-resident ledger. So — exactly as clients/billing.balance()/usage() and core.grantDeposit already resolve it — prefer the co-resident finance ledger (finance.Current()); the commerce S2S read stays only as the split-deploy fallback.

func ParseTxnTime

func ParseTxnTime(s string) (time.Time, error)

ParseTxnTime accepts the commerce ledger's RFC3339 forms.

func SQLInList

func SQLInList(vals []string) string

SQLInList renders a set of server-side-constant strings as a datastore string list ('a','b',…) for an IN (...) clause. ONLY for closed constant sets (the event-name enums above) — never for user input; positional args carry all caller-derived values.

func ScopedOrgs

func ScopedOrgs(s *cloud.Service[State], ctx context.Context, c *zip.Ctx, cr iam.Creds) ([]iam.Org, error)

ScopedOrgs is the ONE fan-in the org-scoped read panels (overview, orgs, usage, analytics) fold over — enforcing the two-scope predicate in a single place. A SuperAdmin gets EVERY org (the cross-tenant list); any other caller gets ONLY their own subtree, each row read from IAM so the display name / createdTime are the REAL values. An org row that can't be read best-effort degrades to a name-only row rather than failing the panel — the scope is unaffected.

func Total

func Total(n int) *int

Total is the row count of a LIST read, as the pointer the envelope's optional total field takes. Present — even at zero — on a success; left nil on a failure, because a failed read has no count and adding the key would change the wire.

func WarehouseSince

func WarehouseSince(rangeLabel string) time.Time

WarehouseSince maps the ?range enum (24h|7d|30d, default 30d) to a lower time bound, mirroring compute.computeSince so the fleet views share ONE window grammar.

func WeekKey

func WeekKey(t time.Time) string

WeekKey buckets to the ISO week's Monday (a stable weekly key).

Types

type CreditRequest

type CreditRequest struct {
	AmountCents int64  `json:"amountCents"`
	Currency    string `json:"currency"`
	Reason      string `json:"reason"`
	// User names the MEMBER to credit, by IAM username — the `name` half of
	// "<org>/<name>". Empty credits the org itself.
	//
	// It exists because "the org" is not always the account a request spends from.
	// In the shared signup org, whose members are strangers to each other, each pays
	// from their OWN wallet; a grant keyed on the org alone lands in a pool that
	// member can neither spend nor see, while they are refused at $0. Which of the
	// two a grant lands on is NOT decided here — principal.WalletFor asks account.Payer,
	// the same rule the spend gate asks — so a pooled tenant org keeps one balance no
	// matter what is named, and a per-member org can finally be funded per member.
	User string `json:"user"`
	// Source splits the grant into the commerce ledger's two money buckets:
	//   - "trial"   (default) — a non-cash promo/comp credit: spendable on non-premium
	//                metered usage only, NEVER refundable cash and NEVER paid out.
	//   - "prepaid" — real money added to the customer's cash balance. Refundable,
	//                GPU-eligible.
	// Unknown/empty → trial (fail-closed to non-cash).
	Source string `json:"source"`
}

CreditRequest is the grant body. AmountCents is the credit to add (positive only — a grant, never a silent debit). Reason is the operator's justification, recorded in the audit trail's before/after (refund / comp / support).

type CustActivity

type CustActivity struct {
	Org        string
	Display    string
	Created    time.Time
	HasCreated bool
	Usage      []TxnPoint
	SpendCents int64
}

CustActivity is one customer's real analytics input: when they signed up (IAM createdTime) and their consumption events (commerce withdraws). Deposits are NOT activity (a credit grant is not the customer using the product), so only withdraws feed active/retention/churn/usage — the honest "used it" signal.

func FleetActivity

func FleetActivity(s *cloud.Service[State], ctx context.Context, orgs []iam.Org) ([]CustActivity, bool)

FleetActivity reads every org's signup time (already on the org row) + usage ledger, folded into the pure activity model. Returns (acts, ok) where ok is false if ANY org's ledger read failed (the caller marks the source degraded and flags the ledger-backed metrics as not-fully-computed). Fanned out concurrently with a bound.

func (CustActivity) ActiveIn

func (ca CustActivity) ActiveIn(bucket string, interval string) bool

ActiveIn reports whether the customer had a usage event in the given bucket.

func (CustActivity) ActiveSince

func (ca CustActivity) ActiveSince(cut time.Time) bool

ActiveSince reports whether the customer had a usage event at or after cut.

type GrantOut

type GrantOut struct {
	Status string       `json:"status"`
	Msg    string       `json:"msg"`
	Data   *GrantResult `json:"data"`
}

GrantOut is the envelope of every credit-grant op. There is one shape because there is ONE credit-write path.

func ApplyGrant

func ApplyGrant(s *cloud.Service[State], c *zip.Ctx, org string, req CreditRequest) (*GrantOut, error)

ApplyGrant validates the amount + target org, deposits into the org's commerce ledger (trial vs prepaid by source), and records the tamper-evident audit row. One path, one way to grant.

Two refusals carry a NON-200 status, set on c before the envelope is returned: an unknown org is 404, and a deployment with no durable audit store is 503. Both keep the envelope body — the status is the addition, not a different contract.

type GrantResult

type GrantResult struct {
	// Org is the tenant whose ledger was credited.
	Org string `json:"org"`
	// Subject is the ACCOUNT the credit landed on inside that ledger: the org slug for
	// a pooled org, "<org>/<name>" for a member of a per-member one. It is echoed
	// because the operator does not choose it — account.Payer does — so naming a
	// member of a pooled org credits the pool and the receipt has to say so.
	Subject string `json:"subject"`
	// GrantedCents is the amount actually credited.
	GrantedCents int64 `json:"grantedCents"`
	// Currency is the lower-cased ISO code the grant was denominated in.
	Currency string `json:"currency"`
	// Source is the money bucket: "trial" (non-cash comp) or "prepaid" (real money).
	Source string `json:"source"`
	// BalanceCents is the account balance AFTER the grant, in whole cents.
	BalanceCents int64 `json:"balanceCents"`
	// BalanceExact is that same balance at full 18-decimal precision, so a sub-cent
	// debit is visible rather than rounded away.
	BalanceExact string `json:"balanceExact"`
	// TransactionID is the ledger entry id, for reconciliation against commerce.
	TransactionID string `json:"transactionId"`
}

GrantResult is what a credit grant DID — the receipt both grant ops answer with.

type None

type None struct{}

None is the input of an op that takes none: no body, no query, no path param. It is shared rather than redeclared per op because an empty struct carries no contract to document — the ops that DO take input each declare their own named In.

type SeriesPoint

type SeriesPoint struct {
	T     string `json:"t"`
	Value int64  `json:"value"`
}

SeriesPoint is one bucketed point (count OR cents, per the series). T is the bucket key (RFC3339 date / "2006-01" month).

func SpendSeries

func SpendSeries(acts []CustActivity, since, now time.Time, interval string) []SeriesPoint

SpendSeries buckets fleet usage cents into a continuous series over since..now. Shared by the analytics usage/revenue trend and the revenue board's spend trend (one implementation, DRY). A bucket with no usage is an honest 0, not a gap.

type SourceStatus

type SourceStatus struct {
	Name  string `json:"name"`
	OK    bool   `json:"ok"`
	Rows  int    `json:"rows"`
	Error string `json:"error"`
	At    string `json:"at"`
}

SourceStatus is the freshness of one upstream the aggregator pulls from (overview.sources[] / revenue.sources[] / finance.sources[] / analytics.sources[]).

func SrcOf

func SrcOf(name string, err error, rows int, at string) SourceStatus

SrcOf builds a SourceStatus freshness row for an aggregator.

type State

type State struct {
	IAM        *iam.Client
	Commerce   *commerce.Client
	Health     *health.Client
	DO         *digitalocean.Client
	AdminOrg   string
	AuditStore *audit.Recorder

	// WLTenants is the fail-closed allowlist of enabled WHITE-LABEL TENANT orgs — the
	// resellers/brands whose OWN-org admins may reach the org-scoped cockpit panels
	// (GuardScoped) at admin.<brand>. It is the second admission tier next to the admin
	// org: a SuperAdmin (owner == AdminOrg) is cross-tenant and never consults this set;
	// EVERY other caller must be an admin of an org that is IN this set, and is then
	// hard-scoped to that org's subtree. Seeded ONCE from ADMIN_WL_TENANT_ORGS at Mount
	// and otherwise immutable, so the decision is a deliberate, git-/KMS-auditable
	// onboarding — never self-service. EMPTY by default: with no entry, NO customer
	// org-admin is admitted (only SuperAdmins reach the cockpit), so a mis-set/absent
	// env fails CLOSED, never open.
	WLTenants map[string]bool
}

State is admin's own data: the resolved upstream clients + the admin org for this deployment. admin holds NO Base shared deps (it fans out over HTTP replaying the caller's own creds); the embedded cloud.Base carries only the mount-time logger.

AuditStore is cloud's OWN tamper-evident audit store (nil when unconfigured, in which case /v1/admin/audit falls back to the IAM get-records proxy). Serve builds it and hands it over via deps.Audit.

func (State) IsWhiteLabelTenant

func (st State) IsWhiteLabelTenant(org string) bool

IsWhiteLabelTenant reports whether org is an enabled white-label tenant — the ONE place the WL admission decision is read. Nil/empty set ⇒ always false (fail-closed): no org is a WL tenant until explicitly enabled. The org is matched VERBATIM (only trimmed), the same owner key principal.Org yields, so folding can never collapse a distinct owner into an enabled one.

type TenantScope

type TenantScope struct {
	Super bool
	Orgs  []string
}

TenantScope is a request's resolved visibility window. Super and Orgs are the two mutually exclusive views: a SuperAdmin sees all tenants (Orgs ignored); anyone else sees exactly Orgs (their own subtree).

func ResolveScope

func ResolveScope(s *cloud.Service[State], c *zip.Ctx) TenantScope

ResolveScope derives the request's tenant window from the SANITIZED identity only — never a client-forgeable field. A SuperAdmin (c.IsAdmin(), owner == admin org) is cross-tenant; any other caller is pinned to the subtree of their own (sanitized) org.

func (TenantScope) ScopedToOrg

func (t TenantScope) ScopedToOrg(o string) bool

ScopedToOrg reports whether the scope admits reads for org o. Super admits every org; a scoped caller admits only orgs in their subtree. Used by panels that filter an upstream list (e.g. bases) rather than fanning out per-org.

type TxnPoint

type TxnPoint struct {
	T     time.Time
	Cents int64
}

TxnPoint is one dated usage event (a commerce `withdraw`, in cents).

Jump to

Keyboard shortcuts

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