Help us shape the future of Go! Take the 2026 Go Developer Survey

siteconfig

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Oct 28, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package siteconfig reads the singleton site configuration row (hatamoto_site_config).

The table has exactly one row (BOOLEAN primary key with CHECK (id = TRUE)). Reads are extremely hot (every public page render), so we cache the value in-process with a 60-second TTL — same pattern as redirect.Service.

Index

Constants

View Source
const (
	PreloadModeMissing = "missing"
	PreloadModeAll     = "all"
)

Preload modes: skip pages that are already cached, or rebuild everything.

View Source
const (
	MinPageCacheTTLSeconds = 30
	MaxPageCacheTTLSeconds = 30 * 24 * 3600
)

Page cache lifetime bounds in seconds (0 = server default).

Variables

View Source
var ErrInvalidPageCache = errors.New("invalid page cache setting")

ErrInvalidPageCache is returned by Update for out-of-range page cache values.

View Source
var ErrNotConfigured = errors.New("site config row missing — run migration 075")

ErrNotConfigured is returned when the singleton row has not been seeded. Code paths that hit this should fall back to safe defaults (the pre-Path-B WhiteLabelConfig was JSONB-nullable too — same blast radius).

Functions

This section is empty.

Types

type Config

type Config struct {
	CompanyName       string
	LogoURL           string
	CustomDomain      string
	PrimaryColor      string
	ThemeExtra        json.RawMessage // raw JSONB, callers parse if they need it
	Tagline           string
	Timezone          string
	HomepageEntityID  uuid.UUID // uuid.Nil if unset
	NotificationEmail string
	// Language is the BCP 47 site language ("en" by default): <html lang>,
	// JSON-LD inLanguage and feed language.
	Language string
	// Phone and BusinessHours are the public contact details, free text.
	Phone         string
	BusinessHours string
	// PostalAddress is the business address, JSONB {street, city, state,
	// postal_code, country}. Nil-or-empty means "unset".
	PostalAddress json.RawMessage
	// LegacyWPRedirects turns on the built-in WordPress URL redirects
	// (dated permalinks, feeds, taxonomy archives, wp-* paths). Off by default.
	LegacyWPRedirects bool
	// PublicBaseURL is the site's public origin set in the admin ("" = derive
	// from the request); the PUBLIC_BASE_URL env var overrides it.
	PublicBaseURL string
	// SetupCompletedAt is when the first-run wizard finished (nil = still open).
	SetupCompletedAt *time.Time
	UpdatedAt        time.Time

	// Page cache controls (Settings > Performance). Zero values are
	// sentinels: TTL 0 = server default, MaxMB 0 = no limit, preload interval
	// 0 = same as the cache lifetime.
	PageCacheEnabled           bool
	PageCacheTTLSeconds        int
	PageCacheMaxMB             int
	PagePreloadEnabled         bool
	PagePreloadIntervalSeconds int
	// PagePreloadMode is PreloadModeMissing or PreloadModeAll.
	PagePreloadMode string
	// PagePreloadAfterChanges schedules a preload shortly after a content
	// change empties the cache.
	PagePreloadAfterChanges bool
}

Config is the in-memory shape of the singleton row.

type PublicSettings

type PublicSettings struct {
	DefaultEntitySchema string     `json:"default_entity_schema,omitempty"`
	NotificationEmail   string     `json:"notification_email,omitempty"`
	Timezone            string     `json:"timezone,omitempty"`
	HomepageEntityID    *uuid.UUID `json:"homepage_entity_id,omitempty"`
}

PublicSettings is the slim, public-facing slice of admin-configurable settings rendered into PublicSiteData. Pre-Path-B this lived in the tenant package as tenant.TenantSettings; relocated here because all fields ultimately derive from hatamoto_site_config.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store reads (and eventually writes) hatamoto_site_config. Holds a small TTL'd cache to absorb high-frequency reads from public page renders.

func NewStore

func NewStore(db *database.DB, logger *slog.Logger) *Store

NewStore constructs a site-config store backed by the given database.

func (*Store) Get

func (s *Store) Get(ctx context.Context) (*Config, error)

Get returns the singleton site config, refreshing from the DB if the cached copy is older than cacheTTL. Runs under superadmin context — the table has no RLS post-Migration-A but the GUC set is harmless.

On DB error, returns the stale cached copy if available; otherwise the error. Callers should treat "stale" as acceptable since the singleton changes manually via admin UI (PR 2b will add the write path), never via automated traffic.

func (*Store) Invalidate

func (s *Store) Invalidate()

Invalidate forces the next Get to hit the DB. Call from any write path that mutates hatamoto_site_config so admin UI changes are immediately visible.

func (*Store) Update

func (s *Store) Update(ctx context.Context, in UpdateInput) (*Config, error)

Update applies a patch to the singleton row and invalidates the cache. Concurrency-safe via single UPDATE statement + COALESCE for nil fields. Returns the refreshed Config on success.

type ThemeBorderRadius

type ThemeBorderRadius struct {
	Sm string `json:"sm,omitempty"`
	Md string `json:"md,omitempty"`
	Lg string `json:"lg,omitempty"`
}

ThemeBorderRadius holds border radius design tokens.

type ThemeCTA

type ThemeCTA struct {
	Text string `json:"text"`
	URL  string `json:"url"`
}

ThemeCTA is a call-to-action button (label and target) shown by themes.

type ThemeColors

type ThemeColors struct {
	Primary    string `json:"primary,omitempty"`
	Secondary  string `json:"secondary,omitempty"`
	Accent     string `json:"accent,omitempty"`
	Background string `json:"background,omitempty"`
	Text       string `json:"text,omitempty"`
}

ThemeColors holds color design tokens.

type ThemeConfig

type ThemeConfig struct {
	Colors       ThemeColors       `json:"colors"`
	Typography   ThemeTypography   `json:"typography"`
	BorderRadius ThemeBorderRadius `json:"borderRadius"`
	// HeaderCTA is the optional header call-to-action. Nil (omitted from JSON)
	// means the theme renders no header button.
	HeaderCTA *ThemeCTA `json:"headerCta,omitempty"`
}

ThemeConfig holds all design tokens for CSS variable injection.

func DefaultThemeConfig

func DefaultThemeConfig() ThemeConfig

DefaultThemeConfig returns the default theme configuration.

func (*ThemeConfig) Scan

func (t *ThemeConfig) Scan(src any) error

Scan implements the sql.Scanner interface for ThemeConfig so callers can decode the theme_extra JSONB column directly into the typed shape.

type ThemeTypography

type ThemeTypography struct {
	FontFamily    string `json:"fontFamily,omitempty"`
	HeadingFamily string `json:"headingFamily,omitempty"`
}

ThemeTypography holds typography design tokens.

type UpdateInput

type UpdateInput struct {
	CompanyName       *string
	LogoURL           *string
	CustomDomain      *string
	PrimaryColor      *string
	ThemeExtra        json.RawMessage
	Tagline           *string
	Timezone          *string
	HomepageEntityID  *uuid.UUID
	NotificationEmail *string
	PostalAddress     json.RawMessage
	Language          *string
	Phone             *string
	BusinessHours     *string
	LegacyWPRedirects *bool
	PublicBaseURL     *string
	// Page cache controls; see Config for the zero-value sentinels.
	PageCacheEnabled           *bool
	PageCacheTTLSeconds        *int
	PageCacheMaxMB             *int
	PagePreloadEnabled         *bool
	PagePreloadIntervalSeconds *int
	PagePreloadMode            *string
	PagePreloadAfterChanges    *bool
	// SetupCompleted true stamps setup_completed_at once (never cleared).
	SetupCompleted bool
}

UpdateInput is the patch shape for Update. Any pointer-nil field is left unchanged. theme_extra is JSONB — pass the raw bytes you want stored (validate upstream).

Jump to

Keyboard shortcuts

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