Move persistence off the browser
Course 1 put your watchlist in localStorage deliberately: it protected the ten-minute first win and needed no backend. That decision has now expired, and this lesson is about migrating rather than regretting.
What localStorage actually promised
It promised this browser, this profile, this origin, until something clears it. That was fine for one list on one laptop. Four things break it once you have a cockpit:
- One device. Your layout does not follow you to another machine, and a dashboard is exactly the thing you want on the big screen and the small one.
- Silently evictable. Private windows, storage pressure and "clear site data" all take it, with no event you can catch.
- No history. A bad edit is permanent; there is no version of yesterday's layout.
- Nothing else can read it. An alert that fires while the tab is closed needs your rules somewhere a server can see them, which is unit 3.
Migrate, do not switch
The wrong move is deleting the localStorage code and shipping. Your own data is in there, and so is anyone else's who used your tool.
The right shape is three steps, in this order:
- Read from server, fall back to local. Ship this alone and nothing changes for anyone.
- On first successful server read, upload whatever is local and mark it migrated. One flag, written after the upload succeeds, never before.
- Remove the fallback once you have seen the migration work on your own data on two devices.
Each step is separately revertible, which is the property that matters. This is exactly the small-diffs discipline from course 1 applied to something that can lose your data.
The shape on the server
Keep it boring. One row per user per document, the document as JSON, and a version integer:
user_id | key | version | payload | updated_at
--------|-----------|---------|-------------------|-----------
1 | watchlist | 3 | {"symbols":[...]} | ...
1 | layout | 7 | {"panels":[...]} | ...
The version column is not decoration. Two tabs open on the same dashboard will both write, and without a version the second write silently destroys the first. Send the version you read, reject the write if it has moved, and tell the user their other tab is ahead. That is fifteen lines and it is the difference between a tool you trust and one that eats your work.
Where the key still is not
Nothing changes about secrets. The server now stores your documents and holds the API key, which means the proxy from course 1 and this store are the same server — one deployment, one environment file, one CI scan already watching it.
What is new is that you now hold someone else's data, even if that someone is only you. Every request must be scoped by the authenticated user, and a query without a user_id filter is the whole vulnerability in one line. Add a test that asks for another user's document and expects a 404.
Try it now
Ship step 1 only — read from server, fall back to local — and use it for a day before writing step 2. If the fallback ever fires, you have learned something about your own reliability that a migration done in one commit would have hidden.