From 0800b0550625efa51dcef403681771dafe86c740 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 20 May 2026 22:09:01 +0000 Subject: [PATCH] docs(web): drop migration-history framing from store docstrings (LUM-1752) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrites the module docstrings on auth-store, organization-store, nudge-store, and onboarding-store to describe what each store does now — session lifecycle, org list + active-org selection, nudge prefs, onboarding/privacy flags — instead of leading with what it replaced. Same for the inline focus-refetch comment in setupOrganizationStore. No behavior changes; docstrings and one inline comment only. Acceptance grep clean: grep -rnE 'Replaces the|previously lived|Matches the old' \ apps/web/src --include='*.ts' --include='*.tsx' https://claude.ai/code/session_018S9mQ5rmtUAvixYCcmXJaZ --- apps/web/src/domains/nudges/nudge-store.ts | 18 ++++++++---------- .../src/domains/onboarding/onboarding-store.ts | 17 +++++++++-------- apps/web/src/stores/auth-store.ts | 8 +++----- apps/web/src/stores/organization-store.ts | 17 +++++++---------- 4 files changed, 27 insertions(+), 33 deletions(-) diff --git a/apps/web/src/domains/nudges/nudge-store.ts b/apps/web/src/domains/nudges/nudge-store.ts index 26af2a3ff11..8e2d41abab1 100644 --- a/apps/web/src/domains/nudges/nudge-store.ts +++ b/apps/web/src/domains/nudges/nudge-store.ts @@ -1,21 +1,19 @@ /** * Zustand store for GitHub + Discord nudge prefs. * - * Replaces the hand-rolled `useSyncExternalStore` + per-key - * subscribe/snapshot caches that previously lived in `github-prefs.ts` - * and `discord-prefs.ts`. Both pref modules now read/write through this - * store; their public hooks (`useGitHubNudgeState`, `useDiscordNudgeState`) - * remain as thin selector wrappers so consumers don't change. + * Owns whether each nudge has been actioned (starred, joined) or + * dismissed (banner, sidebar) and when. `github-prefs.ts` and + * `discord-prefs.ts` expose thin selector hooks (`useGitHubNudgeState`, + * `useDiscordNudgeState`) backed by this store. * * **Storage model:** * * - The persist middleware serialises the whole nudge slice into a * single localStorage key, `vellum:nudge-prefs`. * - On first load (no `vellum:nudge-prefs` key present), the initial - * state is seeded from the legacy per-key entries the old modules - * wrote (`app.githubNudge.starred`, `app.discordNudge.joined`, etc.), - * so users carrying over from the platform deployment keep their - * dismissals. + * state is seeded from per-key boolean/number entries under + * `app.githubNudge.*` / `app.discordNudge.*` so a returning user + * keeps their dismissals. * - Cross-tab updates: the persist middleware doesn't sync across tabs * on its own. We listen for `storage` events on `vellum:nudge-prefs` * and call `persist.rehydrate()` to pull in the other tab's write. @@ -78,7 +76,7 @@ export interface NudgeActions { export type NudgeStore = NudgeState & NudgeActions; // --------------------------------------------------------------------------- -// Initial state — hydrate from legacy per-key localStorage entries +// Initial state — seeded from per-key localStorage entries on first load // --------------------------------------------------------------------------- function computeInitialFromLegacy(): NudgeState { diff --git a/apps/web/src/domains/onboarding/onboarding-store.ts b/apps/web/src/domains/onboarding/onboarding-store.ts index 07f7ba18b94..6bfe845ed1e 100644 --- a/apps/web/src/domains/onboarding/onboarding-store.ts +++ b/apps/web/src/domains/onboarding/onboarding-store.ts @@ -1,15 +1,15 @@ /** * Zustand store for onboarding boolean preferences. * - * Replaces the hand-rolled `useSyncExternalStore` + per-key listener - * boilerplate that previously lived in `prefs.ts`. Public hooks - * (`useShareAnalytics`, `useShareDiagnostics`, `useTosAccepted`, - * `useAiDataConsent`, `useOnboardingCompleted`) remain in `prefs.ts` - * as thin wrappers around `.use.field()` selectors + setter actions. + * Owns the five onboarding/privacy flags consumed by the privacy page, + * the onboarding pages, the chat-gate, and Sentry. `prefs.ts` exposes + * thin hooks (`useShareAnalytics`, `useShareDiagnostics`, + * `useTosAccepted`, `useAiDataConsent`, `useOnboardingCompleted`) that + * wrap `.use.field()` selectors and setter actions on this store. * * **Storage model — strict per-key, with absence semantics preserved:** * - * Each field maps 1:1 to its existing localStorage key: + * Each field maps 1:1 to its own localStorage key: * * | Field | localStorage key | Read by | * |-------------------|-------------------------------|------------------------| @@ -29,8 +29,9 @@ * privacy-safe default and ANY explicit `"true"` as opt-in. * * Instead, each setter writes only its own key via `setLocalSetting`, - * preserving the original per-key write semantics. Initial state is - * read once on module load via `computeInitialFromLS()`. + * so a field that was never explicitly set stays absent in localStorage + * — keeping the privacy-safe default intact. Initial state is read once + * on module load via `computeInitialFromLS()`. * * **Cross-tab + cross-surface sync:** * diff --git a/apps/web/src/stores/auth-store.ts b/apps/web/src/stores/auth-store.ts index dfaef406146..7d5412d03e7 100644 --- a/apps/web/src/stores/auth-store.ts +++ b/apps/web/src/stores/auth-store.ts @@ -1,13 +1,11 @@ /** * Zustand auth store. * - * Replaces the React Context-based AuthProvider with a store that can be - * read from anywhere — middleware, loaders, API interceptors — via - * `useAuthStore.getState()`. - * * Session lifecycle: probes the allauth session on `initSession()`, * re-validates on window focus / visibility change, and synchronizes - * logout across tabs via BroadcastChannel. + * logout across tabs via BroadcastChannel. Middleware, loaders, and + * API interceptors read state synchronously via + * `useAuthStore.getState()`. * * References: * - https://zustand.docs.pmnd.rs/guides/reading-and-writing-state-outside-components diff --git a/apps/web/src/stores/organization-store.ts b/apps/web/src/stores/organization-store.ts index 07ec7d5dd0e..69ebaff1e05 100644 --- a/apps/web/src/stores/organization-store.ts +++ b/apps/web/src/stores/organization-store.ts @@ -1,13 +1,11 @@ /** * Zustand organization store. * - * Replaces the React Context-based OrganizationProvider with a store - * readable from anywhere — middleware, loaders, API interceptors — via - * `useOrganizationStore.getState()`. - * - * Fetches the organization list via the generated SDK client (not React - * Query) so the store is self-contained and usable outside the React tree. - * Persists the active organization to sessionStorage so page refreshes + * Owns the organization list and the active-organization selection. + * Fetches the list via the generated SDK client (not React Query) so + * middleware, loaders, and API interceptors can read state synchronously + * via `useOrganizationStore.getState()` outside the React tree. The + * active organization is persisted to sessionStorage so page refreshes * and new tabs preserve the selection. * * Lifecycle (auth subscription + focus/visibility refetch) is registered @@ -176,9 +174,8 @@ export function clearOrganization(): void { * 1. Auth subscription — fetches orgs when the user logs in or switches * accounts (including cross-tab via BroadcastChannel). * 2. Window focus / visibility — refetches the org list when the tab - * regains focus, but only if data is stale (older than STALE_TIME_MS). - * Matches the old React Query `refetchOnWindowFocus` + `staleTime` - * behavior from `createQueryClient({ staleTime: 10_000 })`. + * regains focus, but only if data is older than STALE_TIME_MS so + * rapid focus events on fresh data don't trigger redundant fetches. */ export function setupOrganizationStore(): () => void { const STALE_TIME_MS = 10_000;