@open-mercato/core 0.7.0 → 0.7.1-develop.7102.1.b41f7e3e51

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 +11 -4
  160. package/dist/modules/customers/api/deals/aggregate/route.js.map +2 -2
  161. package/dist/modules/customers/api/deals/map/route.js +2 -1
  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 +14 -4
  631. package/src/modules/customers/api/deals/map/route.ts +1 -0
  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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/customers/api/people/%5Bid%5D/companies/%5BlinkId%5D/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { CrudHttpError, isCrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { CommandBus } from '@open-mercato/shared/lib/commands'\nimport { serializeOperationMetadata } from '@open-mercato/shared/lib/commands/operationMetadata'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveAuthActorId } from '@open-mercato/core/modules/customers/lib/interactionRequestContext'\nimport { CustomerPersonCompanyLink } from '@open-mercato/core/modules/customers/data/entities'\nimport {\n personCompanyLinkDeleteSchema,\n personCompanyLinkUpdateSchema,\n type PersonCompanyLinkDeleteInput,\n type PersonCompanyLinkUpdateInput,\n} from '@open-mercato/core/modules/customers/data/validators'\nimport { loadPersonContext } from '../context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\n\nconst paramsSchema = z.object({\n id: z.string().uuid(),\n linkId: z.string().uuid(),\n})\n\n/**\n * Resolve the second path segment to a concrete `customer_person_company_links` row id.\n * The UI on company/person detail pages calls this route with the company entity id as\n * the last segment (symmetric with the other company-centric endpoints); older callers\n * may pass the actual link row id. We try a direct id lookup first, then fall back to\n * resolving via `(person, company)` pair.\n */\nasync function resolveLinkId(\n em: EntityManager,\n rawLinkId: string,\n personEntityId: string,\n tenantId: string,\n organizationId: string | null,\n): Promise<string | null> {\n const decryptionScope = { tenantId, organizationId }\n const directFilter: FilterQuery<CustomerPersonCompanyLink> = organizationId\n ? { id: rawLinkId, tenantId, organizationId, deletedAt: null }\n : { id: rawLinkId, tenantId, deletedAt: null }\n const direct = await findOneWithDecryption(\n em,\n CustomerPersonCompanyLink,\n directFilter,\n undefined,\n decryptionScope,\n )\n if (direct) return direct.id\n\n const companyFilter: FilterQuery<CustomerPersonCompanyLink> = organizationId\n ? {\n person: personEntityId,\n company: rawLinkId,\n tenantId,\n organizationId,\n deletedAt: null,\n }\n : { person: personEntityId, company: rawLinkId, tenantId, deletedAt: null }\n const viaCompany = await findOneWithDecryption(\n em,\n CustomerPersonCompanyLink,\n companyFilter,\n undefined,\n decryptionScope,\n )\n return viaCompany?.id ?? null\n}\n\nconst updateSchema = z.object({\n isPrimary: z.boolean().optional(),\n})\n\nconst updateResponseSchema = z.object({\n ok: z.literal(true),\n result: z\n .object({\n id: z.string().uuid(),\n companyId: z.string().uuid(),\n displayName: z.string(),\n isPrimary: z.boolean(),\n })\n .nullable(),\n})\n\nexport const metadata = {\n PATCH: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n methods: {\n PATCH: {\n summary: 'Update a linked company for a person',\n requestBody: { schema: updateSchema },\n responses: [{ status: 200, description: 'Updated company link', schema: updateResponseSchema }],\n },\n DELETE: {\n summary: 'Remove a linked company from a person',\n responses: [{ status: 200, description: 'Deletion result', schema: z.object({ ok: z.literal(true) }) }],\n },\n },\n}\n\nexport async function PATCH(req: Request, ctx: { params?: { id?: string; linkId?: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id, linkId } = paramsSchema.parse({ id: ctx.params?.id, linkId: ctx.params?.linkId })\n const payload = updateSchema.parse(await readJsonSafe(req, {}))\n const { container, auth, selectedOrganizationId, person } = await loadPersonContext(req, id)\n if (!selectedOrganizationId) {\n throw new CrudHttpError(400, { error: translate('customers.errors.organization_required', 'Organization context is required') })\n }\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.person',\n resourceId: person.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: payload,\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n if (payload.isPrimary === undefined) {\n return NextResponse.json({ ok: true as const, result: null })\n }\n\n const resolveEm = (container.resolve('em') as EntityManager).fork()\n const resolvedLinkId = await resolveLinkId(\n resolveEm,\n linkId,\n person.id,\n auth.tenantId,\n selectedOrganizationId,\n )\n if (!resolvedLinkId) {\n throw notFound(translate('customers.errors.person_company_link_not_found', 'Person-company link not found'))\n }\n\n const commandInput = personCompanyLinkUpdateSchema.parse({\n linkId: resolvedLinkId,\n isPrimary: payload.isPrimary,\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n } satisfies PersonCompanyLinkUpdateInput)\n\n const commandBus = container.resolve('commandBus') as CommandBus\n const { result, logEntry } = await commandBus.execute<PersonCompanyLinkUpdateInput, { linkId: string }>(\n 'customers.personCompanyLinks.update',\n {\n input: commandInput,\n ctx: {\n container,\n auth,\n organizationScope: null,\n selectedOrganizationId,\n organizationIds: [selectedOrganizationId],\n request: req,\n },\n },\n )\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.person',\n resourceId: person.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n const freshEm = (container.resolve('em') as EntityManager).fork()\n const linkRecord = await findOneWithDecryption(\n freshEm,\n CustomerPersonCompanyLink,\n { id: result.linkId, tenantId: auth.tenantId, organizationId: selectedOrganizationId },\n { populate: ['company'] },\n { tenantId: auth.tenantId, organizationId: selectedOrganizationId },\n )\n const company = linkRecord && typeof linkRecord.company !== 'string' ? linkRecord.company : null\n const response = NextResponse.json({\n ok: true as const,\n result: linkRecord\n ? {\n id: linkRecord.id,\n companyId: company?.id ?? '',\n displayName: company?.displayName ?? '',\n isPrimary: Boolean(linkRecord.isPrimary),\n }\n : null,\n })\n if (logEntry?.undoToken && logEntry.id && logEntry.commandId) {\n response.headers.set(\n 'x-om-operation',\n serializeOperationMetadata({\n id: logEntry.id,\n undoToken: logEntry.undoToken,\n commandId: logEntry.commandId,\n actionLabel: logEntry.actionLabel ?? null,\n resourceKind: logEntry.resourceKind ?? 'customers.personCompanyLink',\n resourceId: logEntry.resourceId ?? result.linkId,\n executedAt: logEntry.createdAt instanceof Date ? logEntry.createdAt.toISOString() : new Date().toISOString(),\n }),\n )\n }\n return response\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n return NextResponse.json({ error: translate('customers.errors.internal', 'Internal server error') }, { status: 500 })\n }\n}\n\nexport async function DELETE(req: Request, ctx: { params?: { id?: string; linkId?: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id, linkId } = paramsSchema.parse({ id: ctx.params?.id, linkId: ctx.params?.linkId })\n const { container, auth, selectedOrganizationId, person } = await loadPersonContext(req, id)\n if (!selectedOrganizationId) {\n throw new CrudHttpError(400, { error: translate('customers.errors.organization_required', 'Organization context is required') })\n }\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.person',\n resourceId: person.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: { id: linkId },\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n const resolveEm = (container.resolve('em') as EntityManager).fork()\n const resolvedLinkId = await resolveLinkId(\n resolveEm,\n linkId,\n person.id,\n auth.tenantId,\n selectedOrganizationId,\n )\n if (!resolvedLinkId) {\n throw notFound(translate('customers.errors.person_company_link_not_found', 'Person-company link not found'))\n }\n\n const commandInput = personCompanyLinkDeleteSchema.parse({\n linkId: resolvedLinkId,\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n } satisfies PersonCompanyLinkDeleteInput)\n\n const commandBus = container.resolve('commandBus') as CommandBus\n const { result, logEntry } = await commandBus.execute<PersonCompanyLinkDeleteInput, { linkId: string }>(\n 'customers.personCompanyLinks.delete',\n {\n input: commandInput,\n ctx: {\n container,\n auth,\n organizationScope: null,\n selectedOrganizationId,\n organizationIds: [selectedOrganizationId],\n request: req,\n },\n },\n )\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.person',\n resourceId: person.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n const response = NextResponse.json({ ok: true as const })\n if (logEntry?.undoToken && logEntry.id && logEntry.commandId) {\n response.headers.set(\n 'x-om-operation',\n serializeOperationMetadata({\n id: logEntry.id,\n undoToken: logEntry.undoToken,\n commandId: logEntry.commandId,\n actionLabel: logEntry.actionLabel ?? null,\n resourceKind: logEntry.resourceKind ?? 'customers.personCompanyLink',\n resourceId: logEntry.resourceId ?? result.linkId,\n executedAt: logEntry.createdAt instanceof Date ? logEntry.createdAt.toISOString() : new Date().toISOString(),\n }),\n )\n }\n return response\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n return NextResponse.json({ error: translate('customers.errors.internal', 'Internal server error') }, { status: 500 })\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { CrudHttpError, isCrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { CommandBus } from '@open-mercato/shared/lib/commands'\nimport { serializeOperationMetadata } from '@open-mercato/shared/lib/commands/operationMetadata'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveAuthActorId } from '@open-mercato/core/modules/customers/lib/interactionRequestContext'\nimport { CustomerPersonCompanyLink } from '@open-mercato/core/modules/customers/data/entities'\nimport {\n personCompanyLinkDeleteSchema,\n personCompanyLinkUpdateSchema,\n type PersonCompanyLinkDeleteInput,\n type PersonCompanyLinkUpdateInput,\n} from '@open-mercato/core/modules/customers/data/validators'\nimport { loadPersonContext } from '../context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\n\nconst paramsSchema = z.object({\n id: z.string().uuid(),\n linkId: z.string().uuid(),\n})\n\n/**\n * Resolve the second path segment to a concrete `customer_person_company_links` row id.\n * The UI on company/person detail pages calls this route with the company entity id as\n * the last segment (symmetric with the other company-centric endpoints); older callers\n * may pass the actual link row id. We try a direct id lookup first, then fall back to\n * resolving via `(person, company)` pair.\n */\nasync function resolveLinkId(\n em: EntityManager,\n rawLinkId: string,\n personEntityId: string,\n tenantId: string,\n organizationId: string | null,\n): Promise<string | null> {\n const decryptionScope = { tenantId, organizationId }\n const directFilter: FilterQuery<CustomerPersonCompanyLink> = organizationId\n ? { id: rawLinkId, tenantId, organizationId, deletedAt: null }\n : { id: rawLinkId, tenantId, deletedAt: null }\n const direct = await findOneWithDecryption(\n em,\n CustomerPersonCompanyLink,\n directFilter,\n undefined,\n decryptionScope,\n )\n if (direct) return direct.id\n\n const companyFilter: FilterQuery<CustomerPersonCompanyLink> = organizationId\n ? {\n person: personEntityId,\n company: rawLinkId,\n tenantId,\n organizationId,\n deletedAt: null,\n }\n : { person: personEntityId, company: rawLinkId, tenantId, deletedAt: null }\n const viaCompany = await findOneWithDecryption(\n em,\n CustomerPersonCompanyLink,\n companyFilter,\n undefined,\n decryptionScope,\n )\n return viaCompany?.id ?? null\n}\n\nconst updateSchema = z.object({\n isPrimary: z.boolean().optional(),\n})\n\nconst updateResponseSchema = z.object({\n ok: z.literal(true),\n result: z\n .object({\n id: z.string().uuid(),\n companyId: z.string().uuid(),\n displayName: z.string(),\n isPrimary: z.boolean(),\n })\n .nullable(),\n})\n\nexport const metadata = {\n PATCH: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n methods: {\n PATCH: {\n summary: 'Update a linked company for a person',\n requestBody: { schema: updateSchema },\n responses: [{ status: 200, description: 'Updated company link', schema: updateResponseSchema }],\n },\n DELETE: {\n summary: 'Remove a linked company from a person',\n responses: [{ status: 200, description: 'Deletion result', schema: z.object({ ok: z.literal(true) }) }],\n },\n },\n}\n\nexport async function PATCH(req: Request, ctx: { params?: { id?: string; linkId?: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id, linkId } = paramsSchema.parse({ id: ctx.params?.id, linkId: ctx.params?.linkId })\n const payload = updateSchema.parse(await readJsonSafe(req, {}))\n const { container, auth, selectedOrganizationId, person } = await loadPersonContext(req, id)\n if (!selectedOrganizationId) {\n throw new CrudHttpError(400, { error: translate('customers.errors.organization_required', 'Organization context is required') })\n }\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.person',\n resourceId: person.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: payload,\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n if (payload.isPrimary === undefined) {\n return NextResponse.json({ ok: true as const, result: null })\n }\n\n const resolveEm = (container.resolve('em') as EntityManager).fork()\n const resolvedLinkId = await resolveLinkId(\n resolveEm,\n linkId,\n person.id,\n auth.tenantId,\n selectedOrganizationId,\n )\n if (!resolvedLinkId) {\n throw notFound(translate('customers.errors.person_company_link_not_found', 'Person-company link not found'))\n }\n\n const commandInput = personCompanyLinkUpdateSchema.parse({\n linkId: resolvedLinkId,\n isPrimary: payload.isPrimary,\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n } satisfies PersonCompanyLinkUpdateInput)\n\n const commandBus = container.resolve('commandBus') as CommandBus\n const { result, logEntry } = await commandBus.execute<PersonCompanyLinkUpdateInput, { linkId: string }>(\n 'customers.personCompanyLinks.update',\n {\n input: commandInput,\n ctx: {\n container,\n auth,\n organizationScope: null,\n selectedOrganizationId,\n organizationIds: [selectedOrganizationId],\n request: req,\n },\n },\n )\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.person',\n resourceId: person.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n const freshEm = (container.resolve('em') as EntityManager).fork()\n const linkRecord = await findOneWithDecryption(\n freshEm,\n CustomerPersonCompanyLink,\n { id: result.linkId, tenantId: auth.tenantId, organizationId: selectedOrganizationId },\n { populate: ['company'] },\n { tenantId: auth.tenantId, organizationId: selectedOrganizationId },\n )\n const company = linkRecord && typeof linkRecord.company !== 'string' ? linkRecord.company : null\n const response = NextResponse.json({\n ok: true as const,\n result: linkRecord\n ? {\n id: linkRecord.id,\n companyId: company?.id ?? '',\n displayName: company?.displayName ?? '',\n isPrimary: Boolean(linkRecord.isPrimary),\n }\n : null,\n })\n if (logEntry?.undoToken && logEntry.id && logEntry.commandId) {\n response.headers.set(\n 'x-om-operation',\n serializeOperationMetadata({\n id: logEntry.id,\n undoToken: logEntry.undoToken,\n commandId: logEntry.commandId,\n actionLabel: logEntry.actionLabel ?? null,\n resourceKind: logEntry.resourceKind ?? 'customers.personCompanyLink',\n resourceId: logEntry.resourceId ?? result.linkId,\n executedAt: logEntry.createdAt instanceof Date ? logEntry.createdAt.toISOString() : new Date().toISOString(),\n }),\n )\n }\n return response\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n return NextResponse.json({ error: translate('customers.errors.internal', 'Internal server error') }, { status: 500 })\n }\n}\n\nexport async function DELETE(req: Request, ctx: { params?: { id?: string; linkId?: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id, linkId } = paramsSchema.parse({ id: ctx.params?.id, linkId: ctx.params?.linkId })\n const { container, auth, selectedOrganizationId, person, profile } = await loadPersonContext(req, id)\n if (!selectedOrganizationId) {\n throw new CrudHttpError(400, { error: translate('customers.errors.organization_required', 'Organization context is required') })\n }\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.person',\n resourceId: person.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: { id: linkId },\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n const resolveEm = (container.resolve('em') as EntityManager).fork()\n const resolvedLinkId = await resolveLinkId(\n resolveEm,\n linkId,\n person.id,\n auth.tenantId,\n selectedOrganizationId,\n )\n // No `CustomerPersonCompanyLink` row resolves for the profile-only association case\n // (`CustomerPersonProfile.company` set without a link row, e.g. from a CRM migration).\n // The delete command accepts that shape too, so it is dispatched instead of 404ing and\n // the detach keeps its audit entry, undo token and cache invalidation (#5114).\n const isProfileOnlyMatch =\n profile.company && typeof profile.company !== 'string' && profile.company.id === linkId\n if (!resolvedLinkId && !isProfileOnlyMatch) {\n throw notFound(translate('customers.errors.person_company_link_not_found', 'Person-company link not found'))\n }\n\n const commandInput = personCompanyLinkDeleteSchema.parse({\n ...(resolvedLinkId\n ? { linkId: resolvedLinkId }\n : { personEntityId: person.id, companyEntityId: linkId }),\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n } satisfies PersonCompanyLinkDeleteInput)\n\n const commandBus = container.resolve('commandBus') as CommandBus\n const { result, logEntry } = await commandBus.execute<PersonCompanyLinkDeleteInput, { linkId: string | null }>(\n 'customers.personCompanyLinks.delete',\n {\n input: commandInput,\n ctx: {\n container,\n auth,\n organizationScope: null,\n selectedOrganizationId,\n organizationIds: [selectedOrganizationId],\n request: req,\n },\n },\n )\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.person',\n resourceId: person.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n const response = NextResponse.json({ ok: true as const })\n if (logEntry?.undoToken && logEntry.id && logEntry.commandId) {\n response.headers.set(\n 'x-om-operation',\n serializeOperationMetadata({\n id: logEntry.id,\n undoToken: logEntry.undoToken,\n commandId: logEntry.commandId,\n actionLabel: logEntry.actionLabel ?? null,\n resourceKind: logEntry.resourceKind ?? 'customers.personCompanyLink',\n resourceId: logEntry.resourceId ?? result.linkId,\n executedAt: logEntry.createdAt instanceof Date ? logEntry.createdAt.toISOString() : new Date().toISOString(),\n }),\n )\n }\n return response\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n return NextResponse.json({ error: translate('customers.errors.internal', 'Internal server error') }, { status: 500 })\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -34,7 +34,7 @@ async function loadPersonContext(req, personId) {
34
34
  throw notFound(translate("customers.errors.person_not_found", "Person not found"));
35
35
  }
36
36
  if (!isOrganizationReadAccessAllowed({ scope, auth: authenticatedAuth, organizationId: person.organizationId })) {
37
- throw new CrudHttpError(403, { error: translate("customers.errors.access_denied", "Access denied") });
37
+ throw notFound(translate("customers.errors.person_not_found", "Person not found"));
38
38
  }
39
39
  const profile = await findOneWithDecryption(
40
40
  em,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/customers/api/people/%5Bid%5D/companies/context.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport {\n CustomerEntity,\n CustomerPersonProfile,\n} from '@open-mercato/core/modules/customers/data/entities'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\nexport async function loadPersonContext(req: Request, personId: string) {\n const { translate } = await resolveTranslations()\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId) {\n throw new CrudHttpError(401, { error: translate('customers.errors.unauthorized', 'Unauthorized') })\n }\n const authenticatedAuth = auth as typeof auth & { tenantId: string }\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth: authenticatedAuth, request: req })\n const em = (container.resolve('em') as EntityManager).fork()\n const decryptionScope = {\n tenantId: authenticatedAuth.tenantId,\n organizationId: scope?.selectedId ?? authenticatedAuth.orgId ?? null,\n }\n const person = await findOneWithDecryption(\n em,\n CustomerEntity,\n { id: personId, kind: 'person', tenantId: authenticatedAuth.tenantId, deletedAt: null },\n {},\n decryptionScope,\n )\n\n if (!person) {\n throw notFound(translate('customers.errors.person_not_found', 'Person not found'))\n }\n\n if (!isOrganizationReadAccessAllowed({ scope, auth: authenticatedAuth, organizationId: person.organizationId })) {\n throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })\n }\n\n const profile = await findOneWithDecryption(\n em,\n CustomerPersonProfile,\n { entity: person, tenantId: person.tenantId, organizationId: person.organizationId },\n { populate: ['company'] },\n {\n tenantId: person.tenantId,\n organizationId: person.organizationId,\n },\n )\n if (!profile) {\n throw notFound(translate('customers.errors.person_profile_not_found', 'Person profile not found'))\n }\n\n return {\n container,\n auth: authenticatedAuth,\n selectedOrganizationId: scope?.selectedId ?? authenticatedAuth.orgId ?? null,\n em,\n person,\n profile,\n }\n}\n"],
5
- "mappings": "AACA,SAAS,eAAe,gBAAgB;AACxC,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,0CAA0C;AACnD,SAAS,uCAAuC;AAChD,SAAS,2BAA2B;AACpC,SAAS,6BAA6B;AAEtC,eAAsB,kBAAkB,KAAc,UAAkB;AACtE,QAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,UAAU;AACnB,UAAM,IAAI,cAAc,KAAK,EAAE,OAAO,UAAU,iCAAiC,cAAc,EAAE,CAAC;AAAA,EACpG;AACA,QAAM,oBAAoB;AAE1B,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,mBAAmB,SAAS,IAAI,CAAC;AAC3G,QAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC3D,QAAM,kBAAkB;AAAA,IACtB,UAAU,kBAAkB;AAAA,IAC5B,gBAAgB,OAAO,cAAc,kBAAkB,SAAS;AAAA,EAClE;AACA,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,IACA,EAAE,IAAI,UAAU,MAAM,UAAU,UAAU,kBAAkB,UAAU,WAAW,KAAK;AAAA,IACtF,CAAC;AAAA,IACD;AAAA,EACF;AAEA,MAAI,CAAC,QAAQ;AACX,UAAM,SAAS,UAAU,qCAAqC,kBAAkB,CAAC;AAAA,EACnF;AAEA,MAAI,CAAC,gCAAgC,EAAE,OAAO,MAAM,mBAAmB,gBAAgB,OAAO,eAAe,CAAC,GAAG;AAC/G,UAAM,IAAI,cAAc,KAAK,EAAE,OAAO,UAAU,kCAAkC,eAAe,EAAE,CAAC;AAAA,EACtG;AAEA,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA,EAAE,QAAQ,QAAQ,UAAU,OAAO,UAAU,gBAAgB,OAAO,eAAe;AAAA,IACnF,EAAE,UAAU,CAAC,SAAS,EAAE;AAAA,IACxB;AAAA,MACE,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,IACzB;AAAA,EACF;AACA,MAAI,CAAC,SAAS;AACZ,UAAM,SAAS,UAAU,6CAA6C,0BAA0B,CAAC;AAAA,EACnG;AAEA,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,wBAAwB,OAAO,cAAc,kBAAkB,SAAS;AAAA,IACxE;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport {\n CustomerEntity,\n CustomerPersonProfile,\n} from '@open-mercato/core/modules/customers/data/entities'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\nexport async function loadPersonContext(req: Request, personId: string) {\n const { translate } = await resolveTranslations()\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId) {\n throw new CrudHttpError(401, { error: translate('customers.errors.unauthorized', 'Unauthorized') })\n }\n const authenticatedAuth = auth as typeof auth & { tenantId: string }\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth: authenticatedAuth, request: req })\n const em = (container.resolve('em') as EntityManager).fork()\n const decryptionScope = {\n tenantId: authenticatedAuth.tenantId,\n organizationId: scope?.selectedId ?? authenticatedAuth.orgId ?? null,\n }\n const person = await findOneWithDecryption(\n em,\n CustomerEntity,\n { id: personId, kind: 'person', tenantId: authenticatedAuth.tenantId, deletedAt: null },\n {},\n decryptionScope,\n )\n\n if (!person) {\n throw notFound(translate('customers.errors.person_not_found', 'Person not found'))\n }\n\n // Existence oracle (#5504): deny a cross-org read as not-found \u2014 identical to\n // the parent-not-found above \u2014 so it cannot reveal that a person exists in an\n // organization the caller cannot see.\n if (!isOrganizationReadAccessAllowed({ scope, auth: authenticatedAuth, organizationId: person.organizationId })) {\n throw notFound(translate('customers.errors.person_not_found', 'Person not found'))\n }\n\n const profile = await findOneWithDecryption(\n em,\n CustomerPersonProfile,\n { entity: person, tenantId: person.tenantId, organizationId: person.organizationId },\n { populate: ['company'] },\n {\n tenantId: person.tenantId,\n organizationId: person.organizationId,\n },\n )\n if (!profile) {\n throw notFound(translate('customers.errors.person_profile_not_found', 'Person profile not found'))\n }\n\n return {\n container,\n auth: authenticatedAuth,\n selectedOrganizationId: scope?.selectedId ?? authenticatedAuth.orgId ?? null,\n em,\n person,\n profile,\n }\n}\n"],
5
+ "mappings": "AACA,SAAS,eAAe,gBAAgB;AACxC,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,0CAA0C;AACnD,SAAS,uCAAuC;AAChD,SAAS,2BAA2B;AACpC,SAAS,6BAA6B;AAEtC,eAAsB,kBAAkB,KAAc,UAAkB;AACtE,QAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,UAAU;AACnB,UAAM,IAAI,cAAc,KAAK,EAAE,OAAO,UAAU,iCAAiC,cAAc,EAAE,CAAC;AAAA,EACpG;AACA,QAAM,oBAAoB;AAE1B,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,mBAAmB,SAAS,IAAI,CAAC;AAC3G,QAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC3D,QAAM,kBAAkB;AAAA,IACtB,UAAU,kBAAkB;AAAA,IAC5B,gBAAgB,OAAO,cAAc,kBAAkB,SAAS;AAAA,EAClE;AACA,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,IACA,EAAE,IAAI,UAAU,MAAM,UAAU,UAAU,kBAAkB,UAAU,WAAW,KAAK;AAAA,IACtF,CAAC;AAAA,IACD;AAAA,EACF;AAEA,MAAI,CAAC,QAAQ;AACX,UAAM,SAAS,UAAU,qCAAqC,kBAAkB,CAAC;AAAA,EACnF;AAKA,MAAI,CAAC,gCAAgC,EAAE,OAAO,MAAM,mBAAmB,gBAAgB,OAAO,eAAe,CAAC,GAAG;AAC/G,UAAM,SAAS,UAAU,qCAAqC,kBAAkB,CAAC;AAAA,EACnF;AAEA,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA,EAAE,QAAQ,QAAQ,UAAU,OAAO,UAAU,gBAAgB,OAAO,eAAe;AAAA,IACnF,EAAE,UAAU,CAAC,SAAS,EAAE;AAAA,IACxB;AAAA,MACE,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,IACzB;AAAA,EACF;AACA,MAAI,CAAC,SAAS;AACZ,UAAM,SAAS,UAAU,6CAA6C,0BAA0B,CAAC;AAAA,EACnG;AAEA,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,wBAAwB,OAAO,cAAc,kBAAkB,SAAS;AAAA,IACxE;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -153,7 +153,7 @@ async function GET(req, ctx) {
153
153
  throw notFound(translate("customers.errors.person_not_found", "Person not found"));
154
154
  }
155
155
  if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: person.organizationId })) {
156
- throw new CrudHttpError(403, { error: translate("customers.errors.access_denied", "Access denied") });
156
+ throw notFound(translate("customers.errors.person_not_found", "Person not found"));
157
157
  }
158
158
  const entityScope = { tenantId: auth.tenantId, organizationId: person.organizationId };
159
159
  const linkWhere = await withActiveCustomerPersonCompanyLinkFilter(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/customers/api/people/%5Bid%5D/companies/enriched/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError, isCrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'\nimport {\n CustomerEntity,\n CustomerCompanyProfile,\n CustomerPersonCompanyLink,\n CustomerAddress,\n CustomerCompanyBilling,\n CustomerPersonCompanyRole,\n CustomerTagAssignment,\n CustomerDealCompanyLink,\n CustomerDeal,\n CustomerInteraction,\n} from '../../../../../data/entities'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n} from '../../../../../lib/personCompanyLinkTable'\nimport { isOpenDealStatus, isWonDealStatus } from '../../../../../lib/dealStatus'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nconst paramsSchema = z.object({\n id: z.string().uuid(),\n})\n\nconst querySchema = z.object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(20),\n search: z.string().optional(),\n sort: z.enum(['name-asc', 'name-desc', 'recent']).default('name-asc'),\n})\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.people.view'] },\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n methods: {\n GET: {\n summary: 'Get enriched company data for a person\\'s linked companies',\n query: querySchema,\n responses: [\n {\n status: 200,\n description: 'Enriched company rows with profile, billing, tags, deals and more',\n schema: z.object({\n items: z.array(\n z.object({\n linkId: z.string().uuid(),\n companyId: z.string().uuid(),\n displayName: z.string(),\n isPrimary: z.boolean(),\n subtitle: z.string().nullable(),\n profile: z\n .object({\n industry: z.string().nullable(),\n sizeBucket: z.string().nullable(),\n legalName: z.string().nullable(),\n domain: z.string().nullable(),\n websiteUrl: z.string().nullable(),\n })\n .nullable(),\n billing: z\n .object({\n bankName: z.string().nullable(),\n bankAccountMasked: z.string().nullable(),\n paymentTerms: z.string().nullable(),\n preferredCurrency: z.string().nullable(),\n })\n .nullable(),\n primaryAddress: z.object({ formatted: z.string() }).nullable(),\n tags: z.array(\n z.object({\n id: z.string().uuid(),\n label: z.string(),\n color: z.string().nullable(),\n }),\n ),\n roles: z.array(\n z.object({\n id: z.string().uuid(),\n roleValue: z.string(),\n }),\n ),\n activeDeal: z\n .object({\n title: z.string(),\n valueAmount: z.string().nullable(),\n valueCurrency: z.string().nullable(),\n })\n .nullable(),\n lastContactAt: z.string().nullable(),\n clv: z.object({ amount: z.number(), currency: z.string() }).nullable(),\n status: z.string().nullable(),\n lifecycleStage: z.string().nullable(),\n temperature: z.string().nullable(),\n renewalQuarter: z.string().nullable(),\n }),\n ),\n total: z.number().int().nonnegative(),\n page: z.number().int().min(1),\n pageSize: z.number().int().min(1),\n totalPages: z.number().int().min(1),\n }),\n },\n ],\n },\n },\n}\n\nfunction formatAddress(address: CustomerAddress): string {\n return [address.addressLine1, address.city, address.region, address.postalCode]\n .filter(Boolean)\n .join(', ')\n}\n\nfunction buildSubtitle(industry: string | null | undefined, address: CustomerAddress | null): string | null {\n const parts: string[] = []\n if (industry) parts.push(industry)\n if (address) {\n const locationParts = [address.city, address.region].filter(Boolean)\n if (locationParts.length > 0) parts.push(locationParts.join(', '))\n }\n return parts.length > 0 ? parts.join(' \u00B7 ') : null\n}\n\nfunction matchesSearch(item: Record<string, unknown>, query: string): boolean {\n const normalized = query.trim().toLowerCase()\n if (!normalized.length) return true\n return [\n typeof item.displayName === 'string' ? item.displayName : null,\n typeof item.subtitle === 'string' ? item.subtitle : null,\n typeof item.status === 'string' ? item.status : null,\n typeof item.lifecycleStage === 'string' ? item.lifecycleStage : null,\n typeof item.temperature === 'string' ? item.temperature : null,\n typeof item.renewalQuarter === 'string' ? item.renewalQuarter : null,\n ]\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n .some((value) => value.toLowerCase().includes(normalized))\n}\n\nexport async function GET(req: Request, ctx: { params?: { id?: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id } = paramsSchema.parse({ id: ctx.params?.id })\n\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId) {\n throw new CrudHttpError(401, { error: translate('customers.errors.unauthorized', 'Unauthorized') })\n }\n const url = new URL(req.url)\n const query = querySchema.parse({\n page: url.searchParams.get('page') ?? undefined,\n pageSize: url.searchParams.get('pageSize') ?? undefined,\n search: url.searchParams.get('search') ?? undefined,\n sort: url.searchParams.get('sort') ?? undefined,\n })\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const em = (container.resolve('em') as EntityManager).fork()\n\n const decryptionScope = { tenantId: auth.tenantId, organizationId: auth.orgId ?? null }\n const person = await findOneWithDecryption(em, CustomerEntity, { id, kind: 'person', tenantId: auth.tenantId, deletedAt: null }, {}, decryptionScope)\n if (!person) {\n throw notFound(translate('customers.errors.person_not_found', 'Person not found'))\n }\n\n if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: person.organizationId })) {\n throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })\n }\n\n const entityScope = { tenantId: auth.tenantId, organizationId: person.organizationId }\n const linkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n person,\n tenantId: auth.tenantId,\n },\n 'customers.people.companiesEnriched.GET',\n )\n const links = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n linkWhere,\n { populate: ['company'] },\n entityScope,\n ),\n )\n\n const companyIds = links.map((link) => (link.company as CustomerEntity).id)\n\n if (companyIds.length === 0) {\n return NextResponse.json({\n items: [],\n total: 0,\n page: 1,\n pageSize: query.pageSize,\n totalPages: 1,\n })\n }\n\n const tenantScope = { tenantId: auth.tenantId, organizationId: person.organizationId }\n const [allProfiles, allAddresses, allBillings, allTagAssignments, allRoles, allDealLinks, allInteractions] =\n await Promise.all([\n findWithDecryption(em, CustomerCompanyProfile, { entity: { $in: companyIds }, ...tenantScope }, {}, entityScope),\n findWithDecryption(em, CustomerAddress, { entity: { $in: companyIds }, isPrimary: true, ...tenantScope }, {}, entityScope),\n findWithDecryption(em, CustomerCompanyBilling, { entity: { $in: companyIds }, ...tenantScope }, {}, entityScope),\n findWithDecryption(em, CustomerTagAssignment, { entity: { $in: companyIds }, ...tenantScope }, { populate: ['tag'] }, entityScope),\n findWithDecryption(em, CustomerPersonCompanyRole, { personEntity: person, companyEntity: { $in: companyIds }, ...tenantScope }, {}, entityScope),\n // CustomerDealCompanyLink is a pure junction table without tenantId/organizationId columns;\n // scoping flows transitively through the already-tenant-scoped `company` filter.\n findWithDecryption(em, CustomerDealCompanyLink, { company: { $in: companyIds } }, { populate: ['deal'] }, entityScope),\n findWithDecryption(em, CustomerInteraction, {\n entity: { $in: companyIds },\n occurredAt: { $ne: null },\n deletedAt: null,\n ...tenantScope,\n }, { orderBy: { occurredAt: 'DESC' } }, entityScope),\n ])\n\n const profileByCompany = new Map(allProfiles.map((p) => [(p.entity as { id: string }).id, p]))\n const addressByCompany = new Map(allAddresses.map((a) => [(a.entity as { id: string }).id, a]))\n const billingByCompany = new Map(allBillings.map((b) => [(b.entity as { id: string }).id, b]))\n\n const tagsByCompany = new Map<string, typeof allTagAssignments>()\n for (const ta of allTagAssignments) {\n const entityId = (ta.entity as { id: string }).id\n const existing = tagsByCompany.get(entityId) ?? []\n existing.push(ta)\n tagsByCompany.set(entityId, existing)\n }\n\n const rolesByCompany = new Map<string, typeof allRoles>()\n for (const role of allRoles) {\n const entityId = (role.companyEntity as { id: string }).id\n const existing = rolesByCompany.get(entityId) ?? []\n existing.push(role)\n rolesByCompany.set(entityId, existing)\n }\n\n const dealLinksByCompany = new Map<string, typeof allDealLinks>()\n for (const dcl of allDealLinks) {\n const entityId = (dcl.company as { id: string }).id\n const existing = dealLinksByCompany.get(entityId) ?? []\n existing.push(dcl)\n dealLinksByCompany.set(entityId, existing)\n }\n\n const lastInteractionByCompany = new Map<string, CustomerInteraction>()\n for (const interaction of allInteractions) {\n const entityId = (interaction.entity as { id: string }).id\n if (!lastInteractionByCompany.has(entityId)) {\n lastInteractionByCompany.set(entityId, interaction)\n }\n }\n\n const items = links.map((link) => {\n const company = link.company as CustomerEntity\n const companyId = company.id\n const profile = profileByCompany.get(companyId) ?? null\n const primaryAddress = addressByCompany.get(companyId) ?? null\n const billing = billingByCompany.get(companyId) ?? null\n const tagAssignments = tagsByCompany.get(companyId) ?? []\n const roles = rolesByCompany.get(companyId) ?? []\n const companyDealLinks = dealLinksByCompany.get(companyId) ?? []\n const lastInteraction = lastInteractionByCompany.get(companyId) ?? null\n\n const activeDeals = companyDealLinks\n .map((dcl) => dcl.deal as CustomerDeal)\n .filter((deal) => isOpenDealStatus(deal.status) && !deal.deletedAt)\n .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())\n const activeDeal = activeDeals.length > 0 ? activeDeals[0] : null\n\n const wonDeals = companyDealLinks\n .map((dcl) => dcl.deal as CustomerDeal)\n .filter((deal) => isWonDealStatus(deal.status) && !deal.deletedAt)\n let clv: { amount: number; currency: string } | null = null\n if (wonDeals.length > 0) {\n const currencies = new Map<string, number>()\n for (const deal of wonDeals) {\n if (deal.valueAmount) {\n const currency = deal.valueCurrency ?? 'USD'\n currencies.set(currency, (currencies.get(currency) ?? 0) + parseFloat(deal.valueAmount))\n }\n }\n if (currencies.size > 0) {\n const [currency, amount] = currencies.entries().next().value!\n clv = { amount, currency }\n }\n }\n\n return {\n linkId: link.id,\n companyId,\n displayName: company.displayName,\n isPrimary: Boolean(link.isPrimary),\n subtitle: buildSubtitle(profile?.industry, primaryAddress),\n profile: profile\n ? {\n industry: profile.industry ?? null,\n sizeBucket: profile.sizeBucket ?? null,\n legalName: profile.legalName ?? null,\n domain: profile.domain ?? null,\n websiteUrl: profile.websiteUrl ?? null,\n }\n : null,\n billing: billing\n ? {\n bankName: billing.bankName ?? null,\n bankAccountMasked: billing.bankAccountMasked ?? null,\n paymentTerms: billing.paymentTerms ?? null,\n preferredCurrency: billing.preferredCurrency ?? null,\n }\n : null,\n primaryAddress: primaryAddress ? { formatted: formatAddress(primaryAddress) } : null,\n tags: tagAssignments.map((ta) => {\n const tag = ta.tag as { id: string; label: string; color?: string | null }\n return {\n id: tag.id,\n label: tag.label,\n color: tag.color ?? null,\n }\n }),\n roles: roles.map((r) => ({ id: r.id, roleValue: r.roleValue })),\n activeDeal: activeDeal\n ? {\n title: activeDeal.title,\n valueAmount: activeDeal.valueAmount ?? null,\n valueCurrency: activeDeal.valueCurrency ?? null,\n }\n : null,\n lastContactAt: lastInteraction?.occurredAt?.toISOString() ?? null,\n clv,\n status: company.status ?? null,\n lifecycleStage: company.lifecycleStage ?? null,\n temperature: company.temperature ?? null,\n renewalQuarter: company.renewalQuarter ?? null,\n }\n })\n\n const filteredItems = query.search?.trim().length\n ? items.filter((item) => matchesSearch(item as Record<string, unknown>, query.search ?? ''))\n : items\n const sortedItems = [...filteredItems].sort((left, right) => {\n if (query.sort === 'recent') {\n const leftTimestamp = left.lastContactAt ? new Date(left.lastContactAt).getTime() : 0\n const rightTimestamp = right.lastContactAt ? new Date(right.lastContactAt).getTime() : 0\n if (leftTimestamp === rightTimestamp) {\n return left.displayName.localeCompare(right.displayName, undefined, { sensitivity: 'base' })\n }\n return rightTimestamp - leftTimestamp\n }\n const compare = left.displayName.localeCompare(right.displayName, undefined, { sensitivity: 'base' })\n return query.sort === 'name-asc' ? compare : -compare\n })\n\n const total = sortedItems.length\n const totalPages = Math.max(1, Math.ceil(total / query.pageSize))\n const page = Math.min(query.page, totalPages)\n const start = (page - 1) * query.pageSize\n\n return NextResponse.json({\n items: sortedItems.slice(start, start + query.pageSize),\n total,\n page,\n pageSize: query.pageSize,\n totalPages,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n logger.error('/companies/enriched] GET failed', { component: 'people/[id', err })\n return NextResponse.json({ error: translate('customers.errors.internal', 'Internal server error') }, { status: 500 })\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError, isCrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'\nimport {\n CustomerEntity,\n CustomerCompanyProfile,\n CustomerPersonCompanyLink,\n CustomerAddress,\n CustomerCompanyBilling,\n CustomerPersonCompanyRole,\n CustomerTagAssignment,\n CustomerDealCompanyLink,\n CustomerDeal,\n CustomerInteraction,\n} from '../../../../../data/entities'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n} from '../../../../../lib/personCompanyLinkTable'\nimport { isOpenDealStatus, isWonDealStatus } from '../../../../../lib/dealStatus'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nconst paramsSchema = z.object({\n id: z.string().uuid(),\n})\n\nconst querySchema = z.object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(20),\n search: z.string().optional(),\n sort: z.enum(['name-asc', 'name-desc', 'recent']).default('name-asc'),\n})\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.people.view'] },\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n methods: {\n GET: {\n summary: 'Get enriched company data for a person\\'s linked companies',\n query: querySchema,\n responses: [\n {\n status: 200,\n description: 'Enriched company rows with profile, billing, tags, deals and more',\n schema: z.object({\n items: z.array(\n z.object({\n linkId: z.string().uuid(),\n companyId: z.string().uuid(),\n displayName: z.string(),\n isPrimary: z.boolean(),\n subtitle: z.string().nullable(),\n profile: z\n .object({\n industry: z.string().nullable(),\n sizeBucket: z.string().nullable(),\n legalName: z.string().nullable(),\n domain: z.string().nullable(),\n websiteUrl: z.string().nullable(),\n })\n .nullable(),\n billing: z\n .object({\n bankName: z.string().nullable(),\n bankAccountMasked: z.string().nullable(),\n paymentTerms: z.string().nullable(),\n preferredCurrency: z.string().nullable(),\n })\n .nullable(),\n primaryAddress: z.object({ formatted: z.string() }).nullable(),\n tags: z.array(\n z.object({\n id: z.string().uuid(),\n label: z.string(),\n color: z.string().nullable(),\n }),\n ),\n roles: z.array(\n z.object({\n id: z.string().uuid(),\n roleValue: z.string(),\n }),\n ),\n activeDeal: z\n .object({\n title: z.string(),\n valueAmount: z.string().nullable(),\n valueCurrency: z.string().nullable(),\n })\n .nullable(),\n lastContactAt: z.string().nullable(),\n clv: z.object({ amount: z.number(), currency: z.string() }).nullable(),\n status: z.string().nullable(),\n lifecycleStage: z.string().nullable(),\n temperature: z.string().nullable(),\n renewalQuarter: z.string().nullable(),\n }),\n ),\n total: z.number().int().nonnegative(),\n page: z.number().int().min(1),\n pageSize: z.number().int().min(1),\n totalPages: z.number().int().min(1),\n }),\n },\n ],\n },\n },\n}\n\nfunction formatAddress(address: CustomerAddress): string {\n return [address.addressLine1, address.city, address.region, address.postalCode]\n .filter(Boolean)\n .join(', ')\n}\n\nfunction buildSubtitle(industry: string | null | undefined, address: CustomerAddress | null): string | null {\n const parts: string[] = []\n if (industry) parts.push(industry)\n if (address) {\n const locationParts = [address.city, address.region].filter(Boolean)\n if (locationParts.length > 0) parts.push(locationParts.join(', '))\n }\n return parts.length > 0 ? parts.join(' \u00B7 ') : null\n}\n\nfunction matchesSearch(item: Record<string, unknown>, query: string): boolean {\n const normalized = query.trim().toLowerCase()\n if (!normalized.length) return true\n return [\n typeof item.displayName === 'string' ? item.displayName : null,\n typeof item.subtitle === 'string' ? item.subtitle : null,\n typeof item.status === 'string' ? item.status : null,\n typeof item.lifecycleStage === 'string' ? item.lifecycleStage : null,\n typeof item.temperature === 'string' ? item.temperature : null,\n typeof item.renewalQuarter === 'string' ? item.renewalQuarter : null,\n ]\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n .some((value) => value.toLowerCase().includes(normalized))\n}\n\nexport async function GET(req: Request, ctx: { params?: { id?: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id } = paramsSchema.parse({ id: ctx.params?.id })\n\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId) {\n throw new CrudHttpError(401, { error: translate('customers.errors.unauthorized', 'Unauthorized') })\n }\n const url = new URL(req.url)\n const query = querySchema.parse({\n page: url.searchParams.get('page') ?? undefined,\n pageSize: url.searchParams.get('pageSize') ?? undefined,\n search: url.searchParams.get('search') ?? undefined,\n sort: url.searchParams.get('sort') ?? undefined,\n })\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const em = (container.resolve('em') as EntityManager).fork()\n\n const decryptionScope = { tenantId: auth.tenantId, organizationId: auth.orgId ?? null }\n const person = await findOneWithDecryption(em, CustomerEntity, { id, kind: 'person', tenantId: auth.tenantId, deletedAt: null }, {}, decryptionScope)\n if (!person) {\n throw notFound(translate('customers.errors.person_not_found', 'Person not found'))\n }\n\n // Existence oracle (#5504): deny a cross-org read as not-found \u2014 identical to\n // the parent-not-found above \u2014 so it cannot reveal that a person exists in an\n // organization the caller cannot see.\n if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: person.organizationId })) {\n throw notFound(translate('customers.errors.person_not_found', 'Person not found'))\n }\n\n const entityScope = { tenantId: auth.tenantId, organizationId: person.organizationId }\n const linkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n person,\n tenantId: auth.tenantId,\n },\n 'customers.people.companiesEnriched.GET',\n )\n const links = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n linkWhere,\n { populate: ['company'] },\n entityScope,\n ),\n )\n\n const companyIds = links.map((link) => (link.company as CustomerEntity).id)\n\n if (companyIds.length === 0) {\n return NextResponse.json({\n items: [],\n total: 0,\n page: 1,\n pageSize: query.pageSize,\n totalPages: 1,\n })\n }\n\n const tenantScope = { tenantId: auth.tenantId, organizationId: person.organizationId }\n const [allProfiles, allAddresses, allBillings, allTagAssignments, allRoles, allDealLinks, allInteractions] =\n await Promise.all([\n findWithDecryption(em, CustomerCompanyProfile, { entity: { $in: companyIds }, ...tenantScope }, {}, entityScope),\n findWithDecryption(em, CustomerAddress, { entity: { $in: companyIds }, isPrimary: true, ...tenantScope }, {}, entityScope),\n findWithDecryption(em, CustomerCompanyBilling, { entity: { $in: companyIds }, ...tenantScope }, {}, entityScope),\n findWithDecryption(em, CustomerTagAssignment, { entity: { $in: companyIds }, ...tenantScope }, { populate: ['tag'] }, entityScope),\n findWithDecryption(em, CustomerPersonCompanyRole, { personEntity: person, companyEntity: { $in: companyIds }, ...tenantScope }, {}, entityScope),\n // CustomerDealCompanyLink is a pure junction table without tenantId/organizationId columns;\n // scoping flows transitively through the already-tenant-scoped `company` filter.\n findWithDecryption(em, CustomerDealCompanyLink, { company: { $in: companyIds } }, { populate: ['deal'] }, entityScope),\n findWithDecryption(em, CustomerInteraction, {\n entity: { $in: companyIds },\n occurredAt: { $ne: null },\n deletedAt: null,\n ...tenantScope,\n }, { orderBy: { occurredAt: 'DESC' } }, entityScope),\n ])\n\n const profileByCompany = new Map(allProfiles.map((p) => [(p.entity as { id: string }).id, p]))\n const addressByCompany = new Map(allAddresses.map((a) => [(a.entity as { id: string }).id, a]))\n const billingByCompany = new Map(allBillings.map((b) => [(b.entity as { id: string }).id, b]))\n\n const tagsByCompany = new Map<string, typeof allTagAssignments>()\n for (const ta of allTagAssignments) {\n const entityId = (ta.entity as { id: string }).id\n const existing = tagsByCompany.get(entityId) ?? []\n existing.push(ta)\n tagsByCompany.set(entityId, existing)\n }\n\n const rolesByCompany = new Map<string, typeof allRoles>()\n for (const role of allRoles) {\n const entityId = (role.companyEntity as { id: string }).id\n const existing = rolesByCompany.get(entityId) ?? []\n existing.push(role)\n rolesByCompany.set(entityId, existing)\n }\n\n const dealLinksByCompany = new Map<string, typeof allDealLinks>()\n for (const dcl of allDealLinks) {\n const entityId = (dcl.company as { id: string }).id\n const existing = dealLinksByCompany.get(entityId) ?? []\n existing.push(dcl)\n dealLinksByCompany.set(entityId, existing)\n }\n\n const lastInteractionByCompany = new Map<string, CustomerInteraction>()\n for (const interaction of allInteractions) {\n const entityId = (interaction.entity as { id: string }).id\n if (!lastInteractionByCompany.has(entityId)) {\n lastInteractionByCompany.set(entityId, interaction)\n }\n }\n\n const items = links.map((link) => {\n const company = link.company as CustomerEntity\n const companyId = company.id\n const profile = profileByCompany.get(companyId) ?? null\n const primaryAddress = addressByCompany.get(companyId) ?? null\n const billing = billingByCompany.get(companyId) ?? null\n const tagAssignments = tagsByCompany.get(companyId) ?? []\n const roles = rolesByCompany.get(companyId) ?? []\n const companyDealLinks = dealLinksByCompany.get(companyId) ?? []\n const lastInteraction = lastInteractionByCompany.get(companyId) ?? null\n\n const activeDeals = companyDealLinks\n .map((dcl) => dcl.deal as CustomerDeal)\n .filter((deal) => isOpenDealStatus(deal.status) && !deal.deletedAt)\n .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())\n const activeDeal = activeDeals.length > 0 ? activeDeals[0] : null\n\n const wonDeals = companyDealLinks\n .map((dcl) => dcl.deal as CustomerDeal)\n .filter((deal) => isWonDealStatus(deal.status) && !deal.deletedAt)\n let clv: { amount: number; currency: string } | null = null\n if (wonDeals.length > 0) {\n const currencies = new Map<string, number>()\n for (const deal of wonDeals) {\n if (deal.valueAmount) {\n const currency = deal.valueCurrency ?? 'USD'\n currencies.set(currency, (currencies.get(currency) ?? 0) + parseFloat(deal.valueAmount))\n }\n }\n if (currencies.size > 0) {\n const [currency, amount] = currencies.entries().next().value!\n clv = { amount, currency }\n }\n }\n\n return {\n linkId: link.id,\n companyId,\n displayName: company.displayName,\n isPrimary: Boolean(link.isPrimary),\n subtitle: buildSubtitle(profile?.industry, primaryAddress),\n profile: profile\n ? {\n industry: profile.industry ?? null,\n sizeBucket: profile.sizeBucket ?? null,\n legalName: profile.legalName ?? null,\n domain: profile.domain ?? null,\n websiteUrl: profile.websiteUrl ?? null,\n }\n : null,\n billing: billing\n ? {\n bankName: billing.bankName ?? null,\n bankAccountMasked: billing.bankAccountMasked ?? null,\n paymentTerms: billing.paymentTerms ?? null,\n preferredCurrency: billing.preferredCurrency ?? null,\n }\n : null,\n primaryAddress: primaryAddress ? { formatted: formatAddress(primaryAddress) } : null,\n tags: tagAssignments.map((ta) => {\n const tag = ta.tag as { id: string; label: string; color?: string | null }\n return {\n id: tag.id,\n label: tag.label,\n color: tag.color ?? null,\n }\n }),\n roles: roles.map((r) => ({ id: r.id, roleValue: r.roleValue })),\n activeDeal: activeDeal\n ? {\n title: activeDeal.title,\n valueAmount: activeDeal.valueAmount ?? null,\n valueCurrency: activeDeal.valueCurrency ?? null,\n }\n : null,\n lastContactAt: lastInteraction?.occurredAt?.toISOString() ?? null,\n clv,\n status: company.status ?? null,\n lifecycleStage: company.lifecycleStage ?? null,\n temperature: company.temperature ?? null,\n renewalQuarter: company.renewalQuarter ?? null,\n }\n })\n\n const filteredItems = query.search?.trim().length\n ? items.filter((item) => matchesSearch(item as Record<string, unknown>, query.search ?? ''))\n : items\n const sortedItems = [...filteredItems].sort((left, right) => {\n if (query.sort === 'recent') {\n const leftTimestamp = left.lastContactAt ? new Date(left.lastContactAt).getTime() : 0\n const rightTimestamp = right.lastContactAt ? new Date(right.lastContactAt).getTime() : 0\n if (leftTimestamp === rightTimestamp) {\n return left.displayName.localeCompare(right.displayName, undefined, { sensitivity: 'base' })\n }\n return rightTimestamp - leftTimestamp\n }\n const compare = left.displayName.localeCompare(right.displayName, undefined, { sensitivity: 'base' })\n return query.sort === 'name-asc' ? compare : -compare\n })\n\n const total = sortedItems.length\n const totalPages = Math.max(1, Math.ceil(total / query.pageSize))\n const page = Math.min(query.page, totalPages)\n const start = (page - 1) * query.pageSize\n\n return NextResponse.json({\n items: sortedItems.slice(start, start + query.pageSize),\n total,\n page,\n pageSize: query.pageSize,\n totalPages,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n logger.error('/companies/enriched] GET failed', { component: 'people/[id', err })\n return NextResponse.json({ error: translate('customers.errors.internal', 'Internal server error') }, { status: 500 })\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAElB,SAAS,eAAe,iBAAiB,gBAAgB;AACzD,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,0CAA0C;AACnD,SAAS,2BAA2B;AAEpC,SAAS,oBAAoB,6BAA6B;AAC1D,SAAS,uCAAuC;AAChD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB,uBAAuB;AAClD,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,WAAW;AAEvC,MAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,IAAI,EAAE,OAAO,EAAE,KAAK;AACtB,CAAC;AAED,MAAM,cAAc,EAAE,OAAO;AAAA,EAC3B,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AAAA,EACxC,UAAU,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA,EACtD,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,MAAM,EAAE,KAAK,CAAC,YAAY,aAAa,QAAQ,CAAC,EAAE,QAAQ,UAAU;AACtE,CAAC;AAEM,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,uBAAuB,EAAE;AACvE;AAEO,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,OAAO;AAAA,MACP,WAAW;AAAA,QACT;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO;AAAA,YACf,OAAO,EAAE;AAAA,cACP,EAAE,OAAO;AAAA,gBACP,QAAQ,EAAE,OAAO,EAAE,KAAK;AAAA,gBACxB,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,gBAC3B,aAAa,EAAE,OAAO;AAAA,gBACtB,WAAW,EAAE,QAAQ;AAAA,gBACrB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,gBAC9B,SAAS,EACN,OAAO;AAAA,kBACN,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,kBAC9B,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,kBAChC,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,kBAC/B,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,kBAC5B,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,gBAClC,CAAC,EACA,SAAS;AAAA,gBACZ,SAAS,EACN,OAAO;AAAA,kBACN,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,kBAC9B,mBAAmB,EAAE,OAAO,EAAE,SAAS;AAAA,kBACvC,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,kBAClC,mBAAmB,EAAE,OAAO,EAAE,SAAS;AAAA,gBACzC,CAAC,EACA,SAAS;AAAA,gBACZ,gBAAgB,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS;AAAA,gBAC7D,MAAM,EAAE;AAAA,kBACN,EAAE,OAAO;AAAA,oBACP,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,oBACpB,OAAO,EAAE,OAAO;AAAA,oBAChB,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,kBAC7B,CAAC;AAAA,gBACH;AAAA,gBACA,OAAO,EAAE;AAAA,kBACP,EAAE,OAAO;AAAA,oBACP,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,oBACpB,WAAW,EAAE,OAAO;AAAA,kBACtB,CAAC;AAAA,gBACH;AAAA,gBACA,YAAY,EACT,OAAO;AAAA,kBACN,OAAO,EAAE,OAAO;AAAA,kBAChB,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,kBACjC,eAAe,EAAE,OAAO,EAAE,SAAS;AAAA,gBACrC,CAAC,EACA,SAAS;AAAA,gBACZ,eAAe,EAAE,OAAO,EAAE,SAAS;AAAA,gBACnC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,UAAU,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS;AAAA,gBACrE,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,gBAC5B,gBAAgB,EAAE,OAAO,EAAE,SAAS;AAAA,gBACpC,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,gBACjC,gBAAgB,EAAE,OAAO,EAAE,SAAS;AAAA,cACtC,CAAC;AAAA,YACH;AAAA,YACA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,YACpC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;AAAA,YAC5B,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;AAAA,YAChC,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;AAAA,UACpC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,cAAc,SAAkC;AACvD,SAAO,CAAC,QAAQ,cAAc,QAAQ,MAAM,QAAQ,QAAQ,QAAQ,UAAU,EAC3E,OAAO,OAAO,EACd,KAAK,IAAI;AACd;AAEA,SAAS,cAAc,UAAqC,SAAgD;AAC1G,QAAM,QAAkB,CAAC;AACzB,MAAI,SAAU,OAAM,KAAK,QAAQ;AACjC,MAAI,SAAS;AACX,UAAM,gBAAgB,CAAC,QAAQ,MAAM,QAAQ,MAAM,EAAE,OAAO,OAAO;AACnE,QAAI,cAAc,SAAS,EAAG,OAAM,KAAK,cAAc,KAAK,IAAI,CAAC;AAAA,EACnE;AACA,SAAO,MAAM,SAAS,IAAI,MAAM,KAAK,QAAK,IAAI;AAChD;AAEA,SAAS,cAAc,MAA+B,OAAwB;AAC5E,QAAM,aAAa,MAAM,KAAK,EAAE,YAAY;AAC5C,MAAI,CAAC,WAAW,OAAQ,QAAO;AAC/B,SAAO;AAAA,IACL,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc;AAAA,IAC1D,OAAO,KAAK,aAAa,WAAW,KAAK,WAAW;AAAA,IACpD,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;AAAA,IAChD,OAAO,KAAK,mBAAmB,WAAW,KAAK,iBAAiB;AAAA,IAChE,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc;AAAA,IAC1D,OAAO,KAAK,mBAAmB,WAAW,KAAK,iBAAiB;AAAA,EAClE,EACG,OAAO,CAAC,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC,EAChF,KAAK,CAAC,UAAU,MAAM,YAAY,EAAE,SAAS,UAAU,CAAC;AAC7D;AAEA,eAAsB,IAAI,KAAc,KAAmC;AACzE,QAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,MAAI;AACF,UAAM,EAAE,GAAG,IAAI,aAAa,MAAM,EAAE,IAAI,IAAI,QAAQ,GAAG,CAAC;AAExD,UAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,QAAI,CAAC,MAAM,UAAU;AACnB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,UAAU,iCAAiC,cAAc,EAAE,CAAC;AAAA,IACpG;AACA,UAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,UAAM,QAAQ,YAAY,MAAM;AAAA,MAC9B,MAAM,IAAI,aAAa,IAAI,MAAM,KAAK;AAAA,MACtC,UAAU,IAAI,aAAa,IAAI,UAAU,KAAK;AAAA,MAC9C,QAAQ,IAAI,aAAa,IAAI,QAAQ,KAAK;AAAA,MAC1C,MAAM,IAAI,aAAa,IAAI,MAAM,KAAK;AAAA,IACxC,CAAC;AAED,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,SAAS,IAAI,CAAC;AACxF,UAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAE3D,UAAM,kBAAkB,EAAE,UAAU,KAAK,UAAU,gBAAgB,KAAK,SAAS,KAAK;AACtF,UAAM,SAAS,MAAM,sBAAsB,IAAI,gBAAgB,EAAE,IAAI,MAAM,UAAU,UAAU,KAAK,UAAU,WAAW,KAAK,GAAG,CAAC,GAAG,eAAe;AACpJ,QAAI,CAAC,QAAQ;AACX,YAAM,SAAS,UAAU,qCAAqC,kBAAkB,CAAC;AAAA,IACnF;AAKA,QAAI,CAAC,gCAAgC,EAAE,OAAO,MAAM,gBAAgB,OAAO,eAAe,CAAC,GAAG;AAC5F,YAAM,SAAS,UAAU,qCAAqC,kBAAkB,CAAC;AAAA,IACnF;AAEA,UAAM,cAAc,EAAE,UAAU,KAAK,UAAU,gBAAgB,OAAO,eAAe;AACrF,UAAM,YAAY,MAAM;AAAA,MACtB;AAAA,MACA;AAAA,QACE;AAAA,QACA,UAAU,KAAK;AAAA,MACjB;AAAA,MACA;AAAA,IACF;AACA,UAAM,QAAQ;AAAA,MACZ,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA,EAAE,UAAU,CAAC,SAAS,EAAE;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAa,MAAM,IAAI,CAAC,SAAU,KAAK,QAA2B,EAAE;AAE1E,QAAI,WAAW,WAAW,GAAG;AAC3B,aAAO,aAAa,KAAK;AAAA,QACvB,OAAO,CAAC;AAAA,QACR,OAAO;AAAA,QACP,MAAM;AAAA,QACN,UAAU,MAAM;AAAA,QAChB,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAEA,UAAM,cAAc,EAAE,UAAU,KAAK,UAAU,gBAAgB,OAAO,eAAe;AACrF,UAAM,CAAC,aAAa,cAAc,aAAa,mBAAmB,UAAU,cAAc,eAAe,IACvG,MAAM,QAAQ,IAAI;AAAA,MAChB,mBAAmB,IAAI,wBAAwB,EAAE,QAAQ,EAAE,KAAK,WAAW,GAAG,GAAG,YAAY,GAAG,CAAC,GAAG,WAAW;AAAA,MAC/G,mBAAmB,IAAI,iBAAiB,EAAE,QAAQ,EAAE,KAAK,WAAW,GAAG,WAAW,MAAM,GAAG,YAAY,GAAG,CAAC,GAAG,WAAW;AAAA,MACzH,mBAAmB,IAAI,wBAAwB,EAAE,QAAQ,EAAE,KAAK,WAAW,GAAG,GAAG,YAAY,GAAG,CAAC,GAAG,WAAW;AAAA,MAC/G,mBAAmB,IAAI,uBAAuB,EAAE,QAAQ,EAAE,KAAK,WAAW,GAAG,GAAG,YAAY,GAAG,EAAE,UAAU,CAAC,KAAK,EAAE,GAAG,WAAW;AAAA,MACjI,mBAAmB,IAAI,2BAA2B,EAAE,cAAc,QAAQ,eAAe,EAAE,KAAK,WAAW,GAAG,GAAG,YAAY,GAAG,CAAC,GAAG,WAAW;AAAA;AAAA;AAAA,MAG/I,mBAAmB,IAAI,yBAAyB,EAAE,SAAS,EAAE,KAAK,WAAW,EAAE,GAAG,EAAE,UAAU,CAAC,MAAM,EAAE,GAAG,WAAW;AAAA,MACrH,mBAAmB,IAAI,qBAAqB;AAAA,QAC1C,QAAQ,EAAE,KAAK,WAAW;AAAA,QAC1B,YAAY,EAAE,KAAK,KAAK;AAAA,QACxB,WAAW;AAAA,QACX,GAAG;AAAA,MACL,GAAG,EAAE,SAAS,EAAE,YAAY,OAAO,EAAE,GAAG,WAAW;AAAA,IACrD,CAAC;AAEH,UAAM,mBAAmB,IAAI,IAAI,YAAY,IAAI,CAAC,MAAM,CAAE,EAAE,OAA0B,IAAI,CAAC,CAAC,CAAC;AAC7F,UAAM,mBAAmB,IAAI,IAAI,aAAa,IAAI,CAAC,MAAM,CAAE,EAAE,OAA0B,IAAI,CAAC,CAAC,CAAC;AAC9F,UAAM,mBAAmB,IAAI,IAAI,YAAY,IAAI,CAAC,MAAM,CAAE,EAAE,OAA0B,IAAI,CAAC,CAAC,CAAC;AAE7F,UAAM,gBAAgB,oBAAI,IAAsC;AAChE,eAAW,MAAM,mBAAmB;AAClC,YAAM,WAAY,GAAG,OAA0B;AAC/C,YAAM,WAAW,cAAc,IAAI,QAAQ,KAAK,CAAC;AACjD,eAAS,KAAK,EAAE;AAChB,oBAAc,IAAI,UAAU,QAAQ;AAAA,IACtC;AAEA,UAAM,iBAAiB,oBAAI,IAA6B;AACxD,eAAW,QAAQ,UAAU;AAC3B,YAAM,WAAY,KAAK,cAAiC;AACxD,YAAM,WAAW,eAAe,IAAI,QAAQ,KAAK,CAAC;AAClD,eAAS,KAAK,IAAI;AAClB,qBAAe,IAAI,UAAU,QAAQ;AAAA,IACvC;AAEA,UAAM,qBAAqB,oBAAI,IAAiC;AAChE,eAAW,OAAO,cAAc;AAC9B,YAAM,WAAY,IAAI,QAA2B;AACjD,YAAM,WAAW,mBAAmB,IAAI,QAAQ,KAAK,CAAC;AACtD,eAAS,KAAK,GAAG;AACjB,yBAAmB,IAAI,UAAU,QAAQ;AAAA,IAC3C;AAEA,UAAM,2BAA2B,oBAAI,IAAiC;AACtE,eAAW,eAAe,iBAAiB;AACzC,YAAM,WAAY,YAAY,OAA0B;AACxD,UAAI,CAAC,yBAAyB,IAAI,QAAQ,GAAG;AAC3C,iCAAyB,IAAI,UAAU,WAAW;AAAA,MACpD;AAAA,IACF;AAEA,UAAM,QAAQ,MAAM,IAAI,CAAC,SAAS;AAChC,YAAM,UAAU,KAAK;AACrB,YAAM,YAAY,QAAQ;AAC1B,YAAM,UAAU,iBAAiB,IAAI,SAAS,KAAK;AACnD,YAAM,iBAAiB,iBAAiB,IAAI,SAAS,KAAK;AAC1D,YAAM,UAAU,iBAAiB,IAAI,SAAS,KAAK;AACnD,YAAM,iBAAiB,cAAc,IAAI,SAAS,KAAK,CAAC;AACxD,YAAM,QAAQ,eAAe,IAAI,SAAS,KAAK,CAAC;AAChD,YAAM,mBAAmB,mBAAmB,IAAI,SAAS,KAAK,CAAC;AAC/D,YAAM,kBAAkB,yBAAyB,IAAI,SAAS,KAAK;AAEnE,YAAM,cAAc,iBACjB,IAAI,CAAC,QAAQ,IAAI,IAAoB,EACrC,OAAO,CAAC,SAAS,iBAAiB,KAAK,MAAM,KAAK,CAAC,KAAK,SAAS,EACjE,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,QAAQ,IAAI,EAAE,UAAU,QAAQ,CAAC;AAC/D,YAAM,aAAa,YAAY,SAAS,IAAI,YAAY,CAAC,IAAI;AAE7D,YAAM,WAAW,iBACd,IAAI,CAAC,QAAQ,IAAI,IAAoB,EACrC,OAAO,CAAC,SAAS,gBAAgB,KAAK,MAAM,KAAK,CAAC,KAAK,SAAS;AACnE,UAAI,MAAmD;AACvD,UAAI,SAAS,SAAS,GAAG;AACvB,cAAM,aAAa,oBAAI,IAAoB;AAC3C,mBAAW,QAAQ,UAAU;AAC3B,cAAI,KAAK,aAAa;AACpB,kBAAM,WAAW,KAAK,iBAAiB;AACvC,uBAAW,IAAI,WAAW,WAAW,IAAI,QAAQ,KAAK,KAAK,WAAW,KAAK,WAAW,CAAC;AAAA,UACzF;AAAA,QACF;AACA,YAAI,WAAW,OAAO,GAAG;AACvB,gBAAM,CAAC,UAAU,MAAM,IAAI,WAAW,QAAQ,EAAE,KAAK,EAAE;AACvD,gBAAM,EAAE,QAAQ,SAAS;AAAA,QAC3B;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb;AAAA,QACA,aAAa,QAAQ;AAAA,QACrB,WAAW,QAAQ,KAAK,SAAS;AAAA,QACjC,UAAU,cAAc,SAAS,UAAU,cAAc;AAAA,QACzD,SAAS,UACL;AAAA,UACE,UAAU,QAAQ,YAAY;AAAA,UAC9B,YAAY,QAAQ,cAAc;AAAA,UAClC,WAAW,QAAQ,aAAa;AAAA,UAChC,QAAQ,QAAQ,UAAU;AAAA,UAC1B,YAAY,QAAQ,cAAc;AAAA,QACpC,IACA;AAAA,QACJ,SAAS,UACL;AAAA,UACE,UAAU,QAAQ,YAAY;AAAA,UAC9B,mBAAmB,QAAQ,qBAAqB;AAAA,UAChD,cAAc,QAAQ,gBAAgB;AAAA,UACtC,mBAAmB,QAAQ,qBAAqB;AAAA,QAClD,IACA;AAAA,QACJ,gBAAgB,iBAAiB,EAAE,WAAW,cAAc,cAAc,EAAE,IAAI;AAAA,QAChF,MAAM,eAAe,IAAI,CAAC,OAAO;AAC/B,gBAAM,MAAM,GAAG;AACf,iBAAO;AAAA,YACL,IAAI,IAAI;AAAA,YACR,OAAO,IAAI;AAAA,YACX,OAAO,IAAI,SAAS;AAAA,UACtB;AAAA,QACF,CAAC;AAAA,QACD,OAAO,MAAM,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,WAAW,EAAE,UAAU,EAAE;AAAA,QAC9D,YAAY,aACR;AAAA,UACE,OAAO,WAAW;AAAA,UAClB,aAAa,WAAW,eAAe;AAAA,UACvC,eAAe,WAAW,iBAAiB;AAAA,QAC7C,IACA;AAAA,QACJ,eAAe,iBAAiB,YAAY,YAAY,KAAK;AAAA,QAC7D;AAAA,QACA,QAAQ,QAAQ,UAAU;AAAA,QAC1B,gBAAgB,QAAQ,kBAAkB;AAAA,QAC1C,aAAa,QAAQ,eAAe;AAAA,QACpC,gBAAgB,QAAQ,kBAAkB;AAAA,MAC5C;AAAA,IACF,CAAC;AAED,UAAM,gBAAgB,MAAM,QAAQ,KAAK,EAAE,SACvC,MAAM,OAAO,CAAC,SAAS,cAAc,MAAiC,MAAM,UAAU,EAAE,CAAC,IACzF;AACJ,UAAM,cAAc,CAAC,GAAG,aAAa,EAAE,KAAK,CAAC,MAAM,UAAU;AAC3D,UAAI,MAAM,SAAS,UAAU;AAC3B,cAAM,gBAAgB,KAAK,gBAAgB,IAAI,KAAK,KAAK,aAAa,EAAE,QAAQ,IAAI;AACpF,cAAM,iBAAiB,MAAM,gBAAgB,IAAI,KAAK,MAAM,aAAa,EAAE,QAAQ,IAAI;AACvF,YAAI,kBAAkB,gBAAgB;AACpC,iBAAO,KAAK,YAAY,cAAc,MAAM,aAAa,QAAW,EAAE,aAAa,OAAO,CAAC;AAAA,QAC7F;AACA,eAAO,iBAAiB;AAAA,MAC1B;AACA,YAAM,UAAU,KAAK,YAAY,cAAc,MAAM,aAAa,QAAW,EAAE,aAAa,OAAO,CAAC;AACpG,aAAO,MAAM,SAAS,aAAa,UAAU,CAAC;AAAA,IAChD,CAAC;AAED,UAAM,QAAQ,YAAY;AAC1B,UAAM,aAAa,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,MAAM,QAAQ,CAAC;AAChE,UAAM,OAAO,KAAK,IAAI,MAAM,MAAM,UAAU;AAC5C,UAAM,SAAS,OAAO,KAAK,MAAM;AAEjC,WAAO,aAAa,KAAK;AAAA,MACvB,OAAO,YAAY,MAAM,OAAO,QAAQ,MAAM,QAAQ;AAAA,MACtD;AAAA,MACA;AAAA,MACA,UAAU,MAAM;AAAA,MAChB;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,QAAI,gBAAgB,GAAG,GAAG;AACxB,aAAO,aAAa,KAAK,IAAI,MAAM,EAAE,QAAQ,IAAI,OAAO,CAAC;AAAA,IAC3D;AACA,WAAO,MAAM,mCAAmC,EAAE,WAAW,cAAc,IAAI,CAAC;AAChF,WAAO,aAAa,KAAK,EAAE,OAAO,UAAU,6BAA6B,uBAAuB,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACtH;AACF;",
6
6
  "names": []
7
7
  }
@@ -31,7 +31,7 @@ import { resolveCustomerInteractionFeatureFlags } from "../../../lib/interaction
31
31
  import { hydrateCanonicalInteractions } from "../../../lib/interactionReadModel.js";
32
32
  import { findWithDecryption, findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
33
33
  import { parseBooleanFromUnknown, parseBooleanToken } from "@open-mercato/shared/lib/boolean";
34
- import { isOrganizationReadAccessAllowed } from "@open-mercato/core/modules/directory/utils/organizationScopeGuard";
34
+ import { denyCustomerDetailReadAsNotFound } from "../../../lib/detailReadAccess.js";
35
35
  import { loadPersonCompanyLinks, summarizePersonCompanies } from "../../../lib/personCompanies.js";
36
36
  import { normalizeCustomerDetailCustomFields } from "../../detailCustomFields.js";
37
37
  import { buildEmailVisibilityMikroFilter } from "../../../lib/visibilityFilter.js";
@@ -89,9 +89,6 @@ function parseIncludeParams(request) {
89
89
  });
90
90
  return tokens;
91
91
  }
92
- function forbidden(message) {
93
- return NextResponse.json({ error: message }, { status: 403 });
94
- }
95
92
  function notFound(message) {
96
93
  return NextResponse.json({ error: message }, { status: 404 });
97
94
  }
@@ -443,10 +440,14 @@ async function GET(_req, ctx) {
443
440
  profileMeta = { reason: "person_not_found" };
444
441
  return notFound("Person not found");
445
442
  }
446
- if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: person.organizationId })) {
447
- statusCode = 403;
448
- profileMeta = { reason: "organization_forbidden" };
449
- return forbidden("Access denied");
443
+ const organizationReadDenied = denyCustomerDetailReadAsNotFound(
444
+ { scope, auth, organizationId: person.organizationId },
445
+ "Person not found"
446
+ );
447
+ if (organizationReadDenied) {
448
+ statusCode = 404;
449
+ profileMeta = { reason: "organization_not_in_scope" };
450
+ return organizationReadDenied;
450
451
  }
451
452
  const personDetailTenantId = person.tenantId ?? auth.tenantId ?? null;
452
453
  const personDetailOrganizationId = person.organizationId ?? null;
@@ -1113,8 +1114,8 @@ const openApi = {
1113
1114
  errors: [
1114
1115
  { status: 400, description: "Invalid identifier", schema: personDetailErrorSchema },
1115
1116
  { status: 401, description: "Unauthorized", schema: personDetailErrorSchema },
1116
- { status: 403, description: "Forbidden for tenant/organization scope", schema: personDetailErrorSchema },
1117
- { status: 404, description: "Person not found", schema: personDetailErrorSchema }
1117
+ { status: 403, description: "Forbidden \u2014 caller lacks the required feature", schema: personDetailErrorSchema },
1118
+ { status: 404, description: "Person not found, or its organization is not in the caller\u2019s scope", schema: personDetailErrorSchema }
1118
1119
  ]
1119
1120
  }
1120
1121
  }