Documentation
¶
Overview ¶
Package events provides unified event storage via ClickHouse.
Package events provides unified event storage for Commerce.
Events are written to a shared ClickHouse instance (Hanzo Datastore) that both Insights (PostHog) and Analytics (Umami) can query from. This ensures a single source of truth for all analytics data.
Architecture:
Commerce App
│
▼
┌─────────────────┐
│ Event Emitter │
└────────┬────────┘
│
▼
┌─────────────────┐
│ ClickHouse │ ◄── Single source of truth
│ (Datastore) │
└────────┬────────┘
│
┌────┴────┐
▼ ▼
Insights Analytics
(PostHog) (Umami)
Optional: HTTP forwarding to external Insights/Analytics instances is still supported for backwards compatibility or hybrid deployments.
Package events provides ClickHouse schema for unified analytics.
Index ¶
- Constants
- Variables
- func EnsureSchema(ctx context.Context, datastore db.Datastore) error
- type CheckoutSession
- type Config
- type DatastoreWriter
- type DatastoreWriterConfig
- type Emitter
- func (e *Emitter) Close() error
- func (e *Emitter) EmitCheckoutStarted(ctx context.Context, session *CheckoutSession) error
- func (e *Emitter) EmitOrderCompleted(ctx context.Context, order *Order) error
- func (e *Emitter) EmitOrderRefunded(ctx context.Context, order *Order, refundAmount float64) error
- func (e *Emitter) EmitPageView(ctx context.Context, pv *PageView) error
- func (e *Emitter) EmitProductAdded(ctx context.Context, userID string, product *Product, quantity int) error
- func (e *Emitter) EmitProductViewed(ctx context.Context, userID string, product *Product) error
- func (e *Emitter) EmitRaw(ctx context.Context, event *RawEvent) error
- func (e *Emitter) EmitUserSignedUp(ctx context.Context, user *User) error
- func (e *Emitter) Flush() error
- func (e *Emitter) SetDatastore(datastore db.Datastore)
- type Order
- type OrderItem
- type PageView
- type Product
- type RawEvent
- type User
Constants ¶
const Schema = `` /* 6432-byte string literal not displayed */
Schema contains ClickHouse table definitions for unified analytics. Both Insights (PostHog) and Analytics (Umami) read from these tables.
Variables ¶
var StandardEvents = struct { // Page/Screen events PageView string ScreenView string // Identification Identify string GroupIdentify string Alias string // Commerce events ProductViewed string ProductAdded string ProductRemoved string CartViewed string CheckoutStarted string CheckoutStep string OrderCompleted string OrderRefunded string // User lifecycle SignedUp string SignedIn string SignedOut string // Engagement FeatureUsed string ButtonClick string FormSubmit string SearchQuery string // AST/UI events (astley.js) SectionViewed string ElementInteraction string LinkClicked string InputChanged string ScrollDepth string VisibilityChange string // AI/Cloud events AIMessageCreated string AIChatStarted string AICompletion string AITokensConsumed string AIModelInvoked string AIError string // Pixel tracking PixelView string // API tracking APIRequest string Exception string }{ PageView: "$pageview", ScreenView: "$screen", Identify: "$identify", GroupIdentify: "$groupidentify", Alias: "$create_alias", ProductViewed: "product_viewed", ProductAdded: "product_added", ProductRemoved: "product_removed", CartViewed: "cart_viewed", CheckoutStarted: "checkout_started", CheckoutStep: "checkout_step", OrderCompleted: "order_completed", OrderRefunded: "order_refunded", SignedUp: "signed_up", SignedIn: "signed_in", SignedOut: "signed_out", FeatureUsed: "feature_used", ButtonClick: "button_clicked", FormSubmit: "form_submitted", SearchQuery: "search_query", SectionViewed: "section_viewed", ElementInteraction: "element_interaction", LinkClicked: "link_clicked", InputChanged: "input_changed", ScrollDepth: "scroll_depth", VisibilityChange: "visibility_change", AIMessageCreated: "ai.message.created", AIChatStarted: "ai.chat.started", AICompletion: "ai.completion", AITokensConsumed: "ai.tokens.consumed", AIModelInvoked: "ai.model.invoked", AIError: "ai.error", PixelView: "pixel_view", APIRequest: "$api_request", Exception: "$exception", }
StandardEvents defines event names used across the platform.
Functions ¶
Types ¶
type CheckoutSession ¶
type CheckoutSession struct {
SessionID string
OrganizationID string
CustomerEmail string
Currency string
TotalAmount float64
ItemCount int
ProviderHint string
}
CheckoutSession represents a checkout session for event emission.
type Config ¶
type Config struct {
// Datastore configuration (primary - writes to ClickHouse)
DatastoreEnabled bool
// Insights (PostHog) HTTP forwarding (optional)
InsightsEndpoint string
InsightsAPIKey string
InsightsEnabled bool
// Analytics (Umami) HTTP forwarding (optional)
AnalyticsEndpoint string
AnalyticsWebsiteID string
AnalyticsEnabled bool
}
Config holds event emitter configuration.
type DatastoreWriter ¶
type DatastoreWriter struct {
// contains filtered or unexported fields
}
DatastoreWriter writes events directly to ClickHouse. This is the unified storage that both Insights and Analytics read from.
func NewDatastoreWriter ¶
func NewDatastoreWriter(datastore db.Datastore, config *DatastoreWriterConfig) *DatastoreWriter
NewDatastoreWriter creates a new datastore writer.
func (*DatastoreWriter) Close ¶
func (w *DatastoreWriter) Close() error
Close gracefully shuts down the writer.
func (*DatastoreWriter) Flush ¶
func (w *DatastoreWriter) Flush() error
Flush writes all pending events immediately.
func (*DatastoreWriter) Write ¶
func (w *DatastoreWriter) Write(event *RawEvent) error
Write queues an event for writing to ClickHouse.
type DatastoreWriterConfig ¶
type DatastoreWriterConfig struct {
// BatchSize is the number of events to batch before writing
BatchSize int
// FlushInterval is how often to flush partial batches
FlushInterval time.Duration
// AsyncInsert uses ClickHouse async insert (faster, less guaranteed)
AsyncInsert bool
// BufferSize is the event channel buffer size
BufferSize int
}
DatastoreWriterConfig configures the datastore writer.
func DefaultDatastoreWriterConfig ¶
func DefaultDatastoreWriterConfig() *DatastoreWriterConfig
DefaultDatastoreWriterConfig returns sensible defaults.
type Emitter ¶
type Emitter struct {
// contains filtered or unexported fields
}
Emitter sends events to the unified datastore and optionally to HTTP endpoints.
func NewEmitterWithDatastore ¶
NewEmitterWithDatastore creates an emitter with a datastore connection.
func (*Emitter) EmitCheckoutStarted ¶
func (e *Emitter) EmitCheckoutStarted(ctx context.Context, session *CheckoutSession) error
EmitCheckoutStarted sends checkout started events.
func (*Emitter) EmitOrderCompleted ¶
EmitOrderCompleted sends order completed events.
func (*Emitter) EmitOrderRefunded ¶
EmitOrderRefunded sends order refunded events.
func (*Emitter) EmitPageView ¶
EmitPageView sends page view events.
func (*Emitter) EmitProductAdded ¶
func (e *Emitter) EmitProductAdded(ctx context.Context, userID string, product *Product, quantity int) error
EmitProductAdded sends product added to cart events.
func (*Emitter) EmitProductViewed ¶
EmitProductViewed sends product viewed events.
func (*Emitter) EmitUserSignedUp ¶
EmitUserSignedUp sends user registration events.
func (*Emitter) SetDatastore ¶
SetDatastore sets the datastore writer (can be called after creation).
type Order ¶
type Order struct {
ID string
UserID string
Email string
Total float64
Currency string
Items []OrderItem
Status string
OrgID string
}
Order represents a Commerce order for event emission.
type PageView ¶
type PageView struct {
URL string
Title string
Referrer string
UserID string
SessionID string
OrgID string
IP string
UserAgent string
Language string
Screen string
}
PageView represents a page view event.
type RawEvent ¶
type RawEvent struct {
// Core identifiers
DistinctID string `json:"distinct_id"`
Event string `json:"event"`
// Organization
OrganizationID string `json:"organization_id"`
ProjectID string `json:"project_id,omitempty"`
// Session
SessionID string `json:"session_id,omitempty"`
VisitID string `json:"visit_id,omitempty"`
// Properties
Properties map[string]interface{} `json:"properties,omitempty"`
PersonProperties map[string]interface{} `json:"person_properties,omitempty"`
// Group
GroupType string `json:"group_type,omitempty"`
GroupKey string `json:"group_key,omitempty"`
GroupProperties map[string]interface{} `json:"group_properties,omitempty"`
// Web analytics
URL string `json:"url,omitempty"`
URLPath string `json:"url_path,omitempty"`
Referrer string `json:"referrer,omitempty"`
ReferrerDomain string `json:"referrer_domain,omitempty"`
Hostname string `json:"hostname,omitempty"`
// Device
Browser string `json:"browser,omitempty"`
BrowserVersion string `json:"browser_version,omitempty"`
OS string `json:"os,omitempty"`
OSVersion string `json:"os_version,omitempty"`
Device string `json:"device,omitempty"`
DeviceType string `json:"device_type,omitempty"`
Screen string `json:"screen,omitempty"`
Language string `json:"language,omitempty"`
// Geo
Country string `json:"country,omitempty"`
Region string `json:"region,omitempty"`
City string `json:"city,omitempty"`
// UTM
UTMSource string `json:"utm_source,omitempty"`
UTMMedium string `json:"utm_medium,omitempty"`
UTMCampaign string `json:"utm_campaign,omitempty"`
UTMContent string `json:"utm_content,omitempty"`
UTMTerm string `json:"utm_term,omitempty"`
// Click IDs
GCLID string `json:"gclid,omitempty"`
FBCLID string `json:"fbclid,omitempty"`
MSCLID string `json:"msclid,omitempty"`
// Request
IP string `json:"ip,omitempty"`
UserAgent string `json:"user_agent,omitempty"`
// Commerce
OrderID string `json:"order_id,omitempty"`
ProductID string `json:"product_id,omitempty"`
CartID string `json:"cart_id,omitempty"`
Revenue float64 `json:"revenue,omitempty"`
Quantity int `json:"quantity,omitempty"`
// AST/Structured Data (astley.js support)
// JSON-LD context for semantic data
ASTContext string `json:"@context,omitempty"`
ASTType string `json:"@type,omitempty"`
// Page structure elements
PageTitle string `json:"page_title,omitempty"`
PageDescription string `json:"page_description,omitempty"`
PageType string `json:"page_type,omitempty"` // hero, block, cta, etc.
// Element interaction tracking
ElementID string `json:"element_id,omitempty"`
ElementType string `json:"element_type,omitempty"` // button, link, form, section
ElementSelector string `json:"element_selector,omitempty"` // CSS selector
ElementText string `json:"element_text,omitempty"` // visible text
ElementHref string `json:"element_href,omitempty"` // link destination
// Section tracking (astley.js WebsiteSection)
SectionName string `json:"section_name,omitempty"`
SectionType string `json:"section_type,omitempty"` // hero, block, cta
SectionID string `json:"section_id,omitempty"`
// Component hierarchy
ComponentPath string `json:"component_path,omitempty"` // e.g., "header/nav/menu/item"
ComponentData string `json:"component_data,omitempty"` // JSON blob of component props
// AI/Cloud events
ModelProvider string `json:"model_provider,omitempty"` // openai, anthropic, etc.
ModelName string `json:"model_name,omitempty"` // gpt-4, claude-3, etc.
TokenCount int `json:"token_count,omitempty"`
TokenPrice float64 `json:"token_price,omitempty"`
PromptTokens int `json:"prompt_tokens,omitempty"`
OutputTokens int `json:"output_tokens,omitempty"`
// Timestamps
Timestamp time.Time `json:"timestamp"`
SentAt time.Time `json:"sent_at,omitempty"`
// Library
Lib string `json:"lib,omitempty"`
LibVersion string `json:"lib_version,omitempty"`
}
RawEvent is the unified event format written to ClickHouse.