Files
Jakob Wennberg 771dfd45ba docs(compliance): record the deletion trigger for client-side storage (#1246)
Answers the ISO 27001 A.8.10 finding from the compliance swarm on #1242,
which read the storage inventory as saying the two localStorage keys
persist forever with no deletion mechanism. Half of that was our
omission: the inventory never said what logout does.

ph_conv_<token> IS deleted on logout. posthog.reset() resets the
conversations manager, which removes that single known key, and
resetAnalyticsIdentity() already runs in both logout handlers before
signOut(). That is what stops a shared device carrying one user's
support-ticket session into the next user's. Recorded in
lib/analytics/reset.ts too, because it now makes that call load-bearing
for a cross-user concern rather than mere tidiness. Verified by reading
the SDK, not by executing a logout, and the docs say so.

seenSurvey_<id> genuinely has no deletion trigger and cannot have one:
no PostHog bundle enumerates localStorage (zero occurrences of
localStorage.key( or Object.keys(localStorage) across module.js,
surveys.js and conversations.js), so nothing can discover the keys to
remove them. Stated as the accepted retention position rather than left
silent: the value is "true" under an opaque survey id with no personal
data, and clearing it on logout would re-prompt every survey to the next
person on the device and produce false survey responses.

Adds the review date the A.5.9 remediation asked for, and reframes the
review trigger as a pre-launch step, since Support was caught post-hoc
and left the privacy page inaccurate in the interval.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 17:07:22 +02:00

38 lines
1.6 KiB
TypeScript

import posthog from 'posthog-js'
import { isAnalyticsEnabled } from './enabled'
/**
* Detach the current person from PostHog on logout.
*
* Call this ONLY on the transition out of an identified session, never on an
* initially anonymous page load: reset() discards the anonymous distinct id
* and the history attached to it, so a stray call at boot would sever the
* pre-login part of a signup funnel.
*
* Replaces clearRecaptIdentity() from lib/recapt.ts. That helper also had to
* sweep localStorage by key prefix, because Recapt cached the uid there. We
* run with `persistence: 'memory'`, so there is no cached identity to wipe:
* reset() is sufficient.
*
* This call is load-bearing for shared devices, not just tidiness.
* `posthog.reset()` also resets the conversations manager, which removes the
* `ph_conv_<token>` key holding the support-ticket session id. Without it the
* next person at the same browser would inherit the previous user's ticket
* session. Do not "optimise" this away when analytics is otherwise quiet.
*
* What it does NOT clear: `seenSurvey_<id>`. No PostHog bundle enumerates
* localStorage, so the SDK cannot find those keys to delete them. That is
* accepted, and desirable: clearing them would re-prompt every survey to the
* next person on the device. See the client-side storage inventory in
* .compliance/Data_Classification_Handling.md.
*/
export function resetAnalyticsIdentity(): void {
if (typeof window === 'undefined') return
if (!isAnalyticsEnabled()) return
try {
posthog.reset()
} catch {
// best-effort: we're already in a logout flow
}
}