@open-mercato/core 0.6.7-develop.6758.1.697eade236 → 0.6.7-develop.6768.1.9d2c4efc43

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 (269) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/api_keys/backend/api-keys/page.js +2 -1
  3. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  4. package/dist/modules/api_keys/extension-points.js +16 -0
  5. package/dist/modules/api_keys/extension-points.js.map +7 -0
  6. package/dist/modules/audit_logs/components/AccessLogsTable.js +2 -1
  7. package/dist/modules/audit_logs/components/AccessLogsTable.js.map +2 -2
  8. package/dist/modules/audit_logs/components/AuditLogsActions.js +2 -1
  9. package/dist/modules/audit_logs/components/AuditLogsActions.js.map +2 -2
  10. package/dist/modules/audit_logs/extension-points.js +14 -0
  11. package/dist/modules/audit_logs/extension-points.js.map +7 -0
  12. package/dist/modules/auth/backend/roles/page.js +2 -1
  13. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  14. package/dist/modules/auth/backend/users/page.js +2 -1
  15. package/dist/modules/auth/backend/users/page.js.map +2 -2
  16. package/dist/modules/auth/extension-points.js +21 -0
  17. package/dist/modules/auth/extension-points.js.map +7 -0
  18. package/dist/modules/auth/frontend/login.js +5 -1
  19. package/dist/modules/auth/frontend/login.js.map +2 -2
  20. package/dist/modules/business_rules/backend/rules/page.js +2 -1
  21. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  22. package/dist/modules/business_rules/events.js +13 -0
  23. package/dist/modules/business_rules/events.js.map +7 -0
  24. package/dist/modules/business_rules/extension-points.js +13 -0
  25. package/dist/modules/business_rules/extension-points.js.map +7 -0
  26. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +2 -1
  27. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  28. package/dist/modules/catalog/backend/catalog/products/create/page.js +2 -1
  29. package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
  30. package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -1
  31. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  32. package/dist/modules/catalog/components/products/ProductsDataTable.js +3 -2
  33. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  34. package/dist/modules/catalog/events.js +1 -0
  35. package/dist/modules/catalog/events.js.map +2 -2
  36. package/dist/modules/catalog/extension-points.js +27 -0
  37. package/dist/modules/catalog/extension-points.js.map +7 -0
  38. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +2 -1
  39. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
  40. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +3 -2
  41. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +2 -2
  42. package/dist/modules/communication_channels/extension-points.js +20 -0
  43. package/dist/modules/communication_channels/extension-points.js.map +7 -0
  44. package/dist/modules/configs/backend/config/system-status/page.js +2 -1
  45. package/dist/modules/configs/backend/config/system-status/page.js.map +2 -2
  46. package/dist/modules/configs/extension-points.js +18 -0
  47. package/dist/modules/configs/extension-points.js.map +7 -0
  48. package/dist/modules/currencies/backend/currencies/page.js +2 -1
  49. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  50. package/dist/modules/currencies/backend/exchange-rates/page.js +2 -1
  51. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  52. package/dist/modules/currencies/extension-points.js +14 -0
  53. package/dist/modules/currencies/extension-points.js.map +7 -0
  54. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +2 -1
  55. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
  56. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +2 -1
  57. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
  58. package/dist/modules/customer_accounts/extension-points.js +14 -0
  59. package/dist/modules/customer_accounts/extension-points.js.map +7 -0
  60. package/dist/modules/customers/api/deals/summary/route.js +9 -115
  61. package/dist/modules/customers/api/deals/summary/route.js.map +2 -2
  62. package/dist/modules/customers/backend/customers/companies/[id]/page.js +2 -1
  63. package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
  64. package/dist/modules/customers/backend/customers/companies/page.js +2 -1
  65. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  66. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +5 -4
  67. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  68. package/dist/modules/customers/backend/customers/deals/[id]/page.js +5 -4
  69. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  70. package/dist/modules/customers/backend/customers/deals/page.js +2 -1
  71. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  72. package/dist/modules/customers/backend/customers/people/[id]/page.js +2 -1
  73. package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
  74. package/dist/modules/customers/backend/customers/people/page.js +2 -1
  75. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  76. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +5 -4
  77. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  78. package/dist/modules/customers/components/CustomerTodosTable.js +2 -1
  79. package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
  80. package/dist/modules/customers/extension-points.js +42 -0
  81. package/dist/modules/customers/extension-points.js.map +7 -0
  82. package/dist/modules/customers/lib/calendar/format.js +8 -4
  83. package/dist/modules/customers/lib/calendar/format.js.map +2 -2
  84. package/dist/modules/customers/lib/dealsSummaryQueries.js +144 -0
  85. package/dist/modules/customers/lib/dealsSummaryQueries.js.map +7 -0
  86. package/dist/modules/data_sync/backend/data-sync/page.js +2 -1
  87. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  88. package/dist/modules/data_sync/extension-points.js +13 -0
  89. package/dist/modules/data_sync/extension-points.js.map +7 -0
  90. package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
  91. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  92. package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
  93. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  94. package/dist/modules/directory/extension-points.js +14 -0
  95. package/dist/modules/directory/extension-points.js.map +7 -0
  96. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +5 -1
  97. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  98. package/dist/modules/entities/components/SystemEntitiesTable.js +2 -1
  99. package/dist/modules/entities/components/SystemEntitiesTable.js.map +2 -2
  100. package/dist/modules/entities/components/UserEntitiesTable.js +2 -1
  101. package/dist/modules/entities/components/UserEntitiesTable.js.map +2 -2
  102. package/dist/modules/entities/extension-points.js +21 -0
  103. package/dist/modules/entities/extension-points.js.map +7 -0
  104. package/dist/modules/integrations/backend/integrations/[id]/page.js +2 -4
  105. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  106. package/dist/modules/integrations/extension-points.js +30 -0
  107. package/dist/modules/integrations/extension-points.js.map +7 -0
  108. package/dist/modules/messages/components/ComposeMessagePageClient.js +2 -1
  109. package/dist/modules/messages/components/ComposeMessagePageClient.js.map +2 -2
  110. package/dist/modules/messages/components/MessageDetailPageClient.js +3 -2
  111. package/dist/modules/messages/components/MessageDetailPageClient.js.map +2 -2
  112. package/dist/modules/messages/components/MessagesInboxPageClient.js +2 -1
  113. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
  114. package/dist/modules/messages/extension-points.js +16 -0
  115. package/dist/modules/messages/extension-points.js.map +7 -0
  116. package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -2
  117. package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
  118. package/dist/modules/payment_gateways/extension-points.js +19 -0
  119. package/dist/modules/payment_gateways/extension-points.js.map +7 -0
  120. package/dist/modules/portal/extension-points.js +32 -0
  121. package/dist/modules/portal/extension-points.js.map +7 -0
  122. package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js +3 -3
  123. package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js.map +2 -2
  124. package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js +3 -3
  125. package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js.map +2 -2
  126. package/dist/modules/portal/frontend/[orgSlug]/portal/page.js +3 -3
  127. package/dist/modules/portal/frontend/[orgSlug]/portal/page.js.map +2 -2
  128. package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js +3 -3
  129. package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js.map +2 -2
  130. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js +3 -3
  131. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js.map +2 -2
  132. package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js +3 -3
  133. package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js.map +2 -2
  134. package/dist/modules/query_index/components/QueryIndexesTable.js +2 -1
  135. package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
  136. package/dist/modules/query_index/events.js +20 -0
  137. package/dist/modules/query_index/events.js.map +7 -0
  138. package/dist/modules/query_index/extension-points.js +13 -0
  139. package/dist/modules/query_index/extension-points.js.map +7 -0
  140. package/dist/modules/resources/backend/resources/resource-types/page.js +2 -1
  141. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  142. package/dist/modules/resources/backend/resources/resources/page.js +2 -1
  143. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  144. package/dist/modules/resources/extension-points.js +14 -0
  145. package/dist/modules/resources/extension-points.js.map +7 -0
  146. package/dist/modules/sales/backend/sales/documents/[id]/page.js +11 -3
  147. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  148. package/dist/modules/sales/components/documents/ItemsSection.js +2 -1
  149. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  150. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +4 -1
  151. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  152. package/dist/modules/sales/events.js +1 -0
  153. package/dist/modules/sales/events.js.map +2 -2
  154. package/dist/modules/sales/extension-points.js +36 -0
  155. package/dist/modules/sales/extension-points.js.map +7 -0
  156. package/dist/modules/wms/components/backend/WmsConfigurationPage.js +5 -4
  157. package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +2 -2
  158. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +4 -3
  159. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
  160. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +3 -2
  161. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +2 -2
  162. package/dist/modules/wms/components/backend/WmsLotDetailPage.js +3 -2
  163. package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +2 -2
  164. package/dist/modules/wms/components/backend/WmsLotsListPage.js +2 -1
  165. package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
  166. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +3 -2
  167. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +2 -2
  168. package/dist/modules/wms/extension-points.js +26 -0
  169. package/dist/modules/wms/extension-points.js.map +7 -0
  170. package/dist/modules/workflows/backend/definitions/page.js +2 -1
  171. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  172. package/dist/modules/workflows/backend/instances/page.js +2 -1
  173. package/dist/modules/workflows/backend/instances/page.js.map +2 -2
  174. package/dist/modules/workflows/backend/tasks/page.js +2 -1
  175. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  176. package/dist/modules/workflows/events.js +1 -0
  177. package/dist/modules/workflows/events.js.map +2 -2
  178. package/dist/modules/workflows/extension-points.js +15 -0
  179. package/dist/modules/workflows/extension-points.js.map +7 -0
  180. package/package.json +7 -7
  181. package/src/modules/api_keys/backend/api-keys/page.tsx +2 -1
  182. package/src/modules/api_keys/extension-points.ts +13 -0
  183. package/src/modules/audit_logs/components/AccessLogsTable.tsx +2 -1
  184. package/src/modules/audit_logs/components/AuditLogsActions.tsx +2 -1
  185. package/src/modules/audit_logs/extension-points.ts +11 -0
  186. package/src/modules/auth/backend/roles/page.tsx +2 -1
  187. package/src/modules/auth/backend/users/page.tsx +2 -1
  188. package/src/modules/auth/extension-points.ts +18 -0
  189. package/src/modules/auth/frontend/login.tsx +5 -1
  190. package/src/modules/business_rules/backend/rules/page.tsx +2 -1
  191. package/src/modules/business_rules/events.ts +10 -0
  192. package/src/modules/business_rules/extension-points.ts +10 -0
  193. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +2 -1
  194. package/src/modules/catalog/backend/catalog/products/create/page.tsx +2 -1
  195. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +2 -1
  196. package/src/modules/catalog/components/products/ProductsDataTable.tsx +3 -2
  197. package/src/modules/catalog/events.ts +1 -0
  198. package/src/modules/catalog/extension-points.ts +24 -0
  199. package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +2 -1
  200. package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +3 -2
  201. package/src/modules/communication_channels/extension-points.ts +17 -0
  202. package/src/modules/configs/backend/config/system-status/page.tsx +2 -1
  203. package/src/modules/configs/extension-points.ts +15 -0
  204. package/src/modules/currencies/backend/currencies/page.tsx +2 -1
  205. package/src/modules/currencies/backend/exchange-rates/page.tsx +2 -1
  206. package/src/modules/currencies/extension-points.ts +11 -0
  207. package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +2 -1
  208. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +2 -1
  209. package/src/modules/customer_accounts/extension-points.ts +11 -0
  210. package/src/modules/customers/api/deals/summary/route.ts +10 -158
  211. package/src/modules/customers/backend/customers/companies/[id]/page.tsx +2 -1
  212. package/src/modules/customers/backend/customers/companies/page.tsx +2 -1
  213. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +5 -4
  214. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +5 -4
  215. package/src/modules/customers/backend/customers/deals/page.tsx +2 -1
  216. package/src/modules/customers/backend/customers/people/[id]/page.tsx +2 -1
  217. package/src/modules/customers/backend/customers/people/page.tsx +2 -1
  218. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +5 -4
  219. package/src/modules/customers/components/CustomerTodosTable.tsx +2 -1
  220. package/src/modules/customers/extension-points.ts +40 -0
  221. package/src/modules/customers/lib/calendar/format.ts +10 -4
  222. package/src/modules/customers/lib/dealsSummaryQueries.ts +211 -0
  223. package/src/modules/data_sync/backend/data-sync/page.tsx +2 -1
  224. package/src/modules/data_sync/extension-points.ts +10 -0
  225. package/src/modules/directory/backend/directory/organizations/page.tsx +2 -1
  226. package/src/modules/directory/backend/directory/tenants/page.tsx +2 -1
  227. package/src/modules/directory/extension-points.ts +11 -0
  228. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +5 -1
  229. package/src/modules/entities/components/SystemEntitiesTable.tsx +2 -1
  230. package/src/modules/entities/components/UserEntitiesTable.tsx +2 -1
  231. package/src/modules/entities/extension-points.ts +18 -0
  232. package/src/modules/integrations/backend/integrations/[id]/page.tsx +2 -2
  233. package/src/modules/integrations/extension-points.ts +27 -0
  234. package/src/modules/messages/components/ComposeMessagePageClient.tsx +2 -1
  235. package/src/modules/messages/components/MessageDetailPageClient.tsx +3 -2
  236. package/src/modules/messages/components/MessagesInboxPageClient.tsx +2 -1
  237. package/src/modules/messages/extension-points.ts +13 -0
  238. package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +3 -2
  239. package/src/modules/payment_gateways/extension-points.ts +16 -0
  240. package/src/modules/portal/extension-points.ts +30 -0
  241. package/src/modules/portal/frontend/[orgSlug]/portal/dashboard/page.tsx +3 -3
  242. package/src/modules/portal/frontend/[orgSlug]/portal/login/page.tsx +3 -3
  243. package/src/modules/portal/frontend/[orgSlug]/portal/page.tsx +3 -3
  244. package/src/modules/portal/frontend/[orgSlug]/portal/profile/page.tsx +3 -3
  245. package/src/modules/portal/frontend/[orgSlug]/portal/reset-password/page.tsx +4 -4
  246. package/src/modules/portal/frontend/[orgSlug]/portal/signup/page.tsx +3 -3
  247. package/src/modules/query_index/components/QueryIndexesTable.tsx +2 -1
  248. package/src/modules/query_index/events.ts +17 -0
  249. package/src/modules/query_index/extension-points.ts +10 -0
  250. package/src/modules/resources/backend/resources/resource-types/page.tsx +2 -1
  251. package/src/modules/resources/backend/resources/resources/page.tsx +2 -1
  252. package/src/modules/resources/extension-points.ts +11 -0
  253. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +11 -3
  254. package/src/modules/sales/components/documents/ItemsSection.tsx +2 -1
  255. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +6 -1
  256. package/src/modules/sales/events.ts +1 -0
  257. package/src/modules/sales/extension-points.ts +33 -0
  258. package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +5 -4
  259. package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +4 -3
  260. package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +3 -2
  261. package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +3 -2
  262. package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -1
  263. package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +3 -2
  264. package/src/modules/wms/extension-points.ts +23 -0
  265. package/src/modules/workflows/backend/definitions/page.tsx +2 -1
  266. package/src/modules/workflows/backend/instances/page.tsx +2 -1
  267. package/src/modules/workflows/backend/tasks/page.tsx +2 -1
  268. package/src/modules/workflows/events.ts +1 -0
  269. package/src/modules/workflows/extension-points.ts +12 -0
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/catalog/extension-points'
4
5
  import Link from 'next/link'
5
6
  import type { ColumnDef, SortingState } from '@tanstack/react-table'
6
7
  import { DataTable, type DataTableExportFormat } from '@open-mercato/ui/backend/DataTable'
@@ -696,7 +697,7 @@ export default function ProductsDataTable({
696
697
  onCustomFieldFilterFieldsetChange={handleCustomFieldsetFilterChange}
697
698
  sorting={sorting}
698
699
  onSortingChange={setSorting}
699
- injectionSpotId="data-table:catalog.products"
700
+ injectionSpotId={extensionPoints.hosts.productsTable.baseSpotId}
700
701
  injectionContext={{
701
702
  search,
702
703
  filters: filterValues,
@@ -721,7 +722,7 @@ export default function ProductsDataTable({
721
722
  }}
722
723
  exporter={exportConfig}
723
724
  isLoading={isLoading}
724
- perspective={{ tableId: 'catalog.products.list' }}
725
+ perspective={{ tableId: extensionPoints.hosts.productsTable.tableId }}
725
726
  stickyActionsColumn
726
727
  rowActions={(row) => (
727
728
  <RowActions
@@ -13,6 +13,7 @@ const events = [
13
13
  { id: 'catalog.product.created', label: 'Product Created', entity: 'product', category: 'crud', clientBroadcast: true },
14
14
  { id: 'catalog.product.updated', label: 'Product Updated', entity: 'product', category: 'crud', clientBroadcast: true },
15
15
  { id: 'catalog.product.deleted', label: 'Product Deleted', entity: 'product', category: 'crud', clientBroadcast: true },
16
+ { id: 'catalog.product.stock_low', label: 'Product Stock Low', entity: 'product', category: 'lifecycle' },
16
17
  { id: 'catalog.product_unit_conversion.created', label: 'Product Unit Conversion Created', entity: 'product_unit_conversion', category: 'crud' },
17
18
  { id: 'catalog.product_unit_conversion.updated', label: 'Product Unit Conversion Updated', entity: 'product_unit_conversion', category: 'crud' },
18
19
  { id: 'catalog.product_unit_conversion.deleted', label: 'Product Unit Conversion Deleted', entity: 'product_unit_conversion', category: 'crud' },
@@ -0,0 +1,24 @@
1
+ import {
2
+ crudFormExtensionHost,
3
+ dataTableExtensionHost,
4
+ defineModuleExtensionPoints,
5
+ } from '@open-mercato/shared/modules/widgets/extension-points'
6
+
7
+ export const extensionPoints = defineModuleExtensionPoints({
8
+ moduleId: 'catalog',
9
+ hosts: {
10
+ productForm: crudFormExtensionHost({
11
+ entityId: 'catalog.product',
12
+ spotId: 'crud-form:catalog.product',
13
+ source: 'backend/catalog/products/[id]/page.tsx',
14
+ }),
15
+ productsTable: dataTableExtensionHost({
16
+ baseSpotId: 'data-table:catalog.products',
17
+ tableId: 'catalog.products.list',
18
+ source: 'components/products/ProductsDataTable.tsx',
19
+ }),
20
+ categoriesTable: dataTableExtensionHost({ tableId: 'catalog.categories.list', source: 'components/categories/CategoriesDataTable.tsx' }),
21
+ },
22
+ })
23
+
24
+ export default extensionPoints
@@ -1,6 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/communication_channels/extension-points'
4
5
  import type { ColumnDef } from '@tanstack/react-table'
5
6
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
6
7
  import { DataTable } from '@open-mercato/ui/backend/DataTable'
@@ -114,7 +115,7 @@ export default function ChannelsListPage() {
114
115
  <PageBody>
115
116
  <DataTable<ChannelRow>
116
117
  title={t('communication_channels.nav.title', 'Communication Channels')}
117
- extensionTableId="communication_channels.channels"
118
+ extensionTableId={extensionPoints.hosts.channelsTable.tableId}
118
119
  columns={columns}
119
120
  data={rows}
120
121
  isLoading={isLoading}
@@ -1,6 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/communication_channels/extension-points'
4
5
  import type { ColumnDef } from '@tanstack/react-table'
5
6
  import { useRouter, useSearchParams } from 'next/navigation'
6
7
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
@@ -469,7 +470,7 @@ export default function ProfileCommunicationChannelsPage() {
469
470
  {/* Provider connect entry points injected by each channel-* package
470
471
  (channel-gmail, channel-imap) via UMES. */}
471
472
  <InjectionSpot
472
- spotId="profile:communication-channels:connect"
473
+ spotId={extensionPoints.hosts.profileConnect.spotId}
473
474
  context={{ reload: () => setReloadKey((k) => k + 1) }}
474
475
  data={{}}
475
476
  />
@@ -489,7 +490,7 @@ export default function ProfileCommunicationChannelsPage() {
489
490
 
490
491
  <DataTable<ChannelRow>
491
492
  title={t('communication_channels.profile.tableTitle', 'Your channels')}
492
- extensionTableId="communication_channels.profile.channels"
493
+ extensionTableId={extensionPoints.hosts.profileChannelsTable.tableId}
493
494
  columns={columns}
494
495
  data={rows}
495
496
  isLoading={isLoading}
@@ -0,0 +1,17 @@
1
+ import { dataTableExtensionHost, defineModuleExtensionPoints, injectionExtensionHost } from '@open-mercato/shared/modules/widgets/extension-points'
2
+
3
+ export const extensionPoints = defineModuleExtensionPoints({
4
+ moduleId: 'communication_channels',
5
+ hosts: {
6
+ channelsTable: dataTableExtensionHost({ tableId: 'communication_channels.channels', source: 'backend/communication_channels/channels/page.tsx' }),
7
+ profileConnect: injectionExtensionHost({
8
+ family: 'generic',
9
+ spotId: 'profile:communication-channels:connect',
10
+ supported: ['render-widget'],
11
+ source: 'backend/profile/communication-channels/page.tsx',
12
+ }),
13
+ profileChannelsTable: dataTableExtensionHost({ tableId: 'communication_channels.profile.channels', source: 'backend/profile/communication-channels/page.tsx' }),
14
+ },
15
+ })
16
+
17
+ export default extensionPoints
@@ -1,5 +1,6 @@
1
1
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
2
2
  import { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'
3
+ import { extensionPoints } from '@open-mercato/core/modules/configs/extension-points'
3
4
  import SystemStatusPanel from '../../../components/SystemStatusPanel'
4
5
 
5
6
  export default function SystemStatusPage() {
@@ -8,7 +9,7 @@ export default function SystemStatusPage() {
8
9
  <PageBody>
9
10
  <SystemStatusPanel />
10
11
  <InjectionSpot
11
- spotId="configs.system_status:details"
12
+ spotId={extensionPoints.hosts.systemStatusDetails.spotId}
12
13
  context={{ path: '/backend/config/system-status' }}
13
14
  />
14
15
  </PageBody>
@@ -0,0 +1,15 @@
1
+ import { defineModuleExtensionPoints, injectionExtensionHost } from '@open-mercato/shared/modules/widgets/extension-points'
2
+
3
+ export const extensionPoints = defineModuleExtensionPoints({
4
+ moduleId: 'configs',
5
+ hosts: {
6
+ systemStatusDetails: injectionExtensionHost({
7
+ family: 'detail',
8
+ spotId: 'configs.system_status:details',
9
+ supported: ['render-widget'],
10
+ source: 'backend/config/system-status/page.tsx',
11
+ }),
12
+ },
13
+ })
14
+
15
+ export default extensionPoints
@@ -1,6 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/currencies/extension-points'
4
5
  import Link from 'next/link'
5
6
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
6
7
  import { DataTable } from '@open-mercato/ui/backend/DataTable'
@@ -343,7 +344,7 @@ export default function CurrenciesPage() {
343
344
  )}
344
345
  pagination={{ page, pageSize: 50, total, totalPages, onPageChange: setPage }}
345
346
  isLoading={isLoading}
346
- perspective={{ tableId: 'currencies.list' }}
347
+ perspective={{ tableId: extensionPoints.hosts.currenciesTable.tableId }}
347
348
  />
348
349
  </PageBody>
349
350
  {ConfirmDialogElement}
@@ -1,6 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/currencies/extension-points'
4
5
  import Link from 'next/link'
5
6
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
6
7
  import { DataTable } from '@open-mercato/ui/backend/DataTable'
@@ -333,7 +334,7 @@ export default function ExchangeRatesPage() {
333
334
  )}
334
335
  pagination={{ page, pageSize: 50, total, totalPages, onPageChange: setPage }}
335
336
  isLoading={isLoading}
336
- perspective={{ tableId: 'exchange-rates.list' }}
337
+ perspective={{ tableId: extensionPoints.hosts.exchangeRatesTable.tableId }}
337
338
  />
338
339
  </PageBody>
339
340
  {ConfirmDialogElement}
@@ -0,0 +1,11 @@
1
+ import { dataTableExtensionHost, defineModuleExtensionPoints } from '@open-mercato/shared/modules/widgets/extension-points'
2
+
3
+ export const extensionPoints = defineModuleExtensionPoints({
4
+ moduleId: 'currencies',
5
+ hosts: {
6
+ currenciesTable: dataTableExtensionHost({ tableId: 'currencies.list', source: 'backend/currencies/page.tsx' }),
7
+ exchangeRatesTable: dataTableExtensionHost({ tableId: 'exchange-rates.list', source: 'backend/exchange-rates/page.tsx' }),
8
+ },
9
+ })
10
+
11
+ export default extensionPoints
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/customer_accounts/extension-points'
4
5
  import Link from 'next/link'
5
6
  import { useRouter } from 'next/navigation'
6
7
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
@@ -213,7 +214,7 @@ export default function CustomerRolesPage() {
213
214
  searchValue={search}
214
215
  onSearchChange={(value) => { setSearch(value); setPage(1) }}
215
216
  searchPlaceholder={t('customer_accounts.admin.roles.searchPlaceholder', 'Search roles...')}
216
- perspective={{ tableId: 'customer_accounts.admin.roles' }}
217
+ perspective={{ tableId: extensionPoints.hosts.rolesTable.tableId }}
217
218
  emptyState={(
218
219
  <ListEmptyState
219
220
  entityName={t('customer_accounts.admin.roles.title', 'Customer Roles')}
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/customer_accounts/extension-points'
4
5
  import Link from 'next/link'
5
6
  import { useRouter } from 'next/navigation'
6
7
  import { Globe, Settings } from 'lucide-react'
@@ -545,7 +546,7 @@ export default function CustomerAccountsPage() {
545
546
  filterValues={filterValues}
546
547
  onFiltersApply={handleFiltersApply}
547
548
  onFiltersClear={handleFiltersClear}
548
- perspective={{ tableId: 'customer_accounts.admin.users' }}
549
+ perspective={{ tableId: extensionPoints.hosts.usersTable.tableId }}
549
550
  emptyState={(
550
551
  <ListEmptyState
551
552
  entityName={t('customer_accounts.admin.title', 'Users')}
@@ -0,0 +1,11 @@
1
+ import { dataTableExtensionHost, defineModuleExtensionPoints } from '@open-mercato/shared/modules/widgets/extension-points'
2
+
3
+ export const extensionPoints = defineModuleExtensionPoints({
4
+ moduleId: 'customer_accounts',
5
+ hosts: {
6
+ usersTable: dataTableExtensionHost({ tableId: 'customer_accounts.admin.users', source: 'backend/customer_accounts/users/page.tsx' }),
7
+ rolesTable: dataTableExtensionHost({ tableId: 'customer_accounts.admin.roles', source: 'backend/customer_accounts/roles/page.tsx' }),
8
+ },
9
+ })
10
+
11
+ export default extensionPoints
@@ -1,15 +1,14 @@
1
1
  import { NextResponse } from 'next/server'
2
2
  import { z } from 'zod'
3
3
  import type { EntityManager as CoreEntityManager } from '@mikro-orm/core'
4
- import type { EntityManager as PgEntityManager } from '@mikro-orm/postgresql'
5
4
  import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
6
5
  import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
7
6
  import { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'
8
7
  import type { ExchangeRateService, RateResult } from '@open-mercato/core/modules/currencies/services/exchangeRateService'
9
8
  import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
10
- import { fetchStuckDealIds } from '../../../lib/stuckDeals'
11
9
  import { resolveDealsOrganizationIds } from '../../../lib/dealsOrganizationScope'
12
10
  import { resolveOptionalBaseCurrencyCode } from '../../../lib/optionalBaseCurrency'
11
+ import { loadDealsSummaryQueryRows } from '../../../lib/dealsSummaryQueries'
13
12
  import {
14
13
  computeDelta,
15
14
  convertSumsToBase,
@@ -27,7 +26,6 @@ export const metadata = {
27
26
  GET: { requireAuth: true, requireFeatures: ['customers.deals.view'] },
28
27
  }
29
28
 
30
- const OPEN_STATUSES = ['open', 'in_progress'] as const
31
29
  const TRAILING_MONTHS = 6
32
30
  const TOP_OWNERS = 5
33
31
 
@@ -108,40 +106,6 @@ export const openApi: OpenApiRouteDoc = {
108
106
  },
109
107
  }
110
108
 
111
- type OpenPipelineRow = {
112
- stage: string | null
113
- currency: string | null
114
- total: string | number | null
115
- count: string | number
116
- owner_user_id: string | null
117
- }
118
-
119
- type WindowSumRow = {
120
- currency: string | null
121
- current_total: string | number | null
122
- current_count: string | number
123
- previous_total: string | number | null
124
- previous_count: string | number
125
- }
126
-
127
- type WinLossRow = {
128
- current_won: string | number
129
- current_lost: string | number
130
- previous_won: string | number
131
- previous_lost: string | number
132
- }
133
-
134
- type WinRateMonthRow = {
135
- period: string
136
- won: string | number
137
- lost: string | number
138
- }
139
-
140
- type OwnerCountRow = {
141
- owner_user_id: string | null
142
- count: string | number
143
- }
144
-
145
109
  function toNumber(value: string | number | null | undefined): number {
146
110
  const parsed = Number(value ?? 0)
147
111
  return Number.isFinite(parsed) ? parsed : 0
@@ -185,133 +149,21 @@ export async function GET(req: Request) {
185
149
  const trailingMonths = getTrailingMonths(today, TRAILING_MONTHS)
186
150
  const seriesStart = trailingMonths[0]?.start ?? currentQuarter.start
187
151
 
188
- const connection = em.getConnection()
189
-
190
152
  const baseCurrencyCode = await resolveOptionalBaseCurrencyCode(
191
153
  container,
192
154
  effectiveTenantId,
193
155
  orgFilterIds[0],
194
156
  )
195
157
 
196
- const orgPlaceholders = orgFilterIds.map(() => '?').join(',')
197
- const scopeWhere = `tenant_id = ? AND organization_id IN (${orgPlaceholders}) AND deleted_at IS NULL`
198
- const scopeValues: Array<string | number | null> = [effectiveTenantId, ...orgFilterIds]
199
- const openPlaceholders = OPEN_STATUSES.map(() => '?').join(',')
200
-
201
- // 1) Open pipeline: per (stage, currency) sums + open-deal owner per row, so we can
202
- // derive pipeline value (per stage + converted total) and the open owner set in one pass.
203
- const openRows: OpenPipelineRow[] = await connection.execute<OpenPipelineRow[]>(
204
- `SELECT
205
- pipeline_stage AS stage,
206
- UPPER(COALESCE(value_currency, '')) AS currency,
207
- COALESCE(SUM(value_amount), 0) AS total,
208
- COUNT(*) AS count,
209
- owner_user_id
210
- FROM customer_deals
211
- WHERE ${scopeWhere} AND status IN (${openPlaceholders})
212
- GROUP BY pipeline_stage, UPPER(COALESCE(value_currency, '')), owner_user_id`,
213
- [...scopeValues, ...OPEN_STATUSES],
214
- )
215
-
216
- // 2) Open-deal value created in the current vs previous quarter (pipeline inflow delta).
217
- const inflowRows: WindowSumRow[] = await connection.execute<WindowSumRow[]>(
218
- `SELECT
219
- UPPER(COALESCE(value_currency, '')) AS currency,
220
- COALESCE(SUM(value_amount) FILTER (WHERE created_at >= ? AND created_at < ?), 0) AS current_total,
221
- COUNT(*) FILTER (WHERE created_at >= ? AND created_at < ?) AS current_count,
222
- COALESCE(SUM(value_amount) FILTER (WHERE created_at >= ? AND created_at < ?), 0) AS previous_total,
223
- COUNT(*) FILTER (WHERE created_at >= ? AND created_at < ?) AS previous_count
224
- FROM customer_deals
225
- WHERE ${scopeWhere} AND status IN (${openPlaceholders})
226
- GROUP BY UPPER(COALESCE(value_currency, ''))`,
227
- [
228
- currentQuarter.start.toISOString(), currentQuarter.end.toISOString(),
229
- currentQuarter.start.toISOString(), currentQuarter.end.toISOString(),
230
- previousQuarter.start.toISOString(), previousQuarter.end.toISOString(),
231
- previousQuarter.start.toISOString(), previousQuarter.end.toISOString(),
232
- ...scopeValues, ...OPEN_STATUSES,
233
- ],
234
- )
235
-
236
- // 3) Won value per currency for the current vs previous quarter (updated_at in window).
237
- const wonRows: WindowSumRow[] = await connection.execute<WindowSumRow[]>(
238
- `SELECT
239
- UPPER(COALESCE(value_currency, '')) AS currency,
240
- COALESCE(SUM(value_amount) FILTER (WHERE updated_at >= ? AND updated_at < ?), 0) AS current_total,
241
- COUNT(*) FILTER (WHERE updated_at >= ? AND updated_at < ?) AS current_count,
242
- COALESCE(SUM(value_amount) FILTER (WHERE updated_at >= ? AND updated_at < ?), 0) AS previous_total,
243
- COUNT(*) FILTER (WHERE updated_at >= ? AND updated_at < ?) AS previous_count
244
- FROM customer_deals
245
- WHERE ${scopeWhere} AND (status = 'win' OR closure_outcome = 'won')
246
- GROUP BY UPPER(COALESCE(value_currency, ''))`,
247
- [
248
- currentQuarter.start.toISOString(), currentQuarter.end.toISOString(),
249
- currentQuarter.start.toISOString(), currentQuarter.end.toISOString(),
250
- previousQuarter.start.toISOString(), previousQuarter.end.toISOString(),
251
- previousQuarter.start.toISOString(), previousQuarter.end.toISOString(),
252
- ...scopeValues,
253
- ],
254
- )
255
-
256
- // 4) Win/lost counts for the current vs previous quarter (win rate + delta-pp).
257
- const winLossRows: WinLossRow[] = await connection.execute<WinLossRow[]>(
258
- `SELECT
259
- COUNT(*) FILTER (WHERE (status = 'win' OR closure_outcome = 'won') AND updated_at >= ? AND updated_at < ?) AS current_won,
260
- COUNT(*) FILTER (WHERE (status = 'loose' OR closure_outcome = 'lost') AND updated_at >= ? AND updated_at < ?) AS current_lost,
261
- COUNT(*) FILTER (WHERE (status = 'win' OR closure_outcome = 'won') AND updated_at >= ? AND updated_at < ?) AS previous_won,
262
- COUNT(*) FILTER (WHERE (status = 'loose' OR closure_outcome = 'lost') AND updated_at >= ? AND updated_at < ?) AS previous_lost
263
- FROM customer_deals
264
- WHERE ${scopeWhere}`,
265
- [
266
- currentQuarter.start.toISOString(), currentQuarter.end.toISOString(),
267
- currentQuarter.start.toISOString(), currentQuarter.end.toISOString(),
268
- previousQuarter.start.toISOString(), previousQuarter.end.toISOString(),
269
- previousQuarter.start.toISOString(), previousQuarter.end.toISOString(),
270
- ...scopeValues,
271
- ],
272
- )
273
-
274
- // 5) Win-rate series over the trailing months (won/lost grouped by updated_at month).
275
- const seriesRows: WinRateMonthRow[] = await connection.execute<WinRateMonthRow[]>(
276
- `SELECT
277
- to_char(date_trunc('month', updated_at AT TIME ZONE 'UTC'), 'YYYY-MM') AS period,
278
- COUNT(*) FILTER (WHERE status = 'win' OR closure_outcome = 'won') AS won,
279
- COUNT(*) FILTER (WHERE status = 'loose' OR closure_outcome = 'lost') AS lost
280
- FROM customer_deals
281
- WHERE ${scopeWhere} AND updated_at >= ?
282
- GROUP BY 1`,
283
- [...scopeValues, seriesStart.toISOString()],
284
- )
285
-
286
- // Overdue open deals (id set) + stuck deals (id set) → union count for "need attention".
287
- const overdueRows: Array<{ id: string }> = await connection.execute<Array<{ id: string }>>(
288
- `SELECT id FROM customer_deals
289
- WHERE ${scopeWhere} AND status = 'open' AND expected_close_at IS NOT NULL AND expected_close_at < CURRENT_DATE`,
290
- [...scopeValues],
291
- )
292
- // `fetchStuckDealIds` is single-org; run it for every org in scope so multi-org callers don't
293
- // undercount stuck deals (the aggregates above already span every org in `orgFilterIds`).
294
- const stuckIdLists = await Promise.all(
295
- orgFilterIds.map((orgId) =>
296
- fetchStuckDealIds(em as unknown as PgEntityManager, orgId, effectiveTenantId)),
297
- )
298
- const stuckIdSet = new Set<string>()
299
- for (const list of stuckIdLists) for (const id of list) stuckIdSet.add(id)
300
-
301
- // The stuck-deal query does not filter status, so a stuck id can be a won/lost/closed deal.
302
- // "Need attention" is an active-deal metric — intersect with the open (OPEN_STATUSES) set so
303
- // terminal deals never inflate the count.
304
- let openStuckIds: string[] = []
305
- if (stuckIdSet.size > 0) {
306
- const stuckIdValues = Array.from(stuckIdSet)
307
- const stuckPlaceholders = stuckIdValues.map(() => '?').join(',')
308
- const openStuckRows: Array<{ id: string }> = await connection.execute<Array<{ id: string }>>(
309
- `SELECT id FROM customer_deals
310
- WHERE ${scopeWhere} AND status IN (${openPlaceholders}) AND id IN (${stuckPlaceholders})`,
311
- [...scopeValues, ...OPEN_STATUSES, ...stuckIdValues],
312
- )
313
- openStuckIds = openStuckRows.map((row) => row.id)
314
- }
158
+ const { openRows, inflowRows, wonRows, winLossRows, seriesRows, overdueRows, openStuckIds } =
159
+ await loadDealsSummaryQueryRows({
160
+ em,
161
+ tenantId: effectiveTenantId,
162
+ organizationIds: orgFilterIds,
163
+ currentQuarter,
164
+ previousQuarter,
165
+ seriesStart,
166
+ })
315
167
 
316
168
  const attentionIds = new Set<string>()
317
169
  for (const row of overdueRows) attentionIds.add(row.id)
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'
4
5
  import Link from 'next/link'
5
6
  import { useRouter, useSearchParams } from 'next/navigation'
6
7
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
@@ -967,7 +968,7 @@ export default function CustomerCompanyDetailPage({ params }: { params?: { id?:
967
968
  <h2 className="text-sm font-semibold">{t('customers.companies.detail.sections.details', 'Company details')}</h2>
968
969
  <DetailFieldsSection fields={detailFields} />
969
970
  <InjectionSpot
970
- spotId="customers.company.detail:details"
971
+ spotId={extensionPoints.hosts.companyLegacyDetails.spotId}
971
972
  context={injectionContext}
972
973
  data={data}
973
974
  onDataChange={(next) => setData(next as CompanyOverview)}
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'
4
5
  import Link from 'next/link'
5
6
  import { usePathname, useRouter, useSearchParams } from 'next/navigation'
6
7
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
@@ -888,7 +889,7 @@ export default function CustomersCompaniesPage() {
888
889
  searchPlaceholder={t('customers.companies.list.searchPlaceholder')}
889
890
  entityIds={[E.customers.customer_entity, E.customers.customer_company_profile]}
890
891
  onRowClick={(row) => router.push(`/backend/customers/companies-v2/${row.id}`)}
891
- perspective={{ tableId: 'customers.companies.list' }}
892
+ perspective={{ tableId: extensionPoints.hosts.companiesTable.tableId }}
892
893
  sortable
893
894
  manualSorting
894
895
  sorting={sorting}
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'
4
5
  import Link from 'next/link'
5
6
  import { useRouter, useSearchParams, usePathname } from 'next/navigation'
6
7
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
@@ -471,8 +472,8 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
471
472
  <PageBody>
472
473
  <div className="space-y-4">
473
474
  {/* UMES header injection */}
474
- <InjectionSpot spotId="detail:customers.company:header" context={injectionContext} data={data} />
475
- <InjectionSpot spotId="detail:customers.company:status-badges" context={injectionContext} data={data} />
475
+ <InjectionSpot spotId={extensionPoints.hosts.companyHeader.spotId} context={injectionContext} data={data} />
476
+ <InjectionSpot spotId={extensionPoints.hosts.companyStatusBadges.spotId} context={injectionContext} data={data} />
476
477
 
477
478
  {/* Persistent company header */}
478
479
  <CompanyDetailHeader
@@ -500,7 +501,7 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
500
501
  <CrudForm<CompanyEditFormValues>
501
502
  embedded
502
503
  trackDirtyWhenEmbedded
503
- injectionSpotId="crud-form:customers.company"
504
+ injectionSpotId={extensionPoints.hosts.companyForm.spotId}
504
505
  entityIds={[E.customers.customer_entity, E.customers.customer_company_profile]}
505
506
  schema={formSchema}
506
507
  fields={formFields}
@@ -606,7 +607,7 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
606
607
  />
607
608
 
608
609
  {/* UMES footer injection */}
609
- <InjectionSpot spotId="detail:customers.company:footer" context={injectionContext} data={data} />
610
+ <InjectionSpot spotId={extensionPoints.hosts.companyFooter.spotId} context={injectionContext} data={data} />
610
611
 
611
612
  {/* Schedule Activity Dialog */}
612
613
  <ScheduleActivityDialog
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'
4
5
  import Link from 'next/link'
5
6
  import { Building2, UserSearch, Users } from 'lucide-react'
6
7
  import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
@@ -383,7 +384,7 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
383
384
  showAssociationsGroup={false}
384
385
  showVersionHistory={false}
385
386
  showCancelAction={false}
386
- injectionSpotId="crud-form:customers.deal"
387
+ injectionSpotId={extensionPoints.hosts.dealForm.spotId}
387
388
  optimisticLockUpdatedAt={data.deal.updatedAt}
388
389
  onDirtyChange={setIsDirty}
389
390
  initialPipelineOptions={formPipelineOptions}
@@ -610,7 +611,7 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
610
611
  <Page>
611
612
  <PageBody>
612
613
  <div className="space-y-6">
613
- <InjectionSpot spotId="detail:customers.deal:header" context={injectionContext} data={data} />
614
+ <InjectionSpot spotId={extensionPoints.hosts.dealHeader.spotId} context={injectionContext} data={data} />
614
615
 
615
616
  <DealDetailHeader
616
617
  deal={data.deal}
@@ -628,7 +629,7 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
628
629
  isSaving={isSaving}
629
630
  />
630
631
 
631
- <InjectionSpot spotId="detail:customers.deal:status-badges" context={injectionContext} data={data} />
632
+ <InjectionSpot spotId={extensionPoints.hosts.dealStatusBadges.spotId} context={injectionContext} data={data} />
632
633
 
633
634
  <PipelineStepper
634
635
  stages={data.pipelineStages}
@@ -663,7 +664,7 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
663
664
  />
664
665
  </DealDetailTabs>
665
666
 
666
- <InjectionSpot spotId="detail:customers.deal:footer" context={injectionContext} data={data} />
667
+ <InjectionSpot spotId={extensionPoints.hosts.dealFooter.spotId} context={injectionContext} data={data} />
667
668
  </div>
668
669
 
669
670
  {ConfirmDialogElement}
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'
4
5
  import Link from 'next/link'
5
6
  import { usePathname, useRouter, useSearchParams } from 'next/navigation'
6
7
  import { useQueryClient } from '@tanstack/react-query'
@@ -1146,7 +1147,7 @@ export default function CustomersDealsPage() {
1146
1147
  }}
1147
1148
  exporter={exportConfig}
1148
1149
  entityId={E.customers.customer_deal}
1149
- perspective={{ tableId: 'customers.deals.list' }}
1150
+ perspective={{ tableId: extensionPoints.hosts.dealsTable.tableId }}
1150
1151
  advancedFilter={{
1151
1152
  auto: true,
1152
1153
  value: filterPanel.tree,
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'
4
5
  import Link from 'next/link'
5
6
  import { useRouter, useSearchParams } from 'next/navigation'
6
7
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
@@ -922,7 +923,7 @@ export default function CustomerPersonDetailPage({ params }: { params?: { id?: s
922
923
  <h2 className="text-sm font-semibold">{t('customers.people.detail.sections.details')}</h2>
923
924
  <DetailFieldsSection fields={detailFields} />
924
925
  <InjectionSpot
925
- spotId="customers.person.detail:details"
926
+ spotId={extensionPoints.hosts.personLegacyDetails.spotId}
926
927
  context={injectionContext}
927
928
  data={data}
928
929
  onDataChange={(next) => setData(next as PersonOverview)}
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
+ import { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'
4
5
  import Link from 'next/link'
5
6
  import { usePathname, useRouter, useSearchParams } from 'next/navigation'
6
7
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
@@ -914,7 +915,7 @@ export default function CustomersPeoplePage() {
914
915
  onSearchChange={(value) => { setSearch(value); setPage(1) }}
915
916
  searchPlaceholder={t('customers.people.list.searchPlaceholder')}
916
917
  entityIds={[E.customers.customer_entity, E.customers.customer_person_profile]}
917
- perspective={{ tableId: 'customers.people.list' }}
918
+ perspective={{ tableId: extensionPoints.hosts.peopleTable.tableId }}
918
919
  onRowClick={(row) => router.push(`/backend/customers/people-v2/${row.id}`)}
919
920
  sortable
920
921
  manualSorting