@open-mercato/core 0.6.5-develop.4516.1.88e6ab71a9 → 0.6.5-develop.4544.1.71c003c861

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 (726) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/AGENTS.md +5 -0
  3. package/dist/generated/entities/role/index.js +3 -1
  4. package/dist/generated/entities/role/index.js.map +2 -2
  5. package/dist/generated/entities/step_instance/index.js +2 -0
  6. package/dist/generated/entities/step_instance/index.js.map +2 -2
  7. package/dist/generated/entities/user/index.js +3 -1
  8. package/dist/generated/entities/user/index.js.map +2 -2
  9. package/dist/generated/entities/user_task/index.js +2 -0
  10. package/dist/generated/entities/user_task/index.js.map +2 -2
  11. package/dist/generated/entities/workflow_branch_instance/index.js +39 -0
  12. package/dist/generated/entities/workflow_branch_instance/index.js.map +7 -0
  13. package/dist/generated/entities/workflow_event/index.js +2 -0
  14. package/dist/generated/entities/workflow_event/index.js.map +2 -2
  15. package/dist/generated/entities/workflow_instance/index.js +2 -0
  16. package/dist/generated/entities/workflow_instance/index.js.map +2 -2
  17. package/dist/generated/entities.ids.generated.js +1 -0
  18. package/dist/generated/entities.ids.generated.js.map +2 -2
  19. package/dist/generated/entity-fields-registry.js +26 -0
  20. package/dist/generated/entity-fields-registry.js.map +2 -2
  21. package/dist/helpers/integration/optimisticLockUi.js +104 -0
  22. package/dist/helpers/integration/optimisticLockUi.js.map +7 -0
  23. package/dist/helpers/integration/salesFixtures.js +17 -0
  24. package/dist/helpers/integration/salesFixtures.js.map +2 -2
  25. package/dist/modules/api_keys/backend/api-keys/page.js +9 -5
  26. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  27. package/dist/modules/attachments/components/AttachmentPartitionSettings.js +17 -9
  28. package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
  29. package/dist/modules/auth/api/roles/acl/route.js +32 -13
  30. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  31. package/dist/modules/auth/api/roles/route.js +3 -1
  32. package/dist/modules/auth/api/roles/route.js.map +2 -2
  33. package/dist/modules/auth/api/sidebar/preferences/route.js +71 -3
  34. package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
  35. package/dist/modules/auth/api/users/acl/route.js +42 -19
  36. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  37. package/dist/modules/auth/api/users/route.js +3 -1
  38. package/dist/modules/auth/api/users/route.js.map +2 -2
  39. package/dist/modules/auth/backend/roles/[id]/edit/page.js +24 -4
  40. package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
  41. package/dist/modules/auth/backend/roles/page.js +8 -4
  42. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  43. package/dist/modules/auth/backend/users/[id]/edit/page.js +27 -5
  44. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  45. package/dist/modules/auth/backend/users/page.js +6 -2
  46. package/dist/modules/auth/backend/users/page.js.map +2 -2
  47. package/dist/modules/auth/components/AclEditor.js +3 -1
  48. package/dist/modules/auth/components/AclEditor.js.map +2 -2
  49. package/dist/modules/auth/data/entities.js +6 -0
  50. package/dist/modules/auth/data/entities.js.map +2 -2
  51. package/dist/modules/auth/services/sidebarPreferencesService.js +32 -4
  52. package/dist/modules/auth/services/sidebarPreferencesService.js.map +2 -2
  53. package/dist/modules/business_rules/api/rules/route.js +28 -0
  54. package/dist/modules/business_rules/api/rules/route.js.map +2 -2
  55. package/dist/modules/business_rules/api/sets/route.js +28 -0
  56. package/dist/modules/business_rules/api/sets/route.js.map +2 -2
  57. package/dist/modules/business_rules/backend/rules/[id]/page.js +11 -4
  58. package/dist/modules/business_rules/backend/rules/[id]/page.js.map +3 -3
  59. package/dist/modules/business_rules/backend/rules/page.js +20 -11
  60. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  61. package/dist/modules/business_rules/backend/sets/[id]/page.js +11 -4
  62. package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
  63. package/dist/modules/business_rules/backend/sets/page.js +20 -11
  64. package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
  65. package/dist/modules/catalog/api/categories/route.js +2 -0
  66. package/dist/modules/catalog/api/categories/route.js.map +2 -2
  67. package/dist/modules/catalog/api/products/route.js +2 -1
  68. package/dist/modules/catalog/api/products/route.js.map +2 -2
  69. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +2 -0
  70. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
  71. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +94 -40
  72. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  73. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +37 -8
  74. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  75. package/dist/modules/catalog/backend/catalog/products/optionSchemaClient.js.map +2 -2
  76. package/dist/modules/catalog/commands/variants.js +32 -31
  77. package/dist/modules/catalog/commands/variants.js.map +2 -2
  78. package/dist/modules/catalog/components/PriceKindSettings.js +12 -5
  79. package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
  80. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  81. package/dist/modules/catalog/components/products/ProductMediaManager.js.map +2 -2
  82. package/dist/modules/catalog/components/products/ProductsDataTable.js +5 -3
  83. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  84. package/dist/modules/catalog/components/products/productForm.js.map +2 -2
  85. package/dist/modules/catalog/components/products/variantForm.js +2 -1
  86. package/dist/modules/catalog/components/products/variantForm.js.map +2 -2
  87. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +5 -0
  88. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +2 -2
  89. package/dist/modules/currencies/backend/currencies/[id]/page.js +6 -3
  90. package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
  91. package/dist/modules/currencies/backend/currencies/page.js +18 -11
  92. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  93. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +1 -0
  94. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
  95. package/dist/modules/currencies/backend/exchange-rates/page.js +10 -6
  96. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  97. package/dist/modules/currencies/commands/currencies.js +7 -5
  98. package/dist/modules/currencies/commands/currencies.js.map +2 -2
  99. package/dist/modules/currencies/components/CurrencyFetchingConfig.js +26 -19
  100. package/dist/modules/currencies/components/CurrencyFetchingConfig.js.map +2 -2
  101. package/dist/modules/customer_accounts/api/admin/roles/[id].js +28 -5
  102. package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
  103. package/dist/modules/customer_accounts/api/admin/roles.js +4 -2
  104. package/dist/modules/customer_accounts/api/admin/roles.js.map +2 -2
  105. package/dist/modules/customer_accounts/api/admin/users/[id].js +28 -5
  106. package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
  107. package/dist/modules/customer_accounts/api/admin/users.js +2 -0
  108. package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
  109. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +16 -8
  110. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
  111. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +8 -4
  112. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
  113. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js +8 -4
  114. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js.map +2 -2
  115. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +29 -18
  116. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
  117. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +18 -11
  118. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
  119. package/dist/modules/customers/api/companies/route.js +13 -2
  120. package/dist/modules/customers/api/companies/route.js.map +2 -2
  121. package/dist/modules/customers/api/deals/route.js +2 -0
  122. package/dist/modules/customers/api/deals/route.js.map +2 -2
  123. package/dist/modules/customers/api/people/route.js +11 -2
  124. package/dist/modules/customers/api/people/route.js.map +2 -2
  125. package/dist/modules/customers/api/todos/route.js +1 -0
  126. package/dist/modules/customers/api/todos/route.js.map +2 -2
  127. package/dist/modules/customers/backend/config/customers/deals/page.js.map +2 -2
  128. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +34 -21
  129. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +2 -2
  130. package/dist/modules/customers/backend/customers/companies/[id]/page.js +45 -27
  131. package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
  132. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  133. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +22 -5
  134. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  135. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js +30 -8
  136. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js.map +2 -2
  137. package/dist/modules/customers/backend/customers/deals/[id]/page.js +1 -0
  138. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  139. package/dist/modules/customers/backend/customers/deals/page.js +16 -6
  140. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  141. package/dist/modules/customers/backend/customers/deals/pipeline/page.js +62 -39
  142. package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
  143. package/dist/modules/customers/backend/customers/people/[id]/page.js +41 -26
  144. package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
  145. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  146. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +50 -23
  147. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  148. package/dist/modules/customers/commands/addresses.js +16 -14
  149. package/dist/modules/customers/commands/addresses.js.map +2 -2
  150. package/dist/modules/customers/commands/companies.js +1 -1
  151. package/dist/modules/customers/commands/companies.js.map +2 -2
  152. package/dist/modules/customers/commands/interactions.js +41 -4
  153. package/dist/modules/customers/commands/interactions.js.map +2 -2
  154. package/dist/modules/customers/commands/people.js +1 -1
  155. package/dist/modules/customers/commands/people.js.map +2 -2
  156. package/dist/modules/customers/commands/personCompanyLinks.js +8 -5
  157. package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
  158. package/dist/modules/customers/commands/pipeline-stages.js +13 -11
  159. package/dist/modules/customers/commands/pipeline-stages.js.map +3 -3
  160. package/dist/modules/customers/components/AddressFormatSettings.js.map +2 -2
  161. package/dist/modules/customers/components/DictionarySettings.js +20 -13
  162. package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
  163. package/dist/modules/customers/components/DictionarySortSettings.js +4 -0
  164. package/dist/modules/customers/components/DictionarySortSettings.js.map +2 -2
  165. package/dist/modules/customers/components/PipelineSettings.js +38 -23
  166. package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
  167. package/dist/modules/customers/components/detail/ActivityTimeline.js +1 -1
  168. package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
  169. package/dist/modules/customers/components/detail/AddressesSection.js +4 -0
  170. package/dist/modules/customers/components/detail/AddressesSection.js.map +2 -2
  171. package/dist/modules/customers/components/detail/CompanyPeopleSection.js +28 -22
  172. package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
  173. package/dist/modules/customers/components/detail/DealsSection.js +36 -24
  174. package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
  175. package/dist/modules/customers/components/detail/EmailCardActions.js +5 -0
  176. package/dist/modules/customers/components/detail/EmailCardActions.js.map +2 -2
  177. package/dist/modules/customers/components/detail/EntityTagsDialog.js +7 -0
  178. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
  179. package/dist/modules/customers/components/detail/ManageTagsDialog.js +34 -22
  180. package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +2 -2
  181. package/dist/modules/customers/components/detail/PersonCompaniesSection.js +41 -29
  182. package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
  183. package/dist/modules/customers/components/detail/RoleAssignmentRow.js +14 -8
  184. package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +2 -2
  185. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +14 -6
  186. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
  187. package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js +29 -13
  188. package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js.map +2 -2
  189. package/dist/modules/customers/components/detail/hooks/useInteractions.js +77 -35
  190. package/dist/modules/customers/components/detail/hooks/useInteractions.js.map +2 -2
  191. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +25 -17
  192. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
  193. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
  194. package/dist/modules/customers/components/formConfig.js.map +2 -2
  195. package/dist/modules/customers/data/guards.js +66 -0
  196. package/dist/modules/customers/data/guards.js.map +7 -0
  197. package/dist/modules/customers/di.js +37 -0
  198. package/dist/modules/customers/di.js.map +2 -2
  199. package/dist/modules/customers/lib/todoCompatibility.js +11 -0
  200. package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
  201. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
  202. package/dist/modules/data_sync/api/options.js +4 -4
  203. package/dist/modules/data_sync/api/options.js.map +2 -2
  204. package/dist/modules/data_sync/api/schedules/route.js +9 -1
  205. package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
  206. package/dist/modules/data_sync/backend/data-sync/page.js +17 -8
  207. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  208. package/dist/modules/data_sync/components/IntegrationScheduleTab.js +43 -22
  209. package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
  210. package/dist/modules/data_sync/lib/sync-schedule-service.js +9 -0
  211. package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
  212. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +8 -1
  213. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  214. package/dist/modules/dictionaries/api/[dictionaryId]/route.js +17 -1
  215. package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
  216. package/dist/modules/dictionaries/components/DictionariesManager.js +31 -10
  217. package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
  218. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +28 -15
  219. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
  220. package/dist/modules/directory/api/organizations/route.js +3 -0
  221. package/dist/modules/directory/api/organizations/route.js.map +2 -2
  222. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +2 -0
  223. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
  224. package/dist/modules/directory/backend/directory/organizations/page.js +9 -5
  225. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  226. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +7 -3
  227. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
  228. package/dist/modules/directory/backend/directory/tenants/page.js +8 -4
  229. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  230. package/dist/modules/directory/commands/organizations.js +7 -2
  231. package/dist/modules/directory/commands/organizations.js.map +2 -2
  232. package/dist/modules/entities/api/records.js +66 -0
  233. package/dist/modules/entities/api/records.js.map +2 -2
  234. package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js +1 -0
  235. package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js.map +2 -2
  236. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +8 -4
  237. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  238. package/dist/modules/entities/lib/helpers.js +17 -0
  239. package/dist/modules/entities/lib/helpers.js.map +2 -2
  240. package/dist/modules/feature_toggles/api/global/[id]/override/route.js +2 -1
  241. package/dist/modules/feature_toggles/api/global/[id]/override/route.js.map +2 -2
  242. package/dist/modules/feature_toggles/api/overrides/route.js +15 -0
  243. package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
  244. package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js +15 -14
  245. package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js.map +2 -2
  246. package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js +20 -12
  247. package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js.map +2 -2
  248. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +6 -2
  249. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
  250. package/dist/modules/feature_toggles/components/formConfig.js +2 -1
  251. package/dist/modules/feature_toggles/components/formConfig.js.map +2 -2
  252. package/dist/modules/feature_toggles/components/overrideFormConfig.js +5 -1
  253. package/dist/modules/feature_toggles/components/overrideFormConfig.js.map +2 -2
  254. package/dist/modules/feature_toggles/data/validators.js +7 -4
  255. package/dist/modules/feature_toggles/data/validators.js.map +2 -2
  256. package/dist/modules/inbox_ops/api/settings/route.js +17 -2
  257. package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
  258. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js +13 -8
  259. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js.map +2 -2
  260. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +9 -4
  261. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
  262. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +18 -11
  263. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
  264. package/dist/modules/integrations/backend/integrations/page.js +12 -8
  265. package/dist/modules/integrations/backend/integrations/page.js.map +2 -2
  266. package/dist/modules/messages/commands/messages.js +13 -10
  267. package/dist/modules/messages/commands/messages.js.map +2 -2
  268. package/dist/modules/perspectives/api/[tableId]/route.js +39 -30
  269. package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
  270. package/dist/modules/perspectives/services/perspectiveService.js +7 -0
  271. package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
  272. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +6 -14
  273. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +3 -3
  274. package/dist/modules/planner/backend/planner/availability-rulesets/page.js +4 -2
  275. package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
  276. package/dist/modules/planner/components/AvailabilityRuleSetForm.js +2 -0
  277. package/dist/modules/planner/components/AvailabilityRuleSetForm.js.map +2 -2
  278. package/dist/modules/planner/components/AvailabilityRulesEditor.js +36 -11
  279. package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
  280. package/dist/modules/planner/components/AvailabilitySchedule.js +9 -5
  281. package/dist/modules/planner/components/AvailabilitySchedule.js.map +2 -2
  282. package/dist/modules/progress/api/jobs/[id]/route.js +7 -1
  283. package/dist/modules/progress/api/jobs/[id]/route.js.map +2 -2
  284. package/dist/modules/query_index/lib/engine.js +19 -0
  285. package/dist/modules/query_index/lib/engine.js.map +2 -2
  286. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +1 -0
  287. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
  288. package/dist/modules/resources/backend/resources/resource-types/page.js +4 -2
  289. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  290. package/dist/modules/resources/backend/resources/resources/[id]/page.js +14 -3
  291. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  292. package/dist/modules/resources/backend/resources/resources/page.js +8 -4
  293. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  294. package/dist/modules/resources/components/ResourceCrudForm.js +2 -0
  295. package/dist/modules/resources/components/ResourceCrudForm.js.map +2 -2
  296. package/dist/modules/resources/components/ResourceTypeCrudForm.js +1 -0
  297. package/dist/modules/resources/components/ResourceTypeCrudForm.js.map +2 -2
  298. package/dist/modules/sales/api/documents/factory.js +7 -2
  299. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  300. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +3 -1
  301. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
  302. package/dist/modules/sales/backend/sales/channels/offers/page.js +13 -4
  303. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  304. package/dist/modules/sales/backend/sales/channels/page.js +16 -4
  305. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  306. package/dist/modules/sales/backend/sales/documents/[id]/page.js +68 -22
  307. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  308. package/dist/modules/sales/backend/sales/documents/create/page.js.map +2 -2
  309. package/dist/modules/sales/commands/documentAddresses.js +181 -2
  310. package/dist/modules/sales/commands/documentAddresses.js.map +2 -2
  311. package/dist/modules/sales/commands/documents.js +29 -1
  312. package/dist/modules/sales/commands/documents.js.map +2 -2
  313. package/dist/modules/sales/commands/returns.js +12 -2
  314. package/dist/modules/sales/commands/returns.js.map +2 -2
  315. package/dist/modules/sales/commands/shared.js +15 -0
  316. package/dist/modules/sales/commands/shared.js.map +2 -2
  317. package/dist/modules/sales/commands/shipments.js +4 -1
  318. package/dist/modules/sales/commands/shipments.js.map +2 -2
  319. package/dist/modules/sales/components/AdjustmentKindSettings.js +19 -11
  320. package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
  321. package/dist/modules/sales/components/DocumentNumberSettings.js.map +2 -2
  322. package/dist/modules/sales/components/OrderEditingSettings.js.map +2 -2
  323. package/dist/modules/sales/components/PaymentMethodsSettings.js +12 -4
  324. package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
  325. package/dist/modules/sales/components/ShippingMethodsSettings.js +12 -4
  326. package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
  327. package/dist/modules/sales/components/StatusSettings.js +18 -11
  328. package/dist/modules/sales/components/StatusSettings.js.map +2 -2
  329. package/dist/modules/sales/components/TaxRatesSettings.js +12 -4
  330. package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
  331. package/dist/modules/sales/components/channels/ChannelOfferForm.js +47 -16
  332. package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
  333. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +8 -4
  334. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
  335. package/dist/modules/sales/components/documents/AddressesSection.js +44 -25
  336. package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
  337. package/dist/modules/sales/components/documents/AdjustmentsSection.js +43 -23
  338. package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
  339. package/dist/modules/sales/components/documents/ItemsSection.js +22 -13
  340. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  341. package/dist/modules/sales/components/documents/LineItemDialog.js +23 -10
  342. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  343. package/dist/modules/sales/components/documents/PaymentDialog.js +29 -14
  344. package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
  345. package/dist/modules/sales/components/documents/PaymentsSection.js +20 -10
  346. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  347. package/dist/modules/sales/components/documents/ReturnDialog.js +26 -17
  348. package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
  349. package/dist/modules/sales/components/documents/ReturnsSection.js +3 -1
  350. package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
  351. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +10 -5
  352. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  353. package/dist/modules/sales/components/documents/ShipmentDialog.js +21 -7
  354. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  355. package/dist/modules/sales/components/documents/ShipmentsSection.js +19 -10
  356. package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
  357. package/dist/modules/sales/components/documents/optimisticLock.js +27 -0
  358. package/dist/modules/sales/components/documents/optimisticLock.js.map +7 -0
  359. package/dist/modules/sales/di.js +18 -0
  360. package/dist/modules/sales/di.js.map +2 -2
  361. package/dist/modules/shipping_carriers/api/cancel/route.js +2 -2
  362. package/dist/modules/shipping_carriers/api/cancel/route.js.map +2 -2
  363. package/dist/modules/shipping_carriers/lib/status-sync.js +8 -1
  364. package/dist/modules/shipping_carriers/lib/status-sync.js.map +2 -2
  365. package/dist/modules/staff/api/job-histories.js +11 -2
  366. package/dist/modules/staff/api/job-histories.js.map +2 -2
  367. package/dist/modules/staff/api/timesheets/time-entries/route.js +11 -4
  368. package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
  369. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +13 -8
  370. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  371. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +2 -1
  372. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
  373. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +7 -4
  374. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  375. package/dist/modules/staff/backend/staff/team-members/page.js +4 -2
  376. package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
  377. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +1 -0
  378. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
  379. package/dist/modules/staff/backend/staff/team-roles/page.js +4 -2
  380. package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
  381. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +5 -2
  382. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  383. package/dist/modules/staff/backend/staff/teams/page.js +12 -3
  384. package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
  385. package/dist/modules/staff/backend/staff/timesheets/page.js +4 -1
  386. package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
  387. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +2 -2
  388. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +12 -3
  389. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
  390. package/dist/modules/staff/commands/job-histories.js +40 -3
  391. package/dist/modules/staff/commands/job-histories.js.map +2 -2
  392. package/dist/modules/staff/components/LeaveRequestForm.js +1 -0
  393. package/dist/modules/staff/components/LeaveRequestForm.js.map +2 -2
  394. package/dist/modules/staff/components/TeamForm.js +1 -0
  395. package/dist/modules/staff/components/TeamForm.js.map +2 -2
  396. package/dist/modules/staff/components/TeamMemberForm.js +1 -0
  397. package/dist/modules/staff/components/TeamMemberForm.js.map +2 -2
  398. package/dist/modules/staff/components/TeamRoleForm.js +1 -0
  399. package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
  400. package/dist/modules/staff/components/detail/JobHistorySection.js +20 -7
  401. package/dist/modules/staff/components/detail/JobHistorySection.js.map +2 -2
  402. package/dist/modules/staff/data/validators.js +7 -1
  403. package/dist/modules/staff/data/validators.js.map +2 -2
  404. package/dist/modules/staff/lib/leaveRequestHelpers.js +2 -1
  405. package/dist/modules/staff/lib/leaveRequestHelpers.js.map +2 -2
  406. package/dist/modules/translations/components/TranslationManager.js +12 -8
  407. package/dist/modules/translations/components/TranslationManager.js.map +2 -2
  408. package/dist/modules/workflows/api/definitions/[id]/route.js +106 -0
  409. package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
  410. package/dist/modules/workflows/backend/definitions/[id]/page.js +11 -3
  411. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  412. package/dist/modules/workflows/backend/definitions/page.js +19 -8
  413. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  414. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +29 -16
  415. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  416. package/dist/modules/workflows/components/NodeEditDialog.js +3 -1
  417. package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
  418. package/dist/modules/workflows/components/WorkflowGraphImpl.js +4 -2
  419. package/dist/modules/workflows/components/WorkflowGraphImpl.js.map +2 -2
  420. package/dist/modules/workflows/components/formConfig.js +4 -1
  421. package/dist/modules/workflows/components/formConfig.js.map +2 -2
  422. package/dist/modules/workflows/components/nodes/ParallelForkNode.js +49 -0
  423. package/dist/modules/workflows/components/nodes/ParallelForkNode.js.map +7 -0
  424. package/dist/modules/workflows/components/nodes/ParallelJoinNode.js +49 -0
  425. package/dist/modules/workflows/components/nodes/ParallelJoinNode.js.map +7 -0
  426. package/dist/modules/workflows/components/nodes/index.js +4 -0
  427. package/dist/modules/workflows/components/nodes/index.js.map +2 -2
  428. package/dist/modules/workflows/data/entities.js +81 -0
  429. package/dist/modules/workflows/data/entities.js.map +2 -2
  430. package/dist/modules/workflows/data/validators.js +146 -1
  431. package/dist/modules/workflows/data/validators.js.map +2 -2
  432. package/dist/modules/workflows/di.js +12 -0
  433. package/dist/modules/workflows/di.js.map +2 -2
  434. package/dist/modules/workflows/events.js +7 -1
  435. package/dist/modules/workflows/events.js.map +2 -2
  436. package/dist/modules/workflows/lib/activity-executor.js +4 -2
  437. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  438. package/dist/modules/workflows/lib/activity-queue-types.js.map +2 -2
  439. package/dist/modules/workflows/lib/event-logger.js +2 -0
  440. package/dist/modules/workflows/lib/event-logger.js.map +2 -2
  441. package/dist/modules/workflows/lib/execution-token.js +98 -0
  442. package/dist/modules/workflows/lib/execution-token.js.map +7 -0
  443. package/dist/modules/workflows/lib/node-type-icons.js +14 -5
  444. package/dist/modules/workflows/lib/node-type-icons.js.map +2 -2
  445. package/dist/modules/workflows/lib/parallel-handler.js +364 -0
  446. package/dist/modules/workflows/lib/parallel-handler.js.map +7 -0
  447. package/dist/modules/workflows/lib/signal-handler.js +63 -1
  448. package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
  449. package/dist/modules/workflows/lib/step-handler.js +74 -30
  450. package/dist/modules/workflows/lib/step-handler.js.map +2 -2
  451. package/dist/modules/workflows/lib/task-handler.js +26 -0
  452. package/dist/modules/workflows/lib/task-handler.js.map +2 -2
  453. package/dist/modules/workflows/lib/timer-handler.js +26 -1
  454. package/dist/modules/workflows/lib/timer-handler.js.map +2 -2
  455. package/dist/modules/workflows/lib/transition-handler.js +33 -21
  456. package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
  457. package/dist/modules/workflows/lib/workflow-executor.js +39 -1
  458. package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
  459. package/dist/modules/workflows/migrations/Migration20260602120000.js +24 -0
  460. package/dist/modules/workflows/migrations/Migration20260602120000.js.map +7 -0
  461. package/dist/modules/workflows/workers/workflow-activities.worker.js +8 -4
  462. package/dist/modules/workflows/workers/workflow-activities.worker.js.map +2 -2
  463. package/generated/entities/role/index.ts +1 -0
  464. package/generated/entities/step_instance/index.ts +1 -0
  465. package/generated/entities/user/index.ts +1 -0
  466. package/generated/entities/user_task/index.ts +1 -0
  467. package/generated/entities/workflow_branch_instance/index.ts +18 -0
  468. package/generated/entities/workflow_event/index.ts +1 -0
  469. package/generated/entities/workflow_instance/index.ts +1 -0
  470. package/generated/entities.ids.generated.ts +1 -0
  471. package/generated/entity-fields-registry.ts +26 -0
  472. package/jest.setup.ts +17 -0
  473. package/package.json +8 -7
  474. package/src/helpers/integration/optimisticLockUi.ts +172 -0
  475. package/src/helpers/integration/salesFixtures.ts +29 -0
  476. package/src/modules/api_keys/backend/api-keys/page.tsx +10 -5
  477. package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +19 -9
  478. package/src/modules/auth/api/roles/acl/route.ts +37 -11
  479. package/src/modules/auth/api/roles/route.ts +2 -0
  480. package/src/modules/auth/api/sidebar/preferences/route.ts +73 -0
  481. package/src/modules/auth/api/users/acl/route.ts +46 -18
  482. package/src/modules/auth/api/users/route.ts +2 -0
  483. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +29 -4
  484. package/src/modules/auth/backend/roles/page.tsx +9 -4
  485. package/src/modules/auth/backend/users/[id]/edit/page.tsx +37 -4
  486. package/src/modules/auth/backend/users/page.tsx +7 -2
  487. package/src/modules/auth/components/AclEditor.tsx +10 -1
  488. package/src/modules/auth/data/entities.ts +7 -1
  489. package/src/modules/auth/services/sidebarPreferencesService.ts +38 -4
  490. package/src/modules/business_rules/api/rules/route.ts +30 -0
  491. package/src/modules/business_rules/api/sets/route.ts +30 -0
  492. package/src/modules/business_rules/backend/rules/[id]/page.tsx +16 -4
  493. package/src/modules/business_rules/backend/rules/page.tsx +20 -11
  494. package/src/modules/business_rules/backend/sets/[id]/page.tsx +16 -4
  495. package/src/modules/business_rules/backend/sets/page.tsx +20 -11
  496. package/src/modules/catalog/api/categories/route.ts +3 -0
  497. package/src/modules/catalog/api/products/route.ts +4 -0
  498. package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +5 -0
  499. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +112 -35
  500. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +56 -7
  501. package/src/modules/catalog/backend/catalog/products/optionSchemaClient.ts +2 -0
  502. package/src/modules/catalog/commands/variants.ts +32 -32
  503. package/src/modules/catalog/components/PriceKindSettings.tsx +20 -7
  504. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +1 -0
  505. package/src/modules/catalog/components/products/ProductMediaManager.tsx +2 -0
  506. package/src/modules/catalog/components/products/ProductsDataTable.tsx +8 -4
  507. package/src/modules/catalog/components/products/productForm.ts +3 -0
  508. package/src/modules/catalog/components/products/variantForm.ts +9 -0
  509. package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +5 -0
  510. package/src/modules/currencies/backend/currencies/[id]/page.tsx +13 -6
  511. package/src/modules/currencies/backend/currencies/page.tsx +18 -11
  512. package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +3 -0
  513. package/src/modules/currencies/backend/exchange-rates/page.tsx +10 -6
  514. package/src/modules/currencies/commands/currencies.ts +10 -5
  515. package/src/modules/currencies/components/CurrencyFetchingConfig.tsx +31 -21
  516. package/src/modules/customer_accounts/api/admin/roles/[id].ts +35 -5
  517. package/src/modules/customer_accounts/api/admin/roles.ts +2 -0
  518. package/src/modules/customer_accounts/api/admin/users/[id].ts +38 -5
  519. package/src/modules/customer_accounts/api/admin/users.ts +2 -0
  520. package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +34 -20
  521. package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +9 -4
  522. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/page.tsx +11 -4
  523. package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +28 -17
  524. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +19 -11
  525. package/src/modules/customers/AGENTS.md +2 -2
  526. package/src/modules/customers/api/companies/route.ts +14 -1
  527. package/src/modules/customers/api/deals/route.ts +3 -0
  528. package/src/modules/customers/api/people/route.ts +12 -1
  529. package/src/modules/customers/api/todos/route.ts +1 -0
  530. package/src/modules/customers/backend/config/customers/deals/page.tsx +1 -0
  531. package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +36 -21
  532. package/src/modules/customers/backend/customers/companies/[id]/page.tsx +52 -27
  533. package/src/modules/customers/backend/customers/companies/page.tsx +2 -0
  534. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +27 -5
  535. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.ts +39 -7
  536. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +1 -0
  537. package/src/modules/customers/backend/customers/deals/page.tsx +18 -6
  538. package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +64 -39
  539. package/src/modules/customers/backend/customers/people/[id]/page.tsx +46 -26
  540. package/src/modules/customers/backend/customers/people/page.tsx +2 -0
  541. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +84 -24
  542. package/src/modules/customers/commands/addresses.ts +16 -14
  543. package/src/modules/customers/commands/companies.ts +3 -1
  544. package/src/modules/customers/commands/interactions.ts +50 -4
  545. package/src/modules/customers/commands/people.ts +2 -1
  546. package/src/modules/customers/commands/personCompanyLinks.ts +8 -5
  547. package/src/modules/customers/commands/pipeline-stages.ts +16 -16
  548. package/src/modules/customers/components/AddressFormatSettings.tsx +1 -0
  549. package/src/modules/customers/components/DictionarySettings.tsx +18 -13
  550. package/src/modules/customers/components/DictionarySortSettings.tsx +4 -0
  551. package/src/modules/customers/components/PipelineSettings.tsx +42 -21
  552. package/src/modules/customers/components/detail/ActivityTimeline.tsx +3 -3
  553. package/src/modules/customers/components/detail/AddressesSection.tsx +4 -0
  554. package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +2 -0
  555. package/src/modules/customers/components/detail/DealsSection.tsx +4 -0
  556. package/src/modules/customers/components/detail/EmailCardActions.tsx +5 -0
  557. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +7 -0
  558. package/src/modules/customers/components/detail/ManageTagsDialog.tsx +4 -0
  559. package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +4 -0
  560. package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +2 -0
  561. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +23 -7
  562. package/src/modules/customers/components/detail/hooks/useInteractionMutations.ts +25 -15
  563. package/src/modules/customers/components/detail/hooks/useInteractions.ts +76 -35
  564. package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +30 -17
  565. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +2 -0
  566. package/src/modules/customers/components/detail/types.ts +1 -0
  567. package/src/modules/customers/components/formConfig.tsx +2 -0
  568. package/src/modules/customers/data/guards.ts +67 -0
  569. package/src/modules/customers/di.ts +66 -0
  570. package/src/modules/customers/i18n/de.json +2 -0
  571. package/src/modules/customers/i18n/en.json +2 -0
  572. package/src/modules/customers/i18n/es.json +2 -0
  573. package/src/modules/customers/i18n/pl.json +2 -0
  574. package/src/modules/customers/lib/todoCompatibility.ts +14 -0
  575. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +2 -0
  576. package/src/modules/data_sync/api/options.ts +7 -4
  577. package/src/modules/data_sync/api/schedules/route.ts +9 -1
  578. package/src/modules/data_sync/backend/data-sync/page.tsx +18 -5
  579. package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +46 -19
  580. package/src/modules/data_sync/lib/sync-schedule-service.ts +11 -0
  581. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +8 -1
  582. package/src/modules/dictionaries/api/[dictionaryId]/route.ts +23 -0
  583. package/src/modules/dictionaries/components/DictionariesManager.tsx +32 -9
  584. package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +30 -14
  585. package/src/modules/dictionaries/i18n/de.json +1 -0
  586. package/src/modules/dictionaries/i18n/en.json +1 -0
  587. package/src/modules/dictionaries/i18n/es.json +1 -0
  588. package/src/modules/dictionaries/i18n/pl.json +1 -0
  589. package/src/modules/directory/api/organizations/route.ts +3 -0
  590. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +8 -0
  591. package/src/modules/directory/backend/directory/organizations/page.tsx +10 -5
  592. package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +16 -5
  593. package/src/modules/directory/backend/directory/tenants/page.tsx +8 -4
  594. package/src/modules/directory/commands/organizations.ts +7 -4
  595. package/src/modules/entities/api/records.ts +99 -0
  596. package/src/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.tsx +7 -0
  597. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +8 -4
  598. package/src/modules/entities/lib/helpers.ts +17 -0
  599. package/src/modules/feature_toggles/api/global/[id]/override/route.ts +1 -0
  600. package/src/modules/feature_toggles/api/overrides/route.ts +19 -0
  601. package/src/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.tsx +19 -13
  602. package/src/modules/feature_toggles/components/FeatureToggleOverrideCard.tsx +22 -12
  603. package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +7 -2
  604. package/src/modules/feature_toggles/components/formConfig.tsx +2 -1
  605. package/src/modules/feature_toggles/components/overrideFormConfig.tsx +10 -1
  606. package/src/modules/feature_toggles/data/validators.ts +11 -3
  607. package/src/modules/inbox_ops/api/settings/route.ts +18 -0
  608. package/src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx +15 -10
  609. package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +9 -4
  610. package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +20 -11
  611. package/src/modules/integrations/backend/integrations/page.tsx +13 -8
  612. package/src/modules/messages/commands/messages.ts +27 -15
  613. package/src/modules/perspectives/api/[tableId]/route.ts +11 -2
  614. package/src/modules/perspectives/services/perspectiveService.ts +13 -1
  615. package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +16 -14
  616. package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +6 -3
  617. package/src/modules/planner/components/AvailabilityRuleSetForm.tsx +3 -0
  618. package/src/modules/planner/components/AvailabilityRulesEditor.tsx +58 -15
  619. package/src/modules/planner/components/AvailabilitySchedule.tsx +22 -7
  620. package/src/modules/progress/api/jobs/[id]/route.ts +7 -0
  621. package/src/modules/query_index/lib/engine.ts +34 -0
  622. package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +7 -1
  623. package/src/modules/resources/backend/resources/resource-types/page.tsx +6 -3
  624. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +23 -3
  625. package/src/modules/resources/backend/resources/resources/page.tsx +15 -4
  626. package/src/modules/resources/components/ResourceCrudForm.tsx +3 -0
  627. package/src/modules/resources/components/ResourceTypeCrudForm.tsx +2 -0
  628. package/src/modules/sales/api/documents/factory.ts +13 -1
  629. package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +6 -0
  630. package/src/modules/sales/backend/sales/channels/offers/page.tsx +10 -4
  631. package/src/modules/sales/backend/sales/channels/page.tsx +19 -4
  632. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +73 -20
  633. package/src/modules/sales/backend/sales/documents/create/page.tsx +2 -0
  634. package/src/modules/sales/commands/documentAddresses.ts +226 -4
  635. package/src/modules/sales/commands/documents.ts +28 -0
  636. package/src/modules/sales/commands/returns.ts +12 -3
  637. package/src/modules/sales/commands/shared.ts +36 -0
  638. package/src/modules/sales/commands/shipments.ts +17 -1
  639. package/src/modules/sales/components/AdjustmentKindSettings.tsx +20 -11
  640. package/src/modules/sales/components/DocumentNumberSettings.tsx +1 -0
  641. package/src/modules/sales/components/OrderEditingSettings.tsx +1 -0
  642. package/src/modules/sales/components/PaymentMethodsSettings.tsx +12 -4
  643. package/src/modules/sales/components/ShippingMethodsSettings.tsx +12 -4
  644. package/src/modules/sales/components/StatusSettings.tsx +20 -11
  645. package/src/modules/sales/components/TaxRatesSettings.tsx +12 -5
  646. package/src/modules/sales/components/channels/ChannelOfferForm.tsx +67 -14
  647. package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +7 -4
  648. package/src/modules/sales/components/documents/AddressesSection.tsx +35 -25
  649. package/src/modules/sales/components/documents/AdjustmentsSection.tsx +50 -25
  650. package/src/modules/sales/components/documents/ItemsSection.tsx +24 -13
  651. package/src/modules/sales/components/documents/LineItemDialog.tsx +26 -9
  652. package/src/modules/sales/components/documents/PaymentDialog.tsx +33 -14
  653. package/src/modules/sales/components/documents/PaymentsSection.tsx +22 -10
  654. package/src/modules/sales/components/documents/ReturnDialog.tsx +28 -17
  655. package/src/modules/sales/components/documents/ReturnsSection.tsx +4 -1
  656. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +11 -4
  657. package/src/modules/sales/components/documents/ShipmentDialog.tsx +23 -8
  658. package/src/modules/sales/components/documents/ShipmentsSection.tsx +20 -10
  659. package/src/modules/sales/components/documents/optimisticLock.ts +34 -0
  660. package/src/modules/sales/components/documents/shipmentTypes.ts +1 -0
  661. package/src/modules/sales/di.ts +35 -0
  662. package/src/modules/sales/i18n/de.json +3 -0
  663. package/src/modules/sales/i18n/en.json +3 -0
  664. package/src/modules/sales/i18n/es.json +3 -0
  665. package/src/modules/sales/i18n/pl.json +3 -0
  666. package/src/modules/shipping_carriers/api/cancel/route.ts +2 -2
  667. package/src/modules/shipping_carriers/lib/status-sync.ts +19 -0
  668. package/src/modules/staff/api/job-histories.ts +12 -2
  669. package/src/modules/staff/api/timesheets/time-entries/route.ts +16 -4
  670. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +12 -7
  671. package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +2 -0
  672. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +16 -5
  673. package/src/modules/staff/backend/staff/team-members/page.tsx +6 -2
  674. package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +8 -0
  675. package/src/modules/staff/backend/staff/team-roles/page.tsx +6 -2
  676. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +13 -3
  677. package/src/modules/staff/backend/staff/teams/page.tsx +9 -3
  678. package/src/modules/staff/backend/staff/timesheets/page.tsx +10 -1
  679. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -0
  680. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +9 -3
  681. package/src/modules/staff/commands/job-histories.ts +42 -3
  682. package/src/modules/staff/components/LeaveRequestForm.tsx +2 -0
  683. package/src/modules/staff/components/TeamForm.tsx +2 -0
  684. package/src/modules/staff/components/TeamMemberForm.tsx +2 -0
  685. package/src/modules/staff/components/TeamRoleForm.tsx +2 -0
  686. package/src/modules/staff/components/detail/JobHistorySection.tsx +28 -6
  687. package/src/modules/staff/data/validators.ts +6 -0
  688. package/src/modules/staff/i18n/de.json +1 -0
  689. package/src/modules/staff/i18n/en.json +1 -0
  690. package/src/modules/staff/i18n/es.json +1 -0
  691. package/src/modules/staff/i18n/pl.json +1 -0
  692. package/src/modules/staff/lib/leaveRequestHelpers.ts +4 -0
  693. package/src/modules/translations/components/TranslationManager.tsx +13 -8
  694. package/src/modules/workflows/api/definitions/[id]/route.ts +112 -0
  695. package/src/modules/workflows/backend/definitions/[id]/page.tsx +20 -4
  696. package/src/modules/workflows/backend/definitions/page.tsx +20 -9
  697. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +29 -16
  698. package/src/modules/workflows/components/NodeEditDialog.tsx +2 -0
  699. package/src/modules/workflows/components/WorkflowGraphImpl.tsx +3 -1
  700. package/src/modules/workflows/components/formConfig.tsx +5 -0
  701. package/src/modules/workflows/components/nodes/ParallelForkNode.tsx +66 -0
  702. package/src/modules/workflows/components/nodes/ParallelJoinNode.tsx +66 -0
  703. package/src/modules/workflows/components/nodes/index.ts +6 -0
  704. package/src/modules/workflows/data/entities.ts +109 -0
  705. package/src/modules/workflows/data/validators.ts +223 -0
  706. package/src/modules/workflows/di.ts +20 -0
  707. package/src/modules/workflows/events.ts +7 -0
  708. package/src/modules/workflows/i18n/de.json +13 -0
  709. package/src/modules/workflows/i18n/en.json +13 -0
  710. package/src/modules/workflows/i18n/es.json +13 -0
  711. package/src/modules/workflows/i18n/pl.json +13 -0
  712. package/src/modules/workflows/lib/activity-executor.ts +8 -2
  713. package/src/modules/workflows/lib/activity-queue-types.ts +3 -0
  714. package/src/modules/workflows/lib/event-logger.ts +3 -0
  715. package/src/modules/workflows/lib/execution-token.ts +166 -0
  716. package/src/modules/workflows/lib/node-type-icons.ts +11 -2
  717. package/src/modules/workflows/lib/parallel-handler.ts +575 -0
  718. package/src/modules/workflows/lib/signal-handler.ts +72 -1
  719. package/src/modules/workflows/lib/step-handler.ts +94 -34
  720. package/src/modules/workflows/lib/task-handler.ts +32 -0
  721. package/src/modules/workflows/lib/timer-handler.ts +30 -1
  722. package/src/modules/workflows/lib/transition-handler.ts +56 -24
  723. package/src/modules/workflows/lib/workflow-executor.ts +53 -1
  724. package/src/modules/workflows/migrations/.snapshot-open-mercato.json +263 -0
  725. package/src/modules/workflows/migrations/Migration20260602120000.ts +25 -0
  726. package/src/modules/workflows/workers/workflow-activities.worker.ts +9 -4
@@ -186,6 +186,23 @@ export async function setRecordCustomFields(
186
186
 
187
187
  if (toPersist.length) em.persist(toPersist)
188
188
  await em.flush()
189
+ if (process.env.OM_CF_DEBUG) {
190
+ try {
191
+ const conn = em.getConnection()
192
+ for (const fieldKey of keys) {
193
+ if (values[fieldKey] === undefined) continue
194
+ const rows = await conn.execute(
195
+ 'select value_text, value_multiline, value_int, value_float, value_bool from custom_field_values where entity_id = ? and record_id = ? and field_key = ? and ((organization_id is null and ? is null) or organization_id = ?) and ((tenant_id is null and ? is null) or tenant_id = ?)',
196
+ [entityId, recordId, fieldKey, organizationId, organizationId, tenantId, tenantId],
197
+ 'all',
198
+ ) as Array<Record<string, unknown>>
199
+ const persisted = rows.map((row) => row.value_text ?? row.value_multiline ?? row.value_int ?? row.value_float ?? row.value_bool)
200
+ console.warn(`[CF_DEBUG] setRecordCustomFields entityId=${entityId} recordId=${recordId} fieldKey=${fieldKey} input=${JSON.stringify(values[fieldKey])} persistedRows=${rows.length} persisted=${JSON.stringify(persisted)}`)
201
+ }
202
+ } catch (err) {
203
+ console.warn(`[CF_DEBUG] re-query failed: ${(err as Error)?.message ?? String(err)}`)
204
+ }
205
+ }
189
206
  // Emit hook for indexing if requested (outside CRUD flows)
190
207
  try {
191
208
  if (typeof opts.onChanged === 'function') {
@@ -45,6 +45,7 @@ export async function GET(req: Request, { params }: { params: { id: string } })
45
45
  tenantName: tenant.name,
46
46
  tenantId: tenant.id,
47
47
  toggleType: toggle.type,
48
+ updatedAt: override?.updatedAt instanceof Date ? override.updatedAt.toISOString() : null,
48
49
  }
49
50
 
50
51
  await logCrudAccess({
@@ -6,7 +6,9 @@ import type { CommandBus } from '@open-mercato/shared/lib/commands'
6
6
  import { serializeOperationMetadata } from '@open-mercato/shared/lib/commands/operationMetadata'
7
7
  import { getOverrides } from '../../lib/queries'
8
8
  import { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
9
+ import { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
9
10
  import { logCrudAccess } from '@open-mercato/shared/lib/crud/factory'
11
+ import { FeatureToggleOverride } from '../../data/entities'
10
12
  import { buildContext } from '../../lib/utils'
11
13
  import { resolveFeatureCheckContext } from "@open-mercato/core/modules/directory/utils/organizationScope"
12
14
  import { ProcessedChangeOverrideStateInput } from '../../data/validators'
@@ -87,6 +89,23 @@ export async function PUT(req: Request) {
87
89
  }, { status: 400 })
88
90
  }
89
91
 
92
+ // Optimistic lock: refuse a stale override overwrite when two admins edit the
93
+ // same global toggle override in parallel. Only enforced when an override row
94
+ // already exists (first set has no prior version). Strictly additive.
95
+ const em = ctx.container.resolve('em') as EntityManager
96
+ const existingOverride = await em.findOne(FeatureToggleOverride, {
97
+ tenantId: scope.tenantId,
98
+ toggle: { id: parsed.data.toggleId },
99
+ })
100
+ if (existingOverride) {
101
+ enforceCommandOptimisticLock({
102
+ resourceKind: 'feature_toggles.feature_toggle_override',
103
+ resourceId: existingOverride.id,
104
+ current: existingOverride.updatedAt ?? null,
105
+ request: req,
106
+ })
107
+ }
108
+
90
109
  const commandBus = ctx.container.resolve('commandBus') as CommandBus
91
110
  const { result, logEntry } = await commandBus.execute<ProcessedChangeOverrideStateInput, { overrideToggleId: string | null }>('feature_toggles.overrides.changeState', {
92
111
  input: {
@@ -10,7 +10,6 @@ import { createFieldDefinitions, createFormGroups } from "@open-mercato/core/mod
10
10
 
11
11
 
12
12
  export default function EditFeatureTogglePage({ params }: { params?: { id?: string } }) {
13
- const [initialValues, setInitialValues] = React.useState<any>(null)
14
13
  const { id } = params ?? {}
15
14
  const t = useT()
16
15
  const fields = createFieldDefinitions(t);
@@ -18,30 +17,37 @@ export default function EditFeatureTogglePage({ params }: { params?: { id?: stri
18
17
 
19
18
  const { data: featureToggleItem, isLoading } = useFeatureToggleItem(id)
20
19
 
21
- React.useEffect(() => {
22
- if (featureToggleItem) {
23
- setInitialValues({
24
- identifier: featureToggleItem.identifier,
25
- name: featureToggleItem.name,
26
- description: featureToggleItem.description,
27
- category: featureToggleItem.category,
28
-
29
- type: featureToggleItem.type,
30
- defaultValue: featureToggleItem.defaultValue,
31
- })
20
+ // Derive the form's initial values synchronously from the loaded record. Using
21
+ // a useState+useEffect here caused #2452: `isLoading` flips to false one render
22
+ // before the effect set `initialValues`, so CrudForm mounted with `{}` and the
23
+ // `type` SELECT captured an empty value (text inputs re-sync from the prop, the
24
+ // select does not). Deriving here means the value is present in the same render
25
+ // the data arrives; the `key` below also forces a clean remount on load.
26
+ const initialValues = React.useMemo(() => {
27
+ if (!featureToggleItem) return null
28
+ return {
29
+ id: featureToggleItem.id ?? (id ? String(id) : ''),
30
+ identifier: featureToggleItem.identifier,
31
+ name: featureToggleItem.name,
32
+ description: featureToggleItem.description,
33
+ category: featureToggleItem.category,
34
+ type: featureToggleItem.type,
35
+ defaultValue: featureToggleItem.defaultValue,
32
36
  }
33
- }, [featureToggleItem])
37
+ }, [featureToggleItem, id])
34
38
 
35
39
  return (
36
40
  <Page>
37
41
  <PageBody>
38
42
  <CrudForm
43
+ key={initialValues ? 'ft-edit-loaded' : 'ft-edit-loading'}
39
44
  title={t('feature_toggles.form.title.edit', 'Edit Feature Toggle')}
40
45
  backHref="/backend/feature-toggles/global"
41
46
  versionHistory={{ resourceKind: 'feature_toggles.global', resourceId: id ? String(id) : '' }}
42
47
  fields={fields}
43
48
  entityId={E.feature_toggles.feature_toggle}
44
49
  initialValues={initialValues ?? {}}
50
+ optimisticLockUpdatedAt={featureToggleItem?.updatedAt ?? null}
45
51
  isLoading={isLoading}
46
52
  groups={formGroups}
47
53
  loadingMessage={t('feature_toggles.form.loading', 'Loading feature toggles')}
@@ -2,7 +2,9 @@
2
2
  import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@open-mercato/ui/primitives/card'
3
3
  import { DataLoader, ErrorNotice } from "@open-mercato/ui";
4
4
  import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
5
- import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
5
+ import { apiCall, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
6
+ import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
7
+ import { surfaceRecordConflict } from "@open-mercato/ui/backend/conflicts";
6
8
  import { raiseCrudError } from "@open-mercato/ui/backend/utils/serverErrors";
7
9
  import { useT } from "@open-mercato/shared/lib/i18n/context";
8
10
  import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
@@ -28,23 +30,31 @@ export function FeatureToggleOverrideCard({ toggleId }: { toggleId: string }) {
28
30
 
29
31
  const mutation = useMutation({
30
32
  mutationFn: async (input: { toggleId: string; isOverride: boolean; overrideValue?: any; tenantId: string }) => {
31
- const call = await apiCall<{ ok: boolean }>(
32
- `/api/feature_toggles/overrides`,
33
- {
34
- method: 'PUT',
35
- headers: { 'content-type': 'application/json' },
36
- body: JSON.stringify({
37
- toggleId: input.toggleId,
38
- isOverride: input.isOverride,
39
- overrideValue: input.overrideValue,
40
- }),
41
- },
33
+ const call = await withScopedApiRequestHeaders(
34
+ buildOptimisticLockHeader(overrideData?.updatedAt ?? null),
35
+ () => apiCall<{ ok: boolean }>(
36
+ `/api/feature_toggles/overrides`,
37
+ {
38
+ method: 'PUT',
39
+ headers: { 'content-type': 'application/json' },
40
+ body: JSON.stringify({
41
+ toggleId: input.toggleId,
42
+ isOverride: input.isOverride,
43
+ overrideValue: input.overrideValue,
44
+ }),
45
+ },
46
+ ),
42
47
  )
43
48
  if (!call.ok) {
44
49
  await raiseCrudError(call.response, t('feature_toggles.overrides.error.update', 'Failed to update override'))
45
50
  }
46
51
  return call.result
47
52
  },
53
+ onError: (err: unknown) => {
54
+ // Route an optimistic-lock 409 to the unified conflict bar; other errors
55
+ // already surfaced via raiseCrudError inside mutationFn.
56
+ surfaceRecordConflict(err, t)
57
+ },
48
58
  onSettled: async () => {
49
59
  await queryClient.invalidateQueries({ queryKey: ['feature_toggle_override', toggleId] })
50
60
  await queryClient.invalidateQueries({ queryKey: ['feature_toggle_overrides'] })
@@ -2,7 +2,8 @@
2
2
  import { DataTable } from "@open-mercato/ui/backend/DataTable";
3
3
  import { RowActions } from "@open-mercato/ui/backend/RowActions";
4
4
  import { useT } from "@open-mercato/shared/lib/i18n/context";
5
- import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
5
+ import { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
6
+ import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
6
7
  import { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'
7
8
  import { useQuery, useQueryClient } from '@tanstack/react-query'
8
9
  import type { ColumnDef, SortingState } from '@tanstack/react-table'
@@ -23,6 +24,7 @@ type Row = {
23
24
  description: string
24
25
  category?: string
25
26
  type: FeatureToggleType
27
+ updatedAt?: string | null
26
28
  }
27
29
 
28
30
  type BadgeVariant = 'default' | 'secondary' | 'destructive' | 'outline' | 'muted'
@@ -126,7 +128,10 @@ export function FeatureTogglesTable() {
126
128
 
127
129
  const deleteFeatureToggleMutation = useMutation({
128
130
  mutationFn: async (row: Row) => {
129
- await deleteCrud('feature_toggles/global', row.id)
131
+ await withScopedApiRequestHeaders(
132
+ buildOptimisticLockHeader(row.updatedAt),
133
+ () => deleteCrud('feature_toggles/global', row.id),
134
+ )
130
135
  },
131
136
  onSuccess: async () => {
132
137
  await queryClient.invalidateQueries({ queryKey: ['feature_toggles'] })
@@ -10,6 +10,7 @@ import {
10
10
  SelectValue,
11
11
  } from "@open-mercato/ui/primitives/select";
12
12
  import { useT } from '@open-mercato/shared/lib/i18n/context'
13
+ import { booleanOverrideSelectValue } from "./overrideFormConfig";
13
14
 
14
15
 
15
16
  export function renderDefaultValueCreateComponent(props: CrudCustomFieldRenderProps) {
@@ -22,7 +23,7 @@ export function renderDefaultValueCreateComponent(props: CrudCustomFieldRenderPr
22
23
  <div>
23
24
  <label className="block text-sm font-medium mb-2">{t('feature_toggles.form.fields.defaultValue.boolean.label', 'Default Value (Boolean)')}</label>
24
25
  <Select
25
- value={props.value as string || 'false'}
26
+ value={booleanOverrideSelectValue(props.value)}
26
27
  onValueChange={(value) => props.setValue(value === 'true')}
27
28
  disabled={props.disabled}
28
29
  >
@@ -11,6 +11,15 @@ import {
11
11
  } from "@open-mercato/ui/primitives/select";
12
12
  import { useT } from '@open-mercato/shared/lib/i18n/context'
13
13
 
14
+ /**
15
+ * Normalize a boolean override value (which may be stored as a real boolean or a
16
+ * 'true'/'false' string) to the string the `<Select>` needs. Passing a raw boolean
17
+ * to `Select.value` matched no `<SelectItem>` and rendered blank (#2410).
18
+ */
19
+ export function booleanOverrideSelectValue(value: unknown): 'true' | 'false' {
20
+ return value === true || value === 'true' ? 'true' : 'false'
21
+ }
22
+
14
23
  export function renderOverrideValueComponent(props: CrudCustomFieldRenderProps) {
15
24
  const t = useT()
16
25
  const toggleType = props.values?.toggleType as string;
@@ -30,7 +39,7 @@ export function renderOverrideValueComponent(props: CrudCustomFieldRenderProps)
30
39
  <div>
31
40
  <label className="block text-sm font-medium mb-2">{t('feature_toggles.override.fields.value.boolean.label', 'Override Value (Boolean)')}</label>
32
41
  <Select
33
- value={props.value as string || 'false'}
42
+ value={booleanOverrideSelectValue(props.value)}
34
43
  onValueChange={(value) => props.setValue(value === 'true')}
35
44
  disabled={props.disabled}
36
45
  >
@@ -1,13 +1,20 @@
1
1
  import { z } from 'zod'
2
2
 
3
- export const IDENTIFIER_PATTERN = /^[a-z][a-z0-9_]*$/
3
+ // Namespaced feature-flag identifiers use dots and dashes as separators
4
+ // (e.g. the seeded `customers.interactions.legacy-adapters`), so the validator
5
+ // accepts lowercase letters, digits, `_`, `.`, and `-` after the leading
6
+ // lowercase letter (#2055 QA round-6).
7
+ export const IDENTIFIER_PATTERN = /^[a-z][a-z0-9_.-]*$/
8
+
9
+ export const IDENTIFIER_PATTERN_MESSAGE =
10
+ 'identifier must start with a lowercase letter and contain only lowercase letters, numbers, dots, dashes, and underscores'
4
11
 
5
12
  export const toggleTypeSchema = z.enum(['boolean', 'string', 'number', 'json'])
6
13
 
7
14
  export const toggleCreateSchema = z.object({
8
15
  identifier: z.string().min(1).regex(
9
16
  IDENTIFIER_PATTERN,
10
- 'identifier must start with a lowercase letter and contain only lowercase letters, numbers, and underscores',
17
+ IDENTIFIER_PATTERN_MESSAGE,
11
18
  ),
12
19
  name: z.string().min(1),
13
20
  description: z.string().nullable().optional(),
@@ -42,6 +49,7 @@ export const featureToggleOverrideResponseSchema = z.object({
42
49
  tenantName: z.string(),
43
50
  tenantId: z.string().uuid(),
44
51
  toggleType: toggleTypeSchema,
52
+ updatedAt: z.string().nullable().optional(),
45
53
  })
46
54
 
47
55
  export type FeatureToggleOverrideResponse = z.infer<typeof featureToggleOverrideResponseSchema>
@@ -70,7 +78,7 @@ export const featureToggleSchema = z.object({
70
78
  id: z.string().uuid().optional(),
71
79
  identifier: z.string().min(1).regex(
72
80
  IDENTIFIER_PATTERN,
73
- 'identifier must start with a lowercase letter and contain only lowercase letters, numbers, and underscores',
81
+ IDENTIFIER_PATTERN_MESSAGE,
74
82
  ),
75
83
  name: z.string().min(1),
76
84
  description: z.string().nullable().optional(),
@@ -2,6 +2,8 @@ import { NextResponse } from 'next/server'
2
2
  import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
3
3
  import { runWithCacheTenant } from '@open-mercato/cache'
4
4
  import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
5
+ import { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
6
+ import { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
5
7
  import { InboxSettings } from '../../data/entities'
6
8
  import { updateSettingsSchema } from '../../data/validators'
7
9
  import { resolveRequestContext, handleRouteError } from '../routeHelpers'
@@ -49,6 +51,7 @@ export async function GET(req: Request) {
49
51
  inboxAddress: settings.inboxAddress,
50
52
  isActive: settings.isActive,
51
53
  workingLanguage: settings.workingLanguage,
54
+ updatedAt: settings.updatedAt instanceof Date ? settings.updatedAt.toISOString() : (settings.updatedAt ?? null),
52
55
  } : null,
53
56
  }
54
57
 
@@ -96,6 +99,20 @@ export async function PATCH(req: Request) {
96
99
  return NextResponse.json({ error: 'Settings not found' }, { status: 404 })
97
100
  }
98
101
 
102
+ // Optimistic lock: refuse a stale overwrite when two tabs edit the same inbox
103
+ // settings record. Strictly additive — a no-op without the expected-version header.
104
+ try {
105
+ enforceCommandOptimisticLock({
106
+ resourceKind: 'inbox_ops.settings',
107
+ resourceId: settings.id,
108
+ current: settings.updatedAt ?? null,
109
+ request: req,
110
+ })
111
+ } catch (err) {
112
+ if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })
113
+ throw err
114
+ }
115
+
99
116
  if (parsed.data.workingLanguage !== undefined) {
100
117
  settings.workingLanguage = parsed.data.workingLanguage
101
118
  }
@@ -115,6 +132,7 @@ export async function PATCH(req: Request) {
115
132
  inboxAddress: settings.inboxAddress,
116
133
  isActive: settings.isActive,
117
134
  workingLanguage: settings.workingLanguage,
135
+ updatedAt: settings.updatedAt instanceof Date ? settings.updatedAt.toISOString() : (settings.updatedAt ?? null),
118
136
  },
119
137
  })
120
138
  } catch (err) {
@@ -11,7 +11,9 @@ import {
11
11
  SelectTrigger,
12
12
  SelectValue,
13
13
  } from '@open-mercato/ui/primitives/select'
14
- import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
14
+ import { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
15
+ import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
16
+ import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
15
17
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
16
18
  import { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'
17
19
  import { useT } from '@open-mercato/shared/lib/i18n/context'
@@ -30,7 +32,7 @@ export default function InboxSettingsPage() {
30
32
  value: key,
31
33
  label: t(`inbox_ops.settings.language_${key}` as never, key),
32
34
  }))
33
- const [settings, setSettings] = React.useState<{ inboxAddress?: string; isActive?: boolean; workingLanguage?: string } | null>(null)
35
+ const [settings, setSettings] = React.useState<{ inboxAddress?: string; isActive?: boolean; workingLanguage?: string; updatedAt?: string | null } | null>(null)
34
36
  const [isLoading, setIsLoading] = React.useState(true)
35
37
  const [error, setError] = React.useState<string | null>(null)
36
38
  const [copied, setCopied] = React.useState(false)
@@ -42,7 +44,7 @@ export default function InboxSettingsPage() {
42
44
  setIsLoading(true)
43
45
  setError(null)
44
46
  try {
45
- const result = await apiCall<{ settings: { inboxAddress?: string; isActive?: boolean; workingLanguage?: string } | null }>('/api/inbox_ops/settings')
47
+ const result = await apiCall<{ settings: { inboxAddress?: string; isActive?: boolean; workingLanguage?: string; updatedAt?: string | null } | null }>('/api/inbox_ops/settings')
46
48
  if (!cancelled) {
47
49
  if (result?.ok && result.result?.settings) {
48
50
  setSettings(result.result.settings)
@@ -71,20 +73,23 @@ export default function InboxSettingsPage() {
71
73
  const handleLanguageChange = React.useCallback(async (workingLanguage: string) => {
72
74
  setIsSavingLanguage(true)
73
75
  const result = await runMutation({
74
- operation: () => apiCall<{ ok: boolean; settings: { workingLanguage: string } }>('/api/inbox_ops/settings', {
75
- method: 'PATCH',
76
- body: JSON.stringify({ workingLanguage }),
77
- }),
76
+ operation: () => withScopedApiRequestHeaders(
77
+ buildOptimisticLockHeader(settings?.updatedAt ?? null),
78
+ () => apiCall<{ ok: boolean; settings: { workingLanguage: string; updatedAt?: string | null } }>('/api/inbox_ops/settings', {
79
+ method: 'PATCH',
80
+ body: JSON.stringify({ workingLanguage }),
81
+ }),
82
+ ),
78
83
  context: {},
79
84
  })
80
85
  if (result?.ok && result.result?.ok) {
81
- setSettings((prev) => prev ? { ...prev, workingLanguage: result.result!.settings.workingLanguage } : prev)
86
+ setSettings((prev) => prev ? { ...prev, workingLanguage: result.result!.settings.workingLanguage, updatedAt: result.result!.settings.updatedAt ?? prev.updatedAt } : prev)
82
87
  flash(t('inbox_ops.settings.language_saved', 'Working language updated'), 'success')
83
- } else {
88
+ } else if (!surfaceRecordConflict({ status: result?.status, body: result?.result }, t)) {
84
89
  flash(t('inbox_ops.settings.language_save_failed', 'Failed to update working language'), 'error')
85
90
  }
86
91
  setIsSavingLanguage(false)
87
- }, [t, runMutation])
92
+ }, [t, runMutation, settings?.updatedAt])
88
93
 
89
94
  return (
90
95
  <Page>
@@ -9,7 +9,8 @@ import {
9
9
  SelectTrigger,
10
10
  SelectValue,
11
11
  } from '@open-mercato/ui/primitives/select'
12
- import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
12
+ import { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
13
+ import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
13
14
  import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
14
15
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
15
16
  import { useT } from '@open-mercato/shared/lib/i18n/context'
@@ -461,9 +462,13 @@ export function EditActionDialog({
461
462
 
462
463
  setIsSaving(true)
463
464
  const result = await runMutation({
464
- operation: () => apiCall<{ ok: boolean; error?: string }>(
465
- `/api/inbox_ops/proposals/${action.proposalId}/actions/${action.id}`,
466
- { method: 'PATCH', body: JSON.stringify({ payload: finalPayload }) },
465
+ // TODO(#2373-D): thread updatedAt ActionDetail type lives outside this file's edit scope
466
+ operation: () => withScopedApiRequestHeaders(
467
+ buildOptimisticLockHeader(undefined),
468
+ () => apiCall<{ ok: boolean; error?: string }>(
469
+ `/api/inbox_ops/proposals/${action.proposalId}/actions/${action.id}`,
470
+ { method: 'PATCH', body: JSON.stringify({ payload: finalPayload }) },
471
+ ),
467
472
  ),
468
473
  context: {},
469
474
  })
@@ -16,7 +16,8 @@ import {
16
16
  SelectValue,
17
17
  } from '@open-mercato/ui/primitives/select'
18
18
  import { Spinner } from '@open-mercato/ui/primitives/spinner'
19
- import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
19
+ import { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
20
+ import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
20
21
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
21
22
  import { useT } from '@open-mercato/shared/lib/i18n/context'
22
23
  import type { CredentialFieldType, IntegrationCredentialField } from '@open-mercato/shared/modules/integrations/types'
@@ -146,11 +147,15 @@ export default function BundleConfigPage({ params }: BundleConfigPageProps) {
146
147
  const currentBundleId = resolveCurrentBundleId()
147
148
  if (!currentBundleId) return
148
149
  setIsSavingCreds(true)
149
- const call = await apiCall(`/api/integrations/${encodeURIComponent(currentBundleId)}/credentials`, {
150
- method: 'PUT',
151
- headers: { 'Content-Type': 'application/json' },
152
- body: JSON.stringify({ credentials: credValues }),
153
- }, { fallback: null })
150
+ // TODO(#2373-B): thread updatedAt — integration detail/state response does not expose a record version yet
151
+ const call = await withScopedApiRequestHeaders(
152
+ buildOptimisticLockHeader(undefined),
153
+ () => apiCall(`/api/integrations/${encodeURIComponent(currentBundleId)}/credentials`, {
154
+ method: 'PUT',
155
+ headers: { 'Content-Type': 'application/json' },
156
+ body: JSON.stringify({ credentials: credValues }),
157
+ }, { fallback: null }),
158
+ )
154
159
  if (call.ok) {
155
160
  flash(t('integrations.detail.credentials.saved'), 'success')
156
161
  } else {
@@ -161,11 +166,15 @@ export default function BundleConfigPage({ params }: BundleConfigPageProps) {
161
166
 
162
167
  const handleToggle = React.useCallback(async (integrationId: string, enabled: boolean) => {
163
168
  setTogglingIds((prev) => new Set(prev).add(integrationId))
164
- const call = await apiCall(`/api/integrations/${encodeURIComponent(integrationId)}/state`, {
165
- method: 'PUT',
166
- headers: { 'Content-Type': 'application/json' },
167
- body: JSON.stringify({ isEnabled: enabled }),
168
- }, { fallback: null })
169
+ // TODO(#2373-B): thread updatedAt — integration detail/state response does not expose a record version yet
170
+ const call = await withScopedApiRequestHeaders(
171
+ buildOptimisticLockHeader(undefined),
172
+ () => apiCall(`/api/integrations/${encodeURIComponent(integrationId)}/state`, {
173
+ method: 'PUT',
174
+ headers: { 'Content-Type': 'application/json' },
175
+ body: JSON.stringify({ isEnabled: enabled }),
176
+ }, { fallback: null }),
177
+ )
169
178
  if (call.ok) {
170
179
  setDetail((prev) => {
171
180
  if (!prev) return prev
@@ -7,7 +7,8 @@ import { Button } from '@open-mercato/ui/primitives/button'
7
7
  import { Switch } from '@open-mercato/ui/primitives/switch'
8
8
  import { Input } from '@open-mercato/ui/primitives/input'
9
9
  import { Spinner } from '@open-mercato/ui/primitives/spinner'
10
- import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
10
+ import { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
11
+ import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
11
12
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
12
13
  import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
13
14
  import { useT } from '@open-mercato/shared/lib/i18n/context'
@@ -43,6 +44,7 @@ type IntegrationItem = {
43
44
  hasCredentials: boolean
44
45
  healthStatus: 'healthy' | 'degraded' | 'unhealthy' | 'unconfigured'
45
46
  analytics: IntegrationAnalytics
47
+ updatedAt?: string | null
46
48
  }
47
49
 
48
50
  type BundleItem = {
@@ -198,13 +200,16 @@ export default function IntegrationsMarketplacePage() {
198
200
  setPage(1)
199
201
  }, [debouncedSearch, filterValues, selectedCategory, sortField, sortOrder])
200
202
 
201
- const handleToggle = React.useCallback(async (integrationId: string, enabled: boolean) => {
203
+ const handleToggle = React.useCallback(async (integrationId: string, enabled: boolean, updatedAt?: string | null) => {
202
204
  setTogglingIds((prev) => new Set(prev).add(integrationId))
203
- const call = await apiCall(`/api/integrations/${encodeURIComponent(integrationId)}/state`, {
204
- method: 'PUT',
205
- headers: { 'Content-Type': 'application/json' },
206
- body: JSON.stringify({ isEnabled: enabled }),
207
- }, { fallback: null })
205
+ const call = await withScopedApiRequestHeaders(
206
+ buildOptimisticLockHeader(updatedAt),
207
+ () => apiCall(`/api/integrations/${encodeURIComponent(integrationId)}/state`, {
208
+ method: 'PUT',
209
+ headers: { 'Content-Type': 'application/json' },
210
+ body: JSON.stringify({ isEnabled: enabled }),
211
+ }, { fallback: null }),
212
+ )
208
213
 
209
214
  if (!call.ok) {
210
215
  flash(t('integrations.detail.stateError'), 'error')
@@ -439,7 +444,7 @@ export default function IntegrationsMarketplacePage() {
439
444
  <Switch
440
445
  checked={item.isEnabled}
441
446
  disabled={togglingIds.has(item.id)}
442
- onCheckedChange={(checked) => void handleToggle(item.id, checked)}
447
+ onCheckedChange={(checked) => void handleToggle(item.id, checked, item.updatedAt)}
443
448
  className="shrink-0"
444
449
  />
445
450
  </div>
@@ -526,7 +526,30 @@ const updateDraftCommand: CommandHandler<unknown, { ok: true; id: string }> = {
526
526
  }
527
527
  }
528
528
 
529
- await withAtomicFlush(em, [async () => {
529
+ // Validate the send transition BEFORE the atomic-flush block so a rejected
530
+ // send never mutates or flushes anything (everything checked here is known
531
+ // from the parsed input + the loaded message).
532
+ if (isSending) {
533
+ const finalVisibility = input.visibility ?? message.visibility
534
+ const finalSubject = input.subject ?? message.subject
535
+ const finalBody = input.body ?? message.body
536
+ const finalRecipientCount = input.recipients
537
+ ? input.recipients.length
538
+ : (preloadedRecipients?.length ?? 0)
539
+ if (finalVisibility !== 'public' && finalRecipientCount === 0) {
540
+ throw new Error('at least one recipient is required')
541
+ }
542
+ if (!finalSubject?.trim()) throw new Error('subject is required')
543
+ if (!finalBody?.trim()) throw new Error('body is required')
544
+ }
545
+
546
+ // Phase 1 mutates the managed `message` scalars; the per-phase flush issues
547
+ // those changes before phase 2's interleaved reads run (e.g.
548
+ // `linkAttachmentsToMessage` issues an `em.find`). Under MikroORM v7 a read
549
+ // between a scalar mutation and the terminal flush on the same EntityManager
550
+ // silently drops the pending changeset, so keeping the scalar edits in their
551
+ // own phase guarantees subject/body/etc. are persisted (SPEC-018 Problem 1).
552
+ await withAtomicFlush(em, [() => {
530
553
  if (input.type !== undefined) message.type = input.type
531
554
  if (input.visibility !== undefined) message.visibility = input.visibility
532
555
  if (input.sourceEntityType !== undefined) message.sourceEntityType = input.sourceEntityType
@@ -539,7 +562,7 @@ const updateDraftCommand: CommandHandler<unknown, { ok: true; id: string }> = {
539
562
  if (input.priority !== undefined) message.priority = input.priority
540
563
  if (input.actionData !== undefined) message.actionData = input.actionData
541
564
  if (input.sendViaEmail !== undefined) message.sendViaEmail = input.sendViaEmail
542
-
565
+ }, async () => {
543
566
  if (input.recipients) {
544
567
  await em.nativeDelete(MessageRecipient, { messageId: message.id })
545
568
  for (const recipient of input.recipients) {
@@ -595,19 +618,8 @@ const updateDraftCommand: CommandHandler<unknown, { ok: true; id: string }> = {
595
618
  }
596
619
 
597
620
  if (isSending) {
598
- const finalVisibility = input.visibility ?? message.visibility
599
- const finalSubject = input.subject ?? message.subject
600
- const finalBody = input.body ?? message.body
601
- const finalRecipientCount = input.recipients
602
- ? input.recipients.length
603
- : (preloadedRecipients?.length ?? 0)
604
-
605
- if (finalVisibility !== 'public' && finalRecipientCount === 0) {
606
- throw new Error('at least one recipient is required')
607
- }
608
- if (!finalSubject?.trim()) throw new Error('subject is required')
609
- if (!finalBody?.trim()) throw new Error('body is required')
610
-
621
+ // Send transition was validated before the block; just apply the
622
+ // status mutations here (persisted by this phase's boundary flush).
611
623
  message.isDraft = false
612
624
  message.status = 'sent'
613
625
  message.sentAt = new Date()
@@ -3,6 +3,7 @@ import { z } from 'zod'
3
3
  import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
4
4
  import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
5
5
  import { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'
6
+ import { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
6
7
  import { perspectiveSaveSchema } from '@open-mercato/core/modules/perspectives/data/validators'
7
8
  import {
8
9
  loadPerspectivesState,
@@ -199,12 +200,14 @@ export async function POST(req: Request, ctx: { params: { tableId: string } }) {
199
200
  let saved: Awaited<ReturnType<typeof saveUserPerspective>> | null = null
200
201
  let updatedRolePerspectives: Awaited<ReturnType<typeof saveRolePerspectives>> | null = null
201
202
 
202
- await withAtomicFlush(em, [
203
+ try {
204
+ await withAtomicFlush(em, [
203
205
  async () => {
204
206
  saved = await saveUserPerspective(em, cache, {
205
207
  scope,
206
208
  tableId,
207
209
  input: parsed.data,
210
+ request: req,
208
211
  })
209
212
  },
210
213
  async () => {
@@ -232,7 +235,13 @@ export async function POST(req: Request, ctx: { params: { tableId: string } }) {
232
235
  })
233
236
  }
234
237
  },
235
- ], { transaction: true })
238
+ ], { transaction: true })
239
+ } catch (err) {
240
+ if (isCrudHttpError(err)) {
241
+ return NextResponse.json(err.body, { status: err.status })
242
+ }
243
+ throw err
244
+ }
236
245
 
237
246
  return NextResponse.json({
238
247
  perspective: saved,