Skip to content

fix(useNotifications): persist interaction state, not notification snapshots - #893

Open
johnleider wants to merge 1 commit into
devfrom
rework/notifications-interaction-state
Open

fix(useNotifications): persist interaction state, not notification snapshots#893
johnleider wants to merge 1 commit into
devfrom
rework/notifications-interaction-state

Conversation

@johnleider

Copy link
Copy Markdown
Member

Fix-forward for the persist option merged in #384, completing the persist-doctrine pair with #892 (never duplicate a source of truth code recreates on boot).

Was: whole-notification snapshots (subject/body/severity/arbitrary data) re-registered wholesale on restore — deleted notifications resurrected forever, content duplicated code, payloads hit storage, expired snoozes came back.

Now: Record<id, { readAt?, seenAt?, archivedAt?, snoozedUntil? }> — interaction state only, merged onto notifications the app actually registers. Restore never creates tickets; a register:ticket subscription merges saved state onto late arrivals (adapter setup, runtime sends, and the AppBanner's boot registration all ride the same path); expired snoozes drop at coercion and write; unregistered ids GC naturally on the next write; UNSAFE_KEYS guarded; numeric ids round-trip; the old array format is rejected outright (dev never shipped, so a hard schema break was cleared).

Judgment call (flag for review): on merge, storage wins for interaction fields, adapters win for content — a snooze is a local user choice; server-side read-state sync would be a different feature. One-line change in merge if you want adapter interaction state to win instead.

Browser-proven on the real consumer: banner snooze → storage holds only the interaction map (zero content) → reload holds → hand-expired snooze reappears. AppBanner needed no changes.

Changeset edited in place (one changelog entry at the minor). useNotifications 124/124; full sweep 4,765 green; typecheck clean.

…apshots

The merged persist option stored whole notifications (subject, body,
severity, arbitrary data) and restore re-registered them wholesale —
deleted notifications resurrected forever, content duplicated the code
source of truth, payloads landed in storage, and expired snoozes
restored unfiltered. Persistence is now a map of id → { readAt, seenAt,
archivedAt, snoozedUntil } merged onto notifications the app actually
registers: restore never creates tickets, a register:ticket
subscription merges saved state onto late arrivals (adapter and
runtime), expired snoozes drop at both coercion and write, unregistered
ids prune naturally on the next write, and the old array format is
rejected by the shape guard. Storage wins for interaction fields on
merge; adapters win for content.
@johnleider johnleider added this to the v1.1.0 milestone Aug 19, 2026
@johnleider johnleider added the T: bug Something isn't working label Aug 19, 2026
@johnleider johnleider self-assigned this Aug 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ No changeset found

This PR changes packages/* source but has no changeset, so it won't be in the next release's version bump or notes. Add one:

pnpm changeset

Pick the affected package(s) — @vuetify/v0 carries @vuetify/paper automatically; @paper/genesis (and other @paper/* design systems) version separately — a bump type, and a short summary, then commit the generated .changeset/*.md. Docs-only, chore, or CI PRs can ignore this.

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

Labels

T: bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant