@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
@@ -28,7 +28,10 @@ export const metadata = {
28
28
 
29
29
  type WidgetContext = WidgetScopeContext & { limit: number }
30
30
 
31
- async function resolveContext(req: Request, translate: (key: string, fallback?: string) => string): Promise<WidgetContext> {
31
+ async function resolveContext(
32
+ req: Request,
33
+ translate: (key: string, fallback?: string) => string,
34
+ ): Promise<WidgetContext> {
32
35
  const url = new URL(req.url)
33
36
  const rawQuery: Record<string, string> = {}
34
37
  for (const [key, value] of url.searchParams.entries()) {
@@ -39,16 +42,18 @@ async function resolveContext(req: Request, translate: (key: string, fallback?:
39
42
  throw new CrudHttpError(400, { error: translate('customers.errors.invalid_query', 'Invalid query parameters') })
40
43
  }
41
44
 
42
- const { container, em, tenantId, organizationIds } = await resolveWidgetScope(req, translate, {
43
- tenantId: parsed.data.tenantId ?? null,
44
- organizationId: parsed.data.organizationId ?? null,
45
- })
45
+ const { container, em, tenantId, organizationIds, isUnrestrictedOrganizationScope } =
46
+ await resolveWidgetScope(req, translate, {
47
+ tenantId: parsed.data.tenantId ?? null,
48
+ organizationId: parsed.data.organizationId ?? null,
49
+ })
46
50
 
47
51
  return {
48
52
  container,
49
53
  em,
50
54
  tenantId,
51
55
  organizationIds,
56
+ isUnrestrictedOrganizationScope,
52
57
  limit: parsed.data.limit,
53
58
  }
54
59
  }
@@ -56,7 +61,8 @@ async function resolveContext(req: Request, translate: (key: string, fallback?:
56
61
  export async function GET(req: Request) {
57
62
  const { translate } = await resolveTranslations()
58
63
  try {
59
- const { container, em, tenantId, organizationIds, limit } = await resolveContext(req, translate)
64
+ const { container, em, tenantId, organizationIds, isUnrestrictedOrganizationScope, limit } =
65
+ await resolveContext(req, translate)
60
66
  const auth = {
61
67
  tenantId,
62
68
  orgId: organizationIds?.[0] ?? null,
@@ -64,6 +70,7 @@ export async function GET(req: Request) {
64
70
  }
65
71
  const flags = await resolveCustomerInteractionFeatureFlags(container, tenantId)
66
72
  const mergedWindow = Math.min(limit * 4, 50)
73
+ const isUnrestricted = isUnrestrictedOrganizationScope === true
67
74
  const rows = flags.unified
68
75
  ? (await listCanonicalTodoRows(
69
76
  em,
@@ -71,7 +78,7 @@ export async function GET(req: Request) {
71
78
  auth,
72
79
  organizationIds?.[0] ?? null,
73
80
  organizationIds ?? null,
74
- { pagination: { page: 1, pageSize: limit } },
81
+ { pagination: { page: 1, pageSize: limit }, isUnrestricted },
75
82
  )).items
76
83
  : await Promise.all([
77
84
  listLegacyTodoRows(
@@ -80,7 +87,7 @@ export async function GET(req: Request) {
80
87
  tenantId,
81
88
  organizationIds ?? null,
82
89
  undefined,
83
- { limit: mergedWindow },
90
+ { limit: mergedWindow, isUnrestricted },
84
91
  ),
85
92
  listCanonicalTodoRows(
86
93
  em,
@@ -91,6 +98,7 @@ export async function GET(req: Request) {
91
98
  {
92
99
  includeDeleted: true,
93
100
  limit: mergedWindow,
101
+ isUnrestricted,
94
102
  },
95
103
  ),
96
104
  ]).then(([legacyRows, canonicalRows]) =>
@@ -101,8 +101,11 @@ export async function GET(req: Request, ctx: { params?: { id?: string } }) {
101
101
  throw notFound(translate('customers.errors.deal_not_found', 'Deal not found'))
102
102
  }
103
103
 
104
+ // Existence oracle (#5504): deny a cross-org read as not-found — identical to
105
+ // the parent-not-found above — so it cannot reveal that a deal exists in an
106
+ // organization the caller cannot see.
104
107
  if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: deal.organizationId })) {
105
- throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })
108
+ throw notFound(translate('customers.errors.deal_not_found', 'Deal not found'))
106
109
  }
107
110
 
108
111
  const entityScope = { tenantId: deal.tenantId, organizationId: deal.organizationId }
@@ -102,8 +102,11 @@ export async function GET(req: Request, ctx: { params?: { id?: string } }) {
102
102
  throw notFound(translate('customers.errors.deal_not_found', 'Deal not found'))
103
103
  }
104
104
 
105
+ // Existence oracle (#5504): deny a cross-org read as not-found — identical to
106
+ // the parent-not-found above — so it cannot reveal that a deal exists in an
107
+ // organization the caller cannot see.
105
108
  if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: deal.organizationId })) {
106
- throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })
109
+ throw notFound(translate('customers.errors.deal_not_found', 'Deal not found'))
107
110
  }
108
111
 
109
112
  const entityScope = { tenantId: deal.tenantId, organizationId: deal.organizationId }
@@ -19,10 +19,9 @@ import type { ActionLogService } from '@open-mercato/core/modules/audit_logs/ser
19
19
  import { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'
20
20
  import { normalizeCustomFieldResponse } from '@open-mercato/shared/lib/custom-fields/normalize'
21
21
  import { E } from '#generated/entities.ids.generated'
22
- import type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'
23
22
  import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
24
23
  import { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
25
- import { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'
24
+ import { denyCustomerDetailReadAsNotFound } from '../../../lib/detailReadAccess'
26
25
  import { decryptEntitiesWithFallbackScope } from '@open-mercato/shared/lib/encryption/subscriber'
27
26
  import { runWithCacheTenant } from '@open-mercato/cache'
28
27
  import {
@@ -47,10 +46,6 @@ function notFound(message: string) {
47
46
  return NextResponse.json({ error: message }, { status: 404 })
48
47
  }
49
48
 
50
- function forbidden(message: string) {
51
- return NextResponse.json({ error: message }, { status: 403 })
52
- }
53
-
54
49
  type DealAssociation = {
55
50
  id: string
56
51
  label: string
@@ -416,23 +411,10 @@ export async function GET(request: Request, context: { params?: Record<string, u
416
411
  return NextResponse.json({ error: 'Authentication required' }, { status: 401 })
417
412
  }
418
413
 
419
- let rbac: RbacService | null = null
420
- try {
421
- rbac = (container.resolve('rbacService') as RbacService)
422
- } catch {
423
- rbac = null
424
- }
425
-
426
- if (!rbac || !auth?.sub) {
427
- return forbidden('Access denied')
428
- }
429
- const hasFeature = await rbac.userHasAllFeatures(auth.sub, ['customers.deals.view'], {
430
- tenantId: auth.tenantId ?? null,
431
- organizationId: auth.orgId ?? null,
432
- })
433
- if (!hasFeature) {
434
- return forbidden('Access denied')
435
- }
414
+ // The API dispatcher already enforces `requireFeatures: ['customers.deals.view']`
415
+ // against the caller's effective (selected) organization before this handler
416
+ // runs, so no in-route feature re-check is needed. Re-checking here against the
417
+ // token org (auth.orgId) would wrongly 403 org-switched callers (#5012).
436
418
 
437
419
  const scope = await resolveOrganizationScopeForRequest({ container, auth, request })
438
420
  const em = (container.resolve('em') as EntityManager)
@@ -454,9 +436,16 @@ export async function GET(request: Request, context: { params?: Record<string, u
454
436
  return notFound('Deal not found')
455
437
  }
456
438
 
457
- if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: deal.organizationId })) {
458
- return forbidden('Access denied')
459
- }
439
+ // Existence oracle (issue #5504): a caller who holds customers.deals.view but
440
+ // whose scope excludes the record's organization must get the SAME response as
441
+ // for a non-existent id, so 403-when-present / 404-when-absent collapses to a
442
+ // uniform 404 not-found. The dispatcher already returns a uniform 403 for
443
+ // callers who lack the feature entirely.
444
+ const organizationReadDenied = denyCustomerDetailReadAsNotFound(
445
+ { scope, auth, organizationId: deal.organizationId },
446
+ 'Deal not found',
447
+ )
448
+ if (organizationReadDenied) return organizationReadDenied
460
449
 
461
450
  const decryptionScope = {
462
451
  tenantId: deal.tenantId ?? auth.tenantId ?? null,
@@ -977,8 +966,8 @@ export const openApi: OpenApiRouteDoc = {
977
966
  ],
978
967
  errors: [
979
968
  { status: 401, description: 'Unauthorized', schema: dealDetailErrorSchema },
980
- { status: 403, description: 'Forbidden for tenant/organization scope', schema: dealDetailErrorSchema },
981
- { status: 404, description: 'Deal not found', schema: dealDetailErrorSchema },
969
+ { status: 403, description: 'Forbidden caller lacks the required feature', schema: dealDetailErrorSchema },
970
+ { status: 404, description: 'Deal not found, or its organization is not in the caller’s scope', schema: dealDetailErrorSchema },
982
971
  ],
983
972
  },
984
973
  },
@@ -7,7 +7,6 @@ import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
7
7
  import type { EntityManager } from '@mikro-orm/postgresql'
8
8
  import { CustomerDeal, CustomerPipeline } from '../../../../data/entities'
9
9
  import { DictionaryEntry } from '@open-mercato/core/modules/dictionaries/data/entities'
10
- import type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'
11
10
  import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
12
11
  import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
13
12
  import { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'
@@ -24,10 +23,6 @@ function notFound(message: string) {
24
23
  return NextResponse.json({ error: message }, { status: 404 })
25
24
  }
26
25
 
27
- function forbidden(message: string) {
28
- return NextResponse.json({ error: message }, { status: 403 })
29
- }
30
-
31
26
  function badRequest(message: string, code?: string) {
32
27
  return NextResponse.json(
33
28
  code ? { error: message, code } : { error: message },
@@ -67,23 +62,10 @@ export async function GET(request: Request, context: { params?: Record<string, u
67
62
  return NextResponse.json({ error: translate('customers.errors.authentication_required', 'Authentication required') }, { status: 401 })
68
63
  }
69
64
 
70
- let rbac: RbacService | null = null
71
- try {
72
- rbac = (container.resolve('rbacService') as RbacService)
73
- } catch {
74
- rbac = null
75
- }
76
-
77
- if (!rbac || !auth?.sub) {
78
- return forbidden(translate('customers.errors.access_denied', 'Access denied'))
79
- }
80
- const hasFeature = await rbac.userHasAllFeatures(auth.sub, ['customers.deals.view'], {
81
- tenantId: auth.tenantId ?? null,
82
- organizationId: auth.orgId ?? null,
83
- })
84
- if (!hasFeature) {
85
- return forbidden(translate('customers.errors.access_denied', 'Access denied'))
86
- }
65
+ // The API dispatcher already enforces `requireFeatures: ['customers.deals.view']`
66
+ // against the caller's effective (selected) organization before this handler
67
+ // runs, so no in-route feature re-check is needed. Re-checking against the token
68
+ // org (auth.orgId) would wrongly 403 org-switched callers (#5012).
87
69
 
88
70
  const scope = await resolveOrganizationScopeForRequest({ container, auth, request })
89
71
  const em = (container.resolve('em') as EntityManager)
@@ -98,8 +80,11 @@ export async function GET(request: Request, context: { params?: Record<string, u
98
80
  return notFound(translate('customers.errors.deal_not_found', 'Deal not found'))
99
81
  }
100
82
 
83
+ // Existence oracle (#5504): deny a cross-org read as not-found — identical to
84
+ // the deal-not-found above — so it cannot reveal that a deal exists in an
85
+ // organization the caller cannot see.
101
86
  if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: deal.organizationId })) {
102
- return forbidden(translate('customers.errors.access_denied', 'Access denied'))
87
+ return notFound(translate('customers.errors.deal_not_found', 'Deal not found'))
103
88
  }
104
89
 
105
90
  if (!deal.closureOutcome) {
@@ -206,8 +191,8 @@ export const openApi: OpenApiRouteDoc = {
206
191
  errors: [
207
192
  { status: 400, description: 'Deal is not closed', schema: dealStatsErrorSchema },
208
193
  { status: 401, description: 'Unauthorized', schema: dealStatsErrorSchema },
209
- { status: 403, description: 'Forbidden for tenant/organization scope', schema: dealStatsErrorSchema },
210
- { status: 404, description: 'Deal not found', schema: dealStatsErrorSchema },
194
+ { status: 403, description: 'Forbidden caller lacks the required feature', schema: dealStatsErrorSchema },
195
+ { status: 404, description: 'Deal not found, or its organization is not in the caller’s scope', schema: dealStatsErrorSchema },
211
196
  ],
212
197
  },
213
198
  },
@@ -11,9 +11,11 @@ import type { ExchangeRateService } from '@open-mercato/core/modules/currencies/
11
11
  import { parseBooleanFromUnknown } from '@open-mercato/shared/lib/boolean'
12
12
  import { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'
13
13
  import type { CrudCtx } from '@open-mercato/shared/lib/crud/factory'
14
+ import { readQueryParamList } from '@open-mercato/shared/lib/crud/query-params'
14
15
  import { isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'
15
16
  import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
16
17
  import { fetchStuckDealIds } from '../../../lib/stuckDeals'
18
+ import { expandDealStatusAliases } from '../../../lib/dealStatus'
17
19
  import { findMatchingEntityIdsBySearchTokensAcrossSources } from '../../utils'
18
20
  import { E } from '#generated/entities.ids.generated'
19
21
  import { createLogger } from '@open-mercato/shared/lib/logger'
@@ -27,7 +29,7 @@ export const metadata = {
27
29
  const querySchema = z.object({
28
30
  pipelineId: z.string().uuid().optional(),
29
31
  search: z.string().optional(),
30
- status: z.array(z.enum(['open', 'closed', 'win', 'loose'])).optional(),
32
+ status: z.array(z.string().max(50)).max(20).optional(),
31
33
  ownerUserId: z.array(z.string().uuid()).optional(),
32
34
  personId: z.array(z.string().uuid()).optional(),
33
35
  companyId: z.array(z.string().uuid()).optional(),
@@ -121,11 +123,8 @@ export const openApi: OpenApiRouteDoc = {
121
123
  }
122
124
 
123
125
  function readArrayParam(searchParams: URLSearchParams, key: string): string[] | null {
124
- const all = searchParams.getAll(key)
125
- if (!all.length) return null
126
- const flat = all.flatMap((v) => v.split(','))
127
- const trimmed = flat.map((s) => s.trim()).filter(Boolean)
128
- return trimmed.length ? trimmed : null
126
+ const values = readQueryParamList(searchParams, key)
127
+ return values.length ? values : null
129
128
  }
130
129
 
131
130
  function restrictToIds(where: string[], values: Array<string | number | null>, ids: string[]) {
@@ -247,9 +246,11 @@ export async function GET(req: Request) {
247
246
  }
248
247
  }
249
248
  if (parsed.data.status && parsed.data.status.length) {
250
- const placeholders = parsed.data.status.map(() => '?').join(',')
249
+ // Non-empty input always expands to a non-empty set, so this always narrows.
250
+ const expandedStatuses = expandDealStatusAliases(parsed.data.status)
251
+ const placeholders = expandedStatuses.map(() => '?').join(',')
251
252
  where.push(`status IN (${placeholders})`)
252
- values.push(...parsed.data.status)
253
+ values.push(...expandedStatuses)
253
254
  }
254
255
  if (parsed.data.ownerUserId && parsed.data.ownerUserId.length) {
255
256
  const placeholders = parsed.data.ownerUserId.map(() => '?').join(',')
@@ -265,7 +266,14 @@ export async function GET(req: Request) {
265
266
  values.push(parsed.data.expectedCloseAtTo)
266
267
  }
267
268
  if (parsed.data.isOverdue) {
268
- where.push("expected_close_at < CURRENT_DATE AND status = 'open'")
269
+ // Mirror the list route's precedence: the caller-supplied status filter wins, and
270
+ // status='open' is injected only when none was provided.
271
+ const hasCallerStatus = !!parsed.data.status?.length
272
+ if (hasCallerStatus) {
273
+ where.push('expected_close_at < CURRENT_DATE')
274
+ } else {
275
+ where.push("expected_close_at < CURRENT_DATE AND status = 'open'")
276
+ }
269
277
  }
270
278
  if (parsed.data.isStuck) {
271
279
  // Reuse the list endpoint's stuck-deal lookup so kanban headers, lane counts, and the
@@ -5,6 +5,7 @@ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
5
5
  import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
6
6
  import { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'
7
7
  import type { CrudCtx } from '@open-mercato/shared/lib/crud/factory'
8
+ import { readQueryParamList } from '@open-mercato/shared/lib/crud/query-params'
8
9
  import { SortDir, type QueryEngine } from '@open-mercato/shared/lib/query/types'
9
10
  import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
10
11
  import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
@@ -161,10 +162,8 @@ function toIsoStringOrNull(value: unknown): string | null {
161
162
  }
162
163
 
163
164
  function readArrayParam(searchParams: URLSearchParams, key: string): string[] | null {
164
- const all = searchParams.getAll(key)
165
- if (!all.length) return null
166
- const trimmed = all.flatMap((value) => value.split(',')).map((value) => value.trim()).filter(Boolean)
167
- return trimmed.length ? trimmed : null
165
+ const values = readQueryParamList(searchParams, key)
166
+ return values.length ? values : null
168
167
  }
169
168
 
170
169
  function collectRefIds(rows: unknown[], key: string): string[] {
@@ -545,5 +544,6 @@ export async function GET(req: Request) {
545
544
  page: query.page,
546
545
  pageSize: query.pageSize,
547
546
  totalPages: Math.ceil(res.total / (query.pageSize || 1)),
547
+ ...(res.meta?.listCountCapWarning ? { totalIsCapped: true } : {}),
548
548
  })
549
549
  }
@@ -22,7 +22,9 @@ import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
22
22
  import { isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'
23
23
  import { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'
24
24
  import { consumeAdvancedFilterState, mergeAdvancedFilterTree } from '@open-mercato/shared/lib/crud/advanced-filter-integration'
25
+ import type { FilterGroup, FilterRule } from '@open-mercato/shared/lib/query/advanced-filter-tree'
25
26
  import { fetchStuckDealIds } from '../../lib/stuckDeals'
27
+ import { expandDealStatusAliases } from '../../lib/dealStatus'
26
28
  import { createLogger } from '@open-mercato/shared/lib/logger'
27
29
 
28
30
  const logger = createLogger('customers')
@@ -31,6 +33,19 @@ const rawBodySchema = z.object({}).passthrough()
31
33
 
32
34
  const stringOrStringArray = z.union([z.string(), z.array(z.string())])
33
35
  const OPEN_DEAL_STATUSES = ['open', 'in_progress'] as const
36
+ // Tree operators whose `status` values are rewritten through the canonical vocabulary.
37
+ // Text (`contains`/`starts_with`/…) and range (`between`) operators are left untouched
38
+ // so a URL-supplied rule keeps its scalar semantics.
39
+ const STATUS_TREE_OPERATORS = new Set([
40
+ 'is',
41
+ 'equals',
42
+ 'is_not',
43
+ 'not_equals',
44
+ 'is_any_of',
45
+ 'has_any_of',
46
+ 'is_none_of',
47
+ 'has_none_of',
48
+ ])
34
49
  const booleanQueryParam = z.preprocess((value) => {
35
50
  const parsed = parseBooleanFromUnknown(value)
36
51
  return parsed === null ? value : parsed
@@ -245,6 +260,39 @@ function normalizeUuidList(values: Array<unknown>): string[] {
245
260
 
246
261
  export async function buildDealListFilters(query: DealListQuery, ctx?: import('@open-mercato/shared/lib/crud/factory').CrudCtx) {
247
262
  const advancedFilterTree = consumeAdvancedFilterState(query)
263
+ if (advancedFilterTree) {
264
+ // Expand status aliases in the advanced-filter tree so List (tree path) and
265
+ // Kanban (plain ?status=) share the same canonical vocabulary (#5107). Only
266
+ // set-membership operators are rewritten — text/range operators on `status`
267
+ // keep their pre-existing scalar semantics instead of being corrupted.
268
+ const walk = (node: FilterGroup | FilterRule): void => {
269
+ if (node.type === 'rule' && node.field === 'status' && STATUS_TREE_OPERATORS.has(node.operator)) {
270
+ const listOperators = new Set(['is_any_of', 'has_any_of', 'is_none_of', 'has_none_of'])
271
+ const rawValues: string[] = Array.isArray(node.value)
272
+ ? (node.value as unknown[]).filter((v): v is string => typeof v === 'string')
273
+ : typeof node.value === 'string'
274
+ ? [node.value]
275
+ : []
276
+ if (rawValues.length === 0) return
277
+ const expanded = expandDealStatusAliases(rawValues)
278
+ if (listOperators.has(node.operator)) {
279
+ node.value = expanded
280
+ } else if (expanded.length === 1) {
281
+ node.value = expanded[0]
282
+ } else {
283
+ node.value = expanded
284
+ if (node.operator === 'is' || node.operator === 'equals') {
285
+ node.operator = 'is_any_of'
286
+ } else if (node.operator === 'is_not' || node.operator === 'not_equals') {
287
+ node.operator = 'is_none_of'
288
+ }
289
+ }
290
+ } else if (node.type === 'group') {
291
+ for (const child of node.children) walk(child)
292
+ }
293
+ }
294
+ walk(advancedFilterTree.root)
295
+ }
248
296
  const filters: Record<string, unknown> = {}
249
297
  let restrictedIds: string[] | null = null
250
298
 
@@ -300,7 +348,8 @@ export async function buildDealListFilters(query: DealListQuery, ctx?: import('@
300
348
  }
301
349
  }
302
350
 
303
- const statusList = query.status ? normalizeStringList(query.status) : []
351
+ const rawStatusList = query.status ? normalizeStringList(query.status) : []
352
+ const statusList = expandDealStatusAliases(rawStatusList)
304
353
  if (statusList.length > 0) {
305
354
  filters.status = statusList.length === 1 ? { $eq: statusList[0] } : { $in: statusList }
306
355
  }
@@ -77,10 +77,14 @@ function ensureRouteOrganizationAccess(
77
77
  organizationId: string,
78
78
  scope: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['scope'],
79
79
  auth: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['auth'],
80
- translate: Translator,
80
+ notFoundMessage: string,
81
81
  ) {
82
+ // Existence oracle (#5504): a caller who holds the feature but whose scope
83
+ // excludes the record's organization is denied as not-found (the same response
84
+ // the caller gets for a missing record), so this cannot reveal that the record
85
+ // exists in an organization they cannot see.
82
86
  if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId })) {
83
- throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })
87
+ throw notFound(notFoundMessage)
84
88
  }
85
89
  }
86
90
 
@@ -132,7 +136,7 @@ async function resolveEntityRouteScope(
132
136
  if (!entity || entity.tenantId !== auth.tenantId) {
133
137
  throw notFound(translate('customers.errors.customer_not_found', 'Customer not found'))
134
138
  }
135
- ensureRouteOrganizationAccess(entity.organizationId, scope, auth, translate)
139
+ ensureRouteOrganizationAccess(entity.organizationId, scope, auth, translate('customers.errors.customer_not_found', 'Customer not found'))
136
140
  return {
137
141
  entity,
138
142
  organizationId: entity.organizationId,
@@ -164,7 +168,7 @@ async function resolveRoleRouteScope(
164
168
  ) {
165
169
  throw notFound(translate('customers.errors.role_not_found', 'Role not found'))
166
170
  }
167
- ensureRouteOrganizationAccess(role.organizationId, scope, auth, translate)
171
+ ensureRouteOrganizationAccess(role.organizationId, scope, auth, translate('customers.errors.role_not_found', 'Role not found'))
168
172
  return {
169
173
  role,
170
174
  organizationId: role.organizationId,
@@ -180,7 +180,7 @@ type InteractionListRow = {
180
180
  all_day: boolean | null
181
181
  recurrence_rule: string | null
182
182
  recurrence_end: Date | null
183
- participants: Array<{ userId: string; name?: string; email?: string; status?: string }> | null
183
+ participants: Array<{ userId?: string; name?: string; email?: string; status?: string }> | null
184
184
  reminder_minutes: number | null
185
185
  visibility: string | null
186
186
  linked_entities: Array<{ id: string; type: string; label: string }> | null
@@ -744,7 +744,13 @@ const interactionListItemSchema = z
744
744
  recurrenceEnd: z.string().nullable().optional(),
745
745
  participants: z.array(
746
746
  z.object({
747
- userId: z.string().uuid(),
747
+ userId: z
748
+ .string()
749
+ .uuid()
750
+ .optional()
751
+ .describe(
752
+ 'Absent for an external guest, who has no person/customer/staff record and is identified by email instead. Identify a participant by userId when present, otherwise by its normalized email.',
753
+ ),
748
754
  name: z.string().optional(),
749
755
  email: z.string().optional(),
750
756
  status: z.string().optional(),
@@ -3,6 +3,7 @@ import { z } from 'zod'
3
3
  import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
4
4
  import { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
5
5
  import { parseBooleanToken } from '@open-mercato/shared/lib/boolean'
6
+ import { isUnrestrictedOrganizationScope } from '@open-mercato/shared/lib/auth/organizationAccess'
6
7
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
7
8
  import type { QueryEngine } from '@open-mercato/shared/lib/query/types'
8
9
  import { createCustomersCrudOpenApi, createPagedListResponseSchema } from '../../openapi'
@@ -40,11 +41,30 @@ const MERGED_TASK_FETCH_CAP = 2000
40
41
  export async function GET(request: Request): Promise<Response> {
41
42
  const { translate } = await resolveTranslations()
42
43
  try {
43
- const { auth, em, organizationIds, container, selectedOrganizationId } =
44
+ const { auth, em, organizationIds, container, selectedOrganizationId, scope } =
44
45
  await resolveCustomersRequestContext(request)
45
46
  const query = querySchema.parse(Object.fromEntries(new URL(request.url).searchParams))
46
47
  const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)
47
48
  const exportAll = parseBooleanToken(query.all) === true
49
+ const isUnrestricted = isUnrestrictedOrganizationScope({
50
+ isSuperAdmin: auth.isSuperAdmin === true,
51
+ allowedOrganizationIds: scope?.allowedIds,
52
+ })
53
+ if (!isUnrestricted && (!organizationIds || organizationIds.length === 0)) {
54
+ logger.warn('customers.interactions.tasks.list collapsed organization scope', {
55
+ tenantId: auth.tenantId,
56
+ organizationIds,
57
+ selectedId: scope?.selectedId ?? null,
58
+ allowedIdsCount: scope?.allowedIds?.length ?? null,
59
+ })
60
+ return NextResponse.json({
61
+ items: [],
62
+ total: 0,
63
+ page: exportAll ? 1 : query.page,
64
+ pageSize: exportAll ? 0 : query.pageSize,
65
+ totalPages: 1,
66
+ })
67
+ }
48
68
  const search = normalizeTodoSearch(query.search)
49
69
  const queryEngine = container.resolve('queryEngine') as QueryEngine
50
70
 
@@ -59,6 +79,7 @@ export async function GET(request: Request): Promise<Response> {
59
79
  entityId: query.entityId,
60
80
  pagination: exportAll ? null : { page: query.page, pageSize: query.pageSize },
61
81
  searchText: search,
82
+ isUnrestricted,
62
83
  },
63
84
  )
64
85
  const total = canonical.total
@@ -80,6 +101,7 @@ export async function GET(request: Request): Promise<Response> {
80
101
  const [legacyRows, canonicalRows] = await Promise.all([
81
102
  listLegacyTodoRows(em, queryEngine, auth.tenantId, organizationIds, query.entityId, {
82
103
  limit: legacyWindow,
104
+ isUnrestricted,
83
105
  }),
84
106
  listCanonicalTodoRows(
85
107
  em,
@@ -91,6 +113,7 @@ export async function GET(request: Request): Promise<Response> {
91
113
  entityId: query.entityId,
92
114
  includeDeleted: true,
93
115
  limit: legacyWindow,
116
+ isUnrestricted,
94
117
  },
95
118
  ),
96
119
  ])
@@ -234,7 +234,7 @@ export async function DELETE(req: Request, ctx: { params?: { id?: string; linkId
234
234
  const { translate } = await resolveTranslations()
235
235
  try {
236
236
  const { id, linkId } = paramsSchema.parse({ id: ctx.params?.id, linkId: ctx.params?.linkId })
237
- const { container, auth, selectedOrganizationId, person } = await loadPersonContext(req, id)
237
+ const { container, auth, selectedOrganizationId, person, profile } = await loadPersonContext(req, id)
238
238
  if (!selectedOrganizationId) {
239
239
  throw new CrudHttpError(400, { error: translate('customers.errors.organization_required', 'Organization context is required') })
240
240
  }
@@ -262,18 +262,26 @@ export async function DELETE(req: Request, ctx: { params?: { id?: string; linkId
262
262
  auth.tenantId,
263
263
  selectedOrganizationId,
264
264
  )
265
- if (!resolvedLinkId) {
265
+ // No `CustomerPersonCompanyLink` row resolves for the profile-only association case
266
+ // (`CustomerPersonProfile.company` set without a link row, e.g. from a CRM migration).
267
+ // The delete command accepts that shape too, so it is dispatched instead of 404ing and
268
+ // the detach keeps its audit entry, undo token and cache invalidation (#5114).
269
+ const isProfileOnlyMatch =
270
+ profile.company && typeof profile.company !== 'string' && profile.company.id === linkId
271
+ if (!resolvedLinkId && !isProfileOnlyMatch) {
266
272
  throw notFound(translate('customers.errors.person_company_link_not_found', 'Person-company link not found'))
267
273
  }
268
274
 
269
275
  const commandInput = personCompanyLinkDeleteSchema.parse({
270
- linkId: resolvedLinkId,
276
+ ...(resolvedLinkId
277
+ ? { linkId: resolvedLinkId }
278
+ : { personEntityId: person.id, companyEntityId: linkId }),
271
279
  tenantId: auth.tenantId,
272
280
  organizationId: selectedOrganizationId,
273
281
  } satisfies PersonCompanyLinkDeleteInput)
274
282
 
275
283
  const commandBus = container.resolve('commandBus') as CommandBus
276
- const { result, logEntry } = await commandBus.execute<PersonCompanyLinkDeleteInput, { linkId: string }>(
284
+ const { result, logEntry } = await commandBus.execute<PersonCompanyLinkDeleteInput, { linkId: string | null }>(
277
285
  'customers.personCompanyLinks.delete',
278
286
  {
279
287
  input: commandInput,
@@ -38,8 +38,11 @@ export async function loadPersonContext(req: Request, personId: string) {
38
38
  throw notFound(translate('customers.errors.person_not_found', 'Person not found'))
39
39
  }
40
40
 
41
+ // Existence oracle (#5504): deny a cross-org read as not-found — identical to
42
+ // the parent-not-found above — so it cannot reveal that a person exists in an
43
+ // organization the caller cannot see.
41
44
  if (!isOrganizationReadAccessAllowed({ scope, auth: authenticatedAuth, organizationId: person.organizationId })) {
42
- throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })
45
+ throw notFound(translate('customers.errors.person_not_found', 'Person not found'))
43
46
  }
44
47
 
45
48
  const profile = await findOneWithDecryption(
@@ -178,8 +178,11 @@ export async function GET(req: Request, ctx: { params?: { id?: string } }) {
178
178
  throw notFound(translate('customers.errors.person_not_found', 'Person not found'))
179
179
  }
180
180
 
181
+ // Existence oracle (#5504): deny a cross-org read as not-found — identical to
182
+ // the parent-not-found above — so it cannot reveal that a person exists in an
183
+ // organization the caller cannot see.
181
184
  if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: person.organizationId })) {
182
- throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })
185
+ throw notFound(translate('customers.errors.person_not_found', 'Person not found'))
183
186
  }
184
187
 
185
188
  const entityScope = { tenantId: auth.tenantId, organizationId: person.organizationId }