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

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