@open-mercato/core 0.4.2-canary-f075c3eb92 → 0.4.2-canary-8a04af8836

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 (507) 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 +46 -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 +138 -306
  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/setup.js +15 -0
  124. package/dist/modules/dashboards/setup.js.map +2 -2
  125. package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js +2 -1
  126. package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js.map +2 -2
  127. package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js +2 -1
  128. package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js.map +2 -2
  129. package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js +2 -1
  130. package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js.map +2 -2
  131. package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js +2 -1
  132. package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js.map +2 -2
  133. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js +2 -1
  134. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js.map +2 -2
  135. package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js +2 -1
  136. package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js.map +2 -2
  137. package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js +2 -1
  138. package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js.map +2 -2
  139. package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js +2 -1
  140. package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js.map +2 -2
  141. package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js +2 -1
  142. package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js.map +2 -2
  143. package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js +2 -1
  144. package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js.map +2 -2
  145. package/dist/modules/dictionaries/components/DictionaryTable.js +2 -0
  146. package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
  147. package/dist/modules/directory/api/get/tenants/lookup.js +70 -0
  148. package/dist/modules/directory/api/get/tenants/lookup.js.map +7 -0
  149. package/dist/modules/directory/backend/directory/organizations/page.js +2 -2
  150. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  151. package/dist/modules/directory/backend/directory/tenants/page.js +2 -2
  152. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  153. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +2 -2
  154. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  155. package/dist/modules/entities/components/SystemEntitiesTable.js +1 -1
  156. package/dist/modules/entities/components/SystemEntitiesTable.js.map +2 -2
  157. package/dist/modules/entities/components/UserEntitiesTable.js +2 -2
  158. package/dist/modules/entities/components/UserEntitiesTable.js.map +2 -2
  159. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +3 -3
  160. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
  161. package/dist/modules/feature_toggles/components/OverridesTable.js +1 -1
  162. package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
  163. package/dist/modules/notifications/acl.js +11 -0
  164. package/dist/modules/notifications/acl.js.map +7 -0
  165. package/dist/modules/notifications/api/[id]/action/route.js +74 -0
  166. package/dist/modules/notifications/api/[id]/action/route.js.map +7 -0
  167. package/dist/modules/notifications/api/[id]/dismiss/route.js +15 -0
  168. package/dist/modules/notifications/api/[id]/dismiss/route.js.map +7 -0
  169. package/dist/modules/notifications/api/[id]/read/route.js +15 -0
  170. package/dist/modules/notifications/api/[id]/read/route.js.map +7 -0
  171. package/dist/modules/notifications/api/[id]/restore/route.js +53 -0
  172. package/dist/modules/notifications/api/[id]/restore/route.js.map +7 -0
  173. package/dist/modules/notifications/api/batch/route.js +17 -0
  174. package/dist/modules/notifications/api/batch/route.js.map +7 -0
  175. package/dist/modules/notifications/api/feature/route.js +17 -0
  176. package/dist/modules/notifications/api/feature/route.js.map +7 -0
  177. package/dist/modules/notifications/api/mark-all-read/route.js +35 -0
  178. package/dist/modules/notifications/api/mark-all-read/route.js.map +7 -0
  179. package/dist/modules/notifications/api/openapi.js +76 -0
  180. package/dist/modules/notifications/api/openapi.js.map +7 -0
  181. package/dist/modules/notifications/api/role/route.js +17 -0
  182. package/dist/modules/notifications/api/role/route.js.map +7 -0
  183. package/dist/modules/notifications/api/route.js +85 -0
  184. package/dist/modules/notifications/api/route.js.map +7 -0
  185. package/dist/modules/notifications/api/settings/route.js +155 -0
  186. package/dist/modules/notifications/api/settings/route.js.map +7 -0
  187. package/dist/modules/notifications/api/unread-count/route.js +38 -0
  188. package/dist/modules/notifications/api/unread-count/route.js.map +7 -0
  189. package/dist/modules/notifications/backend/config/notifications/page.js +10 -0
  190. package/dist/modules/notifications/backend/config/notifications/page.js.map +7 -0
  191. package/dist/modules/notifications/backend/config/notifications/page.meta.js +24 -0
  192. package/dist/modules/notifications/backend/config/notifications/page.meta.js.map +7 -0
  193. package/dist/modules/notifications/cli.js +16 -0
  194. package/dist/modules/notifications/cli.js.map +7 -0
  195. package/dist/modules/notifications/data/entities.js +112 -0
  196. package/dist/modules/notifications/data/entities.js.map +7 -0
  197. package/dist/modules/notifications/data/validators.js +98 -0
  198. package/dist/modules/notifications/data/validators.js.map +7 -0
  199. package/dist/modules/notifications/di.js +13 -0
  200. package/dist/modules/notifications/di.js.map +7 -0
  201. package/dist/modules/notifications/emails/NotificationEmail.js +58 -0
  202. package/dist/modules/notifications/emails/NotificationEmail.js.map +7 -0
  203. package/dist/modules/notifications/frontend/NotificationInboxPageClient.js +44 -0
  204. package/dist/modules/notifications/frontend/NotificationInboxPageClient.js.map +7 -0
  205. package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +220 -0
  206. package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +7 -0
  207. package/dist/modules/notifications/index.js +14 -0
  208. package/dist/modules/notifications/index.js.map +7 -0
  209. package/dist/modules/notifications/lib/deliveryConfig.js +107 -0
  210. package/dist/modules/notifications/lib/deliveryConfig.js.map +7 -0
  211. package/dist/modules/notifications/lib/deliveryStrategies.js +14 -0
  212. package/dist/modules/notifications/lib/deliveryStrategies.js.map +7 -0
  213. package/dist/modules/notifications/lib/events.js +12 -0
  214. package/dist/modules/notifications/lib/events.js.map +7 -0
  215. package/dist/modules/notifications/lib/notificationBuilder.js +66 -0
  216. package/dist/modules/notifications/lib/notificationBuilder.js.map +7 -0
  217. package/dist/modules/notifications/lib/notificationFactory.js +54 -0
  218. package/dist/modules/notifications/lib/notificationFactory.js.map +7 -0
  219. package/dist/modules/notifications/lib/notificationMapper.js +34 -0
  220. package/dist/modules/notifications/lib/notificationMapper.js.map +7 -0
  221. package/dist/modules/notifications/lib/notificationRecipients.js +35 -0
  222. package/dist/modules/notifications/lib/notificationRecipients.js.map +7 -0
  223. package/dist/modules/notifications/lib/notificationService.js +279 -0
  224. package/dist/modules/notifications/lib/notificationService.js.map +7 -0
  225. package/dist/modules/notifications/lib/routeHelpers.js +101 -0
  226. package/dist/modules/notifications/lib/routeHelpers.js.map +7 -0
  227. package/dist/modules/notifications/lib/safeHref.js +24 -0
  228. package/dist/modules/notifications/lib/safeHref.js.map +7 -0
  229. package/dist/modules/notifications/migrations/Migration20260123000001.js +70 -0
  230. package/dist/modules/notifications/migrations/Migration20260123000001.js.map +7 -0
  231. package/dist/modules/notifications/migrations/Migration20260126150000.js +37 -0
  232. package/dist/modules/notifications/migrations/Migration20260126150000.js.map +7 -0
  233. package/dist/modules/notifications/migrations/Migration20260129082610.js +13 -0
  234. package/dist/modules/notifications/migrations/Migration20260129082610.js.map +7 -0
  235. package/dist/modules/notifications/subscribers/deliver-notification.js +165 -0
  236. package/dist/modules/notifications/subscribers/deliver-notification.js.map +7 -0
  237. package/dist/modules/notifications/workers/create-notification.worker.js +70 -0
  238. package/dist/modules/notifications/workers/create-notification.worker.js.map +7 -0
  239. package/dist/modules/planner/backend/planner/availability-rulesets/page.js +2 -2
  240. package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
  241. package/dist/modules/query_index/cli.js +63 -7
  242. package/dist/modules/query_index/cli.js.map +2 -2
  243. package/dist/modules/query_index/components/QueryIndexesTable.js +7 -1
  244. package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
  245. package/dist/modules/resources/backend/resources/resource-types/page.js +2 -2
  246. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  247. package/dist/modules/resources/backend/resources/resources/page.js +2 -2
  248. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  249. package/dist/modules/sales/backend/sales/channels/offers/page.js +2 -0
  250. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  251. package/dist/modules/sales/backend/sales/channels/page.js +2 -0
  252. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  253. package/dist/modules/sales/cli.js +2 -42
  254. package/dist/modules/sales/cli.js.map +2 -2
  255. package/dist/modules/sales/commands/documents.js +53 -0
  256. package/dist/modules/sales/commands/documents.js.map +2 -2
  257. package/dist/modules/sales/commands/payments.js +26 -0
  258. package/dist/modules/sales/commands/payments.js.map +2 -2
  259. package/dist/modules/sales/components/AdjustmentKindSettings.js +2 -2
  260. package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
  261. package/dist/modules/sales/components/PaymentMethodsSettings.js +2 -2
  262. package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
  263. package/dist/modules/sales/components/ShippingMethodsSettings.js +2 -2
  264. package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
  265. package/dist/modules/sales/components/TaxRatesSettings.js +2 -2
  266. package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
  267. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +2 -0
  268. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
  269. package/dist/modules/sales/components/documents/AdjustmentsSection.js +2 -0
  270. package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
  271. package/dist/modules/sales/components/documents/PaymentsSection.js +2 -1
  272. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  273. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +2 -0
  274. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  275. package/dist/modules/sales/lib/seeds.js +48 -0
  276. package/dist/modules/sales/lib/seeds.js.map +7 -0
  277. package/dist/modules/sales/notifications.client.js +51 -0
  278. package/dist/modules/sales/notifications.client.js.map +7 -0
  279. package/dist/modules/sales/notifications.js +88 -0
  280. package/dist/modules/sales/notifications.js.map +7 -0
  281. package/dist/modules/sales/subscribers/quote-expiring-notification.js +38 -0
  282. package/dist/modules/sales/subscribers/quote-expiring-notification.js.map +7 -0
  283. package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +137 -0
  284. package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +7 -0
  285. package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +137 -0
  286. package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +7 -0
  287. package/dist/modules/sales/widgets/notifications/index.js +7 -0
  288. package/dist/modules/sales/widgets/notifications/index.js.map +7 -0
  289. package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js +60 -0
  290. package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js.map +7 -0
  291. package/dist/modules/staff/backend/staff/team-members/page.js +1 -1
  292. package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
  293. package/dist/modules/staff/backend/staff/team-roles/page.js +2 -2
  294. package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
  295. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +2 -2
  296. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  297. package/dist/modules/staff/backend/staff/teams/page.js +2 -2
  298. package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
  299. package/dist/modules/staff/commands/leave-requests.js +79 -0
  300. package/dist/modules/staff/commands/leave-requests.js.map +2 -2
  301. package/dist/modules/staff/notifications.js +75 -0
  302. package/dist/modules/staff/notifications.js.map +7 -0
  303. package/dist/modules/workflows/backend/definitions/page.js +5 -0
  304. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  305. package/dist/modules/workflows/backend/instances/page.js +3 -0
  306. package/dist/modules/workflows/backend/instances/page.js.map +2 -2
  307. package/dist/modules/workflows/backend/tasks/page.js +3 -0
  308. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  309. package/dist/modules/workflows/cli.js +12 -12
  310. package/dist/modules/workflows/cli.js.map +2 -2
  311. package/dist/modules/workflows/lib/transition-handler.js +14 -6
  312. package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
  313. package/dist/modules/workflows/notifications.js +28 -0
  314. package/dist/modules/workflows/notifications.js.map +7 -0
  315. package/dist/modules/workflows/subscribers/task-assigned-notification.js +38 -0
  316. package/dist/modules/workflows/subscribers/task-assigned-notification.js.map +7 -0
  317. package/generated/entities/notification/index.ts +27 -0
  318. package/generated/entities.ids.generated.ts +5 -1
  319. package/generated/entity-fields-registry.ts +2 -0
  320. package/package.json +2 -2
  321. package/src/modules/api_docs/frontend/docs/api/page.tsx +3 -2
  322. package/src/modules/api_keys/backend/api-keys/page.tsx +1 -1
  323. package/src/modules/attachments/components/AttachmentLibrary.tsx +4 -0
  324. package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +2 -0
  325. package/src/modules/auth/README.md +1 -1
  326. package/src/modules/auth/__tests__/cli-setup-acl.test.ts +1 -1
  327. package/src/modules/auth/api/__tests__/login.test.ts +2 -0
  328. package/src/modules/auth/api/admin/nav.ts +10 -6
  329. package/src/modules/auth/api/login.ts +26 -7
  330. package/src/modules/auth/api/profile/route.ts +163 -0
  331. package/src/modules/auth/api/reset/confirm.ts +25 -2
  332. package/src/modules/auth/api/reset.ts +23 -0
  333. package/src/modules/auth/api/sidebar/preferences/route.ts +21 -12
  334. package/src/modules/auth/api/users/route.ts +5 -2
  335. package/src/modules/auth/backend/auth/profile/page.meta.ts +9 -0
  336. package/src/modules/auth/backend/auth/profile/page.tsx +174 -0
  337. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +4 -1
  338. package/src/modules/auth/backend/roles/page.tsx +3 -3
  339. package/src/modules/auth/backend/users/[id]/edit/page.tsx +22 -3
  340. package/src/modules/auth/backend/users/create/page.tsx +19 -2
  341. package/src/modules/auth/backend/users/page.tsx +3 -3
  342. package/src/modules/auth/cli.ts +38 -11
  343. package/src/modules/auth/commands/users.ts +73 -2
  344. package/src/modules/auth/data/validators.ts +6 -2
  345. package/src/modules/auth/frontend/login.tsx +134 -5
  346. package/src/modules/auth/frontend/reset/[token]/page.tsx +24 -11
  347. package/src/modules/auth/i18n/de.json +48 -1
  348. package/src/modules/auth/i18n/en.json +48 -1
  349. package/src/modules/auth/i18n/es.json +48 -1
  350. package/src/modules/auth/i18n/pl.json +48 -1
  351. package/src/modules/auth/lib/setup-app.ts +63 -9
  352. package/src/modules/auth/notifications.ts +109 -0
  353. package/src/modules/auth/services/authService.ts +27 -4
  354. package/src/modules/business_rules/api/execute/route.ts +8 -1
  355. package/src/modules/business_rules/backend/rules/page.tsx +4 -0
  356. package/src/modules/business_rules/backend/sets/page.tsx +3 -0
  357. package/src/modules/business_rules/cli.ts +2 -1
  358. package/src/modules/business_rules/i18n/en.json +3 -1
  359. package/src/modules/business_rules/lib/__tests__/rule-engine.test.ts +51 -0
  360. package/src/modules/business_rules/lib/rule-engine.ts +57 -3
  361. package/src/modules/business_rules/notifications.ts +25 -0
  362. package/src/modules/business_rules/subscribers/rule-execution-failed-notification.ts +50 -0
  363. package/src/modules/catalog/components/PriceKindSettings.tsx +2 -0
  364. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +2 -2
  365. package/src/modules/catalog/components/products/ProductsDataTable.tsx +2 -0
  366. package/src/modules/catalog/i18n/en.json +3 -1
  367. package/src/modules/catalog/notifications.ts +25 -0
  368. package/src/modules/catalog/subscribers/low-stock-notification.ts +52 -0
  369. package/src/modules/configs/cli.ts +6 -0
  370. package/src/modules/configs/components/CachePanel.tsx +4 -4
  371. package/src/modules/configs/i18n/en.json +12 -2
  372. package/src/modules/configs/i18n/pl.json +12 -2
  373. package/src/modules/configs/lib/system-status.ts +48 -1
  374. package/src/modules/configs/lib/system-status.types.ts +1 -0
  375. package/src/modules/configs/lib/upgrade-actions.ts +157 -351
  376. package/src/modules/currencies/backend/currencies/page.tsx +3 -0
  377. package/src/modules/currencies/backend/exchange-rates/page.tsx +2 -0
  378. package/src/modules/customers/backend/customers/companies/page.tsx +3 -0
  379. package/src/modules/customers/backend/customers/deals/page.tsx +3 -0
  380. package/src/modules/customers/backend/customers/people/page.tsx +3 -0
  381. package/src/modules/customers/commands/deals.ts +39 -0
  382. package/src/modules/customers/components/CustomerTodosTable.tsx +1 -0
  383. package/src/modules/customers/i18n/en.json +5 -1
  384. package/src/modules/customers/notifications.ts +44 -0
  385. package/src/modules/customers/widgets/dashboard/customer-todos/widget.ts +2 -2
  386. package/src/modules/customers/widgets/dashboard/new-customers/widget.ts +2 -2
  387. package/src/modules/customers/widgets/dashboard/new-deals/widget.ts +2 -2
  388. package/src/modules/customers/widgets/dashboard/next-interactions/widget.ts +2 -2
  389. package/src/modules/dashboards/cli.ts +55 -5
  390. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +22 -11
  391. package/src/modules/dashboards/lib/role-widgets.ts +80 -0
  392. package/src/modules/dashboards/services/widgetDataService.ts +164 -4
  393. package/src/modules/dashboards/setup.ts +16 -0
  394. package/src/modules/dashboards/widgets/dashboard/aov-kpi/widget.ts +2 -2
  395. package/src/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.ts +2 -2
  396. package/src/modules/dashboards/widgets/dashboard/orders-by-status/widget.ts +2 -2
  397. package/src/modules/dashboards/widgets/dashboard/orders-kpi/widget.ts +2 -2
  398. package/src/modules/dashboards/widgets/dashboard/pipeline-summary/widget.ts +2 -2
  399. package/src/modules/dashboards/widgets/dashboard/revenue-kpi/widget.ts +2 -2
  400. package/src/modules/dashboards/widgets/dashboard/revenue-trend/widget.ts +2 -2
  401. package/src/modules/dashboards/widgets/dashboard/sales-by-region/widget.ts +2 -2
  402. package/src/modules/dashboards/widgets/dashboard/top-customers/widget.ts +2 -2
  403. package/src/modules/dashboards/widgets/dashboard/top-products/widget.ts +2 -2
  404. package/src/modules/dictionaries/components/DictionaryTable.tsx +2 -0
  405. package/src/modules/directory/api/get/tenants/lookup.ts +75 -0
  406. package/src/modules/directory/backend/directory/organizations/page.tsx +2 -2
  407. package/src/modules/directory/backend/directory/tenants/page.tsx +2 -2
  408. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +2 -2
  409. package/src/modules/entities/components/SystemEntitiesTable.tsx +1 -1
  410. package/src/modules/entities/components/UserEntitiesTable.tsx +2 -2
  411. package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +3 -4
  412. package/src/modules/feature_toggles/components/OverridesTable.tsx +1 -1
  413. package/src/modules/notifications/__tests__/deliver-notification.test.ts +195 -0
  414. package/src/modules/notifications/__tests__/deliveryStrategies.test.ts +19 -0
  415. package/src/modules/notifications/__tests__/notificationService.test.ts +208 -0
  416. package/src/modules/notifications/acl.ts +7 -0
  417. package/src/modules/notifications/api/[id]/action/route.ts +75 -0
  418. package/src/modules/notifications/api/[id]/dismiss/route.ts +12 -0
  419. package/src/modules/notifications/api/[id]/read/route.ts +12 -0
  420. package/src/modules/notifications/api/[id]/restore/route.ts +53 -0
  421. package/src/modules/notifications/api/batch/route.ts +14 -0
  422. package/src/modules/notifications/api/feature/route.ts +14 -0
  423. package/src/modules/notifications/api/mark-all-read/route.ts +34 -0
  424. package/src/modules/notifications/api/openapi.ts +76 -0
  425. package/src/modules/notifications/api/role/route.ts +14 -0
  426. package/src/modules/notifications/api/route.ts +92 -0
  427. package/src/modules/notifications/api/settings/route.ts +157 -0
  428. package/src/modules/notifications/api/unread-count/route.ts +38 -0
  429. package/src/modules/notifications/backend/config/notifications/page.meta.ts +22 -0
  430. package/src/modules/notifications/backend/config/notifications/page.tsx +12 -0
  431. package/src/modules/notifications/cli.ts +18 -0
  432. package/src/modules/notifications/data/entities.ts +99 -0
  433. package/src/modules/notifications/data/validators.ts +115 -0
  434. package/src/modules/notifications/di.ts +11 -0
  435. package/src/modules/notifications/emails/NotificationEmail.tsx +98 -0
  436. package/src/modules/notifications/frontend/NotificationInboxPageClient.tsx +42 -0
  437. package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +233 -0
  438. package/src/modules/notifications/i18n/de.json +50 -0
  439. package/src/modules/notifications/i18n/en.json +50 -0
  440. package/src/modules/notifications/i18n/es.json +50 -0
  441. package/src/modules/notifications/i18n/pl.json +50 -0
  442. package/src/modules/notifications/index.ts +12 -0
  443. package/src/modules/notifications/lib/deliveryConfig.ts +153 -0
  444. package/src/modules/notifications/lib/deliveryStrategies.ts +50 -0
  445. package/src/modules/notifications/lib/events.ts +48 -0
  446. package/src/modules/notifications/lib/notificationBuilder.ts +121 -0
  447. package/src/modules/notifications/lib/notificationFactory.ts +76 -0
  448. package/src/modules/notifications/lib/notificationMapper.ts +33 -0
  449. package/src/modules/notifications/lib/notificationRecipients.ts +83 -0
  450. package/src/modules/notifications/lib/notificationService.ts +414 -0
  451. package/src/modules/notifications/lib/routeHelpers.ts +151 -0
  452. package/src/modules/notifications/lib/safeHref.ts +29 -0
  453. package/src/modules/notifications/migrations/.snapshot-open-mercato.json +336 -0
  454. package/src/modules/notifications/migrations/Migration20260123000001.ts +73 -0
  455. package/src/modules/notifications/migrations/Migration20260126150000.ts +39 -0
  456. package/src/modules/notifications/migrations/Migration20260129082610.ts +13 -0
  457. package/src/modules/notifications/subscribers/deliver-notification.ts +204 -0
  458. package/src/modules/notifications/workers/create-notification.worker.ts +122 -0
  459. package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +2 -2
  460. package/src/modules/query_index/cli.ts +82 -13
  461. package/src/modules/query_index/components/QueryIndexesTable.tsx +8 -2
  462. package/src/modules/resources/backend/resources/resource-types/page.tsx +2 -2
  463. package/src/modules/resources/backend/resources/resources/page.tsx +2 -2
  464. package/src/modules/sales/backend/sales/channels/offers/page.tsx +2 -0
  465. package/src/modules/sales/backend/sales/channels/page.tsx +2 -0
  466. package/src/modules/sales/cli.ts +2 -43
  467. package/src/modules/sales/commands/documents.ts +65 -0
  468. package/src/modules/sales/commands/payments.ts +33 -0
  469. package/src/modules/sales/components/AdjustmentKindSettings.tsx +2 -2
  470. package/src/modules/sales/components/PaymentMethodsSettings.tsx +2 -2
  471. package/src/modules/sales/components/ShippingMethodsSettings.tsx +2 -2
  472. package/src/modules/sales/components/TaxRatesSettings.tsx +2 -2
  473. package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +2 -0
  474. package/src/modules/sales/components/documents/AdjustmentsSection.tsx +2 -0
  475. package/src/modules/sales/components/documents/PaymentsSection.tsx +2 -1
  476. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +2 -0
  477. package/src/modules/sales/i18n/de.json +20 -0
  478. package/src/modules/sales/i18n/en.json +25 -1
  479. package/src/modules/sales/i18n/es.json +20 -0
  480. package/src/modules/sales/i18n/pl.json +20 -0
  481. package/src/modules/sales/lib/seeds.ts +53 -0
  482. package/src/modules/sales/notifications.client.ts +65 -0
  483. package/src/modules/sales/notifications.ts +82 -0
  484. package/src/modules/sales/subscribers/quote-expiring-notification.ts +53 -0
  485. package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +156 -0
  486. package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +156 -0
  487. package/src/modules/sales/widgets/notifications/index.ts +2 -0
  488. package/src/modules/sales/widgets/notifications/useSalesDocumentTotals.ts +81 -0
  489. package/src/modules/staff/backend/staff/team-members/page.tsx +1 -1
  490. package/src/modules/staff/backend/staff/team-roles/page.tsx +2 -2
  491. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +2 -2
  492. package/src/modules/staff/backend/staff/teams/page.tsx +2 -2
  493. package/src/modules/staff/commands/leave-requests.ts +94 -0
  494. package/src/modules/staff/i18n/de.json +6 -0
  495. package/src/modules/staff/i18n/en.json +9 -1
  496. package/src/modules/staff/i18n/es.json +6 -0
  497. package/src/modules/staff/i18n/pl.json +6 -0
  498. package/src/modules/staff/notifications.ts +71 -0
  499. package/src/modules/workflows/backend/definitions/page.tsx +5 -0
  500. package/src/modules/workflows/backend/instances/page.tsx +4 -1
  501. package/src/modules/workflows/backend/tasks/page.tsx +4 -1
  502. package/src/modules/workflows/cli.ts +12 -12
  503. package/src/modules/workflows/i18n/en.json +3 -1
  504. package/src/modules/workflows/lib/__tests__/transition-handler.test.ts +6 -3
  505. package/src/modules/workflows/lib/transition-handler.ts +18 -6
  506. package/src/modules/workflows/notifications.ts +25 -0
  507. package/src/modules/workflows/subscribers/task-assigned-notification.ts +53 -0
@@ -11,6 +11,7 @@ import { TenantSelect } from '@open-mercato/core/modules/directory/components/Te
11
11
  import { fetchRoleOptions } from '@open-mercato/core/modules/auth/backend/users/roleOptions'
12
12
  import { Spinner } from '@open-mercato/ui/primitives/spinner'
13
13
  import { useT } from '@open-mercato/shared/lib/i18n/context'
14
+ import { formatPasswordRequirements, getPasswordPolicy } from '@open-mercato/shared/lib/auth/passwordPolicy'
14
15
 
15
16
  type CreateUserFormValues = {
16
17
  email: string
@@ -84,6 +85,16 @@ export default function CreateUserPage() {
84
85
  const [selectedWidgets, setSelectedWidgets] = React.useState<string[]>([])
85
86
  const [selectedTenantId, setSelectedTenantId] = React.useState<string | null>(null)
86
87
  const [actorIsSuperAdmin, setActorIsSuperAdmin] = React.useState(false)
88
+ const passwordPolicy = React.useMemo(() => getPasswordPolicy(), [])
89
+ const passwordRequirements = React.useMemo(
90
+ () => formatPasswordRequirements(passwordPolicy, t),
91
+ [passwordPolicy, t],
92
+ )
93
+ const passwordDescription = React.useMemo(() => (
94
+ passwordRequirements
95
+ ? t('auth.password.requirements.help', 'Password requirements: {requirements}', { requirements: passwordRequirements })
96
+ : undefined
97
+ ), [passwordRequirements, t])
87
98
 
88
99
  React.useEffect(() => {
89
100
  let cancelled = false
@@ -156,7 +167,13 @@ export default function CreateUserPage() {
156
167
  const fields: CrudField[] = React.useMemo(() => {
157
168
  const items: CrudField[] = [
158
169
  { id: 'email', label: t('auth.users.form.field.email', 'Email'), type: 'text', required: true },
159
- { id: 'password', label: t('auth.users.form.field.password', 'Password'), type: 'text', required: true },
170
+ {
171
+ id: 'password',
172
+ label: t('auth.users.form.field.password', 'Password'),
173
+ type: 'text',
174
+ required: true,
175
+ description: passwordDescription,
176
+ },
160
177
  ]
161
178
  if (actorIsSuperAdmin) {
162
179
  items.push({
@@ -203,7 +220,7 @@ export default function CreateUserPage() {
203
220
  })
204
221
  items.push({ id: 'roles', label: t('auth.users.form.field.roles', 'Roles'), type: 'tags', loadOptions: loadRoleOptions })
205
222
  return items
206
- }, [actorIsSuperAdmin, loadRoleOptions, selectedTenantId, t])
223
+ }, [actorIsSuperAdmin, loadRoleOptions, passwordDescription, selectedTenantId, t])
207
224
 
208
225
  const detailFieldIds = React.useMemo(() => {
209
226
  const base: string[] = ['email', 'password', 'organizationId', 'roles']
@@ -383,9 +383,9 @@ export default function UsersListPage() {
383
383
  perspective={{ tableId: 'auth.users.list' }}
384
384
  rowActions={(row) => (
385
385
  <RowActions items={[
386
- { label: t('common.edit', 'Edit'), href: `/backend/users/${row.id}/edit` },
387
- { label: t('auth.users.list.actions.showRoles', 'Show roles'), href: `/backend/roles?userId=${encodeURIComponent(row.id)}` },
388
- { label: t('common.delete', 'Delete'), destructive: true, onSelect: () => { void handleDelete(row) } },
386
+ { id: 'edit', label: t('common.edit', 'Edit'), href: `/backend/users/${row.id}/edit` },
387
+ { id: 'show-roles', label: t('auth.users.list.actions.showRoles', 'Show roles'), href: `/backend/roles?userId=${encodeURIComponent(row.id)}` },
388
+ { id: 'delete', label: t('common.delete', 'Delete'), destructive: true, onSelect: () => { void handleDelete(row) } },
389
389
  ]} />
390
390
  )}
391
391
  pagination={{ page, pageSize: 50, total, totalPages, onPageChange: setPage }}
@@ -16,6 +16,8 @@ import { decryptWithAesGcm } from '@open-mercato/shared/lib/encryption/aes'
16
16
  import { env } from 'process'
17
17
  import type { KmsService, TenantDek } from '@open-mercato/shared/lib/encryption/kms'
18
18
  import crypto from 'node:crypto'
19
+ import { formatPasswordRequirements, getPasswordPolicy, validatePassword } from '@open-mercato/shared/lib/auth/passwordPolicy'
20
+ import { parseBooleanToken } from '@open-mercato/shared/lib/boolean'
19
21
 
20
22
  const addUser: ModuleCli = {
21
23
  command: 'add-user',
@@ -34,6 +36,7 @@ const addUser: ModuleCli = {
34
36
  console.error('Usage: mercato auth add-user --email <email> --password <password> --organizationId <id> [--roles customer,employee]')
35
37
  return
36
38
  }
39
+ if (!ensurePasswordPolicy(password)) return
37
40
  const { resolve } = await createRequestContainer()
38
41
  const em = resolve('em') as any
39
42
  const org =
@@ -102,6 +105,16 @@ function hashSecret(value: string | null | undefined): string | null {
102
105
  return crypto.createHash('sha256').update(normalizeKeyInput(value)).digest('hex').slice(0, 12)
103
106
  }
104
107
 
108
+ function ensurePasswordPolicy(password: string): boolean {
109
+ const policy = getPasswordPolicy()
110
+ const result = validatePassword(password, policy)
111
+ if (result.ok) return true
112
+ const requirements = formatPasswordRequirements(policy, (_key, fallback) => fallback)
113
+ const suffix = requirements ? `: ${requirements}` : ''
114
+ console.error(`Password does not meet the requirements${suffix}.`)
115
+ return false
116
+ }
117
+
105
118
  async function withEncryptionDebugDisabled<T>(fn: () => Promise<T>): Promise<T> {
106
119
  const previous = process.env.TENANT_DATA_ENCRYPTION_DEBUG
107
120
  process.env.TENANT_DATA_ENCRYPTION_DEBUG = 'no'
@@ -392,20 +405,33 @@ const addOrganization: ModuleCli = {
392
405
  const setupApp: ModuleCli = {
393
406
  command: 'setup',
394
407
  async run(rest) {
395
- const args: Record<string, string> = {}
396
- for (let i = 0; i < rest.length; i += 2) {
397
- const k = rest[i]?.replace(/^--/, '')
398
- const v = rest[i + 1]
399
- if (k) args[k] = v
400
- }
401
- const orgName = args.orgName || args.name
402
- const email = args.email
403
- const password = args.password
404
- const rolesCsv = (args.roles ?? 'superadmin,admin,employee').trim()
408
+ const args = parseArgs(rest)
409
+ const orgName = typeof args.orgName === 'string'
410
+ ? args.orgName
411
+ : typeof args.name === 'string'
412
+ ? args.name
413
+ : undefined
414
+ const email = typeof args.email === 'string' ? args.email : undefined
415
+ const password = typeof args.password === 'string' ? args.password : undefined
416
+ const rolesCsv = typeof args.roles === 'string'
417
+ ? args.roles.trim()
418
+ : 'superadmin,admin,employee'
419
+ const skipPasswordPolicyRaw =
420
+ args['skip-password-policy'] ??
421
+ args.skipPasswordPolicy ??
422
+ args['allow-weak-password'] ??
423
+ args.allowWeakPassword
424
+ const skipPasswordPolicy = typeof skipPasswordPolicyRaw === 'boolean'
425
+ ? skipPasswordPolicyRaw
426
+ : parseBooleanToken(typeof skipPasswordPolicyRaw === 'string' ? skipPasswordPolicyRaw : null) ?? false
405
427
  if (!orgName || !email || !password) {
406
- console.error('Usage: mercato auth setup --orgName <name> --email <email> --password <password> [--roles superadmin,admin,employee]')
428
+ console.error('Usage: mercato auth setup --orgName <name> --email <email> --password <password> [--roles superadmin,admin,employee] [--skip-password-policy]')
407
429
  return
408
430
  }
431
+ if (!skipPasswordPolicy && !ensurePasswordPolicy(password)) return
432
+ if (skipPasswordPolicy) {
433
+ console.warn('⚠️ Password policy validation skipped for setup.')
434
+ }
409
435
  const { resolve } = await createRequestContainer()
410
436
  const em = resolve<EntityManager>('em')
411
437
  const roleNames = rolesCsv
@@ -595,6 +621,7 @@ const setPassword: ModuleCli = {
595
621
  console.error('Usage: mercato auth set-password --email <email> --password <newPassword>')
596
622
  return
597
623
  }
624
+ if (!ensurePasswordPolicy(password)) return
598
625
 
599
626
  const { resolve } = await createRequestContainer()
600
627
  const em = resolve('em') as any
@@ -27,6 +27,10 @@ import {
27
27
  import { normalizeTenantId } from '@open-mercato/core/modules/auth/lib/tenantAccess'
28
28
  import { computeEmailHash } from '@open-mercato/core/modules/auth/lib/emailHash'
29
29
  import { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
30
+ import { buildNotificationFromType } from '@open-mercato/core/modules/notifications/lib/notificationBuilder'
31
+ import { resolveNotificationService } from '@open-mercato/core/modules/notifications/lib/notificationService'
32
+ import notificationTypes from '@open-mercato/core/modules/auth/notifications'
33
+ import { buildPasswordSchema } from '@open-mercato/shared/lib/auth/passwordPolicy'
30
34
 
31
35
  type SerializedUser = {
32
36
  email: string
@@ -63,9 +67,11 @@ type UserSnapshots = {
63
67
  undo: UserUndoSnapshot
64
68
  }
65
69
 
70
+ const passwordSchema = buildPasswordSchema()
71
+
66
72
  const createSchema = z.object({
67
73
  email: z.string().email(),
68
- password: z.string().min(6),
74
+ password: passwordSchema,
69
75
  organizationId: z.string().uuid(),
70
76
  roles: z.array(z.string()).optional(),
71
77
  })
@@ -73,7 +79,7 @@ const createSchema = z.object({
73
79
  const updateSchema = z.object({
74
80
  id: z.string().uuid(),
75
81
  email: z.string().email().optional(),
76
- password: z.string().min(6).optional(),
82
+ password: passwordSchema.optional(),
77
83
  organizationId: z.string().uuid().optional(),
78
84
  roles: z.array(z.string()).optional(),
79
85
  })
@@ -105,6 +111,46 @@ export const userCrudIndexer: CrudIndexerConfig = {
105
111
  }),
106
112
  }
107
113
 
114
+ async function notifyRoleChanges(
115
+ ctx: CommandRuntimeContext,
116
+ user: User,
117
+ assignedRoles: string[],
118
+ revokedRoles: string[],
119
+ ): Promise<void> {
120
+ const tenantId = user.tenantId ? String(user.tenantId) : null
121
+ if (!tenantId) return
122
+ const organizationId = user.organizationId ? String(user.organizationId) : null
123
+
124
+ try {
125
+ const notificationService = resolveNotificationService(ctx.container)
126
+ if (assignedRoles.length) {
127
+ const assignedType = notificationTypes.find((type) => type.type === 'auth.role.assigned')
128
+ if (assignedType) {
129
+ const notificationInput = buildNotificationFromType(assignedType, {
130
+ recipientUserId: String(user.id),
131
+ sourceEntityType: 'auth:user',
132
+ sourceEntityId: String(user.id),
133
+ })
134
+ await notificationService.create(notificationInput, { tenantId, organizationId })
135
+ }
136
+ }
137
+
138
+ if (revokedRoles.length) {
139
+ const revokedType = notificationTypes.find((type) => type.type === 'auth.role.revoked')
140
+ if (revokedType) {
141
+ const notificationInput = buildNotificationFromType(revokedType, {
142
+ recipientUserId: String(user.id),
143
+ sourceEntityType: 'auth:user',
144
+ sourceEntityId: String(user.id),
145
+ })
146
+ await notificationService.create(notificationInput, { tenantId, organizationId })
147
+ }
148
+ }
149
+ } catch (err) {
150
+ console.error('[auth.users.roles] Failed to create notification:', err)
151
+ }
152
+ }
153
+
108
154
  const createUserCommand: CommandHandler<Record<string, unknown>, User> = {
109
155
  id: 'auth.users.create',
110
156
  async execute(rawInput, ctx) {
@@ -147,8 +193,10 @@ const createUserCommand: CommandHandler<Record<string, unknown>, User> = {
147
193
  throw error
148
194
  }
149
195
 
196
+ let assignedRoles: string[] = []
150
197
  if (Array.isArray(parsed.roles) && parsed.roles.length) {
151
198
  await syncUserRoles(em, user, parsed.roles, tenantId)
199
+ assignedRoles = await loadUserRoleNames(em, String(user.id))
152
200
  }
153
201
 
154
202
  await setCustomFieldsIfAny({
@@ -173,6 +221,10 @@ const createUserCommand: CommandHandler<Record<string, unknown>, User> = {
173
221
  indexer: userCrudIndexer,
174
222
  })
175
223
 
224
+ if (assignedRoles.length) {
225
+ await notifyRoleChanges(ctx, user, assignedRoles, [])
226
+ }
227
+
176
228
  return user
177
229
  },
178
230
  captureAfter: async (_input, result, ctx) => {
@@ -288,6 +340,9 @@ const updateUserCommand: CommandHandler<Record<string, unknown>, User> = {
288
340
  async execute(rawInput, ctx) {
289
341
  const { parsed, custom } = parseWithCustomFields(updateSchema, rawInput)
290
342
  const em = (ctx.container.resolve('em') as EntityManager)
343
+ const rolesBefore = Array.isArray(parsed.roles)
344
+ ? await loadUserRoleNames(em, parsed.id)
345
+ : null
291
346
 
292
347
  if (parsed.email !== undefined) {
293
348
  const emailHash = computeEmailHash(parsed.email)
@@ -377,6 +432,14 @@ const updateUserCommand: CommandHandler<Record<string, unknown>, User> = {
377
432
  indexer: userCrudIndexer,
378
433
  })
379
434
 
435
+ if (Array.isArray(parsed.roles) && rolesBefore) {
436
+ const rolesAfter = await loadUserRoleNames(em, String(user.id))
437
+ const { assigned, revoked } = diffRoleChanges(rolesBefore, rolesAfter)
438
+ if (assigned.length || revoked.length) {
439
+ await notifyRoleChanges(ctx, user, assigned, revoked)
440
+ }
441
+ }
442
+
380
443
  await invalidateUserCache(ctx, parsed.id)
381
444
 
382
445
  return user
@@ -772,6 +835,14 @@ async function invalidateUserCache(ctx: CommandRuntimeContext, userId: string) {
772
835
  }
773
836
  }
774
837
 
838
+ function diffRoleChanges(before: string[], after: string[]) {
839
+ const beforeSet = new Set(before)
840
+ const afterSet = new Set(after)
841
+ const assigned = after.filter((role) => !beforeSet.has(role))
842
+ const revoked = before.filter((role) => !afterSet.has(role))
843
+ return { assigned, revoked }
844
+ }
845
+
775
846
  function arrayEquals(left: string[] | undefined, right: string[]): boolean {
776
847
  if (!left) return false
777
848
  if (left.length !== right.length) return false
@@ -1,10 +1,14 @@
1
1
  import { z } from 'zod'
2
+ import { buildPasswordSchema } from '@open-mercato/shared/lib/auth/passwordPolicy'
3
+
4
+ const passwordSchema = buildPasswordSchema()
2
5
 
3
6
  // Core auth validators
4
7
  export const userLoginSchema = z.object({
5
8
  email: z.string().email(),
6
9
  password: z.string().min(6),
7
10
  requireRole: z.string().optional(),
11
+ tenantId: z.string().uuid().optional(),
8
12
  })
9
13
 
10
14
  export const requestPasswordResetSchema = z.object({
@@ -13,7 +17,7 @@ export const requestPasswordResetSchema = z.object({
13
17
 
14
18
  export const confirmPasswordResetSchema = z.object({
15
19
  token: z.string().min(10),
16
- password: z.string().min(6),
20
+ password: passwordSchema,
17
21
  })
18
22
 
19
23
  export const sidebarPreferencesInputSchema = z.object({
@@ -29,7 +33,7 @@ export const sidebarPreferencesInputSchema = z.object({
29
33
  // Optional helpers for CLI or admin forms
30
34
  export const userCreateSchema = z.object({
31
35
  email: z.string().email(),
32
- password: z.string().min(6),
36
+ password: passwordSchema,
33
37
  tenantId: z.string().uuid().optional(),
34
38
  organizationId: z.string().uuid(),
35
39
  rolesCsv: z.string().optional(),
@@ -1,14 +1,40 @@
1
1
  "use client"
2
- import { useState } from 'react'
2
+ import { useCallback, useEffect, useState } from 'react'
3
3
  import Image from 'next/image'
4
4
  import Link from 'next/link'
5
5
  import { useRouter, useSearchParams } from 'next/navigation'
6
- import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@open-mercato/ui/primitives/card'
6
+ import { Card, CardContent, CardHeader, CardDescription } from '@open-mercato/ui/primitives/card'
7
7
  import { Input } from '@open-mercato/ui/primitives/input'
8
8
  import { Label } from '@open-mercato/ui/primitives/label'
9
+ import { Button } from '@open-mercato/ui/primitives/button'
9
10
  import { useT } from '@open-mercato/shared/lib/i18n/context'
10
11
  import { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'
11
12
  import { clearAllOperations } from '@open-mercato/ui/backend/operations/store'
13
+ import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
14
+ import { X } from 'lucide-react'
15
+
16
+ const loginTenantKey = 'om_login_tenant'
17
+ const loginTenantCookieMaxAge = 60 * 60 * 24 * 14
18
+
19
+ function readTenantCookie() {
20
+ if (typeof document === 'undefined') return null
21
+ const entries = document.cookie.split(';')
22
+ for (const entry of entries) {
23
+ const [name, ...rest] = entry.trim().split('=')
24
+ if (name === loginTenantKey) return decodeURIComponent(rest.join('='))
25
+ }
26
+ return null
27
+ }
28
+
29
+ function setTenantCookie(value: string) {
30
+ if (typeof document === 'undefined') return
31
+ document.cookie = `${loginTenantKey}=${encodeURIComponent(value)}; path=/; max-age=${loginTenantCookieMaxAge}; samesite=lax`
32
+ }
33
+
34
+ function clearTenantCookie() {
35
+ if (typeof document === 'undefined') return
36
+ document.cookie = `${loginTenantKey}=; path=/; max-age=0; samesite=lax`
37
+ }
12
38
 
13
39
  function extractErrorMessage(payload: unknown): string | null {
14
40
  if (!payload) return null
@@ -44,8 +70,11 @@ function looksLikeJsonString(value: string): boolean {
44
70
 
45
71
  export default function LoginPage() {
46
72
  const t = useT()
47
- const translate = (key: string, fallback: string, params?: Record<string, string | number>) =>
48
- translateWithFallback(t, key, fallback, params)
73
+ const translate = useCallback(
74
+ (key: string, fallback: string, params?: Record<string, string | number>) =>
75
+ translateWithFallback(t, key, fallback, params),
76
+ [t],
77
+ )
49
78
  const router = useRouter()
50
79
  const searchParams = useSearchParams()
51
80
  const requireRole = (searchParams.get('requireRole') || searchParams.get('role') || '').trim()
@@ -56,6 +85,80 @@ export default function LoginPage() {
56
85
  const translatedFeatures = requiredFeatures.map((feature) => translate(`features.${feature}`, feature))
57
86
  const [error, setError] = useState<string | null>(null)
58
87
  const [submitting, setSubmitting] = useState(false)
88
+ const [tenantId, setTenantId] = useState<string | null>(null)
89
+ const [tenantName, setTenantName] = useState<string | null>(null)
90
+ const [tenantLoading, setTenantLoading] = useState(false)
91
+ const [tenantInvalid, setTenantInvalid] = useState<string | null>(null)
92
+ const showTenantInvalid = tenantId != null && tenantInvalid === tenantId
93
+
94
+ useEffect(() => {
95
+ const tenantParam = (searchParams.get('tenant') || '').trim()
96
+ if (tenantParam) {
97
+ setTenantId(tenantParam)
98
+ window.localStorage.setItem(loginTenantKey, tenantParam)
99
+ setTenantCookie(tenantParam)
100
+ return
101
+ }
102
+ const storedTenant = window.localStorage.getItem(loginTenantKey) || readTenantCookie()
103
+ if (storedTenant) {
104
+ setTenantId(storedTenant)
105
+ }
106
+ }, [searchParams])
107
+
108
+ useEffect(() => {
109
+ if (!tenantId) {
110
+ setTenantName(null)
111
+ setTenantInvalid(null)
112
+ return
113
+ }
114
+ if (tenantInvalid === tenantId) {
115
+ setTenantName(null)
116
+ setTenantLoading(false)
117
+ return
118
+ }
119
+ let active = true
120
+ setTenantLoading(true)
121
+ setTenantInvalid(null)
122
+ apiCall<{ ok: boolean; tenant?: { id: string; name: string }; error?: string }>(
123
+ `/api/directory/tenants/lookup?tenantId=${encodeURIComponent(tenantId)}`,
124
+ )
125
+ .then(({ result }) => {
126
+ if (!active) return
127
+ if (result?.ok && result.tenant) {
128
+ setTenantName(result.tenant.name)
129
+ return
130
+ }
131
+ const message = translate('auth.login.errors.tenantInvalid', 'Tenant not found. Clear the tenant selection and try again.')
132
+ setTenantName(null)
133
+ setTenantInvalid(tenantId)
134
+ setError(null)
135
+ })
136
+ .catch(() => {
137
+ if (!active) return
138
+ setTenantName(null)
139
+ setTenantInvalid(tenantId)
140
+ setError(null)
141
+ })
142
+ .finally(() => {
143
+ if (active) setTenantLoading(false)
144
+ })
145
+ return () => {
146
+ active = false
147
+ }
148
+ }, [tenantId, translate])
149
+
150
+ function handleClearTenant() {
151
+ window.localStorage.removeItem(loginTenantKey)
152
+ clearTenantCookie()
153
+ setTenantId(null)
154
+ setTenantName(null)
155
+ setTenantInvalid(null)
156
+ const params = new URLSearchParams(searchParams)
157
+ params.delete('tenant')
158
+ setError(null)
159
+ const query = params.toString()
160
+ router.replace(query ? `/login?${query}` : '/login')
161
+ }
59
162
 
60
163
  async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
61
164
  e.preventDefault()
@@ -141,6 +244,9 @@ export default function LoginPage() {
141
244
  </CardHeader>
142
245
  <CardContent>
143
246
  <form className="grid gap-3" onSubmit={onSubmit} noValidate>
247
+ {tenantId ? (
248
+ <input type="hidden" name="tenantId" value={tenantId} />
249
+ ) : null}
144
250
  {!!translatedRoles.length && (
145
251
  <div className="rounded-md border border-blue-200 bg-blue-50 px-3 py-2 text-center text-xs text-blue-900">
146
252
  {translate(
@@ -159,7 +265,30 @@ export default function LoginPage() {
159
265
  })}
160
266
  </div>
161
267
  )}
162
- {error && (
268
+ {showTenantInvalid ? (
269
+ <div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-center text-xs text-red-700">
270
+ <div className="font-medium">{translate('auth.login.errors.tenantInvalid', 'Tenant not found. Clear the tenant selection and try again.')}</div>
271
+ <Button type="button" variant="outline" size="sm" className="mt-2 border-red-300 text-red-700" onClick={handleClearTenant}>
272
+ <X className="mr-2 size-4" aria-hidden="true" />
273
+ {translate('auth.login.tenantClear', 'Clear')}
274
+ </Button>
275
+ </div>
276
+ ) : tenantId ? (
277
+ <div className="rounded-md border border-emerald-200 bg-emerald-50 px-3 py-2 text-center text-xs text-emerald-900">
278
+ <div className="font-medium">
279
+ {tenantLoading
280
+ ? translate('auth.login.tenantLoading', 'Loading tenant details...')
281
+ : translate('auth.login.tenantBanner', "You're logging in to {tenant} tenant.", {
282
+ tenant: tenantName || tenantId,
283
+ })}
284
+ </div>
285
+ <Button type="button" variant="outline" size="sm" className="mt-2 border-emerald-300 text-emerald-900" onClick={handleClearTenant}>
286
+ <X className="mr-2 size-4" aria-hidden="true" />
287
+ {translate('auth.login.tenantClear', 'Clear')}
288
+ </Button>
289
+ </div>
290
+ ) : null}
291
+ {error && !showTenantInvalid && (
163
292
  <div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-center text-sm text-red-700" role="alert" aria-live="polite">
164
293
  {error}
165
294
  </div>
@@ -4,11 +4,20 @@ import { Input } from '@open-mercato/ui/primitives/input'
4
4
  import { Label } from '@open-mercato/ui/primitives/label'
5
5
  import { useState } from 'react'
6
6
  import { useRouter } from 'next/navigation'
7
+ import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
8
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
9
+ import { formatPasswordRequirements, getPasswordPolicy } from '@open-mercato/shared/lib/auth/passwordPolicy'
7
10
 
8
11
  export default function ResetWithTokenPage({ params }: { params: { token: string } }) {
9
12
  const router = useRouter()
13
+ const t = useT()
10
14
  const [error, setError] = useState<string | null>(null)
11
15
  const [submitting, setSubmitting] = useState(false)
16
+ const passwordPolicy = getPasswordPolicy()
17
+ const passwordRequirements = formatPasswordRequirements(passwordPolicy, t)
18
+ const passwordDescription = passwordRequirements
19
+ ? t('auth.password.requirements.help', 'Password requirements: {requirements}', { requirements: passwordRequirements })
20
+ : ''
12
21
 
13
22
  async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
14
23
  e.preventDefault()
@@ -17,13 +26,15 @@ export default function ResetWithTokenPage({ params }: { params: { token: string
17
26
  try {
18
27
  const form = new FormData(e.currentTarget)
19
28
  form.set('token', params.token)
20
- const res = await fetch('/api/auth/reset/confirm', { method: 'POST', body: form })
21
- const data = await res.json().catch(() => null)
22
- if (!res.ok) {
23
- setError(data?.error || 'Unable to reset password')
29
+ const { ok, result } = await apiCall<{ ok?: boolean; error?: string; redirect?: string }>(
30
+ '/api/auth/reset/confirm',
31
+ { method: 'POST', body: form },
32
+ )
33
+ if (!ok || result?.ok === false) {
34
+ setError(result?.error || t('auth.reset.errors.failed', 'Unable to reset password'))
24
35
  return
25
36
  }
26
- router.replace(data?.redirect || '/login')
37
+ router.replace(result?.redirect || '/login')
27
38
  } finally {
28
39
  setSubmitting(false)
29
40
  }
@@ -33,18 +44,21 @@ export default function ResetWithTokenPage({ params }: { params: { token: string
33
44
  <div className="min-h-svh flex items-center justify-center p-4">
34
45
  <Card className="w-full max-w-sm">
35
46
  <CardHeader>
36
- <CardTitle>Set a new password</CardTitle>
37
- <CardDescription>Choose a strong password for your account.</CardDescription>
47
+ <CardTitle>{t('auth.reset.title', 'Set a new password')}</CardTitle>
48
+ <CardDescription>{t('auth.reset.subtitle', 'Choose a strong password for your account.')}</CardDescription>
38
49
  </CardHeader>
39
50
  <CardContent>
40
51
  <form className="grid gap-3" onSubmit={onSubmit}>
41
52
  {error && <div className="text-sm text-red-600">{error}</div>}
42
53
  <div className="grid gap-1">
43
- <Label htmlFor="password">New password</Label>
44
- <Input id="password" name="password" type="password" required minLength={6} />
54
+ <Label htmlFor="password">{t('auth.reset.form.password', 'New password')}</Label>
55
+ <Input id="password" name="password" type="password" required minLength={passwordPolicy.minLength} />
56
+ {passwordDescription ? (
57
+ <p className="text-xs text-muted-foreground">{passwordDescription}</p>
58
+ ) : null}
45
59
  </div>
46
60
  <button disabled={submitting} className="h-10 rounded-md bg-foreground text-background mt-2 hover:opacity-90 transition disabled:opacity-60">
47
- {submitting ? '...' : 'Update password'}
61
+ {submitting ? t('auth.reset.form.loading', '...') : t('auth.reset.form.submit', 'Update password')}
48
62
  </button>
49
63
  </form>
50
64
  </CardContent>
@@ -52,4 +66,3 @@ export default function ResetWithTokenPage({ params }: { params: { token: string
52
66
  </div>
53
67
  )
54
68
  }
55
-
@@ -2,12 +2,26 @@
2
2
  "auth.signIn": "Anmelden",
3
3
  "auth.email": "E-Mail",
4
4
  "auth.password": "Passwort",
5
+ "auth.password.requirements.help": "Passwortanforderungen: {requirements}",
6
+ "auth.password.requirements.minLength": "Mindestens {min} Zeichen",
7
+ "auth.password.requirements.digit": "Eine Zahl",
8
+ "auth.password.requirements.uppercase": "Ein Großbuchstabe",
9
+ "auth.password.requirements.special": "Ein Sonderzeichen",
10
+ "auth.password.requirements.separator": ", ",
5
11
  "auth.sendResetLink": "Link zum Zurücksetzen senden",
6
12
  "auth.resetPassword": "Passwort zurücksetzen",
13
+ "auth.reset.title": "Neues Passwort festlegen",
14
+ "auth.reset.subtitle": "Wähle ein sicheres Passwort für dein Konto.",
15
+ "auth.reset.form.password": "Neues Passwort",
16
+ "auth.reset.form.loading": "...",
17
+ "auth.reset.form.submit": "Passwort aktualisieren",
18
+ "auth.reset.errors.failed": "Passwort konnte nicht zurückgesetzt werden",
7
19
  "auth.usersRoles": "Benutzer und Rollen",
8
20
  "auth.manageAuthSettings": "Verwalte die Authentifizierungseinstellungen.",
9
21
  "auth.login.errors.permissionDenied": "Du hast keine Berechtigung, auf diesen Bereich zuzugreifen. Bitte wende dich an deine Administration.",
10
22
  "auth.login.errors.invalidCredentials": "Ungültige E-Mail oder ungültiges Passwort",
23
+ "auth.login.errors.tenantRequired": "Nutze den Login-Link aus deiner Tenant-Aktivierung, um fortzufahren.",
24
+ "auth.login.errors.tenantInvalid": "Tenant nicht gefunden. Entferne die Tenant-Auswahl und versuche es erneut.",
11
25
  "auth.login.errors.generic": "Es ist ein Fehler aufgetreten. Bitte versuche es erneut.",
12
26
  "auth.login.logoAlt": "Open Mercato Logo",
13
27
  "auth.login.brandName": "Open Mercato",
@@ -15,6 +29,9 @@
15
29
  "auth.login.requireRoleMessage": "Für den Zugriff ist die folgende Rolle erforderlich: {roles}",
16
30
  "auth.login.requireRolesMessage": "Für den Zugriff ist eine der folgenden Rollen erforderlich: {roles}",
17
31
  "auth.login.featureDenied": "Du hast keinen Zugriff auf diese Funktion ({feature}). Bitte wende dich an deine Administration.",
32
+ "auth.login.tenantBanner": "Du meldest dich beim Tenant {tenant} an.",
33
+ "auth.login.tenantLoading": "Tenant-Daten werden geladen...",
34
+ "auth.login.tenantClear": "Zurücksetzen",
18
35
  "auth.login.rememberMe": "Angemeldet bleiben",
19
36
  "auth.login.loading": "Wird geladen ...",
20
37
  "auth.login.forgotPassword": "Passwort vergessen?",
@@ -80,6 +97,21 @@
80
97
  "auth.users.form.errors.load": "Benutzerdaten konnten nicht geladen werden",
81
98
  "auth.users.form.errors.aclUpdate": "Aktualisierung der Benutzerberechtigungen fehlgeschlagen",
82
99
  "auth.users.form.errors.delete": "Benutzer konnte nicht gelöscht werden",
100
+ "auth.profile.title": "Profil",
101
+ "auth.profile.subtitle": "Passwort ändern",
102
+ "auth.profile.form.email": "E-Mail",
103
+ "auth.profile.form.password": "Neues Passwort",
104
+ "auth.profile.form.confirmPassword": "Neues Passwort bestätigen",
105
+ "auth.profile.form.save": "Änderungen speichern",
106
+ "auth.profile.form.loading": "Profil wird geladen...",
107
+ "auth.profile.form.errors.load": "Profil konnte nicht geladen werden.",
108
+ "auth.profile.form.errors.save": "Profil konnte nicht aktualisiert werden.",
109
+ "auth.profile.form.errors.invalid": "Ungültige Profilaktualisierung.",
110
+ "auth.profile.form.errors.passwordMismatch": "Die Passwörter stimmen nicht überein.",
111
+ "auth.profile.form.errors.passwordRequirements": "Das Passwort muss die Anforderungen erfüllen.",
112
+ "auth.profile.form.errors.noChanges": "Keine Änderungen zu speichern.",
113
+ "auth.profile.form.errors.emailRequired": "E-Mail ist erforderlich.",
114
+ "auth.profile.form.success": "Profil aktualisiert.",
83
115
  "auth.users.list.error.load": "Benutzer konnten nicht geladen werden",
84
116
  "auth.users.list.error.delete": "Benutzer konnte nicht gelöscht werden",
85
117
  "auth.users.flash.created": "Benutzer erstellt",
@@ -95,5 +127,20 @@
95
127
  "auth.email.resetPassword.title": "Passwort zurücksetzen",
96
128
  "auth.email.resetPassword.body": "Klicken Sie auf den Link unten, um ein neues Passwort festzulegen. Dieser Link läuft in 60 Minuten ab.",
97
129
  "auth.email.resetPassword.cta": "Neues Passwort festlegen",
98
- "auth.email.resetPassword.hint": "Wenn Sie dies nicht angefordert haben, können Sie diese E-Mail ignorieren."
130
+ "auth.email.resetPassword.hint": "Wenn Sie dies nicht angefordert haben, können Sie diese E-Mail ignorieren.",
131
+ "auth.notifications.passwordReset.requested.title": "Passwort-Zurücksetzung angefordert",
132
+ "auth.notifications.passwordReset.requested.body": "Ein Link zum Zurücksetzen des Passworts wurde an Ihre E-Mail gesendet",
133
+ "auth.notifications.passwordReset.completed.title": "Passwort erfolgreich geändert",
134
+ "auth.notifications.passwordReset.completed.body": "Ihr Passwort wurde erfolgreich aktualisiert",
135
+ "auth.notifications.account.locked.title": "Konto gesperrt",
136
+ "auth.notifications.account.locked.body": "Ihr Konto wurde aus Sicherheitsgründen gesperrt. Bitte wenden Sie sich an den Support.",
137
+ "auth.notifications.login.newDevice.title": "Neues Gerät erkannt",
138
+ "auth.notifications.login.newDevice.body": "Es wurde eine Anmeldung von einem unbekannten Gerät für Ihr Konto erkannt",
139
+ "auth.notifications.role.assigned.title": "Neue Rolle zugewiesen",
140
+ "auth.notifications.role.assigned.body": "Ihnen wurde eine neue Rolle mit zusätzlichen Berechtigungen zugewiesen",
141
+ "auth.notifications.role.revoked.title": "Rolle entfernt",
142
+ "auth.notifications.role.revoked.body": "Eine Rolle wurde von Ihrem Konto entfernt",
143
+ "auth.actions.contactSupport": "Support kontaktieren",
144
+ "auth.actions.viewSessions": "Sitzungen anzeigen",
145
+ "auth.actions.viewPermissions": "Berechtigungen anzeigen"
99
146
  }