openfrontio / openfrontio/OpenFrontIO

Store user settings on the account instead of localStorage

Open
#5,179 2 comments 0 reactions 0 assignees View on GitHub
approved Backend
Dominant language
TypeScript
Stars
2.7k
Forks
1.4k
Avg merge
17h 43m
Merged PRs (30d)
310

Description

**Proposed by @evanpelle** in #5091:

> i was thinking we could store a jsonb in the db for user settings, so it can
> replace localhost. maybe for adfree/premium users

**Problem**

Client preferences live in `localStorage`, so they are per-device and per-origin.
They do not follow the account. A player who sets something up on one machine
gets defaults on the next one, and a reinstall or a cleared profile loses
everything.

Concrete cases already causing issues:

- **The verified-name toggle** (`useVerifiedName`) — #5091. A subscriber who
claims a name and turns the toggle on is silently back to a free-form name on
any other device, because the opt-in did not travel with the account. This is
the case that prompted the suggestion.
- **The in-game username and clan tag** (`username`, `clanTag`) — a player who
types a name on the web has to type it again in the desktop build, which loads
from a different origin and so has an entirely separate `localStorage`.
- General user settings currently held client-side.

**Proposed shape**

A `jsonb` column on `players` holding account-scoped settings, read on
`/users/@me` and written through a settings endpoint, with `localStorage` kept
as the fallback for signed-out players.

**Design questions worth settling before implementation**

1. **Which settings move.** Not all of them should — some are genuinely
device-local (graphics quality, audio volume, keybinds on a shared machine).
The ones that describe *identity* are the ones that want to follow the
account.
2. **Conflict semantics.** Two devices, both with local state, one comes online.
Last-write-wins is the cheap answer; it silently discards. Worth deciding
rather than inheriting.
3. **Migration.** Existing players have `localStorage` values and no server
record. First read after the change needs a defined direction so nobody's
current setup is wiped by an empty server default.
4. **Scoping.** The suggestion says "maybe for adfree/premium users". Gating by
entitlement keeps the write volume down, but it means the behaviour differs
between free and paying players, which is a support burden. Worth an explicit
decision either way.
5. **Size and validation.** A `jsonb` blob written from the client needs a shape,
a size cap, and server-side validation, or it becomes an unbounded
client-controlled column.

**Relationship to #5091**

#5091 changes the *default* of the verified-name toggle so an eligible player
plays under their claimed name without hunting for the control. This issue fixes
the underlying reason the preference is lost in the first place.

They are compatible, and #5091 is much the smaller change — but once settings are
account-scoped, most of what #5091 works around goes away. If this lands first,
#5091 should be re-scoped rather than implemented as written.

**Note on scope**

This spans both repos: the column and endpoint are server-side, the consumption
is here. Filed here because that is where the discussion started; the server half
may want its own tracking issue.

Contributor guide

Open the contributing guide

Research direction

Start by tracing the client preferences stored in localStorage and how account data is read from /users/@me. Before implementation, resolve which settings move, conflict and migration behavior, entitlement scope, and validation limits; done means the client and server agree on an account-scoped settings flow while signed-out players retain the localStorage fallback.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend-api-design, full-stack
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.