Feat/notification service 122#140
Open
iyanumajekodunmi756 wants to merge 2 commits into
Open
Conversation
Implements the Freelancer Discovery API described in Lumina-eX#121: GET /api/freelancers ?q=<text>&skills=react,nodejs&minRating=4&page=2&limit=20 &sort=rating&order=desc GET /api/freelancers/<id> Highlights: * lib/freelancerDiscovery.ts encapsulates the SQL builder, pagination, sort/filter validation, and row -> API shape mapping. * Single-template WHERE fragment with `<null/0 IS 0 OR <pred>>` lets the query issue exactly one DB round-trip per request, with every value bound as a Postgres parameter (no runtime SQL interpolation of the sort column or column name). * ORDER BY is a fully-static switch on (sort, order) with literal ASC/DESC inlined per branch. * Backward compatible with the existing /freelancers page: legacy ?rating= alias accepted, response shape unchanged, ?skills accepts both repeating and comma-separated values. * Structured error responses ({error, code}) for invalid query params and downstream failures (400 / 503). * GET /api/freelancers/[id] returns { freelancer, reputation } with reputation loaded best-effort; null on lookup failure so the page still renders. * scripts/010-freelancer-discovery-indexes.sql adds a GIN index on users.skills (skill-overlap + ILIKE search), a btree on users.rating DESC, and a partial index on user_type IN (freelancer, both). * 22 unit tests covering parse, validation, list/detail happy paths, pagination, fallback COUNT, validation errors, and 503 on DB error.
Implements the Notification Service Backend described in Lumina-eX#122. Endpoints GET /api/notifications list w/ pagination, type filter, unread toggle PATCH /api/notifications/[id]/read mark single read POST /api/notifications/read-all mark all read (returns updatedCount) GET /api/notifications/stream SSE real-time push + 25s keep-alive Layers lib/notifications.ts * typed NOTIFICATION_EVENT_TYPES whitelist + LEGACY aliases * NotificationError with stable {code, message} -> 400 mapping * parseNotificationQuery validation (page, limit, type, unreadOnly) * mapNotificationRow (snake -> camel, Date -> ISO) * createNotification persists + best-effort hub fan-out * listNotificationsForUser uses COUNT(*) OVER() so data + total arrive in a single round-trip * markNotificationRead returns {notification|null} so callers can distinguish 404 from 200 without an extra read * markAllNotificationsRead uses a CTE so updatedCount only counts rows flipped by THIS call (previously inflated by prior reads) * NotificationHub singleton: subscribe / publish / unsubscribe / subscriberCount for the SSE channel * notifyContractCreated / notifyMilestoneSubmitted / Approved / notifyEscrowReleased / notifyDisputeCreated event helpers lib/auth/middleware.ts * new withAuthCtx<Ctx> wrapper for handlers that need the Next.js route context (params) * new resolveUserIdByWallet(wallet) helper, shared across the four notification routes (no more inline duplication) app/api/notifications/{route, [id]/read/route, read-all/route, stream/route}.ts * withAuth / withAuthCtx wrappers * granular status mapping (200/400/401/404/500/503) * SSE stream with shared cleanup path reachable from BOTH request.signal abort and consumer cancel() Schema (scripts/011-notification-service.sql) * event_type CHECK constraint covering worker legacy types (info/success/warning) + domain events (contract_created, milestone_submitted, milestone_approved, escrow_released, escrow_refunded, dispute_created, dispute_resolved) * payload JSONB + channel + delivered_at columns * composite indexes (user_id, is_read, created_at) and (user_id, event_type, created_at) for the GET filters * CASE-based backfill so a stray legacy type cannot break ADD CONSTRAINT CHECK Tests __tests__/api/notifications.test.ts (34 tests) * parseNotificationQuery edge cases * mapNotificationRow shape * createNotification persists + publishes + tolerates broken subscribers + handles empty insert * listNotificationsForUser pagination + COUNT(*) OVER() + invalid user id * markNotificationRead owner-mismatch -> null, success path * markAllNotificationsRead CTE returns updated_count * NotificationHub subscribe/unsubscribe/isolated-fanout * GET /api/notifications happy path, 400 invalid type, 503 DB fail * PATCH /api/notifications/[id]/read 200, 404, 400 invalid id, 404 when wallet does not map to a user * POST /api/notifications/read-all 200 + updatedCount * GET /api/notifications/stream SSE headers + cancel cleanup * event-creation helpers (one notification per recipient) Validation * npx tsc --noEmit -> clean for changed files * npx eslint -> 0 errors / 0 warnings for changed files * npm run test -- --run __tests__/api/{notifications, freelancers}.test.ts __tests__/rbac.test.ts -> 89/89 passing * git merge-tree against upstream/main -> no conflicts Out of scope (intentional, follow-up PRs) * wiring notifyContractCreated/notifyMilestoneSubmitted/... into escrow.create, milestones.submit, escrow.release and dispute.resolve route handlers * multi-instance fan-out (Redis pub/sub backplane) for horizontally-scaled deployments Refs Lumina-eX#122
|
@iyanumajekodunmi756 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! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem Statement
Description
Implement a backend notification system to handle important group and contract-related events, ensuring real-time delivery and persistent storage.
Events
Contract creation
Milestone submission
Escrow release
Dispute creation
Requirements
Store notifications in database with fields: id, userId, eventType, message, timestamp, read
Support read/unread status updates
Provide API endpoints to fetch notifications (with pagination and filtering)
Deliver notifications in real time via WebSocket or push events
Ensure proper error handling and logging for failed delivery attempts
Tasks
Define notification schema in database
Implement notification creation logic triggered by events
Build API endpoints for fetching and updating notifications
Integrate WebSocket/push service for real-time delivery
Add unit tests for notification creation, retrieval, and status updates
Acceptance Criteria
Notifications stored reliably in database with correct event mapping
Read/unread status supported and persisted
Notifications delivered in real time to connected clients
API endpoints documented for frontend integration
Pagination supported for large notification lists
Unit tests pass for backend logic and API endpoints
📈 Expected Impact
High — Would significantly improve user experience
closes #122