Skip to main content
Version: v5.7.0

Preference

Included from Basic tier

A preference is one per-user named preference document: GUI state — a dashboard layout, chosen filters, a refresh cadence — stored server-side so it follows the user across browsers, machines and reinstalls instead of living in per-browser localStorage. The document body is opaque JSON: the server validates that it parses as JSON and enforces the bounds below, nothing more.

The surface is API v2 only (PreferencesService — see opschain docs api-v2), and strictly scoped to the authenticated caller's own rows: no request names a user, and no caller — superuser included — can read or write another user's documents. Different users may hold same-named documents; each name resolves to the caller's own row. PostgreSQL-backed: under the embedded SQLite store every call answers the typed ERROR_REASON_STORE_POSTGRES_REQUIRED, so GUI clients keep a localStorage fallback.

Writes are compare-and-set: PutPreference with expected_version 0 (or absent) creates the document at version 1, a positive expected_version replaces exactly that stored version (incrementing it), and anything else answers the typed ERROR_REASON_VERSION_MISMATCH with the current and supplied versions. Successful writes record api:preferences:create / api:preferences:update audit events carrying the document's name and the supplied expected_version only — the body never reaches the event lane.

Bounds​

BoundValueBreach
Document size64 KiB of JSON textinvalid_argument + ERROR_REASON_PREFERENCE_TOO_LARGE (metadata: limit_bytes, size_bytes)
Documents per user100 namesfailed_precondition + ERROR_REASON_PREFERENCE_LIMIT_EXCEEDED (metadata: limit); overwriting an existing name always stays possible
Name length255 charactersinvalid_argument field violation

Fields​

FieldTypeMeaning
namestringThe document's name, unique per user (e.g. dashboard).
document_jsonstringThe stored document, JSON text. Never present on listing rows (ListPreferences serves PreferenceInfo: name, version, updated_at only).
versionintThe compare-and-set counter, 1 on create, +1 per successful put.
created_attimestampWhen the document was created.
updated_attimestampWhen the document was last written.

There is no delete yet: the v2 write contract carries no delete verbs, and a preferences delete lands with that v2-wide decision rather than ahead of it. Storage is user_preference_documents (migration 00042), one row per (user_id, name) cascading with the owning user; the adopted v1 user_preferences ui_support table is a different, unversioned document and is unchanged by this surface (its GET/PATCH /api/ui_support/preferences routes are deprecated in the v1 OpenAPI document, no caller — but keep serving).