@tailor-platform/erp-kit 0.7.0 → 0.8.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 (635) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +8 -4
  3. package/dist/cli.mjs +70 -70
  4. package/package.json +1 -1
  5. package/skills/erp-kit-app-5-impl-backend/SKILL.md +5 -5
  6. package/skills/erp-kit-app-5-impl-backend/references/app-config.md +1 -1
  7. package/skills/erp-kit-app-5-impl-backend/references/module-wiring.md +37 -12
  8. package/skills/erp-kit-app-6-impl-frontend/SKILL.md +3 -1
  9. package/skills/erp-kit-app-6-impl-frontend/references/component.md +90 -0
  10. package/skills/erp-kit-app-6-impl-frontend/references/detail-view.md +255 -0
  11. package/skills/erp-kit-app-6-impl-frontend/references/pages.md +1 -5
  12. package/skills/erp-kit-app-7-impl-review/SKILL.md +3 -2
  13. package/skills/erp-kit-app-7-impl-review/references/module-wiring-parity.md +14 -8
  14. package/skills/erp-kit-module-6-impl-review/SKILL.md +16 -19
  15. package/skills/erp-kit-module-shared/references/commands.md +68 -1
  16. package/src/commands/index.ts +8 -2
  17. package/src/commands/init.test.ts +24 -8
  18. package/src/commands/init.ts +5 -12
  19. package/src/commands/lib/distribute.test.ts +1 -20
  20. package/src/commands/lib/distribute.ts +0 -14
  21. package/src/commands/update.test.ts +1 -1
  22. package/src/generator/scaffold.ts +25 -4
  23. package/src/module.ts +4 -1
  24. package/src/modules/accounting/README.md +63 -0
  25. package/src/modules/accounting/command/activateBudget.generated.ts +6 -0
  26. package/src/modules/accounting/command/activateBudget.test.ts +119 -0
  27. package/src/modules/accounting/command/activateBudget.ts +77 -0
  28. package/src/modules/accounting/command/activateCostElement.generated.ts +6 -0
  29. package/src/modules/accounting/command/activateCostElement.test.ts +59 -0
  30. package/src/modules/accounting/command/activateCostElement.ts +41 -0
  31. package/src/modules/accounting/command/activateProfitCenter.generated.ts +6 -0
  32. package/src/modules/accounting/command/activateProfitCenter.test.ts +60 -0
  33. package/src/modules/accounting/command/activateProfitCenter.ts +38 -0
  34. package/src/modules/accounting/command/approveBudget.generated.ts +6 -0
  35. package/src/modules/accounting/command/approveBudget.test.ts +69 -0
  36. package/src/modules/accounting/command/approveBudget.ts +47 -0
  37. package/src/modules/accounting/command/assignCostCenterToHierarchyNode.generated.ts +6 -0
  38. package/src/modules/accounting/command/assignCostCenterToHierarchyNode.test.ts +112 -0
  39. package/src/modules/accounting/command/assignCostCenterToHierarchyNode.ts +67 -0
  40. package/src/modules/accounting/command/assignProfitCenterToHierarchyNode.generated.ts +6 -0
  41. package/src/modules/accounting/command/assignProfitCenterToHierarchyNode.test.ts +123 -0
  42. package/src/modules/accounting/command/assignProfitCenterToHierarchyNode.ts +71 -0
  43. package/src/modules/accounting/command/closeBudget.generated.ts +6 -0
  44. package/src/modules/accounting/command/closeBudget.test.ts +93 -0
  45. package/src/modules/accounting/command/closeBudget.ts +40 -0
  46. package/src/modules/accounting/command/closeInternalOrder.generated.ts +6 -0
  47. package/src/modules/accounting/command/closeInternalOrder.test.ts +74 -0
  48. package/src/modules/accounting/command/closeInternalOrder.ts +38 -0
  49. package/src/modules/accounting/command/consumeCommitment.generated.ts +6 -0
  50. package/src/modules/accounting/command/consumeCommitment.test.ts +123 -0
  51. package/src/modules/accounting/command/consumeCommitment.ts +62 -0
  52. package/src/modules/accounting/command/createAllocationCycle.generated.ts +6 -0
  53. package/src/modules/accounting/command/createAllocationCycle.test.ts +166 -0
  54. package/src/modules/accounting/command/createAllocationCycle.ts +68 -0
  55. package/src/modules/accounting/command/createAllocationRule.generated.ts +6 -0
  56. package/src/modules/accounting/command/createAllocationRule.test.ts +195 -0
  57. package/src/modules/accounting/command/createAllocationRule.ts +103 -0
  58. package/src/modules/accounting/command/createBudget.generated.ts +6 -0
  59. package/src/modules/accounting/command/createBudget.test.ts +159 -0
  60. package/src/modules/accounting/command/createBudget.ts +100 -0
  61. package/src/modules/accounting/command/createBudgetLineItem.generated.ts +6 -0
  62. package/src/modules/accounting/command/createBudgetLineItem.test.ts +178 -0
  63. package/src/modules/accounting/command/createBudgetLineItem.ts +104 -0
  64. package/src/modules/accounting/command/createCostCenter.generated.ts +6 -0
  65. package/src/modules/accounting/command/createCostCenter.test.ts +179 -0
  66. package/src/modules/accounting/command/createCostCenter.ts +112 -0
  67. package/src/modules/accounting/command/createCostCenterHierarchy.generated.ts +6 -0
  68. package/src/modules/accounting/command/createCostCenterHierarchy.test.ts +91 -0
  69. package/src/modules/accounting/command/createCostCenterHierarchy.ts +48 -0
  70. package/src/modules/accounting/command/createCostCenterHierarchyNode.generated.ts +6 -0
  71. package/src/modules/accounting/command/createCostCenterHierarchyNode.test.ts +171 -0
  72. package/src/modules/accounting/command/createCostCenterHierarchyNode.ts +117 -0
  73. package/src/modules/accounting/command/createCostElement.generated.ts +6 -0
  74. package/src/modules/accounting/command/createCostElement.test.ts +317 -0
  75. package/src/modules/accounting/command/createCostElement.ts +149 -0
  76. package/src/modules/accounting/command/createInternalOrder.generated.ts +6 -0
  77. package/src/modules/accounting/command/createInternalOrder.test.ts +206 -0
  78. package/src/modules/accounting/command/createInternalOrder.ts +104 -0
  79. package/src/modules/accounting/command/createPlanVersion.generated.ts +6 -0
  80. package/src/modules/accounting/command/createPlanVersion.test.ts +230 -0
  81. package/src/modules/accounting/command/createPlanVersion.ts +71 -0
  82. package/src/modules/accounting/command/createProfitCenter.generated.ts +6 -0
  83. package/src/modules/accounting/command/createProfitCenter.test.ts +227 -0
  84. package/src/modules/accounting/command/createProfitCenter.ts +81 -0
  85. package/src/modules/accounting/command/createProfitCenterHierarchy.generated.ts +6 -0
  86. package/src/modules/accounting/command/createProfitCenterHierarchy.test.ts +91 -0
  87. package/src/modules/accounting/command/createProfitCenterHierarchy.ts +46 -0
  88. package/src/modules/accounting/command/createProfitCenterHierarchyNode.generated.ts +6 -0
  89. package/src/modules/accounting/command/createProfitCenterHierarchyNode.test.ts +160 -0
  90. package/src/modules/accounting/command/createProfitCenterHierarchyNode.ts +109 -0
  91. package/src/modules/accounting/command/deactivateCostElement.generated.ts +6 -0
  92. package/src/modules/accounting/command/deactivateCostElement.test.ts +59 -0
  93. package/src/modules/accounting/command/deactivateCostElement.ts +41 -0
  94. package/src/modules/accounting/command/deactivateProfitCenter.generated.ts +6 -0
  95. package/src/modules/accounting/command/deactivateProfitCenter.test.ts +60 -0
  96. package/src/modules/accounting/command/deactivateProfitCenter.ts +42 -0
  97. package/src/modules/accounting/command/deleteAllocationCycle.generated.ts +6 -0
  98. package/src/modules/accounting/command/deleteAllocationCycle.test.ts +90 -0
  99. package/src/modules/accounting/command/deleteAllocationCycle.ts +39 -0
  100. package/src/modules/accounting/command/deleteAllocationRule.generated.ts +6 -0
  101. package/src/modules/accounting/command/deleteAllocationRule.test.ts +98 -0
  102. package/src/modules/accounting/command/deleteAllocationRule.ts +40 -0
  103. package/src/modules/accounting/command/deleteBudget.generated.ts +6 -0
  104. package/src/modules/accounting/command/deleteBudget.test.ts +90 -0
  105. package/src/modules/accounting/command/deleteBudget.ts +35 -0
  106. package/src/modules/accounting/command/deleteBudgetLineItem.generated.ts +6 -0
  107. package/src/modules/accounting/command/deleteBudgetLineItem.test.ts +85 -0
  108. package/src/modules/accounting/command/deleteBudgetLineItem.ts +50 -0
  109. package/src/modules/accounting/command/deleteCostCenter.generated.ts +6 -0
  110. package/src/modules/accounting/command/deleteCostCenter.test.ts +79 -0
  111. package/src/modules/accounting/command/deleteCostCenter.ts +67 -0
  112. package/src/modules/accounting/command/deleteCostCenterHierarchyNode.generated.ts +6 -0
  113. package/src/modules/accounting/command/deleteCostCenterHierarchyNode.test.ts +59 -0
  114. package/src/modules/accounting/command/deleteCostCenterHierarchyNode.ts +58 -0
  115. package/src/modules/accounting/command/deleteCostElement.generated.ts +6 -0
  116. package/src/modules/accounting/command/deleteCostElement.test.ts +58 -0
  117. package/src/modules/accounting/command/deleteCostElement.ts +33 -0
  118. package/src/modules/accounting/command/deleteInternalOrder.generated.ts +6 -0
  119. package/src/modules/accounting/command/deleteInternalOrder.test.ts +81 -0
  120. package/src/modules/accounting/command/deleteInternalOrder.ts +37 -0
  121. package/src/modules/accounting/command/deleteProfitCenter.generated.ts +6 -0
  122. package/src/modules/accounting/command/deleteProfitCenter.test.ts +68 -0
  123. package/src/modules/accounting/command/deleteProfitCenter.ts +39 -0
  124. package/src/modules/accounting/command/deleteProfitCenterHierarchyNode.generated.ts +6 -0
  125. package/src/modules/accounting/command/deleteProfitCenterHierarchyNode.test.ts +72 -0
  126. package/src/modules/accounting/command/deleteProfitCenterHierarchyNode.ts +61 -0
  127. package/src/modules/accounting/command/executeAllocationCycle.generated.ts +6 -0
  128. package/src/modules/accounting/command/executeAllocationCycle.test.ts +167 -0
  129. package/src/modules/accounting/command/executeAllocationCycle.ts +94 -0
  130. package/src/modules/accounting/command/finalizeVarianceReport.generated.ts +6 -0
  131. package/src/modules/accounting/command/finalizeVarianceReport.test.ts +60 -0
  132. package/src/modules/accounting/command/finalizeVarianceReport.ts +45 -0
  133. package/src/modules/accounting/command/generateVarianceReport.generated.ts +6 -0
  134. package/src/modules/accounting/command/generateVarianceReport.test.ts +386 -0
  135. package/src/modules/accounting/command/generateVarianceReport.ts +219 -0
  136. package/src/modules/accounting/command/invalidateAllocationCycle.generated.ts +6 -0
  137. package/src/modules/accounting/command/invalidateAllocationCycle.test.ts +84 -0
  138. package/src/modules/accounting/command/invalidateAllocationCycle.ts +45 -0
  139. package/src/modules/accounting/command/moveCostCenterHierarchyNode.generated.ts +6 -0
  140. package/src/modules/accounting/command/moveCostCenterHierarchyNode.test.ts +135 -0
  141. package/src/modules/accounting/command/moveCostCenterHierarchyNode.ts +81 -0
  142. package/src/modules/accounting/command/postAllocationCycle.generated.ts +6 -0
  143. package/src/modules/accounting/command/postAllocationCycle.test.ts +98 -0
  144. package/src/modules/accounting/command/postAllocationCycle.ts +65 -0
  145. package/src/modules/accounting/command/reactivateCostElement.generated.ts +6 -0
  146. package/src/modules/accounting/command/reactivateCostElement.test.ts +59 -0
  147. package/src/modules/accounting/command/reactivateCostElement.ts +41 -0
  148. package/src/modules/accounting/command/reactivateProfitCenter.generated.ts +6 -0
  149. package/src/modules/accounting/command/reactivateProfitCenter.test.ts +60 -0
  150. package/src/modules/accounting/command/reactivateProfitCenter.ts +42 -0
  151. package/src/modules/accounting/command/recordCommitment.generated.ts +6 -0
  152. package/src/modules/accounting/command/recordCommitment.test.ts +157 -0
  153. package/src/modules/accounting/command/recordCommitment.ts +113 -0
  154. package/src/modules/accounting/command/rejectBudget.generated.ts +6 -0
  155. package/src/modules/accounting/command/rejectBudget.test.ts +105 -0
  156. package/src/modules/accounting/command/rejectBudget.ts +51 -0
  157. package/src/modules/accounting/command/releaseCommitment.generated.ts +6 -0
  158. package/src/modules/accounting/command/releaseCommitment.test.ts +94 -0
  159. package/src/modules/accounting/command/releaseCommitment.ts +51 -0
  160. package/src/modules/accounting/command/releaseInternalOrder.generated.ts +6 -0
  161. package/src/modules/accounting/command/releaseInternalOrder.test.ts +74 -0
  162. package/src/modules/accounting/command/releaseInternalOrder.ts +38 -0
  163. package/src/modules/accounting/command/reverseAllocationCycle.generated.ts +6 -0
  164. package/src/modules/accounting/command/reverseAllocationCycle.test.ts +124 -0
  165. package/src/modules/accounting/command/reverseAllocationCycle.ts +63 -0
  166. package/src/modules/accounting/command/submitBudget.generated.ts +6 -0
  167. package/src/modules/accounting/command/submitBudget.test.ts +60 -0
  168. package/src/modules/accounting/command/submitBudget.ts +51 -0
  169. package/src/modules/accounting/command/technicallyCompleteInternalOrder.generated.ts +6 -0
  170. package/src/modules/accounting/command/technicallyCompleteInternalOrder.test.ts +74 -0
  171. package/src/modules/accounting/command/technicallyCompleteInternalOrder.ts +42 -0
  172. package/src/modules/accounting/command/updateAllocationCycle.generated.ts +6 -0
  173. package/src/modules/accounting/command/updateAllocationCycle.test.ts +112 -0
  174. package/src/modules/accounting/command/updateAllocationCycle.ts +41 -0
  175. package/src/modules/accounting/command/updateBudget.generated.ts +6 -0
  176. package/src/modules/accounting/command/updateBudget.test.ts +112 -0
  177. package/src/modules/accounting/command/updateBudget.ts +44 -0
  178. package/src/modules/accounting/command/updateCostCenter.generated.ts +6 -0
  179. package/src/modules/accounting/command/updateCostCenter.test.ts +105 -0
  180. package/src/modules/accounting/command/updateCostCenter.ts +79 -0
  181. package/src/modules/accounting/command/updateCostElement.generated.ts +6 -0
  182. package/src/modules/accounting/command/updateCostElement.test.ts +265 -0
  183. package/src/modules/accounting/command/updateCostElement.ts +158 -0
  184. package/src/modules/accounting/command/updateInternalOrder.generated.ts +6 -0
  185. package/src/modules/accounting/command/updateInternalOrder.test.ts +209 -0
  186. package/src/modules/accounting/command/updateInternalOrder.ts +88 -0
  187. package/src/modules/accounting/command/updateProfitCenter.generated.ts +6 -0
  188. package/src/modules/accounting/command/updateProfitCenter.test.ts +162 -0
  189. package/src/modules/accounting/command/updateProfitCenter.ts +73 -0
  190. package/src/modules/accounting/command/validateAllocationCycle.generated.ts +6 -0
  191. package/src/modules/accounting/command/validateAllocationCycle.test.ts +141 -0
  192. package/src/modules/accounting/command/validateAllocationCycle.ts +80 -0
  193. package/src/modules/accounting/db/allocationCycle.ts +59 -0
  194. package/src/modules/accounting/db/allocationResult.ts +58 -0
  195. package/src/modules/accounting/db/allocationRule.ts +48 -0
  196. package/src/modules/accounting/db/budget.ts +84 -0
  197. package/src/modules/accounting/db/budgetLineItem.ts +64 -0
  198. package/src/modules/accounting/db/commitment.ts +60 -0
  199. package/src/modules/accounting/db/costCenter.ts +73 -0
  200. package/src/modules/accounting/db/costCenterHierarchy.ts +37 -0
  201. package/src/modules/accounting/db/costCenterHierarchyNode.ts +48 -0
  202. package/src/modules/accounting/db/costElement.ts +56 -0
  203. package/src/modules/accounting/db/internalOrder.ts +69 -0
  204. package/src/modules/accounting/db/planVersion.ts +47 -0
  205. package/src/modules/accounting/db/profitCenter.ts +52 -0
  206. package/src/modules/accounting/db/profitCenterHierarchy.ts +36 -0
  207. package/src/modules/accounting/db/profitCenterHierarchyAssignment.ts +62 -0
  208. package/src/modules/accounting/db/profitCenterHierarchyNode.ts +48 -0
  209. package/src/modules/accounting/db/varianceReport.ts +54 -0
  210. package/src/modules/accounting/db/varianceReportLine.ts +62 -0
  211. package/src/modules/accounting/docs/commands/ActivateBudget.md +54 -0
  212. package/src/modules/accounting/docs/commands/ActivateCostElement.md +43 -0
  213. package/src/modules/accounting/docs/commands/ActivateProfitCenter.md +43 -0
  214. package/src/modules/accounting/docs/commands/ApproveBudget.md +46 -0
  215. package/src/modules/accounting/docs/commands/AssignCostCenterToHierarchyNode.md +46 -0
  216. package/src/modules/accounting/docs/commands/AssignProfitCenterToHierarchyNode.md +47 -0
  217. package/src/modules/accounting/docs/commands/CloseBudget.md +47 -0
  218. package/src/modules/accounting/docs/commands/CloseInternalOrder.md +45 -0
  219. package/src/modules/accounting/docs/commands/ConsumeCommitment.md +53 -0
  220. package/src/modules/accounting/docs/commands/CreateAllocationCycle.md +55 -0
  221. package/src/modules/accounting/docs/commands/CreateAllocationRule.md +60 -0
  222. package/src/modules/accounting/docs/commands/CreateBudget.md +65 -0
  223. package/src/modules/accounting/docs/commands/CreateBudgetLineItem.md +66 -0
  224. package/src/modules/accounting/docs/commands/CreateCostCenter.md +64 -0
  225. package/src/modules/accounting/docs/commands/CreateCostCenterHierarchy.md +45 -0
  226. package/src/modules/accounting/docs/commands/CreateCostCenterHierarchyNode.md +61 -0
  227. package/src/modules/accounting/docs/commands/CreateCostElement.md +91 -0
  228. package/src/modules/accounting/docs/commands/CreateInternalOrder.md +72 -0
  229. package/src/modules/accounting/docs/commands/CreatePlanVersion.md +59 -0
  230. package/src/modules/accounting/docs/commands/CreateProfitCenter.md +63 -0
  231. package/src/modules/accounting/docs/commands/CreateProfitCenterHierarchy.md +45 -0
  232. package/src/modules/accounting/docs/commands/CreateProfitCenterHierarchyNode.md +60 -0
  233. package/src/modules/accounting/docs/commands/DeactivateCostElement.md +43 -0
  234. package/src/modules/accounting/docs/commands/DeactivateProfitCenter.md +44 -0
  235. package/src/modules/accounting/docs/commands/DeleteAllocationCycle.md +46 -0
  236. package/src/modules/accounting/docs/commands/DeleteAllocationRule.md +45 -0
  237. package/src/modules/accounting/docs/commands/DeleteBudget.md +46 -0
  238. package/src/modules/accounting/docs/commands/DeleteBudgetLineItem.md +45 -0
  239. package/src/modules/accounting/docs/commands/DeleteCostCenter.md +50 -0
  240. package/src/modules/accounting/docs/commands/DeleteCostCenterHierarchyNode.md +45 -0
  241. package/src/modules/accounting/docs/commands/DeleteCostElement.md +43 -0
  242. package/src/modules/accounting/docs/commands/DeleteInternalOrder.md +45 -0
  243. package/src/modules/accounting/docs/commands/DeleteProfitCenter.md +46 -0
  244. package/src/modules/accounting/docs/commands/DeleteProfitCenterHierarchyNode.md +46 -0
  245. package/src/modules/accounting/docs/commands/ExecuteAllocationCycle.md +54 -0
  246. package/src/modules/accounting/docs/commands/FinalizeVarianceReport.md +44 -0
  247. package/src/modules/accounting/docs/commands/GenerateVarianceReport.md +83 -0
  248. package/src/modules/accounting/docs/commands/InvalidateAllocationCycle.md +45 -0
  249. package/src/modules/accounting/docs/commands/MoveCostCenterHierarchyNode.md +51 -0
  250. package/src/modules/accounting/docs/commands/PostAllocationCycle.md +58 -0
  251. package/src/modules/accounting/docs/commands/ReactivateCostElement.md +43 -0
  252. package/src/modules/accounting/docs/commands/ReactivateProfitCenter.md +43 -0
  253. package/src/modules/accounting/docs/commands/RecordCommitment.md +60 -0
  254. package/src/modules/accounting/docs/commands/RejectBudget.md +49 -0
  255. package/src/modules/accounting/docs/commands/ReleaseCommitment.md +45 -0
  256. package/src/modules/accounting/docs/commands/ReleaseInternalOrder.md +44 -0
  257. package/src/modules/accounting/docs/commands/ReverseAllocationCycle.md +55 -0
  258. package/src/modules/accounting/docs/commands/SubmitBudget.md +47 -0
  259. package/src/modules/accounting/docs/commands/TechnicallyCompleteInternalOrder.md +44 -0
  260. package/src/modules/accounting/docs/commands/UpdateAllocationCycle.md +45 -0
  261. package/src/modules/accounting/docs/commands/UpdateBudget.md +47 -0
  262. package/src/modules/accounting/docs/commands/UpdateCostCenter.md +50 -0
  263. package/src/modules/accounting/docs/commands/UpdateCostElement.md +82 -0
  264. package/src/modules/accounting/docs/commands/UpdateInternalOrder.md +62 -0
  265. package/src/modules/accounting/docs/commands/UpdateProfitCenter.md +56 -0
  266. package/src/modules/accounting/docs/commands/ValidateAllocationCycle.md +57 -0
  267. package/src/modules/accounting/docs/features/budget-management.md +147 -0
  268. package/src/modules/accounting/docs/features/cost-allocation.md +129 -0
  269. package/src/modules/accounting/docs/features/cost-center-management.md +118 -0
  270. package/src/modules/accounting/docs/features/cost-element-management.md +114 -0
  271. package/src/modules/accounting/docs/features/internal-order-management.md +111 -0
  272. package/src/modules/accounting/docs/features/profit-center-management.md +120 -0
  273. package/src/modules/accounting/docs/features/variance-analysis.md +130 -0
  274. package/src/modules/accounting/docs/models/AllocationCycle.md +81 -0
  275. package/src/modules/accounting/docs/models/AllocationResult.md +37 -0
  276. package/src/modules/accounting/docs/models/AllocationRule.md +41 -0
  277. package/src/modules/accounting/docs/models/Budget.md +77 -0
  278. package/src/modules/accounting/docs/models/BudgetLineItem.md +40 -0
  279. package/src/modules/accounting/docs/models/Commitment.md +45 -0
  280. package/src/modules/accounting/docs/models/CostCenter.md +51 -0
  281. package/src/modules/accounting/docs/models/CostCenterHierarchy.md +38 -0
  282. package/src/modules/accounting/docs/models/CostCenterHierarchyNode.md +41 -0
  283. package/src/modules/accounting/docs/models/CostElement.md +66 -0
  284. package/src/modules/accounting/docs/models/InternalOrder.md +67 -0
  285. package/src/modules/accounting/docs/models/PlanVersion.md +36 -0
  286. package/src/modules/accounting/docs/models/ProfitCenter.md +66 -0
  287. package/src/modules/accounting/docs/models/ProfitCenterHierarchy.md +36 -0
  288. package/src/modules/accounting/docs/models/ProfitCenterHierarchyAssignment.md +36 -0
  289. package/src/modules/accounting/docs/models/ProfitCenterHierarchyNode.md +39 -0
  290. package/src/modules/accounting/docs/models/VarianceReport.md +58 -0
  291. package/src/modules/accounting/docs/models/VarianceReportLine.md +43 -0
  292. package/src/modules/accounting/docs/queries/CalculateBudgetAvailability.md +64 -0
  293. package/src/modules/accounting/docs/queries/GetAllocationCycle.md +43 -0
  294. package/src/modules/accounting/docs/queries/GetBudget.md +42 -0
  295. package/src/modules/accounting/docs/queries/GetCostCenter.md +38 -0
  296. package/src/modules/accounting/docs/queries/GetCostCenterHierarchy.md +45 -0
  297. package/src/modules/accounting/docs/queries/GetCostElement.md +39 -0
  298. package/src/modules/accounting/docs/queries/GetInternalOrder.md +42 -0
  299. package/src/modules/accounting/docs/queries/GetProfitCenter.md +38 -0
  300. package/src/modules/accounting/docs/queries/GetProfitCenterHierarchy.md +46 -0
  301. package/src/modules/accounting/docs/queries/GetVarianceReport.md +45 -0
  302. package/src/modules/accounting/docs/queries/ListAllocationCycles.md +63 -0
  303. package/src/modules/accounting/docs/queries/ListBudgets.md +70 -0
  304. package/src/modules/accounting/docs/queries/ListCostCenters.md +55 -0
  305. package/src/modules/accounting/docs/queries/ListCostElements.md +63 -0
  306. package/src/modules/accounting/docs/queries/ListInternalOrders.md +62 -0
  307. package/src/modules/accounting/docs/queries/ListProfitCenters.md +49 -0
  308. package/src/modules/accounting/generated/enums.ts +110 -0
  309. package/src/modules/accounting/generated/kysely-tailordb.ts +302 -0
  310. package/src/modules/accounting/index.ts +2 -0
  311. package/src/modules/accounting/lib/_db_deps.ts +70 -0
  312. package/src/modules/accounting/lib/actualAmounts.ts +93 -0
  313. package/src/modules/accounting/lib/allocationPosting.ts +152 -0
  314. package/src/modules/accounting/lib/errors.generated.ts +432 -0
  315. package/src/modules/accounting/lib/permissions.generated.ts +61 -0
  316. package/src/modules/accounting/lib/types.ts +114 -0
  317. package/src/modules/accounting/module.ts +428 -0
  318. package/src/modules/accounting/permissions.ts +3 -0
  319. package/src/modules/accounting/query/calculateBudgetAvailability.generated.ts +5 -0
  320. package/src/modules/accounting/query/calculateBudgetAvailability.test.ts +229 -0
  321. package/src/modules/accounting/query/calculateBudgetAvailability.ts +147 -0
  322. package/src/modules/accounting/query/getAllocationCycle.generated.ts +5 -0
  323. package/src/modules/accounting/query/getAllocationCycle.test.ts +94 -0
  324. package/src/modules/accounting/query/getAllocationCycle.ts +37 -0
  325. package/src/modules/accounting/query/getBudget.generated.ts +5 -0
  326. package/src/modules/accounting/query/getBudget.test.ts +80 -0
  327. package/src/modules/accounting/query/getBudget.ts +31 -0
  328. package/src/modules/accounting/query/getCostCenter.generated.ts +5 -0
  329. package/src/modules/accounting/query/getCostCenter.test.ts +50 -0
  330. package/src/modules/accounting/query/getCostCenter.ts +33 -0
  331. package/src/modules/accounting/query/getCostCenterHierarchy.generated.ts +5 -0
  332. package/src/modules/accounting/query/getCostCenterHierarchy.test.ts +100 -0
  333. package/src/modules/accounting/query/getCostCenterHierarchy.ts +80 -0
  334. package/src/modules/accounting/query/getCostElement.generated.ts +5 -0
  335. package/src/modules/accounting/query/getCostElement.test.ts +57 -0
  336. package/src/modules/accounting/query/getCostElement.ts +21 -0
  337. package/src/modules/accounting/query/getInternalOrder.generated.ts +5 -0
  338. package/src/modules/accounting/query/getInternalOrder.test.ts +73 -0
  339. package/src/modules/accounting/query/getInternalOrder.ts +21 -0
  340. package/src/modules/accounting/query/getProfitCenter.generated.ts +5 -0
  341. package/src/modules/accounting/query/getProfitCenter.test.ts +65 -0
  342. package/src/modules/accounting/query/getProfitCenter.ts +31 -0
  343. package/src/modules/accounting/query/getProfitCenterHierarchy.generated.ts +5 -0
  344. package/src/modules/accounting/query/getProfitCenterHierarchy.test.ts +97 -0
  345. package/src/modules/accounting/query/getProfitCenterHierarchy.ts +87 -0
  346. package/src/modules/accounting/query/getVarianceReport.generated.ts +5 -0
  347. package/src/modules/accounting/query/getVarianceReport.test.ts +108 -0
  348. package/src/modules/accounting/query/getVarianceReport.ts +31 -0
  349. package/src/modules/accounting/query/listAllocationCycles.generated.ts +5 -0
  350. package/src/modules/accounting/query/listAllocationCycles.test.ts +152 -0
  351. package/src/modules/accounting/query/listAllocationCycles.ts +96 -0
  352. package/src/modules/accounting/query/listBudgets.generated.ts +5 -0
  353. package/src/modules/accounting/query/listBudgets.test.ts +150 -0
  354. package/src/modules/accounting/query/listBudgets.ts +85 -0
  355. package/src/modules/accounting/query/listCostCenters.generated.ts +5 -0
  356. package/src/modules/accounting/query/listCostCenters.test.ts +111 -0
  357. package/src/modules/accounting/query/listCostCenters.ts +71 -0
  358. package/src/modules/accounting/query/listCostElements.generated.ts +5 -0
  359. package/src/modules/accounting/query/listCostElements.test.ts +138 -0
  360. package/src/modules/accounting/query/listCostElements.ts +105 -0
  361. package/src/modules/accounting/query/listInternalOrders.generated.ts +5 -0
  362. package/src/modules/accounting/query/listInternalOrders.test.ts +129 -0
  363. package/src/modules/accounting/query/listInternalOrders.ts +94 -0
  364. package/src/modules/accounting/query/listProfitCenters.generated.ts +5 -0
  365. package/src/modules/accounting/query/listProfitCenters.test.ts +94 -0
  366. package/src/modules/accounting/query/listProfitCenters.ts +56 -0
  367. package/src/modules/accounting/seed/index.ts +19 -0
  368. package/src/modules/accounting/tailor.config.ts +13 -0
  369. package/src/modules/accounting/testing/commandTestUtils.ts +35 -0
  370. package/src/modules/accounting/testing/fixtures.ts +502 -0
  371. package/src/modules/audit/command/logAuditEvent.ts +43 -38
  372. package/src/modules/audit/command/updateAuditPolicy.ts +2 -2
  373. package/src/modules/audit/docs/commands/UpdateAuditPolicy.md +1 -1
  374. package/src/modules/audit/module.ts +4 -0
  375. package/src/modules/business-partner/command/updateContactPerson.ts +3 -4
  376. package/src/modules/business-partner/command/updatePartner.ts +13 -6
  377. package/src/modules/business-partner/command/updatePartnerAddress.ts +13 -6
  378. package/src/modules/business-partner/command/updatePartnerBankAccount.ts +3 -4
  379. package/src/modules/business-partner/command/updatePartnerIdentification.ts +3 -4
  380. package/src/modules/business-partner/docs/commands/UpdateContactPerson.md +3 -3
  381. package/src/modules/business-partner/docs/commands/UpdatePartner.md +2 -2
  382. package/src/modules/business-partner/docs/commands/UpdatePartnerAddress.md +2 -2
  383. package/src/modules/business-partner/docs/commands/UpdatePartnerIdentification.md +2 -2
  384. package/src/modules/coa-management/command/updateAccount.ts +3 -3
  385. package/src/modules/coa-management/command/updateAccountGroup.test.ts +22 -0
  386. package/src/modules/coa-management/command/updateAccountGroup.ts +30 -18
  387. package/src/modules/coa-management/command/updateChartOfAccounts.ts +3 -4
  388. package/src/modules/coa-management/docs/commands/UpdateAccountGroup.md +4 -3
  389. package/src/modules/finance-ledger/command/updateFiscalYear.ts +2 -3
  390. package/src/modules/finance-ledger/command/updateJournalEntry.test.ts +0 -17
  391. package/src/modules/finance-ledger/command/updateJournalEntry.ts +2 -10
  392. package/src/modules/finance-ledger/command/updateJournalLine.ts +2 -3
  393. package/src/modules/finance-ledger/docs/commands/UpdateJournalEntry.md +1 -4
  394. package/src/modules/inventory/command/updateLot.test.ts +1 -1
  395. package/src/modules/inventory/command/updateLot.ts +2 -3
  396. package/src/modules/inventory/command/updateStockMovement.ts +2 -3
  397. package/src/modules/inventory/command/updateStorageLocation.ts +12 -17
  398. package/src/modules/inventory/command/updateValuationPolicy.ts +2 -3
  399. package/src/modules/inventory/command/updateWarehouse.ts +2 -3
  400. package/src/modules/inventory/docs/commands/UpdateLot.md +3 -3
  401. package/src/modules/inventory/docs/commands/UpdateStorageLocation.md +6 -6
  402. package/src/modules/inventory/docs/commands/UpdateWarehouse.md +2 -2
  403. package/src/modules/item-management/command/updateItem.test.ts +16 -12
  404. package/src/modules/item-management/command/updateItem.ts +47 -31
  405. package/src/modules/item-management/command/updateTaxonomyNode.test.ts +15 -16
  406. package/src/modules/item-management/command/updateTaxonomyNode.ts +42 -29
  407. package/src/modules/item-management/docs/commands/UpdateItem.md +7 -11
  408. package/src/modules/item-management/docs/commands/UpdateTaxonomyNode.md +10 -14
  409. package/src/modules/manufacturing/command/updateBillOfMaterial.ts +3 -4
  410. package/src/modules/manufacturing/command/updateProductionOrder.ts +3 -4
  411. package/src/modules/manufacturing/command/updateRouting.ts +3 -4
  412. package/src/modules/manufacturing/command/updateWorkCenter.test.ts +16 -7
  413. package/src/modules/manufacturing/command/updateWorkCenter.ts +41 -38
  414. package/src/modules/manufacturing/docs/commands/ActivateWorkCenter.md +2 -0
  415. package/src/modules/manufacturing/docs/commands/CompleteWorkOrder.md +2 -0
  416. package/src/modules/manufacturing/docs/commands/CreateBillOfMaterial.md +1 -0
  417. package/src/modules/manufacturing/docs/commands/ReviewManufacturingCostSummary.md +1 -0
  418. package/src/modules/manufacturing/docs/commands/UpdateWorkCenter.md +6 -5
  419. package/src/modules/manufacturing/docs/models/BillOfMaterialLine.md +42 -0
  420. package/src/modules/manufacturing/docs/models/CostVarianceLine.md +36 -0
  421. package/src/modules/manufacturing/docs/models/ManufacturingCostLine.md +37 -0
  422. package/src/modules/manufacturing/docs/models/ManufacturingCostSettlementRecord.md +34 -0
  423. package/src/modules/manufacturing/docs/models/ProductionOrderBomSnapshot.md +35 -0
  424. package/src/modules/manufacturing/docs/models/ProductionOrderCostBaseline.md +36 -0
  425. package/src/modules/manufacturing/docs/models/ProductionOrderMaterialRequirement.md +35 -0
  426. package/src/modules/manufacturing/docs/models/ProductionOrderRoutingSnapshot.md +34 -0
  427. package/src/modules/manufacturing/docs/models/RoutingOperation.md +40 -0
  428. package/src/modules/manufacturing/docs/models/WorkOrderExecutionEvent.md +38 -0
  429. package/src/modules/manufacturing/docs/queries/ExplodeBillOfMaterial.md +1 -0
  430. package/src/modules/manufacturing/docs/queries/ListWorkCentersBySite.md +1 -0
  431. package/src/modules/organization/command/updateCompany.test.ts +6 -6
  432. package/src/modules/organization/command/updateCompany.ts +3 -4
  433. package/src/modules/organization/command/updateDepartment.test.ts +7 -7
  434. package/src/modules/organization/command/updateDepartment.ts +13 -12
  435. package/src/modules/organization/command/updateSite.test.ts +10 -10
  436. package/src/modules/organization/command/updateSite.ts +3 -4
  437. package/src/modules/organization/docs/commands/UpdateCompany.md +6 -6
  438. package/src/modules/organization/docs/commands/UpdateDepartment.md +9 -10
  439. package/src/modules/organization/docs/commands/UpdateSite.md +12 -12
  440. package/src/modules/product-management/command/updateProduct.test.ts +17 -11
  441. package/src/modules/product-management/command/updateProduct.ts +45 -28
  442. package/src/modules/product-management/command/updateProductAttribute.test.ts +16 -21
  443. package/src/modules/product-management/command/updateProductAttribute.ts +40 -26
  444. package/src/modules/product-management/command/updateProductAttributeValue.ts +2 -3
  445. package/src/modules/product-management/command/updateProductCategory.test.ts +14 -19
  446. package/src/modules/product-management/command/updateProductCategory.ts +42 -26
  447. package/src/modules/product-management/docs/commands/UpdateProduct.md +16 -20
  448. package/src/modules/product-management/docs/commands/UpdateProductAttribute.md +10 -14
  449. package/src/modules/product-management/docs/commands/UpdateProductCategory.md +10 -14
  450. package/src/modules/purchase/command/updateGoodsReceipt.ts +2 -3
  451. package/src/modules/purchase/command/updatePurchaseBill.ts +2 -3
  452. package/src/modules/purchase/command/updatePurchaseOrder.ts +2 -3
  453. package/src/modules/purchase/command/updatePurchasePaymentTerm.ts +2 -3
  454. package/src/modules/purchase/command/updatePurchasePriceList.ts +2 -3
  455. package/src/modules/purchase/command/updatePurchasePriceRule.ts +2 -3
  456. package/src/modules/sales/command/updateChannel.test.ts +4 -4
  457. package/src/modules/sales/command/updateChannel.ts +2 -3
  458. package/src/modules/sales/command/updateListing.test.ts +2 -2
  459. package/src/modules/sales/command/updateListing.ts +2 -3
  460. package/src/modules/sales/command/updateSalesCreditNote.test.ts +2 -2
  461. package/src/modules/sales/command/updateSalesCreditNote.ts +2 -3
  462. package/src/modules/sales/command/updateSalesInvoice.test.ts +2 -2
  463. package/src/modules/sales/command/updateSalesInvoice.ts +2 -3
  464. package/src/modules/sales/command/updateSalesOrder.test.ts +3 -3
  465. package/src/modules/sales/command/updateSalesOrder.ts +2 -3
  466. package/src/modules/sales/command/updateSalesPaymentTerm.test.ts +2 -2
  467. package/src/modules/sales/command/updateSalesPaymentTerm.ts +2 -3
  468. package/src/modules/sales/command/updateSalesPriceList.test.ts +3 -3
  469. package/src/modules/sales/command/updateSalesPriceList.ts +2 -3
  470. package/src/modules/sales/command/updateSalesPriceRule.test.ts +3 -3
  471. package/src/modules/sales/command/updateSalesPriceRule.ts +2 -3
  472. package/src/modules/sales/command/updateShipment.test.ts +2 -2
  473. package/src/modules/sales/command/updateShipment.ts +2 -3
  474. package/src/modules/sales/docs/commands/UpdateChannel.md +4 -4
  475. package/src/modules/sales/docs/commands/UpdateListing.md +2 -2
  476. package/src/modules/sales/docs/commands/UpdateSalesCreditNote.md +2 -2
  477. package/src/modules/sales/docs/commands/UpdateSalesInvoice.md +2 -2
  478. package/src/modules/sales/docs/commands/UpdateSalesOrder.md +3 -3
  479. package/src/modules/sales/docs/commands/UpdateSalesPaymentTerm.md +2 -2
  480. package/src/modules/sales/docs/commands/UpdateSalesPriceList.md +3 -3
  481. package/src/modules/sales/docs/commands/UpdateSalesPriceRule.md +3 -3
  482. package/src/modules/sales/docs/commands/UpdateShipment.md +2 -2
  483. package/src/modules/user-management/README.md +2 -1
  484. package/src/modules/user-management/command/updateOwnProfile.generated.ts +6 -0
  485. package/src/modules/user-management/command/updateOwnProfile.test.ts +191 -0
  486. package/src/modules/user-management/command/updateOwnProfile.ts +82 -0
  487. package/src/modules/user-management/command/updateUser.generated.ts +6 -0
  488. package/src/modules/user-management/command/updateUser.test.ts +195 -0
  489. package/src/modules/user-management/command/updateUser.ts +76 -0
  490. package/src/modules/user-management/docs/commands/UpdateOwnProfile.md +68 -0
  491. package/src/modules/user-management/docs/commands/UpdateUser.md +67 -0
  492. package/src/modules/user-management/docs/features/user-account-management.md +28 -3
  493. package/src/modules/user-management/docs/models/User.md +2 -0
  494. package/src/modules/user-management/lib/errors.generated.ts +5 -0
  495. package/src/modules/user-management/lib/permissions.generated.ts +2 -0
  496. package/src/modules/user-management/module.ts +5 -0
  497. package/src/modules/user-management/seed/index.ts +19 -0
  498. package/templates/scaffold/app/backend/seed/data/AuditEntry.schema.ts +20 -0
  499. package/templates/scaffold/app/backend/seed/data/AuditPolicy.jsonl +7 -0
  500. package/templates/scaffold/app/backend/seed/data/AuditPolicy.schema.ts +15 -0
  501. package/templates/scaffold/app/backend/seed/data/AuditableEntity.jsonl +4 -0
  502. package/templates/scaffold/app/backend/seed/data/AuditableEntity.schema.ts +20 -0
  503. package/templates/scaffold/app/backend/seed/data/ChangeDetail.schema.ts +20 -0
  504. package/templates/scaffold/app/backend/seed/data/Company.schema.ts +15 -0
  505. package/templates/scaffold/app/backend/seed/data/Permission.jsonl +13 -0
  506. package/templates/scaffold/app/backend/seed/data/Permission.schema.ts +1 -1
  507. package/templates/scaffold/app/backend/seed/data/PolicyFieldRule.schema.ts +20 -0
  508. package/templates/scaffold/app/backend/seed/data/Role.jsonl +1 -0
  509. package/templates/scaffold/app/backend/seed/data/Role.schema.ts +1 -1
  510. package/templates/scaffold/app/backend/seed/data/RolePermission.jsonl +13 -0
  511. package/templates/scaffold/app/backend/seed/data/RolePermission.schema.ts +1 -1
  512. package/templates/scaffold/app/backend/seed/data/User.jsonl +1 -1
  513. package/templates/scaffold/app/backend/seed/data/User.schema.ts +1 -1
  514. package/templates/scaffold/app/backend/seed/data/UserRole.jsonl +1 -0
  515. package/templates/scaffold/app/backend/seed/data/UserRole.schema.ts +1 -1
  516. package/templates/scaffold/app/backend/seed/data/_User.jsonl +1 -1
  517. package/templates/scaffold/app/backend/seed/exec.mjs +12 -0
  518. package/templates/scaffold/app/backend/src/executors/permissionCreated.ts +2 -2
  519. package/templates/scaffold/app/backend/src/executors/permissionDeleted.ts +2 -2
  520. package/templates/scaffold/app/backend/src/generated/kysely-tailordb.ts +62 -0
  521. package/templates/scaffold/app/backend/src/modules-db.ts +13 -0
  522. package/templates/scaffold/app/backend/src/modules.ts +3 -5
  523. package/templates/scaffold/app/backend/src/resolvers/assignPermissionToRole.ts +70 -0
  524. package/templates/scaffold/app/backend/src/resolvers/assignRoleToUser.ts +72 -0
  525. package/templates/scaffold/app/backend/src/resolvers/createRole.ts +92 -0
  526. package/templates/scaffold/app/backend/src/resolvers/createUser.ts +113 -13
  527. package/templates/scaffold/app/backend/src/resolvers/deactivateUser.ts +67 -0
  528. package/templates/scaffold/app/backend/src/resolvers/reactivateUser.ts +63 -0
  529. package/templates/scaffold/app/backend/src/resolvers/revokePermissionFromRole.ts +72 -0
  530. package/templates/scaffold/app/backend/src/resolvers/revokeRoleFromUser.ts +72 -0
  531. package/templates/scaffold/app/backend/src/resolvers/updateOwnProfile.ts +107 -0
  532. package/templates/scaffold/app/backend/src/resolvers/updateUserProfile.ts +107 -0
  533. package/templates/scaffold/app/backend/src/tests/stories/audit-log/user--view-audit-log-detail.test.ts +79 -0
  534. package/templates/scaffold/app/backend/src/tests/stories/audit-log/user--view-audit-log.test.ts +86 -0
  535. package/templates/scaffold/app/backend/src/tests/stories/role-management/user--assign-role-to-user.test.ts +103 -0
  536. package/templates/scaffold/app/backend/src/tests/stories/role-management/user--create-role.test.ts +61 -0
  537. package/templates/scaffold/app/backend/src/tests/stories/role-management/user--remove-role-from-user.test.ts +89 -0
  538. package/templates/scaffold/app/backend/src/tests/stories/role-management/user--update-role-permissions.test.ts +125 -0
  539. package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--browse-user-list.test.ts +91 -0
  540. package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--create-user-account.test.ts +97 -0
  541. package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--toggle-user-status.test.ts +131 -0
  542. package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--update-own-profile.test.ts +85 -0
  543. package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--update-user-profile.test.ts +158 -0
  544. package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--view-own-profile.test.ts +30 -0
  545. package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--view-user-detail.test.ts +98 -0
  546. package/templates/scaffold/app/backend/tailor.config.ts +6 -2
  547. package/templates/scaffold/app/docs/actors/user.md +11 -0
  548. package/templates/scaffold/app/docs/business-flow/audit-log/README.md +31 -0
  549. package/templates/scaffold/app/docs/business-flow/audit-log/story/user--view-audit-log-detail.md +35 -0
  550. package/templates/scaffold/app/docs/business-flow/audit-log/story/user--view-audit-log.md +44 -0
  551. package/templates/scaffold/app/docs/business-flow/role-management/README.md +33 -0
  552. package/templates/scaffold/app/docs/business-flow/role-management/story/user--assign-role-to-user.md +35 -0
  553. package/templates/scaffold/app/docs/business-flow/role-management/story/user--create-role.md +41 -0
  554. package/templates/scaffold/app/docs/business-flow/role-management/story/user--remove-role-from-user.md +33 -0
  555. package/templates/scaffold/app/docs/business-flow/role-management/story/user--update-role-permissions.md +41 -0
  556. package/templates/scaffold/app/docs/business-flow/user-lifecycle/README.md +48 -0
  557. package/templates/scaffold/app/docs/business-flow/user-lifecycle/story/user--browse-user-list.md +38 -0
  558. package/templates/scaffold/app/docs/business-flow/user-lifecycle/story/user--create-user-account.md +45 -0
  559. package/templates/scaffold/app/docs/business-flow/user-lifecycle/story/user--toggle-user-status.md +38 -0
  560. package/templates/scaffold/app/docs/business-flow/user-lifecycle/story/user--update-own-profile.md +36 -0
  561. package/templates/scaffold/app/docs/business-flow/user-lifecycle/story/user--update-user-profile.md +41 -0
  562. package/templates/scaffold/app/docs/business-flow/user-lifecycle/story/user--view-own-profile.md +30 -0
  563. package/templates/scaffold/app/docs/business-flow/user-lifecycle/story/user--view-user-detail.md +33 -0
  564. package/templates/scaffold/app/docs/resolver/assignPermissionToRole.md +16 -0
  565. package/templates/scaffold/app/docs/resolver/assignRoleToUser.md +17 -0
  566. package/templates/scaffold/app/docs/resolver/createRole.md +17 -0
  567. package/templates/scaffold/app/docs/resolver/createUser.md +23 -0
  568. package/templates/scaffold/app/docs/resolver/deactivateUser.md +17 -0
  569. package/templates/scaffold/app/docs/resolver/reactivateUser.md +16 -0
  570. package/templates/scaffold/app/docs/resolver/revokePermissionFromRole.md +17 -0
  571. package/templates/scaffold/app/docs/resolver/revokeRoleFromUser.md +17 -0
  572. package/templates/scaffold/app/docs/resolver/updateOwnProfile.md +20 -0
  573. package/templates/scaffold/app/docs/resolver/updateUserProfile.md +19 -0
  574. package/templates/scaffold/app/docs/screen/audit-entry-detail.md +30 -0
  575. package/templates/scaffold/app/docs/screen/audit-entry-list.md +25 -0
  576. package/templates/scaffold/app/docs/screen/my-profile-edit-form.md +22 -0
  577. package/templates/scaffold/app/docs/screen/my-profile.md +27 -0
  578. package/templates/scaffold/app/docs/screen/role-create-form.md +23 -0
  579. package/templates/scaffold/app/docs/screen/role-detail.md +27 -0
  580. package/templates/scaffold/app/docs/screen/role-edit-form.md +21 -0
  581. package/templates/scaffold/app/docs/screen/role-list.md +23 -0
  582. package/templates/scaffold/app/docs/screen/user-create-form.md +23 -0
  583. package/templates/scaffold/app/docs/screen/user-detail.md +33 -0
  584. package/templates/scaffold/app/docs/screen/user-edit-form.md +22 -0
  585. package/templates/scaffold/app/docs/screen/user-list.md +24 -0
  586. package/templates/scaffold/app/frontend/package.json +1 -1
  587. package/templates/scaffold/app/frontend/src/App.tsx +4 -0
  588. package/templates/scaffold/app/frontend/src/components/composed/error-fallback.tsx +1 -1
  589. package/templates/scaffold/app/frontend/src/graphql/generated/graphql-env.d.ts +59 -31
  590. package/templates/scaffold/app/frontend/src/graphql/generated/schema.graphql +1411 -688
  591. package/templates/scaffold/app/frontend/src/hooks/use-toast.ts +1 -1
  592. package/templates/scaffold/app/frontend/src/lib/permission-groups.ts +59 -0
  593. package/templates/scaffold/app/frontend/src/pages/user-management/audit/[id]/components/audit-entry-detail.tsx +102 -0
  594. package/templates/scaffold/app/frontend/src/pages/user-management/audit/[id]/page.tsx +65 -0
  595. package/templates/scaffold/app/frontend/src/pages/user-management/audit/components/audit-entries-table.tsx +90 -0
  596. package/templates/scaffold/app/frontend/src/pages/user-management/audit/page.tsx +52 -0
  597. package/templates/scaffold/app/frontend/src/pages/user-management/profile/edit/components/edit-profile-form.tsx +125 -0
  598. package/templates/scaffold/app/frontend/src/pages/user-management/profile/edit/page.tsx +19 -0
  599. package/templates/scaffold/app/frontend/src/pages/user-management/profile/page.tsx +41 -21
  600. package/templates/scaffold/app/frontend/src/pages/user-management/role/[id]/components/role-actions.tsx +26 -0
  601. package/templates/scaffold/app/frontend/src/pages/user-management/role/[id]/components/role-detail.tsx +69 -0
  602. package/templates/scaffold/app/frontend/src/pages/user-management/role/[id]/edit/components/edit-role-form.tsx +192 -0
  603. package/templates/scaffold/app/frontend/src/pages/user-management/role/[id]/edit/page.tsx +51 -0
  604. package/templates/scaffold/app/frontend/src/pages/user-management/role/[id]/page.tsx +56 -0
  605. package/templates/scaffold/app/frontend/src/pages/user-management/role/components/roles-table.tsx +85 -0
  606. package/templates/scaffold/app/frontend/src/pages/user-management/role/create/components/create-role-form.tsx +204 -0
  607. package/templates/scaffold/app/frontend/src/pages/user-management/role/create/page.tsx +19 -0
  608. package/templates/scaffold/app/frontend/src/pages/user-management/role/page.tsx +60 -0
  609. package/templates/scaffold/app/frontend/src/pages/user-management/user/[id]/components/user-actions.tsx +216 -0
  610. package/templates/scaffold/app/frontend/src/pages/user-management/user/[id]/components/user-detail.tsx +97 -33
  611. package/templates/scaffold/app/frontend/src/pages/user-management/user/[id]/edit/components/edit-user-form.tsx +115 -0
  612. package/templates/scaffold/app/frontend/src/pages/user-management/user/[id]/edit/page.tsx +51 -0
  613. package/templates/scaffold/app/frontend/src/pages/user-management/user/[id]/page.tsx +8 -2
  614. package/templates/scaffold/app/frontend/src/pages/user-management/user/components/users-table.tsx +43 -42
  615. package/templates/scaffold/app/frontend/src/pages/user-management/user/create/components/create-user-form.tsx +120 -45
  616. package/templates/scaffold/app/frontend/src/pages/user-management/user/page.tsx +3 -4
  617. package/templates/scaffold/app/frontend/src/providers/graphql-provider.tsx +8 -1
  618. package/templates/scaffold/module/eslint.config.js +8 -0
  619. package/templates/scaffold/project/__dot__gitignore +1 -0
  620. package/templates/scaffold/project/__pnpm-workspace.yaml +3 -0
  621. package/templates/scaffold/project/apps/.gitkeep +0 -0
  622. package/templates/scaffold/project/modules/.gitkeep +0 -0
  623. package/templates/scaffold/project/package.json +15 -0
  624. package/templates/workflows/erp-kit-check.yml +10 -4
  625. package/templates/scaffold/app/frontend/src/components/ui/badge.tsx +0 -39
  626. package/templates/scaffold/app/frontend/src/components/ui/button.tsx +0 -60
  627. package/templates/scaffold/app/frontend/src/components/ui/card.tsx +0 -75
  628. package/templates/scaffold/app/frontend/src/components/ui/input.tsx +0 -21
  629. package/templates/scaffold/app/frontend/src/components/ui/table.tsx +0 -90
  630. /package/src/modules/{supplier-portal → accounting/executor}/.gitkeep +0 -0
  631. /package/templates/scaffold/app/{docs/actors/.gitkeep → backend/seed/data/AuditEntry.jsonl} +0 -0
  632. /package/templates/scaffold/app/{docs/business-flow/.gitkeep → backend/seed/data/ChangeDetail.jsonl} +0 -0
  633. /package/templates/scaffold/app/{docs/resolver/.gitkeep → backend/seed/data/Company.jsonl} +0 -0
  634. /package/templates/scaffold/app/{docs/screen/.gitkeep → backend/seed/data/PolicyFieldRule.jsonl} +0 -0
  635. /package/templates/{config → scaffold/project}/license.config.json +0 -0
@@ -0,0 +1,191 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../../testing/index";
3
+ import type { Transaction } from "../generated/kysely-tailordb";
4
+ import {
5
+ InvalidEmailError,
6
+ InvalidNameError,
7
+ InvalidStatusTransitionError,
8
+ MissingRequiredFieldError,
9
+ UserAlreadyExistsError,
10
+ UserNotFoundError,
11
+ } from "../lib/errors.generated";
12
+ import { activeUser, inactiveUser, pendingUser } from "../testing/fixtures";
13
+ import { run } from "./updateOwnProfile";
14
+ import type { CommandContext } from "@tailor-platform/erp-kit/module";
15
+
16
+ describe("updateOwnProfile", () => {
17
+ const ctx = { actorId: activeUser.id } as CommandContext;
18
+
19
+ // Success cases
20
+ it("updates own name", async () => {
21
+ const { db, spies } = createMockDb<Transaction>();
22
+ const updatedUser = { ...activeUser, name: "New Name" };
23
+
24
+ spies.select.mockReturnValue(activeUser);
25
+ spies.update.mockReturnValue(updatedUser);
26
+
27
+ const result = await run(db, { name: "New Name" }, ctx);
28
+
29
+ expect(result.ok).toBe(true);
30
+ if (result.ok) {
31
+ expect(result.value.user.name).toBe("New Name");
32
+ }
33
+ expect(spies.update).toHaveBeenCalled();
34
+ });
35
+
36
+ it("updates own email", async () => {
37
+ const { db, spies } = createMockDb<Transaction>();
38
+ const updatedUser = { ...activeUser, email: "newemail@example.com" };
39
+
40
+ spies.select.mockReturnValue(activeUser);
41
+ // Email uniqueness check returns no existing user
42
+ spies.select.mockReturnValueOnce(activeUser).mockReturnValueOnce(undefined);
43
+ spies.update.mockReturnValue(updatedUser);
44
+
45
+ const result = await run(db, { email: "newemail@example.com" }, ctx);
46
+
47
+ expect(result.ok).toBe(true);
48
+ if (result.ok) {
49
+ expect(result.value.user.email).toBe("newemail@example.com");
50
+ }
51
+ expect(spies.update).toHaveBeenCalled();
52
+ });
53
+
54
+ it("updates both own name and email", async () => {
55
+ const { db, spies } = createMockDb<Transaction>();
56
+ const updatedUser = { ...activeUser, name: "New Name", email: "newemail@example.com" };
57
+
58
+ spies.select.mockReturnValueOnce(activeUser).mockReturnValueOnce(undefined);
59
+ spies.update.mockReturnValue(updatedUser);
60
+
61
+ const result = await run(db, { name: "New Name", email: "newemail@example.com" }, ctx);
62
+
63
+ expect(result.ok).toBe(true);
64
+ if (result.ok) {
65
+ expect(result.value.user.name).toBe("New Name");
66
+ expect(result.value.user.email).toBe("newemail@example.com");
67
+ }
68
+ expect(spies.update).toHaveBeenCalled();
69
+ });
70
+
71
+ it("succeeds when email is unchanged (same as current)", async () => {
72
+ const { db, spies } = createMockDb<Transaction>();
73
+ const updatedUser = { ...activeUser };
74
+
75
+ spies.select.mockReturnValue(activeUser);
76
+ spies.update.mockReturnValue(updatedUser);
77
+
78
+ // Using the same email as the active user — no uniqueness check needed
79
+ const result = await run(db, { email: activeUser.email }, ctx);
80
+
81
+ expect(result.ok).toBe(true);
82
+ if (result.ok) {
83
+ expect(result.value.user.email).toBe(activeUser.email);
84
+ }
85
+ expect(spies.update).toHaveBeenCalled();
86
+ });
87
+
88
+ // Error cases
89
+ it("returns error when caller user does not exist", async () => {
90
+ const { db, spies } = createMockDb<Transaction>();
91
+ spies.select.mockReturnValue(undefined);
92
+
93
+ const result = await run(db, { name: "New Name" }, {
94
+ actorId: "nonexistent",
95
+ } as CommandContext);
96
+
97
+ expect(result.ok).toBe(false);
98
+ if (!result.ok) {
99
+ expect(result.error).toBeInstanceOf(UserNotFoundError);
100
+ }
101
+ });
102
+
103
+ it("returns error when caller is in PENDING status", async () => {
104
+ const { db, spies } = createMockDb<Transaction>();
105
+ spies.select.mockReturnValue(pendingUser);
106
+
107
+ const pendingCtx = { actorId: pendingUser.id } as CommandContext;
108
+ const result = await run(db, { name: "New Name" }, pendingCtx);
109
+
110
+ expect(result.ok).toBe(false);
111
+ if (!result.ok) {
112
+ expect(result.error).toBeInstanceOf(InvalidStatusTransitionError);
113
+ }
114
+ });
115
+
116
+ it("returns error when caller is in INACTIVE status", async () => {
117
+ const { db, spies } = createMockDb<Transaction>();
118
+ spies.select.mockReturnValue(inactiveUser);
119
+
120
+ const inactiveCtx = { actorId: inactiveUser.id } as CommandContext;
121
+ const result = await run(db, { name: "New Name" }, inactiveCtx);
122
+
123
+ expect(result.ok).toBe(false);
124
+ if (!result.ok) {
125
+ expect(result.error).toBeInstanceOf(InvalidStatusTransitionError);
126
+ }
127
+ });
128
+
129
+ it("returns error when no fields are provided", async () => {
130
+ const { db, spies } = createMockDb<Transaction>();
131
+ spies.select.mockReturnValue(activeUser);
132
+
133
+ const result = await run(db, {}, ctx);
134
+
135
+ expect(result.ok).toBe(false);
136
+ if (!result.ok) {
137
+ expect(result.error).toBeInstanceOf(MissingRequiredFieldError);
138
+ }
139
+ });
140
+
141
+ it("returns error when name is empty", async () => {
142
+ const { db, spies } = createMockDb<Transaction>();
143
+ spies.select.mockReturnValue(activeUser);
144
+
145
+ const result = await run(db, { name: "" }, ctx);
146
+
147
+ expect(result.ok).toBe(false);
148
+ if (!result.ok) {
149
+ expect(result.error).toBeInstanceOf(InvalidNameError);
150
+ }
151
+ });
152
+
153
+ it("returns error when name is whitespace only", async () => {
154
+ const { db, spies } = createMockDb<Transaction>();
155
+ spies.select.mockReturnValue(activeUser);
156
+
157
+ const result = await run(db, { name: " " }, ctx);
158
+
159
+ expect(result.ok).toBe(false);
160
+ if (!result.ok) {
161
+ expect(result.error).toBeInstanceOf(InvalidNameError);
162
+ }
163
+ });
164
+
165
+ it("returns error when email format is invalid", async () => {
166
+ const { db, spies } = createMockDb<Transaction>();
167
+ spies.select.mockReturnValue(activeUser);
168
+
169
+ const result = await run(db, { email: "invalidemail" }, ctx);
170
+
171
+ expect(result.ok).toBe(false);
172
+ if (!result.ok) {
173
+ expect(result.error).toBeInstanceOf(InvalidEmailError);
174
+ }
175
+ });
176
+
177
+ it("returns error when email is already used by another user", async () => {
178
+ const { db, spies } = createMockDb<Transaction>();
179
+ const otherUser = { ...activeUser, id: "other-user", email: "taken@example.com" };
180
+
181
+ // First select: find the caller user; second select: email uniqueness check finds another user
182
+ spies.select.mockReturnValueOnce(activeUser).mockReturnValueOnce(otherUser);
183
+
184
+ const result = await run(db, { email: "taken@example.com" }, ctx);
185
+
186
+ expect(result.ok).toBe(false);
187
+ if (!result.ok) {
188
+ expect(result.error).toBeInstanceOf(UserAlreadyExistsError);
189
+ }
190
+ });
191
+ });
@@ -0,0 +1,82 @@
1
+ import { Transaction } from "../generated/kysely-tailordb";
2
+ import {
3
+ InvalidEmailError,
4
+ InvalidNameError,
5
+ InvalidStatusTransitionError,
6
+ MissingRequiredFieldError,
7
+ UserAlreadyExistsError,
8
+ UserNotFoundError,
9
+ } from "../lib/errors.generated";
10
+ import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/module";
11
+
12
+ export type UpdateOwnProfileInput = {
13
+ name?: string;
14
+ email?: string;
15
+ };
16
+
17
+ const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
18
+
19
+ export async function run<CF extends Record<string, unknown>>(
20
+ db: Transaction,
21
+ input: UpdateOwnProfileInput & Omit<Partial<CF>, "status">,
22
+ ctx: CommandContext,
23
+ ) {
24
+ const { name, email, ...customFields } = input;
25
+
26
+ const user = await db
27
+ .selectFrom("User")
28
+ .selectAll()
29
+ .where("id", "=", ctx.actorId)
30
+ .forUpdate()
31
+ .executeTakeFirst();
32
+
33
+ if (!user) {
34
+ return err(new UserNotFoundError(ctx.actorId));
35
+ }
36
+
37
+ if (user.status !== "ACTIVE") {
38
+ return err(new InvalidStatusTransitionError(`${user.status} to UPDATE_OWN_PROFILE`));
39
+ }
40
+
41
+ if (name === undefined && email === undefined) {
42
+ return err(new MissingRequiredFieldError("name or email"));
43
+ }
44
+
45
+ if (name?.trim() === "") {
46
+ return err(new InvalidNameError(name));
47
+ }
48
+
49
+ if (email !== undefined) {
50
+ if (!EMAIL_PATTERN.test(email)) {
51
+ return err(new InvalidEmailError(email));
52
+ }
53
+
54
+ // Skip uniqueness check if email is unchanged
55
+ if (email !== user.email) {
56
+ const existingUser = await db
57
+ .selectFrom("User")
58
+ .selectAll()
59
+ .where("email", "=", email)
60
+ .forUpdate()
61
+ .executeTakeFirst();
62
+
63
+ if (existingUser) {
64
+ return err(new UserAlreadyExistsError(email));
65
+ }
66
+ }
67
+ }
68
+
69
+ const updatedUser = await db
70
+ .updateTable("User")
71
+ .set({
72
+ ...(customFields as Record<string, unknown>),
73
+ ...(name !== undefined ? { name } : {}),
74
+ ...(email !== undefined ? { email } : {}),
75
+ updatedAt: new Date(),
76
+ })
77
+ .where("id", "=", ctx.actorId)
78
+ .returningAll()
79
+ .executeTakeFirst();
80
+
81
+ return ok({ user: updatedUser! });
82
+ }
@@ -0,0 +1,6 @@
1
+ // @generated — do not edit
2
+ import { permissions } from "../lib/permissions.generated";
3
+ import { run } from "./updateUser";
4
+ import { defineCommand } from "@tailor-platform/erp-kit/module";
5
+
6
+ export const updateUser = defineCommand(permissions.updateUser, run);
@@ -0,0 +1,195 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../../testing/index";
3
+ import { Transaction } from "../generated/kysely-tailordb";
4
+ import {
5
+ InvalidEmailError,
6
+ InvalidNameError,
7
+ MissingRequiredFieldError,
8
+ UserAlreadyExistsError,
9
+ UserNotFoundError,
10
+ } from "../lib/errors.generated";
11
+ import { activeUser, inactiveUser, pendingUser } from "../testing/fixtures";
12
+ import { run } from "./updateUser";
13
+
14
+ describe("updateUser", () => {
15
+ // Success cases
16
+ it("updates user name", async () => {
17
+ const { db, spies } = createMockDb<Transaction>();
18
+ const updatedUser = { ...activeUser, name: "New Name" };
19
+
20
+ spies.select.mockReturnValue(activeUser);
21
+ spies.update.mockReturnValue(updatedUser);
22
+
23
+ const result = await run(db, { id: activeUser.id, name: "New Name" });
24
+ expect(result.ok).toBe(true);
25
+ if (result.ok) {
26
+ expect(result.value.user.name).toBe("New Name");
27
+ }
28
+ expect(spies.update).toHaveBeenCalled();
29
+ });
30
+
31
+ it("updates user email", async () => {
32
+ const { db, spies } = createMockDb<Transaction>();
33
+ const updatedUser = { ...activeUser, email: "newemail@example.com" };
34
+
35
+ // First select: find the user being updated; second select: no conflicting email
36
+ spies.select.mockReturnValueOnce(activeUser);
37
+ spies.select.mockReturnValueOnce(undefined);
38
+ spies.update.mockReturnValue(updatedUser);
39
+
40
+ const result = await run(db, { id: activeUser.id, email: "newemail@example.com" });
41
+ expect(result.ok).toBe(true);
42
+ if (result.ok) {
43
+ expect(result.value.user.email).toBe("newemail@example.com");
44
+ }
45
+ expect(spies.update).toHaveBeenCalled();
46
+ });
47
+
48
+ it("updates both name and email", async () => {
49
+ const { db, spies } = createMockDb<Transaction>();
50
+ const updatedUser = { ...activeUser, name: "New Name", email: "newemail@example.com" };
51
+
52
+ // First select: find the user being updated; second select: no conflicting email
53
+ spies.select.mockReturnValueOnce(activeUser);
54
+ spies.select.mockReturnValueOnce(undefined);
55
+ spies.update.mockReturnValue(updatedUser);
56
+
57
+ const result = await run(db, {
58
+ id: activeUser.id,
59
+ name: "New Name",
60
+ email: "newemail@example.com",
61
+ });
62
+ expect(result.ok).toBe(true);
63
+ if (result.ok) {
64
+ expect(result.value.user.name).toBe("New Name");
65
+ expect(result.value.user.email).toBe("newemail@example.com");
66
+ }
67
+ expect(spies.update).toHaveBeenCalled();
68
+ });
69
+
70
+ it("updates user in PENDING status", async () => {
71
+ const { db, spies } = createMockDb<Transaction>();
72
+ const updatedUser = { ...pendingUser, name: "Updated Pending" };
73
+
74
+ spies.select.mockReturnValue(pendingUser);
75
+ spies.update.mockReturnValue(updatedUser);
76
+
77
+ const result = await run(db, { id: pendingUser.id, name: "Updated Pending" });
78
+ expect(result.ok).toBe(true);
79
+ if (result.ok) {
80
+ expect(result.value.user.name).toBe("Updated Pending");
81
+ }
82
+ });
83
+
84
+ it("updates user in ACTIVE status", async () => {
85
+ const { db, spies } = createMockDb<Transaction>();
86
+ const updatedUser = { ...activeUser, name: "Updated Active" };
87
+
88
+ spies.select.mockReturnValue(activeUser);
89
+ spies.update.mockReturnValue(updatedUser);
90
+
91
+ const result = await run(db, { id: activeUser.id, name: "Updated Active" });
92
+ expect(result.ok).toBe(true);
93
+ if (result.ok) {
94
+ expect(result.value.user.name).toBe("Updated Active");
95
+ }
96
+ });
97
+
98
+ it("updates user in INACTIVE status", async () => {
99
+ const { db, spies } = createMockDb<Transaction>();
100
+ const updatedUser = { ...inactiveUser, name: "Updated Inactive" };
101
+
102
+ spies.select.mockReturnValue(inactiveUser);
103
+ spies.update.mockReturnValue(updatedUser);
104
+
105
+ const result = await run(db, { id: inactiveUser.id, name: "Updated Inactive" });
106
+ expect(result.ok).toBe(true);
107
+ if (result.ok) {
108
+ expect(result.value.user.name).toBe("Updated Inactive");
109
+ }
110
+ });
111
+
112
+ it("succeeds when email is unchanged (same as current)", async () => {
113
+ const { db, spies } = createMockDb<Transaction>();
114
+ const updatedUser = { ...activeUser };
115
+
116
+ spies.select.mockReturnValue(activeUser);
117
+ spies.update.mockReturnValue(updatedUser);
118
+
119
+ // Email matches current — should skip uniqueness check
120
+ const result = await run(db, { id: activeUser.id, email: activeUser.email });
121
+ expect(result.ok).toBe(true);
122
+ if (result.ok) {
123
+ expect(result.value.user.email).toBe(activeUser.email);
124
+ }
125
+ expect(spies.update).toHaveBeenCalled();
126
+ });
127
+
128
+ // Error cases
129
+ it("returns error when user does not exist", async () => {
130
+ const { db, spies } = createMockDb<Transaction>();
131
+ spies.select.mockReturnValue(undefined);
132
+
133
+ const result = await run(db, { id: "nonexistent-user", name: "Test" });
134
+ expect(result.ok).toBe(false);
135
+ if (!result.ok) {
136
+ expect(result.error).toBeInstanceOf(UserNotFoundError);
137
+ }
138
+ });
139
+
140
+ it("returns error when no fields are provided", async () => {
141
+ const { db } = createMockDb<Transaction>();
142
+
143
+ const result = await run(db, { id: "user-active-1" });
144
+ expect(result.ok).toBe(false);
145
+ if (!result.ok) {
146
+ expect(result.error).toBeInstanceOf(MissingRequiredFieldError);
147
+ }
148
+ });
149
+
150
+ it("returns error when name is empty", async () => {
151
+ const { db } = createMockDb<Transaction>();
152
+
153
+ const result = await run(db, { id: "user-active-1", name: "" });
154
+ expect(result.ok).toBe(false);
155
+ if (!result.ok) {
156
+ expect(result.error).toBeInstanceOf(InvalidNameError);
157
+ }
158
+ });
159
+
160
+ it("returns error when name is whitespace only", async () => {
161
+ const { db } = createMockDb<Transaction>();
162
+
163
+ const result = await run(db, { id: "user-active-1", name: " " });
164
+ expect(result.ok).toBe(false);
165
+ if (!result.ok) {
166
+ expect(result.error).toBeInstanceOf(InvalidNameError);
167
+ }
168
+ });
169
+
170
+ it("returns error when email format is invalid", async () => {
171
+ const { db } = createMockDb<Transaction>();
172
+
173
+ const result = await run(db, { id: "user-active-1", email: "invalidemail" });
174
+ expect(result.ok).toBe(false);
175
+ if (!result.ok) {
176
+ expect(result.error).toBeInstanceOf(InvalidEmailError);
177
+ }
178
+ });
179
+
180
+ it("returns error when email is already used by another user", async () => {
181
+ const { db, spies } = createMockDb<Transaction>();
182
+ const anotherUser = { ...activeUser, id: "other-user", email: "taken@example.com" };
183
+
184
+ // First select: find the user being updated
185
+ spies.select.mockReturnValueOnce(activeUser);
186
+ // Second select: find the conflicting user with the same email
187
+ spies.select.mockReturnValueOnce(anotherUser);
188
+
189
+ const result = await run(db, { id: activeUser.id, email: "taken@example.com" });
190
+ expect(result.ok).toBe(false);
191
+ if (!result.ok) {
192
+ expect(result.error).toBeInstanceOf(UserAlreadyExistsError);
193
+ }
194
+ });
195
+ });
@@ -0,0 +1,76 @@
1
+ import { Transaction } from "../generated/kysely-tailordb";
2
+ import {
3
+ InvalidEmailError,
4
+ InvalidNameError,
5
+ MissingRequiredFieldError,
6
+ UserAlreadyExistsError,
7
+ UserNotFoundError,
8
+ } from "../lib/errors.generated";
9
+ import { ok, err } from "@tailor-platform/erp-kit/module";
10
+
11
+ export type UpdateUserInput = { id: string } & { name?: string; email?: string };
12
+
13
+ const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
14
+
15
+ /**
16
+ * Function: updateUser
17
+ *
18
+ * Updates an existing user's name or email.
19
+ * At least one field must be provided. Email must be unique.
20
+ */
21
+ export async function run<CF extends Record<string, unknown>>(
22
+ db: Transaction,
23
+ input: UpdateUserInput & Omit<Partial<CF>, "status">,
24
+ ) {
25
+ const { id, name, email, ...customFields } = input;
26
+
27
+ if (name === undefined && email === undefined && Object.keys(customFields).length === 0) {
28
+ return err(new MissingRequiredFieldError("name or email"));
29
+ }
30
+
31
+ if (name?.trim() === "") {
32
+ return err(new InvalidNameError(name));
33
+ }
34
+
35
+ if (email !== undefined && !EMAIL_PATTERN.test(email)) {
36
+ return err(new InvalidEmailError(email));
37
+ }
38
+
39
+ const user = await db
40
+ .selectFrom("User")
41
+ .selectAll()
42
+ .where("id", "=", id)
43
+ .forUpdate()
44
+ .executeTakeFirst();
45
+
46
+ if (!user) {
47
+ return err(new UserNotFoundError(id));
48
+ }
49
+
50
+ if (email !== undefined && email !== user.email) {
51
+ const existingUser = await db
52
+ .selectFrom("User")
53
+ .selectAll()
54
+ .where("email", "=", email)
55
+ .forUpdate()
56
+ .executeTakeFirst();
57
+
58
+ if (existingUser) {
59
+ return err(new UserAlreadyExistsError(email));
60
+ }
61
+ }
62
+
63
+ const updatedUser = await db
64
+ .updateTable("User")
65
+ .set({
66
+ ...(customFields as Record<string, unknown>),
67
+ ...(name !== undefined ? { name } : {}),
68
+ ...(email !== undefined ? { email } : {}),
69
+ updatedAt: new Date(),
70
+ })
71
+ .where("id", "=", id)
72
+ .returningAll()
73
+ .executeTakeFirst();
74
+
75
+ return ok({ user: updatedUser! });
76
+ }
@@ -0,0 +1,68 @@
1
+ # UpdateOwnProfile
2
+
3
+ ## Overview
4
+
5
+ UpdateOwnProfile allows an ACTIVE user to update their own profile fields (name, email). The command implicitly targets the calling user — no userId parameter is needed. This provides a self-service update path that is separate from the admin-only updateUser command.
6
+
7
+ Only ACTIVE users can update their own profile. PENDING and INACTIVE users are rejected.
8
+
9
+ ## Business Rules
10
+
11
+ - Caller must be an existing user (resolved from context)
12
+ - Caller must be in ACTIVE status
13
+ - At least one field (name or email) must be provided
14
+ - Name, if provided, must be non-empty
15
+ - Email, if provided, must follow valid email format
16
+ - Email must be unique across all users (active and inactive); case-insensitive comparison
17
+ - Generates USER_UPDATED audit event with actor ID, timestamp, and changed fields
18
+
19
+ ## Process Flow
20
+
21
+ ```mermaid
22
+ flowchart TD
23
+ A[Receive update request] --> B{Caller user exists?}
24
+ B -->|No| C[Return error: USER_NOT_FOUND]
25
+ B -->|Yes| D{Caller status is ACTIVE?}
26
+ D -->|No| E[Return error: INVALID_STATUS_TRANSITION]
27
+ D -->|Yes| F{At least one field provided?}
28
+ F -->|No| G[Return error: MISSING_REQUIRED_FIELD]
29
+ F -->|Yes| H{Name provided and empty?}
30
+ H -->|Yes| I[Return error: INVALID_NAME]
31
+ H -->|No| J{Email provided?}
32
+ J -->|Yes| K{Valid email format?}
33
+ K -->|No| L[Return error: INVALID_EMAIL]
34
+ K -->|Yes| M{Email unique?}
35
+ M -->|No| N[Return error: USER_ALREADY_EXISTS]
36
+ M -->|Yes| O[Update user record]
37
+ J -->|No| O
38
+ O --> P[Log USER_UPDATED audit event]
39
+ P --> Q[Return updated user]
40
+ ```
41
+
42
+ ## External Dependencies
43
+
44
+ - None
45
+
46
+ ## Error Scenarios
47
+
48
+ - **USER_NOT_FOUND**: Caller's user ID does not exist in the system
49
+ - **INVALID_STATUS_TRANSITION**: Caller is not in ACTIVE status (PENDING or INACTIVE)
50
+ - **MISSING_REQUIRED_FIELD**: Neither name nor email was provided in the update input
51
+ - **INVALID_NAME**: Name is empty or whitespace only
52
+ - **INVALID_EMAIL**: Email does not follow valid email format
53
+ - **USER_ALREADY_EXISTS**: Email address is already registered by another user
54
+
55
+ ## Test Cases
56
+
57
+ - updates own name
58
+ - updates own email
59
+ - updates both own name and email
60
+ - returns error when caller user does not exist
61
+ - returns error when caller is in PENDING status
62
+ - returns error when caller is in INACTIVE status
63
+ - returns error when no fields are provided
64
+ - returns error when name is empty
65
+ - returns error when name is whitespace only
66
+ - returns error when email format is invalid
67
+ - returns error when email is already used by another user
68
+ - succeeds when email is unchanged (same as current)
@@ -0,0 +1,67 @@
1
+ # UpdateUser
2
+
3
+ ## Overview
4
+
5
+ UpdateUser modifies the name or email of an existing user account. This command is intended for administrators who need to update any user's profile regardless of the user's current status (PENDING, ACTIVE, or INACTIVE). Email and name are optional in the update input, but at least one must be provided.
6
+
7
+ This command supports profile corrections such as legal name changes and email address updates.
8
+
9
+ ## Business Rules
10
+
11
+ - User must exist
12
+ - At least one field (name or email) must be provided
13
+ - Name, if provided, must be non-empty
14
+ - Email, if provided, must follow valid email format
15
+ - Email must be unique across all users (active and inactive); case-insensitive comparison
16
+ - Updating is allowed on users in any status (PENDING, ACTIVE, INACTIVE)
17
+ - Status is not part of the update input (use activateUser/deactivateUser/reactivateUser for status changes)
18
+ - Generates USER_UPDATED audit event with actor ID, timestamp, and changed fields
19
+
20
+ ## Process Flow
21
+
22
+ ```mermaid
23
+ flowchart TD
24
+ A[Receive update request] --> B{User exists?}
25
+ B -->|No| C[Return error: USER_NOT_FOUND]
26
+ B -->|Yes| D{At least one field provided?}
27
+ D -->|No| E[Return error: MISSING_REQUIRED_FIELD]
28
+ D -->|Yes| F{Name provided and empty?}
29
+ F -->|Yes| G[Return error: INVALID_NAME]
30
+ F -->|No| H{Email provided?}
31
+ H -->|Yes| I{Valid email format?}
32
+ I -->|No| J[Return error: INVALID_EMAIL]
33
+ I -->|Yes| K{Email unique?}
34
+ K -->|No| L[Return error: USER_ALREADY_EXISTS]
35
+ K -->|Yes| M[Update user record]
36
+ H -->|No| M
37
+ M --> N[Log USER_UPDATED audit event]
38
+ N --> O[Return updated user]
39
+ ```
40
+
41
+ ## External Dependencies
42
+
43
+ - None
44
+
45
+ ## Error Scenarios
46
+
47
+ - **USER_NOT_FOUND**: Specified user ID does not exist in the system
48
+ - **MISSING_REQUIRED_FIELD**: Neither name nor email was provided in the update input
49
+ - **INVALID_NAME**: Name is empty or whitespace only
50
+ - **INVALID_EMAIL**: Email does not follow valid email format
51
+ - **USER_ALREADY_EXISTS**: Email address is already registered by another user
52
+
53
+ ## Test Cases
54
+
55
+ - updates user name
56
+ - updates user email
57
+ - updates both name and email
58
+ - updates user in PENDING status
59
+ - updates user in ACTIVE status
60
+ - updates user in INACTIVE status
61
+ - returns error when user does not exist
62
+ - returns error when no fields are provided
63
+ - returns error when name is empty
64
+ - returns error when name is whitespace only
65
+ - returns error when email format is invalid
66
+ - returns error when email is already used by another user
67
+ - succeeds when email is unchanged (same as current)