@open-mercato/core 0.4.2-canary-07dbc98202 → 0.4.2-canary-11e19dfb84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/dist/generated/entities.ids.generated.js +59 -63
  2. package/dist/generated/entities.ids.generated.js.map +2 -2
  3. package/dist/generated/entity-fields-registry.js +0 -2
  4. package/dist/generated/entity-fields-registry.js.map +2 -2
  5. package/dist/modules/api_docs/frontend/docs/api/page.js +2 -3
  6. package/dist/modules/api_docs/frontend/docs/api/page.js.map +2 -2
  7. package/dist/modules/auth/api/admin/nav.js +3 -4
  8. package/dist/modules/auth/api/admin/nav.js.map +2 -2
  9. package/dist/modules/auth/api/reset/confirm.js +2 -25
  10. package/dist/modules/auth/api/reset/confirm.js.map +2 -2
  11. package/dist/modules/auth/api/reset.js +0 -23
  12. package/dist/modules/auth/api/reset.js.map +2 -2
  13. package/dist/modules/auth/api/sidebar/preferences/route.js +9 -14
  14. package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
  15. package/dist/modules/auth/commands/users.js +0 -55
  16. package/dist/modules/auth/commands/users.js.map +2 -2
  17. package/dist/modules/auth/lib/setup-app.js +0 -1
  18. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  19. package/dist/modules/auth/services/authService.js +3 -3
  20. package/dist/modules/auth/services/authService.js.map +2 -2
  21. package/dist/modules/configs/cli.js +0 -6
  22. package/dist/modules/configs/cli.js.map +2 -2
  23. package/dist/modules/customers/commands/deals.js +0 -31
  24. package/dist/modules/customers/commands/deals.js.map +2 -2
  25. package/dist/modules/sales/commands/documents.js +0 -53
  26. package/dist/modules/sales/commands/documents.js.map +2 -2
  27. package/dist/modules/sales/commands/payments.js +0 -26
  28. package/dist/modules/sales/commands/payments.js.map +2 -2
  29. package/dist/modules/staff/commands/leave-requests.js +0 -79
  30. package/dist/modules/staff/commands/leave-requests.js.map +2 -2
  31. package/generated/entities.ids.generated.ts +59 -63
  32. package/generated/entity-fields-registry.ts +0 -2
  33. package/package.json +2 -2
  34. package/src/modules/api_docs/frontend/docs/api/page.tsx +2 -3
  35. package/src/modules/auth/api/admin/nav.ts +6 -10
  36. package/src/modules/auth/api/reset/confirm.ts +2 -25
  37. package/src/modules/auth/api/reset.ts +0 -23
  38. package/src/modules/auth/api/sidebar/preferences/route.ts +12 -21
  39. package/src/modules/auth/commands/users.ts +0 -68
  40. package/src/modules/auth/i18n/de.json +1 -29
  41. package/src/modules/auth/i18n/en.json +1 -29
  42. package/src/modules/auth/i18n/es.json +1 -29
  43. package/src/modules/auth/i18n/pl.json +1 -29
  44. package/src/modules/auth/lib/setup-app.ts +0 -1
  45. package/src/modules/auth/services/authService.ts +4 -4
  46. package/src/modules/business_rules/i18n/en.json +1 -3
  47. package/src/modules/catalog/i18n/en.json +1 -3
  48. package/src/modules/configs/cli.ts +0 -6
  49. package/src/modules/customers/commands/deals.ts +0 -39
  50. package/src/modules/customers/i18n/en.json +1 -5
  51. package/src/modules/sales/commands/documents.ts +0 -65
  52. package/src/modules/sales/commands/payments.ts +0 -33
  53. package/src/modules/sales/i18n/de.json +0 -20
  54. package/src/modules/sales/i18n/en.json +1 -25
  55. package/src/modules/sales/i18n/es.json +0 -20
  56. package/src/modules/sales/i18n/pl.json +0 -20
  57. package/src/modules/staff/commands/leave-requests.ts +0 -94
  58. package/src/modules/staff/i18n/de.json +0 -4
  59. package/src/modules/staff/i18n/en.json +1 -9
  60. package/src/modules/staff/i18n/es.json +0 -4
  61. package/src/modules/staff/i18n/pl.json +0 -4
  62. package/src/modules/workflows/i18n/en.json +1 -3
  63. package/dist/generated/entities/notification/index.js +0 -57
  64. package/dist/generated/entities/notification/index.js.map +0 -7
  65. package/dist/modules/auth/api/profile/route.js +0 -155
  66. package/dist/modules/auth/api/profile/route.js.map +0 -7
  67. package/dist/modules/auth/backend/auth/profile/page.js +0 -99
  68. package/dist/modules/auth/backend/auth/profile/page.js.map +0 -7
  69. package/dist/modules/auth/backend/auth/profile/page.meta.js +0 -12
  70. package/dist/modules/auth/backend/auth/profile/page.meta.js.map +0 -7
  71. package/dist/modules/auth/notifications.js +0 -112
  72. package/dist/modules/auth/notifications.js.map +0 -7
  73. package/dist/modules/business_rules/notifications.js +0 -28
  74. package/dist/modules/business_rules/notifications.js.map +0 -7
  75. package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js +0 -37
  76. package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js.map +0 -7
  77. package/dist/modules/catalog/notifications.js +0 -28
  78. package/dist/modules/catalog/notifications.js.map +0 -7
  79. package/dist/modules/catalog/subscribers/low-stock-notification.js +0 -38
  80. package/dist/modules/catalog/subscribers/low-stock-notification.js.map +0 -7
  81. package/dist/modules/customers/notifications.js +0 -48
  82. package/dist/modules/customers/notifications.js.map +0 -7
  83. package/dist/modules/notifications/acl.js +0 -11
  84. package/dist/modules/notifications/acl.js.map +0 -7
  85. package/dist/modules/notifications/api/[id]/action/route.js +0 -74
  86. package/dist/modules/notifications/api/[id]/action/route.js.map +0 -7
  87. package/dist/modules/notifications/api/[id]/dismiss/route.js +0 -15
  88. package/dist/modules/notifications/api/[id]/dismiss/route.js.map +0 -7
  89. package/dist/modules/notifications/api/[id]/read/route.js +0 -15
  90. package/dist/modules/notifications/api/[id]/read/route.js.map +0 -7
  91. package/dist/modules/notifications/api/[id]/restore/route.js +0 -53
  92. package/dist/modules/notifications/api/[id]/restore/route.js.map +0 -7
  93. package/dist/modules/notifications/api/batch/route.js +0 -17
  94. package/dist/modules/notifications/api/batch/route.js.map +0 -7
  95. package/dist/modules/notifications/api/feature/route.js +0 -17
  96. package/dist/modules/notifications/api/feature/route.js.map +0 -7
  97. package/dist/modules/notifications/api/mark-all-read/route.js +0 -35
  98. package/dist/modules/notifications/api/mark-all-read/route.js.map +0 -7
  99. package/dist/modules/notifications/api/openapi.js +0 -76
  100. package/dist/modules/notifications/api/openapi.js.map +0 -7
  101. package/dist/modules/notifications/api/role/route.js +0 -17
  102. package/dist/modules/notifications/api/role/route.js.map +0 -7
  103. package/dist/modules/notifications/api/route.js +0 -85
  104. package/dist/modules/notifications/api/route.js.map +0 -7
  105. package/dist/modules/notifications/api/settings/route.js +0 -155
  106. package/dist/modules/notifications/api/settings/route.js.map +0 -7
  107. package/dist/modules/notifications/api/unread-count/route.js +0 -38
  108. package/dist/modules/notifications/api/unread-count/route.js.map +0 -7
  109. package/dist/modules/notifications/backend/config/notifications/page.js +0 -10
  110. package/dist/modules/notifications/backend/config/notifications/page.js.map +0 -7
  111. package/dist/modules/notifications/backend/config/notifications/page.meta.js +0 -24
  112. package/dist/modules/notifications/backend/config/notifications/page.meta.js.map +0 -7
  113. package/dist/modules/notifications/cli.js +0 -16
  114. package/dist/modules/notifications/cli.js.map +0 -7
  115. package/dist/modules/notifications/data/entities.js +0 -112
  116. package/dist/modules/notifications/data/entities.js.map +0 -7
  117. package/dist/modules/notifications/data/validators.js +0 -94
  118. package/dist/modules/notifications/data/validators.js.map +0 -7
  119. package/dist/modules/notifications/di.js +0 -13
  120. package/dist/modules/notifications/di.js.map +0 -7
  121. package/dist/modules/notifications/emails/NotificationEmail.js +0 -58
  122. package/dist/modules/notifications/emails/NotificationEmail.js.map +0 -7
  123. package/dist/modules/notifications/frontend/NotificationInboxPageClient.js +0 -44
  124. package/dist/modules/notifications/frontend/NotificationInboxPageClient.js.map +0 -7
  125. package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +0 -219
  126. package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +0 -7
  127. package/dist/modules/notifications/index.js +0 -14
  128. package/dist/modules/notifications/index.js.map +0 -7
  129. package/dist/modules/notifications/lib/deliveryConfig.js +0 -105
  130. package/dist/modules/notifications/lib/deliveryConfig.js.map +0 -7
  131. package/dist/modules/notifications/lib/events.js +0 -12
  132. package/dist/modules/notifications/lib/events.js.map +0 -7
  133. package/dist/modules/notifications/lib/notificationBuilder.js +0 -66
  134. package/dist/modules/notifications/lib/notificationBuilder.js.map +0 -7
  135. package/dist/modules/notifications/lib/notificationFactory.js +0 -54
  136. package/dist/modules/notifications/lib/notificationFactory.js.map +0 -7
  137. package/dist/modules/notifications/lib/notificationMapper.js +0 -34
  138. package/dist/modules/notifications/lib/notificationMapper.js.map +0 -7
  139. package/dist/modules/notifications/lib/notificationRecipients.js +0 -35
  140. package/dist/modules/notifications/lib/notificationRecipients.js.map +0 -7
  141. package/dist/modules/notifications/lib/notificationService.js +0 -279
  142. package/dist/modules/notifications/lib/notificationService.js.map +0 -7
  143. package/dist/modules/notifications/lib/routeHelpers.js +0 -101
  144. package/dist/modules/notifications/lib/routeHelpers.js.map +0 -7
  145. package/dist/modules/notifications/lib/safeHref.js +0 -24
  146. package/dist/modules/notifications/lib/safeHref.js.map +0 -7
  147. package/dist/modules/notifications/migrations/Migration20260123000001.js +0 -70
  148. package/dist/modules/notifications/migrations/Migration20260123000001.js.map +0 -7
  149. package/dist/modules/notifications/migrations/Migration20260126150000.js +0 -37
  150. package/dist/modules/notifications/migrations/Migration20260126150000.js.map +0 -7
  151. package/dist/modules/notifications/subscribers/deliver-notification.js +0 -139
  152. package/dist/modules/notifications/subscribers/deliver-notification.js.map +0 -7
  153. package/dist/modules/notifications/workers/create-notification.worker.js +0 -70
  154. package/dist/modules/notifications/workers/create-notification.worker.js.map +0 -7
  155. package/dist/modules/sales/notifications.client.js +0 -51
  156. package/dist/modules/sales/notifications.client.js.map +0 -7
  157. package/dist/modules/sales/notifications.js +0 -88
  158. package/dist/modules/sales/notifications.js.map +0 -7
  159. package/dist/modules/sales/subscribers/quote-expiring-notification.js +0 -38
  160. package/dist/modules/sales/subscribers/quote-expiring-notification.js.map +0 -7
  161. package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +0 -137
  162. package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +0 -7
  163. package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +0 -137
  164. package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +0 -7
  165. package/dist/modules/sales/widgets/notifications/index.js +0 -7
  166. package/dist/modules/sales/widgets/notifications/index.js.map +0 -7
  167. package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js +0 -60
  168. package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js.map +0 -7
  169. package/dist/modules/staff/notifications.js +0 -75
  170. package/dist/modules/staff/notifications.js.map +0 -7
  171. package/dist/modules/workflows/notifications.js +0 -28
  172. package/dist/modules/workflows/notifications.js.map +0 -7
  173. package/dist/modules/workflows/subscribers/task-assigned-notification.js +0 -38
  174. package/dist/modules/workflows/subscribers/task-assigned-notification.js.map +0 -7
  175. package/generated/entities/notification/index.ts +0 -27
  176. package/src/modules/auth/api/profile/route.ts +0 -160
  177. package/src/modules/auth/backend/auth/profile/page.meta.ts +0 -8
  178. package/src/modules/auth/backend/auth/profile/page.tsx +0 -127
  179. package/src/modules/auth/notifications.ts +0 -109
  180. package/src/modules/business_rules/notifications.ts +0 -25
  181. package/src/modules/business_rules/subscribers/rule-execution-failed-notification.ts +0 -50
  182. package/src/modules/catalog/notifications.ts +0 -25
  183. package/src/modules/catalog/subscribers/low-stock-notification.ts +0 -52
  184. package/src/modules/customers/notifications.ts +0 -44
  185. package/src/modules/notifications/acl.ts +0 -7
  186. package/src/modules/notifications/api/[id]/action/route.ts +0 -75
  187. package/src/modules/notifications/api/[id]/dismiss/route.ts +0 -12
  188. package/src/modules/notifications/api/[id]/read/route.ts +0 -12
  189. package/src/modules/notifications/api/[id]/restore/route.ts +0 -53
  190. package/src/modules/notifications/api/batch/route.ts +0 -14
  191. package/src/modules/notifications/api/feature/route.ts +0 -14
  192. package/src/modules/notifications/api/mark-all-read/route.ts +0 -34
  193. package/src/modules/notifications/api/openapi.ts +0 -76
  194. package/src/modules/notifications/api/role/route.ts +0 -14
  195. package/src/modules/notifications/api/route.ts +0 -92
  196. package/src/modules/notifications/api/settings/route.ts +0 -157
  197. package/src/modules/notifications/api/unread-count/route.ts +0 -38
  198. package/src/modules/notifications/backend/config/notifications/page.meta.ts +0 -22
  199. package/src/modules/notifications/backend/config/notifications/page.tsx +0 -12
  200. package/src/modules/notifications/cli.ts +0 -18
  201. package/src/modules/notifications/data/entities.ts +0 -99
  202. package/src/modules/notifications/data/validators.ts +0 -110
  203. package/src/modules/notifications/di.ts +0 -11
  204. package/src/modules/notifications/emails/NotificationEmail.tsx +0 -98
  205. package/src/modules/notifications/frontend/NotificationInboxPageClient.tsx +0 -42
  206. package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +0 -231
  207. package/src/modules/notifications/i18n/de.json +0 -50
  208. package/src/modules/notifications/i18n/en.json +0 -50
  209. package/src/modules/notifications/i18n/es.json +0 -50
  210. package/src/modules/notifications/i18n/pl.json +0 -50
  211. package/src/modules/notifications/index.ts +0 -12
  212. package/src/modules/notifications/lib/deliveryConfig.ts +0 -145
  213. package/src/modules/notifications/lib/events.ts +0 -48
  214. package/src/modules/notifications/lib/notificationBuilder.ts +0 -121
  215. package/src/modules/notifications/lib/notificationFactory.ts +0 -76
  216. package/src/modules/notifications/lib/notificationMapper.ts +0 -33
  217. package/src/modules/notifications/lib/notificationRecipients.ts +0 -83
  218. package/src/modules/notifications/lib/notificationService.ts +0 -414
  219. package/src/modules/notifications/lib/routeHelpers.ts +0 -151
  220. package/src/modules/notifications/lib/safeHref.ts +0 -29
  221. package/src/modules/notifications/migrations/.snapshot-open-mercato.json +0 -300
  222. package/src/modules/notifications/migrations/Migration20260123000001.ts +0 -73
  223. package/src/modules/notifications/migrations/Migration20260126150000.ts +0 -39
  224. package/src/modules/notifications/subscribers/deliver-notification.ts +0 -175
  225. package/src/modules/notifications/workers/create-notification.worker.ts +0 -122
  226. package/src/modules/sales/notifications.client.ts +0 -65
  227. package/src/modules/sales/notifications.ts +0 -82
  228. package/src/modules/sales/subscribers/quote-expiring-notification.ts +0 -53
  229. package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +0 -156
  230. package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +0 -156
  231. package/src/modules/sales/widgets/notifications/index.ts +0 -2
  232. package/src/modules/sales/widgets/notifications/useSalesDocumentTotals.ts +0 -81
  233. package/src/modules/staff/notifications.ts +0 -71
  234. package/src/modules/workflows/notifications.ts +0 -25
  235. package/src/modules/workflows/subscribers/task-assigned-notification.ts +0 -53
@@ -64,16 +64,12 @@ export async function GET(req: Request) {
64
64
  { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null },
65
65
  ) ?? false
66
66
 
67
- // For API key auth, use userId (the actual user) if available
68
- const effectiveUserId = auth.isApiKey ? auth.userId : auth.sub
69
- const settings = effectiveUserId
70
- ? await loadSidebarPreference(em, {
71
- userId: effectiveUserId,
72
- tenantId: auth.tenantId ?? null,
73
- organizationId: auth.orgId ?? null,
74
- locale,
75
- })
76
- : null
67
+ const settings = await loadSidebarPreference(em, {
68
+ userId: auth.sub,
69
+ tenantId: auth.tenantId ?? null,
70
+ organizationId: auth.orgId ?? null,
71
+ locale,
72
+ })
77
73
 
78
74
  let rolesPayload: Array<{ id: string; name: string; hasPreference: boolean }> = []
79
75
  if (canApplyToRoles) {
@@ -96,11 +92,11 @@ export async function GET(req: Request) {
96
92
  return NextResponse.json({
97
93
  locale,
98
94
  settings: {
99
- version: settings?.version ?? SIDEBAR_PREFERENCES_VERSION,
100
- groupOrder: settings?.groupOrder ?? [],
101
- groupLabels: settings?.groupLabels ?? {},
102
- itemLabels: settings?.itemLabels ?? {},
103
- hiddenItems: settings?.hiddenItems ?? [],
95
+ version: settings.version ?? SIDEBAR_PREFERENCES_VERSION,
96
+ groupOrder: settings.groupOrder ?? [],
97
+ groupLabels: settings.groupLabels ?? {},
98
+ itemLabels: settings.itemLabels ?? {},
99
+ hiddenItems: settings.hiddenItems ?? [],
104
100
  },
105
101
  canApplyToRoles,
106
102
  roles: rolesPayload,
@@ -110,11 +106,6 @@ export async function GET(req: Request) {
110
106
  export async function PUT(req: Request) {
111
107
  const auth = await getAuthFromRequest(req)
112
108
  if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
113
- // For API key auth, use userId (the actual user) if available
114
- const effectiveUserId = auth.isApiKey ? auth.userId : auth.sub
115
- if (!effectiveUserId) {
116
- return NextResponse.json({ error: 'Cannot save preferences: no user associated with this API key' }, { status: 403 })
117
- }
118
109
 
119
110
  let parsedBody: unknown
120
111
  try {
@@ -191,7 +182,7 @@ export async function PUT(req: Request) {
191
182
  }
192
183
 
193
184
  const settings = await saveSidebarPreference(em, {
194
- userId: effectiveUserId,
185
+ userId: auth.sub,
195
186
  tenantId: auth.tenantId ?? null,
196
187
  organizationId: auth.orgId ?? null,
197
188
  locale,
@@ -27,9 +27,6 @@ import {
27
27
  import { normalizeTenantId } from '@open-mercato/core/modules/auth/lib/tenantAccess'
28
28
  import { computeEmailHash } from '@open-mercato/core/modules/auth/lib/emailHash'
29
29
  import { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
30
- import { buildNotificationFromType } from '@open-mercato/core/modules/notifications/lib/notificationBuilder'
31
- import { resolveNotificationService } from '@open-mercato/core/modules/notifications/lib/notificationService'
32
- import notificationTypes from '@open-mercato/core/modules/auth/notifications'
33
30
 
34
31
  type SerializedUser = {
35
32
  email: string
@@ -108,46 +105,6 @@ export const userCrudIndexer: CrudIndexerConfig = {
108
105
  }),
109
106
  }
110
107
 
111
- async function notifyRoleChanges(
112
- ctx: CommandRuntimeContext,
113
- user: User,
114
- assignedRoles: string[],
115
- revokedRoles: string[],
116
- ): Promise<void> {
117
- const tenantId = user.tenantId ? String(user.tenantId) : null
118
- if (!tenantId) return
119
- const organizationId = user.organizationId ? String(user.organizationId) : null
120
-
121
- try {
122
- const notificationService = resolveNotificationService(ctx.container)
123
- if (assignedRoles.length) {
124
- const assignedType = notificationTypes.find((type) => type.type === 'auth.role.assigned')
125
- if (assignedType) {
126
- const notificationInput = buildNotificationFromType(assignedType, {
127
- recipientUserId: String(user.id),
128
- sourceEntityType: 'auth:user',
129
- sourceEntityId: String(user.id),
130
- })
131
- await notificationService.create(notificationInput, { tenantId, organizationId })
132
- }
133
- }
134
-
135
- if (revokedRoles.length) {
136
- const revokedType = notificationTypes.find((type) => type.type === 'auth.role.revoked')
137
- if (revokedType) {
138
- const notificationInput = buildNotificationFromType(revokedType, {
139
- recipientUserId: String(user.id),
140
- sourceEntityType: 'auth:user',
141
- sourceEntityId: String(user.id),
142
- })
143
- await notificationService.create(notificationInput, { tenantId, organizationId })
144
- }
145
- }
146
- } catch (err) {
147
- console.error('[auth.users.roles] Failed to create notification:', err)
148
- }
149
- }
150
-
151
108
  const createUserCommand: CommandHandler<Record<string, unknown>, User> = {
152
109
  id: 'auth.users.create',
153
110
  async execute(rawInput, ctx) {
@@ -190,10 +147,8 @@ const createUserCommand: CommandHandler<Record<string, unknown>, User> = {
190
147
  throw error
191
148
  }
192
149
 
193
- let assignedRoles: string[] = []
194
150
  if (Array.isArray(parsed.roles) && parsed.roles.length) {
195
151
  await syncUserRoles(em, user, parsed.roles, tenantId)
196
- assignedRoles = await loadUserRoleNames(em, String(user.id))
197
152
  }
198
153
 
199
154
  await setCustomFieldsIfAny({
@@ -218,10 +173,6 @@ const createUserCommand: CommandHandler<Record<string, unknown>, User> = {
218
173
  indexer: userCrudIndexer,
219
174
  })
220
175
 
221
- if (assignedRoles.length) {
222
- await notifyRoleChanges(ctx, user, assignedRoles, [])
223
- }
224
-
225
176
  return user
226
177
  },
227
178
  captureAfter: async (_input, result, ctx) => {
@@ -337,9 +288,6 @@ const updateUserCommand: CommandHandler<Record<string, unknown>, User> = {
337
288
  async execute(rawInput, ctx) {
338
289
  const { parsed, custom } = parseWithCustomFields(updateSchema, rawInput)
339
290
  const em = (ctx.container.resolve('em') as EntityManager)
340
- const rolesBefore = Array.isArray(parsed.roles)
341
- ? await loadUserRoleNames(em, parsed.id)
342
- : null
343
291
 
344
292
  if (parsed.email !== undefined) {
345
293
  const emailHash = computeEmailHash(parsed.email)
@@ -429,14 +377,6 @@ const updateUserCommand: CommandHandler<Record<string, unknown>, User> = {
429
377
  indexer: userCrudIndexer,
430
378
  })
431
379
 
432
- if (Array.isArray(parsed.roles) && rolesBefore) {
433
- const rolesAfter = await loadUserRoleNames(em, String(user.id))
434
- const { assigned, revoked } = diffRoleChanges(rolesBefore, rolesAfter)
435
- if (assigned.length || revoked.length) {
436
- await notifyRoleChanges(ctx, user, assigned, revoked)
437
- }
438
- }
439
-
440
380
  await invalidateUserCache(ctx, parsed.id)
441
381
 
442
382
  return user
@@ -832,14 +772,6 @@ async function invalidateUserCache(ctx: CommandRuntimeContext, userId: string) {
832
772
  }
833
773
  }
834
774
 
835
- function diffRoleChanges(before: string[], after: string[]) {
836
- const beforeSet = new Set(before)
837
- const afterSet = new Set(after)
838
- const assigned = after.filter((role) => !beforeSet.has(role))
839
- const revoked = before.filter((role) => !afterSet.has(role))
840
- return { assigned, revoked }
841
- }
842
-
843
775
  function arrayEquals(left: string[] | undefined, right: string[]): boolean {
844
776
  if (!left) return false
845
777
  if (left.length !== right.length) return false
@@ -80,19 +80,6 @@
80
80
  "auth.users.form.errors.load": "Benutzerdaten konnten nicht geladen werden",
81
81
  "auth.users.form.errors.aclUpdate": "Aktualisierung der Benutzerberechtigungen fehlgeschlagen",
82
82
  "auth.users.form.errors.delete": "Benutzer konnte nicht gelöscht werden",
83
- "auth.profile.title": "Profil",
84
- "auth.profile.form.email": "E-Mail",
85
- "auth.profile.form.password": "Neues Passwort",
86
- "auth.profile.form.confirmPassword": "Neues Passwort bestätigen",
87
- "auth.profile.form.save": "Änderungen speichern",
88
- "auth.profile.form.loading": "Profil wird geladen...",
89
- "auth.profile.form.errors.load": "Profil konnte nicht geladen werden.",
90
- "auth.profile.form.errors.save": "Profil konnte nicht aktualisiert werden.",
91
- "auth.profile.form.errors.invalid": "Ungültige Profilaktualisierung.",
92
- "auth.profile.form.errors.passwordMismatch": "Die Passwörter stimmen nicht überein.",
93
- "auth.profile.form.errors.noChanges": "Keine Änderungen zu speichern.",
94
- "auth.profile.form.errors.emailRequired": "E-Mail ist erforderlich.",
95
- "auth.profile.form.success": "Profil aktualisiert.",
96
83
  "auth.users.list.error.load": "Benutzer konnten nicht geladen werden",
97
84
  "auth.users.list.error.delete": "Benutzer konnte nicht gelöscht werden",
98
85
  "auth.users.flash.created": "Benutzer erstellt",
@@ -108,20 +95,5 @@
108
95
  "auth.email.resetPassword.title": "Passwort zurücksetzen",
109
96
  "auth.email.resetPassword.body": "Klicken Sie auf den Link unten, um ein neues Passwort festzulegen. Dieser Link läuft in 60 Minuten ab.",
110
97
  "auth.email.resetPassword.cta": "Neues Passwort festlegen",
111
- "auth.email.resetPassword.hint": "Wenn Sie dies nicht angefordert haben, können Sie diese E-Mail ignorieren.",
112
- "auth.notifications.passwordReset.requested.title": "Passwort-Zurücksetzung angefordert",
113
- "auth.notifications.passwordReset.requested.body": "Ein Link zum Zurücksetzen des Passworts wurde an Ihre E-Mail gesendet",
114
- "auth.notifications.passwordReset.completed.title": "Passwort erfolgreich geändert",
115
- "auth.notifications.passwordReset.completed.body": "Ihr Passwort wurde erfolgreich aktualisiert",
116
- "auth.notifications.account.locked.title": "Konto gesperrt",
117
- "auth.notifications.account.locked.body": "Ihr Konto wurde aus Sicherheitsgründen gesperrt. Bitte wenden Sie sich an den Support.",
118
- "auth.notifications.login.newDevice.title": "Neues Gerät erkannt",
119
- "auth.notifications.login.newDevice.body": "Es wurde eine Anmeldung von einem unbekannten Gerät für Ihr Konto erkannt",
120
- "auth.notifications.role.assigned.title": "Neue Rolle zugewiesen",
121
- "auth.notifications.role.assigned.body": "Ihnen wurde eine neue Rolle mit zusätzlichen Berechtigungen zugewiesen",
122
- "auth.notifications.role.revoked.title": "Rolle entfernt",
123
- "auth.notifications.role.revoked.body": "Eine Rolle wurde von Ihrem Konto entfernt",
124
- "auth.actions.contactSupport": "Support kontaktieren",
125
- "auth.actions.viewSessions": "Sitzungen anzeigen",
126
- "auth.actions.viewPermissions": "Berechtigungen anzeigen"
98
+ "auth.email.resetPassword.hint": "Wenn Sie dies nicht angefordert haben, können Sie diese E-Mail ignorieren."
127
99
  }
@@ -80,19 +80,6 @@
80
80
  "auth.users.form.errors.load": "Failed to load user data",
81
81
  "auth.users.form.errors.aclUpdate": "Failed to update user access control",
82
82
  "auth.users.form.errors.delete": "Failed to delete user",
83
- "auth.profile.title": "Profile",
84
- "auth.profile.form.email": "Email",
85
- "auth.profile.form.password": "New password",
86
- "auth.profile.form.confirmPassword": "Confirm new password",
87
- "auth.profile.form.save": "Save changes",
88
- "auth.profile.form.loading": "Loading profile...",
89
- "auth.profile.form.errors.load": "Failed to load profile.",
90
- "auth.profile.form.errors.save": "Failed to update profile.",
91
- "auth.profile.form.errors.invalid": "Invalid profile update.",
92
- "auth.profile.form.errors.passwordMismatch": "Passwords do not match.",
93
- "auth.profile.form.errors.noChanges": "No changes to save.",
94
- "auth.profile.form.errors.emailRequired": "Email is required.",
95
- "auth.profile.form.success": "Profile updated.",
96
83
  "auth.users.list.error.load": "Failed to load users",
97
84
  "auth.users.list.error.delete": "Failed to delete user",
98
85
  "auth.users.flash.created": "User created",
@@ -108,20 +95,5 @@
108
95
  "auth.email.resetPassword.title": "Reset your password",
109
96
  "auth.email.resetPassword.body": "Click the link below to set a new password. This link will expire in 60 minutes.",
110
97
  "auth.email.resetPassword.cta": "Set a new password",
111
- "auth.email.resetPassword.hint": "If you didn't request this, you can safely ignore this email.",
112
- "auth.notifications.passwordReset.requested.title": "Password reset requested",
113
- "auth.notifications.passwordReset.requested.body": "A password reset link has been sent to your email",
114
- "auth.notifications.passwordReset.completed.title": "Password successfully changed",
115
- "auth.notifications.passwordReset.completed.body": "Your password has been updated successfully",
116
- "auth.notifications.account.locked.title": "Account locked",
117
- "auth.notifications.account.locked.body": "Your account has been locked due to security reasons. Please contact support.",
118
- "auth.notifications.login.newDevice.title": "New device login detected",
119
- "auth.notifications.login.newDevice.body": "A new login from an unrecognized device was detected on your account",
120
- "auth.notifications.role.assigned.title": "New role assigned",
121
- "auth.notifications.role.assigned.body": "You have been assigned a new role with additional permissions",
122
- "auth.notifications.role.revoked.title": "Role removed",
123
- "auth.notifications.role.revoked.body": "A role has been removed from your account",
124
- "auth.actions.contactSupport": "Contact Support",
125
- "auth.actions.viewSessions": "View Sessions",
126
- "auth.actions.viewPermissions": "View Permissions"
98
+ "auth.email.resetPassword.hint": "If you didn't request this, you can safely ignore this email."
127
99
  }
@@ -80,19 +80,6 @@
80
80
  "auth.users.form.errors.load": "No se pudieron cargar los datos del usuario",
81
81
  "auth.users.form.errors.aclUpdate": "No se pudo actualizar el control de acceso del usuario",
82
82
  "auth.users.form.errors.delete": "No se pudo eliminar el usuario",
83
- "auth.profile.title": "Perfil",
84
- "auth.profile.form.email": "Correo electrónico",
85
- "auth.profile.form.password": "Nueva contraseña",
86
- "auth.profile.form.confirmPassword": "Confirmar nueva contraseña",
87
- "auth.profile.form.save": "Guardar cambios",
88
- "auth.profile.form.loading": "Cargando perfil...",
89
- "auth.profile.form.errors.load": "No se pudo cargar el perfil.",
90
- "auth.profile.form.errors.save": "No se pudo actualizar el perfil.",
91
- "auth.profile.form.errors.invalid": "Actualización de perfil inválida.",
92
- "auth.profile.form.errors.passwordMismatch": "Las contraseñas no coinciden.",
93
- "auth.profile.form.errors.noChanges": "No hay cambios para guardar.",
94
- "auth.profile.form.errors.emailRequired": "El correo electrónico es obligatorio.",
95
- "auth.profile.form.success": "Perfil actualizado.",
96
83
  "auth.users.list.error.load": "No se pudieron cargar los usuarios",
97
84
  "auth.users.list.error.delete": "No se pudo eliminar el usuario",
98
85
  "auth.users.flash.created": "Usuario creado",
@@ -108,20 +95,5 @@
108
95
  "auth.email.resetPassword.title": "Restablecer tu contraseña",
109
96
  "auth.email.resetPassword.body": "Haz clic en el siguiente enlace para establecer una nueva contraseña. Este enlace caducará en 60 minutos.",
110
97
  "auth.email.resetPassword.cta": "Establecer nueva contraseña",
111
- "auth.email.resetPassword.hint": "Si no solicitaste esto, puedes ignorar este correo de forma segura.",
112
- "auth.notifications.passwordReset.requested.title": "Solicitud de restablecimiento de contraseña",
113
- "auth.notifications.passwordReset.requested.body": "Se ha enviado un enlace de restablecimiento de contraseña a tu correo electrónico",
114
- "auth.notifications.passwordReset.completed.title": "Contraseña cambiada correctamente",
115
- "auth.notifications.passwordReset.completed.body": "Tu contraseña se actualizó correctamente",
116
- "auth.notifications.account.locked.title": "Cuenta bloqueada",
117
- "auth.notifications.account.locked.body": "Tu cuenta ha sido bloqueada por razones de seguridad. Ponte en contacto con soporte.",
118
- "auth.notifications.login.newDevice.title": "Nuevo inicio de sesión detectado",
119
- "auth.notifications.login.newDevice.body": "Se detectó un inicio de sesión desde un dispositivo no reconocido en tu cuenta",
120
- "auth.notifications.role.assigned.title": "Nuevo rol asignado",
121
- "auth.notifications.role.assigned.body": "Se te ha asignado un nuevo rol con permisos adicionales",
122
- "auth.notifications.role.revoked.title": "Rol eliminado",
123
- "auth.notifications.role.revoked.body": "Se ha eliminado un rol de tu cuenta",
124
- "auth.actions.contactSupport": "Contactar soporte",
125
- "auth.actions.viewSessions": "Ver sesiones",
126
- "auth.actions.viewPermissions": "Ver permisos"
98
+ "auth.email.resetPassword.hint": "Si no solicitaste esto, puedes ignorar este correo de forma segura."
127
99
  }
@@ -80,19 +80,6 @@
80
80
  "auth.users.form.errors.load": "Nie udało się wczytać danych użytkownika",
81
81
  "auth.users.form.errors.aclUpdate": "Nie udało się zaktualizować uprawnień użytkownika",
82
82
  "auth.users.form.errors.delete": "Nie udało się usunąć użytkownika",
83
- "auth.profile.title": "Profil",
84
- "auth.profile.form.email": "Email",
85
- "auth.profile.form.password": "Nowe hasło",
86
- "auth.profile.form.confirmPassword": "Potwierdź nowe hasło",
87
- "auth.profile.form.save": "Zapisz zmiany",
88
- "auth.profile.form.loading": "Ładowanie profilu...",
89
- "auth.profile.form.errors.load": "Nie udało się wczytać profilu.",
90
- "auth.profile.form.errors.save": "Nie udało się zaktualizować profilu.",
91
- "auth.profile.form.errors.invalid": "Nieprawidłowa aktualizacja profilu.",
92
- "auth.profile.form.errors.passwordMismatch": "Hasła nie są zgodne.",
93
- "auth.profile.form.errors.noChanges": "Brak zmian do zapisania.",
94
- "auth.profile.form.errors.emailRequired": "Email jest wymagany.",
95
- "auth.profile.form.success": "Profil zaktualizowany.",
96
83
  "auth.users.list.error.load": "Nie udało się wczytać użytkowników",
97
84
  "auth.users.list.error.delete": "Nie udało się usunąć użytkownika",
98
85
  "auth.users.flash.created": "Użytkownik utworzony",
@@ -108,20 +95,5 @@
108
95
  "auth.email.resetPassword.title": "Zresetuj swoje hasło",
109
96
  "auth.email.resetPassword.body": "Kliknij poniższy link, aby ustawić nowe hasło. Link wygaśnie za 60 minut.",
110
97
  "auth.email.resetPassword.cta": "Ustaw nowe hasło",
111
- "auth.email.resetPassword.hint": "Jeśli nie prosiłeś o tę wiadomość, możesz ją bezpiecznie zignorować.",
112
- "auth.notifications.passwordReset.requested.title": "Żądanie resetu hasła",
113
- "auth.notifications.passwordReset.requested.body": "Link do resetu hasła został wysłany na Twój adres e-mail",
114
- "auth.notifications.passwordReset.completed.title": "Hasło zmienione pomyślnie",
115
- "auth.notifications.passwordReset.completed.body": "Twoje hasło zostało pomyślnie zaktualizowane",
116
- "auth.notifications.account.locked.title": "Konto zablokowane",
117
- "auth.notifications.account.locked.body": "Twoje konto zostało zablokowane z powodów bezpieczeństwa. Skontaktuj się z pomocą techniczną.",
118
- "auth.notifications.login.newDevice.title": "Wykryto logowanie z nowego urządzenia",
119
- "auth.notifications.login.newDevice.body": "Wykryto logowanie z nieznanego urządzenia na Twoim koncie",
120
- "auth.notifications.role.assigned.title": "Przypisano nową rolę",
121
- "auth.notifications.role.assigned.body": "Przypisano Ci nową rolę z dodatkowymi uprawnieniami",
122
- "auth.notifications.role.revoked.title": "Rola usunięta",
123
- "auth.notifications.role.revoked.body": "Z Twojego konta usunięto rolę",
124
- "auth.actions.contactSupport": "Skontaktuj się z pomocą",
125
- "auth.actions.viewSessions": "Zobacz sesje",
126
- "auth.actions.viewPermissions": "Zobacz uprawnienia"
98
+ "auth.email.resetPassword.hint": "Jeśli nie prosiłeś o tę wiadomość, możesz ją bezpiecznie zignorować."
127
99
  }
@@ -395,7 +395,6 @@ async function ensureDefaultRoleAcls(
395
395
  'dashboards.*',
396
396
  'dashboards.admin.assign-widgets',
397
397
  'api_keys.*',
398
- 'notifications.manage',
399
398
  'perspectives.use',
400
399
  'perspectives.role_defaults',
401
400
  'business_rules.*',
@@ -75,15 +75,15 @@ export class AuthService {
75
75
  return { user, token }
76
76
  }
77
77
 
78
- async confirmPasswordReset(token: string, newPassword: string): Promise<User | null> {
78
+ async confirmPasswordReset(token: string, newPassword: string) {
79
79
  const now = new Date()
80
80
  const row = await this.em.findOne(PasswordReset, { token })
81
- if (!row || (row.usedAt && row.usedAt <= now) || row.expiresAt <= now) return null
81
+ if (!row || (row.usedAt && row.usedAt <= now) || row.expiresAt <= now) return false
82
82
  const user = await this.em.findOne(User, { id: row.user.id })
83
- if (!user) return null
83
+ if (!user) return false
84
84
  user.passwordHash = await hash(newPassword, 10)
85
85
  row.usedAt = new Date()
86
86
  await this.em.flush()
87
- return user
87
+ return true
88
88
  }
89
89
  }
@@ -367,7 +367,5 @@
367
367
  "business_rules.components.conditionRow.field.comparisonPlaceholder": "e.g., user.role",
368
368
  "business_rules.components.conditionRow.value.help": "Use JSON for arrays: [\"a\",\"b\"]",
369
369
  "business_rules.components.conditionRow.field.comparisonHelp": "Field path to compare with",
370
- "business_rules.components.conditionRow.deleteCondition": "Delete condition",
371
- "businessRules.notifications.rule.executionFailed.title": "Business Rule Failed",
372
- "businessRules.notifications.rule.executionFailed.body": "Rule \"{ruleName}\" failed to execute{entityType, select, other { on {entityType}}}: {errorMessage}"
370
+ "business_rules.components.conditionRow.deleteCondition": "Delete condition"
373
371
  }
@@ -681,7 +681,5 @@
681
681
  "deleteError": "Failed to delete variant."
682
682
  }
683
683
  }
684
- },
685
- "catalog.notifications.product.lowStock.title": "Low Stock Alert",
686
- "catalog.notifications.product.lowStock.body": "{productName}{sku, select, other { ({sku})}} is running low on stock ({currentStock} remaining, threshold: {threshold})"
684
+ }
687
685
  }
@@ -2,7 +2,6 @@ import type { ModuleCli } from '@open-mercato/shared/modules/registry'
2
2
  import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
3
3
  import type { ModuleConfigService } from './lib/module-config-service'
4
4
  import { parseBooleanToken } from '@open-mercato/shared/lib/boolean'
5
- import { DEFAULT_NOTIFICATION_DELIVERY_CONFIG, NOTIFICATIONS_DELIVERY_CONFIG_KEY } from '../notifications/lib/deliveryConfig'
6
5
 
7
6
  function envDisablesAutoIndexing(): boolean {
8
7
  const raw = process.env.DISABLE_VECTOR_SEARCH_AUTOINDEXING
@@ -32,11 +31,6 @@ const restoreDefaults: ModuleCli = {
32
31
  name: 'auto_index_enabled',
33
32
  value: defaultEnabled,
34
33
  },
35
- {
36
- moduleId: 'notifications',
37
- name: NOTIFICATIONS_DELIVERY_CONFIG_KEY,
38
- value: DEFAULT_NOTIFICATION_DELIVERY_CONFIG,
39
- },
40
34
  ],
41
35
  { force: true },
42
36
  )
@@ -35,9 +35,6 @@ import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
35
35
  import type { CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'
36
36
  import { E } from '#generated/entities.ids.generated'
37
37
  import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
38
- import { resolveNotificationService } from '../../notifications/lib/notificationService'
39
- import { buildNotificationFromType } from '../../notifications/lib/notificationBuilder'
40
- import { notificationTypes } from '../notifications'
41
38
 
42
39
  const DEAL_ENTITY_ID = 'customers:customer_deal'
43
40
  const dealCrudIndexer: CrudIndexerConfig<CustomerDeal> = {
@@ -284,8 +281,6 @@ const updateDealCommand: CommandHandler<DealUpdateInput, { dealId: string }> = {
284
281
  ensureTenantScope(ctx, record.tenantId)
285
282
  ensureOrganizationScope(ctx, record.organizationId)
286
283
 
287
- const previousStatus = record.status
288
-
289
284
  if (parsed.title !== undefined) record.title = parsed.title
290
285
  if (parsed.description !== undefined) record.description = parsed.description ?? null
291
286
  if (parsed.status !== undefined) record.status = parsed.status ?? record.status
@@ -324,40 +319,6 @@ const updateDealCommand: CommandHandler<DealUpdateInput, { dealId: string }> = {
324
319
  indexer: dealCrudIndexer,
325
320
  })
326
321
 
327
- // Send notifications for deal won/lost status changes
328
- const newStatus = record.status
329
- const normalizedStatus = newStatus === 'win' ? 'won' : newStatus === 'loose' ? 'lost' : newStatus
330
- if (previousStatus !== newStatus && (normalizedStatus === 'won' || normalizedStatus === 'lost') && record.ownerUserId) {
331
- try {
332
- const notificationService = resolveNotificationService(ctx.container)
333
- const notificationType = normalizedStatus === 'won' ? 'customers.deal.won' : 'customers.deal.lost'
334
- const typeDef = notificationTypes.find((type) => type.type === notificationType)
335
- if (typeDef) {
336
- const valueDisplay = record.valueAmount && record.valueCurrency
337
- ? `${record.valueCurrency} ${record.valueAmount}`
338
- : ''
339
-
340
- const notificationInput = buildNotificationFromType(typeDef, {
341
- recipientUserId: record.ownerUserId,
342
- bodyVariables: {
343
- dealTitle: record.title,
344
- dealValue: valueDisplay,
345
- },
346
- sourceEntityType: 'customers:customer_deal',
347
- sourceEntityId: record.id,
348
- linkHref: `/backend/customers/deals/${record.id}`,
349
- })
350
-
351
- await notificationService.create(notificationInput, {
352
- tenantId: record.tenantId,
353
- organizationId: record.organizationId,
354
- })
355
- }
356
- } catch {
357
- // Notification creation is non-critical, don't fail the command
358
- }
359
- }
360
-
361
322
  return { dealId: record.id }
362
323
  },
363
324
  buildLog: async ({ snapshots, ctx }) => {
@@ -943,9 +943,5 @@
943
943
  "customers.workPlan.customerTodos.table.state.empty": "No customer tasks yet.",
944
944
  "customers.workPlan.customerTodos.table.error.load": "Failed to load customer tasks.",
945
945
  "customers.workPlan.customerTodos.table.export.view": "Exports the current list with filters and visible columns.",
946
- "customers.workPlan.customerTodos.table.export.full": "Exports every linked task field, including hidden attributes.",
947
- "customers.notifications.deal.won.title": "Deal Won",
948
- "customers.notifications.deal.won.body": "{dealTitle} has been marked as won{dealValue, select, other { ({dealValue})}}",
949
- "customers.notifications.deal.lost.title": "Deal Lost",
950
- "customers.notifications.deal.lost.body": "{dealTitle} has been marked as lost"
946
+ "customers.workPlan.customerTodos.table.export.full": "Exports every linked task field, including hidden attributes."
951
947
  }
@@ -11,8 +11,6 @@ import type { DataEngine } from '@open-mercato/shared/lib/data/engine'
11
11
  import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
12
12
  import { deriveResourceFromCommandId, invalidateCrudCache } from '@open-mercato/shared/lib/crud/cache'
13
13
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
14
- import { resolveNotificationService } from '../../notifications/lib/notificationService'
15
- import { buildFeatureNotificationFromType } from '../../notifications/lib/notificationBuilder'
16
14
  import { setRecordCustomFields } from '@open-mercato/core/modules/entities/lib/helpers'
17
15
  import { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'
18
16
  import { normalizeCustomFieldValues } from '@open-mercato/shared/lib/custom-fields/normalize'
@@ -90,7 +88,6 @@ import { resolveDictionaryEntryValue } from '../lib/dictionaries'
90
88
  import { resolveStatusEntryIdByValue } from '../lib/statusHelpers'
91
89
  import { SalesDocumentNumberGenerator } from '../services/salesDocumentNumberGenerator'
92
90
  import { loadSalesSettings } from './settings'
93
- import { notificationTypes } from '../notifications'
94
91
 
95
92
  type DocumentAddressSnapshot = {
96
93
  id: string
@@ -3114,37 +3111,6 @@ const createQuoteCommand: CommandHandler<QuoteCreateInput, { quoteId: string }>
3114
3111
  })
3115
3112
  await em.flush()
3116
3113
 
3117
- // Create notification for users with sales.quotes.manage feature
3118
- try {
3119
- const notificationService = resolveNotificationService(ctx.container)
3120
- const typeDef = notificationTypes.find((type) => type.type === 'sales.quote.created')
3121
- if (typeDef) {
3122
- const totalAmount = quote.grandTotalGrossAmount && quote.currencyCode
3123
- ? `${quote.grandTotalGrossAmount} ${quote.currencyCode}`
3124
- : ''
3125
- const totalDisplay = totalAmount ? ` (${totalAmount})` : ''
3126
- const notificationInput = buildFeatureNotificationFromType(typeDef, {
3127
- requiredFeature: 'sales.quotes.manage',
3128
- bodyVariables: {
3129
- quoteNumber: quote.quoteNumber,
3130
- total: totalDisplay,
3131
- totalAmount,
3132
- },
3133
- sourceEntityType: 'sales:quote',
3134
- sourceEntityId: quote.id,
3135
- linkHref: `/backend/sales/quotes/${quote.id}`,
3136
- })
3137
-
3138
- await notificationService.createForFeature(notificationInput, {
3139
- tenantId: quote.tenantId,
3140
- organizationId: quote.organizationId ?? null,
3141
- })
3142
- }
3143
- } catch (err) {
3144
- // Notification creation is non-critical, don't fail the command
3145
- console.error('[sales.quotes.create] Failed to create notification:', err)
3146
- }
3147
-
3148
3114
  return { quoteId: quote.id }
3149
3115
  },
3150
3116
  captureAfter: async (_input, result, ctx) => {
@@ -3816,37 +3782,6 @@ const createOrderCommand: CommandHandler<OrderCreateInput, { orderId: string }>
3816
3782
  })
3817
3783
  await em.flush()
3818
3784
 
3819
- // Create notification for users with sales.orders.manage feature
3820
- try {
3821
- const notificationService = resolveNotificationService(ctx.container)
3822
- const typeDef = notificationTypes.find((type) => type.type === 'sales.order.created')
3823
- if (typeDef) {
3824
- const totalAmount = order.grandTotalGrossAmount && order.currencyCode
3825
- ? `${order.grandTotalGrossAmount} ${order.currencyCode}`
3826
- : ''
3827
- const totalDisplay = totalAmount ? ` (${totalAmount})` : ''
3828
- const notificationInput = buildFeatureNotificationFromType(typeDef, {
3829
- requiredFeature: 'sales.orders.manage',
3830
- bodyVariables: {
3831
- orderNumber: order.orderNumber,
3832
- total: totalDisplay,
3833
- totalAmount,
3834
- },
3835
- sourceEntityType: 'sales:order',
3836
- sourceEntityId: order.id,
3837
- linkHref: `/backend/sales/orders/${order.id}`,
3838
- })
3839
-
3840
- await notificationService.createForFeature(notificationInput, {
3841
- tenantId: order.tenantId,
3842
- organizationId: order.organizationId ?? null,
3843
- })
3844
- }
3845
- } catch (err) {
3846
- // Notification creation is non-critical, don't fail the command
3847
- console.error('[sales.orders.create] Failed to create notification:', err)
3848
- }
3849
-
3850
3785
  return { orderId: order.id }
3851
3786
  },
3852
3787
  captureAfter: async (_input, result, ctx) => {
@@ -35,9 +35,6 @@ import { invalidateCrudCache } from '@open-mercato/shared/lib/crud/cache'
35
35
  import { emitCrudSideEffects } from '@open-mercato/shared/lib/commands/helpers'
36
36
  import type { DataEngine } from '@open-mercato/shared/lib/data/engine'
37
37
  import { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
38
- import { resolveNotificationService } from '../../notifications/lib/notificationService'
39
- import { buildFeatureNotificationFromType } from '../../notifications/lib/notificationBuilder'
40
- import { notificationTypes } from '../notifications'
41
38
 
42
39
  export type PaymentAllocationSnapshot = {
43
40
  id: string
@@ -425,36 +422,6 @@ const createPaymentCommand: CommandHandler<
425
422
  const totals = await recomputeOrderPaymentTotals(em, order)
426
423
  await em.flush()
427
424
  await invalidateOrderCache(ctx.container, order, ctx.auth?.tenantId ?? null)
428
-
429
- // Create notification for payment received
430
- try {
431
- const notificationService = resolveNotificationService(ctx.container)
432
- const typeDef = notificationTypes.find((type) => type.type === 'sales.payment.received')
433
- if (typeDef) {
434
- const amountDisplay = payment.amount && payment.currencyCode
435
- ? `${payment.currencyCode} ${payment.amount}`
436
- : ''
437
- const notificationInput = buildFeatureNotificationFromType(typeDef, {
438
- requiredFeature: 'sales.orders.manage',
439
- bodyVariables: {
440
- orderNumber: order.orderNumber ?? '',
441
- amount: amountDisplay,
442
- },
443
- sourceEntityType: 'sales:order',
444
- sourceEntityId: order.id,
445
- linkHref: `/backend/sales/orders/${order.id}`,
446
- })
447
-
448
- await notificationService.createForFeature(notificationInput, {
449
- tenantId: payment.tenantId,
450
- organizationId: payment.organizationId ?? null,
451
- })
452
- }
453
- } catch (err) {
454
- // Notification creation is non-critical, don't fail the command
455
- console.error('[sales.payments.create] Failed to create notification:', err)
456
- }
457
-
458
425
  return { paymentId: payment.id, orderTotals: totals }
459
426
  },
460
427
  captureAfter: async (_input, result, ctx) => {