@open-mercato/core 0.4.5-develop-754ef4d2f0 → 0.4.5-develop-9f9549ebc8

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 (434) hide show
  1. package/dist/generated/entities/message/index.js +65 -0
  2. package/dist/generated/entities/message/index.js.map +7 -0
  3. package/dist/generated/entities/message_access_token/index.js +19 -0
  4. package/dist/generated/entities/message_access_token/index.js.map +7 -0
  5. package/dist/generated/entities/message_confirmation/index.js +21 -0
  6. package/dist/generated/entities/message_confirmation/index.js.map +7 -0
  7. package/dist/generated/entities/message_object/index.js +23 -0
  8. package/dist/generated/entities/message_object/index.js.map +7 -0
  9. package/dist/generated/entities/message_recipient/index.js +31 -0
  10. package/dist/generated/entities/message_recipient/index.js.map +7 -0
  11. package/dist/generated/entities.ids.generated.js +8 -0
  12. package/dist/generated/entities.ids.generated.js.map +2 -2
  13. package/dist/generated/entity-fields-registry.js +10 -0
  14. package/dist/generated/entity-fields-registry.js.map +2 -2
  15. package/dist/modules/auth/components/AclEditor.js +4 -2
  16. package/dist/modules/auth/components/AclEditor.js.map +2 -2
  17. package/dist/modules/auth/frontend/reset.js +3 -3
  18. package/dist/modules/auth/frontend/reset.js.map +2 -2
  19. package/dist/modules/customers/backend/customers/deals/[id]/page.js +27 -8
  20. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  21. package/dist/modules/customers/lib/messageObjectPreviews.js +131 -0
  22. package/dist/modules/customers/lib/messageObjectPreviews.js.map +7 -0
  23. package/dist/modules/customers/message-objects.js +71 -0
  24. package/dist/modules/customers/message-objects.js.map +7 -0
  25. package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js +51 -0
  26. package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js.map +7 -0
  27. package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js +35 -0
  28. package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js.map +7 -0
  29. package/dist/modules/customers/widgets/messages/index.js +7 -0
  30. package/dist/modules/customers/widgets/messages/index.js.map +7 -0
  31. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +35 -6
  32. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
  33. package/dist/modules/messages/acl.js +15 -0
  34. package/dist/modules/messages/acl.js.map +7 -0
  35. package/dist/modules/messages/api/[id]/actions/[actionId]/route.js +92 -0
  36. package/dist/modules/messages/api/[id]/actions/[actionId]/route.js.map +7 -0
  37. package/dist/modules/messages/api/[id]/archive/route.js +120 -0
  38. package/dist/modules/messages/api/[id]/archive/route.js.map +7 -0
  39. package/dist/modules/messages/api/[id]/attachments/route.js +195 -0
  40. package/dist/modules/messages/api/[id]/attachments/route.js.map +7 -0
  41. package/dist/modules/messages/api/[id]/confirmation/route.js +67 -0
  42. package/dist/modules/messages/api/[id]/confirmation/route.js.map +7 -0
  43. package/dist/modules/messages/api/[id]/conversation/archive/route.js +68 -0
  44. package/dist/modules/messages/api/[id]/conversation/archive/route.js.map +7 -0
  45. package/dist/modules/messages/api/[id]/conversation/read/route.js +68 -0
  46. package/dist/modules/messages/api/[id]/conversation/read/route.js.map +7 -0
  47. package/dist/modules/messages/api/[id]/conversation/route.js +68 -0
  48. package/dist/modules/messages/api/[id]/conversation/route.js.map +7 -0
  49. package/dist/modules/messages/api/[id]/forward/route.js +85 -0
  50. package/dist/modules/messages/api/[id]/forward/route.js.map +7 -0
  51. package/dist/modules/messages/api/[id]/forward-preview/route.js +70 -0
  52. package/dist/modules/messages/api/[id]/forward-preview/route.js.map +7 -0
  53. package/dist/modules/messages/api/[id]/read/route.js +120 -0
  54. package/dist/modules/messages/api/[id]/read/route.js.map +7 -0
  55. package/dist/modules/messages/api/[id]/reply/route.js +87 -0
  56. package/dist/modules/messages/api/[id]/reply/route.js.map +7 -0
  57. package/dist/modules/messages/api/[id]/route.js +350 -0
  58. package/dist/modules/messages/api/[id]/route.js.map +7 -0
  59. package/dist/modules/messages/api/object-types/route.js +54 -0
  60. package/dist/modules/messages/api/object-types/route.js.map +7 -0
  61. package/dist/modules/messages/api/openapi.js +261 -0
  62. package/dist/modules/messages/api/openapi.js.map +7 -0
  63. package/dist/modules/messages/api/route.js +262 -0
  64. package/dist/modules/messages/api/route.js.map +7 -0
  65. package/dist/modules/messages/api/token/[token]/route.js +99 -0
  66. package/dist/modules/messages/api/token/[token]/route.js.map +7 -0
  67. package/dist/modules/messages/api/types/route.js +40 -0
  68. package/dist/modules/messages/api/types/route.js.map +7 -0
  69. package/dist/modules/messages/api/unread-count/route.js +43 -0
  70. package/dist/modules/messages/api/unread-count/route.js.map +7 -0
  71. package/dist/modules/messages/backend/messages/[id]/page.js +10 -0
  72. package/dist/modules/messages/backend/messages/[id]/page.js.map +7 -0
  73. package/dist/modules/messages/backend/messages/[id]/page.meta.js +16 -0
  74. package/dist/modules/messages/backend/messages/[id]/page.meta.js.map +7 -0
  75. package/dist/modules/messages/backend/messages/compose/page.js +10 -0
  76. package/dist/modules/messages/backend/messages/compose/page.js.map +7 -0
  77. package/dist/modules/messages/backend/messages/compose/page.meta.js +17 -0
  78. package/dist/modules/messages/backend/messages/compose/page.meta.js.map +7 -0
  79. package/dist/modules/messages/backend/page.js +10 -0
  80. package/dist/modules/messages/backend/page.js.map +7 -0
  81. package/dist/modules/messages/backend/page.meta.js +33 -0
  82. package/dist/modules/messages/backend/page.meta.js.map +7 -0
  83. package/dist/modules/messages/commands/actions.js +265 -0
  84. package/dist/modules/messages/commands/actions.js.map +7 -0
  85. package/dist/modules/messages/commands/attachments.js +217 -0
  86. package/dist/modules/messages/commands/attachments.js.map +7 -0
  87. package/dist/modules/messages/commands/confirmations.js +151 -0
  88. package/dist/modules/messages/commands/confirmations.js.map +7 -0
  89. package/dist/modules/messages/commands/conversation.js +240 -0
  90. package/dist/modules/messages/commands/conversation.js.map +7 -0
  91. package/dist/modules/messages/commands/messages.js +748 -0
  92. package/dist/modules/messages/commands/messages.js.map +7 -0
  93. package/dist/modules/messages/commands/recipients.js +259 -0
  94. package/dist/modules/messages/commands/recipients.js.map +7 -0
  95. package/dist/modules/messages/commands/shared.js +258 -0
  96. package/dist/modules/messages/commands/shared.js.map +7 -0
  97. package/dist/modules/messages/commands/tokens.js +69 -0
  98. package/dist/modules/messages/commands/tokens.js.map +7 -0
  99. package/dist/modules/messages/components/ComposeMessagePageClient.js +24 -0
  100. package/dist/modules/messages/components/ComposeMessagePageClient.js.map +7 -0
  101. package/dist/modules/messages/components/MessageDetailPageClient.js +261 -0
  102. package/dist/modules/messages/components/MessageDetailPageClient.js.map +7 -0
  103. package/dist/modules/messages/components/MessagesInboxPageClient.js +390 -0
  104. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +7 -0
  105. package/dist/modules/messages/components/confirmation/MessageConfirmationActions.js +31 -0
  106. package/dist/modules/messages/components/confirmation/MessageConfirmationActions.js.map +7 -0
  107. package/dist/modules/messages/components/confirmation/MessageConfirmationContent.js +69 -0
  108. package/dist/modules/messages/components/confirmation/MessageConfirmationContent.js.map +7 -0
  109. package/dist/modules/messages/components/defaults/DefaultMessageActions.js +31 -0
  110. package/dist/modules/messages/components/defaults/DefaultMessageActions.js.map +7 -0
  111. package/dist/modules/messages/components/defaults/DefaultMessageContent.js +19 -0
  112. package/dist/modules/messages/components/defaults/DefaultMessageContent.js.map +7 -0
  113. package/dist/modules/messages/components/defaults/DefaultMessageListItem.js +90 -0
  114. package/dist/modules/messages/components/defaults/DefaultMessageListItem.js.map +7 -0
  115. package/dist/modules/messages/components/defaults/MessageRecordObjectDetail.js +86 -0
  116. package/dist/modules/messages/components/defaults/MessageRecordObjectDetail.js.map +7 -0
  117. package/dist/modules/messages/components/defaults/MessageRecordObjectPreview.js +61 -0
  118. package/dist/modules/messages/components/defaults/MessageRecordObjectPreview.js.map +7 -0
  119. package/dist/modules/messages/components/message-detail/detail-panels.js +27 -0
  120. package/dist/modules/messages/components/message-detail/detail-panels.js.map +7 -0
  121. package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js +52 -0
  122. package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js.map +7 -0
  123. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js +289 -0
  124. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js.map +7 -0
  125. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +103 -0
  126. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +7 -0
  127. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.js +78 -0
  128. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.js.map +7 -0
  129. package/dist/modules/messages/components/message-detail/panels/MainMessageHeader.js +94 -0
  130. package/dist/modules/messages/components/message-detail/panels/MainMessageHeader.js.map +7 -0
  131. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +110 -0
  132. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +7 -0
  133. package/dist/modules/messages/components/message-detail/panels/MessageListComponent.js +58 -0
  134. package/dist/modules/messages/components/message-detail/panels/MessageListComponent.js.map +7 -0
  135. package/dist/modules/messages/components/message-detail/panels/actions-panel.js +51 -0
  136. package/dist/modules/messages/components/message-detail/panels/actions-panel.js.map +7 -0
  137. package/dist/modules/messages/components/message-detail/panels/attachments-panel.js +66 -0
  138. package/dist/modules/messages/components/message-detail/panels/attachments-panel.js.map +7 -0
  139. package/dist/modules/messages/components/message-detail/panels/body-panel.js +20 -0
  140. package/dist/modules/messages/components/message-detail/panels/body-panel.js.map +7 -0
  141. package/dist/modules/messages/components/message-detail/panels/composer-dialogs.js +36 -0
  142. package/dist/modules/messages/components/message-detail/panels/composer-dialogs.js.map +7 -0
  143. package/dist/modules/messages/components/message-detail/panels/dialogs.js +96 -0
  144. package/dist/modules/messages/components/message-detail/panels/dialogs.js.map +7 -0
  145. package/dist/modules/messages/components/message-detail/panels/index.js +25 -0
  146. package/dist/modules/messages/components/message-detail/panels/index.js.map +7 -0
  147. package/dist/modules/messages/components/message-detail/panels/meta-panel.js +14 -0
  148. package/dist/modules/messages/components/message-detail/panels/meta-panel.js.map +7 -0
  149. package/dist/modules/messages/components/message-detail/panels/objects-panel.js +51 -0
  150. package/dist/modules/messages/components/message-detail/panels/objects-panel.js.map +7 -0
  151. package/dist/modules/messages/components/message-detail/panels/thread-panel.js +54 -0
  152. package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +7 -0
  153. package/dist/modules/messages/components/message-detail/types.js +1 -0
  154. package/dist/modules/messages/components/message-detail/types.js.map +7 -0
  155. package/dist/modules/messages/components/message-detail/utils.js +54 -0
  156. package/dist/modules/messages/components/message-detail/utils.js.map +7 -0
  157. package/dist/modules/messages/components/utils/PriorityBadge.js +52 -0
  158. package/dist/modules/messages/components/utils/PriorityBadge.js.map +7 -0
  159. package/dist/modules/messages/components/utils/typeUiRegistry.js +77 -0
  160. package/dist/modules/messages/components/utils/typeUiRegistry.js.map +7 -0
  161. package/dist/modules/messages/data/entities.js +309 -0
  162. package/dist/modules/messages/data/entities.js.map +7 -0
  163. package/dist/modules/messages/data/validators.js +272 -0
  164. package/dist/modules/messages/data/validators.js.map +7 -0
  165. package/dist/modules/messages/emails/MessageEmail.js +108 -0
  166. package/dist/modules/messages/emails/MessageEmail.js.map +7 -0
  167. package/dist/modules/messages/events.js +24 -0
  168. package/dist/modules/messages/events.js.map +7 -0
  169. package/dist/modules/messages/frontend/messages/view/[token]/page.js +247 -0
  170. package/dist/modules/messages/frontend/messages/view/[token]/page.js.map +7 -0
  171. package/dist/modules/messages/frontend/messages/view/[token]/page.meta.js +9 -0
  172. package/dist/modules/messages/frontend/messages/view/[token]/page.meta.js.map +7 -0
  173. package/dist/modules/messages/index.js +21 -0
  174. package/dist/modules/messages/index.js.map +7 -0
  175. package/dist/modules/messages/lib/actions.js +141 -0
  176. package/dist/modules/messages/lib/actions.js.map +7 -0
  177. package/dist/modules/messages/lib/attachments.js +131 -0
  178. package/dist/modules/messages/lib/attachments.js.map +7 -0
  179. package/dist/modules/messages/lib/constants.js +7 -0
  180. package/dist/modules/messages/lib/constants.js.map +7 -0
  181. package/dist/modules/messages/lib/email-sender.js +201 -0
  182. package/dist/modules/messages/lib/email-sender.js.map +7 -0
  183. package/dist/modules/messages/lib/forwarding.js +179 -0
  184. package/dist/modules/messages/lib/forwarding.js.map +7 -0
  185. package/dist/modules/messages/lib/message-objects-registry.js +49 -0
  186. package/dist/modules/messages/lib/message-objects-registry.js.map +7 -0
  187. package/dist/modules/messages/lib/message-types-registry.js +41 -0
  188. package/dist/modules/messages/lib/message-types-registry.js.map +7 -0
  189. package/dist/modules/messages/lib/object-validation.js +20 -0
  190. package/dist/modules/messages/lib/object-validation.js.map +7 -0
  191. package/dist/modules/messages/lib/operationMetadata.js +21 -0
  192. package/dist/modules/messages/lib/operationMetadata.js.map +7 -0
  193. package/dist/modules/messages/lib/priorityUtils.js +61 -0
  194. package/dist/modules/messages/lib/priorityUtils.js.map +7 -0
  195. package/dist/modules/messages/lib/routeHelpers.js +44 -0
  196. package/dist/modules/messages/lib/routeHelpers.js.map +7 -0
  197. package/dist/modules/messages/message-objects.js +7 -0
  198. package/dist/modules/messages/message-objects.js.map +7 -0
  199. package/dist/modules/messages/message-types.js +67 -0
  200. package/dist/modules/messages/message-types.js.map +7 -0
  201. package/dist/modules/messages/migrations/Migration20260213181243.js +31 -0
  202. package/dist/modules/messages/migrations/Migration20260213181243.js.map +7 -0
  203. package/dist/modules/messages/migrations/Migration20260215165126.js +16 -0
  204. package/dist/modules/messages/migrations/Migration20260215165126.js.map +7 -0
  205. package/dist/modules/messages/notifications.js +27 -0
  206. package/dist/modules/messages/notifications.js.map +7 -0
  207. package/dist/modules/messages/setup.js +21 -0
  208. package/dist/modules/messages/setup.js.map +7 -0
  209. package/dist/modules/messages/subscribers/message-notification.js +108 -0
  210. package/dist/modules/messages/subscribers/message-notification.js.map +7 -0
  211. package/dist/modules/messages/workers/send-email.worker.js +253 -0
  212. package/dist/modules/messages/workers/send-email.worker.js.map +7 -0
  213. package/dist/modules/sales/backend/sales/documents/[id]/page.js +30 -11
  214. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  215. package/dist/modules/sales/commands/payments.js +12 -6
  216. package/dist/modules/sales/commands/payments.js.map +2 -2
  217. package/dist/modules/sales/lib/messageObjectPreviews.js +114 -0
  218. package/dist/modules/sales/lib/messageObjectPreviews.js.map +7 -0
  219. package/dist/modules/sales/message-objects.js +57 -0
  220. package/dist/modules/sales/message-objects.js.map +7 -0
  221. package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js +51 -0
  222. package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js.map +7 -0
  223. package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js +36 -0
  224. package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js.map +7 -0
  225. package/dist/modules/sales/widgets/messages/index.js +7 -0
  226. package/dist/modules/sales/widgets/messages/index.js.map +7 -0
  227. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +55 -1
  228. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  229. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +60 -1
  230. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
  231. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +2 -19
  232. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  233. package/dist/modules/staff/components/LeaveRequestDetail.js +112 -0
  234. package/dist/modules/staff/components/LeaveRequestDetail.js.map +7 -0
  235. package/dist/modules/staff/components/LeaveRequestForm.js +3 -1
  236. package/dist/modules/staff/components/LeaveRequestForm.js.map +2 -2
  237. package/dist/modules/staff/components/LeaveRequestPreview.js +43 -0
  238. package/dist/modules/staff/components/LeaveRequestPreview.js.map +7 -0
  239. package/dist/modules/staff/lib/messageObjectPreviews.js +148 -0
  240. package/dist/modules/staff/lib/messageObjectPreviews.js.map +7 -0
  241. package/dist/modules/staff/message-objects.js +104 -0
  242. package/dist/modules/staff/message-objects.js.map +7 -0
  243. package/dist/modules/staff/message-types.js +23 -0
  244. package/dist/modules/staff/message-types.js.map +7 -0
  245. package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js +51 -0
  246. package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js.map +7 -0
  247. package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js +34 -0
  248. package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js.map +7 -0
  249. package/dist/modules/staff/widgets/messages/index.js +7 -0
  250. package/dist/modules/staff/widgets/messages/index.js.map +7 -0
  251. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +6 -6
  252. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  253. package/generated/entities/message/index.ts +31 -0
  254. package/generated/entities/message_access_token/index.ts +8 -0
  255. package/generated/entities/message_confirmation/index.ts +9 -0
  256. package/generated/entities/message_object/index.ts +10 -0
  257. package/generated/entities/message_recipient/index.ts +14 -0
  258. package/generated/entities.ids.generated.ts +8 -0
  259. package/generated/entity-fields-registry.ts +10 -0
  260. package/jest.setup.ts +5 -0
  261. package/package.json +2 -2
  262. package/src/modules/attachments/i18n/de.json +4 -0
  263. package/src/modules/attachments/i18n/en.json +4 -0
  264. package/src/modules/attachments/i18n/es.json +4 -0
  265. package/src/modules/attachments/i18n/pl.json +4 -0
  266. package/src/modules/auth/components/AclEditor.tsx +4 -2
  267. package/src/modules/auth/frontend/reset.tsx +3 -3
  268. package/src/modules/auth/i18n/de.json +5 -0
  269. package/src/modules/auth/i18n/en.json +5 -0
  270. package/src/modules/auth/i18n/es.json +5 -0
  271. package/src/modules/auth/i18n/pl.json +5 -0
  272. package/src/modules/catalog/i18n/de.json +21 -0
  273. package/src/modules/catalog/i18n/en.json +21 -0
  274. package/src/modules/catalog/i18n/es.json +21 -0
  275. package/src/modules/catalog/i18n/pl.json +21 -0
  276. package/src/modules/currencies/i18n/de.json +6 -0
  277. package/src/modules/currencies/i18n/en.json +6 -0
  278. package/src/modules/currencies/i18n/es.json +6 -0
  279. package/src/modules/currencies/i18n/pl.json +6 -0
  280. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +20 -4
  281. package/src/modules/customers/i18n/de.json +26 -1
  282. package/src/modules/customers/i18n/en.json +25 -0
  283. package/src/modules/customers/i18n/es.json +25 -0
  284. package/src/modules/customers/i18n/pl.json +25 -0
  285. package/src/modules/customers/lib/messageObjectPreviews.ts +154 -0
  286. package/src/modules/customers/message-objects.ts +70 -0
  287. package/src/modules/customers/widgets/messages/CustomerMessageObjectDetail.tsx +57 -0
  288. package/src/modules/customers/widgets/messages/CustomerMessageObjectPreview.tsx +49 -0
  289. package/src/modules/customers/widgets/messages/index.ts +2 -0
  290. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +41 -5
  291. package/src/modules/dashboards/i18n/de.json +5 -1
  292. package/src/modules/dashboards/i18n/en.json +5 -1
  293. package/src/modules/dashboards/i18n/es.json +5 -1
  294. package/src/modules/dashboards/i18n/pl.json +5 -1
  295. package/src/modules/dictionaries/i18n/de.json +14 -1
  296. package/src/modules/dictionaries/i18n/en.json +14 -1
  297. package/src/modules/dictionaries/i18n/es.json +14 -1
  298. package/src/modules/dictionaries/i18n/pl.json +14 -1
  299. package/src/modules/feature_toggles/i18n/de.json +3 -0
  300. package/src/modules/feature_toggles/i18n/en.json +3 -0
  301. package/src/modules/feature_toggles/i18n/es.json +3 -0
  302. package/src/modules/feature_toggles/i18n/pl.json +3 -0
  303. package/src/modules/messages/acl.ts +11 -0
  304. package/src/modules/messages/api/[id]/actions/[actionId]/route.ts +103 -0
  305. package/src/modules/messages/api/[id]/archive/route.ts +138 -0
  306. package/src/modules/messages/api/[id]/attachments/route.ts +217 -0
  307. package/src/modules/messages/api/[id]/confirmation/route.ts +73 -0
  308. package/src/modules/messages/api/[id]/conversation/archive/route.ts +69 -0
  309. package/src/modules/messages/api/[id]/conversation/read/route.ts +69 -0
  310. package/src/modules/messages/api/[id]/conversation/route.ts +69 -0
  311. package/src/modules/messages/api/[id]/forward/route.ts +87 -0
  312. package/src/modules/messages/api/[id]/forward-preview/route.ts +75 -0
  313. package/src/modules/messages/api/[id]/read/route.ts +138 -0
  314. package/src/modules/messages/api/[id]/reply/route.ts +89 -0
  315. package/src/modules/messages/api/[id]/route.ts +401 -0
  316. package/src/modules/messages/api/object-types/route.ts +54 -0
  317. package/src/modules/messages/api/openapi.ts +261 -0
  318. package/src/modules/messages/api/route.ts +374 -0
  319. package/src/modules/messages/api/token/[token]/route.ts +103 -0
  320. package/src/modules/messages/api/types/route.ts +39 -0
  321. package/src/modules/messages/api/unread-count/route.ts +55 -0
  322. package/src/modules/messages/backend/messages/[id]/page.meta.ts +12 -0
  323. package/src/modules/messages/backend/messages/[id]/page.tsx +12 -0
  324. package/src/modules/messages/backend/messages/compose/page.meta.ts +13 -0
  325. package/src/modules/messages/backend/messages/compose/page.tsx +12 -0
  326. package/src/modules/messages/backend/page.meta.ts +31 -0
  327. package/src/modules/messages/backend/page.tsx +12 -0
  328. package/src/modules/messages/commands/actions.ts +307 -0
  329. package/src/modules/messages/commands/attachments.ts +227 -0
  330. package/src/modules/messages/commands/confirmations.ts +183 -0
  331. package/src/modules/messages/commands/conversation.ts +292 -0
  332. package/src/modules/messages/commands/messages.ts +845 -0
  333. package/src/modules/messages/commands/recipients.ts +281 -0
  334. package/src/modules/messages/commands/shared.ts +350 -0
  335. package/src/modules/messages/commands/tokens.ts +80 -0
  336. package/src/modules/messages/components/ComposeMessagePageClient.tsx +23 -0
  337. package/src/modules/messages/components/MessageDetailPageClient.tsx +287 -0
  338. package/src/modules/messages/components/MessagesInboxPageClient.tsx +469 -0
  339. package/src/modules/messages/components/confirmation/MessageConfirmationActions.tsx +35 -0
  340. package/src/modules/messages/components/confirmation/MessageConfirmationContent.tsx +88 -0
  341. package/src/modules/messages/components/defaults/DefaultMessageActions.tsx +37 -0
  342. package/src/modules/messages/components/defaults/DefaultMessageContent.tsx +21 -0
  343. package/src/modules/messages/components/defaults/DefaultMessageListItem.tsx +102 -0
  344. package/src/modules/messages/components/defaults/MessageRecordObjectDetail.tsx +114 -0
  345. package/src/modules/messages/components/defaults/MessageRecordObjectPreview.tsx +74 -0
  346. package/src/modules/messages/components/message-detail/detail-panels.ts +13 -0
  347. package/src/modules/messages/components/message-detail/hooks/useMessageDetails.ts +56 -0
  348. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsActions.ts +367 -0
  349. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +134 -0
  350. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.ts +102 -0
  351. package/src/modules/messages/components/message-detail/panels/MainMessageHeader.tsx +108 -0
  352. package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +144 -0
  353. package/src/modules/messages/components/message-detail/panels/MessageListComponent.tsx +63 -0
  354. package/src/modules/messages/components/message-detail/panels/actions-panel.tsx +66 -0
  355. package/src/modules/messages/components/message-detail/panels/attachments-panel.tsx +86 -0
  356. package/src/modules/messages/components/message-detail/panels/body-panel.tsx +32 -0
  357. package/src/modules/messages/components/message-detail/panels/composer-dialogs.tsx +42 -0
  358. package/src/modules/messages/components/message-detail/panels/dialogs.tsx +107 -0
  359. package/src/modules/messages/components/message-detail/panels/index.ts +11 -0
  360. package/src/modules/messages/components/message-detail/panels/meta-panel.tsx +19 -0
  361. package/src/modules/messages/components/message-detail/panels/objects-panel.tsx +65 -0
  362. package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +65 -0
  363. package/src/modules/messages/components/message-detail/types.ts +114 -0
  364. package/src/modules/messages/components/message-detail/utils.ts +62 -0
  365. package/src/modules/messages/components/utils/PriorityBadge.tsx +63 -0
  366. package/src/modules/messages/components/utils/typeUiRegistry.ts +106 -0
  367. package/src/modules/messages/data/entities.ts +284 -0
  368. package/src/modules/messages/data/validators.ts +297 -0
  369. package/src/modules/messages/emails/MessageEmail.tsx +143 -0
  370. package/src/modules/messages/events.ts +24 -0
  371. package/src/modules/messages/frontend/messages/view/[token]/page.meta.ts +5 -0
  372. package/src/modules/messages/frontend/messages/view/[token]/page.tsx +389 -0
  373. package/src/modules/messages/i18n/de.json +240 -0
  374. package/src/modules/messages/i18n/en.json +240 -0
  375. package/src/modules/messages/i18n/es.json +240 -0
  376. package/src/modules/messages/i18n/pl.json +240 -0
  377. package/src/modules/messages/index.ts +19 -0
  378. package/src/modules/messages/lib/actions.ts +204 -0
  379. package/src/modules/messages/lib/attachments.ts +197 -0
  380. package/src/modules/messages/lib/constants.ts +2 -0
  381. package/src/modules/messages/lib/email-sender.ts +255 -0
  382. package/src/modules/messages/lib/forwarding.ts +240 -0
  383. package/src/modules/messages/lib/message-objects-registry.ts +60 -0
  384. package/src/modules/messages/lib/message-types-registry.ts +48 -0
  385. package/src/modules/messages/lib/object-validation.ts +26 -0
  386. package/src/modules/messages/lib/operationMetadata.ts +43 -0
  387. package/src/modules/messages/lib/priorityUtils.ts +76 -0
  388. package/src/modules/messages/lib/routeHelpers.ts +65 -0
  389. package/src/modules/messages/message-objects.ts +5 -0
  390. package/src/modules/messages/message-types.ts +65 -0
  391. package/src/modules/messages/migrations/.snapshot-open-mercato.json +957 -0
  392. package/src/modules/messages/migrations/Migration20260213181243.ts +34 -0
  393. package/src/modules/messages/migrations/Migration20260215165126.ts +16 -0
  394. package/src/modules/messages/notifications.ts +25 -0
  395. package/src/modules/messages/setup.ts +19 -0
  396. package/src/modules/messages/subscribers/message-notification.ts +138 -0
  397. package/src/modules/messages/workers/send-email.worker.ts +321 -0
  398. package/src/modules/query_index/i18n/es.json +2 -2
  399. package/src/modules/resources/i18n/de.json +57 -0
  400. package/src/modules/resources/i18n/en.json +57 -0
  401. package/src/modules/resources/i18n/es.json +57 -0
  402. package/src/modules/resources/i18n/pl.json +57 -0
  403. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +23 -7
  404. package/src/modules/sales/commands/payments.ts +12 -6
  405. package/src/modules/sales/i18n/de.json +26 -0
  406. package/src/modules/sales/i18n/en.json +26 -0
  407. package/src/modules/sales/i18n/es.json +26 -0
  408. package/src/modules/sales/i18n/pl.json +26 -0
  409. package/src/modules/sales/lib/messageObjectPreviews.ts +150 -0
  410. package/src/modules/sales/message-objects.ts +56 -0
  411. package/src/modules/sales/widgets/messages/SalesDocumentMessageDetail.tsx +57 -0
  412. package/src/modules/sales/widgets/messages/SalesDocumentMessagePreview.tsx +46 -0
  413. package/src/modules/sales/widgets/messages/index.ts +2 -0
  414. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +54 -0
  415. package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +58 -0
  416. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +2 -32
  417. package/src/modules/staff/components/LeaveRequestDetail.tsx +135 -0
  418. package/src/modules/staff/components/LeaveRequestForm.tsx +3 -0
  419. package/src/modules/staff/components/LeaveRequestPreview.tsx +74 -0
  420. package/src/modules/staff/i18n/de.json +22 -0
  421. package/src/modules/staff/i18n/en.json +22 -0
  422. package/src/modules/staff/i18n/es.json +22 -0
  423. package/src/modules/staff/i18n/pl.json +22 -0
  424. package/src/modules/staff/lib/messageObjectPreviews.ts +182 -0
  425. package/src/modules/staff/message-objects.ts +102 -0
  426. package/src/modules/staff/message-types.ts +21 -0
  427. package/src/modules/staff/widgets/messages/StaffMessageObjectDetail.tsx +57 -0
  428. package/src/modules/staff/widgets/messages/StaffMessageObjectPreview.tsx +44 -0
  429. package/src/modules/staff/widgets/messages/index.ts +2 -0
  430. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +6 -6
  431. package/src/modules/workflows/i18n/de.json +41 -0
  432. package/src/modules/workflows/i18n/en.json +41 -0
  433. package/src/modules/workflows/i18n/es.json +41 -0
  434. package/src/modules/workflows/i18n/pl.json +41 -0
@@ -0,0 +1,34 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+
3
+ export class Migration20260213181243 extends Migration {
4
+
5
+ override async up(): Promise<void> {
6
+ this.addSql(`create table "messages" ("id" uuid not null default gen_random_uuid(), "type" text not null default 'default', "thread_id" uuid null, "parent_message_id" uuid null, "sender_user_id" uuid not null, "subject" text not null, "body" text not null, "body_format" text not null default 'text', "priority" text not null default 'normal', "status" text not null default 'draft', "is_draft" boolean not null default true, "sent_at" timestamptz null, "action_data" jsonb null, "action_result" jsonb null, "action_taken" text null, "action_taken_by_user_id" uuid null, "action_taken_at" timestamptz null, "send_via_email" boolean not null default false, "tenant_id" uuid not null, "organization_id" uuid null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, "visibility" text null, "source_entity_type" text null, "source_entity_id" uuid null, "external_email" text null, "external_name" text null, "external_email_sent_at" timestamptz null, "external_email_failed_at" timestamptz null, "external_email_error" text null, constraint "messages_pkey" primary key ("id"));`);
7
+ this.addSql(`create index "messages_tenant_idx" on "messages" ("tenant_id", "organization_id");`);
8
+ this.addSql(`create index "messages_type_idx" on "messages" ("type", "tenant_id");`);
9
+ this.addSql(`create index "messages_thread_idx" on "messages" ("thread_id");`);
10
+ this.addSql(`create index "messages_sender_idx" on "messages" ("sender_user_id", "sent_at");`);
11
+
12
+ this.addSql(`create table "message_access_tokens" ("id" uuid not null default gen_random_uuid(), "message_id" uuid not null, "recipient_user_id" uuid not null, "token" text not null, "expires_at" timestamptz not null, "used_at" timestamptz null, "use_count" int not null default 0, "created_at" timestamptz not null, constraint "message_access_tokens_pkey" primary key ("id"));`);
13
+ this.addSql(`alter table "message_access_tokens" add constraint "message_access_tokens_token_unique" unique ("token");`);
14
+ this.addSql(`create index "message_access_tokens_message_idx" on "message_access_tokens" ("message_id");`);
15
+ this.addSql(`create index "message_access_tokens_token_idx" on "message_access_tokens" ("token");`);
16
+
17
+ this.addSql(`create table "message_objects" ("id" uuid not null default gen_random_uuid(), "message_id" uuid not null, "entity_module" text not null, "entity_type" text not null, "entity_id" uuid not null, "action_required" boolean not null default false, "action_type" text null, "action_label" text null, "entity_snapshot" jsonb null, "created_at" timestamptz not null, constraint "message_objects_pkey" primary key ("id"));`);
18
+ this.addSql(`create index "message_objects_entity_idx" on "message_objects" ("entity_type", "entity_id");`);
19
+ this.addSql(`create index "message_objects_message_idx" on "message_objects" ("message_id");`);
20
+
21
+ this.addSql(`create table "message_recipients" ("id" uuid not null default gen_random_uuid(), "message_id" uuid not null, "recipient_user_id" uuid not null, "recipient_type" text not null default 'to', "status" text not null default 'unread', "read_at" timestamptz null, "archived_at" timestamptz null, "deleted_at" timestamptz null, "email_sent_at" timestamptz null, "email_delivered_at" timestamptz null, "email_opened_at" timestamptz null, "email_failed_at" timestamptz null, "email_error" text null, "created_at" timestamptz not null, constraint "message_recipients_pkey" primary key ("id"));`);
22
+ this.addSql(`alter table "message_recipients" add constraint "message_recipients_message_user_unique" unique ("message_id", "recipient_user_id");`);
23
+ this.addSql(`create index "message_recipients_message_idx" on "message_recipients" ("message_id");`);
24
+ this.addSql(`create index "message_recipients_user_idx" on "message_recipients" ("recipient_user_id", "status");`);
25
+ }
26
+
27
+ override async down(): Promise<void> {
28
+ this.addSql(`drop table if exists "message_recipients" cascade;`);
29
+ this.addSql(`drop table if exists "message_objects" cascade;`);
30
+ this.addSql(`drop table if exists "message_access_tokens" cascade;`);
31
+ this.addSql(`drop table if exists "messages" cascade;`);
32
+ }
33
+
34
+ }
@@ -0,0 +1,16 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+
3
+ export class Migration20260215165126 extends Migration {
4
+
5
+ override async up(): Promise<void> {
6
+ this.addSql(`create table "message_confirmations" ("id" uuid not null default gen_random_uuid(), "message_id" uuid not null, "tenant_id" uuid not null, "organization_id" uuid null, "confirmed" boolean not null default true, "confirmed_by_user_id" uuid null, "confirmed_at" timestamptz null, "created_at" timestamptz not null, "updated_at" timestamptz not null, constraint "message_confirmations_pkey" primary key ("id"));`);
7
+ this.addSql(`create index "message_confirmations_scope_idx" on "message_confirmations" ("tenant_id", "organization_id");`);
8
+ this.addSql(`create index "message_confirmations_message_idx" on "message_confirmations" ("message_id");`);
9
+ this.addSql(`alter table "message_confirmations" add constraint "message_confirmations_message_unique" unique ("message_id");`);
10
+ }
11
+
12
+ override async down(): Promise<void> {
13
+ this.addSql(`drop table if exists "message_confirmations" cascade;`);
14
+ }
15
+
16
+ }
@@ -0,0 +1,25 @@
1
+ import type { NotificationTypeDefinition } from '@open-mercato/shared/modules/notifications/types'
2
+
3
+ export const notificationTypes: NotificationTypeDefinition[] = [
4
+ {
5
+ type: 'messages.new',
6
+ module: 'messages',
7
+ titleKey: 'messages.notifications.new.title',
8
+ bodyKey: 'messages.notifications.new.body',
9
+ icon: 'mail',
10
+ severity: 'info',
11
+ actions: [
12
+ {
13
+ id: 'view',
14
+ labelKey: 'common.view',
15
+ variant: 'outline',
16
+ href: '/backend/messages/{sourceEntityId}',
17
+ icon: 'external-link',
18
+ },
19
+ ],
20
+ linkHref: '/backend/messages/{sourceEntityId}',
21
+ expiresAfterHours: 168,
22
+ },
23
+ ]
24
+
25
+ export default notificationTypes
@@ -0,0 +1,19 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ superadmin: ['messages.*'],
6
+ admin: [
7
+ 'messages.*',
8
+ ],
9
+ employee: [
10
+ 'messages.view',
11
+ 'messages.compose',
12
+ 'messages.attach',
13
+ 'messages.attach_files',
14
+ 'messages.actions',
15
+ ],
16
+ },
17
+ }
18
+
19
+ export default setup
@@ -0,0 +1,138 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
3
+ import { createQueue } from '@open-mercato/queue'
4
+ import { buildBatchNotificationFromType } from '../../notifications/lib/notificationBuilder'
5
+ import { resolveNotificationService } from '../../notifications/lib/notificationService'
6
+ import {
7
+ MESSAGES_EMAIL_QUEUE_NAME,
8
+ type SendMessageEmailJob,
9
+ } from '../workers/send-email.worker'
10
+ import { User } from '../../auth/data/entities'
11
+ import { Message } from '../data/entities'
12
+ import { notificationTypes } from '../notifications'
13
+
14
+ export const metadata = {
15
+ event: 'messages.message.sent',
16
+ persistent: true,
17
+ id: 'messages:queue-email-delivery',
18
+ }
19
+
20
+ type MessageSentPayload = {
21
+ messageId: string
22
+ senderUserId: string
23
+ recipientUserIds: string[]
24
+ sendViaEmail: boolean
25
+ externalEmail?: string | null
26
+ forwardedFrom?: string
27
+ replyTo?: string
28
+ tenantId: string
29
+ organizationId?: string | null
30
+ }
31
+
32
+ type ResolverContext = {
33
+ resolve: <T = unknown>(name: string) => T
34
+ }
35
+
36
+ async function resolveNotificationVariables(payload: MessageSentPayload, ctx: ResolverContext): Promise<{ title: string; from: string }> {
37
+ try {
38
+ const em = ctx.resolve<EntityManager>('em')?.fork()
39
+ if (!em) return { title: '', from: '' }
40
+
41
+ const scope = {
42
+ tenantId: payload.tenantId,
43
+ organizationId: payload.organizationId ?? null,
44
+ }
45
+ const whereUser: { id: string; tenantId: string; deletedAt: null; organizationId?: string | null } = {
46
+ id: payload.senderUserId,
47
+ tenantId: payload.tenantId,
48
+ deletedAt: null,
49
+ }
50
+ if (payload.organizationId !== undefined) {
51
+ whereUser.organizationId = payload.organizationId
52
+ }
53
+
54
+ const [message, sender] = await Promise.all([
55
+ findOneWithDecryption(
56
+ em,
57
+ Message,
58
+ {
59
+ id: payload.messageId,
60
+ tenantId: payload.tenantId,
61
+ deletedAt: null,
62
+ },
63
+ undefined,
64
+ scope,
65
+ ),
66
+ findOneWithDecryption(
67
+ em,
68
+ User,
69
+ whereUser,
70
+ undefined,
71
+ scope,
72
+ ),
73
+ ])
74
+
75
+ return {
76
+ title: typeof message?.subject === 'string' ? message.subject : '',
77
+ from: typeof sender?.name === 'string' && sender.name.trim().length > 0
78
+ ? sender.name
79
+ : typeof sender?.email === 'string'
80
+ ? sender.email
81
+ : '',
82
+ }
83
+ } catch {
84
+ return { title: '', from: '' }
85
+ }
86
+ }
87
+
88
+
89
+ export default async function handle(payload: MessageSentPayload, ctx: ResolverContext): Promise<void> {
90
+ const uniqueRecipientUserIds = Array.from(new Set(payload.recipientUserIds))
91
+
92
+ const typeDef = notificationTypes.find((type) => type.type === 'messages.new')
93
+ if (typeDef && uniqueRecipientUserIds.length > 0) {
94
+ const variables = await resolveNotificationVariables(payload, ctx)
95
+ const notificationService = resolveNotificationService(ctx)
96
+ const notificationInput = buildBatchNotificationFromType(typeDef, {
97
+ recipientUserIds: uniqueRecipientUserIds,
98
+ titleVariables: variables,
99
+ bodyVariables: variables,
100
+ sourceEntityType: 'message',
101
+ sourceEntityId: payload.messageId,
102
+ linkHref: `/backend/messages/${payload.messageId}`,
103
+ })
104
+ await notificationService.createBatch(notificationInput, {
105
+ tenantId: payload.tenantId,
106
+ organizationId: payload.organizationId ?? null,
107
+ })
108
+ }
109
+
110
+ if (!payload.sendViaEmail) {
111
+ return
112
+ }
113
+
114
+ const strategy = process.env.QUEUE_STRATEGY === 'async' ? 'async' : 'local'
115
+
116
+ const emailQueue = createQueue<SendMessageEmailJob>(MESSAGES_EMAIL_QUEUE_NAME, strategy)
117
+
118
+ for (const recipientUserId of uniqueRecipientUserIds) {
119
+ await emailQueue.enqueue({
120
+ type: 'recipient',
121
+ messageId: payload.messageId,
122
+ recipientUserId,
123
+ tenantId: payload.tenantId,
124
+ organizationId: payload.organizationId ?? null,
125
+ })
126
+ }
127
+
128
+ const externalEmail = payload.externalEmail?.trim()
129
+ if (externalEmail) {
130
+ await emailQueue.enqueue({
131
+ type: 'external',
132
+ messageId: payload.messageId,
133
+ email: externalEmail,
134
+ tenantId: payload.tenantId,
135
+ organizationId: payload.organizationId ?? null,
136
+ })
137
+ }
138
+ }
@@ -0,0 +1,321 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import type { JobContext, QueuedJob, WorkerMeta } from '@open-mercato/queue'
3
+ import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
4
+ import { User } from '../../auth/data/entities'
5
+ import { Message, MessageObject, MessageRecipient } from '../data/entities'
6
+ import { emitMessagesEvent } from '../events'
7
+ import { getMessageEmailAttachments } from '../lib/attachments'
8
+ import {
9
+ sendMessageEmailToExternal,
10
+ sendMessageEmailToRecipient,
11
+ } from '../lib/email-sender'
12
+
13
+ export const MESSAGES_EMAIL_QUEUE_NAME = 'messages-email'
14
+
15
+ export type SendMessageEmailToRecipientJob = {
16
+ type: 'recipient'
17
+ messageId: string
18
+ recipientUserId: string
19
+ tenantId: string
20
+ organizationId?: string | null
21
+ }
22
+
23
+ export type SendMessageEmailToExternalJob = {
24
+ type: 'external'
25
+ messageId: string
26
+ email: string
27
+ tenantId: string
28
+ organizationId?: string | null
29
+ }
30
+
31
+ export type SendMessageEmailJob = SendMessageEmailToRecipientJob | SendMessageEmailToExternalJob
32
+
33
+ export const metadata: WorkerMeta = {
34
+ queue: MESSAGES_EMAIL_QUEUE_NAME,
35
+ id: 'messages:send-email',
36
+ concurrency: 10,
37
+ }
38
+
39
+ type HandlerContext = {
40
+ resolve: <T = unknown>(name: string) => T
41
+ }
42
+
43
+ async function emitEmailDeliveryEvent(
44
+ ctx: HandlerContext,
45
+ eventId: 'messages.message.email_sent' | 'messages.message.email_failed',
46
+ payload: {
47
+ messageId: string
48
+ target: 'recipient' | 'external'
49
+ recipientUserId?: string
50
+ email?: string
51
+ error?: string
52
+ tenantId: string
53
+ organizationId?: string | null
54
+ }
55
+ ) {
56
+ const eventBus = ctx.resolve<{ emit?: unknown } | null>('eventBus')
57
+ if (!eventBus || typeof eventBus !== 'object' || typeof (eventBus as { emit?: unknown }).emit !== 'function') {
58
+ return
59
+ }
60
+ await emitMessagesEvent(eventId, payload, { persistent: true })
61
+ }
62
+
63
+ async function resolveSender(em: EntityManager, message: Message) {
64
+ const sender = await findOneWithDecryption(
65
+ em,
66
+ User,
67
+ {
68
+ id: message.senderUserId,
69
+ tenantId: message.tenantId,
70
+ deletedAt: null,
71
+ },
72
+ undefined,
73
+ { tenantId: message.tenantId, organizationId: message.organizationId ?? null }
74
+ )
75
+ return {
76
+ name: sender?.name ?? null,
77
+ email: sender?.email ?? null,
78
+ }
79
+ }
80
+
81
+ async function resolveMessageScope(
82
+ em: EntityManager,
83
+ payload: SendMessageEmailJob
84
+ ) {
85
+ return await em.findOne(Message, {
86
+ id: payload.messageId,
87
+ tenantId: payload.tenantId,
88
+ organizationId: payload.organizationId ?? null,
89
+ deletedAt: null,
90
+ })
91
+ }
92
+
93
+ export async function claimRecipientDelivery(
94
+ em: EntityManager,
95
+ payload: SendMessageEmailToRecipientJob,
96
+ ): Promise<Date | null> {
97
+ const claimTimestamp = new Date()
98
+ const updatedRows = await em.nativeUpdate(
99
+ MessageRecipient,
100
+ {
101
+ messageId: payload.messageId,
102
+ recipientUserId: payload.recipientUserId,
103
+ emailSentAt: null,
104
+ },
105
+ {
106
+ emailSentAt: claimTimestamp,
107
+ emailFailedAt: null,
108
+ emailError: null,
109
+ },
110
+ )
111
+ return updatedRows > 0 ? claimTimestamp : null
112
+ }
113
+
114
+ export async function releaseRecipientClaim(
115
+ em: EntityManager,
116
+ payload: SendMessageEmailToRecipientJob,
117
+ claimTimestamp: Date,
118
+ errorMessage: string,
119
+ ): Promise<void> {
120
+ await em.nativeUpdate(
121
+ MessageRecipient,
122
+ {
123
+ messageId: payload.messageId,
124
+ recipientUserId: payload.recipientUserId,
125
+ emailSentAt: claimTimestamp,
126
+ },
127
+ {
128
+ emailSentAt: null,
129
+ emailFailedAt: new Date(),
130
+ emailError: errorMessage,
131
+ },
132
+ )
133
+ }
134
+
135
+ export async function claimExternalDelivery(
136
+ em: EntityManager,
137
+ payload: SendMessageEmailToExternalJob,
138
+ ): Promise<Date | null> {
139
+ const claimTimestamp = new Date()
140
+ const updatedRows = await em.nativeUpdate(
141
+ Message,
142
+ {
143
+ id: payload.messageId,
144
+ tenantId: payload.tenantId,
145
+ organizationId: payload.organizationId ?? null,
146
+ externalEmailSentAt: null,
147
+ },
148
+ {
149
+ externalEmailSentAt: claimTimestamp,
150
+ externalEmailFailedAt: null,
151
+ externalEmailError: null,
152
+ },
153
+ )
154
+ return updatedRows > 0 ? claimTimestamp : null
155
+ }
156
+
157
+ export async function releaseExternalClaim(
158
+ em: EntityManager,
159
+ payload: SendMessageEmailToExternalJob,
160
+ claimTimestamp: Date,
161
+ errorMessage: string,
162
+ ): Promise<void> {
163
+ await em.nativeUpdate(
164
+ Message,
165
+ {
166
+ id: payload.messageId,
167
+ tenantId: payload.tenantId,
168
+ organizationId: payload.organizationId ?? null,
169
+ externalEmailSentAt: claimTimestamp,
170
+ },
171
+ {
172
+ externalEmailSentAt: null,
173
+ externalEmailFailedAt: new Date(),
174
+ externalEmailError: errorMessage,
175
+ },
176
+ )
177
+ }
178
+
179
+ export default async function handle(
180
+ job: QueuedJob<SendMessageEmailJob>,
181
+ ctx: JobContext & HandlerContext
182
+ ): Promise<void> {
183
+ const { payload } = job
184
+ const em = (ctx.resolve('em') as EntityManager).fork()
185
+
186
+ const message = await resolveMessageScope(em, payload)
187
+ if (!message) {
188
+ console.error('[messages:send-email] Message not found', payload.messageId)
189
+ return
190
+ }
191
+
192
+ const objects = await em.find(MessageObject, { messageId: message.id })
193
+ const attachments = await getMessageEmailAttachments(
194
+ em,
195
+ message.id,
196
+ message.organizationId ?? null,
197
+ message.tenantId
198
+ )
199
+ const sender = await resolveSender(em, message)
200
+
201
+ if (payload.type === 'external') {
202
+ const externalClaimTimestamp = await claimExternalDelivery(em, payload)
203
+ if (!externalClaimTimestamp) {
204
+ return
205
+ }
206
+
207
+ try {
208
+ await sendMessageEmailToExternal({
209
+ message,
210
+ email: payload.email,
211
+ sender,
212
+ objects,
213
+ attachments,
214
+ })
215
+ await emitEmailDeliveryEvent(ctx, 'messages.message.email_sent', {
216
+ messageId: message.id,
217
+ target: 'external',
218
+ email: payload.email,
219
+ tenantId: message.tenantId,
220
+ organizationId: message.organizationId ?? null,
221
+ })
222
+ } catch (error) {
223
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error'
224
+ await releaseExternalClaim(
225
+ em,
226
+ payload,
227
+ externalClaimTimestamp,
228
+ errorMessage,
229
+ )
230
+ await emitEmailDeliveryEvent(ctx, 'messages.message.email_failed', {
231
+ messageId: message.id,
232
+ target: 'external',
233
+ email: payload.email,
234
+ error: errorMessage,
235
+ tenantId: message.tenantId,
236
+ organizationId: message.organizationId ?? null,
237
+ })
238
+ console.error('[messages:send-email] External email send failed', error)
239
+ }
240
+ return
241
+ }
242
+
243
+ const recipientRecord = await em.findOne(MessageRecipient, {
244
+ messageId: payload.messageId,
245
+ recipientUserId: payload.recipientUserId,
246
+ })
247
+ if (!recipientRecord) {
248
+ console.error('[messages:send-email] Recipient row not found', payload)
249
+ return
250
+ }
251
+
252
+ if (recipientRecord.emailSentAt) {
253
+ return
254
+ }
255
+
256
+ const recipientClaimTimestamp = await claimRecipientDelivery(em, payload)
257
+ if (!recipientClaimTimestamp) {
258
+ return
259
+ }
260
+
261
+ const recipientUser = await findOneWithDecryption(
262
+ em,
263
+ User,
264
+ {
265
+ id: payload.recipientUserId,
266
+ tenantId: message.tenantId,
267
+ deletedAt: null,
268
+ },
269
+ undefined,
270
+ { tenantId: message.tenantId, organizationId: message.organizationId ?? null }
271
+ )
272
+
273
+ const recipientEmail = recipientUser?.email?.trim()
274
+ if (!recipientEmail) {
275
+ await releaseRecipientClaim(
276
+ em,
277
+ payload,
278
+ recipientClaimTimestamp,
279
+ 'Recipient has no email address',
280
+ )
281
+ return
282
+ }
283
+
284
+ try {
285
+ await sendMessageEmailToRecipient({
286
+ em,
287
+ message,
288
+ recipientUserId: payload.recipientUserId,
289
+ recipientEmail,
290
+ sender,
291
+ objects,
292
+ attachments,
293
+ })
294
+ await emitEmailDeliveryEvent(ctx, 'messages.message.email_sent', {
295
+ messageId: message.id,
296
+ target: 'recipient',
297
+ recipientUserId: payload.recipientUserId,
298
+ email: recipientEmail,
299
+ tenantId: message.tenantId,
300
+ organizationId: message.organizationId ?? null,
301
+ })
302
+ } catch (error) {
303
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error'
304
+ await releaseRecipientClaim(
305
+ em,
306
+ payload,
307
+ recipientClaimTimestamp,
308
+ errorMessage,
309
+ )
310
+ await emitEmailDeliveryEvent(ctx, 'messages.message.email_failed', {
311
+ messageId: message.id,
312
+ target: 'recipient',
313
+ recipientUserId: payload.recipientUserId,
314
+ email: recipientEmail,
315
+ error: errorMessage,
316
+ tenantId: message.tenantId,
317
+ organizationId: message.organizationId ?? null,
318
+ })
319
+ console.error('[messages:send-email] Recipient email send failed', error)
320
+ }
321
+ }
@@ -20,7 +20,7 @@
20
20
  "query_index.table.columns.label": "Etiqueta",
21
21
  "query_index.table.columns.records": "Registros",
22
22
  "query_index.table.columns.status": "Estado",
23
- "query_index.table.columns.vector": "Vector",
23
+ "query_index.table.columns.vector": "Vectorial",
24
24
  "query_index.table.confirm.fulltextPurge": "¿Eliminar el índice de texto completo de esta entidad? Esta acción no se puede deshacer.",
25
25
  "query_index.table.confirm.vectorPurge": "¿Eliminar los embeddings vectoriales de esta entidad? Esta acción no se puede deshacer.",
26
26
  "query_index.table.errors.actionFailed": "No se pudo ejecutar {{action}}.",
@@ -58,7 +58,7 @@
58
58
  "query_index.table.status.scope.stalled": "Detenido",
59
59
  "query_index.table.status.scopeLabel": "Ámbito",
60
60
  "query_index.table.status.stalled": "Detenido",
61
- "query_index.table.status.vectorLabel": "Vector",
61
+ "query_index.table.status.vectorLabel": "Vectorial",
62
62
  "query_index.table.status.vectorValue": "{{count}} / {{total}}",
63
63
  "query_index.table.status.withProgress": "{{status}} ({{progress}})"
64
64
  }
@@ -76,6 +76,12 @@
76
76
  "resources.audit.availabilityRuleSets.create": "Verfügbarkeitszeitplan erstellen",
77
77
  "resources.audit.availabilityRuleSets.delete": "Verfügbarkeitszeitplan löschen",
78
78
  "resources.audit.availabilityRuleSets.update": "Verfügbarkeitszeitplan aktualisieren",
79
+ "resources.audit.resourceActivities.create": "Ressourcenaktivität erstellen",
80
+ "resources.audit.resourceActivities.delete": "Ressourcenaktivität löschen",
81
+ "resources.audit.resourceActivities.update": "Ressourcenaktivität aktualisieren",
82
+ "resources.audit.resourceComments.create": "Ressourcenkommentar erstellen",
83
+ "resources.audit.resourceComments.delete": "Ressourcenkommentar löschen",
84
+ "resources.audit.resourceComments.update": "Ressourcenkommentar aktualisieren",
79
85
  "resources.audit.resourceTags.assign": "Ressourcen-Tag zuweisen",
80
86
  "resources.audit.resourceTags.create": "Ressourcen-Tag erstellen",
81
87
  "resources.audit.resourceTags.delete": "Ressourcen-Tag löschen",
@@ -349,6 +355,7 @@
349
355
  "resources.resources.detail.activities.update": "Aktivität aktualisieren (Cmd/Ctrl + Enter)",
350
356
  "resources.resources.detail.activities.updateSuccess": "Aktivität aktualisiert.",
351
357
  "resources.resources.detail.back": "Zurück zu Ressourcen",
358
+ "resources.resources.detail.formTitle": "Ressourceneinstellungen",
352
359
  "resources.resources.detail.inline.cancel": "Stornieren",
353
360
  "resources.resources.detail.inline.clear": "Klar",
354
361
  "resources.resources.detail.inline.emailChecking": "Suche nach übereinstimmenden Datensätzen...",
@@ -435,13 +442,63 @@
435
442
  "resources.resources.detail.tabs.notes": "Notizen",
436
443
  "resources.resources.detail.untitled": "Unbenannte Ressource",
437
444
  "resources.resources.flash.createdAvailability": "Gespeichert. Du kannst jetzt die Verfügbarkeit festlegen.",
445
+ "resources.resources.form.actions.create": "Erstellen",
446
+ "resources.resources.form.appearance.colorClear": "Farbe entfernen",
447
+ "resources.resources.form.appearance.colorHelp": "Wählen Sie eine Farbe für diese Ressource.",
448
+ "resources.resources.form.appearance.colorLabel": "Farbe",
449
+ "resources.resources.form.appearance.iconClear": "Symbol entfernen",
450
+ "resources.resources.form.appearance.iconLabel": "Symbol",
451
+ "resources.resources.form.appearance.iconPicker": "Symbole durchsuchen",
452
+ "resources.resources.form.appearance.iconPlaceholder": "Emoji oder Symbolname eingeben",
453
+ "resources.resources.form.appearance.iconSearch": "Symbole oder Emojis suchen…",
454
+ "resources.resources.form.appearance.iconSearchEmpty": "Keine Symbole entsprechen Ihrer Suche",
455
+ "resources.resources.form.appearance.iconSuggestions": "Vorschläge",
456
+ "resources.resources.form.appearance.label": "Darstellung",
457
+ "resources.resources.form.appearance.previewEmpty": "Keine Darstellung ausgewählt",
458
+ "resources.resources.form.createTitle": "Ressource erstellen",
459
+ "resources.resources.form.editTitle": "Ressource bearbeiten",
460
+ "resources.resources.form.errors.create": "Ressource konnte nicht erstellt werden.",
461
+ "resources.resources.form.errors.delete": "Ressource konnte nicht gelöscht werden.",
462
+ "resources.resources.form.errors.load": "Ressource konnte nicht geladen werden.",
463
+ "resources.resources.form.errors.nameRequired": "Ressourcenname ist erforderlich.",
464
+ "resources.resources.form.errors.notFound": "Ressource nicht gefunden.",
465
+ "resources.resources.form.errors.update": "Ressource konnte nicht aktualisiert werden.",
466
+ "resources.resources.form.fields.active": "Aktiv",
467
+ "resources.resources.form.fields.capacity": "Kapazität",
438
468
  "resources.resources.form.fields.capacity.help": "Hängt von der Ressource ab und kann Plätze, Einheiten, Menge oder eine andere Kapazitätsart bedeuten.",
439
469
  "resources.resources.form.fields.capacityUnit": "Kapazitätseinheit",
440
470
  "resources.resources.form.fields.capacityUnit.missing": "Das Kapazitätseinheiten-Wörterbuch ist nicht konfiguriert.",
471
+ "resources.resources.form.fields.description": "Beschreibung",
472
+ "resources.resources.form.fields.name": "Name",
473
+ "resources.resources.form.fields.type": "Ressourcentyp",
441
474
  "resources.resources.form.fields.type.add": "Ressourcentyp hinzufügen",
442
475
  "resources.resources.form.fields.type.manage": "Ressourcentypen verwalten",
476
+ "resources.resources.form.flash.deleted": "Ressource gelöscht.",
477
+ "resources.resources.form.flash.updated": "Ressource aktualisiert.",
478
+ "resources.resources.form.loading": "Ressource wird geladen…",
479
+ "resources.resources.list.actions.create": "Erstellen",
480
+ "resources.resources.list.columns.active": "Aktiv",
481
+ "resources.resources.list.columns.appearance": "Darstellung",
482
+ "resources.resources.list.columns.capacity": "Kapazität",
483
+ "resources.resources.list.columns.capacity.empty": "Nicht festgelegt",
484
+ "resources.resources.list.columns.name": "Name",
485
+ "resources.resources.list.columns.tags": "Tags",
486
+ "resources.resources.list.columns.tags.empty": "Keine Tags",
487
+ "resources.resources.list.columns.type": "Type",
488
+ "resources.resources.list.columns.type.empty": "Kein Typ",
489
+ "resources.resources.list.confirmDelete": "Diese Ressource löschen? Kann nicht rückgängig gemacht werden.",
490
+ "resources.resources.list.error.delete": "Ressource konnte nicht gelöscht werden.",
491
+ "resources.resources.list.error.load": "Ressourcen konnten nicht geladen werden.",
443
492
  "resources.resources.list.filters.resourceType": "Ressourcentyp",
444
493
  "resources.resources.list.filters.tags": "Schlagworte",
494
+ "resources.resources.list.flash.deleted": "Ressource gelöscht.",
495
+ "resources.resources.list.group.unassigned": "Nicht zugewiesen",
496
+ "resources.resources.list.group.unknown": "Unbekannt",
497
+ "resources.resources.page.title": "Ressourcen",
498
+ "resources.resources.schedule.actions.details": "Details anzeigen",
499
+ "resources.resources.tabs.availability": "Verfügbarkeit",
500
+ "resources.resources.tabs.details": "Details",
501
+ "resources.resources.tabs.label": "Ressourcenbereiche",
445
502
  "resources.resources.tags.cancelShortcut": "Abbrechen (Esc)",
446
503
  "resources.resources.tags.createError": "Tag konnte nicht erstellt werden.",
447
504
  "resources.resources.tags.errors.invalid": "Ungültige Tag-Daten",