feat: per-user JSON UI settings store#151
Open
mauripunzueta wants to merge 1 commit into
Open
Conversation
Add a simple, extensible per-user settings store for the upcoming web UI (theme/dark mode, default tenant, active FHIR version, recent queries, …). The value is an opaque JSON object, so new settings keys need no schema or code changes — the frontend owns the document shape. Design: - Dedicated `user_settings` table (one opaque JSON document per user), kept separate from the FHIR `resources` table so UI preferences never leak into CapabilityStatement, _history, _search, or $export. Schema migration v10→v11 for both SQLite and PostgreSQL backends. - New `SettingsStore` trait (get/put/patch) in helios-persistence core, plus an RFC 7386 JSON merge-patch helper. Implemented for SQLite and PostgreSQL with transactional read-modify-write and a monotonic `version` for optimistic locking (surfaced as a weak ETag). - Keyed by user only (issuer|subject), tenant-independent; falls back to a fixed `local|default` key when auth is disabled. - REST endpoints GET/PUT/PATCH /_user/settings. The leading-underscore path keeps them authenticated yet exempt from FHIR scope checks and invisible to FHIR machinery. PUT replaces the document; PATCH merge-patches; both honor If-Match, GET honors If-None-Match (304). - Wired into the SQLite and PostgreSQL standalone backends in the hfs binary; other backends report the feature as unavailable (501). Tests: persistence unit tests (merge-patch + SQLite store), PostgreSQL integration tests, REST extractor tests, and an end-to-end HTTP suite covering defaults, round-trip, merge/delete, optimistic locking, validation, and 304. Also refresh the HTS README to reflect completed PostgreSQL backend parity.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a simple, extensible per-user settings store for the upcoming web UI. Settings like dark mode are just the first of many — the stored value is an opaque JSON object, so new keys need zero schema or code changes (the frontend owns the document shape). Example settings: theme/dark mode, recent FHIR queries by resource type, default tenant, active FHIR version.
The design is hybrid: a server-side store is the source of truth (settings roam across devices), intended to be fronted by a client-side
localStoragecache for instant first paint.Design decisions
user_settingstable, kept separate from the FHIRresourcestable so private UI prefs never leak intoCapabilityStatement,_history,_search, or$export. Schema migration v10→v11 for both SQLite and PostgreSQL.SettingsStoretrait (get/put/patch) inhelios-persistencecore + an RFC 7386 JSON merge-patch helper. Implemented for SQLite and PostgreSQL with transactional read-modify-write and a monotonicversionfor optimistic locking (surfaced as a weakETag).issuer|subject), tenant-independent — a setting like "default tenant" is inherently cross-tenant. Falls back to a fixedlocal|defaultkey when auth is disabled.GET/PUT/PATCH /_user/settings. The leading-underscore path keeps them authenticated yet exempt from FHIR scope checks and invisible to FHIR machinery.PUTreplaces;PATCHmerge-patches (great for toggling one key); both honorIf-Match,GEThonorsIf-None-Match(304).GETreturns{}by default so the UI always gets a usable document.API
/_user/settings{}),ETag: W/"{version}"/_user/settings/_user/settingsTests
UserKeyextractor unit tests.{}, round-trip, single-key merge, null-delete, staleIf-Match→ 412, matchingIf-Match, non-object body → 400,If-None-Match→ 304.All affected crates pass
cargo fmt,clippy -D warnings(CI flags), and tests.Also
Refreshes the HTS README to reflect completed PostgreSQL backend parity (the only change there).
Notes for review
defaultTenantis keyed per-user globally (deliberate — it's cross-tenant). Future per-tenant settings can nest asperTenant: {...}without changing the table key.localStoragecache layer is out of scope here (UI team owns it).