[TTAHUB-5384] Add notification services#3673
Conversation
- Add NOTIFICATION_TYPES and actionable_notifications feature flag to constants - Create Notifications table migration with all spec columns including archivedAt/viewedAt (DATEONLY) - Add actionable_notifications to enum_Users_flags migration - Create Notification Sequelize model with User association - Add User.hasMany(Notification) association - Add seed data with user-specific and global notifications - Add model tests (8 passing) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…UB/actionable-notification-model
…AHUB/actionable-notification-model
…-5385/add-notification-scopes
…-5385/add-notification-scopes
…5384/add-notification-services
|
|
|
✅ Review count: 2 human approvals — kryswisnaskas, AdamAdHocTeam. |
There was a problem hiding this comment.
Pull request overview
This PR introduces a backend notification service layer (plus typings and tests) to support actionable notifications, with handlers/permission checks planned for a follow-up PR.
Changes:
- Added
NOTIFICATION_CONFIGURATIONinsrc/constants.jsto centralize notification text/link/displayId construction by type. - Added
src/services/notifications.tswith CRUD-style helpers (create user/global notifications, update timestamps, delete by scopes, list with pagination/sorting). - Added service typings and Jest tests validating the service behavior.
Impact assessment:
- Benefits: Medium — establishes a clear, test-covered foundation for notification creation and retrieval.
- Risks: High — current TypeScript typings in
src/services/types/notifications.tsare inconsistent with the Sequelize model and include atypeof+import typepattern that is likely to breakyarn build(tsc). Additionally,getNotificationsaccepts arbitrary sort inputs without normalization/whitelisting, which can lead to brittle runtime behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/services/types/notifications.ts | Introduces TS types for notification service inputs/outputs. |
| src/services/notifications.ts | Adds notification creation, update, delete, and retrieval services. |
| src/services/notifications.test.js | Adds Jest tests covering the new notification services. |
| src/constants.js | Adds notification configuration mapping for text/link/label/displayId builders. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
Codex said: |
…helpers - deleteNotification(notificationId) now accepts a single ID, throws when falsy — eliminates the empty-scopes full-table-delete risk - adds deleteNotificationsByEntityAndType(entityId, notificationType) for event-driven stale-notification cleanup; throws when either arg is falsy - updates and expands tests to cover both new signatures and their guards - updates spec doc with typed signatures and safety-guard notes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
…AHUB-5385/add-notification-scopes
…84/add-notification-services
* fix: cap getNotifications limit at 100 and add comprehensive tests
- Fix Math.max -> Math.min bug in getNotifications limit calculation
- Add handler unit tests (src/routes/notifications/handlers.test.ts)
- Add policy unit tests (src/policies/notifications.test.ts)
- Fix and expand service tests for sort field/direction validation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add param middleware
* Updates from code review
* refactor: separate per-user notification state into NotificationUserStates table
The Notifications table previously stored viewedAt and archivedAt directly
on the notification row. Global notifications (userId=null) could not track
whether different users had independently viewed or archived them — a single
row cannot hold state for multiple users.
Changes:
- Migration: creates NotificationUserStates (notificationId, userId,
viewedAt, archivedAt, UNIQUE on notificationId+userId with FK cascades),
backfills existing per-user state, and drops viewedAt/archivedAt from
Notifications
- New model: NotificationUserState with belongsTo Notification+User
- Notification model: removed archivedAt/viewedAt/isInformational, added
hasMany(NotificationUserState, { as: 'userStates' })
- Service: updateNotification → updateNotificationState(notificationId,
userId, { viewedAt?, archivedAt? }) — upserts per-user state row;
getNotifications(userId, scopes, options) — LEFT JOINs state, filters
archived, returns NotificationWithState[]
- Types: added NotificationUserStateModel and NotificationWithState
- Policy: added isGlobalNotification(); canUpdateNotification() now allows
admin, owner, or global notification (any user can set their own state)
- Handlers: getNotificationsHandler passes userId as first arg;
updateNotificationHandler calls updateNotificationState
- Spec: updated to document new table, service signatures, cleanup logic
- Tests: 121/121 passing across 10 suites
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Update to remove findOrCreate
* Update seeder
* Define relation in both directions
* Update test
* Map scopes to types directly to prevent drift
* Updates from code review
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…UB-5384/add-notification-services
…AHUB-5384/add-notification-services
064fa63
into
mb/TTAHUB-5539/actionable-notification-spec
📊 Review Metrics
Review Timeline
|
Description of change
Add services and tests needed for actionable notifications
Handlers will come in a separate PR and will handle permissions, certain validations (as is our pattern elsewhere in the codebase)
NOTE: updates were made to this code in #3674 to accommodate proper global notification ownership, so your feedback may already have been addressed.
How to test
Validate the code, the tests, and consider the UI requirements
Issue(s)
Checklists
Every PR
Before merge to main
Production Deploy
ready_for_reviewtransition triggers the Slack/Jira automation)elainaparrishis the authorized approver under normal circumstances)After merge/deploy