Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

10 — Interaction Specification (Notifications Module)

Precise interaction rules for the inbox + badge. Motion tokens from 00-shared/08; accessibility baseline 00-shared/09.


1. Item Tap (mark read + optional navigate)

  1. Tap tile → if readAt == null: optimistic flip to read (dot off, weight down, m-fast) → fire PATCH /api/v1/notifications/:id/read (controller.ts:37-41).
  2. Response 200 with document → reconcile (no visual change needed).
  3. Response 200 null (not owner) → revert? No — treat as already-read; remove from unread scope.
  4. Error → retry once silently; then snackbar "Couldn't update" and revert tile.
  5. If data carries a recognized route hint (proposed data.targetUrl) → navigate after successful mark; v1 has no hint → no navigation.

2. Unread Badge Mutations

TriggerEffect
tap item (unread)decrement on optimistic flip; server fail → re-increment
mark-all success→ 0 immediately
inbox openedrefetch count; reconcile with list-derived count if drift
app foreground / loginrefetch count
new notification arrivescount+1 (v1: on next fetch — no WS push, 01 §3)

3. Mark All Read

  • Enabled iff unread > 0 and no in-flight request.
  • Fire PATCH /api/v1/notifications/read-all (controller.ts:43-47) → on success: badge 0, all tiles read (m-fast batch, no per-tile animations), snackbar confirmation.
  • Failure: revert, snackbar with Retry.

4. Pull-to-Refresh

  • Refetch page 1 (and unread-count in parallel). Replace list on success; keep scroll offset when meta.totalItems unchanged.

5. Infinite Scroll

  • Trigger: last visible index ≥ data.length - threshold(4) and meta.hasNext.
  • Fetch page+1; append; dedupe by _id (defensive — server pagination is offset-based, stable under insert-on-top drift can duplicate a row across pages; dedupe client-side, see 14 §B).

6. Unread Filter (proposed v1.1)

  • Chip toggle → reset to page 1 with unreadOnly (dto:21-25); chip shows active state; empty-with-filter shows "all caught up" (05 §3).

7. Swipe-to-Mark-Read (proposed)

  • Dismissible end-dismiss (m-fast) → same as §1 (optimistic + API), no navigate. Do not allow swipe on already-read tiles.

8. Keyboard / Shortcut (desktop)

  • m = mark all read when inbox focused; j/k move focus; Enter = tap. (proposed) — adaptivity in 00-shared/11.

9. Motion Summary

InteractionTokenNote
item read flipm-fastdot fade + weight change, no slide
first-load staggerm-baserows fade, 40 ms stagger
badge count changem-fastscale 1→1.15→1
page swap (filter/refresh replace)m-basecrossfade list
snackbar confirmationsm-basestandard toast