@open-mercato/core 0.4.2-canary-bdaa640a68 → 0.4.2-canary-3b5064ce72

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 (497) hide show
  1. package/dist/generated/entities/notification/index.js +57 -0
  2. package/dist/generated/entities/notification/index.js.map +7 -0
  3. package/dist/generated/entities.ids.generated.js +5 -1
  4. package/dist/generated/entities.ids.generated.js.map +2 -2
  5. package/dist/generated/entity-fields-registry.js +2 -0
  6. package/dist/generated/entity-fields-registry.js.map +2 -2
  7. package/dist/modules/api_docs/frontend/docs/api/page.js +3 -2
  8. package/dist/modules/api_docs/frontend/docs/api/page.js.map +2 -2
  9. package/dist/modules/api_keys/backend/api-keys/page.js +1 -1
  10. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  11. package/dist/modules/attachments/components/AttachmentLibrary.js +4 -0
  12. package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
  13. package/dist/modules/attachments/components/AttachmentPartitionSettings.js +2 -0
  14. package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
  15. package/dist/modules/auth/api/admin/nav.js +4 -3
  16. package/dist/modules/auth/api/admin/nav.js.map +2 -2
  17. package/dist/modules/auth/api/login.js +25 -6
  18. package/dist/modules/auth/api/login.js.map +2 -2
  19. package/dist/modules/auth/api/profile/route.js +157 -0
  20. package/dist/modules/auth/api/profile/route.js.map +7 -0
  21. package/dist/modules/auth/api/reset/confirm.js +25 -2
  22. package/dist/modules/auth/api/reset/confirm.js.map +2 -2
  23. package/dist/modules/auth/api/reset.js +23 -0
  24. package/dist/modules/auth/api/reset.js.map +2 -2
  25. package/dist/modules/auth/api/sidebar/preferences/route.js +14 -9
  26. package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
  27. package/dist/modules/auth/api/users/route.js +4 -2
  28. package/dist/modules/auth/api/users/route.js.map +2 -2
  29. package/dist/modules/auth/backend/auth/profile/page.js +141 -0
  30. package/dist/modules/auth/backend/auth/profile/page.js.map +7 -0
  31. package/dist/modules/auth/backend/auth/profile/page.meta.js +13 -0
  32. package/dist/modules/auth/backend/auth/profile/page.meta.js.map +7 -0
  33. package/dist/modules/auth/backend/roles/[id]/edit/page.js +4 -1
  34. package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
  35. package/dist/modules/auth/backend/roles/page.js +3 -3
  36. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  37. package/dist/modules/auth/backend/users/[id]/edit/page.js +18 -3
  38. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  39. package/dist/modules/auth/backend/users/create/page.js +15 -2
  40. package/dist/modules/auth/backend/users/create/page.js.map +2 -2
  41. package/dist/modules/auth/backend/users/page.js +3 -3
  42. package/dist/modules/auth/backend/users/page.js.map +2 -2
  43. package/dist/modules/auth/cli.js +25 -11
  44. package/dist/modules/auth/cli.js.map +2 -2
  45. package/dist/modules/auth/commands/users.js +59 -2
  46. package/dist/modules/auth/commands/users.js.map +2 -2
  47. package/dist/modules/auth/data/validators.js +6 -3
  48. package/dist/modules/auth/data/validators.js.map +2 -2
  49. package/dist/modules/auth/frontend/login.js +112 -3
  50. package/dist/modules/auth/frontend/login.js.map +2 -2
  51. package/dist/modules/auth/frontend/reset/[token]/page.js +20 -10
  52. package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
  53. package/dist/modules/auth/lib/setup-app.js +42 -8
  54. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  55. package/dist/modules/auth/notifications.js +112 -0
  56. package/dist/modules/auth/notifications.js.map +7 -0
  57. package/dist/modules/auth/services/authService.js +24 -3
  58. package/dist/modules/auth/services/authService.js.map +2 -2
  59. package/dist/modules/business_rules/api/execute/route.js +7 -1
  60. package/dist/modules/business_rules/api/execute/route.js.map +2 -2
  61. package/dist/modules/business_rules/backend/rules/page.js +4 -0
  62. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  63. package/dist/modules/business_rules/backend/sets/page.js +3 -0
  64. package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
  65. package/dist/modules/business_rules/cli.js +2 -1
  66. package/dist/modules/business_rules/cli.js.map +2 -2
  67. package/dist/modules/business_rules/lib/rule-engine.js +33 -3
  68. package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
  69. package/dist/modules/business_rules/notifications.js +28 -0
  70. package/dist/modules/business_rules/notifications.js.map +7 -0
  71. package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js +37 -0
  72. package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js.map +7 -0
  73. package/dist/modules/catalog/components/PriceKindSettings.js +2 -0
  74. package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
  75. package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -2
  76. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  77. package/dist/modules/catalog/components/products/ProductsDataTable.js +2 -0
  78. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  79. package/dist/modules/catalog/notifications.js +28 -0
  80. package/dist/modules/catalog/notifications.js.map +7 -0
  81. package/dist/modules/catalog/subscribers/low-stock-notification.js +38 -0
  82. package/dist/modules/catalog/subscribers/low-stock-notification.js.map +7 -0
  83. package/dist/modules/configs/cli.js +6 -0
  84. package/dist/modules/configs/cli.js.map +2 -2
  85. package/dist/modules/configs/components/CachePanel.js +4 -4
  86. package/dist/modules/configs/components/CachePanel.js.map +2 -2
  87. package/dist/modules/configs/lib/system-status.js +48 -1
  88. package/dist/modules/configs/lib/system-status.js.map +2 -2
  89. package/dist/modules/configs/lib/upgrade-actions.js +18 -0
  90. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  91. package/dist/modules/currencies/backend/currencies/page.js +3 -0
  92. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  93. package/dist/modules/currencies/backend/exchange-rates/page.js +2 -0
  94. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  95. package/dist/modules/customers/backend/customers/companies/page.js +3 -0
  96. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  97. package/dist/modules/customers/backend/customers/deals/page.js +3 -0
  98. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  99. package/dist/modules/customers/backend/customers/people/page.js +3 -0
  100. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  101. package/dist/modules/customers/commands/deals.js +31 -0
  102. package/dist/modules/customers/commands/deals.js.map +2 -2
  103. package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
  104. package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
  105. package/dist/modules/customers/notifications.js +48 -0
  106. package/dist/modules/customers/notifications.js.map +7 -0
  107. package/dist/modules/customers/widgets/dashboard/customer-todos/widget.js +2 -1
  108. package/dist/modules/customers/widgets/dashboard/customer-todos/widget.js.map +2 -2
  109. package/dist/modules/customers/widgets/dashboard/new-customers/widget.js +2 -1
  110. package/dist/modules/customers/widgets/dashboard/new-customers/widget.js.map +2 -2
  111. package/dist/modules/customers/widgets/dashboard/new-deals/widget.js +2 -1
  112. package/dist/modules/customers/widgets/dashboard/new-deals/widget.js.map +2 -2
  113. package/dist/modules/customers/widgets/dashboard/next-interactions/widget.js +2 -1
  114. package/dist/modules/customers/widgets/dashboard/next-interactions/widget.js.map +2 -2
  115. package/dist/modules/dashboards/cli.js +44 -5
  116. package/dist/modules/dashboards/cli.js.map +2 -2
  117. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +16 -11
  118. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +3 -3
  119. package/dist/modules/dashboards/lib/role-widgets.js +58 -0
  120. package/dist/modules/dashboards/lib/role-widgets.js.map +7 -0
  121. package/dist/modules/dashboards/services/widgetDataService.js +139 -3
  122. package/dist/modules/dashboards/services/widgetDataService.js.map +2 -2
  123. package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js +2 -1
  124. package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js.map +2 -2
  125. package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js +2 -1
  126. package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js.map +2 -2
  127. package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js +2 -1
  128. package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js.map +2 -2
  129. package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js +2 -1
  130. package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js.map +2 -2
  131. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js +2 -1
  132. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js.map +2 -2
  133. package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js +2 -1
  134. package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js.map +2 -2
  135. package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js +2 -1
  136. package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js.map +2 -2
  137. package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js +2 -1
  138. package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js.map +2 -2
  139. package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js +2 -1
  140. package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js.map +2 -2
  141. package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js +2 -1
  142. package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js.map +2 -2
  143. package/dist/modules/dictionaries/components/DictionaryTable.js +2 -0
  144. package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
  145. package/dist/modules/directory/api/get/tenants/lookup.js +70 -0
  146. package/dist/modules/directory/api/get/tenants/lookup.js.map +7 -0
  147. package/dist/modules/directory/backend/directory/organizations/page.js +2 -2
  148. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  149. package/dist/modules/directory/backend/directory/tenants/page.js +2 -2
  150. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  151. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +2 -2
  152. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  153. package/dist/modules/entities/components/SystemEntitiesTable.js +1 -1
  154. package/dist/modules/entities/components/SystemEntitiesTable.js.map +2 -2
  155. package/dist/modules/entities/components/UserEntitiesTable.js +2 -2
  156. package/dist/modules/entities/components/UserEntitiesTable.js.map +2 -2
  157. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +3 -3
  158. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
  159. package/dist/modules/feature_toggles/components/OverridesTable.js +1 -1
  160. package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
  161. package/dist/modules/notifications/acl.js +11 -0
  162. package/dist/modules/notifications/acl.js.map +7 -0
  163. package/dist/modules/notifications/api/[id]/action/route.js +74 -0
  164. package/dist/modules/notifications/api/[id]/action/route.js.map +7 -0
  165. package/dist/modules/notifications/api/[id]/dismiss/route.js +15 -0
  166. package/dist/modules/notifications/api/[id]/dismiss/route.js.map +7 -0
  167. package/dist/modules/notifications/api/[id]/read/route.js +15 -0
  168. package/dist/modules/notifications/api/[id]/read/route.js.map +7 -0
  169. package/dist/modules/notifications/api/[id]/restore/route.js +53 -0
  170. package/dist/modules/notifications/api/[id]/restore/route.js.map +7 -0
  171. package/dist/modules/notifications/api/batch/route.js +17 -0
  172. package/dist/modules/notifications/api/batch/route.js.map +7 -0
  173. package/dist/modules/notifications/api/feature/route.js +17 -0
  174. package/dist/modules/notifications/api/feature/route.js.map +7 -0
  175. package/dist/modules/notifications/api/mark-all-read/route.js +35 -0
  176. package/dist/modules/notifications/api/mark-all-read/route.js.map +7 -0
  177. package/dist/modules/notifications/api/openapi.js +76 -0
  178. package/dist/modules/notifications/api/openapi.js.map +7 -0
  179. package/dist/modules/notifications/api/role/route.js +17 -0
  180. package/dist/modules/notifications/api/role/route.js.map +7 -0
  181. package/dist/modules/notifications/api/route.js +85 -0
  182. package/dist/modules/notifications/api/route.js.map +7 -0
  183. package/dist/modules/notifications/api/settings/route.js +155 -0
  184. package/dist/modules/notifications/api/settings/route.js.map +7 -0
  185. package/dist/modules/notifications/api/unread-count/route.js +38 -0
  186. package/dist/modules/notifications/api/unread-count/route.js.map +7 -0
  187. package/dist/modules/notifications/backend/config/notifications/page.js +10 -0
  188. package/dist/modules/notifications/backend/config/notifications/page.js.map +7 -0
  189. package/dist/modules/notifications/backend/config/notifications/page.meta.js +24 -0
  190. package/dist/modules/notifications/backend/config/notifications/page.meta.js.map +7 -0
  191. package/dist/modules/notifications/cli.js +16 -0
  192. package/dist/modules/notifications/cli.js.map +7 -0
  193. package/dist/modules/notifications/data/entities.js +112 -0
  194. package/dist/modules/notifications/data/entities.js.map +7 -0
  195. package/dist/modules/notifications/data/validators.js +98 -0
  196. package/dist/modules/notifications/data/validators.js.map +7 -0
  197. package/dist/modules/notifications/di.js +13 -0
  198. package/dist/modules/notifications/di.js.map +7 -0
  199. package/dist/modules/notifications/emails/NotificationEmail.js +58 -0
  200. package/dist/modules/notifications/emails/NotificationEmail.js.map +7 -0
  201. package/dist/modules/notifications/frontend/NotificationInboxPageClient.js +44 -0
  202. package/dist/modules/notifications/frontend/NotificationInboxPageClient.js.map +7 -0
  203. package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +220 -0
  204. package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +7 -0
  205. package/dist/modules/notifications/index.js +14 -0
  206. package/dist/modules/notifications/index.js.map +7 -0
  207. package/dist/modules/notifications/lib/deliveryConfig.js +107 -0
  208. package/dist/modules/notifications/lib/deliveryConfig.js.map +7 -0
  209. package/dist/modules/notifications/lib/deliveryStrategies.js +14 -0
  210. package/dist/modules/notifications/lib/deliveryStrategies.js.map +7 -0
  211. package/dist/modules/notifications/lib/events.js +12 -0
  212. package/dist/modules/notifications/lib/events.js.map +7 -0
  213. package/dist/modules/notifications/lib/notificationBuilder.js +66 -0
  214. package/dist/modules/notifications/lib/notificationBuilder.js.map +7 -0
  215. package/dist/modules/notifications/lib/notificationFactory.js +54 -0
  216. package/dist/modules/notifications/lib/notificationFactory.js.map +7 -0
  217. package/dist/modules/notifications/lib/notificationMapper.js +34 -0
  218. package/dist/modules/notifications/lib/notificationMapper.js.map +7 -0
  219. package/dist/modules/notifications/lib/notificationRecipients.js +35 -0
  220. package/dist/modules/notifications/lib/notificationRecipients.js.map +7 -0
  221. package/dist/modules/notifications/lib/notificationService.js +279 -0
  222. package/dist/modules/notifications/lib/notificationService.js.map +7 -0
  223. package/dist/modules/notifications/lib/routeHelpers.js +101 -0
  224. package/dist/modules/notifications/lib/routeHelpers.js.map +7 -0
  225. package/dist/modules/notifications/lib/safeHref.js +24 -0
  226. package/dist/modules/notifications/lib/safeHref.js.map +7 -0
  227. package/dist/modules/notifications/migrations/Migration20260123000001.js +70 -0
  228. package/dist/modules/notifications/migrations/Migration20260123000001.js.map +7 -0
  229. package/dist/modules/notifications/migrations/Migration20260126150000.js +37 -0
  230. package/dist/modules/notifications/migrations/Migration20260126150000.js.map +7 -0
  231. package/dist/modules/notifications/migrations/Migration20260129082610.js +13 -0
  232. package/dist/modules/notifications/migrations/Migration20260129082610.js.map +7 -0
  233. package/dist/modules/notifications/subscribers/deliver-notification.js +165 -0
  234. package/dist/modules/notifications/subscribers/deliver-notification.js.map +7 -0
  235. package/dist/modules/notifications/workers/create-notification.worker.js +70 -0
  236. package/dist/modules/notifications/workers/create-notification.worker.js.map +7 -0
  237. package/dist/modules/planner/backend/planner/availability-rulesets/page.js +2 -2
  238. package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
  239. package/dist/modules/query_index/cli.js +63 -7
  240. package/dist/modules/query_index/cli.js.map +2 -2
  241. package/dist/modules/query_index/components/QueryIndexesTable.js +7 -1
  242. package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
  243. package/dist/modules/resources/backend/resources/resource-types/page.js +2 -2
  244. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  245. package/dist/modules/resources/backend/resources/resources/page.js +2 -2
  246. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  247. package/dist/modules/sales/backend/sales/channels/offers/page.js +2 -0
  248. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  249. package/dist/modules/sales/backend/sales/channels/page.js +2 -0
  250. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  251. package/dist/modules/sales/commands/documents.js +53 -0
  252. package/dist/modules/sales/commands/documents.js.map +2 -2
  253. package/dist/modules/sales/commands/payments.js +26 -0
  254. package/dist/modules/sales/commands/payments.js.map +2 -2
  255. package/dist/modules/sales/components/AdjustmentKindSettings.js +2 -2
  256. package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
  257. package/dist/modules/sales/components/PaymentMethodsSettings.js +2 -2
  258. package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
  259. package/dist/modules/sales/components/ShippingMethodsSettings.js +2 -2
  260. package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
  261. package/dist/modules/sales/components/TaxRatesSettings.js +2 -2
  262. package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
  263. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +2 -0
  264. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
  265. package/dist/modules/sales/components/documents/AdjustmentsSection.js +2 -0
  266. package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
  267. package/dist/modules/sales/components/documents/PaymentsSection.js +2 -1
  268. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  269. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +2 -0
  270. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  271. package/dist/modules/sales/notifications.client.js +51 -0
  272. package/dist/modules/sales/notifications.client.js.map +7 -0
  273. package/dist/modules/sales/notifications.js +88 -0
  274. package/dist/modules/sales/notifications.js.map +7 -0
  275. package/dist/modules/sales/subscribers/quote-expiring-notification.js +38 -0
  276. package/dist/modules/sales/subscribers/quote-expiring-notification.js.map +7 -0
  277. package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +137 -0
  278. package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +7 -0
  279. package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +137 -0
  280. package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +7 -0
  281. package/dist/modules/sales/widgets/notifications/index.js +7 -0
  282. package/dist/modules/sales/widgets/notifications/index.js.map +7 -0
  283. package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js +60 -0
  284. package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js.map +7 -0
  285. package/dist/modules/staff/backend/staff/team-members/page.js +1 -1
  286. package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
  287. package/dist/modules/staff/backend/staff/team-roles/page.js +2 -2
  288. package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
  289. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +2 -2
  290. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  291. package/dist/modules/staff/backend/staff/teams/page.js +2 -2
  292. package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
  293. package/dist/modules/staff/commands/leave-requests.js +79 -0
  294. package/dist/modules/staff/commands/leave-requests.js.map +2 -2
  295. package/dist/modules/staff/notifications.js +75 -0
  296. package/dist/modules/staff/notifications.js.map +7 -0
  297. package/dist/modules/workflows/backend/definitions/page.js +5 -0
  298. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  299. package/dist/modules/workflows/backend/instances/page.js +3 -0
  300. package/dist/modules/workflows/backend/instances/page.js.map +2 -2
  301. package/dist/modules/workflows/backend/tasks/page.js +3 -0
  302. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  303. package/dist/modules/workflows/cli.js +12 -12
  304. package/dist/modules/workflows/cli.js.map +2 -2
  305. package/dist/modules/workflows/lib/transition-handler.js +14 -6
  306. package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
  307. package/dist/modules/workflows/notifications.js +28 -0
  308. package/dist/modules/workflows/notifications.js.map +7 -0
  309. package/dist/modules/workflows/subscribers/task-assigned-notification.js +38 -0
  310. package/dist/modules/workflows/subscribers/task-assigned-notification.js.map +7 -0
  311. package/generated/entities/notification/index.ts +27 -0
  312. package/generated/entities.ids.generated.ts +5 -1
  313. package/generated/entity-fields-registry.ts +2 -0
  314. package/package.json +2 -2
  315. package/src/modules/api_docs/frontend/docs/api/page.tsx +3 -2
  316. package/src/modules/api_keys/backend/api-keys/page.tsx +1 -1
  317. package/src/modules/attachments/components/AttachmentLibrary.tsx +4 -0
  318. package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +2 -0
  319. package/src/modules/auth/README.md +1 -1
  320. package/src/modules/auth/__tests__/cli-setup-acl.test.ts +1 -1
  321. package/src/modules/auth/api/__tests__/login.test.ts +2 -0
  322. package/src/modules/auth/api/admin/nav.ts +10 -6
  323. package/src/modules/auth/api/login.ts +26 -7
  324. package/src/modules/auth/api/profile/route.ts +163 -0
  325. package/src/modules/auth/api/reset/confirm.ts +25 -2
  326. package/src/modules/auth/api/reset.ts +23 -0
  327. package/src/modules/auth/api/sidebar/preferences/route.ts +21 -12
  328. package/src/modules/auth/api/users/route.ts +5 -2
  329. package/src/modules/auth/backend/auth/profile/page.meta.ts +9 -0
  330. package/src/modules/auth/backend/auth/profile/page.tsx +174 -0
  331. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +4 -1
  332. package/src/modules/auth/backend/roles/page.tsx +3 -3
  333. package/src/modules/auth/backend/users/[id]/edit/page.tsx +22 -3
  334. package/src/modules/auth/backend/users/create/page.tsx +19 -2
  335. package/src/modules/auth/backend/users/page.tsx +3 -3
  336. package/src/modules/auth/cli.ts +38 -11
  337. package/src/modules/auth/commands/users.ts +73 -2
  338. package/src/modules/auth/data/validators.ts +6 -2
  339. package/src/modules/auth/frontend/login.tsx +134 -5
  340. package/src/modules/auth/frontend/reset/[token]/page.tsx +24 -11
  341. package/src/modules/auth/i18n/de.json +48 -1
  342. package/src/modules/auth/i18n/en.json +48 -1
  343. package/src/modules/auth/i18n/es.json +48 -1
  344. package/src/modules/auth/i18n/pl.json +48 -1
  345. package/src/modules/auth/lib/setup-app.ts +58 -9
  346. package/src/modules/auth/notifications.ts +109 -0
  347. package/src/modules/auth/services/authService.ts +27 -4
  348. package/src/modules/business_rules/api/execute/route.ts +8 -1
  349. package/src/modules/business_rules/backend/rules/page.tsx +4 -0
  350. package/src/modules/business_rules/backend/sets/page.tsx +3 -0
  351. package/src/modules/business_rules/cli.ts +2 -1
  352. package/src/modules/business_rules/i18n/en.json +3 -1
  353. package/src/modules/business_rules/lib/__tests__/rule-engine.test.ts +51 -0
  354. package/src/modules/business_rules/lib/rule-engine.ts +57 -3
  355. package/src/modules/business_rules/notifications.ts +25 -0
  356. package/src/modules/business_rules/subscribers/rule-execution-failed-notification.ts +50 -0
  357. package/src/modules/catalog/components/PriceKindSettings.tsx +2 -0
  358. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +2 -2
  359. package/src/modules/catalog/components/products/ProductsDataTable.tsx +2 -0
  360. package/src/modules/catalog/i18n/en.json +3 -1
  361. package/src/modules/catalog/notifications.ts +25 -0
  362. package/src/modules/catalog/subscribers/low-stock-notification.ts +52 -0
  363. package/src/modules/configs/cli.ts +6 -0
  364. package/src/modules/configs/components/CachePanel.tsx +4 -4
  365. package/src/modules/configs/i18n/en.json +12 -2
  366. package/src/modules/configs/i18n/pl.json +12 -2
  367. package/src/modules/configs/lib/system-status.ts +48 -1
  368. package/src/modules/configs/lib/system-status.types.ts +1 -0
  369. package/src/modules/configs/lib/upgrade-actions.ts +18 -0
  370. package/src/modules/currencies/backend/currencies/page.tsx +3 -0
  371. package/src/modules/currencies/backend/exchange-rates/page.tsx +2 -0
  372. package/src/modules/customers/backend/customers/companies/page.tsx +3 -0
  373. package/src/modules/customers/backend/customers/deals/page.tsx +3 -0
  374. package/src/modules/customers/backend/customers/people/page.tsx +3 -0
  375. package/src/modules/customers/commands/deals.ts +39 -0
  376. package/src/modules/customers/components/CustomerTodosTable.tsx +1 -0
  377. package/src/modules/customers/i18n/en.json +5 -1
  378. package/src/modules/customers/notifications.ts +44 -0
  379. package/src/modules/customers/widgets/dashboard/customer-todos/widget.ts +2 -2
  380. package/src/modules/customers/widgets/dashboard/new-customers/widget.ts +2 -2
  381. package/src/modules/customers/widgets/dashboard/new-deals/widget.ts +2 -2
  382. package/src/modules/customers/widgets/dashboard/next-interactions/widget.ts +2 -2
  383. package/src/modules/dashboards/cli.ts +55 -5
  384. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +22 -11
  385. package/src/modules/dashboards/lib/role-widgets.ts +80 -0
  386. package/src/modules/dashboards/services/widgetDataService.ts +164 -4
  387. package/src/modules/dashboards/widgets/dashboard/aov-kpi/widget.ts +2 -2
  388. package/src/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.ts +2 -2
  389. package/src/modules/dashboards/widgets/dashboard/orders-by-status/widget.ts +2 -2
  390. package/src/modules/dashboards/widgets/dashboard/orders-kpi/widget.ts +2 -2
  391. package/src/modules/dashboards/widgets/dashboard/pipeline-summary/widget.ts +2 -2
  392. package/src/modules/dashboards/widgets/dashboard/revenue-kpi/widget.ts +2 -2
  393. package/src/modules/dashboards/widgets/dashboard/revenue-trend/widget.ts +2 -2
  394. package/src/modules/dashboards/widgets/dashboard/sales-by-region/widget.ts +2 -2
  395. package/src/modules/dashboards/widgets/dashboard/top-customers/widget.ts +2 -2
  396. package/src/modules/dashboards/widgets/dashboard/top-products/widget.ts +2 -2
  397. package/src/modules/dictionaries/components/DictionaryTable.tsx +2 -0
  398. package/src/modules/directory/api/get/tenants/lookup.ts +75 -0
  399. package/src/modules/directory/backend/directory/organizations/page.tsx +2 -2
  400. package/src/modules/directory/backend/directory/tenants/page.tsx +2 -2
  401. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +2 -2
  402. package/src/modules/entities/components/SystemEntitiesTable.tsx +1 -1
  403. package/src/modules/entities/components/UserEntitiesTable.tsx +2 -2
  404. package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +3 -4
  405. package/src/modules/feature_toggles/components/OverridesTable.tsx +1 -1
  406. package/src/modules/notifications/__tests__/deliver-notification.test.ts +195 -0
  407. package/src/modules/notifications/__tests__/deliveryStrategies.test.ts +19 -0
  408. package/src/modules/notifications/__tests__/notificationService.test.ts +208 -0
  409. package/src/modules/notifications/acl.ts +7 -0
  410. package/src/modules/notifications/api/[id]/action/route.ts +75 -0
  411. package/src/modules/notifications/api/[id]/dismiss/route.ts +12 -0
  412. package/src/modules/notifications/api/[id]/read/route.ts +12 -0
  413. package/src/modules/notifications/api/[id]/restore/route.ts +53 -0
  414. package/src/modules/notifications/api/batch/route.ts +14 -0
  415. package/src/modules/notifications/api/feature/route.ts +14 -0
  416. package/src/modules/notifications/api/mark-all-read/route.ts +34 -0
  417. package/src/modules/notifications/api/openapi.ts +76 -0
  418. package/src/modules/notifications/api/role/route.ts +14 -0
  419. package/src/modules/notifications/api/route.ts +92 -0
  420. package/src/modules/notifications/api/settings/route.ts +157 -0
  421. package/src/modules/notifications/api/unread-count/route.ts +38 -0
  422. package/src/modules/notifications/backend/config/notifications/page.meta.ts +22 -0
  423. package/src/modules/notifications/backend/config/notifications/page.tsx +12 -0
  424. package/src/modules/notifications/cli.ts +18 -0
  425. package/src/modules/notifications/data/entities.ts +99 -0
  426. package/src/modules/notifications/data/validators.ts +115 -0
  427. package/src/modules/notifications/di.ts +11 -0
  428. package/src/modules/notifications/emails/NotificationEmail.tsx +98 -0
  429. package/src/modules/notifications/frontend/NotificationInboxPageClient.tsx +42 -0
  430. package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +233 -0
  431. package/src/modules/notifications/i18n/de.json +50 -0
  432. package/src/modules/notifications/i18n/en.json +50 -0
  433. package/src/modules/notifications/i18n/es.json +50 -0
  434. package/src/modules/notifications/i18n/pl.json +50 -0
  435. package/src/modules/notifications/index.ts +12 -0
  436. package/src/modules/notifications/lib/deliveryConfig.ts +153 -0
  437. package/src/modules/notifications/lib/deliveryStrategies.ts +50 -0
  438. package/src/modules/notifications/lib/events.ts +48 -0
  439. package/src/modules/notifications/lib/notificationBuilder.ts +121 -0
  440. package/src/modules/notifications/lib/notificationFactory.ts +76 -0
  441. package/src/modules/notifications/lib/notificationMapper.ts +33 -0
  442. package/src/modules/notifications/lib/notificationRecipients.ts +83 -0
  443. package/src/modules/notifications/lib/notificationService.ts +414 -0
  444. package/src/modules/notifications/lib/routeHelpers.ts +151 -0
  445. package/src/modules/notifications/lib/safeHref.ts +29 -0
  446. package/src/modules/notifications/migrations/.snapshot-open-mercato.json +336 -0
  447. package/src/modules/notifications/migrations/Migration20260123000001.ts +73 -0
  448. package/src/modules/notifications/migrations/Migration20260126150000.ts +39 -0
  449. package/src/modules/notifications/migrations/Migration20260129082610.ts +13 -0
  450. package/src/modules/notifications/subscribers/deliver-notification.ts +204 -0
  451. package/src/modules/notifications/workers/create-notification.worker.ts +122 -0
  452. package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +2 -2
  453. package/src/modules/query_index/cli.ts +82 -13
  454. package/src/modules/query_index/components/QueryIndexesTable.tsx +8 -2
  455. package/src/modules/resources/backend/resources/resource-types/page.tsx +2 -2
  456. package/src/modules/resources/backend/resources/resources/page.tsx +2 -2
  457. package/src/modules/sales/backend/sales/channels/offers/page.tsx +2 -0
  458. package/src/modules/sales/backend/sales/channels/page.tsx +2 -0
  459. package/src/modules/sales/commands/documents.ts +65 -0
  460. package/src/modules/sales/commands/payments.ts +33 -0
  461. package/src/modules/sales/components/AdjustmentKindSettings.tsx +2 -2
  462. package/src/modules/sales/components/PaymentMethodsSettings.tsx +2 -2
  463. package/src/modules/sales/components/ShippingMethodsSettings.tsx +2 -2
  464. package/src/modules/sales/components/TaxRatesSettings.tsx +2 -2
  465. package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +2 -0
  466. package/src/modules/sales/components/documents/AdjustmentsSection.tsx +2 -0
  467. package/src/modules/sales/components/documents/PaymentsSection.tsx +2 -1
  468. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +2 -0
  469. package/src/modules/sales/i18n/de.json +20 -0
  470. package/src/modules/sales/i18n/en.json +25 -1
  471. package/src/modules/sales/i18n/es.json +20 -0
  472. package/src/modules/sales/i18n/pl.json +20 -0
  473. package/src/modules/sales/notifications.client.ts +65 -0
  474. package/src/modules/sales/notifications.ts +82 -0
  475. package/src/modules/sales/subscribers/quote-expiring-notification.ts +53 -0
  476. package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +156 -0
  477. package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +156 -0
  478. package/src/modules/sales/widgets/notifications/index.ts +2 -0
  479. package/src/modules/sales/widgets/notifications/useSalesDocumentTotals.ts +81 -0
  480. package/src/modules/staff/backend/staff/team-members/page.tsx +1 -1
  481. package/src/modules/staff/backend/staff/team-roles/page.tsx +2 -2
  482. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +2 -2
  483. package/src/modules/staff/backend/staff/teams/page.tsx +2 -2
  484. package/src/modules/staff/commands/leave-requests.ts +94 -0
  485. package/src/modules/staff/i18n/de.json +4 -0
  486. package/src/modules/staff/i18n/en.json +9 -1
  487. package/src/modules/staff/i18n/es.json +4 -0
  488. package/src/modules/staff/i18n/pl.json +4 -0
  489. package/src/modules/staff/notifications.ts +71 -0
  490. package/src/modules/workflows/backend/definitions/page.tsx +5 -0
  491. package/src/modules/workflows/backend/instances/page.tsx +4 -1
  492. package/src/modules/workflows/backend/tasks/page.tsx +4 -1
  493. package/src/modules/workflows/cli.ts +12 -12
  494. package/src/modules/workflows/i18n/en.json +3 -1
  495. package/src/modules/workflows/lib/transition-handler.ts +18 -6
  496. package/src/modules/workflows/notifications.ts +25 -0
  497. package/src/modules/workflows/subscribers/task-assigned-notification.ts +53 -0
@@ -4,6 +4,7 @@ import type { EntityManager } from '@mikro-orm/postgresql'
4
4
  import { DashboardRoleWidgets } from '@open-mercato/core/modules/dashboards/data/entities'
5
5
  import { Role } from '@open-mercato/core/modules/auth/data/entities'
6
6
  import { loadAllWidgets } from '@open-mercato/core/modules/dashboards/lib/widgets'
7
+ import { appendWidgetsToRoles, resolveAnalyticsWidgetIds } from '@open-mercato/core/modules/dashboards/lib/role-widgets'
7
8
  import { seedAnalyticsData } from './seed/analytics'
8
9
 
9
10
  type Args = Record<string, string>
@@ -41,15 +42,25 @@ export async function seedDashboardDefaultsForTenant(
41
42
  const widgetMap = new Map(widgets.map((widget) => [widget.metadata.id, widget]))
42
43
  const resolvedWidgetIds = widgetIds && widgetIds.length
43
44
  ? widgetIds.filter((id) => widgetMap.has(id))
44
- : widgets.filter((widget) => widget.metadata.defaultEnabled).map((widget) => widget.metadata.id)
45
+ : null
46
+ const defaultWidgetIds = widgets
47
+ .filter((widget) => widget.metadata.defaultEnabled)
48
+ .map((widget) => widget.metadata.id)
49
+ const allWidgetIds = widgets.map((widget) => widget.metadata.id)
45
50
 
46
- if (!resolvedWidgetIds.length) {
51
+ if (resolvedWidgetIds && resolvedWidgetIds.length === 0) {
47
52
  log('No widgets resolved for dashboard seeding.')
48
53
  return false
49
54
  }
50
55
 
51
56
  await em.transactional(async (tem) => {
52
57
  for (const roleName of roleNames) {
58
+ const isAdminRole = roleName === 'admin' || roleName === 'superadmin'
59
+ const roleWidgetIds = resolvedWidgetIds ?? (isAdminRole ? allWidgetIds : defaultWidgetIds)
60
+ if (!roleWidgetIds.length) {
61
+ log(`No widgets resolved for role "${roleName}".`)
62
+ continue
63
+ }
53
64
  const role = await tem.findOne(Role, { name: roleName })
54
65
  if (!role) {
55
66
  log(`Skipping role "${roleName}" (not found)`)
@@ -62,7 +73,7 @@ export async function seedDashboardDefaultsForTenant(
62
73
  deletedAt: null,
63
74
  })
64
75
  if (existing) {
65
- existing.widgetIdsJson = resolvedWidgetIds
76
+ existing.widgetIdsJson = roleWidgetIds
66
77
  tem.persist(existing)
67
78
  log(`Updated dashboard widgets for role "${roleName}"`)
68
79
  } else {
@@ -70,7 +81,7 @@ export async function seedDashboardDefaultsForTenant(
70
81
  roleId: String(role.id),
71
82
  tenantId,
72
83
  organizationId,
73
- widgetIdsJson: resolvedWidgetIds,
84
+ widgetIdsJson: roleWidgetIds,
74
85
  createdAt: new Date(),
75
86
  updatedAt: null,
76
87
  deletedAt: null,
@@ -120,6 +131,45 @@ const seedDefaults: ModuleCli = {
120
131
  },
121
132
  }
122
133
 
134
+ const enableAnalyticsWidgets: ModuleCli = {
135
+ command: 'enable-analytics-widgets',
136
+ async run(rest) {
137
+ const args = parseArgs(rest)
138
+ const tenantId = args.tenant || args.tenantId || null
139
+ const organizationId = args.organization || args.organizationId || args.org || null
140
+ const roleCsv = args.roles || 'admin,employee'
141
+ if (!tenantId) {
142
+ console.error('Usage: mercato dashboards enable-analytics-widgets --tenant <tenantId> [--org <orgId>] [--roles admin,employee]')
143
+ return
144
+ }
145
+
146
+ const roleNames = roleCsv
147
+ .split(',')
148
+ .map((name) => name.trim())
149
+ .filter(Boolean)
150
+
151
+ if (!roleNames.length) {
152
+ console.log('No roles provided, nothing to update.')
153
+ return
154
+ }
155
+
156
+ const { resolve } = await createRequestContainer()
157
+ const em = resolve('em') as EntityManager
158
+ const widgetIds = await resolveAnalyticsWidgetIds()
159
+
160
+ const updated = await appendWidgetsToRoles(em, {
161
+ tenantId,
162
+ organizationId,
163
+ roleNames,
164
+ widgetIds,
165
+ })
166
+
167
+ if (!updated) {
168
+ console.log('No dashboard role widgets updated.')
169
+ }
170
+ },
171
+ }
172
+
123
173
  const seedAnalytics: ModuleCli = {
124
174
  command: 'seed-analytics',
125
175
  async run(rest) {
@@ -282,4 +332,4 @@ const debugAnalytics: ModuleCli = {
282
332
  },
283
333
  }
284
334
 
285
- export default [seedDefaults, seedAnalytics, debugAnalytics]
335
+ export default [seedDefaults, enableAnalyticsWidgets, seedAnalytics, debugAnalytics]
@@ -44,9 +44,13 @@ type UserProps = BaseProps & {
44
44
 
45
45
  type WidgetVisibilityEditorProps = RoleProps | UserProps
46
46
 
47
+ export type WidgetVisibilityEditorHandle = {
48
+ save: () => Promise<void>
49
+ }
50
+
47
51
  const EMPTY: string[] = []
48
52
 
49
- export function WidgetVisibilityEditor(props: WidgetVisibilityEditorProps) {
53
+ export const WidgetVisibilityEditor = React.forwardRef<WidgetVisibilityEditorHandle, WidgetVisibilityEditorProps>(function WidgetVisibilityEditor(props, ref) {
50
54
  const t = useT()
51
55
  const { kind, targetId, tenantId, organizationId } = props
52
56
  const [catalog, setCatalog] = React.useState<WidgetCatalogItem[]>([])
@@ -60,6 +64,15 @@ export function WidgetVisibilityEditor(props: WidgetVisibilityEditorProps) {
60
64
  const [originalMode, setOriginalMode] = React.useState<'inherit' | 'override'>('inherit')
61
65
  const [effective, setEffective] = React.useState<string[]>(EMPTY)
62
66
 
67
+ const dirty = React.useMemo(() => {
68
+ if (kind === 'user') {
69
+ if (mode !== originalMode) return true
70
+ if (mode === 'override') return selected.join('|') !== original.join('|')
71
+ return false
72
+ }
73
+ return selected.join('|') !== original.join('|')
74
+ }, [kind, mode, original, originalMode, selected])
75
+
63
76
  const loadCatalog = React.useCallback(async () => {
64
77
  const data = await readApiResultOrThrow<{ items?: unknown[] }>(
65
78
  '/api/dashboards/widgets/catalog',
@@ -149,6 +162,9 @@ export function WidgetVisibilityEditor(props: WidgetVisibilityEditorProps) {
149
162
  }, [original, originalMode])
150
163
 
151
164
  const save = React.useCallback(async () => {
165
+ if (loading) return
166
+ if (error && catalog.length === 0) return
167
+ if (!dirty) return
152
168
  setSaving(true)
153
169
  setError(null)
154
170
  try {
@@ -202,16 +218,9 @@ export function WidgetVisibilityEditor(props: WidgetVisibilityEditorProps) {
202
218
  } finally {
203
219
  setSaving(false)
204
220
  }
205
- }, [kind, mode, organizationId, selected, t, targetId, tenantId])
221
+ }, [catalog.length, dirty, error, kind, loading, mode, organizationId, selected, t, targetId, tenantId])
206
222
 
207
- const dirty = React.useMemo(() => {
208
- if (kind === 'user') {
209
- if (mode !== originalMode) return true
210
- if (mode === 'override') return selected.join('|') !== original.join('|')
211
- return false
212
- }
213
- return selected.join('|') !== original.join('|')
214
- }, [kind, mode, original, originalMode, selected])
223
+ React.useImperativeHandle(ref, () => ({ save }), [save])
215
224
 
216
225
  if (loading) {
217
226
  return (
@@ -297,4 +306,6 @@ export function WidgetVisibilityEditor(props: WidgetVisibilityEditorProps) {
297
306
  </div>
298
307
  </div>
299
308
  )
300
- }
309
+ })
310
+
311
+ WidgetVisibilityEditor.displayName = 'WidgetVisibilityEditor'
@@ -0,0 +1,80 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import { Role } from '@open-mercato/core/modules/auth/data/entities'
3
+ import { DashboardRoleWidgets } from '../data/entities'
4
+ import { loadAllWidgets } from './widgets'
5
+
6
+ type RoleWidgetScope = {
7
+ tenantId: string
8
+ organizationId?: string | null
9
+ roleNames: string[]
10
+ widgetIds: string[]
11
+ }
12
+
13
+ async function findRoleByName(
14
+ em: EntityManager,
15
+ roleName: string,
16
+ tenantId: string,
17
+ ): Promise<Role | null> {
18
+ const tenantRole = await em.findOne(Role, { name: roleName, tenantId })
19
+ if (tenantRole) return tenantRole
20
+ return em.findOne(Role, { name: roleName, tenantId: null })
21
+ }
22
+
23
+ export async function resolveAnalyticsWidgetIds(): Promise<string[]> {
24
+ const widgets = await loadAllWidgets()
25
+ return widgets
26
+ .filter((widget) => widget.metadata.category === 'analytics' || widget.metadata.id.startsWith('dashboards.analytics.'))
27
+ .map((widget) => widget.metadata.id)
28
+ }
29
+
30
+ export async function appendWidgetsToRoles(
31
+ em: EntityManager,
32
+ { tenantId, organizationId = null, roleNames, widgetIds }: RoleWidgetScope,
33
+ ): Promise<boolean> {
34
+ const trimmedTenantId = tenantId.trim()
35
+ const widgets = await loadAllWidgets()
36
+ const validWidgetIds = new Set(widgets.map((widget) => widget.metadata.id))
37
+ const resolvedWidgetIds = widgetIds.filter((id) => validWidgetIds.has(id))
38
+ if (!resolvedWidgetIds.length) return false
39
+
40
+ let updated = false
41
+ await em.transactional(async (tem) => {
42
+ for (const roleName of roleNames) {
43
+ const role = await findRoleByName(tem, roleName, trimmedTenantId)
44
+ if (!role) continue
45
+
46
+ const record = await tem.findOne(DashboardRoleWidgets, {
47
+ roleId: String(role.id),
48
+ tenantId: trimmedTenantId,
49
+ organizationId,
50
+ deletedAt: null,
51
+ })
52
+ const roleRecord = record ?? (organizationId
53
+ ? await tem.findOne(DashboardRoleWidgets, {
54
+ roleId: String(role.id),
55
+ tenantId: trimmedTenantId,
56
+ organizationId: null,
57
+ deletedAt: null,
58
+ })
59
+ : null)
60
+ if (!roleRecord) continue
61
+
62
+ const current = Array.isArray(roleRecord.widgetIdsJson) ? roleRecord.widgetIdsJson : []
63
+ const next = [...current]
64
+ const existing = new Set(current)
65
+ for (const widgetId of resolvedWidgetIds) {
66
+ if (existing.has(widgetId)) continue
67
+ existing.add(widgetId)
68
+ next.push(widgetId)
69
+ }
70
+
71
+ if (next.length === current.length) continue
72
+ roleRecord.widgetIdsJson = next
73
+ roleRecord.updatedAt = new Date()
74
+ tem.persist(roleRecord)
75
+ updated = true
76
+ }
77
+ })
78
+
79
+ return updated
80
+ }
@@ -1,6 +1,10 @@
1
1
  import type { EntityManager } from '@mikro-orm/postgresql'
2
2
  import type { CacheStrategy } from '@open-mercato/cache'
3
3
  import { createHash } from 'node:crypto'
4
+ import { decryptWithAesGcm } from '@open-mercato/shared/lib/encryption/aes'
5
+ import { resolveTenantEncryptionService } from '@open-mercato/shared/lib/encryption/customFieldValues'
6
+ import { resolveEntityIdFromMetadata } from '@open-mercato/shared/lib/encryption/entityIds'
7
+ import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
4
8
  import {
5
9
  type DateRangePreset,
6
10
  resolveDateRange,
@@ -17,6 +21,8 @@ import {
17
21
  import type { AnalyticsRegistry } from './analyticsRegistry'
18
22
 
19
23
  const WIDGET_DATA_CACHE_TTL = 120_000
24
+ const WIDGET_DATA_SEGMENT_TTL = 86_400_000
25
+ const WIDGET_DATA_SEGMENT_KEY = 'widget-data:__segment__'
20
26
 
21
27
  const SAFE_IDENTIFIER_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/
22
28
 
@@ -168,6 +174,11 @@ export class WidgetDataService {
168
174
  const tags = this.getCacheTags(request.entityType)
169
175
  try {
170
176
  await this.cache.set(cacheKey, response, { ttl: WIDGET_DATA_CACHE_TTL, tags })
177
+ await this.cache.set(
178
+ WIDGET_DATA_SEGMENT_KEY,
179
+ { updatedAt: response.metadata.fetchedAt },
180
+ { ttl: WIDGET_DATA_SEGMENT_TTL, tags: ['widget-data'] },
181
+ )
171
182
  } catch {
172
183
  }
173
184
  }
@@ -282,6 +293,75 @@ export class WidgetDataService {
282
293
  assertSafeIdentifier(config.idColumn, 'id column')
283
294
  assertSafeIdentifier(config.labelColumn, 'label column')
284
295
 
296
+ const meta = this.resolveEntityMetadata(config.table)
297
+ const idProp = meta ? this.resolveEntityPropertyName(meta, config.idColumn) : null
298
+ const labelProp = meta ? this.resolveEntityPropertyName(meta, config.labelColumn) : null
299
+ const tenantProp = meta
300
+ ? (this.resolveEntityPropertyName(meta, 'tenant_id') ?? this.resolveEntityPropertyName(meta, 'tenantId'))
301
+ : null
302
+ const organizationProp = meta
303
+ ? (this.resolveEntityPropertyName(meta, 'organization_id') ?? this.resolveEntityPropertyName(meta, 'organizationId'))
304
+ : null
305
+ const entityName = meta ? ((meta as any).class ?? meta.className ?? meta.name) : null
306
+
307
+ if (meta && idProp && labelProp && tenantProp && entityName) {
308
+ const where: Record<string, unknown> = {
309
+ [idProp]: { $in: uniqueIds },
310
+ [tenantProp]: this.scope.tenantId,
311
+ }
312
+ if (organizationProp && this.scope.organizationIds && this.scope.organizationIds.length > 0) {
313
+ where[organizationProp] = { $in: this.scope.organizationIds }
314
+ }
315
+
316
+ try {
317
+ const records = await findWithDecryption(
318
+ this.em,
319
+ entityName,
320
+ where,
321
+ { fields: [idProp, labelProp, tenantProp, organizationProp].filter(Boolean) },
322
+ { tenantId: this.scope.tenantId, organizationId: this.resolveOrganizationId() },
323
+ )
324
+
325
+ const encryptionService = resolveTenantEncryptionService(this.em as any)
326
+ const dek = encryptionService?.isEnabled() ? await encryptionService.getDek(this.scope.tenantId) : null
327
+ let hasEncryptedLabels = false
328
+ let hasDecryptedLabels = false
329
+
330
+ const labelMap = new Map<string, string>()
331
+ for (const record of records as Array<Record<string, unknown>>) {
332
+ const id = record[idProp]
333
+ let labelValue = record[labelProp]
334
+ if (typeof labelValue === 'string' && this.isEncryptedPayload(labelValue)) {
335
+ hasEncryptedLabels = true
336
+ if (dek?.key) {
337
+ const decrypted = this.decryptWithDek(labelValue, dek.key)
338
+ if (decrypted !== null) {
339
+ labelValue = decrypted
340
+ hasDecryptedLabels = true
341
+ }
342
+ }
343
+ } else if (labelValue != null && labelValue !== '') {
344
+ hasDecryptedLabels = true
345
+ }
346
+
347
+ if (typeof id === 'string' && labelValue != null && labelValue !== '') {
348
+ labelMap.set(id, String(labelValue))
349
+ }
350
+ }
351
+
352
+ if (labelMap.size > 0 && (!hasEncryptedLabels || hasDecryptedLabels)) {
353
+ return data.map((item) => ({
354
+ ...item,
355
+ groupLabel: typeof item.groupKey === 'string' && labelMap.has(item.groupKey)
356
+ ? labelMap.get(item.groupKey)!
357
+ : undefined,
358
+ }))
359
+ }
360
+ } catch {
361
+ // fall through to SQL resolution
362
+ }
363
+ }
364
+
285
365
  const clauses = [`"${config.idColumn}" = ANY(?::uuid[])`, 'tenant_id = ?']
286
366
  const params: unknown[] = [`{${uniqueIds.join(',')}}`, this.scope.tenantId]
287
367
 
@@ -290,17 +370,43 @@ export class WidgetDataService {
290
370
  params.push(`{${this.scope.organizationIds.join(',')}}`)
291
371
  }
292
372
 
293
- const sql = `SELECT "${config.idColumn}" as id, "${config.labelColumn}" as label FROM "${config.table}" WHERE ${clauses.join(
373
+ const sql = `SELECT "${config.idColumn}" as id, "${config.labelColumn}" as label, tenant_id, organization_id FROM "${config.table}" WHERE ${clauses.join(
294
374
  ' AND ',
295
375
  )}`
296
376
 
297
377
  try {
298
378
  const labelRows = await this.em.getConnection().execute(sql, params)
379
+ const entityId = this.resolveEntityId(meta)
380
+ const encryptionService = resolveTenantEncryptionService(this.em as any)
381
+ const organizationId = this.resolveOrganizationId()
382
+ const dek = encryptionService?.isEnabled() ? await encryptionService.getDek(this.scope.tenantId) : null
299
383
 
300
384
  const labelMap = new Map<string, string>()
301
- for (const row of labelRows as Array<{ id: string; label: string | null }>) {
302
- if (row.id && row.label != null && row.label !== '') {
303
- labelMap.set(row.id, row.label)
385
+ for (const row of labelRows as Array<{ id: string; label: string | null; tenant_id?: string | null; organization_id?: string | null }>) {
386
+ let labelValue = row.label
387
+ if (entityId && encryptionService?.isEnabled() && labelValue != null) {
388
+ const rowOrgId = row.organization_id ?? organizationId ?? null
389
+ const decrypted = await encryptionService.decryptEntityPayload(
390
+ entityId,
391
+ { [config.labelColumn]: labelValue },
392
+ this.scope.tenantId,
393
+ rowOrgId,
394
+ )
395
+ const resolved = decrypted[config.labelColumn]
396
+ if (typeof resolved === 'string' || typeof resolved === 'number') {
397
+ labelValue = String(resolved)
398
+ }
399
+ }
400
+
401
+ if (labelValue && dek?.key && this.isEncryptedPayload(labelValue)) {
402
+ const decrypted = this.decryptWithDek(labelValue, dek.key)
403
+ if (decrypted !== null) {
404
+ labelValue = decrypted
405
+ }
406
+ }
407
+
408
+ if (row.id && labelValue != null && labelValue !== '') {
409
+ labelMap.set(row.id, labelValue)
304
410
  }
305
411
  }
306
412
 
@@ -317,6 +423,60 @@ export class WidgetDataService {
317
423
  }))
318
424
  }
319
425
  }
426
+
427
+ private resolveOrganizationId(): string | null {
428
+ if (!this.scope.organizationIds || this.scope.organizationIds.length !== 1) return null
429
+ return this.scope.organizationIds[0] ?? null
430
+ }
431
+
432
+ private resolveEntityMetadata(tableName: string): Record<string, any> | null {
433
+ const registry = (this.em as any)?.getMetadata?.()
434
+ if (!registry) return null
435
+ const entries =
436
+ (typeof registry.getAll === 'function' && registry.getAll()) ||
437
+ (Array.isArray(registry.metadata) ? registry.metadata : Object.values(registry.metadata ?? {}))
438
+ const metas = Array.isArray(entries) ? entries : Object.values(entries ?? {})
439
+ const match = metas.find((meta: any) => {
440
+ const table = meta?.tableName ?? meta?.collection
441
+ if (typeof table !== 'string') return false
442
+ if (table === tableName) return true
443
+ return table.split('.').pop() === tableName
444
+ })
445
+ return match ?? null
446
+ }
447
+
448
+ private resolveEntityPropertyName(meta: Record<string, any>, columnName: string): string | null {
449
+ const properties = meta?.properties ? Object.values(meta.properties) : []
450
+ for (const prop of properties as Array<Record<string, any>>) {
451
+ const fieldName = prop?.fieldName
452
+ const fieldNames = prop?.fieldNames
453
+ if (typeof fieldName === 'string' && fieldName === columnName) return prop?.name ?? null
454
+ if (Array.isArray(fieldNames) && fieldNames.includes(columnName)) return prop?.name ?? null
455
+ if (prop?.name === columnName) return prop?.name ?? null
456
+ }
457
+ return null
458
+ }
459
+
460
+ private resolveEntityId(meta: Record<string, any> | null): string | null {
461
+ if (!meta) return null
462
+ try {
463
+ return resolveEntityIdFromMetadata(meta as any)
464
+ } catch {
465
+ return null
466
+ }
467
+ }
468
+
469
+ private isEncryptedPayload(value: string): boolean {
470
+ const parts = value.split(':')
471
+ return parts.length === 4 && parts[3] === 'v1'
472
+ }
473
+
474
+ private decryptWithDek(value: string, dek: string): string | null {
475
+ const first = decryptWithAesGcm(value, dek)
476
+ if (first === null) return null
477
+ if (!this.isEncryptedPayload(first)) return first
478
+ return decryptWithAesGcm(first, dek) ?? first
479
+ }
320
480
  }
321
481
 
322
482
  export function createWidgetDataService(
@@ -1,6 +1,6 @@
1
- import type { DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
2
- import AovKpiWidget from './widget.client'
1
+ import { lazyDashboardWidget, type DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
3
2
  import { DEFAULT_SETTINGS, hydrateSettings, type AovKpiSettings } from './config'
3
+ const AovKpiWidget = lazyDashboardWidget(() => import('./widget.client'))
4
4
 
5
5
  const widget: DashboardWidgetModule<AovKpiSettings> = {
6
6
  metadata: {
@@ -1,6 +1,6 @@
1
- import type { DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
2
- import NewCustomersKpiWidget from './widget.client'
1
+ import { lazyDashboardWidget, type DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
3
2
  import { DEFAULT_SETTINGS, hydrateSettings, type NewCustomersKpiSettings } from './config'
3
+ const NewCustomersKpiWidget = lazyDashboardWidget(() => import('./widget.client'))
4
4
 
5
5
  const widget: DashboardWidgetModule<NewCustomersKpiSettings> = {
6
6
  metadata: {
@@ -1,6 +1,6 @@
1
- import type { DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
2
- import OrdersByStatusWidget from './widget.client'
1
+ import { lazyDashboardWidget, type DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
3
2
  import { DEFAULT_SETTINGS, hydrateSettings, type OrdersByStatusSettings } from './config'
3
+ const OrdersByStatusWidget = lazyDashboardWidget(() => import('./widget.client'))
4
4
 
5
5
  const widget: DashboardWidgetModule<OrdersByStatusSettings> = {
6
6
  metadata: {
@@ -1,6 +1,6 @@
1
- import type { DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
2
- import OrdersKpiWidget from './widget.client'
1
+ import { lazyDashboardWidget, type DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
3
2
  import { DEFAULT_SETTINGS, hydrateSettings, type OrdersKpiSettings } from './config'
3
+ const OrdersKpiWidget = lazyDashboardWidget(() => import('./widget.client'))
4
4
 
5
5
  const widget: DashboardWidgetModule<OrdersKpiSettings> = {
6
6
  metadata: {
@@ -1,6 +1,6 @@
1
- import type { DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
2
- import PipelineSummaryWidget from './widget.client'
1
+ import { lazyDashboardWidget, type DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
3
2
  import { DEFAULT_SETTINGS, hydrateSettings, type PipelineSummarySettings } from './config'
3
+ const PipelineSummaryWidget = lazyDashboardWidget(() => import('./widget.client'))
4
4
 
5
5
  const widget: DashboardWidgetModule<PipelineSummarySettings> = {
6
6
  metadata: {
@@ -1,6 +1,6 @@
1
- import type { DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
2
- import RevenueKpiWidget from './widget.client'
1
+ import { lazyDashboardWidget, type DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
3
2
  import { DEFAULT_SETTINGS, hydrateSettings, type RevenueKpiSettings } from './config'
3
+ const RevenueKpiWidget = lazyDashboardWidget(() => import('./widget.client'))
4
4
 
5
5
  const widget: DashboardWidgetModule<RevenueKpiSettings> = {
6
6
  metadata: {
@@ -1,6 +1,6 @@
1
- import type { DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
2
- import RevenueTrendWidget from './widget.client'
1
+ import { lazyDashboardWidget, type DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
3
2
  import { DEFAULT_SETTINGS, hydrateSettings, type RevenueTrendSettings } from './config'
3
+ const RevenueTrendWidget = lazyDashboardWidget(() => import('./widget.client'))
4
4
 
5
5
  const widget: DashboardWidgetModule<RevenueTrendSettings> = {
6
6
  metadata: {
@@ -1,6 +1,6 @@
1
- import type { DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
2
- import SalesByRegionWidget from './widget.client'
1
+ import { lazyDashboardWidget, type DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
3
2
  import { DEFAULT_SETTINGS, hydrateSettings, type SalesByRegionSettings } from './config'
3
+ const SalesByRegionWidget = lazyDashboardWidget(() => import('./widget.client'))
4
4
 
5
5
  const widget: DashboardWidgetModule<SalesByRegionSettings> = {
6
6
  metadata: {
@@ -1,6 +1,6 @@
1
- import type { DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
2
- import TopCustomersWidget from './widget.client'
1
+ import { lazyDashboardWidget, type DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
3
2
  import { DEFAULT_SETTINGS, hydrateSettings, type TopCustomersSettings } from './config'
3
+ const TopCustomersWidget = lazyDashboardWidget(() => import('./widget.client'))
4
4
 
5
5
  const widget: DashboardWidgetModule<TopCustomersSettings> = {
6
6
  metadata: {
@@ -1,6 +1,6 @@
1
- import type { DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
2
- import TopProductsWidget from './widget.client'
1
+ import { lazyDashboardWidget, type DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'
3
2
  import { DEFAULT_SETTINGS, hydrateSettings, type TopProductsSettings } from './config'
3
+ const TopProductsWidget = lazyDashboardWidget(() => import('./widget.client'))
4
4
 
5
5
  const widget: DashboardWidgetModule<TopProductsSettings> = {
6
6
  metadata: {
@@ -171,12 +171,14 @@ export function DictionaryTable({
171
171
  const items: RowActionItem[] = []
172
172
  if (onEdit) {
173
173
  items.push({
174
+ id: 'edit',
174
175
  label: translations.editLabel,
175
176
  onSelect: () => onEdit(entry),
176
177
  })
177
178
  }
178
179
  if (onDelete) {
179
180
  items.push({
181
+ id: 'delete',
180
182
  label: translations.deleteLabel,
181
183
  onSelect: () => onDelete(entry),
182
184
  destructive: true,
@@ -0,0 +1,75 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { z } from 'zod'
3
+ import type { EntityManager } from '@mikro-orm/postgresql'
4
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
5
+ import { Tenant } from '@open-mercato/core/modules/directory/data/entities'
6
+ import type { OpenApiMethodDoc, OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
7
+
8
+ export const metadata = {
9
+ GET: {
10
+ requireAuth: false,
11
+ },
12
+ }
13
+
14
+ const tenantLookupQuerySchema = z.object({
15
+ tenantId: z.string().uuid(),
16
+ })
17
+
18
+ export async function GET(req: Request) {
19
+ const url = new URL(req.url)
20
+ const tenantId = url.searchParams.get('tenantId') || url.searchParams.get('tenant') || ''
21
+ const parsed = tenantLookupQuerySchema.safeParse({ tenantId })
22
+ if (!parsed.success) {
23
+ return NextResponse.json({ ok: false, error: 'Invalid tenant id.' }, { status: 400 })
24
+ }
25
+
26
+ const container = await createRequestContainer()
27
+ const em = (container.resolve('em') as EntityManager)
28
+ const tenant = await em.findOne(Tenant, { id: parsed.data.tenantId, deletedAt: null })
29
+ if (!tenant) {
30
+ return NextResponse.json({ ok: false, error: 'Tenant not found.' }, { status: 404 })
31
+ }
32
+ return NextResponse.json({
33
+ ok: true,
34
+ tenant: { id: String(tenant.id), name: tenant.name },
35
+ })
36
+ }
37
+
38
+ const lookupTag = 'Directory'
39
+
40
+ const tenantLookupSuccessSchema = z.object({
41
+ ok: z.literal(true),
42
+ tenant: z.object({
43
+ id: z.string().uuid(),
44
+ name: z.string(),
45
+ }),
46
+ })
47
+
48
+ const tenantLookupErrorSchema = z.object({
49
+ ok: z.literal(false),
50
+ error: z.string(),
51
+ })
52
+
53
+ const tenantLookupDoc: OpenApiMethodDoc = {
54
+ summary: 'Public tenant lookup',
55
+ description: 'Resolves tenant metadata for login/activation flows.',
56
+ tags: [lookupTag],
57
+ query: tenantLookupQuerySchema,
58
+ responses: [
59
+ { status: 200, description: 'Tenant resolved.', schema: tenantLookupSuccessSchema },
60
+ ],
61
+ errors: [
62
+ { status: 400, description: 'Invalid tenant id', schema: tenantLookupErrorSchema },
63
+ { status: 404, description: 'Tenant not found', schema: tenantLookupErrorSchema },
64
+ ],
65
+ }
66
+
67
+ export const openApi: OpenApiRouteDoc = {
68
+ tag: lookupTag,
69
+ summary: 'Public tenant lookup',
70
+ methods: {
71
+ GET: tenantLookupDoc,
72
+ },
73
+ }
74
+
75
+ export default GET
@@ -235,8 +235,8 @@ export default function DirectoryOrganizationsPage() {
235
235
  canManage ? (
236
236
  <RowActions
237
237
  items={[
238
- { label: t('directory.organizations.list.actions.edit', 'Edit'), href: `/backend/directory/organizations/${row.id}/edit` },
239
- { label: t('directory.organizations.list.actions.delete', 'Delete'), destructive: true, onSelect: () => handleDelete(row) },
238
+ { id: 'edit', label: t('directory.organizations.list.actions.edit', 'Edit'), href: `/backend/directory/organizations/${row.id}/edit` },
239
+ { id: 'delete', label: t('directory.organizations.list.actions.delete', 'Delete'), destructive: true, onSelect: () => handleDelete(row) },
240
240
  ]}
241
241
  />
242
242
  ) : null