@open-mercato/core 0.6.5-develop.5337.1.534b781eac → 0.6.5

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 (350) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +1 -1
  3. package/dist/bootstrap.js +46 -6
  4. package/dist/bootstrap.js.map +2 -2
  5. package/dist/generated/entities/organization/index.js +2 -0
  6. package/dist/generated/entities/organization/index.js.map +2 -2
  7. package/dist/generated/entity-fields-registry.js +1 -0
  8. package/dist/generated/entity-fields-registry.js.map +2 -2
  9. package/dist/helpers/integration/crmFixtures.js +4 -0
  10. package/dist/helpers/integration/crmFixtures.js.map +2 -2
  11. package/dist/modules/attachments/api/library/route.js +2 -2
  12. package/dist/modules/attachments/api/library/route.js.map +2 -2
  13. package/dist/modules/attachments/api/route.js +2 -0
  14. package/dist/modules/attachments/api/route.js.map +2 -2
  15. package/dist/modules/attachments/components/AttachmentContentPreview.js +9 -5
  16. package/dist/modules/attachments/components/AttachmentContentPreview.js.map +2 -2
  17. package/dist/modules/attachments/lib/access.js +18 -0
  18. package/dist/modules/attachments/lib/access.js.map +2 -2
  19. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js +3 -2
  20. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +2 -2
  21. package/dist/modules/audit_logs/data/entities.js +2 -1
  22. package/dist/modules/audit_logs/data/entities.js.map +2 -2
  23. package/dist/modules/audit_logs/migrations/Migration20260611104500.js +13 -0
  24. package/dist/modules/audit_logs/migrations/Migration20260611104500.js.map +7 -0
  25. package/dist/modules/audit_logs/services/accessLogService.js +10 -0
  26. package/dist/modules/audit_logs/services/accessLogService.js.map +2 -2
  27. package/dist/modules/auth/api/admin/nav.js +9 -0
  28. package/dist/modules/auth/api/admin/nav.js.map +2 -2
  29. package/dist/modules/auth/api/login.js +4 -13
  30. package/dist/modules/auth/api/login.js.map +2 -2
  31. package/dist/modules/auth/commands/users.js +20 -14
  32. package/dist/modules/auth/commands/users.js.map +2 -2
  33. package/dist/modules/auth/data/entities.js +4 -2
  34. package/dist/modules/auth/data/entities.js.map +2 -2
  35. package/dist/modules/auth/lib/backendChrome.js +35 -2
  36. package/dist/modules/auth/lib/backendChrome.js.map +2 -2
  37. package/dist/modules/auth/lib/consentIntegrity.js +3 -3
  38. package/dist/modules/auth/lib/consentIntegrity.js.map +2 -2
  39. package/dist/modules/auth/migrations/Migration20260610120000.js +30 -0
  40. package/dist/modules/auth/migrations/Migration20260610120000.js.map +7 -0
  41. package/dist/modules/auth/migrations/Migration20260611103000.js +15 -0
  42. package/dist/modules/auth/migrations/Migration20260611103000.js.map +7 -0
  43. package/dist/modules/auth/services/authService.js +5 -3
  44. package/dist/modules/auth/services/authService.js.map +2 -2
  45. package/dist/modules/auth/services/rbacService.js +3 -2
  46. package/dist/modules/auth/services/rbacService.js.map +2 -2
  47. package/dist/modules/catalog/ai-tools/configuration-pack.js.map +1 -1
  48. package/dist/modules/catalog/ai-tools/prices-offers-pack.js.map +1 -1
  49. package/dist/modules/catalog/ai-tools/products-pack.js.map +1 -1
  50. package/dist/modules/catalog/ai-tools/variants-pack.js.map +1 -1
  51. package/dist/modules/communication_channels/data/entities.js.map +1 -1
  52. package/dist/modules/communication_channels/encryption.js.map +1 -1
  53. package/dist/modules/communication_channels/lib/thread-matcher.js.map +1 -1
  54. package/dist/modules/communication_channels/lib/thread-token.js.map +1 -1
  55. package/dist/modules/currencies/api/currencies/route.js +4 -3
  56. package/dist/modules/currencies/api/currencies/route.js.map +2 -2
  57. package/dist/modules/customer_accounts/api/admin/roles.js +2 -1
  58. package/dist/modules/customer_accounts/api/admin/roles.js.map +2 -2
  59. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.js +0 -3
  60. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.js.map +2 -2
  61. package/dist/modules/customer_accounts/events.js +1 -1
  62. package/dist/modules/customer_accounts/events.js.map +1 -1
  63. package/dist/modules/customer_accounts/lib/resolveTenantContext.js.map +1 -1
  64. package/dist/modules/customers/acl.js +1 -1
  65. package/dist/modules/customers/acl.js.map +1 -1
  66. package/dist/modules/customers/ai-tools/companies-pack.js.map +1 -1
  67. package/dist/modules/customers/ai-tools/deals-pack.js.map +1 -1
  68. package/dist/modules/customers/ai-tools/people-pack.js.map +1 -1
  69. package/dist/modules/customers/api/companies/route.js +4 -4
  70. package/dist/modules/customers/api/companies/route.js.map +2 -2
  71. package/dist/modules/customers/api/deals/route.js +43 -2
  72. package/dist/modules/customers/api/deals/route.js.map +2 -2
  73. package/dist/modules/customers/api/deals/summary/route.js +402 -0
  74. package/dist/modules/customers/api/deals/summary/route.js.map +7 -0
  75. package/dist/modules/customers/api/people/route.js +4 -4
  76. package/dist/modules/customers/api/people/route.js.map +2 -2
  77. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js +16 -5
  78. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js.map +2 -2
  79. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealData.js +22 -5
  80. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealData.js.map +2 -2
  81. package/dist/modules/customers/backend/customers/deals/[id]/page.js +12 -2
  82. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  83. package/dist/modules/customers/backend/customers/deals/page.js +221 -56
  84. package/dist/modules/customers/backend/customers/deals/page.js.map +3 -3
  85. package/dist/modules/customers/backend/customers/deals/pipeline/page.js +1 -1
  86. package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
  87. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +18 -0
  88. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  89. package/dist/modules/customers/cli.js +15 -9
  90. package/dist/modules/customers/cli.js.map +2 -2
  91. package/dist/modules/customers/commands/addresses.js +5 -5
  92. package/dist/modules/customers/commands/addresses.js.map +2 -2
  93. package/dist/modules/customers/commands/comments.js +5 -5
  94. package/dist/modules/customers/commands/comments.js.map +2 -2
  95. package/dist/modules/customers/commands/deals.js +2 -2
  96. package/dist/modules/customers/commands/deals.js.map +2 -2
  97. package/dist/modules/customers/commands/entity-roles.js +2 -1
  98. package/dist/modules/customers/commands/entity-roles.js.map +2 -2
  99. package/dist/modules/customers/commands/interactions.js +8 -5
  100. package/dist/modules/customers/commands/interactions.js.map +2 -2
  101. package/dist/modules/customers/commands/shared.js +21 -6
  102. package/dist/modules/customers/commands/shared.js.map +2 -2
  103. package/dist/modules/customers/commands/tags.js +3 -3
  104. package/dist/modules/customers/commands/tags.js.map +2 -2
  105. package/dist/modules/customers/components/DealsKpiStrip.js +282 -0
  106. package/dist/modules/customers/components/DealsKpiStrip.js.map +7 -0
  107. package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js +0 -1
  108. package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js.map +2 -2
  109. package/dist/modules/customers/components/detail/DealForm.js +100 -17
  110. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  111. package/dist/modules/customers/components/detail/PersonDetailTabs.js +11 -3
  112. package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
  113. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +1 -2
  114. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
  115. package/dist/modules/customers/components/detail/assignableStaff.js +21 -8
  116. package/dist/modules/customers/components/detail/assignableStaff.js.map +2 -2
  117. package/dist/modules/customers/components/kpi/PipelineStageBar.js +63 -0
  118. package/dist/modules/customers/components/kpi/PipelineStageBar.js.map +7 -0
  119. package/dist/modules/customers/lib/dealsMetrics.js +82 -0
  120. package/dist/modules/customers/lib/dealsMetrics.js.map +7 -0
  121. package/dist/modules/customers/migrations/Migration20260519120000_pipeline_stage_color_tones.js.map +1 -1
  122. package/dist/modules/data_sync/api/run.js +1 -1
  123. package/dist/modules/data_sync/api/run.js.map +2 -2
  124. package/dist/modules/directory/api/organization-branding/route.js +214 -0
  125. package/dist/modules/directory/api/organization-branding/route.js.map +7 -0
  126. package/dist/modules/directory/api/organizations/route.js +7 -0
  127. package/dist/modules/directory/api/organizations/route.js.map +3 -3
  128. package/dist/modules/directory/backend/directory/branding/page.js +214 -0
  129. package/dist/modules/directory/backend/directory/branding/page.js.map +7 -0
  130. package/dist/modules/directory/backend/directory/branding/page.meta.js +26 -0
  131. package/dist/modules/directory/backend/directory/branding/page.meta.js.map +7 -0
  132. package/dist/modules/directory/commands/organizations.js +8 -1
  133. package/dist/modules/directory/commands/organizations.js.map +2 -2
  134. package/dist/modules/directory/data/entities.js +3 -0
  135. package/dist/modules/directory/data/entities.js.map +2 -2
  136. package/dist/modules/directory/data/validators.js +9 -0
  137. package/dist/modules/directory/data/validators.js.map +2 -2
  138. package/dist/modules/directory/migrations/Migration20260607222259_directory.js +13 -0
  139. package/dist/modules/directory/migrations/Migration20260607222259_directory.js.map +7 -0
  140. package/dist/modules/directory/subscribers/invalidateOrgScopeCache.js +2 -1
  141. package/dist/modules/directory/subscribers/invalidateOrgScopeCache.js.map +2 -2
  142. package/dist/modules/directory/utils/organizationScope.js +59 -27
  143. package/dist/modules/directory/utils/organizationScope.js.map +2 -2
  144. package/dist/modules/entities/api/definitions.batch.js +2 -1
  145. package/dist/modules/entities/api/definitions.batch.js.map +2 -2
  146. package/dist/modules/entities/api/entities.js +7 -0
  147. package/dist/modules/entities/api/entities.js.map +2 -2
  148. package/dist/modules/entities/api/records.js +26 -15
  149. package/dist/modules/entities/api/records.js.map +2 -2
  150. package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js +14 -0
  151. package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js.map +2 -2
  152. package/dist/modules/entities/backend/entities/user/[entityId]/records/create/page.js +14 -0
  153. package/dist/modules/entities/backend/entities/user/[entityId]/records/create/page.js.map +2 -2
  154. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +12 -0
  155. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  156. package/dist/modules/entities/components/useRecordsEntityGuard.js +30 -0
  157. package/dist/modules/entities/components/useRecordsEntityGuard.js.map +7 -0
  158. package/dist/modules/payment_gateways/api/transactions/route.js +2 -4
  159. package/dist/modules/payment_gateways/api/transactions/route.js.map +2 -2
  160. package/dist/modules/progress/api/jobs/[id]/route.js +7 -2
  161. package/dist/modules/progress/api/jobs/[id]/route.js.map +2 -2
  162. package/dist/modules/progress/api/jobs/route.js +1 -1
  163. package/dist/modules/progress/api/jobs/route.js.map +2 -2
  164. package/dist/modules/progress/lib/progressServiceImpl.js +8 -2
  165. package/dist/modules/progress/lib/progressServiceImpl.js.map +2 -2
  166. package/dist/modules/query_index/data/entities.js +2 -1
  167. package/dist/modules/query_index/data/entities.js.map +2 -2
  168. package/dist/modules/query_index/lib/engine.js +4 -2
  169. package/dist/modules/query_index/lib/engine.js.map +2 -2
  170. package/dist/modules/query_index/migrations/Migration20260611103000_query_index.js +16 -0
  171. package/dist/modules/query_index/migrations/Migration20260611103000_query_index.js.map +7 -0
  172. package/dist/modules/resources/api/resources.js +2 -3
  173. package/dist/modules/resources/api/resources.js.map +2 -2
  174. package/dist/modules/sales/api/documents/factory.js +2 -2
  175. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  176. package/dist/modules/sales/commands/documents.js +7 -5
  177. package/dist/modules/sales/commands/documents.js.map +2 -2
  178. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +2 -1
  179. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  180. package/dist/modules/sales/components/documents/salesDocumentsColumns.js +10 -0
  181. package/dist/modules/sales/components/documents/salesDocumentsColumns.js.map +7 -0
  182. package/dist/modules/staff/api/team-members.js +9 -2
  183. package/dist/modules/staff/api/team-members.js.map +2 -2
  184. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +24 -1
  185. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +2 -2
  186. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +11 -6
  187. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  188. package/dist/modules/staff/commands/team-members.js +1 -1
  189. package/dist/modules/staff/commands/team-members.js.map +2 -2
  190. package/dist/modules/staff/components/TeamMemberForm.js +1 -1
  191. package/dist/modules/staff/components/TeamMemberForm.js.map +2 -2
  192. package/dist/modules/staff/lib/scheduleSwitch.js +23 -0
  193. package/dist/modules/staff/lib/scheduleSwitch.js.map +7 -0
  194. package/dist/modules/sync_excel/api/import/route.js +1 -1
  195. package/dist/modules/sync_excel/api/import/route.js.map +2 -2
  196. package/dist/modules/workflows/api/definitions/route.js +3 -2
  197. package/dist/modules/workflows/api/definitions/route.js.map +2 -2
  198. package/dist/modules/workflows/backend/definitions/create/page.js +1 -2
  199. package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
  200. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +1 -2
  201. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  202. package/dist/modules/workflows/components/DefinitionTriggersEditor.js +1 -2
  203. package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +2 -2
  204. package/dist/modules/workflows/components/NodeEditDialog.js +4 -13
  205. package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
  206. package/dist/modules/workflows/components/NodeEditDialogCrudForm.js +4 -13
  207. package/dist/modules/workflows/components/NodeEditDialogCrudForm.js.map +2 -2
  208. package/dist/modules/workflows/components/WorkflowGraphImpl.js +1 -4
  209. package/dist/modules/workflows/components/WorkflowGraphImpl.js.map +2 -2
  210. package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js +2 -5
  211. package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js.map +2 -2
  212. package/generated/entities/organization/index.ts +1 -0
  213. package/generated/entity-fields-registry.ts +1 -0
  214. package/package.json +11 -12
  215. package/src/bootstrap.ts +65 -7
  216. package/src/helpers/integration/crmFixtures.ts +21 -1
  217. package/src/modules/attachments/AGENTS.md +79 -0
  218. package/src/modules/attachments/api/library/route.ts +2 -2
  219. package/src/modules/attachments/api/route.ts +2 -0
  220. package/src/modules/attachments/components/AttachmentContentPreview.tsx +6 -6
  221. package/src/modules/attachments/lib/access.ts +36 -0
  222. package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +14 -2
  223. package/src/modules/audit_logs/data/entities.ts +1 -0
  224. package/src/modules/audit_logs/migrations/.snapshot-open-mercato.json +10 -0
  225. package/src/modules/audit_logs/migrations/Migration20260611104500.ts +13 -0
  226. package/src/modules/audit_logs/services/accessLogService.ts +15 -0
  227. package/src/modules/auth/api/admin/nav.ts +9 -0
  228. package/src/modules/auth/api/login.ts +13 -13
  229. package/src/modules/auth/commands/users.ts +32 -15
  230. package/src/modules/auth/data/entities.ts +13 -1
  231. package/src/modules/auth/i18n/de.json +0 -1
  232. package/src/modules/auth/i18n/en.json +0 -1
  233. package/src/modules/auth/i18n/es.json +0 -1
  234. package/src/modules/auth/i18n/pl.json +0 -1
  235. package/src/modules/auth/lib/backendChrome.tsx +37 -1
  236. package/src/modules/auth/lib/consentIntegrity.ts +6 -3
  237. package/src/modules/auth/migrations/.snapshot-open-mercato.json +20 -10
  238. package/src/modules/auth/migrations/Migration20260610120000.ts +53 -0
  239. package/src/modules/auth/migrations/Migration20260611103000.ts +21 -0
  240. package/src/modules/auth/services/authService.ts +24 -4
  241. package/src/modules/auth/services/rbacService.ts +11 -2
  242. package/src/modules/catalog/ai-tools/configuration-pack.ts +1 -1
  243. package/src/modules/catalog/ai-tools/prices-offers-pack.ts +1 -1
  244. package/src/modules/catalog/ai-tools/products-pack.ts +1 -1
  245. package/src/modules/catalog/ai-tools/variants-pack.ts +1 -1
  246. package/src/modules/communication_channels/data/entities.ts +2 -2
  247. package/src/modules/communication_channels/encryption.ts +1 -1
  248. package/src/modules/communication_channels/lib/adapter.ts +1 -1
  249. package/src/modules/communication_channels/lib/thread-matcher.ts +1 -1
  250. package/src/modules/communication_channels/lib/thread-token.ts +1 -1
  251. package/src/modules/currencies/api/currencies/route.ts +4 -3
  252. package/src/modules/customer_accounts/api/admin/roles.ts +2 -1
  253. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.tsx +0 -3
  254. package/src/modules/customer_accounts/events.ts +1 -1
  255. package/src/modules/customer_accounts/lib/resolveTenantContext.ts +2 -2
  256. package/src/modules/customers/acl.ts +1 -1
  257. package/src/modules/customers/ai-tools/companies-pack.ts +1 -1
  258. package/src/modules/customers/ai-tools/deals-pack.ts +1 -1
  259. package/src/modules/customers/ai-tools/people-pack.ts +1 -1
  260. package/src/modules/customers/api/companies/route.ts +4 -4
  261. package/src/modules/customers/api/deals/route.ts +51 -2
  262. package/src/modules/customers/api/deals/summary/route.ts +496 -0
  263. package/src/modules/customers/api/people/route.ts +4 -4
  264. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.ts +28 -6
  265. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealData.ts +33 -6
  266. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +17 -2
  267. package/src/modules/customers/backend/customers/deals/page.tsx +254 -66
  268. package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +1 -2
  269. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +18 -0
  270. package/src/modules/customers/cli.ts +15 -15
  271. package/src/modules/customers/commands/addresses.ts +5 -5
  272. package/src/modules/customers/commands/comments.ts +5 -5
  273. package/src/modules/customers/commands/deals.ts +2 -2
  274. package/src/modules/customers/commands/entity-roles.ts +2 -1
  275. package/src/modules/customers/commands/interactions.ts +8 -5
  276. package/src/modules/customers/commands/shared.ts +26 -4
  277. package/src/modules/customers/commands/tags.ts +3 -3
  278. package/src/modules/customers/components/DealsKpiStrip.tsx +389 -0
  279. package/src/modules/customers/components/detail/ConfirmDealLostDialog.tsx +0 -1
  280. package/src/modules/customers/components/detail/DealForm.tsx +121 -19
  281. package/src/modules/customers/components/detail/PersonDetailTabs.tsx +12 -2
  282. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +1 -2
  283. package/src/modules/customers/components/detail/assignableStaff.ts +32 -8
  284. package/src/modules/customers/components/kpi/PipelineStageBar.tsx +77 -0
  285. package/src/modules/customers/i18n/de.json +43 -0
  286. package/src/modules/customers/i18n/en.json +43 -0
  287. package/src/modules/customers/i18n/es.json +43 -0
  288. package/src/modules/customers/i18n/pl.json +43 -0
  289. package/src/modules/customers/lib/dealsMetrics.ts +159 -0
  290. package/src/modules/customers/migrations/Migration20260519120000_pipeline_stage_color_tones.ts +1 -1
  291. package/src/modules/data_sync/api/run.ts +1 -1
  292. package/src/modules/directory/api/organization-branding/route.ts +238 -0
  293. package/src/modules/directory/api/organizations/route.ts +7 -0
  294. package/src/modules/directory/backend/directory/branding/page.meta.ts +24 -0
  295. package/src/modules/directory/backend/directory/branding/page.tsx +248 -0
  296. package/src/modules/directory/commands/organizations.ts +9 -1
  297. package/src/modules/directory/data/entities.ts +3 -0
  298. package/src/modules/directory/data/validators.ts +12 -0
  299. package/src/modules/directory/i18n/de.json +21 -0
  300. package/src/modules/directory/i18n/en.json +21 -0
  301. package/src/modules/directory/i18n/es.json +21 -0
  302. package/src/modules/directory/i18n/pl.json +21 -0
  303. package/src/modules/directory/migrations/.snapshot-open-mercato.json +40 -0
  304. package/src/modules/directory/migrations/Migration20260607222259_directory.ts +13 -0
  305. package/src/modules/directory/subscribers/invalidateOrgScopeCache.ts +3 -1
  306. package/src/modules/directory/utils/organizationScope.ts +85 -30
  307. package/src/modules/entities/api/definitions.batch.ts +11 -7
  308. package/src/modules/entities/api/entities.ts +11 -0
  309. package/src/modules/entities/api/records.ts +46 -25
  310. package/src/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.tsx +15 -0
  311. package/src/modules/entities/backend/entities/user/[entityId]/records/create/page.tsx +15 -0
  312. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +23 -0
  313. package/src/modules/entities/components/useRecordsEntityGuard.ts +41 -0
  314. package/src/modules/entities/i18n/de.json +1 -0
  315. package/src/modules/entities/i18n/en.json +1 -0
  316. package/src/modules/entities/i18n/es.json +1 -0
  317. package/src/modules/entities/i18n/pl.json +1 -0
  318. package/src/modules/payment_gateways/api/transactions/route.ts +2 -5
  319. package/src/modules/progress/api/jobs/[id]/route.ts +6 -1
  320. package/src/modules/progress/api/jobs/route.ts +1 -1
  321. package/src/modules/progress/lib/progressServiceImpl.ts +7 -1
  322. package/src/modules/query_index/data/entities.ts +1 -0
  323. package/src/modules/query_index/lib/engine.ts +11 -5
  324. package/src/modules/query_index/migrations/.snapshot-open-mercato.json +11 -0
  325. package/src/modules/query_index/migrations/Migration20260611103000_query_index.ts +29 -0
  326. package/src/modules/resources/api/resources.ts +2 -3
  327. package/src/modules/sales/api/documents/factory.ts +2 -2
  328. package/src/modules/sales/commands/documents.ts +7 -5
  329. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +2 -1
  330. package/src/modules/sales/components/documents/salesDocumentsColumns.ts +6 -0
  331. package/src/modules/staff/AGENTS.md +1 -1
  332. package/src/modules/staff/api/team-members.ts +9 -2
  333. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +31 -1
  334. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +18 -8
  335. package/src/modules/staff/commands/team-members.ts +5 -2
  336. package/src/modules/staff/components/TeamMemberForm.tsx +4 -1
  337. package/src/modules/staff/i18n/de.json +1 -0
  338. package/src/modules/staff/i18n/en.json +1 -0
  339. package/src/modules/staff/i18n/es.json +1 -0
  340. package/src/modules/staff/i18n/pl.json +1 -0
  341. package/src/modules/staff/lib/scheduleSwitch.ts +46 -0
  342. package/src/modules/sync_excel/api/import/route.ts +1 -1
  343. package/src/modules/workflows/api/definitions/route.ts +3 -2
  344. package/src/modules/workflows/backend/definitions/create/page.tsx +1 -2
  345. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +1 -2
  346. package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +1 -2
  347. package/src/modules/workflows/components/NodeEditDialog.tsx +1 -4
  348. package/src/modules/workflows/components/NodeEditDialogCrudForm.tsx +4 -7
  349. package/src/modules/workflows/components/WorkflowGraphImpl.tsx +1 -2
  350. package/src/modules/workflows/components/fields/FormFieldArrayEditor.tsx +2 -3
@@ -53,7 +53,7 @@ type DictionaryDefault = {
53
53
  type CustomFieldValuesPayload = Parameters<DataEngine['setCustomFields']>[0]['values']
54
54
  type ProgressBarHandle = ReturnType<typeof createProgressBar>
55
55
 
56
- const DEAL_STATUS_DEFAULTS: DictionaryDefault[] = [
56
+ export const DEAL_STATUS_DEFAULTS: DictionaryDefault[] = [
57
57
  { value: 'open', label: 'Open', color: '#2563eb', icon: 'lucide:circle' },
58
58
  { value: 'closed', label: 'Closed', color: '#6b7280', icon: 'lucide:check-circle' },
59
59
  { value: 'win', label: 'Win', color: '#22c55e', icon: 'lucide:trophy' },
@@ -61,7 +61,7 @@ const DEAL_STATUS_DEFAULTS: DictionaryDefault[] = [
61
61
  { value: 'in_progress', label: 'In progress', color: '#f59e0b', icon: 'lucide:activity' },
62
62
  ]
63
63
 
64
- const PIPELINE_STAGE_DEFAULTS: DictionaryDefault[] = [
64
+ export const PIPELINE_STAGE_DEFAULTS: DictionaryDefault[] = [
65
65
  { value: 'opportunity', label: 'Opportunity', color: '#38bdf8', icon: 'lucide:target' },
66
66
  { value: 'marketing_qualified_lead', label: 'Marketing Qualified Lead', color: '#a855f7', icon: 'lucide:sparkles' },
67
67
  { value: 'sales_qualified_lead', label: 'Sales Qualified Lead', color: '#f97316', icon: 'lucide:users' },
@@ -72,14 +72,14 @@ const PIPELINE_STAGE_DEFAULTS: DictionaryDefault[] = [
72
72
  { value: 'stalled', label: 'Stalled', color: '#6b7280', icon: 'lucide:alert-circle' },
73
73
  ]
74
74
 
75
- const ENTITY_STATUS_DEFAULTS: DictionaryDefault[] = [
75
+ export const ENTITY_STATUS_DEFAULTS: DictionaryDefault[] = [
76
76
  { value: 'active', label: 'Active', color: '#22c55e', icon: 'lucide:user-check' },
77
77
  { value: 'inactive', label: 'Inactive', color: '#94a3b8', icon: 'lucide:pause-circle' },
78
78
  { value: 'pending', label: 'Pending', color: '#f59e0b', icon: 'lucide:clock' },
79
79
  { value: 'archived', label: 'Archived', color: '#64748b', icon: 'lucide:archive' },
80
80
  ]
81
81
 
82
- const ENTITY_LIFECYCLE_STAGE_DEFAULTS: DictionaryDefault[] = [
82
+ export const ENTITY_LIFECYCLE_STAGE_DEFAULTS: DictionaryDefault[] = [
83
83
  { value: 'lead', label: 'Lead', color: '#3b82f6', icon: 'lucide:sparkles' },
84
84
  { value: 'prospect', label: 'Prospect', color: '#8b5cf6', icon: 'lucide:eye' },
85
85
  { value: 'customer', label: 'Customer', color: '#22c55e', icon: 'lucide:handshake' },
@@ -88,7 +88,7 @@ const ENTITY_LIFECYCLE_STAGE_DEFAULTS: DictionaryDefault[] = [
88
88
  { value: 'other', label: 'Other', color: '#94a3b8', icon: 'lucide:circle' },
89
89
  ]
90
90
 
91
- const ENTITY_SOURCE_DEFAULTS: DictionaryDefault[] = [
91
+ export const ENTITY_SOURCE_DEFAULTS: DictionaryDefault[] = [
92
92
  { value: 'linkedin', label: 'LinkedIn', color: '#0a66c2', icon: 'lucide:linkedin' },
93
93
  { value: 'email', label: 'Email', color: '#3b82f6', icon: 'lucide:mail' },
94
94
  { value: 'web_form', label: 'Web form', color: '#22c55e', icon: 'lucide:globe' },
@@ -291,7 +291,7 @@ function isoDaysFromNow(days: number, options?: { hour?: number; minute?: number
291
291
  return base.toISOString()
292
292
  }
293
293
 
294
- const CUSTOMER_EXAMPLES: ExampleCompany[] = [
294
+ export const CUSTOMER_EXAMPLES: ExampleCompany[] = [
295
295
  {
296
296
  slug: 'brightside-solar',
297
297
  displayName: 'Brightside Solar',
@@ -307,7 +307,7 @@ const CUSTOMER_EXAMPLES: ExampleCompany[] = [
307
307
  primaryPhone: '+1 415-555-0148',
308
308
  source: 'partner_referral',
309
309
  lifecycleStage: 'customer',
310
- status: 'customer',
310
+ status: 'active',
311
311
  custom: {
312
312
  relationship_health: 'healthy',
313
313
  renewal_quarter: 'Q3',
@@ -364,7 +364,7 @@ const CUSTOMER_EXAMPLES: ExampleCompany[] = [
364
364
  phone: '+1 628-555-0199',
365
365
  timezone: 'America/Los_Angeles',
366
366
  linkedInUrl: 'https://www.linkedin.com/in/danielcho-energy/',
367
- source: 'outbound_campaign',
367
+ source: 'cold_outreach',
368
368
  custom: {
369
369
  buying_role: 'economic_buyer',
370
370
  preferred_pronouns: 'he/him',
@@ -438,7 +438,7 @@ const CUSTOMER_EXAMPLES: ExampleCompany[] = [
438
438
  valueCurrency: 'USD',
439
439
  expectedCloseAt: isoDaysFromNow(65),
440
440
  probability: 40,
441
- source: 'inbound_web',
441
+ source: 'web_form',
442
442
  custom: {
443
443
  competitive_risk: 'high',
444
444
  implementation_complexity: 'complex',
@@ -513,7 +513,7 @@ const CUSTOMER_EXAMPLES: ExampleCompany[] = [
513
513
  'Boston-based analytics platform helping consumer brands optimize merchandising decisions.',
514
514
  primaryEmail: 'info@harborviewanalytics.com',
515
515
  primaryPhone: '+1 617-555-0024',
516
- source: 'industry_event',
516
+ source: 'event',
517
517
  lifecycleStage: 'prospect',
518
518
  status: 'active',
519
519
  custom: {
@@ -545,7 +545,7 @@ const CUSTOMER_EXAMPLES: ExampleCompany[] = [
545
545
  phone: '+1 617-555-0168',
546
546
  timezone: 'America/New_York',
547
547
  linkedInUrl: 'https://www.linkedin.com/in/arjunpatel-sales/',
548
- source: 'industry_event',
548
+ source: 'event',
549
549
  custom: {
550
550
  buying_role: 'economic_buyer',
551
551
  preferred_pronouns: 'he/him',
@@ -563,7 +563,7 @@ const CUSTOMER_EXAMPLES: ExampleCompany[] = [
563
563
  phone: '+1 617-555-0179',
564
564
  timezone: 'America/New_York',
565
565
  linkedInUrl: 'https://www.linkedin.com/in/lenaortiz-retail/',
566
- source: 'industry_event',
566
+ source: 'event',
567
567
  custom: {
568
568
  buying_role: 'champion',
569
569
  preferred_pronouns: 'she/her',
@@ -582,7 +582,7 @@ const CUSTOMER_EXAMPLES: ExampleCompany[] = [
582
582
  valueCurrency: 'USD',
583
583
  expectedCloseAt: isoDaysFromNow(-25),
584
584
  probability: 100,
585
- source: 'industry_event',
585
+ source: 'event',
586
586
  custom: {
587
587
  competitive_risk: 'low',
588
588
  implementation_complexity: 'standard',
@@ -637,7 +637,7 @@ const CUSTOMER_EXAMPLES: ExampleCompany[] = [
637
637
  valueCurrency: 'USD',
638
638
  expectedCloseAt: isoDaysFromNow(120),
639
639
  probability: 35,
640
- source: 'outbound_campaign',
640
+ source: 'cold_outreach',
641
641
  custom: {
642
642
  competitive_risk: 'medium',
643
643
  implementation_complexity: 'complex',
@@ -715,7 +715,7 @@ const CUSTOMER_EXAMPLES: ExampleCompany[] = [
715
715
  primaryPhone: '+1 512-555-0456',
716
716
  source: 'customer_referral',
717
717
  lifecycleStage: 'customer',
718
- status: 'customer',
718
+ status: 'active',
719
719
  custom: {
720
720
  relationship_health: 'healthy',
721
721
  renewal_quarter: 'Q1',
@@ -109,7 +109,7 @@ const createAddressCommand: CommandHandler<AddressCreateInput, { addressId: stri
109
109
  ensureOrganizationScope(ctx, parsed.organizationId)
110
110
 
111
111
  const em = (ctx.container.resolve('em') as EntityManager).fork()
112
- const entity = await requireCustomerEntity(em, parsed.entityId, undefined, 'Customer not found')
112
+ const entity = await requireCustomerEntity(em, parsed.entityId, { tenantId: parsed.tenantId, organizationId: parsed.organizationId }, undefined, 'Customer not found')
113
113
  ensureSameScope(entity, parsed.organizationId, parsed.tenantId)
114
114
 
115
115
  const address = em.create(CustomerAddress, {
@@ -198,7 +198,7 @@ const createAddressCommand: CommandHandler<AddressCreateInput, { addressId: stri
198
198
  throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for address create' })
199
199
  }
200
200
  const em = (ctx.container.resolve('em') as EntityManager).fork()
201
- const entity = await requireCustomerEntity(em, after.entityId, undefined, 'Customer not found')
201
+ const entity = await requireCustomerEntity(em, after.entityId, { tenantId: after.tenantId, organizationId: after.organizationId }, undefined, 'Customer not found')
202
202
  let address = await findOneWithDecryption(
203
203
  em,
204
204
  CustomerAddress,
@@ -293,7 +293,7 @@ const updateAddressCommand: CommandHandler<AddressUpdateInput, { addressId: stri
293
293
  ensureOrganizationScope(ctx, address.organizationId)
294
294
 
295
295
  if (parsed.entityId !== undefined) {
296
- const entity = await requireCustomerEntity(em, parsed.entityId, undefined, 'Customer not found')
296
+ const entity = await requireCustomerEntity(em, parsed.entityId, { tenantId: address.tenantId, organizationId: address.organizationId }, undefined, 'Customer not found')
297
297
  ensureSameScope(entity, address.organizationId, address.tenantId)
298
298
  address.entity = entity
299
299
  }
@@ -396,7 +396,7 @@ const updateAddressCommand: CommandHandler<AddressUpdateInput, { addressId: stri
396
396
  if (!before) return
397
397
  const em = (ctx.container.resolve('em') as EntityManager).fork()
398
398
  let address = await em.findOne(CustomerAddress, { id: before.id })
399
- const entity = await requireCustomerEntity(em, before.entityId, undefined, 'Customer not found')
399
+ const entity = await requireCustomerEntity(em, before.entityId, { tenantId: before.tenantId, organizationId: before.organizationId }, undefined, 'Customer not found')
400
400
  if (!address) {
401
401
  address = em.create(CustomerAddress, {
402
402
  id: before.id,
@@ -523,7 +523,7 @@ const deleteAddressCommand: CommandHandler<{ body?: Record<string, unknown>; que
523
523
  const before = payload?.before
524
524
  if (!before) return
525
525
  const em = (ctx.container.resolve('em') as EntityManager).fork()
526
- const entity = await requireCustomerEntity(em, before.entityId, undefined, 'Customer not found')
526
+ const entity = await requireCustomerEntity(em, before.entityId, { tenantId: before.tenantId, organizationId: before.organizationId }, undefined, 'Customer not found')
527
527
  let address = await em.findOne(CustomerAddress, { id: before.id })
528
528
  if (!address) {
529
529
  address = em.create(CustomerAddress, {
@@ -84,7 +84,7 @@ const createCommentCommand: CommandHandler<CommentCreateInput, { commentId: stri
84
84
  const normalizedAuthor = normalizeAuthorUserId(parsed.authorUserId, ctx.auth)
85
85
 
86
86
  const em = (ctx.container.resolve('em') as EntityManager).fork()
87
- const entity = await requireTimelineParentEntity(em, parsed.entityId)
87
+ const entity = await requireTimelineParentEntity(em, parsed.entityId, { tenantId: parsed.tenantId, organizationId: parsed.organizationId })
88
88
  ensureSameScope(entity, parsed.organizationId, parsed.tenantId)
89
89
  const deal = await requireDealInScope(em, parsed.dealId, parsed.tenantId, parsed.organizationId)
90
90
 
@@ -176,7 +176,7 @@ const createCommentCommand: CommandHandler<CommentCreateInput, { commentId: stri
176
176
  appearanceColor: snapshot.appearanceColor,
177
177
  }),
178
178
  beforeRestore: async ({ em, snapshot }) => {
179
- const entity = await requireTimelineParentEntity(em, snapshot.entityId)
179
+ const entity = await requireTimelineParentEntity(em, snapshot.entityId, { tenantId: snapshot.tenantId, organizationId: snapshot.organizationId })
180
180
  const deal = await requireDealInScope(em, snapshot.dealId, snapshot.tenantId, snapshot.organizationId)
181
181
  return { entity, deal }
182
182
  },
@@ -201,7 +201,7 @@ const updateCommentCommand: CommandHandler<CommentUpdateInput, { commentId: stri
201
201
  ensureOrganizationScope(ctx, comment.organizationId)
202
202
 
203
203
  if (parsed.entityId !== undefined) {
204
- const entity = await requireTimelineParentEntity(em, parsed.entityId)
204
+ const entity = await requireTimelineParentEntity(em, parsed.entityId, { tenantId: comment.tenantId, organizationId: comment.organizationId })
205
205
  ensureSameScope(entity, comment.organizationId, comment.tenantId)
206
206
  comment.entity = entity
207
207
  }
@@ -275,7 +275,7 @@ const updateCommentCommand: CommandHandler<CommentUpdateInput, { commentId: stri
275
275
  if (!before) return
276
276
  const em = (ctx.container.resolve('em') as EntityManager).fork()
277
277
  let comment = await em.findOne(CustomerComment, { id: before.id })
278
- const entity = await requireTimelineParentEntity(em, before.entityId)
278
+ const entity = await requireTimelineParentEntity(em, before.entityId, { tenantId: before.tenantId, organizationId: before.organizationId })
279
279
  const deal = await requireDealInScope(em, before.dealId, before.tenantId, before.organizationId)
280
280
 
281
281
  if (!comment) {
@@ -380,7 +380,7 @@ const deleteCommentCommand: CommandHandler<{ body?: Record<string, unknown>; que
380
380
  const before = payload?.before
381
381
  if (!before) return
382
382
  const em = (ctx.container.resolve('em') as EntityManager).fork()
383
- const entity = await requireTimelineParentEntity(em, before.entityId)
383
+ const entity = await requireTimelineParentEntity(em, before.entityId, { tenantId: before.tenantId, organizationId: before.organizationId })
384
384
  const deal = await requireDealInScope(em, before.dealId, before.tenantId, before.organizationId)
385
385
  let comment = await em.findOne(CustomerComment, { id: before.id })
386
386
  if (!comment) {
@@ -376,7 +376,7 @@ async function syncDealPeople(
376
376
  if (!personIds || !personIds.length) return
377
377
  const unique = Array.from(new Set(personIds))
378
378
  for (const personId of unique) {
379
- const person = await requireCustomerEntity(em, personId, 'person', 'Person not found')
379
+ const person = await requireCustomerEntity(em, personId, { tenantId: deal.tenantId, organizationId: deal.organizationId }, 'person', 'Person not found')
380
380
  ensureSameScope(person, deal.organizationId, deal.tenantId)
381
381
  const link = em.create(CustomerDealPersonLink, {
382
382
  deal,
@@ -396,7 +396,7 @@ async function syncDealCompanies(
396
396
  if (!companyIds || !companyIds.length) return
397
397
  const unique = Array.from(new Set(companyIds))
398
398
  for (const companyId of unique) {
399
- const company = await requireCustomerEntity(em, companyId, 'company', 'Company not found')
399
+ const company = await requireCustomerEntity(em, companyId, { tenantId: deal.tenantId, organizationId: deal.organizationId }, 'company', 'Company not found')
400
400
  ensureSameScope(company, deal.organizationId, deal.tenantId)
401
401
  const link = em.create(CustomerDealCompanyLink, {
402
402
  deal,
@@ -137,7 +137,7 @@ const createEntityRoleCommand: CommandHandler<EntityRoleCreateInput, { roleId: s
137
137
  ensureOrganizationScope(ctx, parsed.organizationId)
138
138
 
139
139
  const em = (ctx.container.resolve('em') as EntityManager).fork()
140
- const entity = await requireCustomerEntity(em, parsed.entityId, parsed.entityType, 'Customer not found')
140
+ const entity = await requireCustomerEntity(em, parsed.entityId, { tenantId: parsed.tenantId, organizationId: parsed.organizationId }, parsed.entityType, 'Customer not found')
141
141
  ensureSameScope(entity, parsed.organizationId, parsed.tenantId)
142
142
 
143
143
  const activeExisting = await findOneWithDecryption(
@@ -495,6 +495,7 @@ const deleteEntityRoleCommand: CommandHandler<EntityRoleDeleteInput, { roleId: s
495
495
  const entity = await requireCustomerEntity(
496
496
  em,
497
497
  before.role.entityId,
498
+ { tenantId: before.role.tenantId, organizationId: before.role.organizationId },
498
499
  before.role.entityType,
499
500
  'Customer not found',
500
501
  )
@@ -374,7 +374,7 @@ const createInteractionCommand: CommandHandler<InteractionCreateInput, { interac
374
374
  const em = (ctx.container.resolve('em') as EntityManager).fork()
375
375
  const normalizedAuthor = normalizeAuthorUserId(parsed.authorUserId ?? null, ctx.auth)
376
376
  const { interaction, entityId, nextInteractionId } = await runInTransaction(em, async (trx) => {
377
- const entity = await requireTimelineParentEntity(trx, parsed.entityId)
377
+ const entity = await requireTimelineParentEntity(trx, parsed.entityId, { tenantId: parsed.tenantId, organizationId: parsed.organizationId })
378
378
  ensureTenantScope(ctx, entity.tenantId)
379
379
  ensureOrganizationScope(ctx, entity.organizationId)
380
380
 
@@ -510,7 +510,7 @@ const createInteractionCommand: CommandHandler<InteractionCreateInput, { interac
510
510
  }
511
511
  const em = (ctx.container.resolve('em') as EntityManager).fork()
512
512
  const { interaction, nextInteractionId } = await runInTransaction(em, async (trx) => {
513
- const entity = await requireTimelineParentEntity(trx, after.interaction.entityId)
513
+ const entity = await requireTimelineParentEntity(trx, after.interaction.entityId, { tenantId: after.interaction.tenantId, organizationId: after.interaction.organizationId })
514
514
  let interaction = await findOneWithDecryption(trx, CustomerInteraction, { id: after.interaction.id })
515
515
  if (!interaction) {
516
516
  interaction = buildInteractionGraph(trx, {
@@ -781,7 +781,7 @@ const updateInteractionCommand: CommandHandler<InteractionUpdateInput, { interac
781
781
  const em = (ctx.container.resolve('em') as EntityManager).fork()
782
782
  const { interaction, nextInteractionId } = await runInTransaction(em, async (trx) => {
783
783
  let interaction = await findOneWithDecryption(trx, CustomerInteraction, { id: before.interaction.id })
784
- const entity = await requireTimelineParentEntity(trx, before.interaction.entityId)
784
+ const entity = await requireTimelineParentEntity(trx, before.interaction.entityId, { tenantId: before.interaction.tenantId, organizationId: before.interaction.organizationId })
785
785
 
786
786
  if (!interaction) {
787
787
  interaction = trx.create(CustomerInteraction, {
@@ -1252,7 +1252,7 @@ const deleteInteractionCommand: CommandHandler<{ body?: Record<string, unknown>;
1252
1252
  if (!before) return
1253
1253
  const em = (ctx.container.resolve('em') as EntityManager).fork()
1254
1254
  const { interaction, nextInteractionId } = await runInTransaction(em, async (trx) => {
1255
- const entity = await requireTimelineParentEntity(trx, before.interaction.entityId)
1255
+ const entity = await requireTimelineParentEntity(trx, before.interaction.entityId, { tenantId: before.interaction.tenantId, organizationId: before.interaction.organizationId })
1256
1256
  let interaction = await findOneWithDecryption(trx, CustomerInteraction, { id: before.interaction.id })
1257
1257
  if (!interaction) {
1258
1258
  interaction = trx.create(CustomerInteraction, {
@@ -1372,7 +1372,10 @@ const recomputeNextCommand: CommandHandler<{ entityId: string }, { entityId: str
1372
1372
  const parsed = recomputeNextSchema.parse(rawInput)
1373
1373
  const em = (ctx.container.resolve('em') as EntityManager).fork()
1374
1374
  const projection = await recomputeNextInteraction(em, parsed.entityId)
1375
- const entity = await requireTimelineParentEntity(em, parsed.entityId)
1375
+ const entity = await requireTimelineParentEntity(em, parsed.entityId, {
1376
+ tenantId: ctx.auth?.tenantId ?? '',
1377
+ organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? '',
1378
+ })
1376
1379
  await emitNextInteractionUpdatedEvent(ctx, {
1377
1380
  entityId: parsed.entityId,
1378
1381
  nextInteractionId: projection.nextInteractionId,
@@ -26,13 +26,24 @@ export function normalizeDictionaryIcon(input: unknown): string | null {
26
26
 
27
27
  export { assertFound } from '@open-mercato/shared/lib/crud/errors'
28
28
 
29
+ export type CustomerEntityScope = {
30
+ tenantId: string
31
+ organizationId: string
32
+ }
33
+
29
34
  export async function requireCustomerEntity(
30
35
  em: EntityManager,
31
36
  id: string,
37
+ scope: CustomerEntityScope,
32
38
  kind?: CustomerEntityKind,
33
39
  message = 'Customer entity not found'
34
40
  ): Promise<CustomerEntity> {
35
- const entity = await em.findOne(CustomerEntity, { id, deletedAt: null })
41
+ const entity = await em.findOne(CustomerEntity, {
42
+ id,
43
+ deletedAt: null,
44
+ tenantId: scope.tenantId,
45
+ organizationId: scope.organizationId,
46
+ })
36
47
  if (!entity) throw new CrudHttpError(404, { error: message })
37
48
  if (kind && entity.kind !== kind) {
38
49
  throw new CrudHttpError(400, { error: 'Invalid entity type' })
@@ -43,15 +54,26 @@ export async function requireCustomerEntity(
43
54
  export async function requireTimelineParentEntity(
44
55
  em: EntityManager,
45
56
  id: string,
57
+ scope: CustomerEntityScope,
46
58
  ): Promise<CustomerEntity> {
47
- const entity = await em.findOne(CustomerEntity, { id, deletedAt: null })
59
+ const entity = await em.findOne(CustomerEntity, {
60
+ id,
61
+ deletedAt: null,
62
+ tenantId: scope.tenantId,
63
+ organizationId: scope.organizationId,
64
+ })
48
65
  if (entity) {
49
66
  if (entity.kind !== 'person' && entity.kind !== 'company') {
50
67
  throw new CrudHttpError(422, { error: 'entityId must reference a person or company' })
51
68
  }
52
69
  return entity
53
70
  }
54
- const deal = await em.findOne(CustomerDeal, { id, deletedAt: null })
71
+ const deal = await em.findOne(CustomerDeal, {
72
+ id,
73
+ deletedAt: null,
74
+ tenantId: scope.tenantId,
75
+ organizationId: scope.organizationId,
76
+ })
55
77
  if (deal) {
56
78
  throw new CrudHttpError(422, { error: 'entityId must reference a person or company, not a deal' })
57
79
  }
@@ -111,7 +133,7 @@ export async function requireDealInScope(
111
133
  organizationId: string
112
134
  ): Promise<CustomerDeal | null> {
113
135
  if (!dealId) return null
114
- const deal = await em.findOne(CustomerDeal, { id: dealId, deletedAt: null })
136
+ const deal = await em.findOne(CustomerDeal, { id: dealId, deletedAt: null, tenantId, organizationId })
115
137
  if (!deal) throw new CrudHttpError(400, { error: 'Deal not found' })
116
138
  ensureSameScope(deal, organizationId, tenantId)
117
139
  return deal
@@ -387,7 +387,7 @@ const assignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: strin
387
387
  const em = (ctx.container.resolve('em') as EntityManager).fork()
388
388
  const tag = await em.findOne(CustomerTag, { id: parsed.tagId, tenantId: parsed.tenantId, organizationId: parsed.organizationId })
389
389
  if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })
390
- const entity = await requireCustomerEntity(em, parsed.entityId, undefined, 'Customer not found')
390
+ const entity = await requireCustomerEntity(em, parsed.entityId, { tenantId: parsed.tenantId, organizationId: parsed.organizationId }, undefined, 'Customer not found')
391
391
  ensureSameScope(entity, parsed.organizationId, parsed.tenantId)
392
392
  const tagIds = await loadEntityTagIds(em, entity)
393
393
  if (tagIds.includes(parsed.tagId)) {
@@ -478,7 +478,7 @@ const assignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: strin
478
478
  const em = (ctx.container.resolve('em') as EntityManager).fork()
479
479
  const tag = await em.findOne(CustomerTag, { id: before.tagId })
480
480
  if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })
481
- const entity = await requireCustomerEntity(em, before.entityId, undefined, 'Customer not found')
481
+ const entity = await requireCustomerEntity(em, before.entityId, { tenantId: before.tenantId, organizationId: before.organizationId }, undefined, 'Customer not found')
482
482
  ensureSameScope(entity, before.organizationId, before.tenantId)
483
483
 
484
484
  let assignment = await em.findOne(CustomerTagAssignment, {
@@ -589,7 +589,7 @@ const unassignTagCommand: CommandHandler<TagAssignmentInput, { assignmentId: str
589
589
  if (!before) return
590
590
  const em = (ctx.container.resolve('em') as EntityManager).fork()
591
591
  const tag = await em.findOne(CustomerTag, { id: before.tagId })
592
- const entity = await requireCustomerEntity(em, before.entityId, undefined, 'Customer not found')
592
+ const entity = await requireCustomerEntity(em, before.entityId, { tenantId: before.tenantId, organizationId: before.organizationId }, undefined, 'Customer not found')
593
593
  ensureSameScope(entity, before.organizationId, before.tenantId)
594
594
  if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })
595
595
  const existing = await em.findOne(CustomerTagAssignment, {