Commit 68aa759
[TTAHUB-5539] Specification for actionable notification backend (#3661)
* Add actionble notification specification
* Remove dead link
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Update index.md
* Update index.md
* Update index.md
* Update spec
* Add new subsection
* Update spec
* Correct spelling mistake
* Update spec
* Update delete spec
* [TTAHUB-5383] Add notification model (#3665)
* feat: add Notifications schema (model, migrations, seed, tests)
- 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>
* Simplify model
* Update to add "triggeredAt" to model
* Add all enum types
* Remove digest from notifications enum
* Update model with other needed field
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* [TTAHUB-5385] Add notification scopes (#3668)
* feat: add Notifications schema (model, migrations, seed, tests)
- 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>
* Simplify model
* Update to add "triggeredAt" to model
* Add all enum types
* Scopes, work in progress
* Remove digest from notifications enum
* Add notification scopes
* Register scopes
* Fix bugs, add integration test
* Update model with other needed field
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Rename migration
* Rename seeder
* Add feature flag migration to notifications table
* Fix LDM + missed import
* [TTAHUB-5384] Add notification services (#3673)
* feat: add Notifications schema (model, migrations, seed, tests)
- 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>
* Simplify model
* Update to add "triggeredAt" to model
* Add all enum types
* Scopes, work in progress
* Remove digest from notifications enum
* Add notification scopes
* Register scopes
* Fix bugs, add integration test
* Add services and tests
* Update model with other needed field
* Accomodate missing column in services
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Add notification configuration tests
* fix: replace generic deleteNotification(scopes) with targeted delete 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>
* Fix bad test
* [TTAHUB-5387] Add notification handlers (#3674)
* 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>
* Regenerate Logical Data Model
* Condense down notifications table
* Remove extraneous migration
* Fix LDM bugs
* Remove extra columns from migration
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent 37d116b commit 68aa759
33 files changed
Lines changed: 3460 additions & 65 deletions
File tree
- docs
- specs/actionable-notifications
- src
- middleware
- migrations
- models
- tests
- policies
- routes
- notifications
- scopes
- notifications
- seeders
- services
- types
- widgets
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1057 | 1057 | | |
1058 | 1058 | | |
1059 | 1059 | | |
| 1060 | + | |
| 1061 | + | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
| 1070 | + | |
| 1071 | + | |
| 1072 | + | |
| 1073 | + | |
| 1074 | + | |
| 1075 | + | |
| 1076 | + | |
| 1077 | + | |
| 1078 | + | |
| 1079 | + | |
| 1080 | + | |
| 1081 | + | |
| 1082 | + | |
| 1083 | + | |
1060 | 1084 | | |
1061 | 1085 | | |
1062 | 1086 | | |
| |||
1350 | 1374 | | |
1351 | 1375 | | |
1352 | 1376 | | |
| 1377 | + | |
1353 | 1378 | | |
1354 | 1379 | | |
1355 | 1380 | | |
| |||
2524 | 2549 | | |
2525 | 2550 | | |
2526 | 2551 | | |
| 2552 | + | |
| 2553 | + | |
| 2554 | + | |
| 2555 | + | |
| 2556 | + | |
| 2557 | + | |
| 2558 | + | |
| 2559 | + | |
| 2560 | + | |
| 2561 | + | |
| 2562 | + | |
| 2563 | + | |
| 2564 | + | |
| 2565 | + | |
| 2566 | + | |
| 2567 | + | |
| 2568 | + | |
| 2569 | + | |
| 2570 | + | |
| 2571 | + | |
| 2572 | + | |
| 2573 | + | |
| 2574 | + | |
| 2575 | + | |
| 2576 | + | |
| 2577 | + | |
| 2578 | + | |
| 2579 | + | |
2527 | 2580 | | |
2528 | 2581 | | |
2529 | 2582 | | |
| |||
3038 | 3091 | | |
3039 | 3092 | | |
3040 | 3093 | | |
| 3094 | + | |
3041 | 3095 | | |
3042 | 3096 | | |
3043 | 3097 | | |
| |||
3087 | 3141 | | |
3088 | 3142 | | |
3089 | 3143 | | |
| 3144 | + | |
| 3145 | + | |
3090 | 3146 | | |
3091 | 3147 | | |
3092 | 3148 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
0 commit comments