@tailor-platform/erp-kit 0.1.1 → 0.2.0

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 (342) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +158 -62
  3. package/dist/cli.js +1010 -270
  4. package/package.json +11 -8
  5. package/schemas/module/command.yml +1 -0
  6. package/schemas/module/model.yml +14 -0
  7. package/schemas/module/query.yml +53 -0
  8. package/skills/{app-compose-1-requirement-analysis → erp-kit-app-1-requirements}/SKILL.md +2 -2
  9. package/skills/{app-compose-2-requirements-breakdown → erp-kit-app-2-breakdown}/SKILL.md +3 -3
  10. package/skills/{app-compose-3-doc-review → erp-kit-app-3-doc-review}/SKILL.md +2 -2
  11. package/skills/{app-compose-4-design-mock → erp-kit-app-4-design}/SKILL.md +3 -3
  12. package/skills/{app-compose-5-design-mock-review → erp-kit-app-5-design-review}/SKILL.md +4 -4
  13. package/skills/{app-compose-6-implementation-spec → erp-kit-app-6-impl-spec}/SKILL.md +3 -3
  14. package/skills/{mock-scenario → erp-kit-mock-scenario}/SKILL.md +1 -1
  15. package/skills/{1-module-docs → erp-kit-module-1-docs}/SKILL.md +2 -2
  16. package/skills/{2-module-feature-breakdown → erp-kit-module-2-feature-breakdown}/SKILL.md +13 -9
  17. package/skills/erp-kit-module-2-feature-breakdown/references/naming.md +59 -0
  18. package/skills/{3-module-doc-review → erp-kit-module-3-doc-review}/SKILL.md +83 -25
  19. package/skills/erp-kit-module-4-tdd/SKILL.md +94 -0
  20. package/skills/erp-kit-module-4-tdd/references/cross-module-dependency.md +133 -0
  21. package/skills/{4-module-tdd-implementation → erp-kit-module-4-tdd}/references/db-relations.md +5 -1
  22. package/skills/{4-module-tdd-implementation → erp-kit-module-4-tdd}/references/exports.md +1 -1
  23. package/skills/erp-kit-module-4-tdd/references/generated-code.md +32 -0
  24. package/skills/{5-module-implementation-review → erp-kit-module-5-impl-review}/SKILL.md +46 -44
  25. package/skills/erp-kit-module-5-impl-review/references/commands.md +62 -0
  26. package/skills/erp-kit-module-5-impl-review/references/errors.md +10 -0
  27. package/skills/{5-module-implementation-review → erp-kit-module-5-impl-review}/references/testing.md +1 -1
  28. package/skills/erp-kit-module-shared/SKILL.md +16 -0
  29. package/skills/erp-kit-module-shared/references/commands.md +203 -0
  30. package/skills/erp-kit-module-shared/references/errors.md +35 -0
  31. package/skills/erp-kit-module-shared/references/queries.md +168 -0
  32. package/skills/erp-kit-module-shared/references/structure.md +36 -0
  33. package/skills/{3-module-doc-review → erp-kit-module-shared}/references/testing.md +4 -3
  34. package/skills/erp-kit-update/SKILL.md +64 -0
  35. package/src/cli.doc.test.ts +65 -0
  36. package/src/cli.ts +3 -117
  37. package/src/commands/app/index.ts +74 -0
  38. package/src/commands/check.test.ts +3 -2
  39. package/src/commands/check.ts +3 -2
  40. package/src/commands/index.ts +73 -0
  41. package/src/commands/init.test.ts +22 -5
  42. package/src/commands/init.ts +25 -16
  43. package/src/commands/license.ts +193 -0
  44. package/src/commands/mock/index.ts +2 -2
  45. package/src/commands/mock/start.ts +1 -1
  46. package/src/commands/mock/validate.test.ts +1 -1
  47. package/src/commands/module/generate.ts +35 -0
  48. package/src/commands/module/index.ts +87 -0
  49. package/src/commands/module/list.test.ts +57 -0
  50. package/src/commands/module/list.ts +64 -0
  51. package/src/commands/scaffold-templates.ts +65 -0
  52. package/src/commands/scaffold.test.ts +97 -2
  53. package/src/commands/scaffold.ts +24 -3
  54. package/src/commands/sync-check.test.ts +88 -1
  55. package/src/commands/sync-check.ts +41 -2
  56. package/src/generator/generate-code.test.ts +200 -0
  57. package/src/generator/generate-code.ts +260 -0
  58. package/src/generator/parse-command-doc.test.ts +159 -0
  59. package/src/generator/parse-command-doc.ts +116 -0
  60. package/src/integration.test.ts +6 -8
  61. package/src/module.ts +10 -9
  62. package/src/modules/item-management/README.md +38 -0
  63. package/src/modules/item-management/command/activateItem.generated.ts +6 -0
  64. package/src/modules/item-management/command/activateItem.test.ts +76 -0
  65. package/src/modules/item-management/command/activateItem.ts +42 -0
  66. package/src/modules/item-management/command/assignItemToTaxonomy.generated.ts +6 -0
  67. package/src/modules/item-management/command/assignItemToTaxonomy.test.ts +88 -0
  68. package/src/modules/item-management/command/assignItemToTaxonomy.ts +63 -0
  69. package/src/modules/item-management/command/createItem.generated.ts +6 -0
  70. package/src/modules/item-management/command/createItem.test.ts +152 -0
  71. package/src/modules/item-management/command/createItem.ts +72 -0
  72. package/src/modules/item-management/command/createTaxonomyNode.generated.ts +6 -0
  73. package/src/modules/item-management/command/createTaxonomyNode.test.ts +126 -0
  74. package/src/modules/item-management/command/createTaxonomyNode.ts +70 -0
  75. package/src/modules/item-management/command/deactivateItem.generated.ts +6 -0
  76. package/src/modules/item-management/command/deactivateItem.test.ts +76 -0
  77. package/src/modules/item-management/command/deactivateItem.ts +42 -0
  78. package/src/modules/item-management/command/deleteItem.generated.ts +6 -0
  79. package/src/modules/item-management/command/deleteItem.test.ts +61 -0
  80. package/src/modules/item-management/command/deleteItem.ts +38 -0
  81. package/src/modules/item-management/command/deleteTaxonomyNode.generated.ts +6 -0
  82. package/src/modules/item-management/command/deleteTaxonomyNode.test.ts +73 -0
  83. package/src/modules/item-management/command/deleteTaxonomyNode.ts +50 -0
  84. package/src/modules/item-management/command/moveTaxonomyNode.generated.ts +6 -0
  85. package/src/modules/item-management/command/moveTaxonomyNode.test.ts +136 -0
  86. package/src/modules/item-management/command/moveTaxonomyNode.ts +85 -0
  87. package/src/modules/item-management/command/reactivateItem.generated.ts +6 -0
  88. package/src/modules/item-management/command/reactivateItem.test.ts +76 -0
  89. package/src/modules/item-management/command/reactivateItem.ts +42 -0
  90. package/src/modules/item-management/command/removeItemFromTaxonomy.generated.ts +6 -0
  91. package/src/modules/item-management/command/removeItemFromTaxonomy.test.ts +43 -0
  92. package/src/modules/item-management/command/removeItemFromTaxonomy.ts +30 -0
  93. package/src/modules/item-management/command/updateItem.generated.ts +6 -0
  94. package/src/modules/item-management/command/updateItem.test.ts +178 -0
  95. package/src/modules/item-management/command/updateItem.ts +103 -0
  96. package/src/modules/item-management/command/updateTaxonomyNode.generated.ts +6 -0
  97. package/src/modules/item-management/command/updateTaxonomyNode.test.ts +88 -0
  98. package/src/modules/item-management/command/updateTaxonomyNode.ts +62 -0
  99. package/src/modules/item-management/db/item.ts +47 -0
  100. package/src/modules/item-management/db/itemTaxonomyAssignment.ts +49 -0
  101. package/src/modules/item-management/db/taxonomyNode.ts +34 -0
  102. package/src/modules/item-management/docs/commands/ActivateItem.md +32 -0
  103. package/src/modules/item-management/docs/commands/AssignItemToTaxonomy.md +38 -0
  104. package/src/modules/item-management/docs/commands/CreateItem.md +44 -0
  105. package/src/modules/item-management/docs/commands/CreateTaxonomyNode.md +44 -0
  106. package/src/modules/item-management/docs/commands/DeactivateItem.md +34 -0
  107. package/src/modules/item-management/docs/commands/DeleteItem.md +35 -0
  108. package/src/modules/item-management/docs/commands/DeleteTaxonomyNode.md +39 -0
  109. package/src/modules/item-management/docs/commands/MoveTaxonomyNode.md +45 -0
  110. package/src/modules/item-management/docs/commands/ReactivateItem.md +34 -0
  111. package/src/modules/item-management/docs/commands/RemoveItemFromTaxonomy.md +30 -0
  112. package/src/modules/item-management/docs/commands/UpdateItem.md +55 -0
  113. package/src/modules/item-management/docs/commands/UpdateTaxonomyNode.md +36 -0
  114. package/src/modules/item-management/docs/features/item-lifecycle.md +60 -0
  115. package/src/modules/item-management/docs/features/item-taxonomy.md +65 -0
  116. package/src/modules/item-management/docs/models/ItemTaxonomyAssignment.md +36 -0
  117. package/src/modules/item-management/docs/models/TaxonomyNode.md +47 -0
  118. package/src/modules/item-management/docs/models/item.md +59 -0
  119. package/src/modules/item-management/docs/queries/CalculateNodeDepth.md +36 -0
  120. package/src/modules/item-management/docs/queries/CalculateSubtreeDepth.md +40 -0
  121. package/src/modules/item-management/docs/queries/DetectCircularReference.md +41 -0
  122. package/src/modules/item-management/docs/queries/GetItem.md +38 -0
  123. package/src/modules/item-management/docs/queries/GetItemTaxonomyAssignment.md +29 -0
  124. package/src/modules/item-management/docs/queries/GetTaxonomyNode.md +35 -0
  125. package/src/modules/item-management/docs/queries/GetTaxonomyNodeAssignments.md +29 -0
  126. package/src/modules/item-management/docs/queries/GetTaxonomyNodeChildren.md +29 -0
  127. package/src/modules/item-management/generated/enums.ts +9 -0
  128. package/src/modules/item-management/generated/kysely-tailordb.ts +62 -0
  129. package/src/modules/item-management/index.ts +53 -0
  130. package/src/modules/item-management/lib/_db_deps.ts +13 -0
  131. package/src/modules/item-management/lib/errors.generated.ts +117 -0
  132. package/src/modules/item-management/lib/permissions.generated.ts +17 -0
  133. package/src/modules/item-management/lib/types.ts +19 -0
  134. package/src/modules/item-management/module.ts +97 -0
  135. package/src/modules/item-management/query/calculateNodeDepth.generated.ts +5 -0
  136. package/src/modules/item-management/query/calculateNodeDepth.test.ts +56 -0
  137. package/src/modules/item-management/query/calculateNodeDepth.ts +28 -0
  138. package/src/modules/item-management/query/calculateSubtreeDepth.generated.ts +5 -0
  139. package/src/modules/item-management/query/calculateSubtreeDepth.test.ts +75 -0
  140. package/src/modules/item-management/query/calculateSubtreeDepth.ts +29 -0
  141. package/src/modules/item-management/query/detectCircularReference.generated.ts +5 -0
  142. package/src/modules/item-management/query/detectCircularReference.test.ts +61 -0
  143. package/src/modules/item-management/query/detectCircularReference.ts +32 -0
  144. package/src/modules/item-management/query/getItem.generated.ts +5 -0
  145. package/src/modules/item-management/query/getItem.test.ts +67 -0
  146. package/src/modules/item-management/query/getItem.ts +20 -0
  147. package/src/modules/item-management/query/getItemTaxonomyAssignment.generated.ts +5 -0
  148. package/src/modules/item-management/query/getItemTaxonomyAssignment.test.ts +25 -0
  149. package/src/modules/item-management/query/getItemTaxonomyAssignment.ts +18 -0
  150. package/src/modules/item-management/query/getTaxonomyNode.generated.ts +5 -0
  151. package/src/modules/item-management/query/getTaxonomyNode.test.ts +47 -0
  152. package/src/modules/item-management/query/getTaxonomyNode.ts +18 -0
  153. package/src/modules/item-management/query/getTaxonomyNodeAssignments.generated.ts +5 -0
  154. package/src/modules/item-management/query/getTaxonomyNodeAssignments.test.ts +25 -0
  155. package/src/modules/item-management/query/getTaxonomyNodeAssignments.ts +16 -0
  156. package/src/modules/item-management/query/getTaxonomyNodeChildren.generated.ts +5 -0
  157. package/src/modules/item-management/query/getTaxonomyNodeChildren.test.ts +34 -0
  158. package/src/modules/item-management/query/getTaxonomyNodeChildren.ts +16 -0
  159. package/src/modules/item-management/tailor.config.ts +11 -0
  160. package/src/modules/item-management/testing/fixtures.ts +81 -0
  161. package/src/modules/primitives/command/activateCategory.generated.ts +6 -0
  162. package/src/modules/primitives/command/activateCategory.test.ts +11 -29
  163. package/src/modules/primitives/command/activateCategory.ts +27 -34
  164. package/src/modules/primitives/command/activateCurrency.generated.ts +6 -0
  165. package/src/modules/primitives/command/activateCurrency.test.ts +11 -29
  166. package/src/modules/primitives/command/activateCurrency.ts +27 -34
  167. package/src/modules/primitives/command/activateUnit.generated.ts +6 -0
  168. package/src/modules/primitives/command/activateUnit.test.ts +11 -15
  169. package/src/modules/primitives/command/activateUnit.ts +27 -34
  170. package/src/modules/primitives/command/createCategory.generated.ts +6 -0
  171. package/src/modules/primitives/command/createCategory.test.ts +27 -39
  172. package/src/modules/primitives/command/createCategory.ts +53 -62
  173. package/src/modules/primitives/command/createCurrency.generated.ts +6 -0
  174. package/src/modules/primitives/command/createCurrency.test.ts +78 -71
  175. package/src/modules/primitives/command/createCurrency.ts +43 -48
  176. package/src/modules/primitives/command/createExchangeRate.generated.ts +6 -0
  177. package/src/modules/primitives/command/createExchangeRate.test.ts +101 -100
  178. package/src/modules/primitives/command/createExchangeRate.ts +50 -59
  179. package/src/modules/primitives/command/createUnit.generated.ts +6 -0
  180. package/src/modules/primitives/command/createUnit.test.ts +92 -95
  181. package/src/modules/primitives/command/createUnit.ts +54 -57
  182. package/src/modules/primitives/command/deactivateCategory.generated.ts +6 -0
  183. package/src/modules/primitives/command/deactivateCategory.test.ts +27 -28
  184. package/src/modules/primitives/command/deactivateCategory.ts +43 -50
  185. package/src/modules/primitives/command/deactivateCurrency.generated.ts +6 -0
  186. package/src/modules/primitives/command/deactivateCurrency.test.ts +23 -38
  187. package/src/modules/primitives/command/deactivateCurrency.ts +31 -38
  188. package/src/modules/primitives/command/deactivateUnit.generated.ts +6 -0
  189. package/src/modules/primitives/command/deactivateUnit.test.ts +27 -23
  190. package/src/modules/primitives/command/deactivateUnit.ts +39 -49
  191. package/src/modules/primitives/command/setBaseCurrency.generated.ts +6 -0
  192. package/src/modules/primitives/command/setBaseCurrency.test.ts +40 -33
  193. package/src/modules/primitives/command/setBaseCurrency.ts +43 -50
  194. package/src/modules/primitives/command/setReferenceUnit.generated.ts +6 -0
  195. package/src/modules/primitives/command/setReferenceUnit.test.ts +39 -35
  196. package/src/modules/primitives/command/setReferenceUnit.ts +46 -59
  197. package/src/modules/primitives/db/unit.ts +13 -3
  198. package/src/modules/primitives/docs/commands/ActivateCategory.md +1 -2
  199. package/src/modules/primitives/docs/commands/ActivateCurrency.md +1 -2
  200. package/src/modules/primitives/docs/commands/ActivateUnit.md +1 -2
  201. package/src/modules/primitives/docs/commands/CreateCategory.md +1 -4
  202. package/src/modules/primitives/docs/commands/CreateCurrency.md +3 -4
  203. package/src/modules/primitives/docs/commands/CreateExchangeRate.md +4 -5
  204. package/src/modules/primitives/docs/commands/CreateUnit.md +5 -5
  205. package/src/modules/primitives/docs/commands/DeactivateCategory.md +2 -3
  206. package/src/modules/primitives/docs/commands/DeactivateCurrency.md +2 -3
  207. package/src/modules/primitives/docs/commands/DeactivateUnit.md +2 -3
  208. package/src/modules/primitives/docs/commands/SetBaseCurrency.md +2 -3
  209. package/src/modules/primitives/docs/commands/SetReferenceUnit.md +2 -3
  210. package/src/modules/primitives/docs/models/Currency.md +4 -0
  211. package/src/modules/primitives/docs/models/ExchangeRate.md +4 -1
  212. package/src/modules/primitives/docs/models/Unit.md +4 -1
  213. package/src/modules/primitives/docs/models/UoMCategory.md +2 -0
  214. package/src/modules/primitives/docs/{commands → queries}/ConvertAmount.md +3 -5
  215. package/src/modules/primitives/docs/{commands → queries}/ConvertQuantity.md +3 -5
  216. package/src/modules/primitives/docs/queries/GetBaseCurrency.md +32 -0
  217. package/src/modules/primitives/docs/queries/GetCurrency.md +36 -0
  218. package/src/modules/primitives/docs/queries/GetUnit.md +36 -0
  219. package/src/modules/primitives/docs/queries/GetUoMCategory.md +36 -0
  220. package/src/modules/primitives/docs/queries/ListUnitsByCategory.md +26 -0
  221. package/src/modules/primitives/generated/kysely-tailordb.ts +24 -45
  222. package/src/modules/primitives/index.ts +17 -6
  223. package/src/modules/primitives/lib/errors.generated.ts +112 -0
  224. package/src/modules/primitives/{permissions.ts → lib/permissions.generated.ts} +9 -10
  225. package/src/modules/primitives/module.ts +39 -27
  226. package/src/modules/primitives/query/convertAmount.generated.ts +5 -0
  227. package/src/modules/primitives/{command → query}/convertAmount.test.ts +4 -21
  228. package/src/modules/primitives/query/convertAmount.ts +121 -0
  229. package/src/modules/primitives/query/convertQuantity.generated.ts +5 -0
  230. package/src/modules/primitives/{command → query}/convertQuantity.test.ts +8 -15
  231. package/src/modules/primitives/query/convertQuantity.ts +63 -0
  232. package/src/modules/primitives/query/getBaseCurrency.generated.ts +5 -0
  233. package/src/modules/primitives/query/getBaseCurrency.test.ts +28 -0
  234. package/src/modules/primitives/query/getBaseCurrency.ts +16 -0
  235. package/src/modules/primitives/query/getCurrency.generated.ts +5 -0
  236. package/src/modules/primitives/query/getCurrency.test.ts +47 -0
  237. package/src/modules/primitives/query/getCurrency.ts +18 -0
  238. package/src/modules/primitives/query/getUnit.generated.ts +5 -0
  239. package/src/modules/primitives/query/getUnit.test.ts +47 -0
  240. package/src/modules/primitives/query/getUnit.ts +18 -0
  241. package/src/modules/primitives/query/getUoMCategory.generated.ts +5 -0
  242. package/src/modules/primitives/query/getUoMCategory.test.ts +47 -0
  243. package/src/modules/primitives/query/getUoMCategory.ts +18 -0
  244. package/src/modules/primitives/query/listUnitsByCategory.generated.ts +5 -0
  245. package/src/modules/primitives/query/listUnitsByCategory.ts +16 -0
  246. package/src/modules/primitives/tailor.config.ts +3 -3
  247. package/src/modules/shared/defineCommand.test.ts +23 -10
  248. package/src/modules/shared/defineCommand.ts +23 -10
  249. package/src/modules/shared/defineQuery.test.ts +28 -0
  250. package/src/modules/shared/defineQuery.ts +16 -0
  251. package/src/modules/shared/internal.ts +3 -1
  252. package/src/modules/shared/requirePermission.test.ts +22 -21
  253. package/src/modules/shared/requirePermission.ts +8 -2
  254. package/src/modules/shared/result.ts +12 -0
  255. package/src/modules/shared/types.ts +8 -0
  256. package/src/modules/testing/index.ts +36 -11
  257. package/src/modules/user-management/command/activateUser.generated.ts +6 -0
  258. package/src/modules/user-management/command/activateUser.test.ts +27 -27
  259. package/src/modules/user-management/command/activateUser.ts +40 -48
  260. package/src/modules/user-management/command/assignPermissionToRole.generated.ts +6 -0
  261. package/src/modules/user-management/command/assignPermissionToRole.test.ts +42 -43
  262. package/src/modules/user-management/command/assignPermissionToRole.ts +59 -62
  263. package/src/modules/user-management/command/assignRoleToUser.generated.ts +6 -0
  264. package/src/modules/user-management/command/assignRoleToUser.test.ts +70 -63
  265. package/src/modules/user-management/command/assignRoleToUser.ts +63 -66
  266. package/src/modules/user-management/command/createPermission.generated.ts +6 -0
  267. package/src/modules/user-management/command/createPermission.test.ts +45 -38
  268. package/src/modules/user-management/command/createPermission.ts +42 -46
  269. package/src/modules/user-management/command/createRole.generated.ts +6 -0
  270. package/src/modules/user-management/command/createRole.test.ts +30 -29
  271. package/src/modules/user-management/command/createRole.ts +33 -33
  272. package/src/modules/user-management/command/createUser.generated.ts +6 -0
  273. package/src/modules/user-management/command/createUser.test.ts +64 -42
  274. package/src/modules/user-management/command/createUser.ts +54 -56
  275. package/src/modules/user-management/command/deactivateUser.generated.ts +6 -0
  276. package/src/modules/user-management/command/deactivateUser.test.ts +27 -27
  277. package/src/modules/user-management/command/deactivateUser.ts +40 -48
  278. package/src/modules/user-management/command/logAuditEvent.generated.ts +6 -0
  279. package/src/modules/user-management/command/logAuditEvent.test.ts +50 -42
  280. package/src/modules/user-management/command/logAuditEvent.ts +25 -28
  281. package/src/modules/user-management/command/reactivateUser.generated.ts +6 -0
  282. package/src/modules/user-management/command/reactivateUser.test.ts +31 -27
  283. package/src/modules/user-management/command/reactivateUser.ts +40 -48
  284. package/src/modules/user-management/command/revokePermissionFromRole.generated.ts +6 -0
  285. package/src/modules/user-management/command/revokePermissionFromRole.test.ts +52 -51
  286. package/src/modules/user-management/command/revokePermissionFromRole.ts +60 -57
  287. package/src/modules/user-management/command/revokeRoleFromUser.generated.ts +6 -0
  288. package/src/modules/user-management/command/revokeRoleFromUser.test.ts +53 -48
  289. package/src/modules/user-management/command/revokeRoleFromUser.ts +58 -57
  290. package/src/modules/user-management/docs/commands/CreatePermission.md +2 -2
  291. package/src/modules/user-management/docs/commands/CreateRole.md +1 -1
  292. package/src/modules/user-management/docs/models/AuditEvent.md +2 -0
  293. package/src/modules/user-management/docs/models/Permission.md +2 -0
  294. package/src/modules/user-management/docs/models/Role.md +2 -0
  295. package/src/modules/user-management/docs/models/RolePermission.md +2 -0
  296. package/src/modules/user-management/docs/models/User.md +2 -0
  297. package/src/modules/user-management/docs/models/UserRole.md +2 -0
  298. package/src/modules/user-management/generated/enums.ts +11 -11
  299. package/src/modules/user-management/generated/kysely-tailordb.ts +27 -56
  300. package/src/modules/user-management/index.ts +2 -2
  301. package/src/modules/user-management/lib/errors.generated.ts +67 -0
  302. package/src/modules/user-management/{permissions.ts → lib/permissions.generated.ts} +8 -7
  303. package/src/modules/user-management/module.ts +22 -22
  304. package/src/modules/user-management/tailor.config.ts +3 -3
  305. package/src/schemas.ts +2 -1
  306. package/skills/1-module-docs/references/structure.md +0 -22
  307. package/skills/2-module-feature-breakdown/references/commands.md +0 -48
  308. package/skills/2-module-feature-breakdown/references/structure.md +0 -22
  309. package/skills/3-module-doc-review/references/commands.md +0 -54
  310. package/skills/3-module-doc-review/references/models.md +0 -29
  311. package/skills/4-module-tdd-implementation/SKILL.md +0 -74
  312. package/skills/4-module-tdd-implementation/references/commands.md +0 -45
  313. package/skills/4-module-tdd-implementation/references/errors.md +0 -7
  314. package/skills/4-module-tdd-implementation/references/models.md +0 -30
  315. package/skills/4-module-tdd-implementation/references/structure.md +0 -22
  316. package/skills/4-module-tdd-implementation/references/testing.md +0 -37
  317. package/skills/5-module-implementation-review/references/commands.md +0 -45
  318. package/skills/5-module-implementation-review/references/errors.md +0 -7
  319. package/skills/5-module-implementation-review/references/exports.md +0 -8
  320. package/skills/5-module-implementation-review/references/models.md +0 -30
  321. package/src/modules/primitives/command/convertAmount.ts +0 -126
  322. package/src/modules/primitives/command/convertQuantity.ts +0 -73
  323. package/src/modules/primitives/lib/errors.ts +0 -138
  324. package/src/modules/user-management/lib/errors.ts +0 -81
  325. /package/skills/{app-compose-1-requirement-analysis → erp-kit-app-1-requirements}/references/structure.md +0 -0
  326. /package/skills/{app-compose-2-requirements-breakdown → erp-kit-app-2-breakdown}/references/screen-detailview.md +0 -0
  327. /package/skills/{app-compose-2-requirements-breakdown → erp-kit-app-2-breakdown}/references/screen-form.md +0 -0
  328. /package/skills/{app-compose-2-requirements-breakdown → erp-kit-app-2-breakdown}/references/screen-listview.md +0 -0
  329. /package/skills/{app-compose-2-requirements-breakdown → erp-kit-app-2-breakdown}/references/structure.md +0 -0
  330. /package/skills/{app-compose-3-doc-review → erp-kit-app-3-doc-review}/references/structure.md +0 -0
  331. /package/skills/{app-compose-4-design-mock → erp-kit-app-4-design}/references/component.md +0 -0
  332. /package/skills/{app-compose-4-design-mock → erp-kit-app-4-design}/references/screen-detailview.md +0 -0
  333. /package/skills/{app-compose-4-design-mock → erp-kit-app-4-design}/references/screen-form.md +0 -0
  334. /package/skills/{app-compose-4-design-mock → erp-kit-app-4-design}/references/screen-listview.md +0 -0
  335. /package/skills/{app-compose-4-design-mock → erp-kit-app-4-design}/references/structure.md +0 -0
  336. /package/skills/{app-compose-5-design-mock-review → erp-kit-app-5-design-review}/references/component.md +0 -0
  337. /package/skills/{app-compose-5-design-mock-review → erp-kit-app-5-design-review}/references/screen-detailview.md +0 -0
  338. /package/skills/{app-compose-5-design-mock-review → erp-kit-app-5-design-review}/references/screen-form.md +0 -0
  339. /package/skills/{app-compose-5-design-mock-review → erp-kit-app-5-design-review}/references/screen-listview.md +0 -0
  340. /package/skills/{app-compose-6-implementation-spec → erp-kit-app-6-impl-spec}/references/auth.md +0 -0
  341. /package/skills/{app-compose-6-implementation-spec → erp-kit-app-6-impl-spec}/references/structure.md +0 -0
  342. /package/skills/{2-module-feature-breakdown → erp-kit-module-4-tdd}/references/models.md +0 -0
@@ -0,0 +1,178 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../testing/index";
3
+ import { type CommandContext } from "../../shared/internal";
4
+ import { DB } from "../generated/kysely-tailordb";
5
+ import {
6
+ DuplicateBarcodeError,
7
+ UnitNotFoundError,
8
+ ItemNotFoundError,
9
+ NoFieldsToUpdateError,
10
+ SkuImmutableError,
11
+ UomLockedError,
12
+ } from "../lib/errors.generated";
13
+ import { baseActiveItem, baseDraftItem, baseInactiveItem } from "../testing/fixtures";
14
+ import { getUnit } from "../../primitives";
15
+ import { run } from "./updateItem";
16
+
17
+ describe("updateItem", () => {
18
+ const ctx: CommandContext = {
19
+ actorId: "test-actor",
20
+ permissions: ["item-management:updateItem"],
21
+ };
22
+
23
+ it("returns error when item does not exist", async () => {
24
+ const { db, spies } = createMockDb<DB>();
25
+ spies.select.mockReturnValue(undefined);
26
+
27
+ const result = await run(db, { id: "nonexistent", name: "New Name" }, ctx, { getUnit });
28
+ expect(result.ok).toBe(false);
29
+ if (!result.ok) {
30
+ expect(result.error).toBeInstanceOf(ItemNotFoundError);
31
+ }
32
+ });
33
+
34
+ it("returns error when attempting to change SKU", async () => {
35
+ const { db, spies } = createMockDb<DB>();
36
+ spies.select.mockReturnValueOnce(baseDraftItem);
37
+
38
+ const result = await run(db, { id: baseDraftItem.id, sku: "NEW-SKU" }, ctx, { getUnit });
39
+ expect(result.ok).toBe(false);
40
+ if (!result.ok) {
41
+ expect(result.error).toBeInstanceOf(SkuImmutableError);
42
+ }
43
+ });
44
+
45
+ it("returns error when no fields to update", async () => {
46
+ const { db, spies } = createMockDb<DB>();
47
+ spies.select.mockReturnValueOnce(baseDraftItem);
48
+
49
+ const result = await run(db, { id: baseDraftItem.id }, ctx, { getUnit });
50
+ expect(result.ok).toBe(false);
51
+ if (!result.ok) {
52
+ expect(result.error).toBeInstanceOf(NoFieldsToUpdateError);
53
+ }
54
+ });
55
+
56
+ it("returns error when barcode is duplicate", async () => {
57
+ const { db, spies } = createMockDb<DB>();
58
+ spies.select
59
+ .mockReturnValueOnce(baseDraftItem) // Item lookup
60
+ .mockReturnValueOnce(baseActiveItem); // Barcode already taken
61
+
62
+ const result = await run(db, { id: baseDraftItem.id, barcode: "BAR-002" }, ctx, { getUnit });
63
+ expect(result.ok).toBe(false);
64
+ if (!result.ok) {
65
+ expect(result.error).toBeInstanceOf(DuplicateBarcodeError);
66
+ }
67
+ });
68
+
69
+ it("returns error when changing UoM on non-DRAFT item", async () => {
70
+ const { db, spies } = createMockDb<DB>();
71
+ spies.select.mockReturnValueOnce(baseActiveItem);
72
+
73
+ const result = await run(db, { id: baseActiveItem.id, unitId: "unit-g" }, ctx, { getUnit });
74
+ expect(result.ok).toBe(false);
75
+ if (!result.ok) {
76
+ expect(result.error).toBeInstanceOf(UomLockedError);
77
+ }
78
+ });
79
+
80
+ it("returns error when changing UoM on INACTIVE item", async () => {
81
+ const { db, spies } = createMockDb<DB>();
82
+ spies.select.mockReturnValueOnce(baseInactiveItem);
83
+
84
+ const result = await run(db, { id: baseInactiveItem.id, unitId: "unit-g" }, ctx, { getUnit });
85
+ expect(result.ok).toBe(false);
86
+ if (!result.ok) {
87
+ expect(result.error).toBeInstanceOf(UomLockedError);
88
+ }
89
+ });
90
+
91
+ it("returns error when new UoM does not exist", async () => {
92
+ const { db, spies } = createMockDb<DB>();
93
+ spies.select
94
+ .mockReturnValueOnce(baseDraftItem) // Item lookup
95
+ .mockReturnValueOnce(undefined); // UoM not found
96
+
97
+ const result = await run(db, { id: baseDraftItem.id, unitId: "nonexistent-unit" }, ctx, {
98
+ getUnit,
99
+ });
100
+ expect(result.ok).toBe(false);
101
+ if (!result.ok) {
102
+ expect(result.error).toBeInstanceOf(UnitNotFoundError);
103
+ }
104
+ });
105
+
106
+ it("updates name in any status", async () => {
107
+ const { db, spies } = createMockDb<DB>();
108
+ const updatedItem = { ...baseActiveItem, name: "Updated Name" };
109
+ spies.select.mockReturnValueOnce(baseActiveItem);
110
+ spies.update.mockReturnValue(updatedItem);
111
+
112
+ const result = await run(db, { id: baseActiveItem.id, name: "Updated Name" }, ctx, { getUnit });
113
+
114
+ expect(result.ok).toBe(true);
115
+ if (result.ok) {
116
+ expect(result.value.item.name).toBe("Updated Name");
117
+ }
118
+ expect(spies.update).toHaveBeenCalled();
119
+ });
120
+
121
+ it("updates barcode in any status", async () => {
122
+ const { db, spies } = createMockDb<DB>();
123
+ const updatedItem = { ...baseActiveItem, barcode: "NEW-BAR" };
124
+ spies.select
125
+ .mockReturnValueOnce(baseActiveItem) // Item lookup
126
+ .mockReturnValueOnce(undefined); // Barcode unique
127
+ spies.update.mockReturnValue(updatedItem);
128
+
129
+ const result = await run(db, { id: baseActiveItem.id, barcode: "NEW-BAR" }, ctx, { getUnit });
130
+
131
+ expect(result.ok).toBe(true);
132
+ if (result.ok) {
133
+ expect(result.value.item.barcode).toBe("NEW-BAR");
134
+ }
135
+ });
136
+
137
+ it("clears barcode by setting to null", async () => {
138
+ const { db, spies } = createMockDb<DB>();
139
+ const updatedItem = { ...baseActiveItem, barcode: null };
140
+ spies.select.mockReturnValueOnce(baseActiveItem);
141
+ spies.update.mockReturnValue(updatedItem);
142
+
143
+ const result = await run(db, { id: baseActiveItem.id, barcode: null }, ctx, { getUnit });
144
+
145
+ expect(result.ok).toBe(true);
146
+ if (result.ok) {
147
+ expect(result.value.item.barcode).toBeNull();
148
+ }
149
+ });
150
+
151
+ it("updates UoM in DRAFT status", async () => {
152
+ const { db, spies } = createMockDb<DB>();
153
+ const activeUnit = { id: "unit-g", isActive: true };
154
+ const updatedItem = { ...baseDraftItem, unitId: "unit-g" };
155
+ spies.select
156
+ .mockReturnValueOnce(baseDraftItem) // Item lookup
157
+ .mockReturnValueOnce(activeUnit); // UoM valid
158
+ spies.update.mockReturnValue(updatedItem);
159
+
160
+ const result = await run(db, { id: baseDraftItem.id, unitId: "unit-g" }, ctx, { getUnit });
161
+
162
+ expect(result.ok).toBe(true);
163
+ if (result.ok) {
164
+ expect(result.value.item.unitId).toBe("unit-g");
165
+ }
166
+ });
167
+
168
+ it("passes custom fields through to set", async () => {
169
+ const { db, spies } = createMockDb<DB>();
170
+ const updatedItem = { ...baseDraftItem, priority: 10 };
171
+ spies.select.mockReturnValueOnce(baseDraftItem);
172
+ spies.update.mockReturnValue(updatedItem);
173
+
174
+ await run(db, { id: baseDraftItem.id, priority: 10 }, ctx, { getUnit });
175
+
176
+ expect(spies.set).toHaveBeenNthCalledWith(1, expect.objectContaining({ priority: 10 }));
177
+ });
178
+ });
@@ -0,0 +1,103 @@
1
+ import { ok, err, type CommandContext } from "../../shared/internal";
2
+ import { DB } from "../generated/kysely-tailordb";
3
+ import {
4
+ DuplicateBarcodeError,
5
+ UnitNotFoundError,
6
+ ItemNotFoundError,
7
+ NoFieldsToUpdateError,
8
+ SkuImmutableError,
9
+ UomLockedError,
10
+ } from "../lib/errors.generated";
11
+ import { getItem } from "../query/getItem.generated";
12
+ import { type PrimitivesQueries } from "../module";
13
+
14
+ export interface UpdateItemInput {
15
+ id: string;
16
+ sku?: string;
17
+ name?: string;
18
+ barcode?: string | null;
19
+ unitId?: string;
20
+ }
21
+
22
+ /**
23
+ * Function: updateItem
24
+ *
25
+ * Updates mutable fields of an existing item. SKU is immutable.
26
+ * UoM can only be changed in DRAFT status.
27
+ */
28
+ export async function run<CF extends Record<string, unknown>>(
29
+ db: DB,
30
+ input: UpdateItemInput & Partial<CF>,
31
+ ctx: CommandContext,
32
+ primitivesQueries?: Pick<PrimitivesQueries, "getUnit">,
33
+ ) {
34
+ const { id, sku, name, barcode, unitId, ...customFields } = input;
35
+
36
+ // 1. Check item exists
37
+ const { item } = await getItem(db, { id }, ctx);
38
+
39
+ if (!item) {
40
+ return err(new ItemNotFoundError(id));
41
+ }
42
+
43
+ // 2. SKU is immutable
44
+ if (sku !== undefined) {
45
+ return err(new SkuImmutableError(id));
46
+ }
47
+
48
+ // 3. Check at least one field provided
49
+ const hasName = name !== undefined;
50
+ const hasBarcode = barcode !== undefined;
51
+ const hasUnitId = unitId !== undefined;
52
+ const hasCustomFields = Object.keys(customFields).length > 0;
53
+
54
+ if (!hasName && !hasBarcode && !hasUnitId && !hasCustomFields) {
55
+ return err(new NoFieldsToUpdateError(id));
56
+ }
57
+
58
+ // 4. Check barcode uniqueness when provided (non-null)
59
+ if (hasBarcode && barcode !== null) {
60
+ const existingBarcode = await db
61
+ .selectFrom("Item")
62
+ .selectAll()
63
+ .where("barcode", "=", barcode)
64
+ .where("id", "!=", id)
65
+ .executeTakeFirst();
66
+
67
+ if (existingBarcode) {
68
+ return err(new DuplicateBarcodeError(barcode));
69
+ }
70
+ }
71
+
72
+ // 5. UoM can only be changed in DRAFT status
73
+ if (hasUnitId) {
74
+ if (item.status !== "DRAFT") {
75
+ return err(new UomLockedError(id));
76
+ }
77
+
78
+ // Validate UoM exists and is active
79
+ const { unit } = await primitivesQueries!.getUnit(db, { id: unitId }, ctx);
80
+
81
+ if (!unit?.isActive) {
82
+ return err(new UnitNotFoundError(unitId));
83
+ }
84
+ }
85
+
86
+ // 6. Apply updates
87
+ const updates: Record<string, unknown> = {
88
+ ...(customFields as Record<string, unknown>),
89
+ updatedAt: new Date(),
90
+ };
91
+ if (hasName) updates.name = name;
92
+ if (hasBarcode) updates.barcode = barcode;
93
+ if (hasUnitId) updates.unitId = unitId;
94
+
95
+ const updatedItem = await db
96
+ .updateTable("Item")
97
+ .set(updates)
98
+ .where("id", "=", id)
99
+ .returningAll()
100
+ .executeTakeFirstOrThrow();
101
+
102
+ return ok({ item: updatedItem });
103
+ }
@@ -0,0 +1,6 @@
1
+ // @generated — do not edit
2
+ import { defineCommand } from "../../shared/internal";
3
+ import { permissions } from "../lib/permissions.generated";
4
+ import { run } from "./updateTaxonomyNode";
5
+
6
+ export const updateTaxonomyNode = defineCommand(permissions.updateTaxonomyNode, run);
@@ -0,0 +1,88 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../testing/index";
3
+ import { type CommandContext } from "../../shared/internal";
4
+ import { DB } from "../generated/kysely-tailordb";
5
+ import {
6
+ CodeImmutableError,
7
+ MissingRequiredFieldsError,
8
+ NodeNotFoundError,
9
+ } from "../lib/errors.generated";
10
+ import { baseRootNode } from "../testing/fixtures";
11
+ import { run } from "./updateTaxonomyNode";
12
+
13
+ describe("updateTaxonomyNode", () => {
14
+ const ctx: CommandContext = {
15
+ actorId: "test-actor",
16
+ permissions: ["item-management:updateTaxonomyNode"],
17
+ };
18
+
19
+ it("returns error when node does not exist", async () => {
20
+ const { db, spies } = createMockDb<DB>();
21
+ spies.select.mockReturnValue(undefined);
22
+
23
+ const result = await run(db, { id: "nonexistent", name: "New Name" }, ctx);
24
+ expect(result.ok).toBe(false);
25
+ if (!result.ok) {
26
+ expect(result.error).toBeInstanceOf(NodeNotFoundError);
27
+ }
28
+ });
29
+
30
+ it("returns error when attempting to change code", async () => {
31
+ const { db, spies } = createMockDb<DB>();
32
+ spies.select.mockReturnValueOnce(baseRootNode);
33
+
34
+ const result = await run(db, { id: baseRootNode.id, code: "NEW-CODE" }, ctx);
35
+ expect(result.ok).toBe(false);
36
+ if (!result.ok) {
37
+ expect(result.error).toBeInstanceOf(CodeImmutableError);
38
+ }
39
+ });
40
+
41
+ it("returns error when name is empty", async () => {
42
+ const { db, spies } = createMockDb<DB>();
43
+ spies.select.mockReturnValueOnce(baseRootNode);
44
+
45
+ const result = await run(db, { id: baseRootNode.id, name: "" }, ctx);
46
+ expect(result.ok).toBe(false);
47
+ if (!result.ok) {
48
+ expect(result.error).toBeInstanceOf(MissingRequiredFieldsError);
49
+ }
50
+ });
51
+
52
+ it("returns error when name is not provided", async () => {
53
+ const { db, spies } = createMockDb<DB>();
54
+ spies.select.mockReturnValueOnce(baseRootNode);
55
+
56
+ const result = await run(db, { id: baseRootNode.id }, ctx);
57
+ expect(result.ok).toBe(false);
58
+ if (!result.ok) {
59
+ expect(result.error).toBeInstanceOf(MissingRequiredFieldsError);
60
+ }
61
+ });
62
+
63
+ it("updates node name", async () => {
64
+ const { db, spies } = createMockDb<DB>();
65
+ const updatedNode = { ...baseRootNode, name: "Consumer Electronics" };
66
+ spies.select.mockReturnValueOnce(baseRootNode);
67
+ spies.update.mockReturnValue(updatedNode);
68
+
69
+ const result = await run(db, { id: baseRootNode.id, name: "Consumer Electronics" }, ctx);
70
+
71
+ expect(result.ok).toBe(true);
72
+ if (result.ok) {
73
+ expect(result.value.node.name).toBe("Consumer Electronics");
74
+ }
75
+ expect(spies.update).toHaveBeenCalled();
76
+ });
77
+
78
+ it("passes custom fields through to set", async () => {
79
+ const { db, spies } = createMockDb<DB>();
80
+ const updatedNode = { ...baseRootNode, sortOrder: 5 };
81
+ spies.select.mockReturnValueOnce(baseRootNode);
82
+ spies.update.mockReturnValue(updatedNode);
83
+
84
+ await run(db, { id: baseRootNode.id, name: "Electronics", sortOrder: 5 }, ctx);
85
+
86
+ expect(spies.set).toHaveBeenNthCalledWith(1, expect.objectContaining({ sortOrder: 5 }));
87
+ });
88
+ });
@@ -0,0 +1,62 @@
1
+ import { ok, err, type CommandContext } from "../../shared/internal";
2
+ import { DB } from "../generated/kysely-tailordb";
3
+ import {
4
+ CodeImmutableError,
5
+ MissingRequiredFieldsError,
6
+ NodeNotFoundError,
7
+ } from "../lib/errors.generated";
8
+ import { getTaxonomyNode } from "../query/getTaxonomyNode.generated";
9
+
10
+ export interface UpdateTaxonomyNodeInput {
11
+ id: string;
12
+ code?: string;
13
+ name?: string;
14
+ }
15
+
16
+ /**
17
+ * Function: updateTaxonomyNode
18
+ *
19
+ * Updates the display name of an existing taxonomy node.
20
+ * Node code is immutable.
21
+ */
22
+ export async function run<CF extends Record<string, unknown>>(
23
+ db: DB,
24
+ input: UpdateTaxonomyNodeInput & Partial<CF>,
25
+ ctx: CommandContext,
26
+ ) {
27
+ const { id, code, name, ...customFields } = input;
28
+
29
+ // 1. Check node exists
30
+ const { node } = await getTaxonomyNode(db, { id }, ctx);
31
+
32
+ if (!node) {
33
+ return err(new NodeNotFoundError(id));
34
+ }
35
+
36
+ // 2. Code is immutable
37
+ if (code !== undefined) {
38
+ return err(new CodeImmutableError(id));
39
+ }
40
+
41
+ // 3. Name must be provided and non-empty (unless custom fields provided)
42
+ const hasCustomFields = Object.keys(customFields).length > 0;
43
+ if (!name && !hasCustomFields) {
44
+ return err(new MissingRequiredFieldsError("name"));
45
+ }
46
+
47
+ // 4. Update fields
48
+ const updates: Record<string, unknown> = {
49
+ ...(customFields as Record<string, unknown>),
50
+ updatedAt: new Date(),
51
+ };
52
+ if (name) updates.name = name;
53
+
54
+ const updatedNode = await db
55
+ .updateTable("TaxonomyNode")
56
+ .set(updates)
57
+ .where("id", "=", id)
58
+ .returningAll()
59
+ .executeTakeFirstOrThrow();
60
+
61
+ return ok({ node: updatedNode });
62
+ }
@@ -0,0 +1,47 @@
1
+ import {
2
+ db,
3
+ type TailorAnyDBField,
4
+ type TailorAnyDBType,
5
+ unsafeAllowAllGqlPermission,
6
+ unsafeAllowAllTypePermission,
7
+ } from "@tailor-platform/sdk";
8
+ import { unit as unitStub } from "../lib/_db_deps";
9
+
10
+ export const BASE_ITEM_STATUSES = ["DRAFT", "ACTIVE", "INACTIVE"] as const;
11
+
12
+ export interface CreateItemTypeParams<F extends Record<string, TailorAnyDBField>> {
13
+ fields?: F;
14
+ additionalStatuses?: string[];
15
+ unitType: TailorAnyDBType;
16
+ }
17
+
18
+ export function createItemType<const F extends Record<string, TailorAnyDBField>>(
19
+ params: CreateItemTypeParams<F>,
20
+ ) {
21
+ const statuses = [...BASE_ITEM_STATUSES, ...(params.additionalStatuses ?? [])] as [
22
+ string,
23
+ ...string[],
24
+ ];
25
+
26
+ return db
27
+ .type("Item", {
28
+ sku: db.string().unique().description("Globally unique, immutable SKU identifier"),
29
+ name: db.string().description("Item display name"),
30
+ barcode: db.string({ optional: true }).unique().description("Optional unique barcode"),
31
+ unitId: db
32
+ .uuid()
33
+ .relation({
34
+ type: "n-1",
35
+ toward: { type: params.unitType },
36
+ backward: "items",
37
+ })
38
+ .description("Foreign key to Unit"),
39
+ status: db.enum(statuses).description("Lifecycle status: DRAFT, ACTIVE, INACTIVE"),
40
+ ...((params.fields ?? {}) as F),
41
+ ...db.fields.timestamps(),
42
+ })
43
+ .permission(unsafeAllowAllTypePermission)
44
+ .gqlPermission(unsafeAllowAllGqlPermission);
45
+ }
46
+
47
+ export const item = createItemType({ unitType: unitStub });
@@ -0,0 +1,49 @@
1
+ import {
2
+ db,
3
+ type TailorAnyDBField,
4
+ unsafeAllowAllGqlPermission,
5
+ unsafeAllowAllTypePermission,
6
+ } from "@tailor-platform/sdk";
7
+ import { item } from "./item";
8
+ import { taxonomyNode } from "./taxonomyNode";
9
+
10
+ export interface CreateItemTaxonomyAssignmentTypeParams<
11
+ F extends Record<string, TailorAnyDBField>,
12
+ > {
13
+ fields?: F;
14
+ }
15
+
16
+ export function createItemTaxonomyAssignmentType<const F extends Record<string, TailorAnyDBField>>(
17
+ params: CreateItemTaxonomyAssignmentTypeParams<F>,
18
+ ) {
19
+ return db
20
+ .type("ItemTaxonomyAssignment", {
21
+ itemId: db
22
+ .uuid()
23
+ .relation({
24
+ type: "n-1",
25
+ toward: { type: item },
26
+ backward: "itemTaxonomyAssignments",
27
+ })
28
+ .description("Foreign key to Item"),
29
+ taxonomyNodeId: db
30
+ .uuid()
31
+ .relation({
32
+ type: "n-1",
33
+ toward: { type: taxonomyNode },
34
+ backward: "itemTaxonomyAssignments",
35
+ })
36
+ .description("Foreign key to TaxonomyNode"),
37
+ ...((params.fields ?? {}) as F),
38
+ ...db.fields.timestamps(),
39
+ })
40
+ .indexes({
41
+ fields: ["itemId", "taxonomyNodeId"],
42
+ unique: true,
43
+ name: "item_taxonomy_assignment_unique_idx",
44
+ })
45
+ .permission(unsafeAllowAllTypePermission)
46
+ .gqlPermission(unsafeAllowAllGqlPermission);
47
+ }
48
+
49
+ export const itemTaxonomyAssignment = createItemTaxonomyAssignmentType({});
@@ -0,0 +1,34 @@
1
+ import {
2
+ db,
3
+ type TailorAnyDBField,
4
+ unsafeAllowAllGqlPermission,
5
+ unsafeAllowAllTypePermission,
6
+ } from "@tailor-platform/sdk";
7
+
8
+ export interface CreateTaxonomyNodeTypeParams<F extends Record<string, TailorAnyDBField>> {
9
+ fields?: F;
10
+ }
11
+
12
+ export function createTaxonomyNodeType<const F extends Record<string, TailorAnyDBField>>(
13
+ params: CreateTaxonomyNodeTypeParams<F>,
14
+ ) {
15
+ return db
16
+ .type("TaxonomyNode", {
17
+ code: db.string().unique().description("Globally unique, immutable node code"),
18
+ name: db.string().description("Display name for the taxonomy node"),
19
+ parentId: db
20
+ .uuid({ optional: true })
21
+ .relation({
22
+ type: "n-1",
23
+ toward: { type: "self" },
24
+ backward: "children",
25
+ })
26
+ .description("Parent node ID (null for root nodes)"),
27
+ ...((params.fields ?? {}) as F),
28
+ ...db.fields.timestamps(),
29
+ })
30
+ .permission(unsafeAllowAllTypePermission)
31
+ .gqlPermission(unsafeAllowAllGqlPermission);
32
+ }
33
+
34
+ export const taxonomyNode = createTaxonomyNodeType({});
@@ -0,0 +1,32 @@
1
+ # ActivateItem
2
+
3
+ ## Overview
4
+
5
+ activateItem transitions an item from DRAFT to ACTIVE status, making it available for use in transactions across downstream modules (Sales, Purchasing, Inventory). Since name, SKU, and UoM are required at creation time, no completeness validation is needed at activation.
6
+
7
+ ## Business Rules
8
+
9
+ - Target item must exist in the system
10
+ - Target item must be in DRAFT status
11
+ - After activation, the item can participate in new transactions
12
+
13
+ ## Process Flow
14
+
15
+ ```mermaid
16
+ flowchart TD
17
+ A[Receive activate request] --> B{Item exists?}
18
+ B -->|No| C[Return error: not found]
19
+ B -->|Yes| D{Status is DRAFT?}
20
+ D -->|No| E[Return error: invalid state transition]
21
+ D -->|Yes| F[Update status to ACTIVE]
22
+ F --> G[Return activated item]
23
+ ```
24
+
25
+ ## External Dependencies
26
+
27
+ - None
28
+
29
+ ## Error Scenarios
30
+
31
+ - **ITEM_NOT_FOUND**: Specified item ID does not exist
32
+ - **INVALID_STATE_TRANSITION**: Item is not in DRAFT status
@@ -0,0 +1,38 @@
1
+ # AssignItemToTaxonomy
2
+
3
+ ## Overview
4
+
5
+ assignItemToTaxonomy creates a link between an item and a taxonomy node, enabling many-to-many classification. A single item can be assigned to multiple taxonomy nodes simultaneously (e.g., both "Electronics > Smartphones" and "Gift Ideas > Tech Gifts"), allowing flexible multi-dimensional classification.
6
+
7
+ ## Business Rules
8
+
9
+ - The referenced item must exist in the system
10
+ - The referenced taxonomy node must exist in the system
11
+ - The combination of item and taxonomy node must be unique — duplicate assignments are rejected
12
+ - An item can be assigned to any number of taxonomy nodes
13
+ - A taxonomy node can have any number of items assigned
14
+ - Assignment does not change the item's status or the node's position in the tree
15
+
16
+ ## Process Flow
17
+
18
+ ```mermaid
19
+ flowchart TD
20
+ A[Receive assign request] --> B{Item exists?}
21
+ B -->|No| C[Return error: item not found]
22
+ B -->|Yes| D{Node exists?}
23
+ D -->|No| E[Return error: node not found]
24
+ D -->|Yes| F{Assignment already exists?}
25
+ F -->|Yes| G[Return error: duplicate assignment]
26
+ F -->|No| H[Create assignment record]
27
+ H --> I[Return created assignment]
28
+ ```
29
+
30
+ ## External Dependencies
31
+
32
+ - None
33
+
34
+ ## Error Scenarios
35
+
36
+ - **ITEM_NOT_FOUND**: Specified item ID does not exist
37
+ - **NODE_NOT_FOUND**: Specified taxonomy node ID does not exist
38
+ - **DUPLICATE_ASSIGNMENT**: Item is already assigned to this taxonomy node
@@ -0,0 +1,44 @@
1
+ # CreateItem
2
+
3
+ ## Overview
4
+
5
+ createItem establishes a new item in the system with a unique SKU, name, unit of measure, and optional barcode. Items can be created in either DRAFT or ACTIVE status. DRAFT items allow review and correction before activation, while ACTIVE items are immediately available for transactions.
6
+
7
+ This command supports both careful item onboarding workflows (create as DRAFT, review, then activate) and rapid setup scenarios (create directly as ACTIVE).
8
+
9
+ ## Business Rules
10
+
11
+ - SKU is required, must be globally unique across all items (active, inactive, and draft)
12
+ - SKU is immutable after creation — it cannot be changed once assigned
13
+ - Name is required
14
+ - Barcode must be unique across all items when provided
15
+ - UoM (unit of measure) is required and must reference an existing active Unit from the primitives module
16
+ - Default status is DRAFT if not specified
17
+
18
+ ## Process Flow
19
+
20
+ ```mermaid
21
+ flowchart TD
22
+ A[Receive create request] --> B{Validate SKU format}
23
+ B -->|Invalid| C[Return error: invalid SKU]
24
+ B -->|Valid| D{SKU unique?}
25
+ D -->|No| E[Return error: duplicate SKU]
26
+ D -->|Yes| F{Barcode provided?}
27
+ F -->|Yes| G{Barcode unique?}
28
+ G -->|No| H[Return error: duplicate barcode]
29
+ G -->|Yes| I{Validate UoM}
30
+ F -->|No| I
31
+ I -->|Invalid| J[Return error: invalid UoM]
32
+ I -->|Valid| K[Create item record]
33
+ K --> L[Return created item]
34
+ ```
35
+
36
+ ## External Dependencies
37
+
38
+ - [primitives::Unit](../../../primitives/docs/models/Unit.md) - Validates that the referenced UoM exists and is active
39
+
40
+ ## Error Scenarios
41
+
42
+ - **DUPLICATE_SKU**: An item with the same SKU already exists
43
+ - **DUPLICATE_BARCODE**: An item with the same barcode already exists
44
+ - **UNIT_NOT_FOUND**: Referenced unit does not exist or is inactive