Summary
Add a per-user SettingsStore implementation to the S3 storage backend so a HFS_STORAGE_BACKEND=s3 deployment can serve the /_user/settings endpoints instead of returning 501 Not Implemented.
Context
PR #151 introduced an opaque, per-user JSON UI settings store (SettingsStore trait in helios-persistence, GET/PUT/PATCH /_user/settings in helios-rest). It is implemented for SQLite, PostgreSQL, and now MongoDB — every standalone transactional primary backend.
Per review feedback on #151 (@smunini), S3 is also offered as a standalone primary (HFS_STORAGE_BACKEND=s3, CRUD/versioning/history), so an S3-only operator currently hits an (explained) 501 on the settings endpoints. This issue tracks closing that gap. The 501 message now names the supported backends and explicitly excludes S3/Elasticsearch, so the behaviour is documented rather than silent in the meantime.
Why deferred from #151
- S3's recommended role is Archive, not a hot transactional primary, so the settings use case (frequent small read-modify-write updates from a UI) is a weaker fit.
- The
SettingsStore contract relies on a read-modify-write with a monotonic version for optimistic locking (surfaced as a weak ETag). On SQLite/Postgres this is a SELECT … FOR UPDATE transaction; on MongoDB a version-conditioned update + retry. S3 has no transactions — correctness requires conditional writes (PutObject with If-Match / If-None-Match), whose availability through the backend's object-store client/SDK needs to be verified before implementing.
Work
Note
Elasticsearch is intentionally out of scope — it is search-only and never a standalone primary, so its 501 is correct.
Follow-up to #151.
Summary
Add a per-user
SettingsStoreimplementation to the S3 storage backend so aHFS_STORAGE_BACKEND=s3deployment can serve the/_user/settingsendpoints instead of returning501 Not Implemented.Context
PR #151 introduced an opaque, per-user JSON UI settings store (
SettingsStoretrait inhelios-persistence,GET/PUT/PATCH /_user/settingsinhelios-rest). It is implemented for SQLite, PostgreSQL, and now MongoDB — every standalone transactional primary backend.Per review feedback on #151 (@smunini), S3 is also offered as a standalone primary (
HFS_STORAGE_BACKEND=s3, CRUD/versioning/history), so an S3-only operator currently hits an (explained)501on the settings endpoints. This issue tracks closing that gap. The501message now names the supported backends and explicitly excludes S3/Elasticsearch, so the behaviour is documented rather than silent in the meantime.Why deferred from #151
SettingsStorecontract relies on a read-modify-write with a monotonicversionfor optimistic locking (surfaced as a weakETag). On SQLite/Postgres this is aSELECT … FOR UPDATEtransaction; on MongoDB a version-conditioned update + retry. S3 has no transactions — correctness requires conditional writes (PutObjectwithIf-Match/If-None-Match), whose availability through the backend's object-store client/SDK needs to be verified before implementing.Work
PutObject(If-Matchon the object's ETag,If-None-Match: *for create-if-absent).user_settingsseparate fromresources).get_settings/put_settings/patch_settingswith optimistic concurrency mapped onto conditional writes; translate a failed precondition toConcurrencyError::OptimisticLockFailure.start_s3/start_s3_elasticsearchpaths incrates/hfs/src/main.rs(viacreate_app_with_auth_bulk_and_settings).SettingsStoresuites./_user/settings501message to drop S3 from the unsupported list.Note
Elasticsearch is intentionally out of scope — it is search-only and never a standalone primary, so its
501is correct.Follow-up to #151.