@tailor-platform/erp-kit 0.0.1 → 0.1.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 (213) hide show
  1. package/README.md +196 -28
  2. package/dist/cli.js +894 -0
  3. package/package.json +65 -8
  4. package/rules/app-compose/backend/auth.md +78 -0
  5. package/rules/app-compose/frontend/auth.md +55 -0
  6. package/rules/app-compose/frontend/component.md +55 -0
  7. package/rules/app-compose/frontend/page.md +86 -0
  8. package/rules/app-compose/frontend/screen-detailview.md +112 -0
  9. package/rules/app-compose/frontend/screen-form.md +145 -0
  10. package/rules/app-compose/frontend/screen-listview.md +159 -0
  11. package/rules/app-compose/structure.md +32 -0
  12. package/rules/module-development/commands.md +54 -0
  13. package/rules/module-development/cross-module-type-injection.md +28 -0
  14. package/rules/module-development/dependency-modules.md +24 -0
  15. package/rules/module-development/errors.md +12 -0
  16. package/rules/module-development/executors.md +67 -0
  17. package/rules/module-development/exports.md +13 -0
  18. package/rules/module-development/models.md +34 -0
  19. package/rules/module-development/structure.md +27 -0
  20. package/rules/module-development/sync-vs-async-operations.md +83 -0
  21. package/rules/module-development/testing.md +43 -0
  22. package/rules/sdk-best-practices/db-relations.md +74 -0
  23. package/rules/sdk-best-practices/sdk-docs.md +14 -0
  24. package/schemas/app-compose/actors.yml +34 -0
  25. package/schemas/app-compose/business-flow.yml +50 -0
  26. package/schemas/app-compose/requirements.yml +33 -0
  27. package/schemas/app-compose/resolver.yml +47 -0
  28. package/schemas/app-compose/screen.yml +81 -0
  29. package/schemas/app-compose/story.yml +67 -0
  30. package/schemas/module/command.yml +52 -0
  31. package/schemas/module/feature.yml +58 -0
  32. package/schemas/module/model.yml +70 -0
  33. package/schemas/module/module.yml +50 -0
  34. package/skills/1-module-docs/SKILL.md +107 -0
  35. package/skills/2-module-feature-breakdown/SKILL.md +66 -0
  36. package/skills/3-module-doc-review/SKILL.md +230 -0
  37. package/skills/4-module-tdd-implementation/SKILL.md +56 -0
  38. package/skills/5-module-implementation-review/SKILL.md +400 -0
  39. package/skills/app-compose-1-requirement-analysis/SKILL.md +85 -0
  40. package/skills/app-compose-2-requirements-breakdown/SKILL.md +88 -0
  41. package/skills/app-compose-3-doc-review/SKILL.md +112 -0
  42. package/skills/app-compose-4-design-mock/SKILL.md +248 -0
  43. package/skills/app-compose-5-design-mock-review/SKILL.md +283 -0
  44. package/skills/app-compose-6-implementation-spec/SKILL.md +122 -0
  45. package/skills/mock-scenario/SKILL.md +118 -0
  46. package/src/app.ts +1 -0
  47. package/src/cli.ts +120 -0
  48. package/src/commands/check.test.ts +30 -0
  49. package/src/commands/check.ts +66 -0
  50. package/src/commands/init.test.ts +77 -0
  51. package/src/commands/init.ts +87 -0
  52. package/src/commands/mock/index.ts +53 -0
  53. package/src/commands/mock/start.ts +179 -0
  54. package/src/commands/mock/validate.test.ts +185 -0
  55. package/src/commands/mock/validate.ts +198 -0
  56. package/src/commands/scaffold.test.ts +76 -0
  57. package/src/commands/scaffold.ts +119 -0
  58. package/src/commands/sync-check.test.ts +125 -0
  59. package/src/commands/sync-check.ts +182 -0
  60. package/src/integration.test.ts +63 -0
  61. package/src/mdschema.ts +48 -0
  62. package/src/mockServer.ts +55 -0
  63. package/src/module.ts +86 -0
  64. package/src/modules/accounting/.gitkeep +0 -0
  65. package/src/modules/coa-management/.gitkeep +0 -0
  66. package/src/modules/inventory/.gitkeep +0 -0
  67. package/src/modules/manufacturing/.gitkeep +0 -0
  68. package/src/modules/primitives/README.md +39 -0
  69. package/src/modules/primitives/command/activateCategory.test.ts +75 -0
  70. package/src/modules/primitives/command/activateCategory.ts +50 -0
  71. package/src/modules/primitives/command/activateCurrency.test.ts +70 -0
  72. package/src/modules/primitives/command/activateCurrency.ts +50 -0
  73. package/src/modules/primitives/command/activateUnit.test.ts +53 -0
  74. package/src/modules/primitives/command/activateUnit.ts +50 -0
  75. package/src/modules/primitives/command/convertAmount.test.ts +275 -0
  76. package/src/modules/primitives/command/convertAmount.ts +126 -0
  77. package/src/modules/primitives/command/convertQuantity.test.ts +219 -0
  78. package/src/modules/primitives/command/convertQuantity.ts +73 -0
  79. package/src/modules/primitives/command/createCategory.test.ts +126 -0
  80. package/src/modules/primitives/command/createCategory.ts +89 -0
  81. package/src/modules/primitives/command/createCurrency.test.ts +191 -0
  82. package/src/modules/primitives/command/createCurrency.ts +77 -0
  83. package/src/modules/primitives/command/createExchangeRate.test.ts +216 -0
  84. package/src/modules/primitives/command/createExchangeRate.ts +91 -0
  85. package/src/modules/primitives/command/createUnit.test.ts +214 -0
  86. package/src/modules/primitives/command/createUnit.ts +88 -0
  87. package/src/modules/primitives/command/deactivateCategory.test.ts +97 -0
  88. package/src/modules/primitives/command/deactivateCategory.ts +62 -0
  89. package/src/modules/primitives/command/deactivateCurrency.test.ts +85 -0
  90. package/src/modules/primitives/command/deactivateCurrency.ts +55 -0
  91. package/src/modules/primitives/command/deactivateUnit.test.ts +78 -0
  92. package/src/modules/primitives/command/deactivateUnit.ts +62 -0
  93. package/src/modules/primitives/command/setBaseCurrency.test.ts +98 -0
  94. package/src/modules/primitives/command/setBaseCurrency.ts +74 -0
  95. package/src/modules/primitives/command/setReferenceUnit.test.ts +108 -0
  96. package/src/modules/primitives/command/setReferenceUnit.ts +84 -0
  97. package/src/modules/primitives/db/currency.ts +30 -0
  98. package/src/modules/primitives/db/exchangeRate.ts +28 -0
  99. package/src/modules/primitives/db/unit.ts +32 -0
  100. package/src/modules/primitives/db/uomCategory.ts +32 -0
  101. package/src/modules/primitives/docs/commands/ActivateCategory.md +34 -0
  102. package/src/modules/primitives/docs/commands/ActivateCurrency.md +33 -0
  103. package/src/modules/primitives/docs/commands/ActivateUnit.md +34 -0
  104. package/src/modules/primitives/docs/commands/ConvertAmount.md +50 -0
  105. package/src/modules/primitives/docs/commands/ConvertQuantity.md +43 -0
  106. package/src/modules/primitives/docs/commands/CreateCategory.md +44 -0
  107. package/src/modules/primitives/docs/commands/CreateCurrency.md +47 -0
  108. package/src/modules/primitives/docs/commands/CreateExchangeRate.md +48 -0
  109. package/src/modules/primitives/docs/commands/CreateUnit.md +48 -0
  110. package/src/modules/primitives/docs/commands/DeactivateCategory.md +38 -0
  111. package/src/modules/primitives/docs/commands/DeactivateCurrency.md +38 -0
  112. package/src/modules/primitives/docs/commands/DeactivateUnit.md +38 -0
  113. package/src/modules/primitives/docs/commands/SetBaseCurrency.md +39 -0
  114. package/src/modules/primitives/docs/commands/SetReferenceUnit.md +43 -0
  115. package/src/modules/primitives/docs/features/currency-definitions.md +55 -0
  116. package/src/modules/primitives/docs/features/exchange-rates.md +61 -0
  117. package/src/modules/primitives/docs/features/unit-conversion.md +66 -0
  118. package/src/modules/primitives/docs/features/uom-categories.md +52 -0
  119. package/src/modules/primitives/docs/models/Currency.md +45 -0
  120. package/src/modules/primitives/docs/models/ExchangeRate.md +33 -0
  121. package/src/modules/primitives/docs/models/Unit.md +46 -0
  122. package/src/modules/primitives/docs/models/UoMCategory.md +44 -0
  123. package/src/modules/primitives/generated/kysely-tailordb.ts +95 -0
  124. package/src/modules/primitives/index.ts +40 -0
  125. package/src/modules/primitives/lib/errors.ts +138 -0
  126. package/src/modules/primitives/lib/types.ts +20 -0
  127. package/src/modules/primitives/module.ts +66 -0
  128. package/src/modules/primitives/permissions.ts +18 -0
  129. package/src/modules/primitives/tailor.config.ts +11 -0
  130. package/src/modules/primitives/testing/fixtures.ts +161 -0
  131. package/src/modules/product-management/.gitkeep +0 -0
  132. package/src/modules/purchase/.gitkeep +0 -0
  133. package/src/modules/sales/.gitkeep +0 -0
  134. package/src/modules/shared/createContext.test.ts +39 -0
  135. package/src/modules/shared/createContext.ts +15 -0
  136. package/src/modules/shared/defineCommand.test.ts +42 -0
  137. package/src/modules/shared/defineCommand.ts +19 -0
  138. package/src/modules/shared/definePermissions.test.ts +146 -0
  139. package/src/modules/shared/definePermissions.ts +94 -0
  140. package/src/modules/shared/entityTypes.ts +15 -0
  141. package/src/modules/shared/errors.ts +22 -0
  142. package/src/modules/shared/index.ts +1 -0
  143. package/src/modules/shared/internal.ts +13 -0
  144. package/src/modules/shared/requirePermission.test.ts +47 -0
  145. package/src/modules/shared/requirePermission.ts +8 -0
  146. package/src/modules/shared/types.ts +4 -0
  147. package/src/modules/supplier-management/.gitkeep +0 -0
  148. package/src/modules/supplier-portal/.gitkeep +0 -0
  149. package/src/modules/testing/index.ts +120 -0
  150. package/src/modules/user-management/README.md +38 -0
  151. package/src/modules/user-management/command/activateUser.test.ts +112 -0
  152. package/src/modules/user-management/command/activateUser.ts +67 -0
  153. package/src/modules/user-management/command/assignPermissionToRole.test.ts +119 -0
  154. package/src/modules/user-management/command/assignPermissionToRole.ts +87 -0
  155. package/src/modules/user-management/command/assignRoleToUser.test.ts +162 -0
  156. package/src/modules/user-management/command/assignRoleToUser.ts +93 -0
  157. package/src/modules/user-management/command/createPermission.test.ts +143 -0
  158. package/src/modules/user-management/command/createPermission.ts +66 -0
  159. package/src/modules/user-management/command/createRole.test.ts +115 -0
  160. package/src/modules/user-management/command/createRole.ts +52 -0
  161. package/src/modules/user-management/command/createUser.test.ts +198 -0
  162. package/src/modules/user-management/command/createUser.ts +85 -0
  163. package/src/modules/user-management/command/deactivateUser.test.ts +112 -0
  164. package/src/modules/user-management/command/deactivateUser.ts +67 -0
  165. package/src/modules/user-management/command/logAuditEvent.test.ts +179 -0
  166. package/src/modules/user-management/command/logAuditEvent.ts +59 -0
  167. package/src/modules/user-management/command/reactivateUser.test.ts +115 -0
  168. package/src/modules/user-management/command/reactivateUser.ts +67 -0
  169. package/src/modules/user-management/command/revokePermissionFromRole.test.ts +112 -0
  170. package/src/modules/user-management/command/revokePermissionFromRole.ts +81 -0
  171. package/src/modules/user-management/command/revokeRoleFromUser.test.ts +112 -0
  172. package/src/modules/user-management/command/revokeRoleFromUser.ts +81 -0
  173. package/src/modules/user-management/db/auditEvent.ts +47 -0
  174. package/src/modules/user-management/db/permission.ts +31 -0
  175. package/src/modules/user-management/db/role.ts +28 -0
  176. package/src/modules/user-management/db/rolePermission.ts +44 -0
  177. package/src/modules/user-management/db/user.ts +38 -0
  178. package/src/modules/user-management/db/userRole.ts +44 -0
  179. package/src/modules/user-management/docs/commands/ActivateUser.md +36 -0
  180. package/src/modules/user-management/docs/commands/AssignPermissionToRole.md +39 -0
  181. package/src/modules/user-management/docs/commands/AssignRoleToUser.md +43 -0
  182. package/src/modules/user-management/docs/commands/CreatePermission.md +35 -0
  183. package/src/modules/user-management/docs/commands/CreateRole.md +35 -0
  184. package/src/modules/user-management/docs/commands/CreateUser.md +41 -0
  185. package/src/modules/user-management/docs/commands/DeactivateUser.md +38 -0
  186. package/src/modules/user-management/docs/commands/LogAuditEvent.md +37 -0
  187. package/src/modules/user-management/docs/commands/ReactivateUser.md +37 -0
  188. package/src/modules/user-management/docs/commands/RevokePermissionFromRole.md +40 -0
  189. package/src/modules/user-management/docs/commands/RevokeRoleFromUser.md +40 -0
  190. package/src/modules/user-management/docs/features/audit-trail.md +80 -0
  191. package/src/modules/user-management/docs/features/role-based-access-control.md +76 -0
  192. package/src/modules/user-management/docs/features/user-account-management.md +64 -0
  193. package/src/modules/user-management/docs/models/AuditEvent.md +34 -0
  194. package/src/modules/user-management/docs/models/Permission.md +31 -0
  195. package/src/modules/user-management/docs/models/Role.md +31 -0
  196. package/src/modules/user-management/docs/models/RolePermission.md +33 -0
  197. package/src/modules/user-management/docs/models/User.md +47 -0
  198. package/src/modules/user-management/docs/models/UserRole.md +34 -0
  199. package/src/modules/user-management/docs/plans/2026-01-30-flattened-permissions-design.md +52 -0
  200. package/src/modules/user-management/executor/recomputeOnRolePermissionChange.ts +61 -0
  201. package/src/modules/user-management/generated/enums.ts +24 -0
  202. package/src/modules/user-management/generated/kysely-tailordb.ts +112 -0
  203. package/src/modules/user-management/index.ts +32 -0
  204. package/src/modules/user-management/lib/errors.ts +81 -0
  205. package/src/modules/user-management/lib/recomputeUserPermissions.ts +53 -0
  206. package/src/modules/user-management/lib/types.ts +31 -0
  207. package/src/modules/user-management/module.ts +77 -0
  208. package/src/modules/user-management/permissions.ts +15 -0
  209. package/src/modules/user-management/tailor.config.ts +11 -0
  210. package/src/modules/user-management/testing/fixtures.ts +98 -0
  211. package/src/schemas.ts +25 -0
  212. package/src/testing.ts +10 -0
  213. package/src/util.ts +3 -0
@@ -0,0 +1,44 @@
1
+ import {
2
+ db,
3
+ unsafeAllowAllGqlPermission,
4
+ unsafeAllowAllTypePermission,
5
+ } from "@tailor-platform/sdk";
6
+ import { role } from "./role";
7
+ import { permission } from "./permission";
8
+
9
+ export interface CreateRolePermissionTypeParams {
10
+ fields?: Record<string, unknown>;
11
+ }
12
+
13
+ export function createRolePermissionType(params: CreateRolePermissionTypeParams) {
14
+ return db
15
+ .type("RolePermission", {
16
+ roleId: db
17
+ .uuid()
18
+ .relation({
19
+ type: "n-1",
20
+ toward: { type: role },
21
+ backward: "rolePermissions",
22
+ })
23
+ .description("Foreign key to Role"),
24
+ permissionId: db
25
+ .uuid()
26
+ .relation({
27
+ type: "n-1",
28
+ toward: { type: permission },
29
+ backward: "rolePermissions",
30
+ })
31
+ .description("Foreign key to Permission"),
32
+ ...params.fields,
33
+ ...db.fields.timestamps(),
34
+ })
35
+ .indexes({
36
+ fields: ["roleId", "permissionId"],
37
+ unique: true,
38
+ name: "role_permission_unique_idx",
39
+ })
40
+ .permission(unsafeAllowAllTypePermission)
41
+ .gqlPermission(unsafeAllowAllGqlPermission);
42
+ }
43
+
44
+ export const rolePermission = createRolePermissionType({});
@@ -0,0 +1,38 @@
1
+ import {
2
+ db,
3
+ type TailorAnyDBField,
4
+ unsafeAllowAllGqlPermission,
5
+ unsafeAllowAllTypePermission,
6
+ } from "@tailor-platform/sdk";
7
+
8
+ export interface CreateUserTypeParams<F extends Record<string, TailorAnyDBField>> {
9
+ fields?: F;
10
+ additionalStatuses?: string[];
11
+ }
12
+
13
+ const BASE_STATUSES = ["PENDING", "ACTIVE", "INACTIVE"] as const;
14
+
15
+ export function createUserType<const F extends Record<string, TailorAnyDBField>>(
16
+ params: CreateUserTypeParams<F>,
17
+ ) {
18
+ const statuses = [...BASE_STATUSES, ...(params.additionalStatuses ?? [])] as [
19
+ string,
20
+ ...string[],
21
+ ];
22
+
23
+ return db
24
+ .type("User", {
25
+ email: db.string().unique().description("User email address (unique identifier)"),
26
+ name: db.string().description("User display name"),
27
+ status: db.enum(statuses).description("User status"),
28
+ permissions: db
29
+ .string({ array: true, optional: true })
30
+ .description("Flattened permission keys from all assigned roles"),
31
+ ...((params.fields ?? {}) as F),
32
+ ...db.fields.timestamps(),
33
+ })
34
+ .permission(unsafeAllowAllTypePermission)
35
+ .gqlPermission(unsafeAllowAllGqlPermission);
36
+ }
37
+
38
+ export const user = createUserType({});
@@ -0,0 +1,44 @@
1
+ import {
2
+ db,
3
+ unsafeAllowAllGqlPermission,
4
+ unsafeAllowAllTypePermission,
5
+ } from "@tailor-platform/sdk";
6
+ import { user } from "./user";
7
+ import { role } from "./role";
8
+
9
+ export interface CreateUserRoleTypeParams {
10
+ fields?: Record<string, unknown>;
11
+ }
12
+
13
+ export function createUserRoleType(params: CreateUserRoleTypeParams) {
14
+ return db
15
+ .type("UserRole", {
16
+ userId: db
17
+ .uuid()
18
+ .relation({
19
+ type: "n-1",
20
+ toward: { type: user },
21
+ backward: "userRoles",
22
+ })
23
+ .description("Foreign key to User"),
24
+ roleId: db
25
+ .uuid()
26
+ .relation({
27
+ type: "n-1",
28
+ toward: { type: role },
29
+ backward: "userRoles",
30
+ })
31
+ .description("Foreign key to Role"),
32
+ ...params.fields,
33
+ ...db.fields.timestamps(),
34
+ })
35
+ .indexes({
36
+ fields: ["userId", "roleId"],
37
+ unique: true,
38
+ name: "user_role_unique_idx",
39
+ })
40
+ .permission(unsafeAllowAllTypePermission)
41
+ .gqlPermission(unsafeAllowAllGqlPermission);
42
+ }
43
+
44
+ export const userRole = createUserRoleType({});
@@ -0,0 +1,36 @@
1
+ # ActivateUser
2
+
3
+ ## Overview
4
+
5
+ ActivateUser transitions a user from PENDING status to ACTIVE status, granting them full access to the system. This command is typically executed by an administrator after the user's identity has been verified and onboarding requirements are complete.
6
+
7
+ Only users in PENDING status can be activated. Attempting to activate an already active or inactive user will fail.
8
+
9
+ ## Business Rules
10
+
11
+ - User must exist in the system
12
+ - User must be in PENDING status
13
+ - Transitions user status from PENDING to ACTIVE
14
+ - Generates USER_ACTIVATED audit event with actor ID, timestamp, and previous status
15
+
16
+ ## Process Flow
17
+
18
+ ```mermaid
19
+ flowchart TD
20
+ A[Receive activate request] --> B{User exists?}
21
+ B -->|No| C[Return error: USER_NOT_FOUND]
22
+ B -->|Yes| D{Status is PENDING?}
23
+ D -->|No| E[Return error: INVALID_STATUS_TRANSITION]
24
+ D -->|Yes| F[Update status to ACTIVE]
25
+ F --> G[Log USER_ACTIVATED audit event]
26
+ G --> H[Return updated user]
27
+ ```
28
+
29
+ ## External Dependencies
30
+
31
+ - None
32
+
33
+ ## Error Scenarios
34
+
35
+ - **USER_NOT_FOUND**: User ID does not exist in the system - return not found error with the provided ID
36
+ - **INVALID_STATUS_TRANSITION**: User is not in PENDING status (already ACTIVE or INACTIVE) - return error with current status and valid transitions
@@ -0,0 +1,39 @@
1
+ # AssignPermissionToRole
2
+
3
+ ## Overview
4
+
5
+ AssignPermissionToRole creates an association between a permission and a role, granting that permission to all users who have the role assigned. This command enables building up role capabilities by adding permissions one at a time.
6
+
7
+ The operation is idempotent - assigning the same permission to a role twice does not create duplicate records or return an error.
8
+
9
+ ## Business Rules
10
+
11
+ - Role must exist in the system
12
+ - Permission must exist in the system
13
+ - Operation is idempotent (assigning same permission twice is not an error)
14
+ - Creates RolePermission association record if not already present
15
+ - Generates PERMISSION_ASSIGNED audit event with actor ID, role ID, permission ID, and timestamp
16
+
17
+ ## Process Flow
18
+
19
+ ```mermaid
20
+ flowchart TD
21
+ A[Receive assign request] --> B{Role exists?}
22
+ B -->|No| C[Return error: ROLE_NOT_FOUND]
23
+ B -->|Yes| D{Permission exists?}
24
+ D -->|No| E[Return error: PERMISSION_NOT_FOUND]
25
+ D -->|Yes| F{Assignment exists?}
26
+ F -->|Yes| G[Return success - idempotent]
27
+ F -->|No| H[Create RolePermission record]
28
+ H --> I[Log PERMISSION_ASSIGNED audit event]
29
+ I --> J[Return success]
30
+ ```
31
+
32
+ ## External Dependencies
33
+
34
+ - None
35
+
36
+ ## Error Scenarios
37
+
38
+ - **ROLE_NOT_FOUND**: Role ID does not exist in the system - return not found error with the provided role ID
39
+ - **PERMISSION_NOT_FOUND**: Permission ID does not exist in the system - return not found error with the provided permission ID
@@ -0,0 +1,43 @@
1
+ # AssignRoleToUser
2
+
3
+ ## Overview
4
+
5
+ AssignRoleToUser creates an association between a role and a user, granting the user all permissions associated with that role. This command enables granting access to users by assigning them roles rather than managing permissions individually.
6
+
7
+ Only ACTIVE users can receive role assignments. The operation is idempotent - assigning the same role to a user twice does not create duplicate records or return an error.
8
+
9
+ ## Business Rules
10
+
11
+ - User must exist in the system
12
+ - Role must exist in the system
13
+ - User must be in ACTIVE status
14
+ - Operation is idempotent (assigning same role twice is not an error)
15
+ - Creates UserRole association record if not already present
16
+ - Generates ROLE_ASSIGNED audit event with actor ID, user ID, role ID, and timestamp
17
+
18
+ ## Process Flow
19
+
20
+ ```mermaid
21
+ flowchart TD
22
+ A[Receive assign request] --> B{User exists?}
23
+ B -->|No| C[Return error: USER_NOT_FOUND]
24
+ B -->|Yes| D{Role exists?}
25
+ D -->|No| E[Return error: ROLE_NOT_FOUND]
26
+ D -->|Yes| F{User is ACTIVE?}
27
+ F -->|No| G[Return error: USER_NOT_ACTIVE]
28
+ F -->|Yes| H{Assignment exists?}
29
+ H -->|Yes| I[Return success - idempotent]
30
+ H -->|No| J[Create UserRole record]
31
+ J --> K[Log ROLE_ASSIGNED audit event]
32
+ K --> L[Return success]
33
+ ```
34
+
35
+ ## External Dependencies
36
+
37
+ - None
38
+
39
+ ## Error Scenarios
40
+
41
+ - **USER_NOT_FOUND**: User ID does not exist in the system - return not found error with the provided user ID
42
+ - **ROLE_NOT_FOUND**: Role ID does not exist in the system - return not found error with the provided role ID
43
+ - **USER_NOT_ACTIVE**: User is in PENDING or INACTIVE status - return error indicating only ACTIVE users can receive role assignments
@@ -0,0 +1,35 @@
1
+ # CreatePermission
2
+
3
+ ## Overview
4
+
5
+ CreatePermission defines a new permission in the system using the `resource:action` format. Permissions are the atomic unit of authorization, specifying what action can be performed on what resource. Examples include `orders:read`, `orders:write`, `users:delete`.
6
+
7
+ Permissions are assigned to roles, which are then assigned to users. This indirection simplifies access management at scale.
8
+
9
+ ## Business Rules
10
+
11
+ - Permission key must follow `resource:action` format (lowercase letters, colon separator)
12
+ - Permission key must be unique across all permissions
13
+ - Description is optional but recommended for clarity
14
+ - Generates PERMISSION_ASSIGNED audit event when assigned to a role (via assignPermissionToRole)
15
+
16
+ ## Process Flow
17
+
18
+ ```mermaid
19
+ flowchart TD
20
+ A[Receive create request] --> B{Validate key format}
21
+ B -->|Invalid| C[Return error: INVALID_KEY_FORMAT]
22
+ B -->|Valid| D{Key unique?}
23
+ D -->|No| E[Return error: PERMISSION_ALREADY_EXISTS]
24
+ D -->|Yes| F[Create permission record]
25
+ F --> G[Return created permission]
26
+ ```
27
+
28
+ ## External Dependencies
29
+
30
+ - None
31
+
32
+ ## Error Scenarios
33
+
34
+ - **INVALID_KEY_FORMAT**: Key does not match `resource:action` pattern - return validation error with format requirements
35
+ - **PERMISSION_ALREADY_EXISTS**: Permission with the same key already exists - return conflict error with existing permission reference
@@ -0,0 +1,35 @@
1
+ # CreateRole
2
+
3
+ ## Overview
4
+
5
+ CreateRole establishes a new role in the system with a unique name and optional description. Roles are containers for permissions that can be assigned to users, providing a level of abstraction that simplifies access management. Examples include "Sales Representative", "Sales Manager", "Administrator".
6
+
7
+ Roles follow the principle of least privilege, bundling only the permissions necessary for a specific job function.
8
+
9
+ ## Business Rules
10
+
11
+ - Role name must be unique across all roles
12
+ - Role name is required and cannot be empty
13
+ - Description is optional but recommended for clarity
14
+ - New roles start with no permissions assigned
15
+
16
+ ## Process Flow
17
+
18
+ ```mermaid
19
+ flowchart TD
20
+ A[Receive create request] --> B{Name provided?}
21
+ B -->|No| C[Return error: MISSING_REQUIRED_FIELD]
22
+ B -->|Yes| D{Name unique?}
23
+ D -->|No| E[Return error: ROLE_ALREADY_EXISTS]
24
+ D -->|Yes| F[Create role record]
25
+ F --> G[Return created role]
26
+ ```
27
+
28
+ ## External Dependencies
29
+
30
+ - None
31
+
32
+ ## Error Scenarios
33
+
34
+ - **MISSING_REQUIRED_FIELD**: Role name not provided - return validation error indicating name is required
35
+ - **ROLE_ALREADY_EXISTS**: Role with the same name already exists - return conflict error with existing role reference
@@ -0,0 +1,41 @@
1
+ # CreateUser
2
+
3
+ ## Overview
4
+
5
+ CreateUser establishes a new user account in the system with the provided name and email address. The user is created in PENDING status, awaiting activation by an administrator after verification is complete. This command supports the user onboarding process where new accounts must be verified before gaining system access.
6
+
7
+ This command enforces email uniqueness across all users (active and inactive) to prevent duplicate accounts.
8
+
9
+ ## Business Rules
10
+
11
+ - Email must be unique across all users (active and inactive)
12
+ - Email must follow valid email format
13
+ - Name is required and cannot be empty
14
+ - New users are created in PENDING status
15
+ - Generates USER_CREATED audit event with actor ID and timestamp
16
+
17
+ ## Process Flow
18
+
19
+ ```mermaid
20
+ flowchart TD
21
+ A[Receive create request] --> B{Validate email format}
22
+ B -->|Invalid| C[Return error: INVALID_EMAIL]
23
+ B -->|Valid| D{Email unique?}
24
+ D -->|No| E[Return error: USER_ALREADY_EXISTS]
25
+ D -->|Yes| F{Name provided?}
26
+ F -->|No| G[Return error: MISSING_REQUIRED_FIELD]
27
+ F -->|Yes| H[Create user record]
28
+ H --> I[Set status: PENDING]
29
+ I --> J[Log USER_CREATED audit event]
30
+ J --> K[Return created user]
31
+ ```
32
+
33
+ ## External Dependencies
34
+
35
+ - None
36
+
37
+ ## Error Scenarios
38
+
39
+ - **USER_ALREADY_EXISTS**: Email address is already registered in the system - return conflict error with message indicating email is taken
40
+ - **INVALID_EMAIL**: Email does not follow valid email format - return validation error with format requirements
41
+ - **MISSING_REQUIRED_FIELD**: Name or email not provided - return validation error listing missing fields
@@ -0,0 +1,38 @@
1
+ # DeactivateUser
2
+
3
+ ## Overview
4
+
5
+ DeactivateUser transitions a user from ACTIVE status to INACTIVE status, revoking their access to the system while preserving their data for audit and historical purposes. This command is used when an employee leaves the organization, is terminated, or needs temporary access suspension.
6
+
7
+ Only users in ACTIVE status can be deactivated. User data, role assignments, and historical associations are preserved.
8
+
9
+ ## Business Rules
10
+
11
+ - User must exist in the system
12
+ - User must be in ACTIVE status
13
+ - Transitions user status from ACTIVE to INACTIVE
14
+ - User data is preserved for audit purposes
15
+ - Existing role assignments remain but become inactive
16
+ - Generates USER_DEACTIVATED audit event with actor ID, timestamp, and previous status
17
+
18
+ ## Process Flow
19
+
20
+ ```mermaid
21
+ flowchart TD
22
+ A[Receive deactivate request] --> B{User exists?}
23
+ B -->|No| C[Return error: USER_NOT_FOUND]
24
+ B -->|Yes| D{Status is ACTIVE?}
25
+ D -->|No| E[Return error: INVALID_STATUS_TRANSITION]
26
+ D -->|Yes| F[Update status to INACTIVE]
27
+ F --> G[Log USER_DEACTIVATED audit event]
28
+ G --> H[Return updated user]
29
+ ```
30
+
31
+ ## External Dependencies
32
+
33
+ - None
34
+
35
+ ## Error Scenarios
36
+
37
+ - **USER_NOT_FOUND**: User ID does not exist in the system - return not found error with the provided ID
38
+ - **INVALID_STATUS_TRANSITION**: User is not in ACTIVE status (PENDING or already INACTIVE) - return error with current status and valid transitions
@@ -0,0 +1,37 @@
1
+ # LogAuditEvent
2
+
3
+ ## Overview
4
+
5
+ LogAuditEvent creates an immutable record of a security-relevant event in the User Management module. This command captures the actor identity, timestamp, event type, and event details for compliance and security purposes.
6
+
7
+ Typically, this command is triggered internally as a side effect of other commands (createUser, activateUser, assignRoleToUser, etc.) rather than being called directly.
8
+
9
+ ## Business Rules
10
+
11
+ - Event type must be a valid event type (USER_CREATED, USER_ACTIVATED, USER_DEACTIVATED, USER_REACTIVATED, ROLE_ASSIGNED, ROLE_REVOKED, PERMISSION_ASSIGNED, PERMISSION_REVOKED)
12
+ - Actor ID is required (identifies who performed the action)
13
+ - Timestamp is auto-generated at creation
14
+ - Event payload contains relevant details specific to the event type
15
+ - Record is immutable once created (no updates or deletes allowed)
16
+
17
+ ## Process Flow
18
+
19
+ ```mermaid
20
+ flowchart TD
21
+ A[Receive log request] --> B{Valid event type?}
22
+ B -->|No| C[Return error: INVALID_EVENT_TYPE]
23
+ B -->|Yes| D{Actor ID provided?}
24
+ D -->|No| E[Return error: MISSING_REQUIRED_FIELD]
25
+ D -->|Yes| F[Generate timestamp]
26
+ F --> G[Create AuditEvent record]
27
+ G --> H[Return created event]
28
+ ```
29
+
30
+ ## External Dependencies
31
+
32
+ - None
33
+
34
+ ## Error Scenarios
35
+
36
+ - **INVALID_EVENT_TYPE**: Event type is not one of the recognized types - return validation error with list of valid event types
37
+ - **MISSING_REQUIRED_FIELD**: Actor ID not provided - return validation error indicating actor ID is required
@@ -0,0 +1,37 @@
1
+ # ReactivateUser
2
+
3
+ ## Overview
4
+
5
+ ReactivateUser transitions a user from INACTIVE status back to ACTIVE status, restoring their access to the system. This command is used when a previously offboarded user returns, such as a contractor returning for a new engagement or a reinstated employee.
6
+
7
+ Only users in INACTIVE status can be reactivated. Historical associations and role assignments are preserved and become active again.
8
+
9
+ ## Business Rules
10
+
11
+ - User must exist in the system
12
+ - User must be in INACTIVE status
13
+ - Transitions user status from INACTIVE to ACTIVE
14
+ - Preserves historical role assignments and associations
15
+ - Generates USER_REACTIVATED audit event with actor ID, timestamp, and previous status
16
+
17
+ ## Process Flow
18
+
19
+ ```mermaid
20
+ flowchart TD
21
+ A[Receive reactivate request] --> B{User exists?}
22
+ B -->|No| C[Return error: USER_NOT_FOUND]
23
+ B -->|Yes| D{Status is INACTIVE?}
24
+ D -->|No| E[Return error: INVALID_STATUS_TRANSITION]
25
+ D -->|Yes| F[Update status to ACTIVE]
26
+ F --> G[Log USER_REACTIVATED audit event]
27
+ G --> H[Return updated user]
28
+ ```
29
+
30
+ ## External Dependencies
31
+
32
+ - None
33
+
34
+ ## Error Scenarios
35
+
36
+ - **USER_NOT_FOUND**: User ID does not exist in the system - return not found error with the provided ID
37
+ - **INVALID_STATUS_TRANSITION**: User is not in INACTIVE status (PENDING or already ACTIVE) - return error with current status and valid transitions
@@ -0,0 +1,40 @@
1
+ # RevokePermissionFromRole
2
+
3
+ ## Overview
4
+
5
+ RevokePermissionFromRole removes an association between a permission and a role, revoking that permission from all users who have the role assigned. This command is used when restructuring role capabilities or removing permissions that are no longer appropriate.
6
+
7
+ The association must exist before it can be revoked.
8
+
9
+ ## Business Rules
10
+
11
+ - Role must exist in the system
12
+ - Permission must exist in the system
13
+ - RolePermission association must exist
14
+ - Removes the RolePermission association record
15
+ - Generates PERMISSION_REVOKED audit event with actor ID, role ID, permission ID, and timestamp
16
+
17
+ ## Process Flow
18
+
19
+ ```mermaid
20
+ flowchart TD
21
+ A[Receive revoke request] --> B{Role exists?}
22
+ B -->|No| C[Return error: ROLE_NOT_FOUND]
23
+ B -->|Yes| D{Permission exists?}
24
+ D -->|No| E[Return error: PERMISSION_NOT_FOUND]
25
+ D -->|Yes| F{Assignment exists?}
26
+ F -->|No| G[Return error: ASSIGNMENT_NOT_FOUND]
27
+ F -->|Yes| H[Delete RolePermission record]
28
+ H --> I[Log PERMISSION_REVOKED audit event]
29
+ I --> J[Return success]
30
+ ```
31
+
32
+ ## External Dependencies
33
+
34
+ - None
35
+
36
+ ## Error Scenarios
37
+
38
+ - **ROLE_NOT_FOUND**: Role ID does not exist in the system - return not found error with the provided role ID
39
+ - **PERMISSION_NOT_FOUND**: Permission ID does not exist in the system - return not found error with the provided permission ID
40
+ - **ASSIGNMENT_NOT_FOUND**: Role does not have this permission assigned - return not found error indicating the association does not exist
@@ -0,0 +1,40 @@
1
+ # RevokeRoleFromUser
2
+
3
+ ## Overview
4
+
5
+ RevokeRoleFromUser removes an association between a role and a user, revoking all permissions that the user had through that role. This command is used when a user changes positions, leaves a project, or no longer requires the access granted by the role.
6
+
7
+ The association must exist before it can be revoked.
8
+
9
+ ## Business Rules
10
+
11
+ - User must exist in the system
12
+ - Role must exist in the system
13
+ - UserRole association must exist
14
+ - Removes the UserRole association record
15
+ - Generates ROLE_REVOKED audit event with actor ID, user ID, role ID, and timestamp
16
+
17
+ ## Process Flow
18
+
19
+ ```mermaid
20
+ flowchart TD
21
+ A[Receive revoke request] --> B{User exists?}
22
+ B -->|No| C[Return error: USER_NOT_FOUND]
23
+ B -->|Yes| D{Role exists?}
24
+ D -->|No| E[Return error: ROLE_NOT_FOUND]
25
+ D -->|Yes| F{Assignment exists?}
26
+ F -->|No| G[Return error: ASSIGNMENT_NOT_FOUND]
27
+ F -->|Yes| H[Delete UserRole record]
28
+ H --> I[Log ROLE_REVOKED audit event]
29
+ I --> J[Return success]
30
+ ```
31
+
32
+ ## External Dependencies
33
+
34
+ - None
35
+
36
+ ## Error Scenarios
37
+
38
+ - **USER_NOT_FOUND**: User ID does not exist in the system - return not found error with the provided user ID
39
+ - **ROLE_NOT_FOUND**: Role ID does not exist in the system - return not found error with the provided role ID
40
+ - **ASSIGNMENT_NOT_FOUND**: User does not have this role assigned - return not found error indicating the association does not exist
@@ -0,0 +1,80 @@
1
+ # Audit Trail
2
+
3
+ ## Overview
4
+
5
+ The Audit Trail captures immutable records of all security-relevant events in the User Management module. Every user lifecycle change, role assignment, and permission modification is logged with the actor identity, timestamp, and event details. These records cannot be modified or deleted, ensuring a trustworthy history for compliance and security investigations.
6
+
7
+ This feature provides the foundation for regulatory compliance and security forensics across the ERP system.
8
+
9
+ ## Business Purpose
10
+
11
+ Organizations require audit trails for multiple reasons:
12
+
13
+ - **Regulatory Compliance**: SOX, GDPR, HIPAA, and other regulations mandate tracking of access and authorization changes
14
+ - **Security Investigations**: When incidents occur, audit logs reveal who did what and when
15
+ - **Access Reviews**: Periodic reviews of who has access to what rely on historical assignment data
16
+ - **Accountability**: Users knowing their actions are logged encourages responsible behavior
17
+ - **Change Tracking**: Understanding how access evolved over time supports troubleshooting and planning
18
+
19
+ ## Process Flow
20
+
21
+ ```mermaid
22
+ flowchart TD
23
+ A[Security Event Occurs] --> B[Capture Event Details]
24
+ B --> C[Record Actor Identity]
25
+ C --> D[Record Timestamp]
26
+ D --> E[Record Event Type]
27
+ E --> F[Record Event Payload]
28
+ F --> G[Store Immutable Record]
29
+ G --> H[Available for Query]
30
+
31
+ subgraph Event Types
32
+ I[USER_CREATED]
33
+ J[USER_ACTIVATED]
34
+ K[USER_DEACTIVATED]
35
+ L[USER_REACTIVATED]
36
+ M[ROLE_ASSIGNED]
37
+ N[ROLE_REVOKED]
38
+ O[PERMISSION_ASSIGNED]
39
+ P[PERMISSION_REVOKED]
40
+ end
41
+
42
+ subgraph Immutability
43
+ G --> Q[No UPDATE Allowed]
44
+ G --> R[No DELETE Allowed]
45
+ end
46
+ ```
47
+
48
+ ## Scenario Patterns
49
+
50
+ - **User Creation Audit**: When admin creates new user, system logs USER_CREATED event with admin ID, new user details, and timestamp. Provides accountability for onboarding.
51
+ - **Status Transition Audit**: User activation logs USER_ACTIVATED with old status (PENDING) and new status (ACTIVE). Complete state change history maintained.
52
+ - **Role Assignment Audit**: Assigning "Sales Manager" role to user logs ROLE_ASSIGNED with assigner ID, user ID, role ID, and timestamp. Tracks who granted elevated access.
53
+ - **Permission Change Audit**: Adding permission to role logs PERMISSION_ASSIGNED. Even though permission affects many users through the role, the change itself is tracked.
54
+ - **Compliance Query**: Auditor requests all access changes for specific user over past year. System returns chronological list of all role assignments and revocations.
55
+ - **Incident Investigation**: Security team investigates unauthorized data access. Audit trail reveals user's roles at time of access and who assigned those roles.
56
+ - **Bulk Operations**: Even bulk operations (e.g., deactivating multiple users) generate individual audit entries for each user affected.
57
+
58
+ ## Test Cases
59
+
60
+ - Creating a user should generate USER_CREATED audit entry
61
+ - Activating a user should generate USER_ACTIVATED entry with previous status
62
+ - Deactivating a user should generate USER_DEACTIVATED entry with previous status
63
+ - Reactivating a user should generate USER_REACTIVATED entry with previous status
64
+ - Assigning role to user should generate ROLE_ASSIGNED entry
65
+ - Revoking role from user should generate ROLE_REVOKED entry
66
+ - Assigning permission to role should generate PERMISSION_ASSIGNED entry
67
+ - Revoking permission from role should generate PERMISSION_REVOKED entry
68
+ - Audit entries should include actor ID (who performed the action)
69
+ - Audit entries should include timestamp (when action occurred)
70
+ - Audit entries should be immutable (no update operation allowed)
71
+ - Audit entries should be immutable (no delete operation allowed)
72
+ - Querying audit by user ID should return all entries related to that user
73
+ - Querying audit by date range should return entries within range
74
+ - Querying audit by event type should filter appropriately
75
+
76
+ ## Reference Links
77
+
78
+ - [OWASP Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html)
79
+ - [NIST Audit and Accountability](https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final)
80
+ - [SOX Compliance Requirements](https://www.soxlaw.com/)