Skip to content

feat: real-time notifications system #365

@davedumto

Description

@davedumto

Overview

Users currently have no way to know when they receive a tip, gain a follower, or when a creator they follow goes live. This issue covers the full notifications system from DB schema to UI.

DB schema

CREATE TYPE notification_type AS ENUM (
  'new_follower',
  'tip_received',
  'stream_live',
  'stream_ended',
  'recording_ready'
);

CREATE TABLE notifications (
  id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id     UUID REFERENCES users(id) ON DELETE CASCADE,
  type        notification_type NOT NULL,
  title       TEXT NOT NULL,
  body        TEXT,
  metadata    JSONB,             -- e.g. { sender_username, amount, stream_title }
  read        BOOLEAN DEFAULT false,
  created_at  TIMESTAMPTZ DEFAULT now()
);

CREATE INDEX notifications_user_unread ON notifications(user_id, read, created_at DESC);

API routes

Method Route Description
GET /api/users/notifications Fetch latest 50 notifications for authed user
PATCH /api/users/notifications/:id Mark single notification as read
PATCH /api/users/notifications/read-all Mark all as read
DELETE /api/users/notifications/:id Delete a notification

All routes require session cookie auth (existing pattern from /api/auth/session).

Where to insert notifications

Notifications should be inserted server-side whenever these events occur:

  • new_follower — in POST /api/users/follow when action === "follow"
  • tip_received — in Stellar webhook or after tip transaction confirm
  • stream_live — in POST /api/streams/start
  • recording_ready — in POST /api/webhooks/mux when type === "video.asset.ready"

Real-time delivery

Use Server-Sent Events (SSE) — simplest approach, no new infrastructure needed:

GET /api/users/notifications/stream
  • Returns text/event-stream
  • Polls Postgres every 5s for new unread notifications
  • Sends data: {...} on new rows
  • Client closes connection on unmount

Alternative: polling SWR with refreshInterval: 15000 on the notifications endpoint — acceptable for MVP.

UI

Notification bell (navbar)

  • Add bell icon to top navbar with unread count badge
  • Clicking opens a dropdown panel (max 5 recent, "View all" link)
  • Badge disappears after opening (mark all read)

Notification panel / page

  • /dashboard/notifications or a slide-out drawer
  • List of notifications with:
    • Icon per type (follow → user icon, tip → coins, live → radio dot)
    • Title + body text
    • Relative timestamp (2 min ago)
    • Unread dot indicator
    • Click marks as read and navigates to relevant page

Notification settings

  • app/settings/notifications/page.tsx already exists — extend it with per-type toggles:
    • New followers: on/off
    • Tips received: on/off
    • Creators going live: on/off
    • Recording ready: on/off
    • Email notifications (nodemailer already in deps)

Email notifications

  • Nodemailer is already a dependency
  • Send email for tip_received (creator earned money — high signal event)
  • Use existing email template pattern from @react-email/render

Acceptance criteria

  • notifications table created with migration script
  • Notifications inserted on follow, tip, stream start, recording ready
  • GET /api/users/notifications returns paginated list
  • PATCH routes correctly mark as read
  • Bell icon in navbar shows unread count
  • Notification dropdown shows recent 5 with correct icons and timestamps
  • Per-type notification preferences respected
  • Email sent on tip received (if user has email notifications enabled)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Stellar WaveIssues in the Stellar wave programenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions