Skip to content

feat: scope AI session browser storage to the logged-in user#9518

Draft
Guilhem-lm wants to merge 2 commits into
mainfrom
glm/make-sessions-user-specific
Draft

feat: scope AI session browser storage to the logged-in user#9518
Guilhem-lm wants to merge 2 commits into
mainfrom
glm/make-sessions-user-specific

Conversation

@Guilhem-lm

Copy link
Copy Markdown
Contributor

Summary

AI "sessions" (the fork/draft workspaces feature behind /sessions, plus the AI chat history that backs them) persisted entirely in the browser un-scoped to the logged-in user. On a shared browser (sequential logins, or a superadmin handing off a machine), user B saw user A's sessions, chat history, and unread badges, and silently inherited A's autonomy setting — including the unsafe auto-execute "YOLO" mode.

This PR namespaces all four browser-persisted session surfaces by the logged-in instance user email — the only identity stable across a fork family (a single session deliberately spans multiple workspace_ids; username varies per workspace, email does not). Existing single-user data is claimed-then-migrated on first login; logged-out / pre-resolve state is empty and fail-safe.

Changes

  • New frontend/src/lib/userScopedStorage.ts — owns a single userStore subscription and exposes:
    • scopedKey(base)`${base}::${email}` (or undefined when logged out → callers no-op)
    • onUserChange(cb) — fires immediately on registration (covers late registrants whose email already resolved) and on every email change
    • migrateLegacyLocalStorage(legacy, target) — claim-then-delete of pre-namespacing data
  • Session list (sessionState.svelte.ts) — starts empty; hydrates/persists under windmill_sessions::email; persistSessions() no-ops while logged out; resets in-memory list + active session on logout / user switch.
  • Unread markers (sessionUnread.svelte.ts) — scoped key + hydrate-on-email.
  • Chat-history IndexedDB (HistoryManager.svelte.ts) — per-user DB name; email-gated init(); legacy DB copied-then-deleteDB. The singleton self-heals via onUserChange.
  • Autonomy mode (AIChatManager.svelte.ts) — initialises to the safe ACCEPT_EDIT default before email resolves; the module-level singleton re-hydrates from ai-chat-autonomy-mode::email (+ legacy ai-chat-yolo-mode) via onUserChange; per-session managers read the scoped key at construction. ai-chat-open/panel size stays global (cosmetic).
  • Each surface claims its legacy un-namespaced data for the first user to log in, then deletes it. Only module-level singletons register onUserChange (per-session managers are post-login and read scoped keys directly) so the never-unregistered callback set stays bounded.

No backend / EE changes (frontend localStorage + IndexedDB only).

Test plan

  • npm run check — 0 errors
  • New userScopedStorage.test.ts + updated AIChatManager.test.ts / sessionState.test.ts — 38 tests pass (isolation, legacy-claim migration, no-persist-while-logged-out, safe autonomy default)
  • Browser E2E: seeded legacy windmill_sessions + ai-chat-autonomy-mode=yolo; after login both claimed into …::admin@windmill.dev and legacy keys deleted; a seeded …::other@user.dev left untouched (isolation); migration did not fire on the logged-out workspace picker; migrated yolo showed live on a new session (reactive hydration)
  • Reviewer: on a shared browser, log in as A (create sessions, set YOLO, accrue chat history) → log out (full reload) → log in as B and confirm empty list / no unread / safe autonomy default / empty chat history; log back in as A and confirm A's state restored
  • Reviewer: with pre-existing un-namespaced data, confirm the first login claims it and a second user does not inherit it

Notes / follow-ups

  • No automated test covers the HistoryManager IndexedDB migration (maybeMigrateLegacyChatDb) — fake-indexeddb isn't currently a dev dependency. Verified manually in-browser; a future test seeding a legacy DB and asserting copy-then-delete would be valuable.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 10, 2026

Copy link
Copy Markdown

Deploying windmill with  Cloudflare Pages  Cloudflare Pages

Latest commit: d65b81d
Status: ✅  Deploy successful!
Preview URL: https://952b5947.windmill.pages.dev
Branch Preview URL: https://glm-make-sessions-user-speci.windmill.pages.dev

View logs

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant