Skip to content

Add a typed in-app notification inbox for social actions #105

Description

@coder13

Goal

Provide a durable in-app inbox for Friend System actions, with realtime delivery as an enhancement rather than the source of truth.

MVP notification types

The notification foundation ships first with:

  • incoming friend request;
  • friend request accepted.

It must define the typed extension point that #187 uses for room invitations, but #105 does not wait for the room-invitation resource to be implemented.

Friend presence is shown in the friends hub and does not create a durable "came online" notification. The MVP does not send email, SMS, browser push, or OS notifications.

Safety model

Notifications are typed references to server-owned resources, not arbitrary action definitions, callback URLs, or executable payloads. Each action calls the authenticated relationship/invitation endpoint, which revalidates the current resource state and recipient. A stale notification may become read/non-actionable but can never authorize an operation by itself.

Never ingest, address, search, deliver, or render notifications through email.

Data and delivery

  • Persist recipient, type, actor reference, source type/ID, dedupe key, created/read timestamps, and expiry/retention metadata.
  • MongoDB remains the source of truth; add a backward-compatible PostgreSQL mirror without switching reads.
  • Deduplicate repeated events for the same active source.
  • Send a typed notification_created/updated event to the recipient's existing per-user Socket.IO room.
  • Refetch unread count/recent notifications on connect and reconnect so Redis interruption or missed events self-heal.
  • Expired/resolved resources remain safe to display but have no invalid action.

User experience

  • Header bell with unread count and a compact recent-notification menu.
  • Full /notifications page with cursor pagination.
  • Mark one/all as read.
  • Accept/decline friend requests with pending, success, stale, and error states.
  • Provide a typed renderer/action registry that Let friends invite each other into active rooms #187 can extend with join/decline room-invite actions without accepting arbitrary server-defined callbacks.
  • Keyboard-accessible actions and responsive mobile layout.

Acceptance criteria

  • Define the typed schema, dedupe rules, retention, and source-resource contract.
  • Add authenticated cursor-paginated list/unread/read APIs with recipient-only authorization.
  • Create friend-request/acceptance notifications idempotently from Build the friend request, friendship, and blocking lifecycle #75 state transitions.
  • Add realtime delivery plus reconnect reconciliation through Redux middleware.
  • Add header dropdown, badge, full page, empty/loading/error states, and typed friend actions.
  • Add a safe typed extension seam for Let friends invite each other into active rooms #187's room-invitation notification.
  • Ensure notification payloads never contain access tokens, email, room passwords, private room membership lists, or arbitrary URLs/actions.
  • Add server tests for recipient isolation, pagination, dedupe, stale sources, replay, expiry, read state, and disabled PostgreSQL.
  • Add client tests for unread counts, action races, reconnect, unknown types, accessibility, and mobile layout.
  • Add a two-user Cypress friend-request notification flow.

Dependencies

Launch gate

Follow-up integration

Non-goals

  • Email notifications.
  • Browser/OS push.
  • Direct messages.
  • Durable friend-online alerts.

Metadata

Metadata

Assignees

Labels

area: dataMongoDB, PostgreSQL, migrations, backfills, and data integrityarea: socialFriends, presence, invitations, and notificationsenhancementNew feature or requestpriority: P1High-priority work for the next delivery cycle

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions