prefs

package
v1.801.388 Latest Latest
Warning

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

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

Documentation

Overview

Package prefs is your own settings — theme, density, pinned nav — following you across every Hanzo app.

It is the per-USER preference plane for the unified Hanzo Cloud binary: the /v1/prefs surface behind the user menu on every Hanzo surface (console, insights, and anything else that renders "signed in as").

ONE preference store, EVERY surface. A user's theme, density, and pinned nav follow them between products instead of each app keeping its own copy in its own localStorage — which is what makes the same person look like two different users depending on which tab they are in.

Surface (all user-scoped; /v1 only):

GET   /v1/prefs   the caller's own document          -> prefsView
PATCH /v1/prefs   shallow key-wise merge into it     -> prefsView

PATCH, not PUT: a surface saves the keys it owns (the console saves `theme`, insights saves `density`) without having to send back keys it does not know about — a PUT would make every client responsible for preserving every other client's keys, and the first one to forget silently deletes them.

USER ISOLATION is enforced SERVER-SIDE on every request. The subject is the canonical `<owner>/<name>` identity built from values the identity boundary minted from a VALIDATED credential (HIP-0026), and is the mandatory predicate on every store statement. It is NEVER read from a query param or body, and there is no "read another user's prefs" path at all: not for an org admin, not for a platform SuperAdmin. Preferences are personal, and no operational task requires reading someone else's.

NOT SETTINGS. apps/settings is per-ORG, per-product configuration with KMS custody for secret fields. This is per-USER UI state with no secrets. They are different tenancy keys answering different questions, so they are different planes — collapsing them would put one user's theme under an org key and make an org admin the owner of everyone's UI.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Mount

func Mount(app cloud.Router, deps cloud.Deps) error

Mount registers the prefs surface on app per HIP-0106.

func Shutdown

func Shutdown(_ context.Context) error

Shutdown releases the prefs store. Idempotent.

Types

type Prefs

type Prefs struct {
	Subject   string // the validated principal; the tenancy key
	Doc       string // opaque JSON object, stored verbatim (bounded at the edge)
	UpdatedAt int64
}

Prefs is one user's preference document.

type Store

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

The prefs STORE is the durable half of the per-USER preference plane: one JSON document per user, following the settings-store discipline — Hanzo Base/SQLite, MaxOpenConns(1) to serialize writes against the file lock, one file.

Isolation is the `subject` PRIMARY KEY and a mandatory `WHERE subject=?` on EVERY statement. The value is the VALIDATED principal (principal.Subject) — never normalized (casing/trimming would collapse distinct subjects into one bucket) and never a client-supplied header. A user's preferences are readable and writable by that user alone; there is deliberately no admin read path, because there is no operational reason to read someone's theme.

NO SECRETS. Preferences are UI state — a theme, a density, a pinned nav. Unlike settings there is no KMS split to maintain, because nothing here is a credential. If a preference ever needs custody, it does not belong in this table.

func (*Store) Close

func (s *Store) Close() error

Close closes the underlying database.

func (*Store) Get

func (s *Store) Get(ctx context.Context, subject string) (Prefs, error)

Get returns the persisted document for subject, or errNotFound when that user has never written one (the caller then serves an empty document, not a 404 — a preferences read always succeeds).

func (*Store) Merge

func (s *Store) Merge(ctx context.Context, subject string, patch map[string]any, now int64) (Prefs, error)

Merge applies a shallow key-wise merge of patch onto the user's stored document and returns the result, all inside ONE transaction on the single serialized connection.

The merge is here rather than in the handler because read-modify-write across two calls is a lost update: two tabs saving different keys would race, and the later write would silently drop the earlier one's key. Doing it under the transaction makes concurrent saves of DIFFERENT keys both survive — which is exactly the multi-tab case a preferences surface actually sees.

Jump to

Keyboard shortcuts

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