Skip to content

feat:Notifications: preferences, unread count, and tip/goal triggers - #1115

Merged
Akanimoh12 merged 4 commits into
Akanimoh12:test-implement-dripsfrom
Samuel1505:test-implement-drips
Jul 25, 2026
Merged

feat:Notifications: preferences, unread count, and tip/goal triggers#1115
Akanimoh12 merged 4 commits into
Akanimoh12:test-implement-dripsfrom
Samuel1505:test-implement-drips

Conversation

@Samuel1505

@Samuel1505 Samuel1505 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Notifications: preferences, unread count, and tip/goal triggers

Closes #963,
closes #964,
closes #966,
closes #967

Summary

Implements the four open notifications issues on top of the existing
list/get/mark-read module:

  • Notifications: Notification preferences model + endpoint #967 — Notification preferences model + endpoint. New
    NotificationPreference model (tipReceived / goalReached booleans,
    default true) with GET and PATCH /api/v1/notifications/preferences.
    A missing row is treated as all-enabled, so existing users don't need a
    backfill.
  • Notifications: Unread count endpoint #966 — Unread count endpoint. GET /api/v1/notifications/unread-count
    returns { count } for the caller's unread, non-deleted notifications.
  • Notifications: Notify creator on new tip #963 — Notify creator on new tip. recordTip now calls the new
    createNotification helper once a tip is newly inserted (not on the
    existing-tip or P2002 dedupe paths). Skips self-tips and recipients with
    no off-chain User row; a notification failure is logged and never blocks
    the tip response.
  • Notifications: Notify on goal reached #964 — Notify on goal reached. The indexer's projectGoalReached
    projection notifies the creator the moment a Goal transitions into
    COMPLETED. The transition is detected from the row's prior status (not
    from event-replay bookkeeping), so replaying the same ledger never creates
    a duplicate notification.

createNotification is the shared piece: it persists the Notification row,
checks the caller's preference for that type, and broadcasts over the
existing Socket.IO realtime gateway (emitNotificationCreated) — the same
mechanism already used for tip.created.

Also fixed (blocking, unrelated to the four issues above)

The branch had several unresolved-merge artifacts that broke the build
outright — prisma generate and tsc both failed before any of this work
could be verified:

  • prisma/schema.prisma: the User model had every relation field listed
    twice, and TipStatus was declared as two conflicting enums.
  • src/app.ts: two import blocks were concatenated mid-statement (} on its
    own line) and several routers were mounted twice.
  • src/common/errors/AppError.ts: ServiceUnavailableError was declared
    twice (duplicate identifier).
  • src/modules/x/x.test.ts: a pre-existing tsc error from an unsafe
    globalThis cast (one-line fix, unknown intermediate cast).

These are isolated in their own fix: commit so they're easy to review or
drop separately.

Verification

npm run typecheck   # passes
npm run lint         # passes (0 errors, 6 pre-existing `any` warnings, untouched)
npm run test         # no new failures; 47 pre-existing failures unchanged

The sandbox this was built in has no Docker/Postgres/Redis available, so the
suites that need a live database (tests/*.test.ts integration tests via
resetDb, and src/modules/x/x.test.ts's real-prisma cases) fail exactly as
they did before this change — confirmed by diffing the failing-test list
before and after. All new notification behavior is covered by
mocked-Prisma unit/integration tests (vitest + supertest), matching the
existing pattern in notifications.test.ts, and passes locally. Please
re-run the full suite with docker compose -f backend/docker-compose.yml up -d before merging to confirm the DB-backed suites are unaffected.

New migration

prisma/migrations/20260725033000_add_notification_preference/ — creates
NotificationPreference (unique userId, FK to User with cascade
delete).

Test plan

  • npm run typecheck
  • npm run lint
  • npm run test (mocked unit/integration suites; DB-backed suites
    unverifiable in this sandbox, see above)
  • Re-run npm run test with Postgres + Redis up to confirm DB-backed
    suites still pass
  • Manual check: GET/PATCH /api/v1/notifications/preferences,
    GET /api/v1/notifications/unread-count

prisma/schema.prisma had duplicate User fields and a duplicate
TipStatus enum from an unresolved merge, src/app.ts had two
concatenated import blocks with a dangling `}` and duplicate route
registrations, and AppError.ts declared ServiceUnavailableError
twice. These broke `prisma generate` and `tsc` outright. Also fixes
an unrelated x.test.ts type error (unsafe globalThis cast) that was
blocking `npm run typecheck`.
Adds the NotificationPreference model (per-user tipReceived/goalReached
toggles, defaulting to all-enabled when no row exists) with GET/PATCH
/notifications/preferences, a GET /notifications/unread-count endpoint,
and a createNotification helper that persists a notification, checks
the caller's preferences, and broadcasts it over the realtime gateway.
The helper is shared infrastructure for the tip and goal notification
triggers.

Closes Akanimoh12#966, Akanimoh12#967
recordTip now notifies the receiving creator via createNotification
once a tip is newly inserted (never on the existing-tip or P2002
dedupe paths, so replays don't double-notify). Skips self-tips and
recipients without an off-chain User row, and never lets a
notification failure block the tip response.

Closes Akanimoh12#963
projectGoalReached now calls createNotification once the goal
transitions into COMPLETED. The transition is detected by comparing
against the row's prior status rather than event replay state, so
re-processing the same ledger never creates a duplicate notification.

Closes Akanimoh12#964
@drips-wave

drips-wave Bot commented Jul 25, 2026

Copy link
Copy Markdown

@Samuel1505 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Akanimoh12

Copy link
Copy Markdown
Owner

You tried

@Akanimoh12
Akanimoh12 merged commit f438456 into Akanimoh12:test-implement-drips Jul 25, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants