@tailor-platform/erp-kit 0.2.1 → 0.2.2

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 (618) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -23
  3. package/dist/cli.mjs +1613 -0
  4. package/package.json +14 -13
  5. package/schemas/app-compose/story.yml +12 -0
  6. package/schemas/module/command.yml +9 -0
  7. package/schemas/module/module.yml +4 -0
  8. package/schemas/module/query.yml +9 -0
  9. package/skills/erp-kit-app-1-requirements/SKILL.md +4 -4
  10. package/skills/erp-kit-app-2-requirements-review/SKILL.md +102 -0
  11. package/skills/erp-kit-app-2-requirements-review/references/best-practices-check.md +66 -0
  12. package/skills/erp-kit-app-2-requirements-review/references/boundary-consistency-check.md +69 -0
  13. package/skills/erp-kit-app-2-requirements-review/references/requirements-report-format.md +25 -0
  14. package/skills/erp-kit-app-3-plan/SKILL.md +157 -0
  15. package/skills/erp-kit-app-3-plan/references/resolver-extraction.md +107 -0
  16. package/skills/erp-kit-app-3-plan/references/screen-extraction.md +74 -0
  17. package/skills/erp-kit-app-3-plan/references/story-extraction.md +86 -0
  18. package/skills/erp-kit-app-4-plan-review/SKILL.md +177 -0
  19. package/skills/erp-kit-app-4-plan-review/references/actor-flow-parity.md +73 -0
  20. package/skills/erp-kit-app-4-plan-review/references/business-flow-story-parity.md +86 -0
  21. package/skills/erp-kit-app-4-plan-review/references/orphan-detection.md +69 -0
  22. package/skills/erp-kit-app-4-plan-review/references/parity-report-format.md +52 -0
  23. package/skills/erp-kit-app-4-plan-review/references/story-resolver-parity.md +83 -0
  24. package/skills/erp-kit-app-4-plan-review/references/story-screen-parity.md +73 -0
  25. package/skills/{erp-kit-app-5-implementation → erp-kit-app-5-impl-backend}/SKILL.md +24 -68
  26. package/skills/erp-kit-app-5-impl-backend/references/app-config.md +38 -0
  27. package/skills/erp-kit-app-5-impl-backend/references/module-wiring.md +48 -0
  28. package/skills/erp-kit-app-5-impl-backend/references/resolver-patterns.md +68 -0
  29. package/skills/erp-kit-app-6-impl-frontend/SKILL.md +74 -0
  30. package/skills/{erp-kit-app-5-implementation/references/frontend.md → erp-kit-app-6-impl-frontend/references/pages.md} +8 -90
  31. package/skills/erp-kit-app-7-impl-review/SKILL.md +176 -0
  32. package/skills/erp-kit-app-7-impl-review/references/impl-parity-report-format.md +52 -0
  33. package/skills/erp-kit-app-7-impl-review/references/module-wiring-parity.md +84 -0
  34. package/skills/erp-kit-app-7-impl-review/references/resolver-doc-code-parity.md +86 -0
  35. package/skills/erp-kit-app-7-impl-review/references/screen-doc-code-parity.md +86 -0
  36. package/skills/erp-kit-module-1-requirements/SKILL.md +126 -0
  37. package/skills/erp-kit-module-1-requirements/references/boundary-analysis.md +51 -0
  38. package/skills/erp-kit-module-1-requirements/references/erp-research.md +57 -0
  39. package/skills/erp-kit-module-1-requirements/references/feature-doc.md +61 -0
  40. package/skills/erp-kit-module-2-requirements-review/SKILL.md +112 -0
  41. package/skills/erp-kit-module-2-requirements-review/references/best-practices-check.md +79 -0
  42. package/skills/erp-kit-module-2-requirements-review/references/boundary-consistency-check.md +70 -0
  43. package/skills/erp-kit-module-2-requirements-review/references/requirements-report-format.md +25 -0
  44. package/skills/erp-kit-module-3-plan/SKILL.md +107 -0
  45. package/skills/erp-kit-module-3-plan/references/command-extraction.md +87 -0
  46. package/skills/erp-kit-module-3-plan/references/model-extraction.md +72 -0
  47. package/skills/erp-kit-module-3-plan/references/query-extraction.md +59 -0
  48. package/skills/erp-kit-module-4-plan-review/SKILL.md +158 -0
  49. package/skills/erp-kit-module-4-plan-review/references/command-model-consistency.md +46 -0
  50. package/skills/erp-kit-module-4-plan-review/references/feature-command-parity.md +97 -0
  51. package/skills/erp-kit-module-4-plan-review/references/feature-model-parity.md +47 -0
  52. package/skills/erp-kit-module-4-plan-review/references/feature-query-parity.md +70 -0
  53. package/skills/erp-kit-module-4-plan-review/references/parity-report-format.md +52 -0
  54. package/skills/erp-kit-module-5-impl/SKILL.md +118 -0
  55. package/skills/erp-kit-module-5-impl/references/command-impl.md +68 -0
  56. package/skills/erp-kit-module-5-impl/references/exports.md +10 -0
  57. package/skills/erp-kit-module-5-impl/references/model-impl.md +45 -0
  58. package/skills/erp-kit-module-5-impl/references/query-impl.md +53 -0
  59. package/skills/erp-kit-module-6-impl-review/SKILL.md +187 -0
  60. package/skills/erp-kit-module-6-impl-review/references/command-doc-code-parity.md +92 -0
  61. package/skills/erp-kit-module-6-impl-review/references/command-doc-test-parity.md +93 -0
  62. package/skills/erp-kit-module-6-impl-review/references/error-implementation-parity.md +95 -0
  63. package/skills/{erp-kit-module-5-impl-review → erp-kit-module-6-impl-review}/references/errors.md +1 -1
  64. package/skills/erp-kit-module-6-impl-review/references/impl-parity-report-format.md +52 -0
  65. package/skills/erp-kit-module-6-impl-review/references/model-doc-code-parity.md +80 -0
  66. package/skills/erp-kit-module-shared/SKILL.md +1 -1
  67. package/skills/erp-kit-module-shared/references/commands.md +1 -1
  68. package/skills/erp-kit-module-shared/references/errors.md +12 -9
  69. package/skills/erp-kit-module-shared/references/queries.md +109 -36
  70. package/skills/erp-kit-module-shared/references/testing.md +10 -0
  71. package/skills/erp-kit-update/SKILL.md +2 -2
  72. package/src/app.ts +1 -1
  73. package/src/commands/check.ts +1 -1
  74. package/src/commands/index.ts +16 -5
  75. package/src/commands/init.test.ts +22 -69
  76. package/src/commands/init.ts +28 -115
  77. package/src/commands/lib/distribute.test.ts +126 -0
  78. package/src/commands/lib/distribute.ts +129 -0
  79. package/src/commands/parse-doc-test-cases.ts +55 -0
  80. package/src/commands/scaffold.test.ts +74 -33
  81. package/src/commands/scaffold.ts +54 -18
  82. package/src/commands/sync-check.test.ts +173 -0
  83. package/src/commands/sync-check.ts +103 -2
  84. package/src/commands/update.test.ts +87 -0
  85. package/src/commands/update.ts +41 -0
  86. package/src/generator/generate-code.test.ts +23 -12
  87. package/src/generator/generate-code.ts +22 -16
  88. package/src/integration.test.ts +1 -1
  89. package/src/module.ts +14 -97
  90. package/src/modules/item-management/README.md +8 -0
  91. package/src/modules/item-management/command/activateItem.generated.ts +1 -1
  92. package/src/modules/item-management/command/activateItem.test.ts +12 -18
  93. package/src/modules/item-management/command/activateItem.ts +9 -5
  94. package/src/modules/item-management/command/assignItemToTaxonomy.generated.ts +1 -1
  95. package/src/modules/item-management/command/assignItemToTaxonomy.test.ts +10 -24
  96. package/src/modules/item-management/command/assignItemToTaxonomy.ts +19 -16
  97. package/src/modules/item-management/command/createItem.generated.ts +1 -1
  98. package/src/modules/item-management/command/createItem.test.ts +11 -11
  99. package/src/modules/item-management/command/createItem.ts +16 -7
  100. package/src/modules/item-management/command/createTaxonomyNode.generated.ts +1 -1
  101. package/src/modules/item-management/command/createTaxonomyNode.test.ts +9 -9
  102. package/src/modules/item-management/command/createTaxonomyNode.ts +33 -14
  103. package/src/modules/item-management/command/deactivateItem.generated.ts +1 -1
  104. package/src/modules/item-management/command/deactivateItem.test.ts +12 -18
  105. package/src/modules/item-management/command/deactivateItem.ts +9 -5
  106. package/src/modules/item-management/command/deleteItem.generated.ts +1 -1
  107. package/src/modules/item-management/command/deleteItem.test.ts +10 -16
  108. package/src/modules/item-management/command/deleteItem.ts +9 -5
  109. package/src/modules/item-management/command/deleteTaxonomyNode.generated.ts +1 -1
  110. package/src/modules/item-management/command/deleteTaxonomyNode.test.ts +10 -16
  111. package/src/modules/item-management/command/deleteTaxonomyNode.ts +22 -12
  112. package/src/modules/item-management/command/moveTaxonomyNode.generated.ts +1 -1
  113. package/src/modules/item-management/command/moveTaxonomyNode.test.ts +10 -10
  114. package/src/modules/item-management/command/moveTaxonomyNode.ts +63 -19
  115. package/src/modules/item-management/command/reactivateItem.generated.ts +1 -1
  116. package/src/modules/item-management/command/reactivateItem.test.ts +12 -18
  117. package/src/modules/item-management/command/reactivateItem.ts +9 -5
  118. package/src/modules/item-management/command/removeItemFromTaxonomy.generated.ts +1 -1
  119. package/src/modules/item-management/command/removeItemFromTaxonomy.test.ts +9 -16
  120. package/src/modules/item-management/command/removeItemFromTaxonomy.ts +11 -6
  121. package/src/modules/item-management/command/updateItem.generated.ts +1 -1
  122. package/src/modules/item-management/command/updateItem.test.ts +16 -16
  123. package/src/modules/item-management/command/updateItem.ts +11 -6
  124. package/src/modules/item-management/command/updateTaxonomyNode.generated.ts +1 -1
  125. package/src/modules/item-management/command/updateTaxonomyNode.test.ts +14 -20
  126. package/src/modules/item-management/command/updateTaxonomyNode.ts +9 -6
  127. package/src/modules/item-management/docs/commands/ActivateItem.md +8 -0
  128. package/src/modules/item-management/docs/commands/AssignItemToTaxonomy.md +7 -0
  129. package/src/modules/item-management/docs/commands/CreateItem.md +10 -0
  130. package/src/modules/item-management/docs/commands/CreateTaxonomyNode.md +9 -0
  131. package/src/modules/item-management/docs/commands/DeactivateItem.md +8 -0
  132. package/src/modules/item-management/docs/commands/DeleteItem.md +7 -0
  133. package/src/modules/item-management/docs/commands/DeleteTaxonomyNode.md +7 -0
  134. package/src/modules/item-management/docs/commands/MoveTaxonomyNode.md +10 -0
  135. package/src/modules/item-management/docs/commands/ReactivateItem.md +8 -0
  136. package/src/modules/item-management/docs/commands/RemoveItemFromTaxonomy.md +5 -0
  137. package/src/modules/item-management/docs/commands/UpdateItem.md +15 -0
  138. package/src/modules/item-management/docs/commands/UpdateTaxonomyNode.md +9 -0
  139. package/src/modules/item-management/docs/queries/CalculateNodeDepth.md +8 -0
  140. package/src/modules/item-management/docs/queries/CalculateSubtreeDepth.md +7 -0
  141. package/src/modules/item-management/docs/queries/DetectCircularReference.md +9 -0
  142. package/src/modules/item-management/docs/queries/GetItem.md +9 -0
  143. package/src/modules/item-management/docs/queries/GetItemTaxonomyAssignment.md +5 -0
  144. package/src/modules/item-management/docs/queries/GetTaxonomyNode.md +7 -0
  145. package/src/modules/item-management/docs/queries/GetTaxonomyNodeAssignments.md +5 -0
  146. package/src/modules/item-management/docs/queries/GetTaxonomyNodeChildren.md +6 -0
  147. package/src/modules/item-management/index.ts +0 -51
  148. package/src/modules/item-management/lib/errors.generated.ts +24 -24
  149. package/src/modules/item-management/lib/permissions.generated.ts +1 -1
  150. package/src/modules/item-management/lib/types.ts +1 -1
  151. package/src/modules/item-management/module.ts +1 -1
  152. package/src/modules/item-management/query/calculateNodeDepth.generated.ts +1 -1
  153. package/src/modules/item-management/query/calculateNodeDepth.test.ts +21 -6
  154. package/src/modules/item-management/query/calculateNodeDepth.ts +2 -2
  155. package/src/modules/item-management/query/calculateSubtreeDepth.generated.ts +1 -1
  156. package/src/modules/item-management/query/calculateSubtreeDepth.test.ts +17 -5
  157. package/src/modules/item-management/query/calculateSubtreeDepth.ts +2 -2
  158. package/src/modules/item-management/query/detectCircularReference.generated.ts +1 -1
  159. package/src/modules/item-management/query/detectCircularReference.test.ts +25 -7
  160. package/src/modules/item-management/query/detectCircularReference.ts +4 -4
  161. package/src/modules/item-management/query/getItem.generated.ts +1 -1
  162. package/src/modules/item-management/query/getItem.test.ts +25 -7
  163. package/src/modules/item-management/query/getItem.ts +2 -2
  164. package/src/modules/item-management/query/getItemTaxonomyAssignment.generated.ts +1 -1
  165. package/src/modules/item-management/query/getItemTaxonomyAssignment.test.ts +9 -3
  166. package/src/modules/item-management/query/getItemTaxonomyAssignment.ts +2 -2
  167. package/src/modules/item-management/query/getTaxonomyNode.generated.ts +1 -1
  168. package/src/modules/item-management/query/getTaxonomyNode.test.ts +17 -5
  169. package/src/modules/item-management/query/getTaxonomyNode.ts +2 -2
  170. package/src/modules/item-management/query/getTaxonomyNodeAssignments.generated.ts +1 -1
  171. package/src/modules/item-management/query/getTaxonomyNodeAssignments.test.ts +9 -3
  172. package/src/modules/item-management/query/getTaxonomyNodeAssignments.ts +2 -2
  173. package/src/modules/item-management/query/getTaxonomyNodeChildren.generated.ts +1 -1
  174. package/src/modules/item-management/query/getTaxonomyNodeChildren.test.ts +13 -4
  175. package/src/modules/item-management/query/getTaxonomyNodeChildren.ts +2 -2
  176. package/src/modules/item-management/tailor.config.ts +6 -4
  177. package/src/modules/item-management/tailor.d.ts +13 -0
  178. package/src/modules/primitives/README.md +8 -0
  179. package/src/modules/primitives/command/activateCategory.generated.ts +1 -1
  180. package/src/modules/primitives/command/activateCategory.test.ts +8 -18
  181. package/src/modules/primitives/command/activateCategory.ts +9 -5
  182. package/src/modules/primitives/command/activateCurrency.generated.ts +1 -1
  183. package/src/modules/primitives/command/activateCurrency.test.ts +8 -18
  184. package/src/modules/primitives/command/activateCurrency.ts +9 -5
  185. package/src/modules/primitives/command/activateUnit.generated.ts +1 -1
  186. package/src/modules/primitives/command/activateUnit.test.ts +8 -15
  187. package/src/modules/primitives/command/activateUnit.ts +9 -5
  188. package/src/modules/primitives/command/createCategory.generated.ts +1 -1
  189. package/src/modules/primitives/command/createCategory.test.ts +29 -44
  190. package/src/modules/primitives/command/createCategory.ts +9 -5
  191. package/src/modules/primitives/command/createCurrency.generated.ts +1 -1
  192. package/src/modules/primitives/command/createCurrency.test.ts +53 -78
  193. package/src/modules/primitives/command/createCurrency.ts +9 -6
  194. package/src/modules/primitives/command/createExchangeRate.generated.ts +1 -1
  195. package/src/modules/primitives/command/createExchangeRate.test.ts +59 -97
  196. package/src/modules/primitives/command/createExchangeRate.ts +13 -7
  197. package/src/modules/primitives/command/createUnit.generated.ts +1 -1
  198. package/src/modules/primitives/command/createUnit.test.ts +59 -90
  199. package/src/modules/primitives/command/createUnit.ts +9 -6
  200. package/src/modules/primitives/command/deactivateCategory.generated.ts +1 -1
  201. package/src/modules/primitives/command/deactivateCategory.test.ts +15 -33
  202. package/src/modules/primitives/command/deactivateCategory.ts +9 -5
  203. package/src/modules/primitives/command/deactivateCurrency.generated.ts +1 -1
  204. package/src/modules/primitives/command/deactivateCurrency.test.ts +12 -26
  205. package/src/modules/primitives/command/deactivateCurrency.ts +9 -5
  206. package/src/modules/primitives/command/deactivateUnit.generated.ts +1 -1
  207. package/src/modules/primitives/command/deactivateUnit.test.ts +15 -30
  208. package/src/modules/primitives/command/deactivateUnit.ts +14 -7
  209. package/src/modules/primitives/command/setBaseCurrency.generated.ts +1 -1
  210. package/src/modules/primitives/command/setBaseCurrency.test.ts +18 -40
  211. package/src/modules/primitives/command/setBaseCurrency.ts +15 -7
  212. package/src/modules/primitives/command/setReferenceUnit.generated.ts +1 -1
  213. package/src/modules/primitives/command/setReferenceUnit.test.ts +22 -44
  214. package/src/modules/primitives/command/setReferenceUnit.ts +21 -9
  215. package/src/modules/primitives/docs/commands/ActivateCategory.md +6 -0
  216. package/src/modules/primitives/docs/commands/ActivateCurrency.md +6 -0
  217. package/src/modules/primitives/docs/commands/ActivateUnit.md +6 -0
  218. package/src/modules/primitives/docs/commands/CreateCategory.md +6 -0
  219. package/src/modules/primitives/docs/commands/CreateCurrency.md +10 -0
  220. package/src/modules/primitives/docs/commands/CreateExchangeRate.md +11 -0
  221. package/src/modules/primitives/docs/commands/CreateUnit.md +10 -0
  222. package/src/modules/primitives/docs/commands/DeactivateCategory.md +7 -0
  223. package/src/modules/primitives/docs/commands/DeactivateCurrency.md +7 -0
  224. package/src/modules/primitives/docs/commands/DeactivateUnit.md +7 -0
  225. package/src/modules/primitives/docs/commands/SetBaseCurrency.md +7 -0
  226. package/src/modules/primitives/docs/commands/SetReferenceUnit.md +7 -0
  227. package/src/modules/primitives/docs/queries/ConvertAmount.md +14 -0
  228. package/src/modules/primitives/docs/queries/ConvertQuantity.md +13 -0
  229. package/src/modules/primitives/docs/queries/GetBaseCurrency.md +5 -0
  230. package/src/modules/primitives/docs/queries/GetCurrency.md +7 -0
  231. package/src/modules/primitives/docs/queries/GetUnit.md +7 -0
  232. package/src/modules/primitives/docs/queries/GetUoMCategory.md +7 -0
  233. package/src/modules/primitives/docs/queries/ListUnitsByCategory.md +15 -5
  234. package/src/modules/primitives/index.ts +0 -49
  235. package/src/modules/primitives/lib/errors.generated.ts +23 -23
  236. package/src/modules/primitives/lib/permissions.generated.ts +1 -1
  237. package/src/modules/primitives/lib/types.ts +1 -1
  238. package/src/modules/primitives/module.ts +1 -1
  239. package/src/modules/primitives/query/convertAmount.generated.ts +1 -1
  240. package/src/modules/primitives/query/convertAmount.test.ts +110 -77
  241. package/src/modules/primitives/query/convertAmount.ts +61 -47
  242. package/src/modules/primitives/query/convertQuantity.generated.ts +1 -1
  243. package/src/modules/primitives/query/convertQuantity.test.ts +99 -69
  244. package/src/modules/primitives/query/convertQuantity.ts +12 -10
  245. package/src/modules/primitives/query/getBaseCurrency.generated.ts +1 -1
  246. package/src/modules/primitives/query/getBaseCurrency.test.ts +10 -4
  247. package/src/modules/primitives/query/getBaseCurrency.ts +2 -2
  248. package/src/modules/primitives/query/getCurrency.generated.ts +1 -1
  249. package/src/modules/primitives/query/getCurrency.test.ts +17 -5
  250. package/src/modules/primitives/query/getCurrency.ts +2 -2
  251. package/src/modules/primitives/query/getUnit.generated.ts +1 -1
  252. package/src/modules/primitives/query/getUnit.test.ts +17 -5
  253. package/src/modules/primitives/query/getUnit.ts +2 -2
  254. package/src/modules/primitives/query/getUoMCategory.generated.ts +1 -1
  255. package/src/modules/primitives/query/getUoMCategory.test.ts +17 -5
  256. package/src/modules/primitives/query/getUoMCategory.ts +2 -2
  257. package/src/modules/primitives/query/listUnitsByCategory.generated.ts +1 -1
  258. package/src/modules/primitives/query/listUnitsByCategory.test.ts +80 -0
  259. package/src/modules/primitives/query/listUnitsByCategory.ts +19 -3
  260. package/src/modules/primitives/tailor.config.ts +6 -4
  261. package/src/modules/primitives/tailor.d.ts +13 -0
  262. package/src/modules/product-management/README.md +52 -0
  263. package/src/modules/product-management/command/activateProduct.generated.ts +6 -0
  264. package/src/modules/product-management/command/activateProduct.test.ts +40 -0
  265. package/src/modules/product-management/command/activateProduct.ts +42 -0
  266. package/src/modules/product-management/command/assignProductToCategory.generated.ts +6 -0
  267. package/src/modules/product-management/command/assignProductToCategory.test.ts +90 -0
  268. package/src/modules/product-management/command/assignProductToCategory.ts +62 -0
  269. package/src/modules/product-management/command/createProduct.generated.ts +6 -0
  270. package/src/modules/product-management/command/createProduct.test.ts +149 -0
  271. package/src/modules/product-management/command/createProduct.ts +73 -0
  272. package/src/modules/product-management/command/createProductAttribute.generated.ts +6 -0
  273. package/src/modules/product-management/command/createProductAttribute.test.ts +70 -0
  274. package/src/modules/product-management/command/createProductAttribute.ts +53 -0
  275. package/src/modules/product-management/command/createProductAttributeValue.generated.ts +6 -0
  276. package/src/modules/product-management/command/createProductAttributeValue.test.ts +68 -0
  277. package/src/modules/product-management/command/createProductAttributeValue.ts +63 -0
  278. package/src/modules/product-management/command/createProductCategory.generated.ts +6 -0
  279. package/src/modules/product-management/command/createProductCategory.test.ts +135 -0
  280. package/src/modules/product-management/command/createProductCategory.ts +82 -0
  281. package/src/modules/product-management/command/deactivateProduct.generated.ts +6 -0
  282. package/src/modules/product-management/command/deactivateProduct.test.ts +40 -0
  283. package/src/modules/product-management/command/deactivateProduct.ts +42 -0
  284. package/src/modules/product-management/command/deleteProduct.generated.ts +6 -0
  285. package/src/modules/product-management/command/deleteProduct.test.ts +42 -0
  286. package/src/modules/product-management/command/deleteProduct.ts +42 -0
  287. package/src/modules/product-management/command/deleteProductAttribute.generated.ts +6 -0
  288. package/src/modules/product-management/command/deleteProductAttribute.test.ts +49 -0
  289. package/src/modules/product-management/command/deleteProductAttribute.ts +45 -0
  290. package/src/modules/product-management/command/deleteProductAttributeValue.generated.ts +6 -0
  291. package/src/modules/product-management/command/deleteProductAttributeValue.test.ts +71 -0
  292. package/src/modules/product-management/command/deleteProductAttributeValue.ts +68 -0
  293. package/src/modules/product-management/command/deleteProductCategory.generated.ts +6 -0
  294. package/src/modules/product-management/command/deleteProductCategory.test.ts +74 -0
  295. package/src/modules/product-management/command/deleteProductCategory.ts +53 -0
  296. package/src/modules/product-management/command/generateVariants.generated.ts +6 -0
  297. package/src/modules/product-management/command/generateVariants.test.ts +365 -0
  298. package/src/modules/product-management/command/generateVariants.ts +168 -0
  299. package/src/modules/product-management/command/moveProductCategory.generated.ts +6 -0
  300. package/src/modules/product-management/command/moveProductCategory.test.ts +170 -0
  301. package/src/modules/product-management/command/moveProductCategory.ts +124 -0
  302. package/src/modules/product-management/command/reactivateProduct.generated.ts +6 -0
  303. package/src/modules/product-management/command/reactivateProduct.test.ts +40 -0
  304. package/src/modules/product-management/command/reactivateProduct.ts +42 -0
  305. package/src/modules/product-management/command/removeProductFromCategory.generated.ts +6 -0
  306. package/src/modules/product-management/command/removeProductFromCategory.test.ts +42 -0
  307. package/src/modules/product-management/command/removeProductFromCategory.ts +32 -0
  308. package/src/modules/product-management/command/setProductAttributeAssignment.generated.ts +6 -0
  309. package/src/modules/product-management/command/setProductAttributeAssignment.test.ts +206 -0
  310. package/src/modules/product-management/command/setProductAttributeAssignment.ts +102 -0
  311. package/src/modules/product-management/command/updateProduct.generated.ts +6 -0
  312. package/src/modules/product-management/command/updateProduct.test.ts +168 -0
  313. package/src/modules/product-management/command/updateProduct.ts +95 -0
  314. package/src/modules/product-management/command/updateProductAttribute.generated.ts +6 -0
  315. package/src/modules/product-management/command/updateProductAttribute.test.ts +101 -0
  316. package/src/modules/product-management/command/updateProductAttribute.ts +68 -0
  317. package/src/modules/product-management/command/updateProductAttributeValue.generated.ts +6 -0
  318. package/src/modules/product-management/command/updateProductAttributeValue.test.ts +80 -0
  319. package/src/modules/product-management/command/updateProductAttributeValue.ts +58 -0
  320. package/src/modules/product-management/command/updateProductCategory.generated.ts +6 -0
  321. package/src/modules/product-management/command/updateProductCategory.test.ts +80 -0
  322. package/src/modules/product-management/command/updateProductCategory.ts +66 -0
  323. package/src/modules/product-management/db/product.ts +47 -0
  324. package/src/modules/product-management/db/productAttribute.ts +26 -0
  325. package/src/modules/product-management/db/productAttributeAssignment.ts +58 -0
  326. package/src/modules/product-management/db/productAttributeValue.ts +39 -0
  327. package/src/modules/product-management/db/productCategory.ts +34 -0
  328. package/src/modules/product-management/db/productCategoryAssignment.ts +49 -0
  329. package/src/modules/product-management/db/productVariant.ts +52 -0
  330. package/src/modules/product-management/docs/commands/ActivateProduct.md +39 -0
  331. package/src/modules/product-management/docs/commands/AssignProductToCategory.md +43 -0
  332. package/src/modules/product-management/docs/commands/CreateProduct.md +48 -0
  333. package/src/modules/product-management/docs/commands/CreateProductAttribute.md +39 -0
  334. package/src/modules/product-management/docs/commands/CreateProductAttributeValue.md +42 -0
  335. package/src/modules/product-management/docs/commands/CreateProductCategory.md +54 -0
  336. package/src/modules/product-management/docs/commands/DeactivateProduct.md +39 -0
  337. package/src/modules/product-management/docs/commands/DeleteProduct.md +42 -0
  338. package/src/modules/product-management/docs/commands/DeleteProductAttribute.md +39 -0
  339. package/src/modules/product-management/docs/commands/DeleteProductAttributeValue.md +42 -0
  340. package/src/modules/product-management/docs/commands/DeleteProductCategory.md +43 -0
  341. package/src/modules/product-management/docs/commands/GenerateVariants.md +68 -0
  342. package/src/modules/product-management/docs/commands/MoveProductCategory.md +54 -0
  343. package/src/modules/product-management/docs/commands/ReactivateProduct.md +38 -0
  344. package/src/modules/product-management/docs/commands/RemoveProductFromCategory.md +34 -0
  345. package/src/modules/product-management/docs/commands/SetProductAttributeAssignment.md +62 -0
  346. package/src/modules/product-management/docs/commands/UpdateProduct.md +61 -0
  347. package/src/modules/product-management/docs/commands/UpdateProductAttribute.md +46 -0
  348. package/src/modules/product-management/docs/commands/UpdateProductAttributeValue.md +47 -0
  349. package/src/modules/product-management/docs/commands/UpdateProductCategory.md +46 -0
  350. package/src/modules/product-management/docs/features/attribute-management.md +48 -0
  351. package/src/modules/product-management/docs/features/product-category.md +71 -0
  352. package/src/modules/product-management/docs/features/product-lifecycle.md +66 -0
  353. package/src/modules/product-management/docs/features/variant-generation.md +77 -0
  354. package/src/modules/product-management/docs/models/Product.md +58 -0
  355. package/src/modules/product-management/docs/models/ProductAttribute.md +37 -0
  356. package/src/modules/product-management/docs/models/ProductAttributeAssignment.md +41 -0
  357. package/src/modules/product-management/docs/models/ProductAttributeValue.md +40 -0
  358. package/src/modules/product-management/docs/models/ProductCategory.md +46 -0
  359. package/src/modules/product-management/docs/models/ProductCategoryAssignment.md +37 -0
  360. package/src/modules/product-management/docs/models/ProductVariant.md +41 -0
  361. package/src/modules/product-management/docs/queries/CalculateCategoryDepth.md +47 -0
  362. package/src/modules/product-management/docs/queries/DetectCategoryCircularReference.md +51 -0
  363. package/src/modules/product-management/docs/queries/GetProduct.md +42 -0
  364. package/src/modules/product-management/docs/queries/GetProductAttribute.md +42 -0
  365. package/src/modules/product-management/docs/queries/GetProductAttributeAssignment.md +34 -0
  366. package/src/modules/product-management/docs/queries/GetProductAttributeValue.md +40 -0
  367. package/src/modules/product-management/docs/queries/GetProductCategory.md +42 -0
  368. package/src/modules/product-management/docs/queries/GetProductCategoryAssignment.md +34 -0
  369. package/src/modules/product-management/docs/queries/GetProductVariant.md +41 -0
  370. package/src/modules/product-management/docs/queries/ListAttributeAssignmentsByAttribute.md +34 -0
  371. package/src/modules/product-management/docs/queries/ListCategoryAssignmentsByProduct.md +35 -0
  372. package/src/modules/product-management/docs/queries/ListProductAttributeAssignments.md +34 -0
  373. package/src/modules/product-management/docs/queries/ListProductAttributeValues.md +36 -0
  374. package/src/modules/product-management/docs/queries/ListProductCategoryAssignments.md +34 -0
  375. package/src/modules/product-management/docs/queries/ListProductCategoryChildren.md +34 -0
  376. package/src/modules/product-management/docs/queries/ListProductVariants.md +34 -0
  377. package/src/modules/product-management/generated/enums.ts +9 -0
  378. package/src/modules/product-management/generated/kysely-tailordb.ts +100 -0
  379. package/src/modules/product-management/index.ts +2 -0
  380. package/src/modules/product-management/lib/_db_deps.ts +17 -0
  381. package/src/modules/product-management/lib/errors.generated.ts +152 -0
  382. package/src/modules/product-management/lib/permissions.generated.ts +25 -0
  383. package/src/modules/product-management/lib/types.ts +51 -0
  384. package/src/modules/product-management/module.ts +201 -0
  385. package/src/modules/product-management/query/calculateCategoryDepth.generated.ts +5 -0
  386. package/src/modules/product-management/query/calculateCategoryDepth.test.ts +72 -0
  387. package/src/modules/product-management/query/calculateCategoryDepth.ts +37 -0
  388. package/src/modules/product-management/query/detectCategoryCircularReference.generated.ts +5 -0
  389. package/src/modules/product-management/query/detectCategoryCircularReference.test.ts +72 -0
  390. package/src/modules/product-management/query/detectCategoryCircularReference.ts +44 -0
  391. package/src/modules/product-management/query/getProduct.generated.ts +5 -0
  392. package/src/modules/product-management/query/getProduct.test.ts +59 -0
  393. package/src/modules/product-management/query/getProduct.ts +18 -0
  394. package/src/modules/product-management/query/getProductAttribute.generated.ts +5 -0
  395. package/src/modules/product-management/query/getProductAttribute.test.ts +59 -0
  396. package/src/modules/product-management/query/getProductAttribute.ts +18 -0
  397. package/src/modules/product-management/query/getProductAttributeAssignment.generated.ts +5 -0
  398. package/src/modules/product-management/query/getProductAttributeAssignment.test.ts +37 -0
  399. package/src/modules/product-management/query/getProductAttributeAssignment.ts +18 -0
  400. package/src/modules/product-management/query/getProductAttributeValue.generated.ts +5 -0
  401. package/src/modules/product-management/query/getProductAttributeValue.test.ts +31 -0
  402. package/src/modules/product-management/query/getProductAttributeValue.ts +16 -0
  403. package/src/modules/product-management/query/getProductCategory.generated.ts +5 -0
  404. package/src/modules/product-management/query/getProductCategory.test.ts +59 -0
  405. package/src/modules/product-management/query/getProductCategory.ts +18 -0
  406. package/src/modules/product-management/query/getProductCategoryAssignment.generated.ts +5 -0
  407. package/src/modules/product-management/query/getProductCategoryAssignment.test.ts +37 -0
  408. package/src/modules/product-management/query/getProductCategoryAssignment.ts +18 -0
  409. package/src/modules/product-management/query/getProductVariant.generated.ts +5 -0
  410. package/src/modules/product-management/query/getProductVariant.test.ts +43 -0
  411. package/src/modules/product-management/query/getProductVariant.ts +20 -0
  412. package/src/modules/product-management/query/listAttributeAssignmentsByAttribute.generated.ts +5 -0
  413. package/src/modules/product-management/query/listAttributeAssignmentsByAttribute.test.ts +31 -0
  414. package/src/modules/product-management/query/listAttributeAssignmentsByAttribute.ts +16 -0
  415. package/src/modules/product-management/query/listCategoryAssignmentsByProduct.generated.ts +5 -0
  416. package/src/modules/product-management/query/listCategoryAssignmentsByProduct.test.ts +31 -0
  417. package/src/modules/product-management/query/listCategoryAssignmentsByProduct.ts +16 -0
  418. package/src/modules/product-management/query/listProductAttributeAssignments.generated.ts +5 -0
  419. package/src/modules/product-management/query/listProductAttributeAssignments.test.ts +31 -0
  420. package/src/modules/product-management/query/listProductAttributeAssignments.ts +16 -0
  421. package/src/modules/product-management/query/listProductAttributeValues.generated.ts +5 -0
  422. package/src/modules/product-management/query/listProductAttributeValues.test.ts +31 -0
  423. package/src/modules/product-management/query/listProductAttributeValues.ts +17 -0
  424. package/src/modules/product-management/query/listProductCategoryAssignments.generated.ts +5 -0
  425. package/src/modules/product-management/query/listProductCategoryAssignments.test.ts +31 -0
  426. package/src/modules/product-management/query/listProductCategoryAssignments.ts +16 -0
  427. package/src/modules/product-management/query/listProductCategoryChildren.generated.ts +5 -0
  428. package/src/modules/product-management/query/listProductCategoryChildren.test.ts +31 -0
  429. package/src/modules/product-management/query/listProductCategoryChildren.ts +16 -0
  430. package/src/modules/product-management/query/listProductVariants.generated.ts +5 -0
  431. package/src/modules/product-management/query/listProductVariants.test.ts +31 -0
  432. package/src/modules/product-management/query/listProductVariants.ts +16 -0
  433. package/src/modules/product-management/tailor.config.ts +13 -0
  434. package/src/modules/product-management/tailor.d.ts +13 -0
  435. package/src/modules/product-management/testing/fixtures.ts +151 -0
  436. package/src/modules/user-management/README.md +9 -3
  437. package/src/modules/user-management/command/activateUser.generated.ts +1 -1
  438. package/src/modules/user-management/command/activateUser.test.ts +12 -65
  439. package/src/modules/user-management/command/activateUser.ts +5 -20
  440. package/src/modules/user-management/command/assignPermissionToRole.generated.ts +1 -1
  441. package/src/modules/user-management/command/assignPermissionToRole.test.ts +25 -60
  442. package/src/modules/user-management/command/assignPermissionToRole.ts +5 -24
  443. package/src/modules/user-management/command/assignRoleToUser.generated.ts +1 -1
  444. package/src/modules/user-management/command/assignRoleToUser.test.ts +35 -87
  445. package/src/modules/user-management/command/assignRoleToUser.ts +5 -24
  446. package/src/modules/user-management/command/createPermission.generated.ts +1 -1
  447. package/src/modules/user-management/command/createPermission.test.ts +23 -33
  448. package/src/modules/user-management/command/createPermission.ts +4 -5
  449. package/src/modules/user-management/command/createRole.generated.ts +1 -1
  450. package/src/modules/user-management/command/createRole.test.ts +17 -27
  451. package/src/modules/user-management/command/createRole.ts +4 -5
  452. package/src/modules/user-management/command/createUser.generated.ts +1 -1
  453. package/src/modules/user-management/command/createUser.test.ts +31 -118
  454. package/src/modules/user-management/command/createUser.ts +7 -25
  455. package/src/modules/user-management/command/deactivateUser.generated.ts +1 -1
  456. package/src/modules/user-management/command/deactivateUser.test.ts +12 -65
  457. package/src/modules/user-management/command/deactivateUser.ts +6 -21
  458. package/src/modules/user-management/command/reactivateUser.generated.ts +1 -1
  459. package/src/modules/user-management/command/reactivateUser.test.ts +13 -66
  460. package/src/modules/user-management/command/reactivateUser.ts +5 -20
  461. package/src/modules/user-management/command/revokePermissionFromRole.generated.ts +1 -1
  462. package/src/modules/user-management/command/revokePermissionFromRole.test.ts +24 -62
  463. package/src/modules/user-management/command/revokePermissionFromRole.ts +5 -24
  464. package/src/modules/user-management/command/revokeRoleFromUser.generated.ts +1 -1
  465. package/src/modules/user-management/command/revokeRoleFromUser.test.ts +24 -60
  466. package/src/modules/user-management/command/revokeRoleFromUser.ts +5 -24
  467. package/src/modules/user-management/docs/commands/ActivateUser.md +7 -0
  468. package/src/modules/user-management/docs/commands/AssignPermissionToRole.md +7 -0
  469. package/src/modules/user-management/docs/commands/AssignRoleToUser.md +9 -0
  470. package/src/modules/user-management/docs/commands/CreatePermission.md +12 -0
  471. package/src/modules/user-management/docs/commands/CreateRole.md +9 -0
  472. package/src/modules/user-management/docs/commands/CreateUser.md +11 -0
  473. package/src/modules/user-management/docs/commands/DeactivateUser.md +7 -0
  474. package/src/modules/user-management/docs/commands/ReactivateUser.md +7 -0
  475. package/src/modules/user-management/docs/commands/RevokePermissionFromRole.md +7 -0
  476. package/src/modules/user-management/docs/commands/RevokeRoleFromUser.md +7 -0
  477. package/src/modules/user-management/index.ts +0 -30
  478. package/src/modules/user-management/lib/errors.generated.ts +14 -14
  479. package/src/modules/user-management/lib/permissions.generated.ts +1 -2
  480. package/src/modules/user-management/lib/recomputeUserPermissions.ts +4 -3
  481. package/src/modules/user-management/lib/types.ts +1 -1
  482. package/src/modules/user-management/module.ts +2 -7
  483. package/src/modules/user-management/tailor.config.ts +6 -4
  484. package/src/modules/user-management/tailor.d.ts +13 -0
  485. package/src/modules/user-management/testing/fixtures.ts +1 -20
  486. package/src/schemas.ts +1 -1
  487. package/src/{modules/shared → shared}/defineCommand.test.ts +23 -7
  488. package/src/{modules/shared → shared}/defineCommand.ts +19 -10
  489. package/src/{modules/shared/internal.ts → shared/index.ts} +9 -1
  490. package/src/shared/pagination.test.ts +43 -0
  491. package/src/shared/pagination.ts +22 -0
  492. package/src/{modules/shared → shared}/types.ts +13 -0
  493. package/src/{modules/testing → testing}/index.ts +14 -7
  494. package/src/testing.ts +1 -1
  495. package/src/util.ts +8 -0
  496. package/templates/config/license.config.json +4 -0
  497. package/templates/scaffold/app/backend/.env.example +1 -0
  498. package/templates/scaffold/app/backend/__dot__gitignore +4 -0
  499. package/templates/scaffold/app/backend/eslint.config.js +32 -0
  500. package/templates/scaffold/app/backend/package.json +31 -0
  501. package/templates/scaffold/app/backend/seed/data/AuditEvent.jsonl +0 -0
  502. package/templates/scaffold/app/backend/seed/data/Permission.jsonl +0 -0
  503. package/templates/scaffold/app/backend/seed/data/Permission.schema.ts +20 -0
  504. package/templates/scaffold/app/backend/seed/data/Role.jsonl +0 -0
  505. package/templates/scaffold/app/backend/seed/data/Role.schema.ts +20 -0
  506. package/templates/scaffold/app/backend/seed/data/RolePermission.jsonl +0 -0
  507. package/templates/scaffold/app/backend/seed/data/RolePermission.schema.ts +24 -0
  508. package/templates/scaffold/app/backend/seed/data/User.jsonl +1 -0
  509. package/templates/scaffold/app/backend/seed/data/User.schema.ts +20 -0
  510. package/templates/scaffold/app/backend/seed/data/UserRole.jsonl +0 -0
  511. package/templates/scaffold/app/backend/seed/data/UserRole.schema.ts +24 -0
  512. package/templates/scaffold/app/backend/seed/data/_User.jsonl +1 -0
  513. package/templates/scaffold/app/backend/seed/data/_User.schema.ts +30 -0
  514. package/templates/scaffold/app/backend/seed/exec.mjs +659 -0
  515. package/templates/scaffold/app/backend/src/executors/permissionCreated.ts +3 -0
  516. package/templates/scaffold/app/backend/src/executors/permissionDeleted.ts +3 -0
  517. package/templates/scaffold/app/backend/src/generated/kysely-tailordb.ts +83 -0
  518. package/templates/scaffold/app/backend/src/modules.ts +9 -0
  519. package/templates/scaffold/app/backend/src/resolvers/createUser.ts +46 -0
  520. package/templates/scaffold/app/backend/tailor.config.ts +68 -0
  521. package/templates/scaffold/app/backend/tailor.d.ts +15 -0
  522. package/templates/scaffold/app/backend/tsconfig.json +19 -0
  523. package/templates/scaffold/app/docs/actors/.gitkeep +0 -0
  524. package/templates/scaffold/app/docs/business-flow/.gitkeep +0 -0
  525. package/templates/scaffold/app/docs/resolver/.gitkeep +0 -0
  526. package/templates/scaffold/app/docs/screen/.gitkeep +0 -0
  527. package/templates/scaffold/app/frontend/.env.example +2 -0
  528. package/templates/scaffold/app/frontend/__dot__gitignore +3 -0
  529. package/templates/scaffold/app/frontend/components.json +23 -0
  530. package/templates/scaffold/app/frontend/eslint.config.js +48 -0
  531. package/templates/scaffold/app/frontend/index.html +13 -0
  532. package/templates/scaffold/app/frontend/package.json +53 -0
  533. package/templates/scaffold/app/frontend/scripts/generate-graphql.mjs +6 -0
  534. package/templates/scaffold/app/frontend/src/App.tsx +58 -0
  535. package/templates/scaffold/app/frontend/src/components/composed/empty-state.tsx +26 -0
  536. package/templates/scaffold/app/frontend/src/components/composed/error-fallback.tsx +28 -0
  537. package/templates/scaffold/app/frontend/src/components/composed/loading.tsx +13 -0
  538. package/templates/scaffold/app/frontend/src/components/ui/badge.tsx +39 -0
  539. package/templates/scaffold/app/frontend/src/components/ui/button.tsx +60 -0
  540. package/templates/scaffold/app/frontend/src/components/ui/card.tsx +75 -0
  541. package/templates/scaffold/app/frontend/src/components/ui/form.tsx +152 -0
  542. package/templates/scaffold/app/frontend/src/components/ui/input.tsx +21 -0
  543. package/templates/scaffold/app/frontend/src/components/ui/label.tsx +21 -0
  544. package/templates/scaffold/app/frontend/src/components/ui/spinner.tsx +16 -0
  545. package/templates/scaffold/app/frontend/src/components/ui/table.tsx +90 -0
  546. package/templates/scaffold/app/frontend/src/graphql/generated/graphql-env.d.ts +103 -0
  547. package/templates/scaffold/app/frontend/src/graphql/generated/schema.graphql +1235 -0
  548. package/templates/scaffold/app/frontend/src/graphql/index.ts +15 -0
  549. package/templates/scaffold/app/frontend/src/index.css +5 -0
  550. package/templates/scaffold/app/frontend/src/lib/auth-client.ts +17 -0
  551. package/templates/scaffold/app/frontend/src/lib/utils.ts +6 -0
  552. package/templates/scaffold/app/frontend/src/main.tsx +10 -0
  553. package/templates/scaffold/app/frontend/src/pages/page.tsx +20 -0
  554. package/templates/scaffold/app/frontend/src/pages/user-management/page.tsx +19 -0
  555. package/templates/scaffold/app/frontend/src/pages/user-management/profile/page.tsx +97 -0
  556. package/templates/scaffold/app/frontend/src/pages/user-management/user/[id]/components/user-detail.tsx +58 -0
  557. package/templates/scaffold/app/frontend/src/pages/user-management/user/[id]/page.tsx +51 -0
  558. package/templates/scaffold/app/frontend/src/pages/user-management/user/components/users-table.tsx +101 -0
  559. package/templates/scaffold/app/frontend/src/pages/user-management/user/create/components/create-user-form.tsx +99 -0
  560. package/templates/scaffold/app/frontend/src/pages/user-management/user/create/page.tsx +19 -0
  561. package/templates/scaffold/app/frontend/src/pages/user-management/user/page.tsx +61 -0
  562. package/templates/scaffold/app/frontend/src/providers/graphql-provider.tsx +21 -0
  563. package/templates/scaffold/app/frontend/tsconfig.app.json +35 -0
  564. package/templates/scaffold/app/frontend/tsconfig.json +16 -0
  565. package/templates/scaffold/app/frontend/tsconfig.node.json +23 -0
  566. package/templates/scaffold/app/frontend/vite.config.ts +23 -0
  567. package/templates/scaffold/module/command/.gitkeep +0 -0
  568. package/templates/scaffold/module/db/.gitkeep +0 -0
  569. package/templates/scaffold/module/executor/.gitkeep +0 -0
  570. package/templates/scaffold/module/generated/.gitkeep +0 -0
  571. package/templates/scaffold/module/index.ts +2 -0
  572. package/templates/scaffold/module/lib/errors.ts +1 -0
  573. package/templates/scaffold/module/lib/types.ts +4 -0
  574. package/templates/scaffold/module/module.ts +7 -0
  575. package/templates/scaffold/module/permissions.ts +3 -0
  576. package/templates/scaffold/module/query/.gitkeep +0 -0
  577. package/templates/scaffold/module/tailor.config.ts +13 -0
  578. package/templates/scaffold/module/testing/fixtures.ts +1 -0
  579. package/templates/workflows/erp-kit-check.yml +37 -0
  580. package/dist/cli.js +0 -1654
  581. package/skills/erp-kit-app-2-breakdown/SKILL.md +0 -88
  582. package/skills/erp-kit-app-3-doc-review/SKILL.md +0 -112
  583. package/skills/erp-kit-app-4-impl-spec/SKILL.md +0 -116
  584. package/skills/erp-kit-app-5-implementation/references/backend.md +0 -232
  585. package/skills/erp-kit-module-1-docs/SKILL.md +0 -111
  586. package/skills/erp-kit-module-2-feature-breakdown/SKILL.md +0 -76
  587. package/skills/erp-kit-module-3-doc-review/SKILL.md +0 -294
  588. package/skills/erp-kit-module-4-tdd/SKILL.md +0 -94
  589. package/skills/erp-kit-module-4-tdd/references/exports.md +0 -8
  590. package/skills/erp-kit-module-5-impl-review/SKILL.md +0 -410
  591. package/src/commands/scaffold-templates.ts +0 -65
  592. package/src/modules/shared/index.ts +0 -1
  593. package/src/modules/user-management/command/logAuditEvent.generated.ts +0 -6
  594. package/src/modules/user-management/command/logAuditEvent.test.ts +0 -187
  595. package/src/modules/user-management/command/logAuditEvent.ts +0 -56
  596. package/src/modules/user-management/db/auditEvent.ts +0 -47
  597. package/src/modules/user-management/docs/commands/LogAuditEvent.md +0 -37
  598. package/src/modules/user-management/docs/features/audit-trail.md +0 -80
  599. package/src/modules/user-management/docs/models/AuditEvent.md +0 -36
  600. /package/skills/{erp-kit-module-2-feature-breakdown → erp-kit-module-3-plan}/references/naming.md +0 -0
  601. /package/skills/{erp-kit-module-4-tdd → erp-kit-module-5-impl}/references/cross-module-dependency.md +0 -0
  602. /package/skills/{erp-kit-module-4-tdd → erp-kit-module-5-impl}/references/db-relations.md +0 -0
  603. /package/skills/{erp-kit-module-4-tdd → erp-kit-module-5-impl}/references/generated-code.md +0 -0
  604. /package/skills/{erp-kit-module-4-tdd → erp-kit-module-5-impl}/references/models.md +0 -0
  605. /package/skills/{erp-kit-module-5-impl-review → erp-kit-module-6-impl-review}/references/commands.md +0 -0
  606. /package/skills/{erp-kit-module-5-impl-review → erp-kit-module-6-impl-review}/references/testing.md +0 -0
  607. /package/src/modules/{product-management → audit}/.gitkeep +0 -0
  608. /package/src/{modules/shared → shared}/createContext.test.ts +0 -0
  609. /package/src/{modules/shared → shared}/createContext.ts +0 -0
  610. /package/src/{modules/shared → shared}/definePermissions.test.ts +0 -0
  611. /package/src/{modules/shared → shared}/definePermissions.ts +0 -0
  612. /package/src/{modules/shared → shared}/defineQuery.test.ts +0 -0
  613. /package/src/{modules/shared → shared}/defineQuery.ts +0 -0
  614. /package/src/{modules/shared → shared}/entityTypes.ts +0 -0
  615. /package/src/{modules/shared → shared}/errors.ts +0 -0
  616. /package/src/{modules/shared → shared}/requirePermission.test.ts +0 -0
  617. /package/src/{modules/shared → shared}/requirePermission.ts +0 -0
  618. /package/src/{modules/shared → shared}/result.ts +0 -0
@@ -1,4 +1,4 @@
1
- import type { ReadonlyDB, QueryContext } from "../../shared/internal";
1
+ import { ok, err, type ReadonlyDB, type QueryContext } from "../../../shared";
2
2
  import type { DB } from "../generated/kysely-tailordb";
3
3
  import {
4
4
  InactiveUnitError,
@@ -21,31 +21,33 @@ export interface ConvertQuantityInput {
21
21
  */
22
22
  export async function run(db: ReadonlyDB<DB>, input: ConvertQuantityInput, ctx: QueryContext) {
23
23
  // Validate source unit exists
24
- const { unit: sourceUnit } = await getUnit(db, { symbol: input.sourceUnitSymbol }, ctx);
24
+ const { unit: sourceUnit } = (await getUnit(db, { symbol: input.sourceUnitSymbol }, ctx)).value;
25
25
 
26
26
  if (!sourceUnit) {
27
- throw new UnitNotFoundError(input.sourceUnitSymbol);
27
+ return err(new UnitNotFoundError(input.sourceUnitSymbol));
28
28
  }
29
29
 
30
30
  // Validate target unit exists
31
- const { unit: targetUnit } = await getUnit(db, { symbol: input.targetUnitSymbol }, ctx);
31
+ const { unit: targetUnit } = (await getUnit(db, { symbol: input.targetUnitSymbol }, ctx)).value;
32
32
 
33
33
  if (!targetUnit) {
34
- throw new UnitNotFoundError(input.targetUnitSymbol);
34
+ return err(new UnitNotFoundError(input.targetUnitSymbol));
35
35
  }
36
36
 
37
37
  // Validate both units are active
38
38
  if (!sourceUnit.isActive) {
39
- throw new InactiveUnitError(input.sourceUnitSymbol);
39
+ return err(new InactiveUnitError(input.sourceUnitSymbol));
40
40
  }
41
41
 
42
42
  if (!targetUnit.isActive) {
43
- throw new InactiveUnitError(input.targetUnitSymbol);
43
+ return err(new InactiveUnitError(input.targetUnitSymbol));
44
44
  }
45
45
 
46
46
  // Validate units belong to the same category
47
47
  if (sourceUnit.categoryId !== targetUnit.categoryId) {
48
- throw new IncompatibleUnitsError(`${input.sourceUnitSymbol} and ${input.targetUnitSymbol}`);
48
+ return err(
49
+ new IncompatibleUnitsError(`${input.sourceUnitSymbol} and ${input.targetUnitSymbol}`),
50
+ );
49
51
  }
50
52
 
51
53
  // Perform conversion: result = quantity * sourceConversionFactor / targetConversionFactor
@@ -55,9 +57,9 @@ export async function run(db: ReadonlyDB<DB>, input: ConvertQuantityInput, ctx:
55
57
  const roundingFactor = Math.pow(10, targetUnit.roundingPrecision);
56
58
  const convertedQuantity = Math.round(rawResult * roundingFactor) / roundingFactor;
57
59
 
58
- return {
60
+ return ok({
59
61
  convertedQuantity,
60
62
  sourceUnit,
61
63
  targetUnit,
62
- };
64
+ });
63
65
  }
@@ -1,5 +1,5 @@
1
1
  // @generated — do not edit
2
- import { defineQuery } from "../../shared/internal";
2
+ import { defineQuery } from "../../../shared";
3
3
  import { run } from "./getBaseCurrency";
4
4
 
5
5
  export const getBaseCurrency = defineQuery(run);
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { createMockDb } from "../../testing/index";
2
+ import { createMockDb } from "../../../testing/index";
3
3
  import type { DB } from "../generated/kysely-tailordb";
4
- import type { QueryContext } from "../../shared/internal";
4
+ import type { QueryContext } from "../../../shared";
5
5
  import { baseCurrencyUSD } from "../testing/fixtures";
6
6
  import { getBaseCurrency } from "./getBaseCurrency.generated";
7
7
 
@@ -14,7 +14,10 @@ describe("getBaseCurrency", () => {
14
14
 
15
15
  const result = await getBaseCurrency(db, undefined, ctx);
16
16
 
17
- expect(result.currency).toEqual(baseCurrencyUSD);
17
+ expect(result.ok).toBe(true);
18
+ if (result.ok) {
19
+ expect(result.value.currency).toEqual(baseCurrencyUSD);
20
+ }
18
21
  });
19
22
 
20
23
  it("returns null when no base currency is set", async () => {
@@ -23,6 +26,9 @@ describe("getBaseCurrency", () => {
23
26
 
24
27
  const result = await getBaseCurrency(db, undefined, ctx);
25
28
 
26
- expect(result.currency).toBeNull();
29
+ expect(result.ok).toBe(true);
30
+ if (result.ok) {
31
+ expect(result.value.currency).toBeNull();
32
+ }
27
33
  });
28
34
  });
@@ -1,4 +1,4 @@
1
- import type { ReadonlyDB } from "../../shared/internal";
1
+ import { ok, type ReadonlyDB } from "../../../shared";
2
2
  import type { DB } from "../generated/kysely-tailordb";
3
3
 
4
4
  /**
@@ -12,5 +12,5 @@ export async function run(db: ReadonlyDB<DB>) {
12
12
  .where("isBaseCurrency", "=", true)
13
13
  .executeTakeFirst();
14
14
 
15
- return { currency: currency ?? null };
15
+ return ok({ currency: currency ?? null });
16
16
  }
@@ -1,5 +1,5 @@
1
1
  // @generated — do not edit
2
- import { defineQuery } from "../../shared/internal";
2
+ import { defineQuery } from "../../../shared";
3
3
  import { run } from "./getCurrency";
4
4
 
5
5
  export const getCurrency = defineQuery(run);
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { createMockDb } from "../../testing/index";
2
+ import { createMockDb } from "../../../testing/index";
3
3
  import type { DB } from "../generated/kysely-tailordb";
4
4
  import { baseCurrencyUSD } from "../testing/fixtures";
5
5
  import { run } from "./getCurrency";
@@ -12,7 +12,10 @@ describe("getCurrency", () => {
12
12
 
13
13
  const result = await run(db, { id: "currency-usd" });
14
14
 
15
- expect(result.currency).toEqual(baseCurrencyUSD);
15
+ expect(result.ok).toBe(true);
16
+ if (result.ok) {
17
+ expect(result.value.currency).toEqual(baseCurrencyUSD);
18
+ }
16
19
  });
17
20
 
18
21
  it("returns null when currency not found", async () => {
@@ -21,7 +24,10 @@ describe("getCurrency", () => {
21
24
 
22
25
  const result = await run(db, { id: "nonexistent" });
23
26
 
24
- expect(result.currency).toBeNull();
27
+ expect(result.ok).toBe(true);
28
+ if (result.ok) {
29
+ expect(result.value.currency).toBeNull();
30
+ }
25
31
  });
26
32
  });
27
33
 
@@ -32,7 +38,10 @@ describe("getCurrency", () => {
32
38
 
33
39
  const result = await run(db, { code: "USD" });
34
40
 
35
- expect(result.currency).toEqual(baseCurrencyUSD);
41
+ expect(result.ok).toBe(true);
42
+ if (result.ok) {
43
+ expect(result.value.currency).toEqual(baseCurrencyUSD);
44
+ }
36
45
  });
37
46
 
38
47
  it("returns null when currency not found", async () => {
@@ -41,7 +50,10 @@ describe("getCurrency", () => {
41
50
 
42
51
  const result = await run(db, { code: "NONEXISTENT" });
43
52
 
44
- expect(result.currency).toBeNull();
53
+ expect(result.ok).toBe(true);
54
+ if (result.ok) {
55
+ expect(result.value.currency).toBeNull();
56
+ }
45
57
  });
46
58
  });
47
59
  });
@@ -1,4 +1,4 @@
1
- import type { ReadonlyDB } from "../../shared/internal";
1
+ import { ok, type ReadonlyDB } from "../../../shared";
2
2
  import type { DB } from "../generated/kysely-tailordb";
3
3
 
4
4
  export type GetCurrencyInput = { id: string } | { code: string };
@@ -14,5 +14,5 @@ export async function run(db: ReadonlyDB<DB>, input: GetCurrencyInput) {
14
14
 
15
15
  const currency = await query.executeTakeFirst();
16
16
 
17
- return { currency: currency ?? null };
17
+ return ok({ currency: currency ?? null });
18
18
  }
@@ -1,5 +1,5 @@
1
1
  // @generated — do not edit
2
- import { defineQuery } from "../../shared/internal";
2
+ import { defineQuery } from "../../../shared";
3
3
  import { run } from "./getUnit";
4
4
 
5
5
  export const getUnit = defineQuery(run);
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { createMockDb } from "../../testing/index";
2
+ import { createMockDb } from "../../../testing/index";
3
3
  import type { DB } from "../generated/kysely-tailordb";
4
4
  import { baseUnitKg } from "../testing/fixtures";
5
5
  import { run } from "./getUnit";
@@ -12,7 +12,10 @@ describe("getUnit", () => {
12
12
 
13
13
  const result = await run(db, { id: "unit-kg" });
14
14
 
15
- expect(result.unit).toEqual(baseUnitKg);
15
+ expect(result.ok).toBe(true);
16
+ if (result.ok) {
17
+ expect(result.value.unit).toEqual(baseUnitKg);
18
+ }
16
19
  });
17
20
 
18
21
  it("returns null when unit not found", async () => {
@@ -21,7 +24,10 @@ describe("getUnit", () => {
21
24
 
22
25
  const result = await run(db, { id: "nonexistent" });
23
26
 
24
- expect(result.unit).toBeNull();
27
+ expect(result.ok).toBe(true);
28
+ if (result.ok) {
29
+ expect(result.value.unit).toBeNull();
30
+ }
25
31
  });
26
32
  });
27
33
 
@@ -32,7 +38,10 @@ describe("getUnit", () => {
32
38
 
33
39
  const result = await run(db, { symbol: "kg" });
34
40
 
35
- expect(result.unit).toEqual(baseUnitKg);
41
+ expect(result.ok).toBe(true);
42
+ if (result.ok) {
43
+ expect(result.value.unit).toEqual(baseUnitKg);
44
+ }
36
45
  });
37
46
 
38
47
  it("returns null when unit not found", async () => {
@@ -41,7 +50,10 @@ describe("getUnit", () => {
41
50
 
42
51
  const result = await run(db, { symbol: "nonexistent" });
43
52
 
44
- expect(result.unit).toBeNull();
53
+ expect(result.ok).toBe(true);
54
+ if (result.ok) {
55
+ expect(result.value.unit).toBeNull();
56
+ }
45
57
  });
46
58
  });
47
59
  });
@@ -1,4 +1,4 @@
1
- import type { ReadonlyDB } from "../../shared/internal";
1
+ import { ok, type ReadonlyDB } from "../../../shared";
2
2
  import type { DB } from "../generated/kysely-tailordb";
3
3
 
4
4
  export type GetUnitInput = { id: string } | { symbol: string };
@@ -14,5 +14,5 @@ export async function run(db: ReadonlyDB<DB>, input: GetUnitInput) {
14
14
 
15
15
  const unit = await query.executeTakeFirst();
16
16
 
17
- return { unit: unit ?? null };
17
+ return ok({ unit: unit ?? null });
18
18
  }
@@ -1,5 +1,5 @@
1
1
  // @generated — do not edit
2
- import { defineQuery } from "../../shared/internal";
2
+ import { defineQuery } from "../../../shared";
3
3
  import { run } from "./getUoMCategory";
4
4
 
5
5
  export const getUoMCategory = defineQuery(run);
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { createMockDb } from "../../testing/index";
2
+ import { createMockDb } from "../../../testing/index";
3
3
  import type { DB } from "../generated/kysely-tailordb";
4
4
  import { baseUoMCategory } from "../testing/fixtures";
5
5
  import { run } from "./getUoMCategory";
@@ -12,7 +12,10 @@ describe("getUoMCategory", () => {
12
12
 
13
13
  const result = await run(db, { id: "category-1" });
14
14
 
15
- expect(result.uoMCategory).toEqual(baseUoMCategory);
15
+ expect(result.ok).toBe(true);
16
+ if (result.ok) {
17
+ expect(result.value.uoMCategory).toEqual(baseUoMCategory);
18
+ }
16
19
  });
17
20
 
18
21
  it("returns null when category not found", async () => {
@@ -21,7 +24,10 @@ describe("getUoMCategory", () => {
21
24
 
22
25
  const result = await run(db, { id: "nonexistent" });
23
26
 
24
- expect(result.uoMCategory).toBeNull();
27
+ expect(result.ok).toBe(true);
28
+ if (result.ok) {
29
+ expect(result.value.uoMCategory).toBeNull();
30
+ }
25
31
  });
26
32
  });
27
33
 
@@ -32,7 +38,10 @@ describe("getUoMCategory", () => {
32
38
 
33
39
  const result = await run(db, { name: "Weight" });
34
40
 
35
- expect(result.uoMCategory).toEqual(baseUoMCategory);
41
+ expect(result.ok).toBe(true);
42
+ if (result.ok) {
43
+ expect(result.value.uoMCategory).toEqual(baseUoMCategory);
44
+ }
36
45
  });
37
46
 
38
47
  it("returns null when category not found", async () => {
@@ -41,7 +50,10 @@ describe("getUoMCategory", () => {
41
50
 
42
51
  const result = await run(db, { name: "Nonexistent" });
43
52
 
44
- expect(result.uoMCategory).toBeNull();
53
+ expect(result.ok).toBe(true);
54
+ if (result.ok) {
55
+ expect(result.value.uoMCategory).toBeNull();
56
+ }
45
57
  });
46
58
  });
47
59
  });
@@ -1,4 +1,4 @@
1
- import type { ReadonlyDB } from "../../shared/internal";
1
+ import { ok, type ReadonlyDB } from "../../../shared";
2
2
  import type { DB } from "../generated/kysely-tailordb";
3
3
 
4
4
  export type GetUoMCategoryInput = { id: string } | { name: string };
@@ -14,5 +14,5 @@ export async function run(db: ReadonlyDB<DB>, input: GetUoMCategoryInput) {
14
14
 
15
15
  const uoMCategory = await query.executeTakeFirst();
16
16
 
17
- return { uoMCategory: uoMCategory ?? null };
17
+ return ok({ uoMCategory: uoMCategory ?? null });
18
18
  }
@@ -1,5 +1,5 @@
1
1
  // @generated — do not edit
2
- import { defineQuery } from "../../shared/internal";
2
+ import { defineQuery } from "../../../shared";
3
3
  import { run } from "./listUnitsByCategory";
4
4
 
5
5
  export const listUnitsByCategory = defineQuery(run);
@@ -0,0 +1,80 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../../testing/index";
3
+ import type { DB } from "../generated/kysely-tailordb";
4
+ import { baseUnitKg, baseUnitGram, baseUnitPound } from "../testing/fixtures";
5
+ import { run } from "./listUnitsByCategory";
6
+
7
+ describe("listUnitsByCategory", () => {
8
+ it("returns paginated units with default page size", async () => {
9
+ const { db, spies } = createMockDb<DB>();
10
+ spies.select.mockReturnValue([baseUnitKg, baseUnitGram]);
11
+
12
+ const result = await run(db, { categoryId: "category-1" });
13
+
14
+ expect(result.ok).toBe(true);
15
+ if (result.ok) {
16
+ expect(result.value.items).toEqual([baseUnitKg, baseUnitGram]);
17
+ expect(result.value.hasNextPage).toBe(false);
18
+ }
19
+ });
20
+
21
+ it("returns hasNextPage true when more results exist", async () => {
22
+ const { db, spies } = createMockDb<DB>();
23
+ // Simulate limit+1 rows returned (3 rows for limit=2)
24
+ spies.select.mockReturnValue([baseUnitKg, baseUnitGram, baseUnitPound]);
25
+
26
+ const result = await run(db, { categoryId: "category-1", limit: 2 });
27
+
28
+ expect(result.ok).toBe(true);
29
+ if (result.ok) {
30
+ expect(result.value.items).toHaveLength(2);
31
+ expect(result.value.hasNextPage).toBe(true);
32
+ }
33
+ });
34
+
35
+ it("returns empty result when no units match", async () => {
36
+ const { db, spies } = createMockDb<DB>();
37
+ spies.select.mockReturnValue([]);
38
+
39
+ const result = await run(db, { categoryId: "nonexistent" });
40
+
41
+ expect(result.ok).toBe(true);
42
+ if (result.ok) {
43
+ expect(result.value.items).toEqual([]);
44
+ expect(result.value.hasNextPage).toBe(false);
45
+ }
46
+ });
47
+
48
+ it("respects custom limit and offset", async () => {
49
+ const { db, spies } = createMockDb<DB>();
50
+ spies.select.mockReturnValue([baseUnitGram]);
51
+
52
+ const result = await run(db, {
53
+ categoryId: "category-1",
54
+ limit: 1,
55
+ offset: 1,
56
+ });
57
+
58
+ expect(result.ok).toBe(true);
59
+ if (result.ok) {
60
+ expect(result.value.items).toEqual([baseUnitGram]);
61
+ expect(result.value.hasNextPage).toBe(false);
62
+ }
63
+ });
64
+
65
+ it("accepts orderBy and orderDirection", async () => {
66
+ const { db, spies } = createMockDb<DB>();
67
+ spies.select.mockReturnValue([baseUnitGram, baseUnitKg]);
68
+
69
+ const result = await run(db, {
70
+ categoryId: "category-1",
71
+ orderBy: "name",
72
+ orderDirection: "desc",
73
+ });
74
+
75
+ expect(result.ok).toBe(true);
76
+ if (result.ok) {
77
+ expect(result.value.items).toEqual([baseUnitGram, baseUnitKg]);
78
+ }
79
+ });
80
+ });
@@ -1,16 +1,32 @@
1
- import type { ReadonlyDB } from "../../shared/internal";
1
+ import {
2
+ ok,
3
+ type ReadonlyDB,
4
+ type PaginationInput,
5
+ buildPaginatedResult,
6
+ DEFAULT_PAGE_SIZE,
7
+ } from "../../../shared";
2
8
  import type { DB } from "../generated/kysely-tailordb";
3
9
 
4
- export interface ListUnitsByCategoryInput {
10
+ type UnitOrderByField = "name" | "symbol" | "createdAt";
11
+
12
+ export interface ListUnitsByCategoryInput extends PaginationInput<UnitOrderByField> {
5
13
  categoryId: string;
6
14
  }
7
15
 
8
16
  export async function run(db: ReadonlyDB<DB>, input: ListUnitsByCategoryInput) {
17
+ const limit = input.limit ?? DEFAULT_PAGE_SIZE;
18
+ const offset = input.offset ?? 0;
19
+ const orderBy = input.orderBy ?? "id";
20
+ const orderDirection = input.orderDirection ?? "asc";
21
+
9
22
  const units = await db
10
23
  .selectFrom("Unit")
11
24
  .selectAll()
12
25
  .where("categoryId", "=", input.categoryId)
26
+ .orderBy(orderBy, orderDirection)
27
+ .limit(limit + 1)
28
+ .offset(offset)
13
29
  .execute();
14
30
 
15
- return { units };
31
+ return ok(buildPaginatedResult(units, limit));
16
32
  }
@@ -1,11 +1,13 @@
1
- import { defineConfig, defineGenerators } from "@tailor-platform/sdk";
1
+ import { defineConfig, definePlugins } from "@tailor-platform/sdk";
2
+ import { kyselyTypePlugin } from "@tailor-platform/sdk/plugin/kysely-type";
3
+ import { enumConstantsPlugin } from "@tailor-platform/sdk/plugin/enum-constants";
2
4
 
3
5
  export default defineConfig({
4
6
  name: "primitives",
5
7
  db: { "main-db": { files: [`./db/*.ts`] } },
6
8
  });
7
9
 
8
- export const generators = defineGenerators(
9
- ["@tailor-platform/kysely-type", { distPath: `./generated/kysely-tailordb.ts` }],
10
- ["@tailor-platform/enum-constants", { distPath: "./generated/enums.ts" }],
10
+ export const plugins = definePlugins(
11
+ kyselyTypePlugin({ distPath: `./generated/kysely-tailordb.ts` }),
12
+ enumConstantsPlugin({ distPath: "./generated/enums.ts" }),
11
13
  );
@@ -0,0 +1,13 @@
1
+ // This file is auto-generated by @tailor-platform/sdk
2
+ // Do not edit this file manually
3
+ // Regenerated automatically when running 'tailor-sdk apply' or 'tailor-sdk generate'
4
+
5
+ declare module "@tailor-platform/sdk" {
6
+ interface AttributeMap {}
7
+ interface AttributeList {
8
+ __tuple?: [];
9
+ }
10
+ interface Env {}
11
+ }
12
+
13
+ export {};
@@ -0,0 +1,52 @@
1
+ # README
2
+
3
+ ## Overview
4
+
5
+ The Product Management module serves as the Product Information Management (PIM) layer of the ERP system. It manages products, attributes, and variant generation. A product defines the commercial representation of a product — its name, description, attributes, and category classification. Variants are generated from attribute value combinations (e.g., Color × Size) and materialize as Items in the item-management module.
6
+
7
+ ## Key Features
8
+
9
+ - **[Product Lifecycle](docs/features/product-lifecycle.md)**: Create, update, and manage products with lifecycle state machine (DRAFT → ACTIVE ↔ ARCHIVED). Products define the commercial view of a product and serve as the parent entity for variant generation
10
+ - **[Attribute Management](docs/features/attribute-management.md)**: Define attributes and their values. All attributes are variant axes that drive variant generation
11
+ - **[Variant Generation](docs/features/variant-generation.md)**: Generate product variants from attribute value combinations on a product. Each generated variant creates an Item in item-management with auto-generated SKU and inherited properties
12
+ - **[Product Category](docs/features/product-category.md)**: Hierarchical category tree for product classification (many-to-many). Separate from item-management's taxonomy — categories organize the commercial/marketing view of products
13
+
14
+ ## Module Scope
15
+
16
+ ### In Scope
17
+
18
+ - Product master data management (create, update, delete, status transitions)
19
+ - Product lifecycle state machine (DRAFT → ACTIVE ↔ ARCHIVED)
20
+ - Attribute definitions with predefined values
21
+ - Variant generation from attribute value combinations
22
+ - Item creation in item-management upon variant generation
23
+ - Hierarchical product category management
24
+ - Product-to-category classification (many-to-many)
25
+
26
+ ### Out of Scope
27
+
28
+ - SKU-level item management and item lifecycle (item-management module)
29
+ - Unit of measure definitions (primitives module)
30
+ - Sales pricing, price lists, and discount rules (pricing module)
31
+ - Channel/marketplace definitions and listing management (sales-channel module)
32
+ - Inventory tracking and stock levels (inventory module)
33
+ - Product images and digital asset management
34
+ - Supplier-specific product information (supplier-management module)
35
+ - Bill of Materials (manufacturing module)
36
+
37
+ ### Scope Decision Rationale
38
+
39
+ This module focuses on the **commercial definition** of products — the "what we sell" perspective — while delegating operational concerns to specialized modules. Product-management owns the template layer (attributes, variants, categories) because these define the product's identity and structure before it enters any operational workflow.
40
+
41
+ SKU-level management belongs to item-management because items have their own lifecycle and are the transactional entity referenced by sales, purchasing, and inventory. Variant generation bridges the two: product-management defines the combinations, but the resulting items live in item-management. This separation ensures that changes to product templates don't directly affect in-flight transactions.
42
+
43
+ Pricing is excluded because prices are context-dependent — they vary by customer segment, quantity tier, date range, and promotional rules. A single product can have dozens of price points that change frequently, while the product definition itself is stable. Embedding pricing here would force product-management to understand sales contexts it shouldn't own. A dedicated pricing module can attach price lists to items independently and evolve its discount/tier logic without touching the product catalog.
44
+
45
+ Channel/marketplace management is excluded because listing a product on a sales channel involves channel-specific data (listing status, channel fees, fulfillment rules, channel-specific descriptions) that are not part of the product's core identity. A product's definition is channel-agnostic — the same product may be listed differently on each channel. Coupling channels to product-management would create a dependency on external marketplace APIs and business rules that change per channel integration.
46
+
47
+ Inventory and supplier data are similarly excluded because they follow independent business rules and change at different rates than product definitions.
48
+
49
+ ## Module Dependencies
50
+
51
+ - [item-management](../item-management/README.md) — Variant generation creates Items via item-management commands
52
+ - [primitives](../primitives/README.md) — UoM definitions inherited by generated Items
@@ -0,0 +1,6 @@
1
+ // @generated — do not edit
2
+ import { defineCommand } from "../../../shared";
3
+ import { permissions } from "../lib/permissions.generated";
4
+ import { run } from "./activateProduct";
5
+
6
+ export const activateProduct = defineCommand(permissions.activateProduct, run);
@@ -0,0 +1,40 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../../testing/index";
3
+ import type { Transaction } from "../generated/kysely-tailordb";
4
+ import { InvalidStateTransitionError, ProductNotFoundError } from "../lib/errors.generated";
5
+ import { baseActiveProduct, baseDraftProduct } from "../testing/fixtures";
6
+ import { run } from "./activateProduct";
7
+
8
+ describe("activateProduct", () => {
9
+ it("returns error when product not found", async () => {
10
+ const { db, spies } = createMockDb<Transaction>();
11
+ spies.select.mockReturnValueOnce(undefined);
12
+ const result = await run(db, { id: "nonexistent" });
13
+ expect(result.ok).toBe(false);
14
+ if (!result.ok) {
15
+ expect(result.error).toBeInstanceOf(ProductNotFoundError);
16
+ }
17
+ });
18
+
19
+ it("returns error when not in DRAFT status", async () => {
20
+ const { db, spies } = createMockDb<Transaction>();
21
+ spies.select.mockReturnValueOnce({ ...baseActiveProduct });
22
+ const result = await run(db, { id: "product-2" });
23
+ expect(result.ok).toBe(false);
24
+ if (!result.ok) {
25
+ expect(result.error).toBeInstanceOf(InvalidStateTransitionError);
26
+ }
27
+ });
28
+
29
+ it("activates DRAFT product to ACTIVE", async () => {
30
+ const { db, spies } = createMockDb<Transaction>();
31
+ const activated = { ...baseDraftProduct, status: "ACTIVE" };
32
+ spies.select.mockReturnValueOnce({ ...baseDraftProduct });
33
+ spies.update.mockReturnValueOnce(activated);
34
+ const result = await run(db, { id: "product-1" });
35
+ expect(result.ok).toBe(true);
36
+ if (result.ok) {
37
+ expect(result.value.product.status).toBe("ACTIVE");
38
+ }
39
+ });
40
+ });
@@ -0,0 +1,42 @@
1
+ import { ok, err } from "../../../shared";
2
+ import { Transaction } from "../generated/kysely-tailordb";
3
+ import { ProductNotFoundError, InvalidStateTransitionError } from "../lib/errors.generated";
4
+
5
+ export interface ActivateProductInput {
6
+ id: string;
7
+ from?: string[];
8
+ }
9
+
10
+ /**
11
+ * Function: activateProduct
12
+ *
13
+ * Transitions a product from DRAFT to ACTIVE.
14
+ */
15
+ export async function run(db: Transaction, input: ActivateProductInput) {
16
+ const { id } = input;
17
+ const validFrom = input.from ?? ["DRAFT"];
18
+
19
+ const product = await db
20
+ .selectFrom("Product")
21
+ .selectAll()
22
+ .where("id", "=", id)
23
+ .forUpdate()
24
+ .executeTakeFirst();
25
+
26
+ if (!product) {
27
+ return err(new ProductNotFoundError(id));
28
+ }
29
+
30
+ if (!validFrom.includes(product.status)) {
31
+ return err(new InvalidStateTransitionError(id));
32
+ }
33
+
34
+ const updated = await db
35
+ .updateTable("Product")
36
+ .set({ status: "ACTIVE", updatedAt: new Date() })
37
+ .where("id", "=", id)
38
+ .returningAll()
39
+ .executeTakeFirst();
40
+
41
+ return ok({ product: updated! });
42
+ }
@@ -0,0 +1,6 @@
1
+ // @generated — do not edit
2
+ import { defineCommand } from "../../../shared";
3
+ import { permissions } from "../lib/permissions.generated";
4
+ import { run } from "./assignProductToCategory";
5
+
6
+ export const assignProductToCategory = defineCommand(permissions.assignProductToCategory, run);