Skip to content

[P1][Privacy] Local Data Controls must preserve analytics opt-out while clearing Byteflow data #302

Description

@baixiangcpp

Summary

LocalDataControls now provides a visible "clear all local data" path, but the current implementation removes every byteflow:* localStorage key. That includes the explicit analytics opt-out key byteflow:analytics:opt-out.

If analytics is disabled today, the impact is latent. But the privacy contract should not depend on analytics staying disabled forever. A user who explicitly opted out should not lose that negative consent merely because they clear local app data.

Why this matters

Clear-data flows need special handling for consent and privacy preferences:

  • Users generally expect "clear app data" to remove app state, cached preferences, recents, favorites, and saved recipes.
  • Users do not expect it to silently re-enable tracking preferences they explicitly disabled.
  • Byteflow's privacy posture depends on conservative handling of analytics and storage controls.
  • The current analytics facade is no-op by design, but isAnalyticsEnabled() is explicitly structured for a future provider; the opt-out semantics should be correct before any provider is introduced.

Current behavior

Relevant code path:

  • src/features/privacy/local-data-controls.tsx
    • clearData() calls clearByteflowLocalData().
    • It then refreshes analyticsOptedOut from isAnalyticsOptedOut().
  • src/core/storage/tool-persistence-policy.ts
    • clearByteflowLocalData() iterates over window.localStorage and removes all keys that start with byteflow:.
  • src/core/analytics/preferences.ts
    • The analytics opt-out key is byteflow:analytics:opt-out.

So a user who opted out of analytics can click "clear all local data" and lose the opt-out flag.

There is a similar completeness gap for session data: clearByteflowLocalData() only clears localStorage, while runtime code also uses window.sessionStorage for safe UI state such as byteflow:pwa-install:session-prompted.

Expected behavior

The clear-data behavior should distinguish between:

  1. App data that should be cleared:
    • favorites;
    • recent tools;
    • tool preferences;
    • PWA prompt state if appropriate;
    • saved Pipeline recipes;
    • Byteflow-owned sessionStorage keys.
  2. Explicit negative consent / privacy preference that should be preserved by default:
    • analytics opt-out.

Suggested implementation plan

  1. Replace clearByteflowLocalData() with a more explicit API, for example:
clearByteflowBrowserData({
  preserveAnalyticsOptOut: true,
  includeSessionStorage: true,
})
  1. Preserve getAnalyticsOptOutStorageKey() by default when clearing all local data.
  2. Add a separate explicit action only if you want users to reset analytics preference to default.
  3. Clear Byteflow-owned sessionStorage keys as part of the all-data clear path, except for any intentionally preserved privacy/consent keys.
  4. Update Local Data Controls copy so users understand that privacy opt-out is preserved unless explicitly changed.
  5. Add tests covering:
    • analytics opt-out survives clear-all;
    • non-consent byteflow:* localStorage keys are removed;
    • Byteflow sessionStorage keys are removed;
    • saved recipes are still cleared;
    • the analytics checkbox state remains opted out after clear-all.

Acceptance criteria

  • Clearing all local data does not remove byteflow:analytics:opt-out when the user opted out.
  • Clearing all local data removes non-consent Byteflow localStorage keys.
  • Clearing all local data removes Byteflow sessionStorage keys that are not explicit consent/privacy preferences.
  • The analytics opt-out checkbox remains checked after clear-all when previously opted out.
  • Tests cover localStorage, sessionStorage, recipes, and analytics opt-out preservation.
  • npm run test -- tests/component/privacy-page.test.tsx passes.
  • npm run test -- tests/guards/sensitive-storage-audit.test.ts tests/guards/verification-mode-acceptance.test.ts passes if updated.
  • npm run check:types and npm run lint pass.

Related code pointers

  • src/features/privacy/local-data-controls.tsx
  • src/core/storage/tool-persistence-policy.ts
  • src/core/analytics/preferences.ts
  • src/components/layout/app-runtime.tsx

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions