KwadMarket Docs
Product Roadmap

Notifications

In-app notification center + email notifications for marketplace events

Build on the event seam

The backend seam for this feature is specified in Operations §4: domain services emit events (deal.status.changed, message created) via @nestjs/event-emitter; one listener module owns mailer templates and, later, the Notification table below — without touching domain services again.

Current state

  • Password reset emails via Resend/SMTP
  • Real-time chat via Socket.IO (per-user unread pushes already consumed by the web app)
  • No in-app notifications, no deal event emails

Channels

ChannelUse casePriority
In-app (bell icon)All eventsV1
EmailDeal status changes, new messages (if offline), payment eventsV1
Push (web)New messages, deal sold, payment receivedV2

Data model

model Notification {
  id        Int      @id @default(autoincrement())
  userId    String
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  type      NotificationType
  title     String
  body      String
  data      Json?    // { dealId: 123, transactionId: 456, etc. }
  read      Boolean  @default(false)
  createdAt DateTime @default(now())

  @@index([userId, read])
  @@index([userId, createdAt])
}

enum NotificationType {
  DEAL_APPROVED
  DEAL_DECLINED
  DEAL_SOLD
  DEAL_EXPIRED
  PAYMENT_RECEIVED
  PAYMENT_RELEASED
  PAYMENT_REFUNDED
  VERIFICATION_APPROVED
  VERIFICATION_REJECTED
  NEW_MESSAGE
  PACKAGE_SHIPPED
  PACKAGE_DELIVERED
  SYSTEM_ANNOUNCEMENT
}

model NotificationPreference {
  userId        String  @id
  user          User    @relation(fields: [userId], references: [id])
  emailDeals    Boolean @default(true)
  emailMessages Boolean @default(true)
  emailPayments Boolean @default(true)
  emailDigest   Boolean @default(true)  // batch emails instead of individual
}

Event → notification matrix

EventWhoChannel
Deal approved / declined by adminSellerIn-app + Email
Someone buys your dealSellerIn-app + Email
Payment confirmedBuyer + SellerIn-app + Email
New chat message (offline 5min+)RecipientIn-app + Email
Package shipped / deliveredBuyer (+ Seller on delivery)In-app (+ Email for shipped)
Funds released / refund issuedSeller / BuyerIn-app + Email
Verification approved / rejectedSellerIn-app (+ Email on reject)
Deal about to expire (7d)SellerIn-app + Email

Architecture

NotificationService
  ├─ create(userId, type, title, body, data)
  │   ├─ Save to DB
  │   ├─ Emit via WebSocket (if user online — user:{id} room already exists)
  │   └─ Queue email (if user offline or email-worthy event)
  ├─ markAsRead(userId, notificationId)
  ├─ markAllAsRead(userId)
  └─ getUnread(userId) → count + list

EmailQueue (BullMQ — Redis already present)
  ├─ Process with Resend API
  ├─ Rate limiting (avoid spam)
  └─ Batch digest: if 5+ unread after 1h, send single digest email

Tasks

Backend: Notification model; NotificationService (create/read/markAsRead); REST endpoints; WebSocket emission on create; email queue (BullMQ + Resend); email templates; digest cron; preferences endpoint; hook into the event listeners from the operations seam — not into domain services directly.

Frontend: bell icon in header with unread badge; notification dropdown/panel; mark-as-read on click (navigates to the relevant page); "mark all as read"; preferences page in profile; real-time delivery via the existing Socket.IO connection.

On this page