@open-mercato/core 0.7.0 → 0.7.1-develop.7103.1.41ff100d93

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 (847) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/helpers/integration/api.js +13 -1
  3. package/dist/helpers/integration/api.js.map +2 -2
  4. package/dist/helpers/integration/communicationChannelsFixtures.js +19 -0
  5. package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
  6. package/dist/modules/api_keys/api/keys/route.js +1 -1
  7. package/dist/modules/api_keys/api/keys/route.js.map +2 -2
  8. package/dist/modules/api_keys/backend/api-keys/page.js +3 -1
  9. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  10. package/dist/modules/api_keys/di.js +9 -0
  11. package/dist/modules/api_keys/di.js.map +7 -0
  12. package/dist/modules/api_keys/services/principalService.js +31 -0
  13. package/dist/modules/api_keys/services/principalService.js.map +7 -0
  14. package/dist/modules/attachments/api/route.js +2 -2
  15. package/dist/modules/attachments/api/route.js.map +2 -2
  16. package/dist/modules/attachments/components/AttachmentLibrary.js +2 -0
  17. package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
  18. package/dist/modules/attachments/di.js +11 -1
  19. package/dist/modules/attachments/di.js.map +2 -2
  20. package/dist/modules/attachments/index.js.map +1 -1
  21. package/dist/modules/attachments/lib/attachment-service.js +313 -0
  22. package/dist/modules/attachments/lib/attachment-service.js.map +7 -0
  23. package/dist/modules/attachments/lib/scoped-upload-service.js +15 -2
  24. package/dist/modules/attachments/lib/scoped-upload-service.js.map +2 -2
  25. package/dist/modules/attachments/lib/upload-limits.js +6 -2
  26. package/dist/modules/attachments/lib/upload-limits.js.map +2 -2
  27. package/dist/modules/audit_logs/backend/audit-logs/page.js +6 -0
  28. package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
  29. package/dist/modules/audit_logs/lib/display-helpers.js +19 -11
  30. package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
  31. package/dist/modules/audit_logs/services/actionLogService.js +57 -12
  32. package/dist/modules/audit_logs/services/actionLogService.js.map +3 -3
  33. package/dist/modules/auth/acl.js +30 -5
  34. package/dist/modules/auth/acl.js.map +2 -2
  35. package/dist/modules/auth/api/feature-check.js +8 -2
  36. package/dist/modules/auth/api/feature-check.js.map +2 -2
  37. package/dist/modules/auth/api/login.js +4 -1
  38. package/dist/modules/auth/api/login.js.map +2 -2
  39. package/dist/modules/auth/api/reset/validate.js +55 -0
  40. package/dist/modules/auth/api/reset/validate.js.map +7 -0
  41. package/dist/modules/auth/api/roles/acl/route.js +28 -33
  42. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  43. package/dist/modules/auth/api/session/refresh.js +25 -1
  44. package/dist/modules/auth/api/session/refresh.js.map +2 -2
  45. package/dist/modules/auth/api/users/acl/route.js +96 -51
  46. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  47. package/dist/modules/auth/api/users/route.js +13 -5
  48. package/dist/modules/auth/api/users/route.js.map +2 -2
  49. package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js +5 -1
  50. package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js.map +2 -2
  51. package/dist/modules/auth/backend/roles/page.js +3 -1
  52. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  53. package/dist/modules/auth/backend/users/[id]/edit/page.meta.js +5 -1
  54. package/dist/modules/auth/backend/users/[id]/edit/page.meta.js.map +2 -2
  55. package/dist/modules/auth/backend/users/page.js +2 -1
  56. package/dist/modules/auth/backend/users/page.js.map +2 -2
  57. package/dist/modules/auth/commands/acl.js +254 -0
  58. package/dist/modules/auth/commands/acl.js.map +7 -0
  59. package/dist/modules/auth/components/AclEditor.js +39 -30
  60. package/dist/modules/auth/components/AclEditor.js.map +2 -2
  61. package/dist/modules/auth/data/entities.js.map +2 -2
  62. package/dist/modules/auth/data/validators.js +5 -1
  63. package/dist/modules/auth/data/validators.js.map +2 -2
  64. package/dist/modules/auth/di.js +35 -9
  65. package/dist/modules/auth/di.js.map +2 -2
  66. package/dist/modules/auth/frontend/reset/[token]/page.js +46 -0
  67. package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
  68. package/dist/modules/auth/lib/grantChecks.js.map +2 -2
  69. package/dist/modules/auth/lib/userIdFilter.js +16 -0
  70. package/dist/modules/auth/lib/userIdFilter.js.map +7 -0
  71. package/dist/modules/auth/services/authService.js +16 -2
  72. package/dist/modules/auth/services/authService.js.map +2 -2
  73. package/dist/modules/auth/services/principalService.js +200 -0
  74. package/dist/modules/auth/services/principalService.js.map +7 -0
  75. package/dist/modules/auth/services/rbacService.js +67 -24
  76. package/dist/modules/auth/services/rbacService.js.map +3 -3
  77. package/dist/modules/auth/services/roleOrganizationScope.js +41 -0
  78. package/dist/modules/auth/services/roleOrganizationScope.js.map +7 -0
  79. package/dist/modules/business_rules/backend/logs/page.js +3 -1
  80. package/dist/modules/business_rules/backend/logs/page.js.map +2 -2
  81. package/dist/modules/business_rules/backend/rules/page.js +3 -1
  82. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  83. package/dist/modules/business_rules/backend/sets/page.js +3 -1
  84. package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
  85. package/dist/modules/business_rules/lib/expression-evaluator.js +9 -9
  86. package/dist/modules/business_rules/lib/expression-evaluator.js.map +2 -2
  87. package/dist/modules/business_rules/lib/rule-evaluator.js +10 -9
  88. package/dist/modules/business_rules/lib/rule-evaluator.js.map +2 -2
  89. package/dist/modules/catalog/ai-agents.js +1 -1
  90. package/dist/modules/catalog/ai-agents.js.map +1 -1
  91. package/dist/modules/catalog/ai-tools/merchandising-pack.js +2 -2
  92. package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +2 -2
  93. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +5 -2
  94. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
  95. package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -0
  96. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  97. package/dist/modules/catalog/components/products/ProductsDataTable.js +7 -1
  98. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  99. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +2 -0
  100. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +2 -2
  101. package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +9 -1
  102. package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +2 -2
  103. package/dist/modules/communication_channels/api/post/test-seed/route.js +95 -10
  104. package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
  105. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +3 -0
  106. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
  107. package/dist/modules/communication_channels/commands/ingest-inbound-message.js +14 -1
  108. package/dist/modules/communication_channels/commands/ingest-inbound-message.js.map +2 -2
  109. package/dist/modules/communication_channels/di.js +7 -1
  110. package/dist/modules/communication_channels/di.js.map +2 -2
  111. package/dist/modules/communication_channels/lib/email-capabilities.js +4 -1
  112. package/dist/modules/communication_channels/lib/email-capabilities.js.map +2 -2
  113. package/dist/modules/communication_channels/lib/outbound-recipient.js +33 -0
  114. package/dist/modules/communication_channels/lib/outbound-recipient.js.map +7 -0
  115. package/dist/modules/communication_channels/lib/resolve-channel-type.js +51 -0
  116. package/dist/modules/communication_channels/lib/resolve-channel-type.js.map +7 -0
  117. package/dist/modules/communication_channels/lib/test-seed.js +41 -2
  118. package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
  119. package/dist/modules/configs/lib/system-status.js +9 -0
  120. package/dist/modules/configs/lib/system-status.js.map +2 -2
  121. package/dist/modules/currencies/backend/currencies/page.js +3 -1
  122. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  123. package/dist/modules/currencies/backend/exchange-rates/page.js +3 -1
  124. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  125. package/dist/modules/currencies/services/rateFetchingService.js +6 -1
  126. package/dist/modules/currencies/services/rateFetchingService.js.map +2 -2
  127. package/dist/modules/customer_accounts/api/admin/domain-mappings.js +9 -0
  128. package/dist/modules/customer_accounts/api/admin/domain-mappings.js.map +2 -2
  129. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +3 -1
  130. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
  131. package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js +3 -1
  132. package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js.map +2 -2
  133. package/dist/modules/customer_accounts/services/domainMappingService.js +10 -0
  134. package/dist/modules/customer_accounts/services/domainMappingService.js.map +2 -2
  135. package/dist/modules/customers/ai-tools/companies-pack.js +4 -1
  136. package/dist/modules/customers/ai-tools/companies-pack.js.map +2 -2
  137. package/dist/modules/customers/ai-tools/deal-analyzer-pack.js +13 -2
  138. package/dist/modules/customers/ai-tools/deal-analyzer-pack.js.map +2 -2
  139. package/dist/modules/customers/ai-tools/deals-pack.js +52 -6
  140. package/dist/modules/customers/ai-tools/deals-pack.js.map +2 -2
  141. package/dist/modules/customers/ai-tools/people-pack.js +4 -1
  142. package/dist/modules/customers/ai-tools/people-pack.js.map +2 -2
  143. package/dist/modules/customers/api/activities/route.js +48 -6
  144. package/dist/modules/customers/api/activities/route.js.map +2 -2
  145. package/dist/modules/customers/api/companies/[id]/people/route.js +20 -64
  146. package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
  147. package/dist/modules/customers/api/companies/[id]/route.js +17 -94
  148. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  149. package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js +8 -5
  150. package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js.map +2 -2
  151. package/dist/modules/customers/api/deals/[id]/companies/route.js +1 -1
  152. package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
  153. package/dist/modules/customers/api/deals/[id]/people/route.js +1 -1
  154. package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
  155. package/dist/modules/customers/api/deals/[id]/route.js +8 -25
  156. package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
  157. package/dist/modules/customers/api/deals/[id]/stats/route.js +3 -22
  158. package/dist/modules/customers/api/deals/[id]/stats/route.js.map +2 -2
  159. package/dist/modules/customers/api/deals/aggregate/route.js +14 -9
  160. package/dist/modules/customers/api/deals/aggregate/route.js.map +2 -2
  161. package/dist/modules/customers/api/deals/map/route.js +5 -5
  162. package/dist/modules/customers/api/deals/map/route.js.map +2 -2
  163. package/dist/modules/customers/api/deals/route.js +38 -1
  164. package/dist/modules/customers/api/deals/route.js.map +2 -2
  165. package/dist/modules/customers/api/entity-roles-factory.js +4 -4
  166. package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
  167. package/dist/modules/customers/api/interactions/route.js +3 -1
  168. package/dist/modules/customers/api/interactions/route.js.map +2 -2
  169. package/dist/modules/customers/api/interactions/tasks/route.js +27 -4
  170. package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
  171. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +4 -3
  172. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
  173. package/dist/modules/customers/api/people/[id]/companies/context.js +1 -1
  174. package/dist/modules/customers/api/people/[id]/companies/context.js.map +2 -2
  175. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +1 -1
  176. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
  177. package/dist/modules/customers/api/people/[id]/route.js +11 -10
  178. package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
  179. package/dist/modules/customers/api/people/check-phone/route.js +51 -9
  180. package/dist/modules/customers/api/people/check-phone/route.js.map +2 -2
  181. package/dist/modules/customers/api/todos/route.js +30 -5
  182. package/dist/modules/customers/api/todos/route.js.map +2 -2
  183. package/dist/modules/customers/backend/customers/companies/page.js +4 -2
  184. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  185. package/dist/modules/customers/backend/customers/deals/[id]/page.js +6 -1
  186. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  187. package/dist/modules/customers/backend/customers/deals/page.js +5 -2
  188. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  189. package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js +4 -13
  190. package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js.map +2 -2
  191. package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js +85 -14
  192. package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js.map +2 -2
  193. package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js +18 -0
  194. package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js.map +7 -0
  195. package/dist/modules/customers/backend/customers/people/page.js +4 -2
  196. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  197. package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js +9 -3
  198. package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js.map +2 -2
  199. package/dist/modules/customers/commands/deals.js +21 -34
  200. package/dist/modules/customers/commands/deals.js.map +2 -2
  201. package/dist/modules/customers/commands/interactions.js.map +1 -1
  202. package/dist/modules/customers/commands/personCompanyLinks.js +131 -2
  203. package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
  204. package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
  205. package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
  206. package/dist/modules/customers/components/DealsKpiStrip.js +7 -6
  207. package/dist/modules/customers/components/DealsKpiStrip.js.map +2 -2
  208. package/dist/modules/customers/components/calendar/AgendaList.js +2 -2
  209. package/dist/modules/customers/components/calendar/AgendaList.js.map +2 -2
  210. package/dist/modules/customers/components/calendar/CalendarEventEditor.js +1 -1
  211. package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +2 -2
  212. package/dist/modules/customers/components/calendar/CalendarScreen.js +1 -1
  213. package/dist/modules/customers/components/calendar/CalendarScreen.js.map +2 -2
  214. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +1 -1
  215. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
  216. package/dist/modules/customers/components/calendar/EventBlock.js +1 -1
  217. package/dist/modules/customers/components/calendar/EventBlock.js.map +2 -2
  218. package/dist/modules/customers/components/calendar/EventPeekPopover.js +3 -2
  219. package/dist/modules/customers/components/calendar/EventPeekPopover.js.map +2 -2
  220. package/dist/modules/customers/components/calendar/editor/PeopleField.js +40 -5
  221. package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
  222. package/dist/modules/customers/components/calendar/editor/hooks.js +2 -1
  223. package/dist/modules/customers/components/calendar/editor/hooks.js.map +2 -2
  224. package/dist/modules/customers/components/calendar/types.js +1 -1
  225. package/dist/modules/customers/components/calendar/types.js.map +2 -2
  226. package/dist/modules/customers/components/detail/CompanyKpiBar.js +5 -4
  227. package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +2 -2
  228. package/dist/modules/customers/components/detail/CompanyPeopleSection.js +3 -1
  229. package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
  230. package/dist/modules/customers/components/detail/DealForm.js +19 -7
  231. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  232. package/dist/modules/customers/components/detail/DealsSection.js +6 -5
  233. package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
  234. package/dist/modules/customers/components/detail/EntityTagsDialog.js +35 -11
  235. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
  236. package/dist/modules/customers/components/detail/PersonCompaniesSection.js +3 -1
  237. package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
  238. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +19 -13
  239. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
  240. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +4 -4
  241. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +2 -2
  242. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +3 -3
  243. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
  244. package/dist/modules/customers/components/detail/utils.js +5 -5
  245. package/dist/modules/customers/components/detail/utils.js.map +2 -2
  246. package/dist/modules/customers/data/entities.js.map +1 -1
  247. package/dist/modules/customers/data/validators.js +32 -3
  248. package/dist/modules/customers/data/validators.js.map +2 -2
  249. package/dist/modules/customers/events.js +5 -0
  250. package/dist/modules/customers/events.js.map +2 -2
  251. package/dist/modules/customers/lib/calendar/conflicts.js +8 -2
  252. package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
  253. package/dist/modules/customers/lib/calendar/editorPayload.js +3 -2
  254. package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
  255. package/dist/modules/customers/lib/calendar/mapItem.js +8 -3
  256. package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
  257. package/dist/modules/customers/lib/calendar/participantIdentity.js +9 -0
  258. package/dist/modules/customers/lib/calendar/participantIdentity.js.map +7 -0
  259. package/dist/modules/customers/lib/closureStage.js +45 -0
  260. package/dist/modules/customers/lib/closureStage.js.map +7 -0
  261. package/dist/modules/customers/lib/dealStatus.js +30 -0
  262. package/dist/modules/customers/lib/dealStatus.js.map +2 -2
  263. package/dist/modules/customers/lib/detailReadAccess.js +12 -0
  264. package/dist/modules/customers/lib/detailReadAccess.js.map +7 -0
  265. package/dist/modules/customers/lib/findPeopleByAddresses.js +1 -0
  266. package/dist/modules/customers/lib/findPeopleByAddresses.js.map +2 -2
  267. package/dist/modules/customers/lib/personCompanies.js +100 -2
  268. package/dist/modules/customers/lib/personCompanies.js.map +2 -2
  269. package/dist/modules/customers/lib/todoCompatibility.js +12 -0
  270. package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
  271. package/dist/modules/dashboards/lib/widgetScope.js +6 -1
  272. package/dist/modules/dashboards/lib/widgetScope.js.map +2 -2
  273. package/dist/modules/data_sync/backend/data-sync/page.js +3 -1
  274. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  275. package/dist/modules/data_sync/lib/abandoned-run.js +19 -0
  276. package/dist/modules/data_sync/lib/abandoned-run.js.map +7 -0
  277. package/dist/modules/data_sync/lib/sync-engine.js +72 -6
  278. package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
  279. package/dist/modules/data_sync/workers/sync-export.js +5 -1
  280. package/dist/modules/data_sync/workers/sync-export.js.map +2 -2
  281. package/dist/modules/data_sync/workers/sync-import.js +5 -1
  282. package/dist/modules/data_sync/workers/sync-import.js.map +2 -2
  283. package/dist/modules/devices/acl.js +9 -1
  284. package/dist/modules/devices/acl.js.map +2 -2
  285. package/dist/modules/devices/api/admin/devices/[id]/route.js +5 -32
  286. package/dist/modules/devices/api/admin/devices/[id]/route.js.map +2 -2
  287. package/dist/modules/devices/api/admin/devices/route.js +14 -1
  288. package/dist/modules/devices/api/admin/devices/route.js.map +2 -2
  289. package/dist/modules/devices/api/deviceList.js +99 -12
  290. package/dist/modules/devices/api/deviceList.js.map +2 -2
  291. package/dist/modules/devices/api/deviceSerialization.js +46 -0
  292. package/dist/modules/devices/api/deviceSerialization.js.map +7 -0
  293. package/dist/modules/devices/api/openapi.js +3 -1
  294. package/dist/modules/devices/api/openapi.js.map +2 -2
  295. package/dist/modules/devices/api/route.js +9 -1
  296. package/dist/modules/devices/api/route.js.map +2 -2
  297. package/dist/modules/devices/backend/devices/[id]/page.js +10 -26
  298. package/dist/modules/devices/backend/devices/[id]/page.js.map +2 -2
  299. package/dist/modules/devices/backend/devices/create/page.js +17 -1
  300. package/dist/modules/devices/backend/devices/create/page.js.map +2 -2
  301. package/dist/modules/devices/backend/devices/page.js +28 -34
  302. package/dist/modules/devices/backend/devices/page.js.map +2 -2
  303. package/dist/modules/devices/backend/devices/useDeviceUserLabels.js +34 -0
  304. package/dist/modules/devices/backend/devices/useDeviceUserLabels.js.map +7 -0
  305. package/dist/modules/devices/backend/devices/userOptions.js +52 -0
  306. package/dist/modules/devices/backend/devices/userOptions.js.map +7 -0
  307. package/dist/modules/devices/setup.js +6 -2
  308. package/dist/modules/devices/setup.js.map +2 -2
  309. package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
  310. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  311. package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
  312. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  313. package/dist/modules/directory/di.js +9 -0
  314. package/dist/modules/directory/di.js.map +2 -2
  315. package/dist/modules/directory/services/organizationHierarchyService.js +29 -0
  316. package/dist/modules/directory/services/organizationHierarchyService.js.map +7 -0
  317. package/dist/modules/directory/services/organizationScopeService.js +56 -0
  318. package/dist/modules/directory/services/organizationScopeService.js.map +7 -0
  319. package/dist/modules/directory/utils/organizationScope.js.map +2 -2
  320. package/dist/modules/entities/api/records.js +4 -2
  321. package/dist/modules/entities/api/records.js.map +2 -2
  322. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +3 -1
  323. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  324. package/dist/modules/eudr/api/plots/route.js +5 -1
  325. package/dist/modules/eudr/api/plots/route.js.map +2 -2
  326. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +3 -0
  327. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +2 -2
  328. package/dist/modules/eudr/backend/eudr/plots/page.js +3 -0
  329. package/dist/modules/eudr/backend/eudr/plots/page.js.map +2 -2
  330. package/dist/modules/eudr/backend/eudr/product-mappings/page.js +3 -0
  331. package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +2 -2
  332. package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +3 -0
  333. package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +2 -2
  334. package/dist/modules/eudr/backend/eudr/statements/page.js +3 -0
  335. package/dist/modules/eudr/backend/eudr/statements/page.js.map +2 -2
  336. package/dist/modules/eudr/commands/statements.js +0 -3
  337. package/dist/modules/eudr/commands/statements.js.map +2 -2
  338. package/dist/modules/eudr/data/validators.js +4 -1
  339. package/dist/modules/eudr/data/validators.js.map +2 -2
  340. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +1 -0
  341. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
  342. package/dist/modules/feature_toggles/components/OverridesTable.js +1 -0
  343. package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
  344. package/dist/modules/feature_toggles/defaults.json +0 -8
  345. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +3 -0
  346. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
  347. package/dist/modules/inbox_ops/backend/inbox-ops/page.js +3 -0
  348. package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
  349. package/dist/modules/inbox_ops/lib/htmlToPlainText.js +1 -12
  350. package/dist/modules/inbox_ops/lib/htmlToPlainText.js.map +2 -2
  351. package/dist/modules/integrations/api/[id]/credentials/route.js +6 -1
  352. package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
  353. package/dist/modules/integrations/backend/integrations/[id]/page.js +38 -29
  354. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  355. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +36 -9
  356. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
  357. package/dist/modules/integrations/backend/integrations/credential-secret-fields.js +55 -0
  358. package/dist/modules/integrations/backend/integrations/credential-secret-fields.js.map +7 -0
  359. package/dist/modules/integrations/data/validators.js +11 -3
  360. package/dist/modules/integrations/data/validators.js.map +2 -2
  361. package/dist/modules/integrations/lib/credentials-masking.js +6 -2
  362. package/dist/modules/integrations/lib/credentials-masking.js.map +2 -2
  363. package/dist/modules/messages/api/[id]/route.js +29 -1
  364. package/dist/modules/messages/api/[id]/route.js.map +2 -2
  365. package/dist/modules/messages/api/openapi.js +17 -2
  366. package/dist/modules/messages/api/openapi.js.map +2 -2
  367. package/dist/modules/messages/api/route.js +17 -2
  368. package/dist/modules/messages/api/route.js.map +2 -2
  369. package/dist/modules/messages/components/MessagesInboxPageClient.js +7 -14
  370. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
  371. package/dist/modules/messages/components/inboxFilters.js +15 -0
  372. package/dist/modules/messages/components/inboxFilters.js.map +2 -2
  373. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +11 -1
  374. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +2 -2
  375. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +3 -1
  376. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +2 -2
  377. package/dist/modules/messages/components/message-detail/panels/thread-panel.js +2 -1
  378. package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
  379. package/dist/modules/messages/components/messageListLabels.js +14 -2
  380. package/dist/modules/messages/components/messageListLabels.js.map +2 -2
  381. package/dist/modules/messages/data/validators.js +18 -4
  382. package/dist/modules/messages/data/validators.js.map +2 -2
  383. package/dist/modules/messages/lib/channel-sender-identity.js +26 -0
  384. package/dist/modules/messages/lib/channel-sender-identity.js.map +7 -0
  385. package/dist/modules/messages/lib/composeSourceChannelType.js +41 -0
  386. package/dist/modules/messages/lib/composeSourceChannelType.js.map +7 -0
  387. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +4 -6
  388. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
  389. package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -1
  390. package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
  391. package/dist/modules/payment_gateways/lib/webhook-processor.js +7 -0
  392. package/dist/modules/payment_gateways/lib/webhook-processor.js.map +2 -2
  393. package/dist/modules/planner/backend/planner/availability-rulesets/page.js +3 -0
  394. package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
  395. package/dist/modules/push_notifications/backend/push_notifications/page.js +3 -1
  396. package/dist/modules/push_notifications/backend/push_notifications/page.js.map +2 -2
  397. package/dist/modules/push_notifications/backend/push_notifications/send/page.js +1 -1
  398. package/dist/modules/push_notifications/backend/push_notifications/send/page.js.map +2 -2
  399. package/dist/modules/query_index/lib/engine.js +150 -51
  400. package/dist/modules/query_index/lib/engine.js.map +2 -2
  401. package/dist/modules/query_index/lib/search-entity-policy.js +14 -0
  402. package/dist/modules/query_index/lib/search-entity-policy.js.map +7 -0
  403. package/dist/modules/query_index/lib/search-tokens.js +79 -3
  404. package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
  405. package/dist/modules/resources/backend/resources/resource-types/page.js +3 -1
  406. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  407. package/dist/modules/resources/backend/resources/resources/page.js +3 -1
  408. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  409. package/dist/modules/sales/backend/sales/channels/offers/page.js +3 -0
  410. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  411. package/dist/modules/sales/backend/sales/channels/page.js +3 -0
  412. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  413. package/dist/modules/sales/backend/sales/documents/[id]/page.js +10 -8
  414. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  415. package/dist/modules/sales/commands/documents.js +79 -1
  416. package/dist/modules/sales/commands/documents.js.map +2 -2
  417. package/dist/modules/sales/components/PriceWithCurrency.js +7 -5
  418. package/dist/modules/sales/components/PriceWithCurrency.js.map +2 -2
  419. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +3 -0
  420. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
  421. package/dist/modules/sales/components/documents/AdjustmentsSection.js +8 -6
  422. package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
  423. package/dist/modules/sales/components/documents/ItemsSection.js +51 -22
  424. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  425. package/dist/modules/sales/components/documents/LineItemDialog.js +83 -18
  426. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  427. package/dist/modules/sales/components/documents/PaymentsSection.js +23 -9
  428. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  429. package/dist/modules/sales/components/documents/ReturnsSection.js +8 -6
  430. package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
  431. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +68 -14
  432. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  433. package/dist/modules/sales/components/documents/SalesOrderDraftLines.js +6 -5
  434. package/dist/modules/sales/components/documents/SalesOrderDraftLines.js.map +2 -2
  435. package/dist/modules/sales/components/documents/ShipmentDialog.js +5 -4
  436. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  437. package/dist/modules/sales/components/documents/ShipmentsSection.js +8 -6
  438. package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
  439. package/dist/modules/sales/components/documents/lineItemShipmentLock.js +54 -0
  440. package/dist/modules/sales/components/documents/lineItemShipmentLock.js.map +7 -0
  441. package/dist/modules/sales/components/documents/lineItemUtils.js +2 -2
  442. package/dist/modules/sales/components/documents/lineItemUtils.js.map +2 -2
  443. package/dist/modules/sales/data/entities.js +8 -2
  444. package/dist/modules/sales/data/entities.js.map +2 -2
  445. package/dist/modules/sales/extension-points.js +1 -0
  446. package/dist/modules/sales/extension-points.js.map +2 -2
  447. package/dist/modules/sales/lib/salesChannelsToggleSeed.js +33 -0
  448. package/dist/modules/sales/lib/salesChannelsToggleSeed.js.map +7 -0
  449. package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js +32 -0
  450. package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js.map +7 -0
  451. package/dist/modules/sales/setup.js +2 -0
  452. package/dist/modules/sales/setup.js.map +2 -2
  453. package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js +10 -2
  454. package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js.map +2 -2
  455. package/dist/modules/sales/widgets/injection-table.js +4 -7
  456. package/dist/modules/sales/widgets/injection-table.js.map +2 -2
  457. package/dist/modules/staff/backend/staff/leave-requests/page.js +3 -0
  458. package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
  459. package/dist/modules/staff/backend/staff/my-leave-requests/page.js +3 -0
  460. package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
  461. package/dist/modules/staff/backend/staff/team-members/page.js +3 -0
  462. package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
  463. package/dist/modules/staff/backend/staff/team-roles/page.js +3 -0
  464. package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
  465. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +3 -0
  466. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  467. package/dist/modules/staff/backend/staff/teams/page.js +3 -0
  468. package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
  469. package/dist/modules/staff/backend/staff/timesheets/page.js +29 -18
  470. package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
  471. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +3 -0
  472. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
  473. package/dist/modules/sync_excel/lib/adapters/customers.js +1 -0
  474. package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
  475. package/dist/modules/warranty_claims/api/assignees/route.js +3 -3
  476. package/dist/modules/warranty_claims/api/assignees/route.js.map +2 -2
  477. package/dist/modules/warranty_claims/api/portal/attachments/route.js +2 -2
  478. package/dist/modules/warranty_claims/api/portal/attachments/route.js.map +2 -2
  479. package/dist/modules/warranty_claims/api/portal/claims/route.js +12 -9
  480. package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
  481. package/dist/modules/warranty_claims/backend/page.js +3 -0
  482. package/dist/modules/warranty_claims/backend/page.js.map +2 -2
  483. package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js +3 -0
  484. package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js.map +2 -2
  485. package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js +3 -0
  486. package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js.map +2 -2
  487. package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js +3 -0
  488. package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js.map +2 -2
  489. package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js +3 -0
  490. package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js.map +2 -2
  491. package/dist/modules/wms/api/warehouseSearch.js +21 -0
  492. package/dist/modules/wms/api/warehouseSearch.js.map +7 -0
  493. package/dist/modules/wms/api/warehouses/route.js +13 -9
  494. package/dist/modules/wms/api/warehouses/route.js.map +2 -2
  495. package/dist/modules/wms/api/zones/route.js +15 -2
  496. package/dist/modules/wms/api/zones/route.js.map +2 -2
  497. package/dist/modules/wms/commands/configuration.js +121 -9
  498. package/dist/modules/wms/commands/configuration.js.map +2 -2
  499. package/dist/modules/wms/commands/inventory-actions.js +3 -0
  500. package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
  501. package/dist/modules/wms/commands/shared.js +9 -1
  502. package/dist/modules/wms/commands/shared.js.map +2 -2
  503. package/dist/modules/wms/components/backend/WarehouseEditDialog.js +158 -0
  504. package/dist/modules/wms/components/backend/WarehouseEditDialog.js.map +7 -0
  505. package/dist/modules/wms/components/backend/WmsConfigurationPage.js +76 -111
  506. package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +3 -3
  507. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +1 -0
  508. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
  509. package/dist/modules/wms/components/backend/WmsLotsListPage.js +1 -0
  510. package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
  511. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +27 -20
  512. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +2 -2
  513. package/dist/modules/wms/components/backend/warehouseFormOptions.js +66 -0
  514. package/dist/modules/wms/components/backend/warehouseFormOptions.js.map +7 -0
  515. package/dist/modules/workflows/backend/definitions/page.js +3 -1
  516. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  517. package/dist/modules/workflows/backend/events/page.js +3 -1
  518. package/dist/modules/workflows/backend/events/page.js.map +2 -2
  519. package/dist/modules/workflows/backend/instances/page.js +3 -1
  520. package/dist/modules/workflows/backend/instances/page.js.map +2 -2
  521. package/dist/modules/workflows/backend/tasks/page.js +3 -1
  522. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  523. package/dist/modules/workflows/lib/activity-executor.js +4 -0
  524. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  525. package/package.json +9 -10
  526. package/src/helpers/integration/api.ts +33 -1
  527. package/src/helpers/integration/communicationChannelsFixtures.ts +69 -1
  528. package/src/modules/api_keys/api/keys/route.ts +3 -1
  529. package/src/modules/api_keys/backend/api-keys/page.tsx +4 -1
  530. package/src/modules/api_keys/di.ts +7 -0
  531. package/src/modules/api_keys/services/principalService.ts +33 -0
  532. package/src/modules/attachments/AGENTS.md +15 -0
  533. package/src/modules/attachments/api/route.ts +2 -2
  534. package/src/modules/attachments/components/AttachmentLibrary.tsx +3 -0
  535. package/src/modules/attachments/di.ts +16 -0
  536. package/src/modules/attachments/i18n/de.json +5 -0
  537. package/src/modules/attachments/i18n/en.json +5 -0
  538. package/src/modules/attachments/i18n/es.json +5 -0
  539. package/src/modules/attachments/i18n/ko.json +5 -0
  540. package/src/modules/attachments/i18n/pl.json +5 -0
  541. package/src/modules/attachments/index.ts +10 -0
  542. package/src/modules/attachments/lib/attachment-service.ts +468 -0
  543. package/src/modules/attachments/lib/scoped-upload-service.ts +46 -0
  544. package/src/modules/attachments/lib/upload-limits.ts +6 -2
  545. package/src/modules/audit_logs/backend/audit-logs/page.tsx +8 -0
  546. package/src/modules/audit_logs/lib/display-helpers.tsx +42 -32
  547. package/src/modules/audit_logs/services/actionLogService.ts +74 -11
  548. package/src/modules/auth/acl.ts +30 -6
  549. package/src/modules/auth/api/feature-check.ts +10 -3
  550. package/src/modules/auth/api/login.ts +9 -1
  551. package/src/modules/auth/api/reset/validate.ts +57 -0
  552. package/src/modules/auth/api/roles/acl/route.ts +42 -39
  553. package/src/modules/auth/api/session/refresh.ts +32 -1
  554. package/src/modules/auth/api/users/acl/route.ts +177 -53
  555. package/src/modules/auth/api/users/route.ts +18 -5
  556. package/src/modules/auth/backend/roles/[id]/edit/page.meta.ts +5 -2
  557. package/src/modules/auth/backend/roles/page.tsx +4 -2
  558. package/src/modules/auth/backend/users/[id]/edit/page.meta.ts +5 -2
  559. package/src/modules/auth/backend/users/page.tsx +3 -2
  560. package/src/modules/auth/commands/acl.ts +495 -0
  561. package/src/modules/auth/components/AclEditor.tsx +63 -33
  562. package/src/modules/auth/data/entities.ts +4 -1
  563. package/src/modules/auth/data/validators.ts +5 -0
  564. package/src/modules/auth/di.ts +46 -16
  565. package/src/modules/auth/frontend/reset/[token]/page.tsx +74 -0
  566. package/src/modules/auth/i18n/de.json +389 -0
  567. package/src/modules/auth/i18n/en.json +389 -0
  568. package/src/modules/auth/i18n/es.json +389 -0
  569. package/src/modules/auth/i18n/ko.json +389 -0
  570. package/src/modules/auth/i18n/pl.json +391 -2
  571. package/src/modules/auth/lib/grantChecks.ts +6 -0
  572. package/src/modules/auth/lib/userIdFilter.ts +31 -0
  573. package/src/modules/auth/services/authService.ts +18 -2
  574. package/src/modules/auth/services/principalService.ts +266 -0
  575. package/src/modules/auth/services/rbacService.ts +110 -24
  576. package/src/modules/auth/services/roleOrganizationScope.ts +70 -0
  577. package/src/modules/business_rules/backend/logs/page.tsx +4 -1
  578. package/src/modules/business_rules/backend/rules/page.tsx +4 -1
  579. package/src/modules/business_rules/backend/sets/page.tsx +4 -1
  580. package/src/modules/business_rules/lib/expression-evaluator.ts +9 -9
  581. package/src/modules/business_rules/lib/rule-evaluator.ts +10 -9
  582. package/src/modules/catalog/ai-agents.ts +1 -1
  583. package/src/modules/catalog/ai-tools/merchandising-pack.ts +2 -2
  584. package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +12 -5
  585. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +3 -0
  586. package/src/modules/catalog/components/products/ProductsDataTable.tsx +7 -0
  587. package/src/modules/catalog/i18n/de.json +1 -0
  588. package/src/modules/catalog/i18n/en.json +1 -0
  589. package/src/modules/catalog/i18n/es.json +1 -0
  590. package/src/modules/catalog/i18n/ko.json +1 -0
  591. package/src/modules/catalog/i18n/pl.json +1 -0
  592. package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +4 -0
  593. package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +17 -1
  594. package/src/modules/communication_channels/api/post/test-seed/route.ts +155 -16
  595. package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +4 -0
  596. package/src/modules/communication_channels/commands/ingest-inbound-message.ts +38 -1
  597. package/src/modules/communication_channels/di.ts +7 -0
  598. package/src/modules/communication_channels/lib/adapter.ts +14 -0
  599. package/src/modules/communication_channels/lib/email-capabilities.ts +4 -0
  600. package/src/modules/communication_channels/lib/outbound-recipient.ts +71 -0
  601. package/src/modules/communication_channels/lib/resolve-channel-type.ts +99 -0
  602. package/src/modules/communication_channels/lib/test-seed.ts +64 -4
  603. package/src/modules/configs/i18n/de.json +2 -0
  604. package/src/modules/configs/i18n/en.json +2 -0
  605. package/src/modules/configs/i18n/es.json +2 -0
  606. package/src/modules/configs/i18n/ko.json +2 -0
  607. package/src/modules/configs/i18n/pl.json +2 -0
  608. package/src/modules/configs/lib/system-status.ts +9 -0
  609. package/src/modules/currencies/AGENTS.md +3 -0
  610. package/src/modules/currencies/backend/currencies/page.tsx +4 -1
  611. package/src/modules/currencies/backend/exchange-rates/page.tsx +4 -1
  612. package/src/modules/currencies/services/README.md +45 -0
  613. package/src/modules/currencies/services/rateFetchingService.ts +6 -1
  614. package/src/modules/customer_accounts/api/admin/domain-mappings.ts +7 -0
  615. package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +4 -1
  616. package/src/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.tsx +4 -1
  617. package/src/modules/customer_accounts/services/domainMappingService.ts +10 -0
  618. package/src/modules/customers/ai-tools/companies-pack.ts +4 -1
  619. package/src/modules/customers/ai-tools/deal-analyzer-pack.ts +17 -2
  620. package/src/modules/customers/ai-tools/deals-pack.ts +66 -1
  621. package/src/modules/customers/ai-tools/people-pack.ts +4 -1
  622. package/src/modules/customers/api/activities/route.ts +45 -0
  623. package/src/modules/customers/api/companies/[id]/people/route.ts +24 -73
  624. package/src/modules/customers/api/companies/[id]/route.ts +24 -107
  625. package/src/modules/customers/api/dashboard/widgets/customer-todos/route.ts +16 -8
  626. package/src/modules/customers/api/deals/[id]/companies/route.ts +4 -1
  627. package/src/modules/customers/api/deals/[id]/people/route.ts +4 -1
  628. package/src/modules/customers/api/deals/[id]/route.ts +17 -28
  629. package/src/modules/customers/api/deals/[id]/stats/route.ts +10 -25
  630. package/src/modules/customers/api/deals/aggregate/route.ts +17 -9
  631. package/src/modules/customers/api/deals/map/route.ts +4 -4
  632. package/src/modules/customers/api/deals/route.ts +50 -1
  633. package/src/modules/customers/api/entity-roles-factory.ts +8 -4
  634. package/src/modules/customers/api/interactions/route.ts +8 -2
  635. package/src/modules/customers/api/interactions/tasks/route.ts +24 -1
  636. package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +12 -4
  637. package/src/modules/customers/api/people/[id]/companies/context.ts +4 -1
  638. package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +4 -1
  639. package/src/modules/customers/api/people/[id]/route.ts +16 -11
  640. package/src/modules/customers/api/people/check-phone/route.ts +75 -10
  641. package/src/modules/customers/api/todos/route.ts +27 -2
  642. package/src/modules/customers/backend/customers/companies/page.tsx +5 -2
  643. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +7 -2
  644. package/src/modules/customers/backend/customers/deals/page.tsx +8 -2
  645. package/src/modules/customers/backend/customers/deals/pipeline/components/Lane.tsx +5 -14
  646. package/src/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.tsx +109 -27
  647. package/src/modules/customers/backend/customers/deals/pipeline/components/toneClasses.ts +21 -0
  648. package/src/modules/customers/backend/customers/people/page.tsx +5 -2
  649. package/src/modules/customers/backend/hooks/useEmailDuplicateCheck.ts +12 -4
  650. package/src/modules/customers/commands/deals.ts +34 -59
  651. package/src/modules/customers/commands/interactions.ts +1 -1
  652. package/src/modules/customers/commands/personCompanyLinks.ts +224 -8
  653. package/src/modules/customers/components/CustomerTodosTable.tsx +2 -0
  654. package/src/modules/customers/components/DealsKpiStrip.tsx +7 -7
  655. package/src/modules/customers/components/calendar/AgendaList.tsx +3 -3
  656. package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +1 -1
  657. package/src/modules/customers/components/calendar/CalendarScreen.tsx +1 -1
  658. package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +1 -1
  659. package/src/modules/customers/components/calendar/EventBlock.tsx +2 -2
  660. package/src/modules/customers/components/calendar/EventPeekPopover.tsx +4 -2
  661. package/src/modules/customers/components/calendar/editor/PeopleField.tsx +61 -5
  662. package/src/modules/customers/components/calendar/editor/hooks.ts +7 -1
  663. package/src/modules/customers/components/calendar/types.ts +2 -2
  664. package/src/modules/customers/components/detail/CompanyKpiBar.tsx +5 -4
  665. package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +8 -1
  666. package/src/modules/customers/components/detail/DealForm.tsx +22 -2
  667. package/src/modules/customers/components/detail/DealsSection.tsx +11 -5
  668. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +58 -12
  669. package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +8 -1
  670. package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +23 -14
  671. package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +5 -5
  672. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +5 -5
  673. package/src/modules/customers/components/detail/types.ts +1 -1
  674. package/src/modules/customers/components/detail/utils.ts +15 -5
  675. package/src/modules/customers/data/entities.ts +1 -1
  676. package/src/modules/customers/data/validators.ts +50 -9
  677. package/src/modules/customers/events.ts +5 -0
  678. package/src/modules/customers/i18n/de.json +9 -1
  679. package/src/modules/customers/i18n/en.json +9 -1
  680. package/src/modules/customers/i18n/es.json +9 -1
  681. package/src/modules/customers/i18n/ko.json +9 -1
  682. package/src/modules/customers/i18n/pl.json +9 -1
  683. package/src/modules/customers/lib/calendar/conflicts.ts +10 -2
  684. package/src/modules/customers/lib/calendar/editorPayload.ts +4 -3
  685. package/src/modules/customers/lib/calendar/mapItem.ts +8 -3
  686. package/src/modules/customers/lib/calendar/participantIdentity.ts +17 -0
  687. package/src/modules/customers/lib/closureStage.ts +76 -0
  688. package/src/modules/customers/lib/dealStatus.ts +42 -0
  689. package/src/modules/customers/lib/detailReadAccess.ts +35 -0
  690. package/src/modules/customers/lib/findPeopleByAddresses.ts +8 -6
  691. package/src/modules/customers/lib/personCompanies.ts +136 -1
  692. package/src/modules/customers/lib/todoCompatibility.ts +19 -1
  693. package/src/modules/dashboards/i18n/es.json +4 -4
  694. package/src/modules/dashboards/i18n/pl.json +7 -7
  695. package/src/modules/dashboards/lib/widgetScope.ts +6 -0
  696. package/src/modules/data_sync/AGENTS.md +1 -1
  697. package/src/modules/data_sync/backend/data-sync/page.tsx +4 -1
  698. package/src/modules/data_sync/lib/abandoned-run.ts +56 -0
  699. package/src/modules/data_sync/lib/adapter.ts +36 -0
  700. package/src/modules/data_sync/lib/sync-engine.ts +113 -5
  701. package/src/modules/data_sync/workers/sync-export.ts +4 -0
  702. package/src/modules/data_sync/workers/sync-import.ts +4 -0
  703. package/src/modules/devices/AGENTS.md +20 -1
  704. package/src/modules/devices/acl.ts +9 -1
  705. package/src/modules/devices/api/admin/devices/[id]/route.ts +5 -34
  706. package/src/modules/devices/api/admin/devices/route.ts +14 -1
  707. package/src/modules/devices/api/deviceList.ts +135 -11
  708. package/src/modules/devices/api/deviceSerialization.ts +50 -0
  709. package/src/modules/devices/api/openapi.ts +9 -1
  710. package/src/modules/devices/api/route.ts +9 -1
  711. package/src/modules/devices/backend/devices/[id]/page.tsx +18 -32
  712. package/src/modules/devices/backend/devices/create/page.tsx +17 -1
  713. package/src/modules/devices/backend/devices/page.tsx +44 -45
  714. package/src/modules/devices/backend/devices/useDeviceUserLabels.ts +45 -0
  715. package/src/modules/devices/backend/devices/userOptions.ts +99 -0
  716. package/src/modules/devices/i18n/de.json +3 -2
  717. package/src/modules/devices/i18n/en.json +3 -2
  718. package/src/modules/devices/i18n/es.json +3 -2
  719. package/src/modules/devices/i18n/ko.json +3 -2
  720. package/src/modules/devices/i18n/pl.json +3 -2
  721. package/src/modules/devices/setup.ts +6 -2
  722. package/src/modules/directory/backend/directory/organizations/page.tsx +3 -1
  723. package/src/modules/directory/backend/directory/tenants/page.tsx +3 -1
  724. package/src/modules/directory/di.ts +14 -2
  725. package/src/modules/directory/services/organizationHierarchyService.ts +34 -0
  726. package/src/modules/directory/services/organizationScopeService.ts +85 -0
  727. package/src/modules/directory/utils/organizationScope.ts +4 -15
  728. package/src/modules/entities/api/records.ts +2 -0
  729. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +4 -1
  730. package/src/modules/eudr/api/plots/route.ts +4 -0
  731. package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +4 -0
  732. package/src/modules/eudr/backend/eudr/plots/page.tsx +4 -0
  733. package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +4 -0
  734. package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +4 -0
  735. package/src/modules/eudr/backend/eudr/statements/page.tsx +4 -0
  736. package/src/modules/eudr/commands/statements.ts +0 -3
  737. package/src/modules/eudr/data/validators.ts +16 -1
  738. package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +2 -1
  739. package/src/modules/feature_toggles/components/OverridesTable.tsx +2 -1
  740. package/src/modules/feature_toggles/defaults.json +0 -8
  741. package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +4 -0
  742. package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +4 -0
  743. package/src/modules/inbox_ops/lib/htmlToPlainText.ts +1 -17
  744. package/src/modules/integrations/api/[id]/credentials/route.ts +6 -4
  745. package/src/modules/integrations/backend/integrations/[id]/page.tsx +61 -31
  746. package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +44 -9
  747. package/src/modules/integrations/backend/integrations/credential-secret-fields.ts +84 -0
  748. package/src/modules/integrations/data/validators.ts +12 -2
  749. package/src/modules/integrations/i18n/de.json +1 -0
  750. package/src/modules/integrations/i18n/en.json +1 -0
  751. package/src/modules/integrations/i18n/es.json +1 -0
  752. package/src/modules/integrations/i18n/ko.json +1 -0
  753. package/src/modules/integrations/i18n/pl.json +1 -0
  754. package/src/modules/integrations/lib/credentials-masking.ts +10 -6
  755. package/src/modules/messages/api/[id]/route.ts +55 -1
  756. package/src/modules/messages/api/openapi.ts +20 -0
  757. package/src/modules/messages/api/route.ts +31 -2
  758. package/src/modules/messages/components/MessagesInboxPageClient.tsx +9 -16
  759. package/src/modules/messages/components/inboxFilters.ts +36 -0
  760. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +14 -1
  761. package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +3 -1
  762. package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +2 -1
  763. package/src/modules/messages/components/message-detail/types.ts +3 -0
  764. package/src/modules/messages/components/messageListLabels.ts +52 -3
  765. package/src/modules/messages/data/validators.ts +43 -4
  766. package/src/modules/messages/lib/channel-sender-identity.ts +55 -0
  767. package/src/modules/messages/lib/composeSourceChannelType.ts +95 -0
  768. package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +4 -6
  769. package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +4 -1
  770. package/src/modules/payment_gateways/lib/webhook-processor.ts +11 -0
  771. package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +4 -0
  772. package/src/modules/push_notifications/backend/push_notifications/page.tsx +4 -1
  773. package/src/modules/push_notifications/backend/push_notifications/send/page.tsx +4 -4
  774. package/src/modules/query_index/lib/engine.ts +249 -61
  775. package/src/modules/query_index/lib/search-entity-policy.ts +46 -0
  776. package/src/modules/query_index/lib/search-tokens.ts +135 -3
  777. package/src/modules/resources/backend/resources/resource-types/page.tsx +4 -1
  778. package/src/modules/resources/backend/resources/resources/page.tsx +4 -1
  779. package/src/modules/sales/backend/sales/channels/offers/page.tsx +4 -0
  780. package/src/modules/sales/backend/sales/channels/page.tsx +4 -0
  781. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +14 -8
  782. package/src/modules/sales/commands/documents.ts +93 -0
  783. package/src/modules/sales/components/PriceWithCurrency.tsx +17 -5
  784. package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +4 -0
  785. package/src/modules/sales/components/documents/AdjustmentsSection.tsx +6 -5
  786. package/src/modules/sales/components/documents/ItemsSection.tsx +56 -18
  787. package/src/modules/sales/components/documents/LineItemDialog.tsx +137 -20
  788. package/src/modules/sales/components/documents/PaymentsSection.tsx +20 -9
  789. package/src/modules/sales/components/documents/ReturnsSection.tsx +6 -5
  790. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +106 -14
  791. package/src/modules/sales/components/documents/SalesOrderDraftLines.tsx +6 -5
  792. package/src/modules/sales/components/documents/ShipmentDialog.tsx +5 -4
  793. package/src/modules/sales/components/documents/ShipmentsSection.tsx +6 -5
  794. package/src/modules/sales/components/documents/lineItemShipmentLock.ts +74 -0
  795. package/src/modules/sales/components/documents/lineItemUtils.ts +7 -2
  796. package/src/modules/sales/data/entities.ts +6 -0
  797. package/src/modules/sales/extension-points.ts +1 -0
  798. package/src/modules/sales/i18n/de.json +8 -0
  799. package/src/modules/sales/i18n/en.json +8 -0
  800. package/src/modules/sales/i18n/es.json +8 -0
  801. package/src/modules/sales/i18n/ko.json +8 -0
  802. package/src/modules/sales/i18n/pl.json +8 -0
  803. package/src/modules/sales/lib/salesChannelsToggleSeed.ts +42 -0
  804. package/src/modules/sales/migrations/.snapshot-open-mercato.json +60 -0
  805. package/src/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.ts +87 -0
  806. package/src/modules/sales/setup.ts +2 -0
  807. package/src/modules/sales/widgets/injection/payment-gateway-status-column/widget.ts +9 -1
  808. package/src/modules/sales/widgets/injection-table.ts +4 -7
  809. package/src/modules/staff/backend/staff/leave-requests/page.tsx +4 -0
  810. package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +4 -0
  811. package/src/modules/staff/backend/staff/team-members/page.tsx +6 -0
  812. package/src/modules/staff/backend/staff/team-roles/page.tsx +4 -0
  813. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +4 -0
  814. package/src/modules/staff/backend/staff/teams/page.tsx +4 -0
  815. package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1
  816. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +4 -0
  817. package/src/modules/sync_excel/lib/adapters/customers.ts +5 -0
  818. package/src/modules/warranty_claims/api/assignees/route.ts +3 -3
  819. package/src/modules/warranty_claims/api/portal/attachments/route.ts +2 -2
  820. package/src/modules/warranty_claims/api/portal/claims/route.ts +12 -9
  821. package/src/modules/warranty_claims/backend/page.tsx +4 -0
  822. package/src/modules/warranty_claims/backend/warranty_claims/registrations/page.tsx +4 -0
  823. package/src/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.tsx +4 -0
  824. package/src/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.tsx +4 -0
  825. package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.tsx +4 -0
  826. package/src/modules/wms/api/warehouseSearch.ts +23 -0
  827. package/src/modules/wms/api/warehouses/route.ts +13 -9
  828. package/src/modules/wms/api/zones/route.ts +16 -0
  829. package/src/modules/wms/commands/configuration.ts +159 -10
  830. package/src/modules/wms/commands/inventory-actions.ts +3 -0
  831. package/src/modules/wms/commands/shared.ts +17 -0
  832. package/src/modules/wms/components/backend/WarehouseEditDialog.tsx +216 -0
  833. package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +95 -141
  834. package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +2 -0
  835. package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -0
  836. package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +36 -20
  837. package/src/modules/wms/components/backend/warehouseFormOptions.ts +72 -0
  838. package/src/modules/wms/i18n/de.json +2 -0
  839. package/src/modules/wms/i18n/en.json +2 -0
  840. package/src/modules/wms/i18n/es.json +2 -0
  841. package/src/modules/wms/i18n/ko.json +2 -0
  842. package/src/modules/wms/i18n/pl.json +2 -0
  843. package/src/modules/workflows/backend/definitions/page.tsx +4 -1
  844. package/src/modules/workflows/backend/events/page.tsx +4 -1
  845. package/src/modules/workflows/backend/instances/page.tsx +4 -1
  846. package/src/modules/workflows/backend/tasks/page.tsx +4 -1
  847. package/src/modules/workflows/lib/activity-executor.ts +9 -0
@@ -38,7 +38,7 @@ import type { EntityId } from '@open-mercato/shared/modules/entities'
38
38
  import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
39
39
  import { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
40
40
  import { parseBooleanFromUnknown, parseBooleanToken } from '@open-mercato/shared/lib/boolean'
41
- import { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'
41
+ import { denyCustomerDetailReadAsNotFound } from '../../../lib/detailReadAccess'
42
42
  import { loadPersonCompanyLinks, summarizePersonCompanies } from '../../../lib/personCompanies'
43
43
  import { normalizeCustomerDetailCustomFields } from '../../detailCustomFields'
44
44
  import { buildEmailVisibilityMikroFilter } from '../../../lib/visibilityFilter'
@@ -129,10 +129,6 @@ function parseIncludeParams(request: Request): Set<string> {
129
129
  return tokens
130
130
  }
131
131
 
132
- function forbidden(message: string) {
133
- return NextResponse.json({ error: message }, { status: 403 })
134
- }
135
-
136
132
  function notFound(message: string) {
137
133
  return NextResponse.json({ error: message }, { status: 404 })
138
134
  }
@@ -542,10 +538,19 @@ export async function GET(_req: Request, ctx: { params?: { id?: string } }) {
542
538
  return notFound('Person not found')
543
539
  }
544
540
 
545
- if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: person.organizationId })) {
546
- statusCode = 403
547
- profileMeta = { reason: 'organization_forbidden' }
548
- return forbidden('Access denied')
541
+ // Existence oracle (issue #5504): a caller who holds customers.people.view
542
+ // but whose scope excludes the record's organization must get the SAME
543
+ // response as for a non-existent id, so 403-when-present / 404-when-absent
544
+ // collapses to a uniform 404 not-found. The dispatcher already returns a
545
+ // uniform 403 for callers who lack the feature entirely.
546
+ const organizationReadDenied = denyCustomerDetailReadAsNotFound(
547
+ { scope, auth, organizationId: person.organizationId },
548
+ 'Person not found',
549
+ )
550
+ if (organizationReadDenied) {
551
+ statusCode = 404
552
+ profileMeta = { reason: 'organization_not_in_scope' }
553
+ return organizationReadDenied
549
554
  }
550
555
 
551
556
  // Gated get-then-set cache. Key on the resolved person plus the effective
@@ -1337,8 +1342,8 @@ export const openApi: OpenApiRouteDoc = {
1337
1342
  errors: [
1338
1343
  { status: 400, description: 'Invalid identifier', schema: personDetailErrorSchema },
1339
1344
  { status: 401, description: 'Unauthorized', schema: personDetailErrorSchema },
1340
- { status: 403, description: 'Forbidden for tenant/organization scope', schema: personDetailErrorSchema },
1341
- { status: 404, description: 'Person not found', schema: personDetailErrorSchema },
1345
+ { status: 403, description: 'Forbidden caller lacks the required feature', schema: personDetailErrorSchema },
1346
+ { status: 404, description: 'Person not found, or its organization is not in the caller’s scope', schema: personDetailErrorSchema },
1342
1347
  ],
1343
1348
  },
1344
1349
  },
@@ -3,9 +3,12 @@ import { z } from 'zod'
3
3
  import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
4
4
  import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
5
5
  import { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'
6
- import type { EntityManager } from '@mikro-orm/postgresql'
6
+ import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'
7
7
  import { CustomerEntity } from '../../../data/entities'
8
8
  import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
9
+ import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
10
+ import { isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'
11
+ import { MATCH_CANDIDATE_LIMIT } from '../../../lib/findPeopleByAddresses'
9
12
 
10
13
  const querySchema = z.object({
11
14
  digits: z
@@ -18,6 +21,10 @@ export const metadata = {
18
21
  GET: { requireAuth: true, requireFeatures: ['customers.people.view'] },
19
22
  }
20
23
 
24
+ function normalizePhoneDigits(value: string | null | undefined): string {
25
+ return typeof value === 'string' ? value.replace(/\D/g, '') : ''
26
+ }
27
+
21
28
  export async function GET(req: Request) {
22
29
  const url = new URL(req.url)
23
30
  const rawQuery: Record<string, string | null> = { digits: url.searchParams.get('digits') }
@@ -45,18 +52,76 @@ export async function GET(req: Request) {
45
52
  return NextResponse.json({ match: null })
46
53
  }
47
54
 
48
- const qb = em.createQueryBuilder(CustomerEntity, 'person')
49
- qb.select(['person.id', 'person.displayName'])
50
- qb.where({ kind: 'person', deletedAt: null })
51
- qb.andWhere('person.primary_phone is not null')
52
- qb.andWhere("regexp_replace(person.primary_phone, '\\D', '', 'g') = ?", [parse.data.digits])
55
+ // SQL fast path, gated on the encryption toggle: it can only match stored
56
+ // plaintext digits, so running it while tenant data encryption is enabled
57
+ // (the default) would pay a per-row scan that provably returns nothing.
58
+ // When encryption is off it serves the pre-encryption single-query behavior,
59
+ // including legacy plaintext rows. Encrypted rows written before the toggle
60
+ // was turned off are not resolvable by either path by design; plaintext
61
+ // legacy rows under an enabled toggle still resolve through the decrypted
62
+ // scan below, where decryption no-ops on non-ciphertext values.
63
+ if (!isTenantDataEncryptionEnabled()) {
64
+ const qb = em.createQueryBuilder(CustomerEntity, 'person')
65
+ qb.select(['person.id', 'person.displayName'])
66
+ qb.where({ kind: 'person', deletedAt: null })
67
+ qb.andWhere('person.primary_phone is not null')
68
+ qb.andWhere("regexp_replace(person.primary_phone, '\\D', '', 'g') = ?", [parse.data.digits])
69
+ if (auth.tenantId) {
70
+ qb.andWhere({ tenantId: auth.tenantId })
71
+ }
72
+ qb.andWhere({ organizationId: { $in: Array.from(allowedOrgIds) } })
73
+ qb.limit(1)
74
+
75
+ const fastMatch = await qb.getSingleResult()
76
+ if (fastMatch) {
77
+ return NextResponse.json({
78
+ match: {
79
+ id: fastMatch.id,
80
+ displayName: fastMatch.displayName,
81
+ },
82
+ })
83
+ }
84
+ }
85
+
86
+ // Encryption-on path: primary_phone holds random-IV ciphertext, so digit
87
+ // normalization must run in application code over decrypted rows instead of
88
+ // SQL against the stored column (issue #3840).
89
+ // Encryption-on path: primary_phone holds random-IV ciphertext, so digit
90
+ // normalization must run in application code over decrypted rows instead of
91
+ // SQL against the stored column (issue #3840). The scan is bounded newest-
92
+ // first and projected to the columns the route uses plus tenantId/
93
+ // organizationId, which the decryption path reads per row to resolve each
94
+ // row's own key (a request-level fallback cannot cover multi-org scans or
95
+ // null-tenant sessions). A primary_phone blind index is the exact O(1)
96
+ // follow-up (#5515).
97
+ const where: FilterQuery<CustomerEntity> = {
98
+ kind: 'person',
99
+ deletedAt: null,
100
+ primaryPhone: { $ne: null },
101
+ organizationId: { $in: Array.from(allowedOrgIds) },
102
+ }
53
103
  if (auth.tenantId) {
54
- qb.andWhere({ tenantId: auth.tenantId })
104
+ where.tenantId = auth.tenantId
55
105
  }
56
- qb.andWhere({ organizationId: { $in: Array.from(allowedOrgIds) } })
57
- qb.limit(1)
58
106
 
59
- const match = await qb.getSingleResult()
107
+ const candidates = await findWithDecryption(
108
+ em,
109
+ CustomerEntity,
110
+ where,
111
+ {
112
+ limit: MATCH_CANDIDATE_LIMIT,
113
+ orderBy: { createdAt: 'DESC' },
114
+ fields: ['id', 'displayName', 'primaryPhone', 'tenantId', 'organizationId'],
115
+ },
116
+ {
117
+ tenantId: auth.tenantId ?? null,
118
+ organizationId: scope?.selectedId ?? auth.orgId ?? null,
119
+ },
120
+ )
121
+
122
+ const match = candidates.find(
123
+ (candidate) => normalizePhoneDigits(candidate.primaryPhone) === parse.data.digits,
124
+ )
60
125
  if (!match) {
61
126
  return NextResponse.json({ match: null })
62
127
  }
@@ -9,6 +9,7 @@ import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
9
9
  import type { CommandBus } from '@open-mercato/shared/lib/commands'
10
10
  import { isCrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'
11
11
  import { parseBooleanToken } from '@open-mercato/shared/lib/boolean'
12
+ import { isUnrestrictedOrganizationScope } from '@open-mercato/shared/lib/auth/organizationAccess'
12
13
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
13
14
  import {
14
15
  runCrudMutationGuardAfterSuccess,
@@ -233,15 +234,36 @@ async function resolveCanonicalTodoTargetId(
233
234
 
234
235
  export async function GET(request: Request): Promise<Response> {
235
236
  try {
236
- const { auth, em, organizationIds, container, selectedOrganizationId } =
237
+ const { auth, em, organizationIds, container, selectedOrganizationId, scope } =
237
238
  await resolveCustomersRequestContext(request)
238
239
  const query = querySchema.parse(Object.fromEntries(new URL(request.url).searchParams))
239
240
  const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)
240
241
  if (!flags.legacyAdapters) {
241
242
  return await legacyAdaptersDisabledResponse()
242
243
  }
243
- const queryEngine = container.resolve('queryEngine') as QueryEngine
244
244
  const exportAll = parseBooleanToken(query.all) === true
245
+ const isUnrestricted = isUnrestrictedOrganizationScope({
246
+ isSuperAdmin: auth.isSuperAdmin === true,
247
+ allowedOrganizationIds: scope?.allowedIds,
248
+ })
249
+ if (!isUnrestricted && (!organizationIds || organizationIds.length === 0)) {
250
+ logger.warn('customers.todos.list collapsed organization scope', {
251
+ tenantId: auth.tenantId,
252
+ organizationIds,
253
+ selectedId: scope?.selectedId ?? null,
254
+ allowedIdsCount: scope?.allowedIds?.length ?? null,
255
+ })
256
+ return withAdapterHeaders(
257
+ NextResponse.json({
258
+ items: [],
259
+ total: 0,
260
+ page: exportAll ? 1 : query.page,
261
+ pageSize: exportAll ? 0 : query.pageSize,
262
+ totalPages: 1,
263
+ }),
264
+ )
265
+ }
266
+ const queryEngine = container.resolve('queryEngine') as QueryEngine
245
267
  const search = normalizeTodoSearch(query.search)
246
268
 
247
269
  if (flags.unified) {
@@ -255,6 +277,7 @@ export async function GET(request: Request): Promise<Response> {
255
277
  entityId: query.entityId,
256
278
  pagination: exportAll ? null : { page: query.page, pageSize: query.pageSize },
257
279
  searchText: search,
280
+ isUnrestricted,
258
281
  },
259
282
  )
260
283
  const total = canonical.total
@@ -275,6 +298,7 @@ export async function GET(request: Request): Promise<Response> {
275
298
  const [legacyRows, canonicalRows] = await Promise.all([
276
299
  listLegacyTodoRows(em, queryEngine, auth.tenantId, organizationIds, query.entityId, {
277
300
  limit: legacyWindow,
301
+ isUnrestricted,
278
302
  }),
279
303
  listCanonicalTodoRows(
280
304
  em,
@@ -287,6 +311,7 @@ export async function GET(request: Request): Promise<Response> {
287
311
  includeDeleted: true,
288
312
  source: CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE,
289
313
  limit: legacyWindow,
314
+ isUnrestricted,
290
315
  },
291
316
  ),
292
317
  ])
@@ -118,6 +118,7 @@ type CompaniesResponse = {
118
118
  total?: number
119
119
  page?: number
120
120
  totalPages?: number
121
+ totalIsCapped?: boolean
121
122
  }
122
123
 
123
124
  type DictionaryKindKey = CustomerDictionaryKind
@@ -198,9 +199,10 @@ export default function CustomersCompaniesPage() {
198
199
  const [sorting, setSorting] = React.useState<SortingState>([])
199
200
  const [total, setTotal] = React.useState(0)
200
201
  const [totalPages, setTotalPages] = React.useState(1)
201
- const [search, setSearch] = React.useState('')
202
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false)
202
203
  const pathname = usePathname()
203
204
  const searchParams = useSearchParams()
205
+ const [search, setSearch] = React.useState(() => searchParams?.get('search')?.trim() ?? '')
204
206
  // One-shot URL hydration used as the hook's initial value. The hook is the
205
207
  // single source of truth from this point on — the page MUST NOT keep a
206
208
  // parallel `useState<AdvancedFilterTree>` (see spec "Migration & Backward
@@ -422,6 +424,7 @@ export default function CustomersCompaniesPage() {
422
424
  setRows(items.map((item) => mapApiItem(item as Record<string, unknown>)).filter((row): row is CompanyRow => !!row))
423
425
  setTotal(typeof payload.total === 'number' ? payload.total : items.length)
424
426
  setTotalPages(typeof payload.totalPages === 'number' ? payload.totalPages : 1)
427
+ setTotalIsCapped(payload?.totalIsCapped === true)
425
428
  } catch (err) {
426
429
  if (!cancelled) {
427
430
  setCacheStatus(null)
@@ -963,7 +966,7 @@ export default function CustomersCompaniesPage() {
963
966
  />
964
967
  )}
965
968
  virtualized
966
- pagination={{ page, pageSize, total, totalPages, onPageChange: setPage, pageSizeOptions: [10, 25, 50, 100], onPageSizeChange: handlePageSizeChange, cacheStatus }}
969
+ pagination={{ page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage, pageSizeOptions: [10, 25, 50, 100], onPageSizeChange: handlePageSizeChange, cacheStatus }}
967
970
  isLoading={isLoading}
968
971
  />
969
972
  <AdvancedFilterPanel
@@ -3,7 +3,7 @@
3
3
  import * as React from 'react'
4
4
  import { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'
5
5
  import Link from 'next/link'
6
- import { Building2, UserSearch, Users } from 'lucide-react'
6
+ import { Building2, FileText, Hash, UserSearch, Users } from 'lucide-react'
7
7
  import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
8
8
  import { useRouter, useSearchParams, usePathname } from 'next/navigation'
9
9
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
@@ -12,7 +12,7 @@ import { AttachmentsSection, ErrorMessage, LoadingMessage, NotesSection, RecordN
12
12
  import { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'
13
13
  import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'
14
14
  import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
15
- import { CollapsibleZoneLayout } from '@open-mercato/ui/backend/crud/CollapsibleZoneLayout'
15
+ import { CollapsibleZoneLayout, type ZoneSectionDescriptor } from '@open-mercato/ui/backend/crud/CollapsibleZoneLayout'
16
16
  import { useT } from '@open-mercato/shared/lib/i18n/context'
17
17
  import { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'
18
18
  import { E } from '#generated/entities.ids.generated'
@@ -57,6 +57,10 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
57
57
  const pathname = usePathname()
58
58
  const { confirm, ConfirmDialogElement } = useConfirmDialog()
59
59
  const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t])
60
+ const zoneSections = React.useMemo<ZoneSectionDescriptor[]>(() => [
61
+ { id: 'details', icon: FileText, label: t('customers.people.detail.deals.form.details', 'Deal details') },
62
+ { id: 'custom', icon: Hash, label: t('customers.people.detail.deals.form.customFields', 'Custom fields') },
63
+ ], [t])
60
64
 
61
65
  const { data, setData, isLoading, error, isNotFound, loadData } = useDealData(id)
62
66
  const [isDirty, setIsDirty] = React.useState(false)
@@ -664,6 +668,7 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
664
668
  pageType="deal-detail-v3"
665
669
  entityName={dealName}
666
670
  isDirty={isDirty}
671
+ sections={zoneSections}
667
672
  zone1DefaultWidth="540px"
668
673
  zone1={zone1Content}
669
674
  zone2={zone2Content}
@@ -125,6 +125,7 @@ type DealsResponse = {
125
125
  items?: Array<Record<string, unknown>>
126
126
  total?: number
127
127
  totalPages?: number
128
+ totalIsCapped?: boolean
128
129
  }
129
130
 
130
131
  type FilterOption = { value: string; label: string }
@@ -210,6 +211,7 @@ export default function CustomersDealsPage() {
210
211
  const [sorting, setSorting] = React.useState<import('@tanstack/react-table').SortingState>([])
211
212
  const [total, setTotal] = React.useState(0)
212
213
  const [totalPages, setTotalPages] = React.useState(1)
214
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false)
213
215
  const [search, setSearch] = React.useState(() => searchParams?.get('search')?.trim() ?? '')
214
216
  const [isLoading, setIsLoading] = React.useState(false)
215
217
  const [reloadToken, setReloadToken] = React.useState(0)
@@ -397,6 +399,7 @@ export default function CustomersDealsPage() {
397
399
  setRows(mapped)
398
400
  setTotal(typeof payload.total === 'number' ? payload.total : mapped.length)
399
401
  setTotalPages(typeof payload.totalPages === 'number' ? payload.totalPages : 1)
402
+ setTotalIsCapped(payload.totalIsCapped === true)
400
403
  } catch (err) {
401
404
  if (!cancelled) {
402
405
  setCacheStatus(null)
@@ -412,10 +415,12 @@ export default function CustomersDealsPage() {
412
415
  }, [queryParams, reloadToken, scopeVersion, t])
413
416
 
414
417
  React.useEffect(() => {
415
- if (totalPages > 0 && page > totalPages) {
418
+ // A capped totalPages is a floor pages past it hold reachable rows, so
419
+ // clamping would bounce a deep-linked user off data that exists.
420
+ if (!totalIsCapped && totalPages > 0 && page > totalPages) {
416
421
  setPage(totalPages)
417
422
  }
418
- }, [page, totalPages])
423
+ }, [page, totalPages, totalIsCapped])
419
424
 
420
425
  const queryRef = React.useRef(searchParams?.toString() ?? '')
421
426
  React.useEffect(() => {
@@ -1136,6 +1141,7 @@ export default function CustomersDealsPage() {
1136
1141
  pageSize,
1137
1142
  total,
1138
1143
  totalPages,
1144
+ totalIsCapped,
1139
1145
  onPageChange: (nextPage) => setPage(nextPage),
1140
1146
  pageSizeOptions: [10, 25, 50, 100],
1141
1147
  onPageSizeChange: handlePageSizeChange,
@@ -7,6 +7,7 @@ import type { RowActionItem } from '@open-mercato/ui/backend/RowActions'
7
7
  import { useT } from '@open-mercato/shared/lib/i18n/context'
8
8
  import { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'
9
9
  import type { FilterOptionTone } from '@open-mercato/shared/lib/query/advanced-filter'
10
+ import { toneToDotClass } from './toneClasses'
10
11
  import { DealCard, type DealCardData } from './DealCard'
11
12
  import { DashedTileButton } from './DashedTileButton'
12
13
  import { LANE_WIDTH_PX } from './constants'
@@ -52,15 +53,10 @@ type LaneProps = {
52
53
  onResetWidth?: (stageId: string) => void
53
54
  }
54
55
 
55
- // 4px color bar tone — uses saturated icon tokens so the bar is visibly colored, not pale
56
- const ACCENT_TONE_CLASS: Record<FilterOptionTone, string> = {
57
- success: 'bg-status-success-icon',
58
- error: 'bg-status-error-icon',
59
- warning: 'bg-status-warning-icon',
60
- info: 'bg-status-info-icon',
61
- neutral: 'bg-status-neutral-icon',
62
- brand: 'bg-brand-violet',
63
- pink: 'bg-status-pink-icon',
56
+ // 4px color bar tone — saturated icon tokens shared with the status filter pills
57
+ // (toneClasses.ts) so the lane bar and the filter dots stay in lockstep (#5107 review).
58
+ function getAccentClass(tone: FilterOptionTone | null): string {
59
+ return toneToDotClass(tone, 'bg-border')
64
60
  }
65
61
 
66
62
  // Count pill bg uses very-light status background, text uses status text color
@@ -74,11 +70,6 @@ const COUNT_BADGE_TONE_CLASS: Record<FilterOptionTone, string> = {
74
70
  pink: 'bg-status-pink-bg text-status-pink-text',
75
71
  }
76
72
 
77
- function getAccentClass(tone: FilterOptionTone | null): string {
78
- if (tone && tone in ACCENT_TONE_CLASS) return ACCENT_TONE_CLASS[tone]
79
- return 'bg-border'
80
- }
81
-
82
73
  function getCountBadgeClass(tone: FilterOptionTone | null): string {
83
74
  if (tone && tone in COUNT_BADGE_TONE_CLASS) return COUNT_BADGE_TONE_CLASS[tone]
84
75
  return 'bg-muted text-muted-foreground'
@@ -10,45 +10,70 @@ import {
10
10
  } from '@open-mercato/ui/primitives/popover'
11
11
  import { useT } from '@open-mercato/shared/lib/i18n/context'
12
12
  import { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'
13
+ import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
14
+ import { mapDictionaryColorToTone } from '@open-mercato/shared/lib/query/advanced-filter'
15
+ import { Spinner } from '@open-mercato/ui/primitives/spinner'
16
+ import { useCustomerDictionary } from '../../../../../components/detail/hooks/useCustomerDictionary'
17
+ import { canonicalDealStatus } from '../../../../../lib/dealStatus'
18
+ import { toneToDotClass } from './toneClasses'
13
19
  import { ChipButton } from './ChipButton'
14
20
  import { FilterPopoverShell } from './FilterPopoverShell'
15
21
 
16
22
  /**
17
23
  * Filter options exposed to the operator.
18
24
  *
19
- * The deal `status` column accepts the historical 4-value enum (`open` | `closed` | `win` |
20
- * `loose`), but the codebase only ever **writes** `loose` for a lost deal — `closed` was a
21
- * latent unused state from an earlier iteration. Exposing a separate "Lost (closed)" filter
22
- * option therefore filtered to nothing and confused operators. We display a single "Lost"
23
- * choice and intentionally map it to the canonical wire value `loose` so the filter matches
24
- * what the rest of the app actually persists. (Renaming the column / migrating the data to
25
- * `lost` is a deeper data-model change tracked separately.)
25
+ * The deal `status` column is dictionary-driven (`deal-statuses`); the seeded dictionary
26
+ * carries five values (`open`, `closed`, `win`, `loose`, `in_progress`) plus any
27
+ * tenant-custom entries. We render every dictionary entry de-duplicated by canonical
28
+ * spelling so the kanban Status pill stays aligned with the list page's advanced filter
29
+ * (which also uses the dictionary). A hard-coded fallback keeps the popover usable while
30
+ * the dictionary is loading or when a tenant has no entries.
31
+ *
32
+ * `won` / `lost` are accepted as aliases for `win` / `loose` at the API layer (see
33
+ * `lib/dealStatus.ts:expandDealStatusAliases`, shared by the deals list route and the
34
+ * kanban aggregate route). The UI only exposes the canonical values to avoid duplicate
35
+ * pills, but `canonicalDealStatus` normalizes any alias passed in through `values` so
36
+ * the chip and draft selection render the correct label.
26
37
  */
27
- const STATUS_OPTIONS: Array<{
38
+ const FALLBACK_STATUS_OPTIONS: Array<{
28
39
  value: string
29
40
  labelKey: string
30
41
  labelFallback: string
31
- /** Tone selects the small ●-dot color on the pill (per Figma: green / amber / gray) */
32
42
  dotClass: string
33
43
  }> = [
34
44
  {
35
45
  value: 'open',
36
46
  labelKey: 'customers.deals.kanban.filter.status.open',
37
47
  labelFallback: 'Open',
38
- dotClass: 'bg-status-success-icon',
48
+ // Tones mirror mapDictionaryColorToTone over the seeded dictionary colors
49
+ // (#2563eb → info, #22c55e → success, #ef4444 → error) so the fallback pills
50
+ // render identically to the dictionary-driven ones.
51
+ dotClass: 'bg-status-info-icon',
39
52
  },
40
53
  {
41
54
  value: 'win',
42
55
  labelKey: 'customers.deals.kanban.filter.status.won',
43
56
  labelFallback: 'Won',
44
- dotClass: 'bg-status-warning-icon',
57
+ dotClass: 'bg-status-success-icon',
45
58
  },
46
59
  {
47
60
  value: 'loose',
48
61
  labelKey: 'customers.deals.kanban.filter.status.lost',
49
62
  labelFallback: 'Lost',
63
+ dotClass: 'bg-status-error-icon',
64
+ },
65
+ {
66
+ value: 'closed',
67
+ labelKey: 'customers.deals.kanban.filter.status.closed',
68
+ labelFallback: 'Closed',
50
69
  dotClass: 'bg-status-neutral-icon',
51
70
  },
71
+ {
72
+ value: 'in_progress',
73
+ labelKey: 'customers.deals.kanban.filter.status.inProgress',
74
+ labelFallback: 'In progress',
75
+ dotClass: 'bg-status-warning-icon',
76
+ },
52
77
  ]
53
78
 
54
79
  type StatusFilterPopoverProps = {
@@ -58,29 +83,75 @@ type StatusFilterPopoverProps = {
58
83
 
59
84
  export function StatusFilterPopover({ values, onApply }: StatusFilterPopoverProps): React.ReactElement {
60
85
  const t = useT()
86
+ const scopeVersion = useOrganizationScopeVersion()
87
+ const { data: dictionaryData, isLoading: dictionaryLoading } = useCustomerDictionary(
88
+ 'deal-statuses',
89
+ scopeVersion,
90
+ )
61
91
  const [open, setOpen] = React.useState(false)
62
- const [draft, setDraft] = React.useState<string[]>(values)
92
+ const normalizedValues = React.useMemo(
93
+ () => Array.from(new Set(values.map(canonicalDealStatus))),
94
+ [values],
95
+ )
96
+ const [draft, setDraft] = React.useState<string[]>(normalizedValues)
63
97
 
64
98
  React.useEffect(() => {
65
- if (open) setDraft(values)
66
- }, [open, values])
99
+ if (open) setDraft(normalizedValues)
100
+ }, [open, normalizedValues])
101
+
102
+ const statusOptions = React.useMemo(() => {
103
+ const entries = dictionaryData?.entries
104
+ if (entries && entries.length > 0) {
105
+ const byCanonical = new Map<string, { value: string; label: string; dotClass: string }>()
106
+ for (const entry of entries) {
107
+ const canonical = canonicalDealStatus(entry.value)
108
+ if (byCanonical.has(canonical)) continue
109
+ const tone = mapDictionaryColorToTone(entry.color ?? null)
110
+ byCanonical.set(canonical, {
111
+ value: canonical,
112
+ label: entry.label,
113
+ dotClass: toneToDotClass(tone),
114
+ })
115
+ }
116
+ // Sort by label exactly like the List page's advanced filter
117
+ // (backend/customers/deals/page.tsx dictionaryOptions) so both surfaces render
118
+ // the same pills in the same order.
119
+ return Array.from(byCanonical.values()).sort((a, b) =>
120
+ a.label.localeCompare(b.label, undefined, { sensitivity: 'base' }),
121
+ )
122
+ }
123
+ return FALLBACK_STATUS_OPTIONS.map((entry) => ({
124
+ value: entry.value,
125
+ label: translateWithFallback(t, entry.labelKey, entry.labelFallback),
126
+ dotClass: entry.dotClass,
127
+ }))
128
+ }, [dictionaryData, t])
129
+
130
+ const labelByValue = React.useMemo(() => {
131
+ const map = new Map<string, string>()
132
+ for (const option of statusOptions) {
133
+ map.set(option.value, option.label)
134
+ }
135
+ for (const fallback of FALLBACK_STATUS_OPTIONS) {
136
+ if (!map.has(fallback.value)) {
137
+ map.set(fallback.value, translateWithFallback(t, fallback.labelKey, fallback.labelFallback))
138
+ }
139
+ }
140
+ return map
141
+ }, [statusOptions, t])
67
142
 
68
143
  const chipLabel = translateWithFallback(t, 'customers.deals.kanban.filter.status', 'Status')
69
144
  const chipValue =
70
- values.length === 0
145
+ normalizedValues.length === 0
71
146
  ? translateWithFallback(t, 'customers.deals.kanban.filter.all', 'All')
72
- : values
73
- .map((value) => {
74
- const option = STATUS_OPTIONS.find((entry) => entry.value === value)
75
- return option
76
- ? translateWithFallback(t, option.labelKey, option.labelFallback)
77
- : value
78
- })
147
+ : normalizedValues
148
+ .map((value) => labelByValue.get(value) ?? value)
79
149
  .join(', ')
80
150
 
81
151
  const toggleDraft = (value: string) => {
152
+ const normalized = canonicalDealStatus(value)
82
153
  setDraft((prev) =>
83
- prev.includes(value) ? prev.filter((entry) => entry !== value) : [...prev, value],
154
+ prev.includes(normalized) ? prev.filter((entry) => entry !== normalized) : [...prev, normalized],
84
155
  )
85
156
  }
86
157
 
@@ -101,7 +172,7 @@ export function StatusFilterPopover({ values, onApply }: StatusFilterPopoverProp
101
172
  return (
102
173
  <Popover open={open} onOpenChange={setOpen}>
103
174
  <PopoverTrigger asChild>
104
- <ChipButton label={chipLabel} value={chipValue} active={values.length > 0} />
175
+ <ChipButton label={chipLabel} value={chipValue} active={normalizedValues.length > 0} />
105
176
  </PopoverTrigger>
106
177
  <PopoverContent
107
178
  className="w-96 rounded-2xl border-border bg-transparent p-0 shadow-xl"
@@ -133,9 +204,19 @@ export function StatusFilterPopover({ values, onApply }: StatusFilterPopoverProp
133
204
  {translateWithFallback(t, 'customers.deals.kanban.filter.status', 'Status')}
134
205
  </span>
135
206
  <div className="flex flex-wrap items-center gap-x-1.5 gap-y-2">
136
- {STATUS_OPTIONS.map((option) => {
207
+ {dictionaryLoading ? (
208
+ <span className="flex items-center gap-2 text-xs text-muted-foreground" role="status" aria-live="polite">
209
+ <Spinner className="size-3" />
210
+ {translateWithFallback(
211
+ t,
212
+ 'customers.deals.kanban.filter.status.loading',
213
+ 'Loading statuses…',
214
+ )}
215
+ </span>
216
+ ) : (
217
+ statusOptions.map((option) => {
137
218
  const isSelected = draft.includes(option.value)
138
- const label = translateWithFallback(t, option.labelKey, option.labelFallback)
219
+ const label = option.label
139
220
  return (
140
221
  <Button
141
222
  key={option.value}
@@ -160,7 +241,8 @@ export function StatusFilterPopover({ values, onApply }: StatusFilterPopoverProp
160
241
  ) : null}
161
242
  </Button>
162
243
  )
163
- })}
244
+ })
245
+ )}
164
246
  </div>
165
247
  </FilterPopoverShell>
166
248
  </PopoverContent>
@@ -0,0 +1,21 @@
1
+ import type { FilterOptionTone } from '@open-mercato/shared/lib/query/advanced-filter'
2
+
3
+ // Saturated icon tokens shared by the kanban lane accent bar and the status filter
4
+ // pills, so both surfaces render the same tone identically (#5107 review).
5
+ export const TONE_DOT_CLASS: Record<FilterOptionTone, string> = {
6
+ success: 'bg-status-success-icon',
7
+ error: 'bg-status-error-icon',
8
+ warning: 'bg-status-warning-icon',
9
+ info: 'bg-status-info-icon',
10
+ neutral: 'bg-status-neutral-icon',
11
+ brand: 'bg-brand-violet',
12
+ pink: 'bg-status-pink-icon',
13
+ }
14
+
15
+ export function toneToDotClass(
16
+ tone: FilterOptionTone | null | undefined,
17
+ fallback = 'bg-status-neutral-icon',
18
+ ): string {
19
+ if (tone && tone in TONE_DOT_CLASS) return TONE_DOT_CLASS[tone]
20
+ return fallback
21
+ }