Documentation
¶
Overview ¶
Package catalogentry is the CMS source-of-truth for the platform product catalog — the single list docs.<brand>, the console sidebar, and pricing all derive from. commerce owns the DATA (source + seed + edits); the shape is the @hanzo/products contract (that package owns the schema + the iconKey→component and brandColor→css code-maps). Pricing is native: an entry references a pricing plan by key (PricingId), or carries a fixed PriceCents.
Conformance (GET /v1/commerce/catalog → the @hanzo/products CatalogEntry):
- iconKey is a @hanzogui/lucide-icons-2 export NAME ("Brain") — never a component.
- brandColor is a swatch KEY ("violet") — never hex. @hanzo/products maps key→css.
- category is EXACTLY one of the 10 canonical categories (others are dropped by scope).
- route is "/<slug>", apiPath is /v1-prefixed, docsUrl is /docs/services/<slug>.
- pricingId is a pricing plans/<key>.json key, or null.
- brands is a category-derived convenience — NOT a hand-authored filter; the server scopes by CATEGORY (categoriesForBrand), matching @hanzo/products catalogForBrand.
Index ¶
- Constants
- func CategorySlug(label string) string
- func Query(db *datastore.Datastore) datastore.Query
- func Seed(db *datastore.Datastore) (created int, err error)
- func SeedIfEmpty(db *datastore.Datastore) (created int, err error)
- type AdminCatalog
- type AdminItem
- type Catalog
- type CatalogEntry
- type Category
- type Economics
- type Item
- type Pricing
- type SeedRow
Constants ¶
const ( StatusEnabled = "enabled" // in-console module that works StatusExternal = "external" // live external brand surface StatusSoon = "soon" // primitive shipped, no console surface yet )
Status enumerates a product's honest enablement state (mirrors the console registry): a working in-console module, a live external surface, or a primitive that ships with no console surface yet. No fabricated states.
Variables ¶
This section is empty.
Functions ¶
func CategorySlug ¶
CategorySlug slugifies a category label the way @hanzo/products categorySlug does: simple lowercase ("AI"→"ai", "Web3"→"web3").
func Seed ¶
Seed loads the embedded @hanzo/products snapshot into db (which MUST be namespaced to the catalog-owning "system" org). IDEMPOTENT + NON-DESTRUCTIVE: an entry whose slug already exists is left UNTOUCHED so CMS edits are never clobbered; only missing slugs are created. Order is the snapshot index (stable display order within a category). Returns the number created.
func SeedIfEmpty ¶
SeedIfEmpty seeds the catalog only when it is currently empty — a cheap single count query gates the full per-row create, so it is safe to call on every bootstrap. Once any entry exists (seeded or CMS-created) it never re-runs, so CMS state stays authoritative.
Types ¶
type AdminCatalog ¶ added in v1.49.7
type AdminCatalog struct {
Brand string `json:"brand"`
Categories []Category `json:"categories"`
Products []AdminItem `json:"products"`
}
AdminCatalog is the projection returned by GET /v1/commerce/admin/catalog. It mirrors Catalog but its products carry cost + marginPct so admin.hanzo.ai can administrate margin.
func ProjectAdmin ¶ added in v1.49.7
func ProjectAdmin(db *datastore.Datastore, brand string) (AdminCatalog, error)
ProjectAdmin returns the admin brand-scoped catalog: the public projection PLUS cost + marginPct on every entry. Callers MUST gate this on owner=="admin"; the projection itself only adds the administrative economics. MarginPct falls back to the derived (price-cost)/price margin when the entry stores no explicit override.
type AdminItem ¶ added in v1.49.7
type AdminItem struct {
Item
CostCents currency.Cents `json:"costCents"`
MarginPct float64 `json:"marginPct"`
}
AdminItem is the admin projection of a CatalogEntry: the full public Item PLUS the administrative economics (cost + margin) the public projection withholds. Only the owner=="admin" admin catalog emits it, so upstream cost and target margin never reach a public reader.
type Catalog ¶
type Catalog struct {
Brand string `json:"brand"`
Categories []Category `json:"categories"`
Products []Item `json:"products"`
}
Catalog is the full PUBLIC projection returned by GET /v1/commerce/catalog. `products` is the CatalogEntry[] @hanzo/products consumes; brand + categories are additive envelope fields. It carries metadata + the public price (Item.PriceCents) + the plan reference (Item.PricingId) + the public pricing block (Item.Pricing) — NEVER cost or margin.
type CatalogEntry ¶
type CatalogEntry struct {
mixin.Model[CatalogEntry]
Slug string `json:"slug"` // stable id / path segment, e.g. "gateway"
Name string `json:"name"` // "Gateway"
Category string `json:"category"` // one of the 10 canonical categories
Description string `json:"description" datastore:",noindex"` // one-line (additive; not in the core contract)
Gcp string `json:"gcp,omitempty"` // GCP product it stands in for
// Presentation KEYS (CMS-editable; @hanzo/products resolves them).
IconKey string `json:"iconKey"` // lucide export name, e.g. "Network"
BrandColor string `json:"brandColor"` // swatch key, e.g. "blue"
Route string `json:"route"` // marketing "/<slug>"
DocsUrl string `json:"docsUrl"` // https://docs.hanzo.ai/docs/services/<slug>
ApiPath string `json:"apiPath"` // /v1-prefixed path, "/v1/<slug>"
ApiRoute string `json:"apiRoute,omitempty"` // host-qualified "api.hanzo.ai/v1/<slug>"
GithubUrl string `json:"githubUrl,omitempty"` // source runtime repo URL
External bool `json:"external,omitempty"` // leaf that links out to another brand surface
// Pricing is the public pricing block; Private is the admin-only unit
// economics (cost + margin) — stored as noindex blobs, projected apart:
// Pricing rides the public projection, Private only the super-admin list.
Pricing *Pricing `json:"pricing,omitempty" datastore:"-"`
Pricing_ string `json:"-" datastore:",noindex"`
Private *Economics `json:"private,omitempty" datastore:"-"`
Private_ string `json:"-" datastore:",noindex"`
// PricingId references a pricing plan by key (plans/<key>.json); empty ⇒
// projected as JSON null. PriceCents is an optional native fixed-price
// override (additive to the contract) — the PUBLIC price a customer pays.
PricingId string `json:"pricingId"`
PriceCents currency.Cents `json:"priceCents,omitempty"`
Currency currency.Type `json:"currency,omitempty"`
// CostCents is the platform's own unit cost for this product (what Hanzo
// pays upstream) and MarginPct is the target gross margin over it. Both are
// administrative economics — the margin surface admin.hanzo.ai edits (HIP-0106)
// — and are projected ONLY by the owner=="admin" admin catalog, NEVER by the
// public projection. When MarginPct is unset the admin projection derives it
// from (PriceCents-CostCents)/PriceCents so a stored override and a computed
// value read the same way.
CostCents currency.Cents `json:"costCents,omitempty"`
MarginPct float64 `json:"marginPct,omitempty"`
Status string `json:"status" orm:"default:enabled"` // enabled|external|soon
Repo string `json:"repo,omitempty"` // source repo, e.g. "hanzoai/ai"
Admin bool `json:"admin,omitempty"` // admin-gated surface
// Brands is a category-derived convenience preserved from the seed (the
// server filters by category, not by this list). Stored as a noindex blob.
Brands []string `json:"brands,omitempty" datastore:"-"`
Brands_ string `json:"-" datastore:",noindex"`
Order int `json:"order"` // display rank within a category
Published bool `json:"published" orm:"default:true"` // gates from the public projection
// ProductId optionally links this catalog surface to a real commerce
// product for checkout/subscription. Empty = presentation/pricing only.
ProductId string `json:"productId,omitempty"`
Metadata Map `json:"metadata,omitempty" datastore:"-"`
Metadata_ string `json:"-" datastore:",noindex"`
}
CatalogEntry is one product in the platform catalog. Slug (== id) is the stable, globally-unique key the entry is addressed by.
func New ¶
func New(db *datastore.Datastore) *CatalogEntry
type Category ¶
type Category struct {
ID string `json:"id"` // slugified label, e.g. "ai"
Label string `json:"label"` // "AI"
Order int `json:"order"` // display rank
}
Category is one taxonomy entry in the projection.
type Economics ¶ added in v1.49.7
Economics is the PRIVATE, admin-only unit economics for a capability. It is NEVER included in the public projection — only the super-admin ListEntries surface returns it. Cost is a display string ("$0.00893 / hour …") or "TODO"; MarginPct is the gross margin percent, nil when not yet computed (so an unknown margin is an absent field, never a fabricated 0).
type Item ¶
type Item struct {
ID string `json:"id"` // == Slug (stable, unique)
Name string `json:"name"`
Category string `json:"category"`
BrandColor string `json:"brandColor"`
IconKey string `json:"iconKey"`
Slug string `json:"slug"`
Route string `json:"route"`
DocsUrl string `json:"docsUrl"`
ApiPath string `json:"apiPath"`
ApiRoute string `json:"apiRoute,omitempty"` // host-qualified api.hanzo.ai/v1/<slug>
GithubUrl string `json:"githubUrl,omitempty"` // source runtime repo URL
PricingId *string `json:"pricingId"` // string OR null
Brands []string `json:"brands,omitempty"` // category-derived convenience
// Additive (client ignores unknowns).
Description string `json:"description,omitempty"`
Gcp string `json:"gcp,omitempty"`
Status string `json:"status,omitempty"`
Repo string `json:"repo,omitempty"`
External bool `json:"external,omitempty"`
Admin bool `json:"admin,omitempty"`
PriceCents currency.Cents `json:"priceCents,omitempty"`
Currency currency.Type `json:"currency,omitempty"`
Order int `json:"order,omitempty"`
ProductId string `json:"productId,omitempty"`
// Pricing is the PUBLIC pricing block. Private economics (cost/margin) are
// deliberately absent here — they ride only the owner=="admin" admin
// projection (AdminItem), never this public projection.
Pricing *Pricing `json:"pricing,omitempty"`
}
Item is the public projection of a CatalogEntry — the exact @hanzo/products CatalogEntry shape. Presentation keys (iconKey, brandColor) are strings resolved client-side; pricingId is null when unset. Fields beyond the core contract (gcp, repo, admin, status, description, priceCents, order, productId) are additive — the client ignores unknowns.
type Pricing ¶ added in v1.49.7
type Pricing struct {
PublicPrice string `json:"publicPrice"`
PlanTiers []string `json:"planTiers,omitempty"`
UsageMeter string `json:"usageMeter,omitempty"`
}
Pricing is the PUBLIC pricing block for a capability — projected to everyone. PublicPrice is a human display string ("From $0.10 / 1M input tokens"), or the literal "TODO" when a real number is not yet sourced (never a fabricated one). PlanTiers are subscription plan keys (api/billing/plans/<key>.json) the capability is included in; UsageMeter is the metering unit ("per_mtok").
type SeedRow ¶
type SeedRow struct {
ID string `json:"id"`
Name string `json:"name"`
Category string `json:"category"`
BrandColor string `json:"brandColor"`
IconKey string `json:"iconKey"`
Slug string `json:"slug"`
Route string `json:"route"`
DocsUrl string `json:"docsUrl"`
ApiPath string `json:"apiPath"`
ApiRoute string `json:"apiRoute"`
GithubUrl string `json:"githubUrl"`
External bool `json:"external"`
PricingId string `json:"pricingId"` // null → ""
Pricing *Pricing `json:"pricing"`
Private *Economics `json:"private"`
Brands []string `json:"brands"`
Repo string `json:"repo"`
Admin bool `json:"admin"`
Status string `json:"status"`
Gcp string `json:"gcp"`
}
SeedRow is the @hanzo/products snapshot shape (the exact CatalogEntry contract). `id` == `slug`; `pricingId` may be JSON null (→ "").
func HanzoSeedRows ¶
HanzoSeedRows returns the parsed embedded snapshot.