@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,116 @@
1
+ import { fromMarkdown } from "mdast-util-from-markdown";
2
+ import { toString } from "mdast-util-to-string";
3
+ import type { Heading, List, Root, RootContent } from "mdast";
4
+
5
+ export interface ParsedError {
6
+ code: string;
7
+ description: string;
8
+ }
9
+
10
+ export interface ParsedDependency {
11
+ module: string;
12
+ entity: string;
13
+ }
14
+
15
+ export interface ParsedCommandDoc {
16
+ commandName: string;
17
+ errors: ParsedError[];
18
+ externalDependencies: ParsedDependency[];
19
+ }
20
+
21
+ export function parseCommandDoc(fileName: string, markdown: string): ParsedCommandDoc {
22
+ const commandName = fileName.charAt(0).toLowerCase() + fileName.slice(1);
23
+ const tree = fromMarkdown(markdown);
24
+
25
+ return {
26
+ commandName,
27
+ errors: parseErrorScenarios(tree),
28
+ externalDependencies: parseExternalDependencies(tree),
29
+ };
30
+ }
31
+
32
+ export function errorCodeToClassName(code: string): string {
33
+ const pascal = code
34
+ .toLowerCase()
35
+ .split("_")
36
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
37
+ .join("");
38
+ return pascal + "Error";
39
+ }
40
+
41
+ function isHeading(node: RootContent): node is Heading {
42
+ return node.type === "heading";
43
+ }
44
+
45
+ function isList(node: RootContent): node is List {
46
+ return node.type === "list";
47
+ }
48
+
49
+ function getNodesUnderHeading(tree: Root, headingText: string): RootContent[] {
50
+ const nodes: RootContent[] = [];
51
+ let collecting = false;
52
+
53
+ for (const node of tree.children) {
54
+ if (isHeading(node)) {
55
+ if (collecting) break;
56
+ if (node.depth === 2 && toString(node) === headingText) {
57
+ collecting = true;
58
+ continue;
59
+ }
60
+ }
61
+ if (collecting) {
62
+ nodes.push(node);
63
+ }
64
+ }
65
+
66
+ return nodes;
67
+ }
68
+
69
+ const ERROR_PATTERN = /^([A-Z_]+):\s*(.+)$/;
70
+
71
+ function parseErrorScenarios(tree: Root): ParsedError[] {
72
+ const nodes = getNodesUnderHeading(tree, "Error Scenarios");
73
+ const errors: ParsedError[] = [];
74
+
75
+ for (const node of nodes) {
76
+ if (!isList(node)) continue;
77
+
78
+ for (const item of node.children) {
79
+ const text = toString(item);
80
+ const match = ERROR_PATTERN.exec(text);
81
+ if (match) {
82
+ errors.push({ code: match[1], description: match[2].trim() });
83
+ }
84
+ }
85
+ }
86
+
87
+ return errors;
88
+ }
89
+
90
+ const DEPENDENCY_PATTERN = /^([^:]+)::(.+)$/;
91
+
92
+ function parseExternalDependencies(tree: Root): ParsedDependency[] {
93
+ const nodes = getNodesUnderHeading(tree, "External Dependencies");
94
+ const deps: ParsedDependency[] = [];
95
+
96
+ for (const node of nodes) {
97
+ if (!isList(node)) continue;
98
+
99
+ for (const item of node.children) {
100
+ const firstChild = item.children[0];
101
+ if (firstChild?.type !== "paragraph") continue;
102
+
103
+ for (const inline of firstChild.children) {
104
+ if (inline.type === "link" || inline.type === "linkReference") {
105
+ const linkText = toString(inline);
106
+ const match = DEPENDENCY_PATTERN.exec(linkText);
107
+ if (match) {
108
+ deps.push({ module: match[1], entity: match[2] });
109
+ }
110
+ }
111
+ }
112
+ }
113
+ }
114
+
115
+ return deps;
116
+ }
@@ -11,13 +11,11 @@ const REPO_ROOT = path.resolve(__dirname, "..", "..", "..");
11
11
  const skipReason = fs.existsSync(CLI_PATH) ? undefined : "Run `pnpm build` first";
12
12
 
13
13
  describe.skipIf(skipReason)("integration", () => {
14
- it("check command runs against sdk-plugins modules", () => {
15
- // mdschema may report validation errors in real docs, so we allow non-zero exit codes
16
- // but verify the CLI itself doesn't crash with an unexpected error
14
+ it("module check command runs against erp-kit modules", () => {
17
15
  try {
18
16
  const result = execFileSync(
19
17
  "node",
20
- [CLI_PATH, "check", "--modules-root", "packages/erp-kit/src/modules"],
18
+ [CLI_PATH, "module", "check", "--root", "packages/erp-kit/src/modules"],
21
19
  {
22
20
  cwd: REPO_ROOT,
23
21
  encoding: "utf-8",
@@ -33,11 +31,11 @@ describe.skipIf(skipReason)("integration", () => {
33
31
  }
34
32
  });
35
33
 
36
- it("sync-check command runs against sdk-plugins modules", () => {
34
+ it("module sync-check command runs against erp-kit modules", () => {
37
35
  try {
38
36
  const result = execFileSync(
39
37
  "node",
40
- [CLI_PATH, "sync-check", "--modules-root", "packages/erp-kit/src/modules"],
38
+ [CLI_PATH, "module", "sync-check", "--root", "packages/erp-kit/src/modules"],
41
39
  {
42
40
  cwd: REPO_ROOT,
43
41
  encoding: "utf-8",
@@ -57,7 +55,7 @@ describe.skipIf(skipReason)("integration", () => {
57
55
  encoding: "utf-8",
58
56
  });
59
57
  expect(result).toContain("erp-kit");
60
- expect(result).toContain("check");
61
- expect(result).toContain("scaffold");
58
+ expect(result).toContain("module");
59
+ expect(result).toContain("app");
62
60
  });
63
61
  });
package/src/module.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  // shared/internal
2
2
  export { defineCommand, type Command } from "./modules/shared/defineCommand";
3
+ export { defineQuery, type Query } from "./modules/shared/defineQuery";
3
4
  export { definePermissions } from "./modules/shared/definePermissions";
4
5
  export { requirePermission } from "./modules/shared/requirePermission";
5
6
  export { createDomainError, InsufficientPermissionError } from "./modules/shared/errors";
6
- export type { CommandContext } from "./modules/shared/types";
7
+ export type { CommandContext, QueryContext, ReadonlyDB } from "./modules/shared/types";
7
8
  export type {
8
9
  InferSchema,
9
10
  Selectable,
@@ -18,9 +19,9 @@ export {
18
19
  permissions as primitivesPermissions,
19
20
  own as primitivesOwn,
20
21
  all as primitivesAll,
21
- } from "./modules/primitives/permissions";
22
+ } from "./modules/primitives/lib/permissions.generated";
22
23
  export {
23
- UoMCategoryNotFoundError,
24
+ UomCategoryNotFoundError,
24
25
  UnitNotFoundError,
25
26
  IncompatibleUnitsError,
26
27
  InactiveUnitError,
@@ -35,21 +36,21 @@ export {
35
36
  DuplicateCategoryNameError,
36
37
  CategoryHasActiveUnitsError,
37
38
  UnitNotInCategoryError,
38
- InvalidISOCodeError,
39
+ InvalidIsoCodeError,
39
40
  DuplicateCurrencyCodeError,
40
41
  InvalidDecimalPlacesError,
41
42
  CannotDeactivateBaseCurrencyError,
42
43
  CannotSetInactiveAsBaseCurrencyError,
43
44
  SameCurrencyPairError,
44
45
  InvalidExchangeRateError,
45
- } from "./modules/primitives/lib/errors";
46
- export { type ConvertQuantityInput } from "./modules/primitives/command/convertQuantity";
46
+ } from "./modules/primitives/lib/errors.generated";
47
+ export { type ConvertQuantityInput } from "./modules/primitives/query/convertQuantity";
47
48
  export { type ActivateCategoryInput } from "./modules/primitives/command/activateCategory";
48
49
  export { type DeactivateCategoryInput } from "./modules/primitives/command/deactivateCategory";
49
50
  export { type SetReferenceUnitInput } from "./modules/primitives/command/setReferenceUnit";
50
51
  export { type ActivateUnitInput } from "./modules/primitives/command/activateUnit";
51
52
  export { type DeactivateUnitInput } from "./modules/primitives/command/deactivateUnit";
52
- export { type ConvertAmountInput } from "./modules/primitives/command/convertAmount";
53
+ export { type ConvertAmountInput } from "./modules/primitives/query/convertAmount";
53
54
  export { type ActivateCurrencyInput } from "./modules/primitives/command/activateCurrency";
54
55
  export { type DeactivateCurrencyInput } from "./modules/primitives/command/deactivateCurrency";
55
56
  export { type SetBaseCurrencyInput } from "./modules/primitives/command/setBaseCurrency";
@@ -59,7 +60,7 @@ export {
59
60
  permissions as userManagementPermissions,
60
61
  own as userManagementOwn,
61
62
  all as userManagementAll,
62
- } from "./modules/user-management/permissions";
63
+ } from "./modules/user-management/lib/permissions.generated";
63
64
  export { AuditEventEventType, UserStatus } from "./modules/user-management/generated/enums";
64
65
  export {
65
66
  UserNotFoundError,
@@ -75,7 +76,7 @@ export {
75
76
  DuplicateRoleNameError,
76
77
  AssignmentNotFoundError,
77
78
  InvalidEventTypeError,
78
- } from "./modules/user-management/lib/errors";
79
+ } from "./modules/user-management/lib/errors.generated";
79
80
  export { type ActivateUserInput } from "./modules/user-management/command/activateUser";
80
81
  export { type DeactivateUserInput } from "./modules/user-management/command/deactivateUser";
81
82
  export { type ReactivateUserInput } from "./modules/user-management/command/reactivateUser";
@@ -0,0 +1,38 @@
1
+ # README
2
+
3
+ ## Overview
4
+
5
+ The Item Management module manages items — the fundamental SKU-level entity in the ERP system. Items are the sellable, purchasable, and trackable unit that all downstream modules (Sales, Purchasing, Inventory, Manufacturing) reference as the primary transactional entity.
6
+
7
+ Each item has its own lifecycle (DRAFT → ACTIVE ↔ INACTIVE), unique SKU identity, and optional barcode. Items are classified through a flexible taxonomy system (many-to-many with TaxonomyNode) for hierarchical browsing and filtering.
8
+
9
+ ## Key Features
10
+
11
+ - **Item Lifecycle**: The canonical SKU-level entity referenced by all operational modules. Lifecycle state management (DRAFT → ACTIVE ↔ INACTIVE), SKU and barcode assignment. Items can be created directly or generated from product templates
12
+ - **Item Taxonomy**: Hierarchical taxonomy tree for multi-dimensional item classification (many-to-many). Items can belong to multiple taxonomy branches simultaneously
13
+
14
+ ## Module Scope
15
+
16
+ ### In Scope
17
+
18
+ - Item master data management (create, update, delete, status transitions)
19
+ - Item lifecycle state machine (DRAFT → ACTIVE ↔ INACTIVE)
20
+ - SKU and barcode assignment and uniqueness enforcement
21
+ - Unit of measure assignment per item
22
+ - Hierarchical item taxonomy management (TaxonomyNode tree)
23
+ - Item-to-taxonomy classification (many-to-many)
24
+
25
+ ### Out of Scope
26
+
27
+ - Product template definitions and attribute schemas (product-management module)
28
+ - Variant generation from attribute combinations (product-management module)
29
+ - Sales price list and pricing rule management (pricing module)
30
+ - Inventory tracking and stock levels (inventory module)
31
+ - Lot and serial number management (inventory module)
32
+ - Vendor/supplier management (supplier-management module)
33
+ - Bill of Materials (manufacturing module)
34
+ - Product images and digital asset management
35
+
36
+ ## Module Dependencies
37
+
38
+ - [primitives](../primitives/README.md) — UoM definitions for item unit of measure
@@ -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 "./activateItem";
5
+
6
+ export const activateItem = defineCommand(permissions.activateItem, run);
@@ -0,0 +1,76 @@
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 { InvalidStateTransitionError, ItemNotFoundError } from "../lib/errors.generated";
6
+ import { baseActiveItem, baseDraftItem, baseInactiveItem } from "../testing/fixtures";
7
+ import { run } from "./activateItem";
8
+
9
+ describe("activateItem", () => {
10
+ const ctx: CommandContext = {
11
+ actorId: "test-actor",
12
+ permissions: ["item-management:activateItem"],
13
+ };
14
+
15
+ it("returns error when item does not exist", async () => {
16
+ const { db, spies } = createMockDb<DB>();
17
+ spies.select.mockReturnValue(undefined);
18
+
19
+ const result = await run(db, { id: "nonexistent" }, ctx);
20
+ expect(result.ok).toBe(false);
21
+ if (!result.ok) {
22
+ expect(result.error).toBeInstanceOf(ItemNotFoundError);
23
+ }
24
+ });
25
+
26
+ it("returns error when item is not DRAFT", async () => {
27
+ const { db, spies } = createMockDb<DB>();
28
+ spies.select.mockReturnValueOnce(baseActiveItem);
29
+
30
+ const result = await run(db, { id: baseActiveItem.id }, ctx);
31
+ expect(result.ok).toBe(false);
32
+ if (!result.ok) {
33
+ expect(result.error).toBeInstanceOf(InvalidStateTransitionError);
34
+ }
35
+ });
36
+
37
+ it("returns error when item is INACTIVE", async () => {
38
+ const { db, spies } = createMockDb<DB>();
39
+ spies.select.mockReturnValueOnce(baseInactiveItem);
40
+
41
+ const result = await run(db, { id: baseInactiveItem.id }, ctx);
42
+ expect(result.ok).toBe(false);
43
+ if (!result.ok) {
44
+ expect(result.error).toBeInstanceOf(InvalidStateTransitionError);
45
+ }
46
+ });
47
+
48
+ it("activates a DRAFT item", async () => {
49
+ const { db, spies } = createMockDb<DB>();
50
+ const activatedItem = { ...baseDraftItem, status: "ACTIVE" };
51
+ spies.select.mockReturnValueOnce(baseDraftItem);
52
+ spies.update.mockReturnValue(activatedItem);
53
+
54
+ const result = await run(db, { id: baseDraftItem.id }, ctx);
55
+
56
+ expect(result.ok).toBe(true);
57
+ if (result.ok) {
58
+ expect(result.value.item.status).toBe("ACTIVE");
59
+ }
60
+ expect(spies.update).toHaveBeenCalled();
61
+ });
62
+
63
+ it("activates from custom status when from is overridden", async () => {
64
+ const { db, spies } = createMockDb<DB>();
65
+ const activatedItem = { ...baseInactiveItem, status: "ACTIVE" };
66
+ spies.select.mockReturnValueOnce(baseInactiveItem);
67
+ spies.update.mockReturnValue(activatedItem);
68
+
69
+ const result = await run(db, { id: baseInactiveItem.id, from: ["DRAFT", "INACTIVE"] }, ctx);
70
+
71
+ expect(result.ok).toBe(true);
72
+ if (result.ok) {
73
+ expect(result.value.item.status).toBe("ACTIVE");
74
+ }
75
+ });
76
+ });
@@ -0,0 +1,42 @@
1
+ import { ok, err, type CommandContext } from "../../shared/internal";
2
+ import { DB } from "../generated/kysely-tailordb";
3
+ import { InvalidStateTransitionError, ItemNotFoundError } from "../lib/errors.generated";
4
+ import { getItem } from "../query/getItem.generated";
5
+
6
+ export interface ActivateItemInput {
7
+ id: string;
8
+ from?: string[];
9
+ }
10
+
11
+ /**
12
+ * Function: activateItem
13
+ *
14
+ * Transitions an item from DRAFT to ACTIVE status.
15
+ * Requires name, SKU, and UoM to be set.
16
+ */
17
+ export async function run(db: DB, input: ActivateItemInput, ctx: CommandContext) {
18
+ const { id, from } = input;
19
+
20
+ // 1. Check item exists
21
+ const { item } = await getItem(db, { id }, ctx);
22
+
23
+ if (!item) {
24
+ return err(new ItemNotFoundError(id));
25
+ }
26
+
27
+ // 2. Check status is valid for activation
28
+ const validFromStatuses = from ?? ["DRAFT"];
29
+ if (!validFromStatuses.includes(item.status)) {
30
+ return err(new InvalidStateTransitionError(`${item.status} to ACTIVE`));
31
+ }
32
+
33
+ // 3. Update status to ACTIVE
34
+ const activatedItem = await db
35
+ .updateTable("Item")
36
+ .set({ status: "ACTIVE", updatedAt: new Date() })
37
+ .where("id", "=", id)
38
+ .returningAll()
39
+ .executeTakeFirstOrThrow();
40
+
41
+ return ok({ item: activatedItem });
42
+ }
@@ -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 "./assignItemToTaxonomy";
5
+
6
+ export const assignItemToTaxonomy = defineCommand(permissions.assignItemToTaxonomy, 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
+ DuplicateAssignmentError,
7
+ ItemNotFoundError,
8
+ NodeNotFoundError,
9
+ } from "../lib/errors.generated";
10
+ import { baseActiveItem, baseAssignment, baseChildNode } from "../testing/fixtures";
11
+ import { run } from "./assignItemToTaxonomy";
12
+
13
+ describe("assignItemToTaxonomy", () => {
14
+ const ctx: CommandContext = {
15
+ actorId: "test-actor",
16
+ permissions: ["item-management:assignItemToTaxonomy"],
17
+ };
18
+
19
+ it("returns error when item does not exist", async () => {
20
+ const { db, spies } = createMockDb<DB>();
21
+ spies.select.mockReturnValueOnce(undefined); // Item not found
22
+
23
+ const result = await run(db, { itemId: "nonexistent", taxonomyNodeId: baseChildNode.id }, ctx);
24
+ expect(result.ok).toBe(false);
25
+ if (!result.ok) {
26
+ expect(result.error).toBeInstanceOf(ItemNotFoundError);
27
+ }
28
+ });
29
+
30
+ it("returns error when node does not exist", async () => {
31
+ const { db, spies } = createMockDb<DB>();
32
+ spies.select
33
+ .mockReturnValueOnce(baseActiveItem) // Item exists
34
+ .mockReturnValueOnce(undefined); // Node not found
35
+
36
+ const result = await run(db, { itemId: baseActiveItem.id, taxonomyNodeId: "nonexistent" }, ctx);
37
+ expect(result.ok).toBe(false);
38
+ if (!result.ok) {
39
+ expect(result.error).toBeInstanceOf(NodeNotFoundError);
40
+ }
41
+ });
42
+
43
+ it("returns error when assignment already exists", async () => {
44
+ const { db, spies } = createMockDb<DB>();
45
+ spies.select
46
+ .mockReturnValueOnce(baseActiveItem) // Item exists
47
+ .mockReturnValueOnce(baseChildNode) // Node exists
48
+ .mockReturnValueOnce(baseAssignment); // Assignment exists
49
+
50
+ const result = await run(
51
+ db,
52
+ { itemId: baseActiveItem.id, taxonomyNodeId: baseChildNode.id },
53
+ ctx,
54
+ );
55
+ expect(result.ok).toBe(false);
56
+ if (!result.ok) {
57
+ expect(result.error).toBeInstanceOf(DuplicateAssignmentError);
58
+ }
59
+ });
60
+
61
+ it("creates assignment successfully", async () => {
62
+ const { db, spies } = createMockDb<DB>();
63
+ const createdAssignment = {
64
+ ...baseAssignment,
65
+ id: "new-assignment-id",
66
+ itemId: baseActiveItem.id,
67
+ taxonomyNodeId: baseChildNode.id,
68
+ };
69
+ spies.select
70
+ .mockReturnValueOnce(baseActiveItem) // Item exists
71
+ .mockReturnValueOnce(baseChildNode) // Node exists
72
+ .mockReturnValueOnce(undefined); // No existing assignment
73
+ spies.insert.mockReturnValue(createdAssignment);
74
+
75
+ const result = await run(
76
+ db,
77
+ { itemId: baseActiveItem.id, taxonomyNodeId: baseChildNode.id },
78
+ ctx,
79
+ );
80
+
81
+ expect(result.ok).toBe(true);
82
+ if (result.ok) {
83
+ expect(result.value.assignment.itemId).toBe(baseActiveItem.id);
84
+ expect(result.value.assignment.taxonomyNodeId).toBe(baseChildNode.id);
85
+ }
86
+ expect(spies.insert).toHaveBeenCalled();
87
+ });
88
+ });
@@ -0,0 +1,63 @@
1
+ import { ok, err, type CommandContext } from "../../shared/internal";
2
+ import { DB } from "../generated/kysely-tailordb";
3
+ import {
4
+ DuplicateAssignmentError,
5
+ ItemNotFoundError,
6
+ NodeNotFoundError,
7
+ } from "../lib/errors.generated";
8
+ import { getItem } from "../query/getItem.generated";
9
+ import { getTaxonomyNode } from "../query/getTaxonomyNode.generated";
10
+ import { getItemTaxonomyAssignment } from "../query/getItemTaxonomyAssignment.generated";
11
+
12
+ export interface AssignItemToTaxonomyInput {
13
+ itemId: string;
14
+ taxonomyNodeId: string;
15
+ }
16
+
17
+ /**
18
+ * Function: assignItemToTaxonomy
19
+ *
20
+ * Creates a link between an item and a taxonomy node for many-to-many classification.
21
+ */
22
+ export async function run(db: DB, input: AssignItemToTaxonomyInput, ctx: CommandContext) {
23
+ const { itemId, taxonomyNodeId } = input;
24
+
25
+ // 1. Check item exists
26
+ const { item } = await getItem(db, { id: itemId }, ctx);
27
+
28
+ if (!item) {
29
+ return err(new ItemNotFoundError(itemId));
30
+ }
31
+
32
+ // 2. Check node exists
33
+ const { node } = await getTaxonomyNode(db, { id: taxonomyNodeId }, ctx);
34
+
35
+ if (!node) {
36
+ return err(new NodeNotFoundError(taxonomyNodeId));
37
+ }
38
+
39
+ // 3. Check for duplicate assignment
40
+ const { assignment: existing } = await getItemTaxonomyAssignment(
41
+ db,
42
+ { itemId, taxonomyNodeId },
43
+ ctx,
44
+ );
45
+
46
+ if (existing) {
47
+ return err(new DuplicateAssignmentError(`${itemId} in ${taxonomyNodeId}`));
48
+ }
49
+
50
+ // 4. Create assignment
51
+ const assignment = await db
52
+ .insertInto("ItemTaxonomyAssignment")
53
+ .values({
54
+ itemId,
55
+ taxonomyNodeId,
56
+ createdAt: new Date(),
57
+ updatedAt: null,
58
+ })
59
+ .returningAll()
60
+ .executeTakeFirstOrThrow();
61
+
62
+ return ok({ assignment: assignment });
63
+ }
@@ -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 "./createItem";
5
+
6
+ export const createItem = defineCommand(permissions.createItem, run);