@open-mercato/cli 0.6.7 → 0.6.8-canary.320.1.bf889f49e4

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 (335) hide show
  1. package/.turbo/turbo-build.log +77 -4
  2. package/AGENTS.md +6 -1
  3. package/build.mjs +68 -11
  4. package/dist/agentic/claude-code/hooks/entity-migration-check.ts +32 -88
  5. package/dist/agentic/codex/enforcement-rules.md +2 -16
  6. package/dist/agentic/cursor/hooks/entity-migration-check.mjs +19 -50
  7. package/dist/agentic/cursor/rules/entity-guard.mdc +9 -21
  8. package/dist/agentic/cursor/rules/generated-guard.mdc +3 -5
  9. package/dist/agentic/cursor/rules/open-mercato.mdc +3 -29
  10. package/dist/agentic/guides/ai-workflows.md +76 -0
  11. package/dist/agentic/guides/architecture.md +107 -0
  12. package/dist/agentic/guides/backend-ui.md +86 -0
  13. package/dist/agentic/guides/contracts.md +92 -0
  14. package/dist/agentic/guides/extensions.md +121 -0
  15. package/dist/agentic/guides/framework-extension-points.md +36 -0
  16. package/dist/agentic/guides/integrations.md +81 -0
  17. package/dist/agentic/guides/module-facts.json +116757 -3951
  18. package/dist/agentic/guides/module-system.md +12 -127
  19. package/dist/agentic/guides/modules/ai_assistant.md +227 -28
  20. package/dist/agentic/guides/modules/api_docs.md +58 -2
  21. package/dist/agentic/guides/modules/api_keys.md +92 -7
  22. package/dist/agentic/guides/modules/attachments.md +119 -14
  23. package/dist/agentic/guides/modules/audit_logs.md +131 -10
  24. package/dist/agentic/guides/modules/auth.md +276 -33
  25. package/dist/agentic/guides/modules/business_rules.md +149 -14
  26. package/dist/agentic/guides/modules/catalog.md +482 -43
  27. package/dist/agentic/guides/modules/channel_gmail.md +82 -3
  28. package/dist/agentic/guides/modules/channel_imap.md +82 -3
  29. package/dist/agentic/guides/modules/checkout.md +305 -27
  30. package/dist/agentic/guides/modules/communication_channels.md +315 -33
  31. package/dist/agentic/guides/modules/configs.md +104 -8
  32. package/dist/agentic/guides/modules/content.md +57 -2
  33. package/dist/agentic/guides/modules/currencies.md +152 -17
  34. package/dist/agentic/guides/modules/customer_accounts.md +387 -45
  35. package/dist/agentic/guides/modules/customers.md +746 -85
  36. package/dist/agentic/guides/modules/dashboards.md +155 -10
  37. package/dist/agentic/guides/modules/data_sync.md +149 -16
  38. package/dist/agentic/guides/modules/design_system.md +102 -0
  39. package/dist/agentic/guides/modules/dictionaries.md +107 -12
  40. package/dist/agentic/guides/modules/directory.md +148 -15
  41. package/dist/agentic/guides/modules/entities.md +145 -13
  42. package/dist/agentic/guides/modules/events.md +59 -2
  43. package/dist/agentic/guides/modules/feature_toggles.md +119 -9
  44. package/dist/agentic/guides/modules/gateway_stripe.md +92 -4
  45. package/dist/agentic/guides/modules/generators.md +45 -2
  46. package/dist/agentic/guides/modules/inbox_ops.md +207 -27
  47. package/dist/agentic/guides/modules/integrations.md +149 -16
  48. package/dist/agentic/guides/modules/messages.md +223 -24
  49. package/dist/agentic/guides/modules/notifications.md +96 -8
  50. package/dist/agentic/guides/modules/onboarding.md +77 -6
  51. package/dist/agentic/guides/modules/payment_gateways.md +168 -21
  52. package/dist/agentic/guides/modules/perspectives.md +77 -7
  53. package/dist/agentic/guides/modules/planner.md +136 -18
  54. package/dist/agentic/guides/modules/portal.md +93 -2
  55. package/dist/agentic/guides/modules/progress.md +104 -14
  56. package/dist/agentic/guides/modules/query_index.md +154 -15
  57. package/dist/agentic/guides/modules/record_locks.md +206 -21
  58. package/dist/agentic/guides/modules/resources.md +197 -30
  59. package/dist/agentic/guides/modules/sales.md +687 -84
  60. package/dist/agentic/guides/modules/scheduler.md +133 -14
  61. package/dist/agentic/guides/modules/search.md +170 -6
  62. package/dist/agentic/guides/modules/security.md +294 -35
  63. package/dist/agentic/guides/modules/shipping_carriers.md +134 -18
  64. package/dist/agentic/guides/modules/sso.md +151 -26
  65. package/dist/agentic/guides/modules/staff.md +372 -57
  66. package/dist/agentic/guides/modules/storage_s3.md +95 -5
  67. package/dist/agentic/guides/modules/sync_akeneo.md +85 -3
  68. package/dist/agentic/guides/modules/sync_excel.md +75 -6
  69. package/dist/agentic/guides/modules/system_status_overlays.md +60 -2
  70. package/dist/agentic/guides/modules/translations.md +104 -10
  71. package/dist/agentic/guides/modules/webhooks.md +203 -24
  72. package/dist/agentic/guides/modules/wms.md +469 -47
  73. package/dist/agentic/guides/modules/workflows.md +302 -43
  74. package/dist/agentic/guides/reference-module-facts.json +6942 -0
  75. package/dist/agentic/guides/reference-modules/example.md +462 -0
  76. package/dist/agentic/guides/spec-delivery.md +56 -0
  77. package/dist/agentic/guides/testing-debugging.md +80 -0
  78. package/dist/agentic/guides/upstream/AGENTS.md +300 -0
  79. package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +334 -0
  80. package/dist/agentic/guides/upstream/manifest.json +8 -0
  81. package/dist/agentic/shared/AGENTS.md.template +120 -311
  82. package/dist/agentic/shared/ai/agentic.config.json +2 -0
  83. package/dist/agentic/shared/ai/harness/README.md +50 -0
  84. package/dist/agentic/shared/ai/harness/RELEASE.md +59 -0
  85. package/dist/agentic/shared/ai/harness/cases.json +20596 -0
  86. package/dist/agentic/shared/ai/harness/cases.schema.json +196 -0
  87. package/dist/agentic/shared/ai/harness/design-system-inventory.json +6326 -0
  88. package/dist/agentic/shared/ai/harness/fixtures/index.json +51 -0
  89. package/dist/agentic/shared/ai/harness/fixtures/seeds.json +166 -0
  90. package/dist/agentic/shared/ai/harness/generated-code-review-policy.md +21 -0
  91. package/dist/agentic/shared/ai/harness/generated-code-review-response.schema.json +96 -0
  92. package/dist/agentic/shared/ai/harness/generated-code-review-result.schema.json +172 -0
  93. package/dist/agentic/shared/ai/harness/knowledge-change.schema.json +228 -0
  94. package/dist/agentic/shared/ai/harness/release-matrix.json +163 -0
  95. package/dist/agentic/shared/ai/harness/release-result.schema.json +219 -0
  96. package/dist/agentic/shared/ai/harness/result.schema.json +136 -0
  97. package/dist/agentic/shared/ai/harness/routing-response.schema.json +22 -0
  98. package/dist/agentic/shared/ai/harness/source-link-inventory.json +1706 -0
  99. package/dist/agentic/shared/ai/harness/target-validation-result.schema.json +73 -0
  100. package/dist/agentic/shared/ai/harness/validators.json +82 -0
  101. package/dist/agentic/shared/ai/harness/writable-ast-oracles.mjs +2121 -0
  102. package/dist/agentic/shared/ai/harness/writable-behavior-oracles.mjs +1096 -0
  103. package/dist/agentic/shared/ai/harness/writable-spec-oracles.mjs +602 -0
  104. package/dist/agentic/shared/ai/lessons/_template.md +16 -0
  105. package/dist/agentic/shared/ai/lessons.md +26 -3
  106. package/dist/agentic/shared/ai/review-checklist.md +36 -0
  107. package/dist/agentic/shared/ai/skills/om-auto-implement-spec/SKILL.md +21 -0
  108. package/dist/agentic/shared/ai/skills/om-auto-review-pr/SKILL.md +4 -0
  109. package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.6.6-to-0.6.7/SKILL.md +98 -0
  110. package/dist/agentic/shared/ai/skills/om-backend-ui-design/SKILL.md +21 -241
  111. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/crud-surfaces.md +31 -0
  112. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/frontend-and-design-system.md +53 -0
  113. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/page-and-navigation.md +15 -0
  114. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/quality-states.md +11 -0
  115. package/dist/agentic/shared/ai/skills/om-build-workflow/SKILL.md +30 -0
  116. package/dist/agentic/shared/ai/skills/om-build-workflow/references/activity-contracts.md +12 -0
  117. package/dist/agentic/shared/ai/skills/om-build-workflow/references/durability-and-progress.md +13 -0
  118. package/dist/agentic/shared/ai/skills/om-build-workflow/references/workflow-design.md +14 -0
  119. package/dist/agentic/shared/ai/skills/om-create-ai-agent/SKILL.md +28 -0
  120. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/attachments-and-overrides.md +12 -0
  121. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/module-agents-and-tools.md +22 -0
  122. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/orchestrator-agents.md +12 -0
  123. package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/surface-selector.md +19 -0
  124. package/dist/agentic/shared/ai/skills/om-data-model-design/SKILL.md +17 -601
  125. package/dist/agentic/shared/ai/skills/om-data-model-design/references/integrity-and-concurrency.md +21 -0
  126. package/dist/agentic/shared/ai/skills/om-data-model-design/references/migration-workflow.md +15 -0
  127. package/dist/agentic/shared/ai/skills/om-data-model-design/references/schema-design.md +16 -0
  128. package/dist/agentic/shared/ai/skills/om-data-model-design/references/sensitive-data.md +10 -0
  129. package/dist/agentic/shared/ai/skills/om-eject-and-customize/SKILL.md +15 -310
  130. package/dist/agentic/shared/ai/skills/om-eject-and-customize/references/decision-and-procedure.md +19 -0
  131. package/dist/agentic/shared/ai/skills/om-evolve-harness/SKILL.md +31 -0
  132. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-template.md +100 -0
  133. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-workflow.md +16 -0
  134. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/knowledge-change.md +133 -0
  135. package/dist/agentic/shared/ai/skills/om-evolve-harness/references/owner-selection.md +17 -0
  136. package/dist/agentic/shared/ai/skills/om-framework-context/SKILL.md +25 -0
  137. package/dist/agentic/shared/ai/skills/om-framework-context/references/resolver-procedure.md +11 -0
  138. package/dist/agentic/shared/ai/skills/om-framework-context/references/skew-and-escalation.md +13 -0
  139. package/dist/agentic/shared/ai/skills/om-help/SKILL.md +15 -97
  140. package/dist/agentic/shared/ai/skills/om-help/references/delivery-workflows.md +18 -0
  141. package/dist/agentic/shared/ai/skills/om-help/references/task-families.md +20 -0
  142. package/dist/agentic/shared/ai/skills/om-implement-spec/SKILL.md +33 -152
  143. package/dist/agentic/shared/ai/skills/om-implement-spec/references/phases-and-gates.md +33 -0
  144. package/dist/agentic/shared/ai/skills/om-implement-spec/references/planning-and-progress.md +40 -0
  145. package/dist/agentic/shared/ai/skills/om-implement-spec/references/report-templates.md +27 -0
  146. package/dist/agentic/shared/ai/skills/om-implement-spec/references/spec-resolution.md +24 -0
  147. package/dist/agentic/shared/ai/skills/om-integration-builder/SKILL.md +25 -708
  148. package/dist/agentic/shared/ai/skills/om-integration-builder/references/package-and-activation.md +16 -0
  149. package/dist/agentic/shared/ai/skills/om-integration-builder/references/provider-families.md +25 -0
  150. package/dist/agentic/shared/ai/skills/om-integration-builder/references/security-and-reliability.md +15 -0
  151. package/dist/agentic/shared/ai/skills/om-integration-builder/references/sync-and-files.md +12 -0
  152. package/dist/agentic/shared/ai/skills/om-judge-agent-session/SKILL.md +34 -0
  153. package/dist/agentic/shared/ai/skills/om-judge-agent-session/agents/openai.yaml +4 -0
  154. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/agentic-setup.md +11 -0
  155. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/input-normalization.md +31 -0
  156. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/judge-workflow.md +39 -0
  157. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/report-template.md +43 -0
  158. package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/rules.md +11 -0
  159. package/dist/agentic/shared/ai/skills/om-module-scaffold/SKILL.md +20 -820
  160. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/api-and-domain.md +32 -0
  161. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/business-one-shot-blueprints.md +172 -0
  162. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/data-and-migrations.md +14 -0
  163. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/discovery-surface-catalog.md +83 -0
  164. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/module-surfaces.md +40 -0
  165. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/planning.md +11 -0
  166. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/runtime-cache-and-queues.md +22 -0
  167. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/verification.md +13 -0
  168. package/dist/agentic/shared/ai/skills/om-share-this-session/SKILL.md +41 -0
  169. package/dist/agentic/shared/ai/skills/om-share-this-session/references/agentic-setup.md +19 -0
  170. package/dist/agentic/shared/ai/skills/om-share-this-session/references/bundle-preparation.md +44 -0
  171. package/dist/agentic/shared/ai/skills/om-share-this-session/references/consent-and-review.md +39 -0
  172. package/dist/agentic/shared/ai/skills/om-share-this-session/references/publication.md +20 -0
  173. package/dist/agentic/shared/ai/skills/om-share-this-session/references/report-templates.md +57 -0
  174. package/dist/agentic/shared/ai/skills/om-share-this-session/references/rules.md +11 -0
  175. package/dist/agentic/shared/ai/skills/om-share-this-session/scripts/prepare-share-bundle.mjs +486 -0
  176. package/dist/agentic/shared/ai/skills/om-system-extension/SKILL.md +20 -843
  177. package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-branches.md +42 -0
  178. package/dist/agentic/shared/ai/skills/om-system-extension/references/mechanism-selector.md +27 -0
  179. package/dist/agentic/shared/ai/skills/om-system-extension/references/read-write-roundtrip.md +13 -0
  180. package/dist/agentic/shared/ai/skills/om-system-extension/references/unified-overrides.md +43 -0
  181. package/dist/agentic/shared/ai/skills/om-system-extension/references/verification.md +11 -0
  182. package/dist/agentic/shared/ai/skills/om-trim-unused-modules/SKILL.md +15 -63
  183. package/dist/agentic/shared/ai/skills/om-trim-unused-modules/references/dependency-and-redirect.md +15 -0
  184. package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +17 -467
  185. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnosis-map.md +29 -0
  186. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/regression-oracles.md +14 -0
  187. package/dist/agentic/shared/ai/skills/tiers.json +143 -21
  188. package/dist/agentic/shared/ai/skills/tiers.schema.json +52 -40
  189. package/dist/agentic/shared/ai/specs/2026-08-06-reference-module-activation.md +248 -0
  190. package/dist/agentic/shared/ai/specs/README.md +4 -3
  191. package/dist/agentic/shared/ai/specs/SPEC-000-template.md +226 -10
  192. package/dist/agentic/shared/ai/trackers/github.md +108 -4
  193. package/dist/agentic/shared/scripts/agent-harness-tool-server.mjs +224 -0
  194. package/dist/agentic/shared/scripts/check-lessons.mjs +178 -0
  195. package/dist/agentic/shared/scripts/evaluate-agent-harness.mjs +3812 -0
  196. package/dist/agentic/shared/scripts/execution-sandbox.mjs +329 -0
  197. package/dist/agentic/shared/scripts/framework-context.mjs +888 -0
  198. package/dist/agentic/shared/scripts/install-skills.mjs +1029 -0
  199. package/dist/agentic/shared/scripts/install-skills.sh +4 -694
  200. package/dist/agentic/shared/scripts/prepare-agent-harness-fixture.mjs +222 -0
  201. package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +1774 -0
  202. package/dist/agentic/shared/scripts/validate-knowledge-change.mjs +1172 -0
  203. package/dist/bin.js +32 -34
  204. package/dist/bin.js.map +2 -2
  205. package/dist/lib/__integration__/TC-INT-008.spec.js +88 -8
  206. package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
  207. package/dist/lib/agentic-init.js +13 -3
  208. package/dist/lib/agentic-init.js.map +2 -2
  209. package/dist/lib/agentic-setup.js +434 -186
  210. package/dist/lib/agentic-setup.js.map +2 -2
  211. package/dist/lib/cli-bootstrap-mode.js +32 -0
  212. package/dist/lib/cli-bootstrap-mode.js.map +7 -0
  213. package/dist/lib/dev-supervisor-manifest.js +105 -0
  214. package/dist/lib/dev-supervisor-manifest.js.map +7 -0
  215. package/dist/lib/generate-watch-events.js +15 -0
  216. package/dist/lib/generate-watch-events.js.map +2 -2
  217. package/dist/lib/generators/entity-ids.js +11 -24
  218. package/dist/lib/generators/entity-ids.js.map +2 -2
  219. package/dist/lib/generators/extensions/injection-widgets.js +20 -0
  220. package/dist/lib/generators/extensions/injection-widgets.js.map +2 -2
  221. package/dist/lib/generators/module-di.js +10 -23
  222. package/dist/lib/generators/module-di.js.map +2 -2
  223. package/dist/lib/generators/module-entities.js +10 -23
  224. package/dist/lib/generators/module-entities.js.map +2 -2
  225. package/dist/lib/generators/module-extension-facts.js +1882 -0
  226. package/dist/lib/generators/module-extension-facts.js.map +7 -0
  227. package/dist/lib/generators/module-fact-sources.js +70 -0
  228. package/dist/lib/generators/module-fact-sources.js.map +7 -0
  229. package/dist/lib/generators/module-facts-discovery.js +64 -7
  230. package/dist/lib/generators/module-facts-discovery.js.map +2 -2
  231. package/dist/lib/generators/module-facts.js +1913 -52
  232. package/dist/lib/generators/module-facts.js.map +3 -3
  233. package/dist/lib/generators/module-override-targets.js +712 -0
  234. package/dist/lib/generators/module-override-targets.js.map +7 -0
  235. package/dist/lib/generators/module-registry.js +405 -36
  236. package/dist/lib/generators/module-registry.js.map +2 -2
  237. package/dist/lib/generators/route-manifest-shards.js +170 -0
  238. package/dist/lib/generators/route-manifest-shards.js.map +7 -0
  239. package/dist/lib/in-process-generate-watcher.js +12 -3
  240. package/dist/lib/in-process-generate-watcher.js.map +2 -2
  241. package/dist/lib/load-env.js +24 -0
  242. package/dist/lib/load-env.js.map +7 -0
  243. package/dist/lib/queue-worker-supervisor.js.map +2 -2
  244. package/dist/lib/resolver.js +28 -3
  245. package/dist/lib/resolver.js.map +2 -2
  246. package/dist/lib/telemetry-init.js +358 -0
  247. package/dist/lib/telemetry-init.js.map +7 -0
  248. package/dist/lib/testing/integration.js +5 -2
  249. package/dist/lib/testing/integration.js.map +2 -2
  250. package/dist/lib/utils.js +15 -8
  251. package/dist/lib/utils.js.map +2 -2
  252. package/dist/mercato.js +35 -9
  253. package/dist/mercato.js.map +2 -2
  254. package/package.json +13 -11
  255. package/src/__tests__/mercato.test.ts +144 -0
  256. package/src/bin.ts +60 -42
  257. package/src/lib/__integration__/TC-INT-008.spec.ts +107 -9
  258. package/src/lib/__tests__/agentic-init.test.ts +41 -5
  259. package/src/lib/__tests__/agentic-setup.ownership.test.ts +386 -0
  260. package/src/lib/__tests__/cli-bootstrap-mode.test.ts +22 -0
  261. package/src/lib/__tests__/content-stable-writes.test.ts +74 -0
  262. package/src/lib/__tests__/dev-supervisor-manifest.test.ts +131 -0
  263. package/src/lib/__tests__/generate-watch-events.test.ts +76 -0
  264. package/src/lib/__tests__/in-process-generate-watcher.test.ts +52 -1
  265. package/src/lib/__tests__/injection-widget-id-validation.test.ts +184 -0
  266. package/src/lib/__tests__/load-env.test.ts +65 -0
  267. package/src/lib/__tests__/queue-worker-supervisor.test.ts +33 -0
  268. package/src/lib/__tests__/resolver.enterprise.test.ts +50 -0
  269. package/src/lib/__tests__/telemetry-init.test.ts +298 -0
  270. package/src/lib/agentic-init.ts +15 -3
  271. package/src/lib/agentic-setup.ts +573 -222
  272. package/src/lib/cli-bootstrap-mode.ts +31 -0
  273. package/src/lib/dev-supervisor-manifest.ts +142 -0
  274. package/src/lib/generate-watch-events.ts +14 -0
  275. package/src/lib/generators/__tests__/activation-adapter-coverage.test.ts +92 -0
  276. package/src/lib/generators/__tests__/entity-ids.test.ts +32 -0
  277. package/src/lib/generators/__tests__/helpers/override-target-diagnostic-fixtures.ts +150 -0
  278. package/src/lib/generators/__tests__/module-extension-activations.test.ts +762 -0
  279. package/src/lib/generators/__tests__/module-extension-facts.test.ts +603 -0
  280. package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +139 -2
  281. package/src/lib/generators/__tests__/module-facts.computed-di-token.test.ts +88 -0
  282. package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +1 -0
  283. package/src/lib/generators/__tests__/module-facts.discovery.test.ts +54 -10
  284. package/src/lib/generators/__tests__/module-facts.example-fact-coverage.test.ts +414 -0
  285. package/src/lib/generators/__tests__/module-facts.extension-hosts.test.ts +108 -0
  286. package/src/lib/generators/__tests__/module-facts.local-reference.test.ts +393 -0
  287. package/src/lib/generators/__tests__/module-facts.owned-contracts.test.ts +561 -0
  288. package/src/lib/generators/__tests__/module-facts.search-entity-id.test.ts +151 -0
  289. package/src/lib/generators/__tests__/module-facts.source-links.test.ts +160 -0
  290. package/src/lib/generators/__tests__/module-override-targets.diagnostic-wiring.test.ts +92 -0
  291. package/src/lib/generators/__tests__/module-override-targets.roundtrip.test.ts +149 -0
  292. package/src/lib/generators/__tests__/module-override-targets.test.ts +328 -0
  293. package/src/lib/generators/__tests__/module-override-targets.unknown-mode.test.ts +117 -0
  294. package/src/lib/generators/__tests__/module-subset.test.ts +266 -0
  295. package/src/lib/generators/__tests__/output-snapshots.test.ts +3 -3
  296. package/src/lib/generators/__tests__/route-manifest-shards.test.ts +62 -0
  297. package/src/lib/generators/entity-ids.ts +10 -26
  298. package/src/lib/generators/extensions/injection-widgets.ts +51 -0
  299. package/src/lib/generators/module-di.ts +9 -25
  300. package/src/lib/generators/module-entities.ts +9 -25
  301. package/src/lib/generators/module-extension-facts.ts +2472 -0
  302. package/src/lib/generators/module-fact-sources.ts +108 -0
  303. package/src/lib/generators/module-facts-discovery.ts +104 -7
  304. package/src/lib/generators/module-facts.ts +2747 -138
  305. package/src/lib/generators/module-override-targets.ts +907 -0
  306. package/src/lib/generators/module-registry.ts +448 -35
  307. package/src/lib/generators/route-manifest-shards.ts +146 -0
  308. package/src/lib/in-process-generate-watcher.ts +13 -4
  309. package/src/lib/load-env.ts +30 -0
  310. package/src/lib/queue-worker-supervisor.ts +7 -2
  311. package/src/lib/resolver.ts +34 -3
  312. package/src/lib/telemetry-init.ts +461 -0
  313. package/src/lib/testing/__tests__/integration.test.ts +4 -0
  314. package/src/lib/testing/integration.ts +5 -2
  315. package/src/lib/utils.ts +24 -16
  316. package/src/mercato.ts +46 -9
  317. package/dist/agentic/guides/cache.md +0 -45
  318. package/dist/agentic/guides/core.md +0 -453
  319. package/dist/agentic/guides/events.md +0 -117
  320. package/dist/agentic/guides/queue.md +0 -53
  321. package/dist/agentic/guides/search.md +0 -115
  322. package/dist/agentic/guides/shared.md +0 -108
  323. package/dist/agentic/guides/ui.md +0 -347
  324. package/dist/agentic/shared/ai/skills/om-auto-continue-pr-loop/SKILL.md +0 -27
  325. package/dist/agentic/shared/ai/skills/om-auto-create-pr-loop/SKILL.md +0 -27
  326. package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/ui-components.md +0 -260
  327. package/dist/agentic/shared/ai/skills/om-data-model-design/references/mikro-orm-cheatsheet.md +0 -146
  328. package/dist/agentic/shared/ai/skills/om-help/references/skills-catalog.md +0 -84
  329. package/dist/agentic/shared/ai/skills/om-help/references/workflow-sequences.md +0 -193
  330. package/dist/agentic/shared/ai/skills/om-integration-builder/STANDALONE.md +0 -34
  331. package/dist/agentic/shared/ai/skills/om-integration-builder/references/adapter-contracts.md +0 -762
  332. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/naming-conventions.md +0 -50
  333. package/dist/agentic/shared/ai/skills/om-module-scaffold/references/navigation-patterns.md +0 -97
  334. package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-contracts.md +0 -271
  335. package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnostic-commands.md +0 -101
package/src/mercato.ts CHANGED
@@ -43,6 +43,7 @@ import { acquireServerStartLock } from './lib/server-start-lock'
43
43
  import { assertSingleInstanceStrategies } from './lib/single-instance-strategy-guard'
44
44
  import { createDevEnvReloader, watchDevEnvFiles } from './lib/dev-env-reload'
45
45
  import { quotePostgresIdentifier } from './lib/db/identifiers'
46
+ import { getRegisteredDevSupervisorManifest } from './lib/dev-supervisor-manifest'
46
47
  // Lazy-imported to avoid pulling in `testcontainers` (devDependency) at startup
47
48
  const lazyIntegration = () => import('./lib/testing/integration')
48
49
  import type { ChildProcess } from 'node:child_process'
@@ -793,7 +794,7 @@ async function runGeneratorSuiteWithStructuralInvalidation(quiet: boolean): Prom
793
794
  * watchers. Filesystem events mark the tree dirty; the existing full content
794
795
  * checksum remains the final authority and the fallback when watching fails.
795
796
  */
796
- async function createGenerateWatchRuntime() {
797
+ async function createGenerateWatchRuntime(quiet = false) {
797
798
  const [
798
799
  { createResolver },
799
800
  { calculateGenerateWatchStructureChecksum },
@@ -824,6 +825,9 @@ async function createGenerateWatchRuntime() {
824
825
  return calculateGenerateWatchStructureChecksum(collectWatchState())
825
826
  },
826
827
  changeSignal: createGenerateWatchChangeSignal({
828
+ onSkippedDirectory: quiet
829
+ ? undefined
830
+ : (directory) => console.log(`[generate:watch] Skipping missing watch directory: ${directory}`),
827
831
  getWatchTargets: () => {
828
832
  const state = collectWatchState()
829
833
  const targets: Array<{ directory: string; recursive: boolean; fileName?: string }> = [{
@@ -867,7 +871,10 @@ async function buildAllModules(): Promise<Module[]> {
867
871
  export async function run(argv = process.argv) {
868
872
  const [, , ...parts] = argv
869
873
  const [first, second, ...remaining] = parts
870
- await ensureEnvLoaded({ createIfMissing: first !== 'deploy', quiet: first === 'deploy' })
874
+ await ensureEnvLoaded({
875
+ createIfMissing: first !== 'deploy' && first !== 'telemetry',
876
+ quiet: first === 'deploy' || first === 'telemetry',
877
+ })
871
878
 
872
879
  // Handle init command directly
873
880
  if (first === 'init') {
@@ -1332,6 +1339,20 @@ export async function run(argv = process.argv) {
1332
1339
  return exitCode
1333
1340
  }
1334
1341
 
1342
+ // Handle telemetry command (bootstrap-free) — wires @open-mercato/telemetry
1343
+ // into an app scaffolded before telemetry existed.
1344
+ if (first === 'telemetry') {
1345
+ if (second === 'init') {
1346
+ const { runTelemetryInit } = await import('./lib/telemetry-init')
1347
+ return runTelemetryInit(remaining.filter(Boolean))
1348
+ }
1349
+ console.log('Usage: yarn mercato telemetry init [--dry-run]')
1350
+ console.log(' Wires @open-mercato/telemetry into this app (package.json, .env,')
1351
+ console.log(' instrumentation.ts, next.config.ts, and the API dispatcher).')
1352
+ console.log(' Idempotent and safe to re-run. Use --dry-run to preview changes.')
1353
+ return second && second !== 'help' && second !== '--help' && second !== '-h' ? 1 : 0
1354
+ }
1355
+
1335
1356
  if (first === 'module') {
1336
1357
  try {
1337
1358
  const subcommand = second
@@ -1654,6 +1675,8 @@ export async function run(argv = process.argv) {
1654
1675
  effectiveByQueue.get(queue) ??
1655
1676
  concurrencyOverride ??
1656
1677
  Math.max(...queueWorkers.map((w) => w.concurrency), 1)
1678
+ const maxStalledCount = Math.max(...queueWorkers.map((w) => w.maxStalledCount ?? 1), 1)
1679
+ const lockDuration = Math.max(...queueWorkers.map((w) => w.lockDuration ?? 0), 0) || undefined
1657
1680
 
1658
1681
  console.log(`[worker] Starting "${queue}" with ${queueWorkers.length} handler(s), concurrency: ${concurrency}`)
1659
1682
 
@@ -1662,6 +1685,8 @@ export async function run(argv = process.argv) {
1662
1685
  queueName: queue,
1663
1686
  connection: queueRedisUrl ? { url: queueRedisUrl } : undefined,
1664
1687
  concurrency,
1688
+ lockDuration,
1689
+ maxStalledCount,
1665
1690
  background: true,
1666
1691
  handler: createPerJobWorkerHandler(queueWorkers, createRequestContainer),
1667
1692
  })
@@ -1705,6 +1730,8 @@ export async function run(argv = process.argv) {
1705
1730
  // never check out more pooled connections than the worker pool holds.
1706
1731
  const budgetPlan = await resolveWorkerBudgetPlan([{ queue: queueName!, concurrency: requested }])
1707
1732
  const concurrency = budgetPlan.entries[0]?.effective ?? requested
1733
+ const maxStalledCount = Math.max(...queueWorkers.map((w) => w.maxStalledCount ?? 1), 1)
1734
+ const lockDuration = Math.max(...queueWorkers.map((w) => w.lockDuration ?? 0), 0) || undefined
1708
1735
 
1709
1736
  console.log(`[worker] Found ${queueWorkers.length} worker(s) for queue "${queueName}"`)
1710
1737
 
@@ -1713,6 +1740,8 @@ export async function run(argv = process.argv) {
1713
1740
  queueName: queueName!,
1714
1741
  connection: queueRedisUrl ? { url: queueRedisUrl } : undefined,
1715
1742
  concurrency,
1743
+ lockDuration,
1744
+ maxStalledCount,
1716
1745
  handler: createPerJobWorkerHandler(queueWorkers, createRequestContainer),
1717
1746
  })
1718
1747
  } else {
@@ -1838,7 +1867,7 @@ export async function run(argv = process.argv) {
1838
1867
  const parsedInterval = intervalArg ? Number.parseInt(intervalArg.split('=')[1] ?? '', 10) : NaN
1839
1868
  const intervalMs = Number.isFinite(parsedInterval) && parsedInterval >= 250 ? parsedInterval : 1000
1840
1869
 
1841
- const generateWatchRuntime = await createGenerateWatchRuntime()
1870
+ const generateWatchRuntime = await createGenerateWatchRuntime(quiet)
1842
1871
  const watcher = startInProcessGenerateWatcher({
1843
1872
  pollMs: intervalMs,
1844
1873
  skipInitial,
@@ -1974,6 +2003,10 @@ export async function run(argv = process.argv) {
1974
2003
  let lastRestartReason: string | null = null
1975
2004
  const generateWatcherMode: GenerateWatcherMode = resolveGenerateWatcherMode(process.env)
1976
2005
  const envReloader = createDevEnvReloader(appDir, process.env, initialProcessEnvironmentEntries)
2006
+ // The CLI binary registers this primitive manifest before dispatching
2007
+ // `server dev`. Direct `run()` callers keep the existing module-registry
2008
+ // fallback for backward compatibility and focused unit tests.
2009
+ const devSupervisorManifest = getRegisteredDevSupervisorManifest()
1977
2010
 
1978
2011
  function cleanup() {
1979
2012
  console.log('[server] Shutting down...')
@@ -2182,14 +2215,15 @@ export async function run(argv = process.argv) {
2182
2215
  applyEventsSingleDeliveryGuard({ processEnv: process.env, runtimeEnv, autoSpawnWorkersMode })
2183
2216
  const autoSpawnSchedulerMode = resolveAutoSpawnSchedulerMode(process.env)
2184
2217
  const queueStrategy = process.env.QUEUE_STRATEGY || 'local'
2185
- const schedulerCommand = lookupModuleCommand(getCliModules(), 'scheduler', 'start')
2218
+ const schedulerStartStatus = devSupervisorManifest?.schedulerStartStatus
2219
+ ?? lookupModuleCommand(getCliModules(), 'scheduler', 'start').status
2186
2220
  const embedSchedulerInSharedWorker =
2187
2221
  shouldEmbedLocalSchedulerInSharedWorker(process.env)
2188
2222
  && queueStrategy === 'local'
2189
2223
  && autoSpawnWorkersMode === 'lazy'
2190
2224
  && resolveLazySpawnMode(process.env) === 'shared'
2191
2225
  && autoSpawnSchedulerMode !== 'off'
2192
- && schedulerCommand.status === 'ok'
2226
+ && schedulerStartStatus === 'ok'
2193
2227
  const nextRuntime = startNextDev(runtimeEnv)
2194
2228
  const restartPromise = waitForDevRestart()
2195
2229
  const backgroundStartAbort = new AbortController()
@@ -2223,10 +2257,13 @@ export async function run(argv = process.argv) {
2223
2257
  }
2224
2258
 
2225
2259
  if (autoSpawnWorkersMode !== 'off') {
2226
- const discoveredWorkers = getRegisteredCliWorkers()
2260
+ const discoveredWorkers = devSupervisorManifest?.workers ?? getRegisteredCliWorkers()
2227
2261
  const discoveredWorkerQueues = [...new Set(discoveredWorkers.map((worker) => worker.queue))]
2228
2262
  if (discoveredWorkerQueues.length === 0) {
2229
- console.error('[server] AUTO_SPAWN_WORKERS is enabled, but no queues were discovered from CLI modules. Run `yarn generate` and verify `.mercato/generated/modules.cli.generated.ts` contains worker entries. Continuing without auto-spawned workers.')
2263
+ const workerRegistryFile = devSupervisorManifest
2264
+ ? 'dev-supervisor.generated.json'
2265
+ : 'modules.cli.generated.ts'
2266
+ console.error(`[server] AUTO_SPAWN_WORKERS is enabled, but no queues were discovered from CLI modules. Run \`yarn generate\` and verify \`.mercato/generated/${workerRegistryFile}\` contains worker entries. Continuing without auto-spawned workers.`)
2230
2267
  } else if (autoSpawnWorkersMode === 'lazy') {
2231
2268
  const lazySpawnMode = resolveLazySpawnMode(process.env)
2232
2269
  const lazyModeHint = lazySpawnMode === 'shared'
@@ -2274,8 +2311,8 @@ export async function run(argv = process.argv) {
2274
2311
  if (embedSchedulerInSharedWorker && activeLazySupervisor) {
2275
2312
  console.log('[server] Local scheduler will run inside the lazy shared worker process.')
2276
2313
  } else if (autoSpawnSchedulerMode !== 'off' && queueStrategy === 'local') {
2277
- if (schedulerCommand.status !== 'ok') {
2278
- console.log(`[server] Skipping scheduler auto-start — ${describeMissingModuleCommand(schedulerCommand)}`)
2314
+ if (schedulerStartStatus !== 'ok') {
2315
+ console.log(`[server] Skipping scheduler auto-start — ${describeMissingModuleCommand({ status: schedulerStartStatus })}`)
2279
2316
  } else if (autoSpawnSchedulerMode === 'lazy') {
2280
2317
  console.log('[server] Lazy scheduler auto-spawn enabled - scheduler will start when an enabled schedule exists.')
2281
2318
  activeLazySchedulerSupervisor = startLazySchedulerSupervisor({
@@ -1,45 +0,0 @@
1
- # Cache Package — Standalone Developer Guide
2
-
3
- `@open-mercato/cache` provides tenant-scoped caching with tag-based invalidation. MUST NOT use raw Redis, SQLite, or in-memory caching directly.
4
-
5
- ## Strategy Selection
6
-
7
- | Strategy | When | Config |
8
- |----------|------|--------|
9
- | Memory | Development, single-process | Default (no config) |
10
- | SQLite | Single-server production | `CACHE_STRATEGY=sqlite` |
11
- | Redis | Multi-server, shared cache | `CACHE_STRATEGY=redis` |
12
-
13
- ## Usage
14
-
15
- Always resolve via DI:
16
-
17
- ```typescript
18
- const cacheService = container.resolve('cacheService')
19
-
20
- // Set with tags for targeted invalidation
21
- await cacheService.set(`${tenantId}:my_module:stats`, value, {
22
- tags: [`tenant:${tenantId}`, 'my_module'],
23
- })
24
-
25
- // Get
26
- const cached = await cacheService.get(`${tenantId}:my_module:stats`)
27
-
28
- // Invalidate by tag (clears all entries with that tag)
29
- await cacheService.invalidateTag('my_module')
30
- ```
31
-
32
- ## MUST Rules
33
-
34
- 1. **MUST resolve via DI** — `container.resolve('cacheService')`, never instantiate directly
35
- 2. **MUST scope to tenant** — include `tenantId` in cache keys
36
- 3. **MUST use tag-based invalidation** for CRUD side effects
37
- 4. **MUST NOT cache sensitive data** without encryption
38
-
39
- ## Adding Cache to a Module
40
-
41
- 1. Resolve `cacheService` from DI in your service or route handler
42
- 2. Define cache keys: `${tenantId}:${module}:${identifier}`
43
- 3. Tag entries: `{ tags: ['tenant:123', 'my_module'] }`
44
- 4. Add cache invalidation to CRUD side effects (`emitCrudSideEffects` with `cacheAliases`)
45
- 5. Test with `CACHE_STRATEGY=memory` (default in dev)
@@ -1,453 +0,0 @@
1
- # Core Package — Standalone Developer Guide
2
-
3
- `@open-mercato/core` contains all built-in business modules. This guide covers module development patterns for standalone apps that build on top of these modules.
4
-
5
- ## Module anatomy, auto-discovery & convention files
6
-
7
- > Moved to the conceptual guide. See **`.ai/guides/module-system.md` → Module anatomy** for the auto-discovery path table and the convention-file reference — they are framework-wide, not core-specific. The sections below cover `@open-mercato/core`-specific development patterns.
8
-
9
- ## API Routes
10
-
11
- Every API route file MUST export an `openApi` object:
12
-
13
- ```typescript
14
- import { createCrudOpenApiFactory } from '@open-mercato/shared/lib/openapi/crud'
15
- const buildOpenApi = createCrudOpenApiFactory({ defaultTag: 'MyModule' })
16
-
17
- export const openApi = buildOpenApi({
18
- resourceName: 'Item',
19
- querySchema: listQuerySchema,
20
- listResponseSchema: createPagedListResponseSchema(itemSchema),
21
- create: { schema: createSchema, description: 'Create item' },
22
- update: { schema: updateSchema, responseSchema: okSchema },
23
- del: { schema: deleteSchema, responseSchema: okSchema },
24
- })
25
- ```
26
-
27
- ### CRUD Routes with makeCrudRoute
28
-
29
- Always set `indexer: { entityType }` for query index coverage:
30
-
31
- ```typescript
32
- makeCrudRoute({
33
- entity: MyEntity,
34
- indexer: { entityType: 'my_module:my_entity' },
35
- enrichers: { entityId: 'my_module.my_entity' }, // opt-in to enrichers
36
- // ...
37
- })
38
- ```
39
-
40
- ### Custom Write Routes
41
-
42
- For non-CRUD write routes (`POST`/`PUT`/`PATCH`/`DELETE`), MUST wire mutation guards:
43
- - Map the route to the closest registry operation (`create`, `update`, or `delete`; state-changing action endpoints usually use `update`)
44
- - Collect registered guards with `getAllMutationGuardInstances()` and append `bridgeLegacyGuard(container)` when present
45
- - Call `runMutationGuards(...)` from `@open-mercato/shared/lib/crud/mutation-guard-registry` before mutation, passing the caller's granted features as `{ userFeatures }`
46
- - Return guard rejection bodies/statuses, merge `modifiedPayload` into validated input when present, and run returned `afterSuccessCallbacks` after successful mutation, catching/logging callback failures so committed writes still return successfully
47
-
48
- ## Module Setup (`setup.ts`)
49
-
50
- Required for tenant initialization:
51
-
52
- ```typescript
53
- import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
54
-
55
- export const setup: ModuleSetupConfig = {
56
- defaultRoleFeatures: {
57
- superadmin: ['my_module.admin_only'],
58
- admin: ['my_module.*'],
59
- employee: ['my_module.view'],
60
- },
61
- async onTenantCreated({ em, tenantId, organizationId }) { /* settings, sequences */ },
62
- async seedDefaults({ em, tenantId, container }) { /* dictionaries, statuses */ },
63
- async seedExamples({ em, tenantId, container }) { /* demo data */ },
64
- }
65
- ```
66
-
67
- ## Events
68
-
69
- Declare events in the emitting module's `events.ts`:
70
-
71
- ```typescript
72
- import { createModuleEvents } from '@open-mercato/shared/modules/events'
73
- const events = [
74
- { id: 'my_mod.item.created', label: 'Item Created', entity: 'item', category: 'crud' },
75
- { id: 'my_mod.item.updated', label: 'Item Updated', entity: 'item', category: 'crud' },
76
- { id: 'my_mod.item.deleted', label: 'Item Deleted', entity: 'item', category: 'crud' },
77
- ] as const
78
- export const eventsConfig = createModuleEvents({ moduleId: 'my_mod', events })
79
- export const emitMyModEvent = eventsConfig.emit
80
- ```
81
-
82
- MUST use `as const` for type safety. Run `yarn generate` after adding.
83
-
84
- ### Subscribers
85
-
86
- ```typescript
87
- // subscribers/item-created-notify.ts
88
- export const metadata = { event: 'my_mod.item.created', persistent: true, id: 'item-created-notify' }
89
- export default async function handler(payload, ctx) { /* one side effect per subscriber */ }
90
- ```
91
-
92
- ## Widget Injection
93
-
94
- The preferred way to extend other modules' UI without direct coupling.
95
-
96
- ### Structure
97
- - Widgets: `widgets/injection/<WidgetName>/widget.tsx` (or `widget.ts` for headless)
98
- - Mapping: `widgets/injection-table.ts`
99
-
100
- ### Spot IDs
101
- - `crud-form:<entityId>` — inject into forms
102
- - `crud-form:<entityId>:fields` — inject form fields
103
- - `data-table:<tableId>:columns|row-actions|bulk-actions|filters` — inject into tables
104
- - `menu:sidebar:main|settings|profile` — sidebar menu items
105
- - `menu:topbar:profile-dropdown|actions` — topbar items
106
-
107
- ### Menu Injection (Headless)
108
- ```typescript
109
- // widgets/injection/MyMenuItem/widget.ts
110
- export const menuItems = [
111
- { id: 'my-mod-dashboard', labelKey: 'my_mod.menu.dashboard', icon: 'lucide:layout-dashboard',
112
- href: '/backend/my-module', placement: { position: InjectionPosition.After, relativeTo: 'customers' } }
113
- ]
114
- ```
115
-
116
- Map in `injection-table.ts`:
117
- ```typescript
118
- export default [{ widgetId: 'MyMenuItem', spots: ['menu:sidebar:main'] }]
119
- ```
120
-
121
- ## Response Enrichers
122
-
123
- Add computed fields to another module's CRUD responses:
124
-
125
- ```typescript
126
- // data/enrichers.ts
127
- export const enrichers: ResponseEnricher[] = [{
128
- id: 'my_mod.customer-stats',
129
- targetEntity: 'customers.person',
130
- features: ['my_mod.view'],
131
- priority: 10,
132
- timeout: 2000,
133
- fallback: { _my_mod: { count: 0 } },
134
- async enrichMany(records, ctx) {
135
- return records.map(r => ({ ...r, _my_mod: { count: 42 } }))
136
- },
137
- }]
138
- ```
139
-
140
- MUST implement `enrichMany()` for batch endpoints. MUST namespace with `_moduleName` prefix.
141
-
142
- ## API Interceptors
143
-
144
- Hook into any route's before/after lifecycle:
145
-
146
- ```typescript
147
- // api/interceptors.ts
148
- export const interceptors: ApiInterceptor[] = [{
149
- id: 'my_mod.narrow-customers',
150
- targetRoute: '/api/customers/people',
151
- methods: ['GET'],
152
- async before(ctx) { /* rewrite query.ids to narrow results */ },
153
- async after(ctx, response) { /* transform response */ },
154
- }]
155
- ```
156
-
157
- ## Access Control (RBAC)
158
-
159
- Declare features in `acl.ts`, guard with metadata:
160
-
161
- ```typescript
162
- // acl.ts
163
- export const features = ['my_module.view', 'my_module.create', 'my_module.edit', 'my_module.delete']
164
- ```
165
-
166
- Always add matching `defaultRoleFeatures` in `setup.ts`.
167
-
168
- Use declarative guards in page metadata: `requireAuth`, `requireRoles`, `requireFeatures`.
169
-
170
- ## Custom Fields & Entities
171
-
172
- Declare in `ce.ts` using DSL helpers:
173
-
174
- ```typescript
175
- import { defineFields, cf } from '@open-mercato/shared/modules/dsl'
176
- export const entities = [{
177
- entityId: 'my_module:my_entity',
178
- fields: defineFields({ fields: [cf.text('notes'), cf.number('priority')] }),
179
- }]
180
- ```
181
-
182
- ## Entity Extensions (Cross-Module Links)
183
-
184
- Extend another module's data without mutating their entities:
185
-
186
- ```typescript
187
- // data/extensions.ts
188
- import { defineLink, entityId, linkable } from '@open-mercato/shared/modules/dsl'
189
- export const extensions = [
190
- defineLink({ source: entityId('my_module:my_entity'), target: linkable('customers:person') })
191
- ]
192
- ```
193
-
194
- ## Component Replacement
195
-
196
- Override or wrap existing UI components:
197
-
198
- ```typescript
199
- // widgets/components.ts
200
- export const componentOverrides = [{
201
- handle: 'page:customers:detail',
202
- mode: 'wrapper', // or 'replace', 'props'
203
- component: MyCustomerDetailWrapper,
204
- }]
205
- ```
206
-
207
- Prefer `wrapper`/`props` modes over full `replace`.
208
-
209
- ## Command Pattern (Write Operations)
210
-
211
- Implement writes via commands for undo/redo support:
212
-
213
- ```typescript
214
- import { registerCommand } from '@open-mercato/shared/lib/commands'
215
- // Reference: @open-mercato/core customers/commands/people.ts
216
- ```
217
-
218
- Include `indexer: { entityType, cacheAliases }` in `emitCrudSideEffects` for query index refresh.
219
-
220
- ## Customer Accounts
221
-
222
- The `customer_accounts` module provides customer-facing authentication, sessions, RBAC, and account management. App modules build on top of it to add portal features.
223
-
224
- ### Auth APIs
225
-
226
- | Endpoint | Purpose |
227
- |----------|---------|
228
- | `POST /api/customer_accounts/login` | Email + password login, returns JWT + session cookies |
229
- | `POST /api/customer_accounts/signup` | Self-registration |
230
- | `POST /api/customer_accounts/magic-link/request` | Request passwordless login link |
231
- | `POST /api/customer_accounts/magic-link/verify` | Verify magic link token |
232
- | `POST /api/customer_accounts/password/reset-request` | Request password reset email |
233
- | `POST /api/customer_accounts/password/reset-confirm` | Confirm password reset with token |
234
- | `POST /api/customer_accounts/email/verify` | Verify email address |
235
- | `POST /api/customer_accounts/invitations/accept` | Accept an invitation token |
236
- | `POST /api/customer_accounts/portal/logout` | Clear customer session |
237
- | `POST /api/customer_accounts/portal/sessions-refresh` | Refresh JWT from session token |
238
- | `POST /api/customer_accounts/portal/password-change` | Change password (authenticated) |
239
-
240
- ### Server-Side Auth Check
241
-
242
- Use `getCustomerAuthFromCookies` in server components and catch-all routes:
243
-
244
- ```typescript
245
- import { getCustomerAuthFromCookies } from '@open-mercato/core/modules/customer_accounts/lib/customerAuthServer'
246
-
247
- const auth = await getCustomerAuthFromCookies()
248
- if (!auth) redirect(`/${orgSlug}/portal/login`)
249
- // auth.sub, auth.email, auth.displayName, auth.resolvedFeatures, auth.customerEntityId
250
- ```
251
-
252
- ### Client-Side Auth
253
-
254
- Use `useCustomerAuth` in portal client components:
255
-
256
- ```typescript
257
- import { useCustomerAuth } from '@open-mercato/ui/portal/hooks/useCustomerAuth'
258
-
259
- const { user, roles, resolvedFeatures, isPortalAdmin, loading, logout } = useCustomerAuth(orgSlug)
260
- ```
261
-
262
- ### Customer RBAC
263
-
264
- Declare `defaultCustomerRoleFeatures` in your module's `setup.ts` to auto-merge features into customer roles during tenant setup:
265
-
266
- ```typescript
267
- import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
268
-
269
- export const setup: ModuleSetupConfig = {
270
- defaultCustomerRoleFeatures: {
271
- buyer: ['portal.my_module.view', 'portal.my_module.create'],
272
- viewer: ['portal.my_module.view'],
273
- },
274
- }
275
- ```
276
-
277
- Built-in customer roles: `portal_admin` (full access), `buyer` (order/quote/catalog), `viewer` (read-only). Features merge additively on `seedDefaults`.
278
-
279
- ### Portal Page Auth Metadata
280
-
281
- Guard portal pages declaratively via page metadata:
282
-
283
- ```typescript
284
- // frontend/[orgSlug]/portal/my-feature/page.meta.ts
285
- export const metadata = {
286
- requireCustomerAuth: true,
287
- requireCustomerFeatures: ['portal.my_module.view'],
288
- navHidden: true,
289
- }
290
- ```
291
-
292
- ### Events
293
-
294
- Subscribe to customer account lifecycle events:
295
-
296
- | Event ID | Category | Broadcast |
297
- |----------|----------|-----------|
298
- | `customer_accounts.user.created` | crud | `clientBroadcast` |
299
- | `customer_accounts.user.updated` | crud | |
300
- | `customer_accounts.user.deleted` | crud | |
301
- | `customer_accounts.user.locked` | lifecycle | |
302
- | `customer_accounts.user.unlocked` | lifecycle | |
303
- | `customer_accounts.login.success` | lifecycle | |
304
- | `customer_accounts.login.failed` | lifecycle | |
305
- | `customer_accounts.email.verified` | lifecycle | |
306
- | `customer_accounts.password.reset` | lifecycle | |
307
- | `customer_accounts.invitation.accepted` | lifecycle | `clientBroadcast` |
308
- | `customer_accounts.role.created` | crud | |
309
- | `customer_accounts.role.updated` | crud | |
310
- | `customer_accounts.role.deleted` | crud | |
311
-
312
- ```typescript
313
- // subscribers/on-customer-signup.ts
314
- export const metadata = { event: 'customer_accounts.user.created', persistent: true, id: 'my-mod-on-customer-signup' }
315
- export default async function handler(payload, ctx) { /* welcome email, CRM sync, etc. */ }
316
- ```
317
-
318
- ### Extending Customer Data
319
-
320
- Link your module's entities to `CustomerUser` via `data/extensions.ts`:
321
-
322
- ```typescript
323
- import { defineLink, entityId, linkable } from '@open-mercato/shared/modules/dsl'
324
- export const extensions = [
325
- defineLink({ source: entityId('my_module:preference'), target: linkable('customer_accounts:user') }),
326
- ]
327
- ```
328
-
329
- Key entities: `CustomerUser` (customer_users), `CustomerRole` (customer_roles), `CustomerRoleAcl`, `CustomerUserRole`, `CustomerUserSession`, `CustomerUserInvitation`.
330
-
331
- ### Admin RBAC Features
332
-
333
- Staff-side features for managing customer accounts:
334
-
335
- | Feature | Purpose |
336
- |---------|---------|
337
- | `customer_accounts.view` | View customer accounts |
338
- | `customer_accounts.manage` | Manage customer accounts |
339
- | `customer_accounts.roles.manage` | Manage customer roles |
340
- | `customer_accounts.invite` | Invite customer users |
341
-
342
- ## Portal Extension
343
-
344
- Build customer-facing portal pages that integrate with the shared portal shell, navigation, and event bridge.
345
-
346
- ### Portal Feature Toggle
347
-
348
- The portal is gated by the `portal_enabled` feature toggle (seeded by the `portal` module). When disabled, all portal routes show a "Portal not available" message.
349
-
350
- ### Portal Page Structure
351
-
352
- Portal pages live at `frontend/[orgSlug]/portal/<feature>/page.tsx` and use the portal shell:
353
-
354
- ```typescript
355
- 'use client'
356
- import { useT } from '@open-mercato/shared/lib/i18n/context'
357
- import { usePortalContext } from '@open-mercato/ui/portal/PortalContext'
358
- import { PortalPageHeader } from '@open-mercato/ui/portal/components/PortalPageHeader'
359
- import { PortalCard, PortalCardHeader } from '@open-mercato/ui/portal/components/PortalCard'
360
-
361
- export default function MyPortalPage({ params }: { params: { orgSlug: string } }) {
362
- const t = useT()
363
- const { auth } = usePortalContext()
364
- const { user, loading } = auth
365
-
366
- if (loading) return <Spinner />
367
- if (!user) return null
368
-
369
- return (
370
- <div className="flex flex-col gap-8">
371
- <PortalPageHeader label={t('my_mod.portal.label')} title={t('my_mod.portal.title')} />
372
- <PortalCard>
373
- <PortalCardHeader label="Section" title="Content" />
374
- {/* page content */}
375
- </PortalCard>
376
- </div>
377
- )
378
- }
379
- ```
380
-
381
- ### Portal Menu Injection
382
-
383
- Inject navigation items into portal chrome surfaces:
384
-
385
- | Spot ID | Purpose |
386
- |---------|---------|
387
- | `menu:portal:sidebar:main` | Main portal navigation |
388
- | `menu:portal:sidebar:account` | Account/settings section |
389
- | `menu:portal:header:actions` | Header action buttons |
390
- | `menu:portal:user-dropdown` | User dropdown items |
391
-
392
- ```typescript
393
- // widgets/injection/PortalNavItem/widget.ts
394
- import { InjectionPosition } from '@open-mercato/shared/modules/widgets/injection-position'
395
-
396
- export const menuItems = [{
397
- id: 'my-mod-portal-nav',
398
- labelKey: 'my_mod.portal.menu.label',
399
- icon: 'lucide:package',
400
- href: '/portal/my-feature',
401
- placement: { position: InjectionPosition.After, relativeTo: 'portal-dashboard' },
402
- }]
403
- ```
404
-
405
- Map in `widgets/injection-table.ts`:
406
- ```typescript
407
- export default { 'menu:portal:sidebar:main': { widgetId: 'my_mod.injection.portal-nav', priority: 10 } }
408
- ```
409
-
410
- ### Portal Widget Injection Spots
411
-
412
- Inject content into portal dashboard and pages:
413
-
414
- | Spot ID | Purpose |
415
- |---------|---------|
416
- | `portal:dashboard:sections` | Dashboard section cards |
417
- | `portal:dashboard:profile` | Dashboard profile area |
418
- | `portal:dashboard:sidebar` | Dashboard sidebar |
419
- | `portal:<pageId>:before` | Before any portal page content |
420
- | `portal:<pageId>:after` | After any portal page content |
421
-
422
- ### Portal Event Bridge
423
-
424
- Events with `portalBroadcast: true` stream to authenticated portal users via SSE at `/api/customer_accounts/portal/events/stream`.
425
-
426
- Declare portal-broadcast events:
427
- ```typescript
428
- // events.ts
429
- const events = [
430
- { id: 'my_mod.item.status_changed', label: 'Item Status Changed', portalBroadcast: true },
431
- ] as const
432
- ```
433
-
434
- Listen in portal components:
435
- ```typescript
436
- import { usePortalAppEvent } from '@open-mercato/ui/portal/hooks/usePortalAppEvent'
437
-
438
- usePortalAppEvent('my_mod.item.status_changed', (event) => { refetch() })
439
- ```
440
-
441
- Enable the bridge in PortalShell with `enableEventBridge` prop.
442
-
443
- ### Portal Component Replacement
444
-
445
- Override portal shell sections via component replacement handles:
446
-
447
- | Handle | Purpose |
448
- |--------|---------|
449
- | `page:portal:layout` | Entire portal shell |
450
- | `section:portal:header` | Header bar |
451
- | `section:portal:footer` | Footer |
452
- | `section:portal:sidebar` | Navigation sidebar |
453
- | `section:portal:user-menu` | User dropdown |