@tailor-platform/erp-kit 0.8.0 → 0.9.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 (159) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +1 -1
  3. package/skills/erp-kit-app-1-requirements/SKILL.md +6 -0
  4. package/skills/erp-kit-app-2-requirements-review/SKILL.md +6 -0
  5. package/skills/erp-kit-app-3-plan/SKILL.md +6 -0
  6. package/skills/erp-kit-app-4-plan-review/SKILL.md +6 -0
  7. package/skills/erp-kit-app-5-impl-backend/SKILL.md +7 -0
  8. package/skills/erp-kit-app-6-impl-frontend/SKILL.md +6 -0
  9. package/skills/erp-kit-app-7-impl-review/SKILL.md +6 -0
  10. package/skills/erp-kit-app-shared/SKILL.md +2 -0
  11. package/skills/erp-kit-mock-scenario/SKILL.md +6 -0
  12. package/skills/erp-kit-module-1-requirements/SKILL.md +6 -0
  13. package/skills/erp-kit-module-2-requirements-review/SKILL.md +6 -0
  14. package/skills/erp-kit-module-3-plan/SKILL.md +6 -0
  15. package/skills/erp-kit-module-3-update-plan/SKILL.md +6 -0
  16. package/skills/erp-kit-module-4-plan-review/SKILL.md +6 -0
  17. package/skills/erp-kit-module-5-impl/SKILL.md +6 -0
  18. package/skills/erp-kit-module-6-impl-review/SKILL.md +6 -0
  19. package/skills/erp-kit-module-shared/SKILL.md +2 -0
  20. package/skills/erp-kit-module-shared/references/commands.md +3 -0
  21. package/skills/erp-kit-update/SKILL.md +6 -0
  22. package/src/modules/accounting/command/assignProfitCenterToHierarchyNode.test.ts +3 -3
  23. package/src/modules/accounting/command/assignProfitCenterToHierarchyNode.ts +1 -1
  24. package/src/modules/accounting/command/createCostCenterHierarchyNode.test.ts +3 -3
  25. package/src/modules/accounting/command/createCostCenterHierarchyNode.ts +1 -1
  26. package/src/modules/accounting/command/moveCostCenterHierarchyNode.test.ts +2 -2
  27. package/src/modules/accounting/command/moveCostCenterHierarchyNode.ts +1 -1
  28. package/src/modules/accounting/module.ts +1 -0
  29. package/src/modules/business-partner/command/createPartnerBankAccount.test.ts +3 -3
  30. package/src/modules/business-partner/command/createPartnerBankAccount.ts +1 -1
  31. package/src/modules/business-partner/module.ts +1 -0
  32. package/src/modules/coa-management/command/activateAccount.test.ts +0 -15
  33. package/src/modules/coa-management/command/activateAccount.ts +1 -42
  34. package/src/modules/coa-management/command/activateChartOfAccounts.test.ts +2 -31
  35. package/src/modules/coa-management/command/activateChartOfAccounts.ts +1 -37
  36. package/src/modules/coa-management/command/createAccount.test.ts +0 -28
  37. package/src/modules/coa-management/command/createAccount.ts +0 -43
  38. package/src/modules/coa-management/command/createAccountGroup.test.ts +2 -51
  39. package/src/modules/coa-management/command/createAccountGroup.ts +1 -56
  40. package/src/modules/coa-management/command/createChartOfAccounts.test.ts +1 -49
  41. package/src/modules/coa-management/command/createChartOfAccounts.ts +0 -51
  42. package/src/modules/coa-management/command/deactivateAccount.test.ts +0 -15
  43. package/src/modules/coa-management/command/deactivateAccount.ts +1 -53
  44. package/src/modules/coa-management/command/deactivateChartOfAccounts.test.ts +2 -29
  45. package/src/modules/coa-management/command/deactivateChartOfAccounts.ts +1 -37
  46. package/src/modules/coa-management/command/deleteAccount.test.ts +0 -13
  47. package/src/modules/coa-management/command/deleteAccount.ts +1 -42
  48. package/src/modules/coa-management/command/deleteAccountGroup.test.ts +0 -19
  49. package/src/modules/coa-management/command/deleteAccountGroup.ts +1 -42
  50. package/src/modules/coa-management/command/deleteChartOfAccounts.test.ts +2 -58
  51. package/src/modules/coa-management/command/deleteChartOfAccounts.ts +4 -88
  52. package/src/modules/coa-management/command/moveAccountGroup.test.ts +0 -27
  53. package/src/modules/coa-management/command/moveAccountGroup.ts +1 -48
  54. package/src/modules/coa-management/command/reactivateAccount.test.ts +0 -15
  55. package/src/modules/coa-management/command/reactivateAccount.ts +1 -53
  56. package/src/modules/coa-management/command/updateAccount.test.ts +0 -15
  57. package/src/modules/coa-management/command/updateAccount.ts +0 -92
  58. package/src/modules/coa-management/command/updateAccountGroup.test.ts +0 -20
  59. package/src/modules/coa-management/command/updateAccountGroup.ts +1 -61
  60. package/src/modules/coa-management/command/updateChartOfAccounts.test.ts +2 -31
  61. package/src/modules/coa-management/command/updateChartOfAccounts.ts +1 -50
  62. package/src/modules/coa-management/docs/commands/ActivateAccount.md +1 -4
  63. package/src/modules/coa-management/docs/commands/ActivateChartOfAccounts.md +1 -4
  64. package/src/modules/coa-management/docs/commands/CreateAccount.md +1 -4
  65. package/src/modules/coa-management/docs/commands/CreateAccountGroup.md +2 -5
  66. package/src/modules/coa-management/docs/commands/CreateChartOfAccounts.md +2 -6
  67. package/src/modules/coa-management/docs/commands/DeactivateAccount.md +1 -4
  68. package/src/modules/coa-management/docs/commands/DeactivateChartOfAccounts.md +1 -4
  69. package/src/modules/coa-management/docs/commands/DeleteAccount.md +1 -4
  70. package/src/modules/coa-management/docs/commands/DeleteAccountGroup.md +1 -4
  71. package/src/modules/coa-management/docs/commands/DeleteChartOfAccounts.md +1 -6
  72. package/src/modules/coa-management/docs/commands/MoveAccountGroup.md +1 -4
  73. package/src/modules/coa-management/docs/commands/ReactivateAccount.md +1 -4
  74. package/src/modules/coa-management/docs/commands/UpdateAccount.md +1 -4
  75. package/src/modules/coa-management/docs/commands/UpdateAccountGroup.md +2 -5
  76. package/src/modules/coa-management/docs/commands/UpdateChartOfAccounts.md +1 -4
  77. package/src/modules/coa-management/module.ts +16 -27
  78. package/src/modules/finance-ledger/module.ts +1 -0
  79. package/src/modules/inventory/command/approveInventoryAdjustment.test.ts +1 -1
  80. package/src/modules/inventory/command/approveInventoryAdjustment.ts +1 -1
  81. package/src/modules/inventory/command/cancelStockMovement.test.ts +2 -2
  82. package/src/modules/inventory/command/cancelStockMovement.ts +1 -1
  83. package/src/modules/inventory/command/confirmInventoryAdjustment.test.ts +4 -4
  84. package/src/modules/inventory/command/confirmInventoryAdjustment.ts +1 -1
  85. package/src/modules/inventory/command/confirmStockMovement.test.ts +1 -1
  86. package/src/modules/inventory/command/confirmStockMovement.ts +1 -1
  87. package/src/modules/inventory/command/createInventoryAdjustment.test.ts +6 -6
  88. package/src/modules/inventory/command/createInventoryAdjustment.ts +1 -1
  89. package/src/modules/inventory/command/createStockMovement.test.ts +3 -3
  90. package/src/modules/inventory/command/createStockMovement.ts +1 -1
  91. package/src/modules/inventory/command/executeStockMovement.test.ts +5 -5
  92. package/src/modules/inventory/command/executeStockMovement.ts +1 -1
  93. package/src/modules/inventory/command/rejectInventoryAdjustment.test.ts +1 -1
  94. package/src/modules/inventory/command/rejectInventoryAdjustment.ts +1 -1
  95. package/src/modules/inventory/command/reviseInventoryAdjustment.test.ts +2 -2
  96. package/src/modules/inventory/command/reviseInventoryAdjustment.ts +1 -1
  97. package/src/modules/inventory/command/submitInventoryAdjustment.test.ts +1 -1
  98. package/src/modules/inventory/command/submitInventoryAdjustment.ts +1 -1
  99. package/src/modules/inventory/command/updateStockMovement.test.ts +4 -4
  100. package/src/modules/inventory/command/updateStockMovement.ts +2 -2
  101. package/src/modules/inventory/module.ts +1 -0
  102. package/src/modules/item-management/command/createTaxonomyNode.test.ts +4 -4
  103. package/src/modules/item-management/command/createTaxonomyNode.ts +1 -1
  104. package/src/modules/item-management/command/moveTaxonomyNode.test.ts +2 -2
  105. package/src/modules/item-management/command/moveTaxonomyNode.ts +2 -2
  106. package/src/modules/item-management/command/updateTaxonomyNode.test.ts +2 -2
  107. package/src/modules/item-management/command/updateTaxonomyNode.ts +1 -1
  108. package/src/modules/item-management/module.ts +1 -0
  109. package/src/modules/manufacturing/command/createRouting.ts +1 -1
  110. package/src/modules/manufacturing/command/recordInventoryIssueOutcome.test.ts +1 -1
  111. package/src/modules/manufacturing/command/recordInventoryIssueOutcome.ts +1 -1
  112. package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.test.ts +1 -1
  113. package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.ts +1 -1
  114. package/src/modules/manufacturing/command/reviewManufacturingCostSummary.test.ts +1 -1
  115. package/src/modules/manufacturing/command/reviewManufacturingCostSummary.ts +1 -1
  116. package/src/modules/manufacturing/command/updateRouting.ts +1 -1
  117. package/src/modules/manufacturing/module.ts +1 -0
  118. package/src/modules/organization/module.ts +1 -0
  119. package/src/modules/primitives/module.ts +1 -0
  120. package/src/modules/product-management/command/assignProductToCategory.test.ts +2 -2
  121. package/src/modules/product-management/command/assignProductToCategory.ts +2 -2
  122. package/src/modules/product-management/command/createProductAttribute.test.ts +1 -1
  123. package/src/modules/product-management/command/createProductAttribute.ts +1 -1
  124. package/src/modules/product-management/command/createProductAttributeValue.test.ts +1 -1
  125. package/src/modules/product-management/command/createProductAttributeValue.ts +1 -1
  126. package/src/modules/product-management/command/createProductCategory.test.ts +2 -2
  127. package/src/modules/product-management/command/createProductCategory.ts +1 -1
  128. package/src/modules/product-management/command/setProductAttributeAssignment.test.ts +3 -3
  129. package/src/modules/product-management/command/setProductAttributeAssignment.ts +2 -2
  130. package/src/modules/product-management/module.ts +1 -0
  131. package/src/modules/purchase/command/activatePurchasePaymentTerm.test.ts +4 -4
  132. package/src/modules/purchase/command/activatePurchasePaymentTerm.ts +2 -2
  133. package/src/modules/purchase/command/deactivatePurchasePaymentTerm.test.ts +4 -4
  134. package/src/modules/purchase/command/deactivatePurchasePaymentTerm.ts +2 -2
  135. package/src/modules/purchase/command/updatePurchasePaymentTerm.test.ts +2 -2
  136. package/src/modules/purchase/command/updatePurchasePaymentTerm.ts +1 -1
  137. package/src/modules/purchase/module.ts +1 -0
  138. package/src/modules/sales/command/createSalesOrder.ts +1 -1
  139. package/src/modules/sales/module.ts +1 -0
  140. package/templates/scaffold/app/backend/eslint.config.js +17 -0
  141. package/templates/scaffold/app/backend/package.json +1 -0
  142. package/templates/scaffold/app/backend/src/tests/stories/audit-log/user--view-audit-log-detail.test.ts +3 -3
  143. package/templates/scaffold/app/backend/src/tests/stories/role-management/user--assign-role-to-user.test.ts +4 -4
  144. package/templates/scaffold/app/backend/src/tests/stories/role-management/user--remove-role-from-user.test.ts +4 -4
  145. package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--toggle-user-status.test.ts +6 -6
  146. package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--update-own-profile.test.ts +13 -13
  147. package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--update-user-profile.test.ts +16 -17
  148. package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--view-user-detail.test.ts +3 -3
  149. package/templates/scaffold/app/backend/tailor.config.ts +15 -1
  150. package/templates/scaffold/app/backend/tsconfig.json +1 -1
  151. package/templates/scaffold/app/frontend/src/App.tsx +57 -16
  152. package/templates/scaffold/module/eslint.config.js +24 -0
  153. package/templates/scaffold/module/module.ts +1 -0
  154. package/templates/scaffold/module/package.json +3 -1
  155. package/templates/scaffold/module/vitest.config.ts +11 -0
  156. /package/templates/scaffold/app/frontend/src/pages/{user-management/audit → audit}/[id]/components/audit-entry-detail.tsx +0 -0
  157. /package/templates/scaffold/app/frontend/src/pages/{user-management/audit → audit}/[id]/page.tsx +0 -0
  158. /package/templates/scaffold/app/frontend/src/pages/{user-management/audit → audit}/components/audit-entries-table.tsx +0 -0
  159. /package/templates/scaffold/app/frontend/src/pages/{user-management/audit → audit}/page.tsx +0 -0
@@ -133,5 +133,5 @@ export async function run<CF extends Record<string, unknown>>(
133
133
  .returningAll()
134
134
  .executeTakeFirst();
135
135
 
136
- return ok({ costSummary: updatedSummary! });
136
+ return ok({ manufacturingCostSummary: updatedSummary! });
137
137
  }
@@ -119,5 +119,5 @@ export async function run<CF extends Record<string, unknown>>(
119
119
  createdOperations.push(operation!);
120
120
  }
121
121
 
122
- return ok({ routing: updatedRouting!, operations: createdOperations });
122
+ return ok({ routing: updatedRouting!, routingOperations: createdOperations });
123
123
  }
@@ -82,6 +82,7 @@ export interface DefineModuleParams<WCF extends Record<string, TailorAnyDBField>
82
82
  };
83
83
  }
84
84
 
85
+ /* @__NO_SIDE_EFFECTS__ */
85
86
  export const defineModule = <const WCF extends Record<string, TailorAnyDBField> = EmptyFields>(
86
87
  params: DefineModuleParams<WCF>,
87
88
  ) => {
@@ -44,6 +44,7 @@ export interface DefineModuleParams<
44
44
  };
45
45
  }
46
46
 
47
+ /* @__NO_SIDE_EFFECTS__ */
47
48
  export const defineModule = <
48
49
  const CF extends Record<string, TailorAnyDBField> = EmptyFields,
49
50
  const SF extends Record<string, TailorAnyDBField> = EmptyFields,
@@ -36,6 +36,7 @@ export interface DefineModuleParams<
36
36
  exchangeRate?: CreateExchangeRateTypeParams<ERF>;
37
37
  }
38
38
 
39
+ /* @__NO_SIDE_EFFECTS__ */
39
40
  export const defineModule = <
40
41
  const CatF extends Record<string, TailorAnyDBField> = EmptyFields,
41
42
  const UnitF extends Record<string, TailorAnyDBField> = EmptyFields,
@@ -63,7 +63,7 @@ describe("assignProductToCategory", () => {
63
63
  const result = await run(db, input);
64
64
  expect(result.ok).toBe(true);
65
65
  if (result.ok) {
66
- expect(result.value.assignment).toEqual(newAssignment);
66
+ expect(result.value.productCategoryAssignment).toEqual(newAssignment);
67
67
  }
68
68
  });
69
69
 
@@ -83,7 +83,7 @@ describe("assignProductToCategory", () => {
83
83
  const result = await run(db, input);
84
84
  expect(result.ok).toBe(true);
85
85
  if (result.ok) {
86
- expect(result.value.assignment).toEqual(baseCategoryAssignment);
86
+ expect(result.value.productCategoryAssignment).toEqual(baseCategoryAssignment);
87
87
  }
88
88
  expect(spies.insert).not.toHaveBeenCalled();
89
89
  });
@@ -44,7 +44,7 @@ export async function run(db: Transaction, input: AssignProductToCategoryInput)
44
44
  .forUpdate()
45
45
  .executeTakeFirst();
46
46
  if (existing) {
47
- return ok({ assignment: existing });
47
+ return ok({ productCategoryAssignment: existing });
48
48
  }
49
49
 
50
50
  const assignment = await db
@@ -58,5 +58,5 @@ export async function run(db: Transaction, input: AssignProductToCategoryInput)
58
58
  .returningAll()
59
59
  .executeTakeFirstOrThrow();
60
60
 
61
- return ok({ assignment });
61
+ return ok({ productCategoryAssignment: assignment });
62
62
  }
@@ -51,7 +51,7 @@ describe("createProductAttribute", () => {
51
51
 
52
52
  expect(result.ok).toBe(true);
53
53
  if (result.ok) {
54
- expect(result.value.attribute.code).toBe("COLOR");
54
+ expect(result.value.productAttribute.code).toBe("COLOR");
55
55
  }
56
56
  expect(spies.insert).toHaveBeenCalled();
57
57
  });
@@ -49,5 +49,5 @@ export async function run<CF extends Record<string, unknown>>(
49
49
  .returningAll()
50
50
  .executeTakeFirstOrThrow();
51
51
 
52
- return ok({ attribute });
52
+ return ok({ productAttribute: attribute });
53
53
  }
@@ -61,7 +61,7 @@ describe("createProductAttributeValue", () => {
61
61
 
62
62
  expect(result.ok).toBe(true);
63
63
  if (result.ok) {
64
- expect(result.value.value.label).toBe("Green");
64
+ expect(result.value.productAttributeValue.label).toBe("Green");
65
65
  }
66
66
  expect(spies.insert).toHaveBeenCalled();
67
67
  });
@@ -59,5 +59,5 @@ export async function run(db: Transaction, input: CreateProductAttributeValueInp
59
59
  .returningAll()
60
60
  .executeTakeFirstOrThrow();
61
61
 
62
- return ok({ value });
62
+ return ok({ productAttributeValue: value });
63
63
  }
@@ -105,7 +105,7 @@ describe("createProductCategory", () => {
105
105
  const result = await run(db, input, ctx, deps);
106
106
  expect(result.ok).toBe(true);
107
107
  if (result.ok) {
108
- expect(result.value.category).toEqual(newCategory);
108
+ expect(result.value.productCategory).toEqual(newCategory);
109
109
  }
110
110
  });
111
111
 
@@ -129,7 +129,7 @@ describe("createProductCategory", () => {
129
129
  const result = await run(db, input, ctx, deps);
130
130
  expect(result.ok).toBe(true);
131
131
  if (result.ok) {
132
- expect(result.value.category).toEqual(newCategory);
132
+ expect(result.value.productCategory).toEqual(newCategory);
133
133
  }
134
134
  });
135
135
  });
@@ -78,5 +78,5 @@ export async function run<CF extends Record<string, unknown>>(
78
78
  .returningAll()
79
79
  .executeTakeFirstOrThrow();
80
80
 
81
- return ok({ category });
81
+ return ok({ productCategory: category });
82
82
  }
@@ -114,7 +114,7 @@ describe("setProductAttributeAssignment", () => {
114
114
 
115
115
  expect(result.ok).toBe(true);
116
116
  if (result.ok) {
117
- expect(result.value.assignment).toEqual(existingAssignment);
117
+ expect(result.value.productAttributeAssignment).toEqual(existingAssignment);
118
118
  }
119
119
  // Should not insert or update
120
120
  expect(spies.insert).not.toHaveBeenCalled();
@@ -165,7 +165,7 @@ describe("setProductAttributeAssignment", () => {
165
165
 
166
166
  expect(result.ok).toBe(true);
167
167
  if (result.ok) {
168
- expect(result.value.assignment.productId).toBe(baseDraftProduct.id);
168
+ expect(result.value.productAttributeAssignment.productId).toBe(baseDraftProduct.id);
169
169
  }
170
170
  expect(spies.insert).toHaveBeenCalled();
171
171
  });
@@ -199,7 +199,7 @@ describe("setProductAttributeAssignment", () => {
199
199
 
200
200
  expect(result.ok).toBe(true);
201
201
  if (result.ok) {
202
- expect(result.value.assignment.valueId).toBe(baseColorBlue.id);
202
+ expect(result.value.productAttributeAssignment.valueId).toBe(baseColorBlue.id);
203
203
  }
204
204
  expect(spies.insert).toHaveBeenCalled();
205
205
  });
@@ -68,7 +68,7 @@ export async function run(db: Transaction, input: SetProductAttributeAssignmentI
68
68
  // Idempotent no-op: if exact triple already exists, return existing
69
69
  const exactMatch = existingAssignments.find((a) => a.valueId === valueId);
70
70
  if (exactMatch) {
71
- return ok({ assignment: exactMatch });
71
+ return ok({ productAttributeAssignment: exactMatch });
72
72
  }
73
73
 
74
74
  // Status-based rules
@@ -98,5 +98,5 @@ export async function run(db: Transaction, input: SetProductAttributeAssignmentI
98
98
  .returningAll()
99
99
  .executeTakeFirstOrThrow();
100
100
 
101
- return ok({ assignment });
101
+ return ok({ productAttributeAssignment: assignment });
102
102
  }
@@ -110,6 +110,7 @@ export interface DefineModuleParams<
110
110
  };
111
111
  }
112
112
 
113
+ /* @__NO_SIDE_EFFECTS__ */
113
114
  export const defineModule = <
114
115
  const PF extends Record<string, TailorAnyDBField> = EmptyFields,
115
116
  const PAF extends Record<string, TailorAnyDBField> = EmptyFields,
@@ -13,9 +13,9 @@ describe("activatePurchasePaymentTerm", () => {
13
13
  spies.update.mockReturnValueOnce({ ...inactivePaymentTerm, status: "ACTIVE" });
14
14
 
15
15
  const result = await run(db, { id: inactivePaymentTerm.id }, commandCtx);
16
- const value = expectOk<{ paymentTerm: typeof inactivePaymentTerm }>(result);
16
+ const value = expectOk<{ purchasePaymentTerm: typeof inactivePaymentTerm }>(result);
17
17
 
18
- expect(value.paymentTerm.status).toBe("ACTIVE");
18
+ expect(value.purchasePaymentTerm.status).toBe("ACTIVE");
19
19
  expect(spies.set).toHaveBeenCalledWith(expect.objectContaining({ status: "ACTIVE" }));
20
20
  });
21
21
 
@@ -24,9 +24,9 @@ describe("activatePurchasePaymentTerm", () => {
24
24
  spies.select.mockReturnValueOnce(basePaymentTerm);
25
25
 
26
26
  const result = await run(db, { id: basePaymentTerm.id }, commandCtx);
27
- const value = expectOk<{ paymentTerm: typeof basePaymentTerm }>(result);
27
+ const value = expectOk<{ purchasePaymentTerm: typeof basePaymentTerm }>(result);
28
28
 
29
- expect(value.paymentTerm).toEqual(basePaymentTerm);
29
+ expect(value.purchasePaymentTerm).toEqual(basePaymentTerm);
30
30
  expect(spies.update).not.toHaveBeenCalled();
31
31
  });
32
32
 
@@ -18,7 +18,7 @@ export async function run(
18
18
  return err(new PaymentTermNotFoundError(input.id));
19
19
  }
20
20
  if (paymentTerm.status === "ACTIVE") {
21
- return ok({ paymentTerm });
21
+ return ok({ purchasePaymentTerm: paymentTerm });
22
22
  }
23
23
 
24
24
  const validation = validateScheduleLines(
@@ -35,5 +35,5 @@ export async function run(
35
35
  .returningAll()
36
36
  .executeTakeFirstOrThrow();
37
37
 
38
- return ok({ paymentTerm: activated });
38
+ return ok({ purchasePaymentTerm: activated });
39
39
  }
@@ -13,9 +13,9 @@ describe("deactivatePurchasePaymentTerm", () => {
13
13
  spies.update.mockReturnValueOnce({ ...basePaymentTerm, status: "INACTIVE" });
14
14
 
15
15
  const result = await run(db, { id: basePaymentTerm.id }, commandCtx);
16
- const value = expectOk<{ paymentTerm: typeof basePaymentTerm }>(result);
16
+ const value = expectOk<{ purchasePaymentTerm: typeof basePaymentTerm }>(result);
17
17
 
18
- expect(value.paymentTerm.status).toBe("INACTIVE");
18
+ expect(value.purchasePaymentTerm.status).toBe("INACTIVE");
19
19
  });
20
20
 
21
21
  it("returns success when the payment term is already inactive", async () => {
@@ -23,9 +23,9 @@ describe("deactivatePurchasePaymentTerm", () => {
23
23
  spies.select.mockReturnValueOnce(inactivePaymentTerm);
24
24
 
25
25
  const result = await run(db, { id: inactivePaymentTerm.id }, commandCtx);
26
- const value = expectOk<{ paymentTerm: typeof inactivePaymentTerm }>(result);
26
+ const value = expectOk<{ purchasePaymentTerm: typeof inactivePaymentTerm }>(result);
27
27
 
28
- expect(value.paymentTerm).toEqual(inactivePaymentTerm);
28
+ expect(value.purchasePaymentTerm).toEqual(inactivePaymentTerm);
29
29
  expect(spies.update).not.toHaveBeenCalled();
30
30
  });
31
31
 
@@ -18,7 +18,7 @@ export async function run(
18
18
  return err(new PaymentTermNotFoundError(input.id));
19
19
  }
20
20
  if (paymentTerm.status === "INACTIVE") {
21
- return ok({ paymentTerm });
21
+ return ok({ purchasePaymentTerm: paymentTerm });
22
22
  }
23
23
 
24
24
  const supplierProfile = await db
@@ -37,5 +37,5 @@ export async function run(
37
37
  .returningAll()
38
38
  .executeTakeFirstOrThrow();
39
39
 
40
- return ok({ paymentTerm: deactivated });
40
+ return ok({ purchasePaymentTerm: deactivated });
41
41
  }
@@ -30,7 +30,7 @@ describe("updatePurchasePaymentTerm", () => {
30
30
  commandCtx,
31
31
  );
32
32
 
33
- expect(expectOk(result).paymentTerm.name).toBe("Net 45");
33
+ expect(expectOk(result).purchasePaymentTerm.name).toBe("Net 45");
34
34
  });
35
35
 
36
36
  it("updates an inactive payment term without reactivating it", async () => {
@@ -45,7 +45,7 @@ describe("updatePurchasePaymentTerm", () => {
45
45
  commandCtx,
46
46
  );
47
47
 
48
- expect(expectOk(result).paymentTerm.status).toBe("INACTIVE");
48
+ expect(expectOk(result).purchasePaymentTerm.status).toBe("INACTIVE");
49
49
  });
50
50
 
51
51
  it("preserves historical purchase-order snapshots after update", async () => {
@@ -68,5 +68,5 @@ export async function run(
68
68
  .returningAll()
69
69
  .executeTakeFirstOrThrow();
70
70
 
71
- return ok({ paymentTerm });
71
+ return ok({ purchasePaymentTerm: paymentTerm });
72
72
  }
@@ -111,6 +111,7 @@ export interface DefineModuleParams<
111
111
  };
112
112
  }
113
113
 
114
+ /* @__NO_SIDE_EFFECTS__ */
114
115
  export const defineModule = <
115
116
  const SPF extends Record<string, TailorAnyDBField> = Record<never, never>,
116
117
  const PTF extends Record<string, TailorAnyDBField> = Record<never, never>,
@@ -136,5 +136,5 @@ export async function run(db: Transaction, input: CreateSalesOrderInput, ctx: Co
136
136
  insertedLines.push(inserted);
137
137
  }
138
138
 
139
- return ok({ salesOrder: salesOrder!, lines: insertedLines });
139
+ return ok({ salesOrder: salesOrder!, salesOrderLines: insertedLines });
140
140
  }
@@ -176,6 +176,7 @@ export interface DefineModuleParams<
176
176
  };
177
177
  }
178
178
 
179
+ /* @__NO_SIDE_EFFECTS__ */
179
180
  export const defineModule = <
180
181
  const ChF extends Record<string, TailorAnyDBField> = EmptyFields,
181
182
  const LiF extends Record<string, TailorAnyDBField> = EmptyFields,
@@ -29,4 +29,21 @@ export default defineConfig([
29
29
  "import-x/no-unresolved": ["error", { ignore: ["^@tailor-platform/"] }],
30
30
  },
31
31
  },
32
+ {
33
+ files: ["src/executors/**/*.ts", "src/resolvers/**/*.ts"],
34
+ ignores: ["**/*.test.ts"],
35
+ rules: {
36
+ "no-restricted-imports": [
37
+ "error",
38
+ {
39
+ patterns: [
40
+ {
41
+ regex: "^node:",
42
+ message: "Node.js built-in modules are not allowed in executors/resolvers.",
43
+ },
44
+ ],
45
+ },
46
+ ],
47
+ },
48
+ },
32
49
  ]);
@@ -10,6 +10,7 @@
10
10
  "lint:fix": "eslint --cache --fix .",
11
11
  "seed": "node --env-file-if-exists=.env seed/exec.mjs",
12
12
  "seed:reset": "node --env-file-if-exists=.env seed/exec.mjs --truncate --yes",
13
+ "seed:validate": "node --env-file-if-exists=.env seed/exec.mjs validate",
13
14
  "test:integration": "vitest run",
14
15
  "typecheck": "tsc --noEmit",
15
16
  "gql-tada:check": "gql-tada check"
@@ -38,8 +38,8 @@ const listRoles = graphql(`
38
38
  `);
39
39
 
40
40
  const createUser = graphql(`
41
- mutation ($name: String!, $email: String!, $roleId: String!) {
42
- createUser(name: $name, email: $email, roleId: $roleId) {
41
+ mutation ($name: String!, $email: String!, $roleIds: [String!]) {
42
+ createUser(name: $name, email: $email, roleIds: $roleIds) {
43
43
  id
44
44
  name
45
45
  email
@@ -69,7 +69,7 @@ describe("user--view-audit-log-detail", () => {
69
69
 
70
70
  const email = `audit-detail-${Date.now()}@example.com`;
71
71
  const createResult = await gql
72
- .mutation(createUser, { name: "Audit Detail User", email, roleId })
72
+ .mutation(createUser, { name: "Audit Detail User", email, roleIds: [roleId] })
73
73
  .toPromise();
74
74
 
75
75
  expect(createResult.data?.createUser.name).toBe("Audit Detail User");
@@ -14,8 +14,8 @@ const listRoles = graphql(`
14
14
  `);
15
15
 
16
16
  const createUser = graphql(`
17
- mutation ($name: String!, $email: String!, $roleId: String!) {
18
- createUser(name: $name, email: $email, roleId: $roleId) {
17
+ mutation ($name: String!, $email: String!, $roleIds: [String!]) {
18
+ createUser(name: $name, email: $email, roleIds: $roleIds) {
19
19
  id
20
20
  }
21
21
  }
@@ -61,7 +61,7 @@ describe("user--assign-role-to-user", () => {
61
61
  .mutation(createUser, {
62
62
  name: "Assign Role User",
63
63
  email: `assign-role-${Date.now()}@example.com`,
64
- roleId,
64
+ roleIds: [roleId],
65
65
  })
66
66
  .toPromise();
67
67
  const userId = createResult.data!.createUser.id;
@@ -90,7 +90,7 @@ describe("user--assign-role-to-user", () => {
90
90
  .mutation(createUser, {
91
91
  name: "Idempotent Role User",
92
92
  email: `idem-role-${Date.now()}@example.com`,
93
- roleId,
93
+ roleIds: [roleId],
94
94
  })
95
95
  .toPromise();
96
96
  const userId = createResult.data!.createUser.id;
@@ -14,8 +14,8 @@ const listRoles = graphql(`
14
14
  `);
15
15
 
16
16
  const createUser = graphql(`
17
- mutation ($name: String!, $email: String!, $roleId: String!) {
18
- createUser(name: $name, email: $email, roleId: $roleId) {
17
+ mutation ($name: String!, $email: String!, $roleIds: [String!]) {
18
+ createUser(name: $name, email: $email, roleIds: $roleIds) {
19
19
  id
20
20
  }
21
21
  }
@@ -53,7 +53,7 @@ describe("user--remove-role-from-user", () => {
53
53
  .mutation(createUser, {
54
54
  name: "Remove Role User",
55
55
  email: `remove-role-${Date.now()}@example.com`,
56
- roleId,
56
+ roleIds: [roleId],
57
57
  })
58
58
  .toPromise();
59
59
  const userId = createResult.data!.createUser.id;
@@ -75,7 +75,7 @@ describe("user--remove-role-from-user", () => {
75
75
  .mutation(createUser, {
76
76
  name: "Cancel Remove User",
77
77
  email: `cancel-remove-${Date.now()}@example.com`,
78
- roleId,
78
+ roleIds: [roleId],
79
79
  })
80
80
  .toPromise();
81
81
  const userId = createResult.data!.createUser.id;
@@ -14,8 +14,8 @@ const listRoles = graphql(`
14
14
  `);
15
15
 
16
16
  const createUserWithStatus = graphql(`
17
- mutation CreateUserWithStatus($name: String!, $email: String!, $roleId: String!) {
18
- createUser(name: $name, email: $email, roleId: $roleId) {
17
+ mutation CreateUserWithStatus($name: String!, $email: String!, $roleIds: [String!]) {
18
+ createUser(name: $name, email: $email, roleIds: $roleIds) {
19
19
  id
20
20
  status
21
21
  }
@@ -23,8 +23,8 @@ const createUserWithStatus = graphql(`
23
23
  `);
24
24
 
25
25
  const createUserIdOnly = graphql(`
26
- mutation CreateUserIdOnly($name: String!, $email: String!, $roleId: String!) {
27
- createUser(name: $name, email: $email, roleId: $roleId) {
26
+ mutation CreateUserIdOnly($name: String!, $email: String!, $roleIds: [String!]) {
27
+ createUser(name: $name, email: $email, roleIds: $roleIds) {
28
28
  id
29
29
  }
30
30
  }
@@ -79,7 +79,7 @@ describe("user--toggle-user-status", () => {
79
79
  .mutation(createUserWithStatus, {
80
80
  name: "Deactivate Test",
81
81
  email: `deactivate-${Date.now()}@example.com`,
82
- roleId: roleId!,
82
+ roleIds: [roleId!],
83
83
  })
84
84
  .toPromise();
85
85
  expect(createResult.data?.createUser.status).toBe("ACTIVE");
@@ -101,7 +101,7 @@ describe("user--toggle-user-status", () => {
101
101
  .mutation(createUserIdOnly, {
102
102
  name: "Reactivate Test",
103
103
  email: `reactivate-${Date.now()}@example.com`,
104
- roleId: roleId!,
104
+ roleIds: [roleId!],
105
105
  })
106
106
  .toPromise();
107
107
 
@@ -14,8 +14,8 @@ const listRoles = graphql(`
14
14
  `);
15
15
 
16
16
  const createUserIdOnly = graphql(`
17
- mutation CreateUserIdOnly($name: String!, $email: String!, $roleId: String!) {
18
- createUser(name: $name, email: $email, roleId: $roleId) {
17
+ mutation CreateUserIdOnly($name: String!, $email: String!, $roleIds: [String!]) {
18
+ createUser(name: $name, email: $email, roleIds: $roleIds) {
19
19
  id
20
20
  }
21
21
  }
@@ -44,7 +44,7 @@ describe("user--update-own-profile", () => {
44
44
  .mutation(createUserIdOnly, {
45
45
  name: "Original Name",
46
46
  email,
47
- roleId: roleId!,
47
+ roleIds: [roleId!],
48
48
  })
49
49
  .toPromise();
50
50
 
@@ -68,18 +68,18 @@ describe("user--update-own-profile", () => {
68
68
  .mutation(createUserIdOnly, {
69
69
  name: "Keep Name",
70
70
  email,
71
- roleId: roleId!,
71
+ roleIds: [roleId!],
72
72
  })
73
73
  .toPromise();
74
74
 
75
- const res = await gql
76
- .mutation(updateUserProfile, {
77
- userId: createResult.data!.createUser.id,
78
- name: "",
79
- email,
80
- })
81
- .toPromise();
82
-
83
- expect(res.data?.updateUserProfile).toBeDefined();
75
+ await expect(
76
+ gql
77
+ .mutation(updateUserProfile, {
78
+ userId: createResult.data!.createUser.id,
79
+ name: "",
80
+ email,
81
+ })
82
+ .toPromise(),
83
+ ).rejects.toThrow();
84
84
  });
85
85
  });
@@ -14,8 +14,8 @@ const listRoles = graphql(`
14
14
  `);
15
15
 
16
16
  const createUserIdOnly = graphql(`
17
- mutation CreateUserIdOnly($name: String!, $email: String!, $roleId: String!) {
18
- createUser(name: $name, email: $email, roleId: $roleId) {
17
+ mutation CreateUserIdOnly($name: String!, $email: String!, $roleIds: [String!]) {
18
+ createUser(name: $name, email: $email, roleIds: $roleIds) {
19
19
  id
20
20
  }
21
21
  }
@@ -59,7 +59,7 @@ describe("user--update-user-profile", () => {
59
59
  .mutation(createUserIdOnly, {
60
60
  name: "Before Update",
61
61
  email,
62
- roleId: roleId!,
62
+ roleIds: [roleId!],
63
63
  })
64
64
  .toPromise();
65
65
 
@@ -83,7 +83,7 @@ describe("user--update-user-profile", () => {
83
83
  .mutation(createUserIdOnly, {
84
84
  name: "Email Update User",
85
85
  email: `old-email-${ts}@example.com`,
86
- roleId: roleId!,
86
+ roleIds: [roleId!],
87
87
  })
88
88
  .toPromise();
89
89
 
@@ -108,7 +108,7 @@ describe("user--update-user-profile", () => {
108
108
  .mutation(createUserIdOnly, {
109
109
  name: "User A",
110
110
  email: `dup-a-${ts}@example.com`,
111
- roleId: roleId!,
111
+ roleIds: [roleId!],
112
112
  })
113
113
  .toPromise();
114
114
 
@@ -116,7 +116,7 @@ describe("user--update-user-profile", () => {
116
116
  .mutation(createUserIdOnly, {
117
117
  name: "User B",
118
118
  email: `dup-b-${ts}@example.com`,
119
- roleId: roleId!,
119
+ roleIds: [roleId!],
120
120
  })
121
121
  .toPromise();
122
122
 
@@ -140,19 +140,18 @@ describe("user--update-user-profile", () => {
140
140
  .mutation(createUserIdOnly, {
141
141
  name: "Clear Name User",
142
142
  email,
143
- roleId: roleId!,
143
+ roleIds: [roleId!],
144
144
  })
145
145
  .toPromise();
146
146
 
147
- // Empty string for name — direct Kysely update accepts it (no module validation)
148
- const res = await gql
149
- .mutation(updateUserProfileName, {
150
- userId: createResult.data!.createUser.id,
151
- name: "",
152
- email,
153
- })
154
- .toPromise();
155
-
156
- expect(res.data?.updateUserProfile).toBeDefined();
147
+ await expect(
148
+ gql
149
+ .mutation(updateUserProfileName, {
150
+ userId: createResult.data!.createUser.id,
151
+ name: "",
152
+ email,
153
+ })
154
+ .toPromise(),
155
+ ).rejects.toThrow();
157
156
  });
158
157
  });
@@ -46,8 +46,8 @@ const listRoles = graphql(`
46
46
  `);
47
47
 
48
48
  const createUserIdOnly = graphql(`
49
- mutation CreateUserIdOnly($name: String!, $email: String!, $roleId: String!) {
50
- createUser(name: $name, email: $email, roleId: $roleId) {
49
+ mutation CreateUserIdOnly($name: String!, $email: String!, $roleIds: [String!]) {
50
+ createUser(name: $name, email: $email, roleIds: $roleIds) {
51
51
  id
52
52
  }
53
53
  }
@@ -84,7 +84,7 @@ describe("user--view-user-detail", () => {
84
84
  .mutation(createUserIdOnly, {
85
85
  name: "Inactive Detail User",
86
86
  email: `inactive-detail-${Date.now()}@example.com`,
87
- roleId: roleId!,
87
+ roleIds: [roleId!],
88
88
  })
89
89
  .toPromise();
90
90
  const userId = createResult.data!.createUser.id;
@@ -33,7 +33,21 @@ const auth = defineAuth("default", {
33
33
  machineUsers: {
34
34
  developer: {
35
35
  attributes: {
36
- permissions: ["ADMIN"],
36
+ permissions: [
37
+ "user-management:createUser",
38
+ "user-management:activateUser",
39
+ "user-management:deactivateUser",
40
+ "user-management:reactivateUser",
41
+ "user-management:createRole",
42
+ "user-management:assignPermissionToRole",
43
+ "user-management:revokePermissionFromRole",
44
+ "user-management:assignRoleToUser",
45
+ "user-management:revokeRoleFromUser",
46
+ "user-management:createPermission",
47
+ "user-management:updateUser",
48
+ "user-management:updateOwnProfile",
49
+ "audit:logAuditEvent",
50
+ ],
37
51
  },
38
52
  },
39
53
  },