Files
warmbly/internal/models/website_tracking.go
T

162 lines
6.2 KiB
Go

package models
import (
"time"
"github.com/google/uuid"
)
// Website visitor tracking (issue #255, section 13): the snippet a workspace
// installs on its own site, and the page views it reports.
// WebsiteConsentMode says when the snippet may record anything.
type WebsiteConsentMode string
const (
// WebsiteConsentExplicit records nothing until the page calls
// warmbly('consent', 'granted'). The default, because the product sells into
// jurisdictions where device and location data need a prior opt-in.
WebsiteConsentExplicit WebsiteConsentMode = "explicit"
// WebsiteConsentImplicit records on load. The workspace asserts its own
// lawful basis by choosing it.
WebsiteConsentImplicit WebsiteConsentMode = "implicit"
)
// WebsiteLocationPrecision is how much of the IP-derived location is kept.
type WebsiteLocationPrecision string
const (
WebsiteLocationNone WebsiteLocationPrecision = "none"
WebsiteLocationCountry WebsiteLocationPrecision = "country"
WebsiteLocationCity WebsiteLocationPrecision = "city"
)
const (
WebsiteRetentionMinDays = 7
WebsiteRetentionMaxDays = 365
WebsiteRetentionDefaultDays = 90
)
// WebsiteTrackingSettings is a workspace's tracking configuration. Created on
// first read with tracking disabled, so every workspace has a site key to show
// but nothing is accepted until someone turns it on.
type WebsiteTrackingSettings struct {
OrganizationID uuid.UUID `json:"organization_id"`
Enabled bool `json:"enabled"`
SiteKey string `json:"site_key"`
ConsentMode WebsiteConsentMode `json:"consent_mode"`
LocationPrecision WebsiteLocationPrecision `json:"location_precision"`
AllowedHosts []string `json:"allowed_hosts"`
RetentionDays int `json:"retention_days"`
UpdatedAt time.Time `json:"updated_at"`
// TrackingHost is the deployment's tracking host (TRACKING_DOMAIN), so the
// dashboard can render the exact snippet. Empty when the install has none.
TrackingHost string `json:"tracking_host"`
}
// UpdateWebsiteTrackingSettingsRequest is the PATCH body. Every field is
// optional; absent fields keep their value.
type UpdateWebsiteTrackingSettingsRequest struct {
Enabled *bool `json:"enabled"`
ConsentMode *WebsiteConsentMode `json:"consent_mode"`
LocationPrecision *WebsiteLocationPrecision `json:"location_precision"`
AllowedHosts *[]string `json:"allowed_hosts"`
RetentionDays *int `json:"retention_days"`
}
// WebsiteHitRequest is what the tracking service forwards to the backend for
// one page view: the snippet's payload plus the request facts only the edge
// saw. Device and location are derived here from UserAgent and IP; nothing
// about them is trusted from the snippet.
type WebsiteHitRequest struct {
SiteKey string `json:"site_key"`
VisitorKey string `json:"visitor_key"`
SessionKey string `json:"session_key"`
// Consent is what the snippet believes: "granted" after an explicit
// opt-in, "implicit" when the snippet runs in implicit mode. The
// workspace's configured mode decides whether that is enough.
Consent string `json:"consent"`
// IdentifyToken is the click ticket the redirect appended to the landing
// URL. It is the only way a hit reaches a contact.
IdentifyToken string `json:"identify_token"`
URL string `json:"url"`
Title string `json:"title"`
Referrer string `json:"referrer"`
Language string `json:"language"`
Timezone string `json:"timezone"`
ScreenWidth int `json:"screen_width"`
ScreenHeight int `json:"screen_height"`
// Landing marks the first view of a session, as judged by the snippet.
Landing bool `json:"landing"`
UserAgent string `json:"user_agent"`
IP string `json:"ip"`
OriginHost string `json:"origin_host"`
}
// WebsiteHitResult tells the tracking service what to answer the browser.
type WebsiteHitResult struct {
// NewVisitorKey is set when the browser must adopt a fresh visitor id:
// the ticket named a different contact than the one already tied to
// this browser, so the record was split rather than merged.
NewVisitorKey string `json:"new_visitor_key,omitempty"`
}
// WebsitePageHit is one counted page view as stored and as shown in the
// contact timeline.
type WebsitePageHit struct {
ID uuid.UUID `json:"id"`
VisitorID uuid.UUID `json:"visitor_id"`
SessionKey string `json:"session_key"`
OccurredAt time.Time `json:"occurred_at"`
URL string `json:"url"`
Path string `json:"path"`
Title string `json:"title"`
Referrer string `json:"referrer"`
ReferrerDomain string `json:"referrer_domain"`
Landing bool `json:"landing"`
UTMSource string `json:"utm_source"`
UTMMedium string `json:"utm_medium"`
UTMCampaign string `json:"utm_campaign"`
UTMTerm string `json:"utm_term"`
UTMContent string `json:"utm_content"`
DeviceType string `json:"device_type"`
OS string `json:"os"`
Browser string `json:"browser"`
BrowserVersion string `json:"browser_version"`
DeviceBrand string `json:"device_brand"`
Language string `json:"language"`
Timezone string `json:"timezone"`
ScreenWidth int `json:"screen_width"`
ScreenHeight int `json:"screen_height"`
CountryCode string `json:"country_code"`
Region string `json:"region"`
City string `json:"city"`
}
// WebsiteSite is what the ingest path needs to know about a site key.
type WebsiteSite struct {
OrganizationID uuid.UUID
Enabled bool
ConsentMode WebsiteConsentMode
LocationPrecision WebsiteLocationPrecision
AllowedHosts []string
}
// WebsiteVisitor is one browser the snippet has seen.
type WebsiteVisitor struct {
ID uuid.UUID
OrganizationID uuid.UUID
VisitorKey string
ContactID *uuid.UUID
IdentifiedAt *time.Time
IdentifiedVia string
}
// WebsiteTrackingRetentionCutoff is one workspace's prune boundary.
type WebsiteTrackingRetentionCutoff struct {
OrganizationID uuid.UUID
Before time.Time
}