Repository navigation
fix(ui): keep upload history and mapping templates per tenant and user (#176) - #235
Merged
Merged
Conversation
#176) Upload history (file names, rejected cell values) and saved mapping templates (column names and types) were kept in localStorage under one global key. Sign-out removes only the session token, so the next person to sign in on the same browser saw the previous tenant's data (BR-36). Both now use a key scoped to the signed-in tenant and user, and store nothing when nobody is signed in. The old unscoped entries belong to an unknown tenant, so they are dropped on first load, not handed to whoever signs in next: existing users lose their local history and saved templates once. The #176 vitest and browser tests were expected failures; they are plain tests now. The browser tests upload unique content, since M5 rejects an identical file within a tenant as a duplicate. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011T6Wqi8yaiaYWUVH8C4QAY
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011T6Wqi8yaiaYWUVH8C4QAY
The accessibility stub planted history under the old global localStorage key. History is per tenant and user now, and the old key is dropped on load, so three scans (upload page with history, audit log, audit report menu) found an empty page and timed out waiting for orders.csv. Plant it under the session's own key. Reproduced locally with the old stub (3 failed, 10 passed); all 13 pass with this change. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011T6Wqi8yaiaYWUVH8C4QAY
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.
Fixes #176: the next person to sign in on a shared browser no longer sees the previous tenant's upload history or saved header-mapping templates.
The leak
The import-history page and the uploader's report read their list from
localStorageunder one global key, and the saved mapping templates did the same. Sign-out removes only the session token, so a second tenant on the same browser saw the first one's file names, rejected cell values and column names (BR-36). Reproduced in Chromium on the production build before this change: tenant B's history page listed tenant A's file.#176 was closed as moot because the React screen is being replaced (#212), but it still ships.
Fix
src/lib/user-storage.ts:userKey(base)scopes a key to the signed-in tenant and user, and returnsnullwhen nobody is signed in, so nothing is stored.use-local-storage.ts(upload history) andmapping-templates.tsuse it. Templates carry column names and types, which are tenant data, so they are fixed in the same change.Keys are per user, not just per tenant: two users of one tenant don't see each other's history either.
Tests
tenant-isolation.test.tsx(vitest, 11 tests): own history and templates kept across a reload; another tenant and another user of the same tenant see nothing; a user's data comes back after others have been and gone; nothing stored when signed out; old entries dropped; delete touches only the signed-in user's template. 9 of the 11 fail onmain.e2e/test_react_ui.py::test_176_…(Chromium, production build): it was an expected failure and is a plain test now. With the old storage code put back it fails at the leak (expected 0 entries, found 1); with this change it passes. It first checks the history page does list the tenant's own import, so "not listed" means something.mapping-templates.test.tsnow signs in first, since signed-out use stores nothing.tscclean, no new lint errors (the two files with existing formatting errors have the same or fewer). Browser suite 8 passed.Not changed
The session token itself is in
sessionStorage(per tab), which was already fine.Generated by Claude Code