Skip to content

Feature: Notifications On Stream Lifecycle Events #533

Description

@Xhristin3

Context

The notifications subsystem exists but nothing ever creates a notification. NotificationsService.create() (api/src/notifications/notifications.service.ts) persists a row, pushes it over the /streams namespace (gateway.emitNotification), and the user-facing surface — GET /notifications, PATCH /notifications/read-all, PATCH /notifications/:id/read, DELETE /notifications/:id (api/src/notifications/notifications.controller.ts) — is fully built and tested. A repo-wide search shows NotificationsService.create has no callers outside its own spec. The notifications table stays empty, the unread badge can never light up, and the entire feature (issue #398's delivery mechanism) is dead weight.

The natural trigger already exists: StreamsService.update() fires dispatchStatusWebhook on every valid status transition and StreamsService is where the event payloads (startedAt/stoppedAt/occurredAt) are built. A naive implementation would scatter notifications.create() calls through services; the maintainable shape is a single hook site that turns the same lifecycle events into notifications.

Goal

Wire notifications to real events so the notification store, WebSocket push, and unread endpoints become live: notify the stream owner on stream status transitions (and optionally notify on webhook delivery failure, reusing WebhooksService's failure path), driven from one integration point.

Scope

1. Stream lifecycle notifications

  • On a valid PATCH /streams/:id status transition (the same transitions dispatchStatusWebhook handles), create a notification for the stream owner with a typed payload ({ streamId, status, occurredAt }). Reuse the payload shapes in api/src/gateways/stream-events.ts (StreamStartedPayload etc.) so notification payloads and socket payloads cannot drift. Decide whether error transitions get a distinct notification type.

2. Webhook delivery failure notifications (optional but recommended)

  • When a delivery becomes terminally failed (attemptCount exhausts MAX_RETRIES in api/src/webhooks/webhooks.service.ts), create a notification for the subscription owner. This requires WebhooksService to know the owner (the subscription row already carries userId) and to depend on NotificationsService — mirror the @Optional() gateway injection pattern in NotificationsService to keep the webhook path testable.

3. App-side surface

  • The app already has app/src/components/NotificationsDropdown/NotificationsDropdown.tsx; wire it to GET /notifications with the auth header story from the dashboard-auth work, and make the unread badge react to the notification:new socket event (NOTIFICATION_EVENTS.NEW in api/src/gateways/stream-events.ts). No new UI components are required beyond what exists.

Downstream impact

  • api/src/streams/streams.service.ts (notification trigger in update), api/src/webhooks/webhooks.service.ts (failure notifications), api/src/notifications/notifications.service.ts (unchanged API, new callers), api/src/webhooks/webhooks.module.ts / streams.module.ts (module wiring).
  • app/src/components/NotificationsDropdown/NotificationsDropdown.tsx, app/hooks/useNotifications.ts if created.
  • Contracts: extend tests/contracts with GET /notifications so the API shape is pinned.
  • SDK: Notification type if the SDK gains a notifications surface (optional; keep out of scope unless trivial).

Acceptance criteria

Service

  • A valid status transition creates exactly one notification for the stream owner, with read_at null and a payload containing the stream id, new status, and timestamp; invalid transitions create none.
  • The notification is pushed over the socket (notification:new) to the owner's user room and is returned by GET /notifications.
  • Terminally failed webhook deliveries create an owner notification (if the optional scope is taken) with the delivery id and error in the payload.

Tests

  • api/src/streams/streams.service.spec.ts: transitions create notifications with correct payloads; a webhook fan-out failure does not prevent the notification.
  • api/src/webhooks/webhooks.service.spec.ts: exhausted-retry delivery creates a notification; transient failures do not.
  • Contract test for GET /notifications passes in provider and consumer suites.
  • App test: the dropdown renders unread count from the endpoint and updates on notification:new.

Documentation

  • Notification types and triggers documented in the NotificationsService JSDoc and Swagger.

Out of scope

Email/push-channel delivery, notification preferences, and the notification retention sweep (already implemented in NotificationsService.sweepExpired).

Getting started

Real files in scope: api/src/notifications/notifications.service.ts, api/src/streams/streams.service.ts (update, dispatchStatusWebhook), api/src/webhooks/webhooks.service.ts, api/src/gateways/stream-events.ts, app/src/components/NotificationsDropdown/NotificationsDropdown.tsx, tests/contracts/src/ (new contract).

Verify with:

cd api && npm run typecheck && npm test
cd ../app && npm run typecheck && npm test

Good first files to read: api/src/notifications/notifications.service.ts, api/src/streams/streams.service.ts (dispatchStatusWebhook), api/src/gateways/stream-events.ts.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third CampaignapiREST API design and endpointsenhancementNew feature or requestfeaturewebsocketWebSocket / real-time features

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions