coder13 / coder13/LetsCube

Add a typed in-app notification inbox for social actions

Open
#105 0 comments 0 reactions 1 assignee Claimed by @coder13 View on GitHub
area: data area: social enhancement priority: P1
Dominant language
JavaScript
Stars
30
Forks
9
PR merge metrics
No merged PRs in 30d

Description

## 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 #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 #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 #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

- #75 for friend request actions
- #191 for the no-email invariant

## Launch gate

- #188 must pass before broad rollout; it does not block building this foundation.

## Follow-up integration

- #187 adds the room invitation resource and its join/decline notification actions after this foundation exists.

## Non-goals

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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.