@tailor-platform/erp-kit 0.0.1 → 0.1.1
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.
- package/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/README.md +196 -28
- package/dist/cli.js +914 -0
- package/package.json +67 -8
- package/schemas/app-compose/actors.yml +34 -0
- package/schemas/app-compose/business-flow.yml +50 -0
- package/schemas/app-compose/requirements.yml +33 -0
- package/schemas/app-compose/resolver.yml +47 -0
- package/schemas/app-compose/screen.yml +81 -0
- package/schemas/app-compose/story.yml +67 -0
- package/schemas/module/command.yml +52 -0
- package/schemas/module/feature.yml +58 -0
- package/schemas/module/model.yml +70 -0
- package/schemas/module/module.yml +50 -0
- package/skills/1-module-docs/SKILL.md +111 -0
- package/skills/1-module-docs/references/structure.md +22 -0
- package/skills/2-module-feature-breakdown/SKILL.md +72 -0
- package/skills/2-module-feature-breakdown/references/commands.md +48 -0
- package/skills/2-module-feature-breakdown/references/models.md +29 -0
- package/skills/2-module-feature-breakdown/references/structure.md +22 -0
- package/skills/3-module-doc-review/SKILL.md +236 -0
- package/skills/3-module-doc-review/references/commands.md +54 -0
- package/skills/3-module-doc-review/references/models.md +29 -0
- package/skills/3-module-doc-review/references/testing.md +37 -0
- package/skills/4-module-tdd-implementation/SKILL.md +74 -0
- package/skills/4-module-tdd-implementation/references/commands.md +45 -0
- package/skills/4-module-tdd-implementation/references/db-relations.md +69 -0
- package/skills/4-module-tdd-implementation/references/errors.md +7 -0
- package/skills/4-module-tdd-implementation/references/exports.md +8 -0
- package/skills/4-module-tdd-implementation/references/models.md +30 -0
- package/skills/4-module-tdd-implementation/references/structure.md +22 -0
- package/skills/4-module-tdd-implementation/references/testing.md +37 -0
- package/skills/5-module-implementation-review/SKILL.md +408 -0
- package/skills/5-module-implementation-review/references/commands.md +45 -0
- package/skills/5-module-implementation-review/references/errors.md +7 -0
- package/skills/5-module-implementation-review/references/exports.md +8 -0
- package/skills/5-module-implementation-review/references/models.md +30 -0
- package/skills/5-module-implementation-review/references/testing.md +29 -0
- package/skills/app-compose-1-requirement-analysis/SKILL.md +89 -0
- package/skills/app-compose-1-requirement-analysis/references/structure.md +27 -0
- package/skills/app-compose-2-requirements-breakdown/SKILL.md +95 -0
- package/skills/app-compose-2-requirements-breakdown/references/screen-detailview.md +106 -0
- package/skills/app-compose-2-requirements-breakdown/references/screen-form.md +139 -0
- package/skills/app-compose-2-requirements-breakdown/references/screen-listview.md +153 -0
- package/skills/app-compose-2-requirements-breakdown/references/structure.md +27 -0
- package/skills/app-compose-3-doc-review/SKILL.md +116 -0
- package/skills/app-compose-3-doc-review/references/structure.md +27 -0
- package/skills/app-compose-4-design-mock/SKILL.md +256 -0
- package/skills/app-compose-4-design-mock/references/component.md +50 -0
- package/skills/app-compose-4-design-mock/references/screen-detailview.md +106 -0
- package/skills/app-compose-4-design-mock/references/screen-form.md +139 -0
- package/skills/app-compose-4-design-mock/references/screen-listview.md +153 -0
- package/skills/app-compose-4-design-mock/references/structure.md +27 -0
- package/skills/app-compose-5-design-mock-review/SKILL.md +290 -0
- package/skills/app-compose-5-design-mock-review/references/component.md +50 -0
- package/skills/app-compose-5-design-mock-review/references/screen-detailview.md +106 -0
- package/skills/app-compose-5-design-mock-review/references/screen-form.md +139 -0
- package/skills/app-compose-5-design-mock-review/references/screen-listview.md +153 -0
- package/skills/app-compose-6-implementation-spec/SKILL.md +127 -0
- package/skills/app-compose-6-implementation-spec/references/auth.md +72 -0
- package/skills/app-compose-6-implementation-spec/references/structure.md +27 -0
- package/skills/mock-scenario/SKILL.md +118 -0
- package/src/app.ts +1 -0
- package/src/cli.ts +120 -0
- package/src/commands/check.test.ts +30 -0
- package/src/commands/check.ts +66 -0
- package/src/commands/init.test.ts +88 -0
- package/src/commands/init.ts +120 -0
- package/src/commands/mock/index.ts +53 -0
- package/src/commands/mock/start.ts +179 -0
- package/src/commands/mock/validate.test.ts +185 -0
- package/src/commands/mock/validate.ts +198 -0
- package/src/commands/scaffold.test.ts +76 -0
- package/src/commands/scaffold.ts +119 -0
- package/src/commands/sync-check.test.ts +125 -0
- package/src/commands/sync-check.ts +182 -0
- package/src/integration.test.ts +63 -0
- package/src/mdschema.ts +48 -0
- package/src/mockServer.ts +55 -0
- package/src/module.ts +86 -0
- package/src/modules/accounting/.gitkeep +0 -0
- package/src/modules/coa-management/.gitkeep +0 -0
- package/src/modules/inventory/.gitkeep +0 -0
- package/src/modules/manufacturing/.gitkeep +0 -0
- package/src/modules/primitives/README.md +39 -0
- package/src/modules/primitives/command/activateCategory.test.ts +75 -0
- package/src/modules/primitives/command/activateCategory.ts +50 -0
- package/src/modules/primitives/command/activateCurrency.test.ts +70 -0
- package/src/modules/primitives/command/activateCurrency.ts +50 -0
- package/src/modules/primitives/command/activateUnit.test.ts +53 -0
- package/src/modules/primitives/command/activateUnit.ts +50 -0
- package/src/modules/primitives/command/convertAmount.test.ts +275 -0
- package/src/modules/primitives/command/convertAmount.ts +126 -0
- package/src/modules/primitives/command/convertQuantity.test.ts +219 -0
- package/src/modules/primitives/command/convertQuantity.ts +73 -0
- package/src/modules/primitives/command/createCategory.test.ts +126 -0
- package/src/modules/primitives/command/createCategory.ts +89 -0
- package/src/modules/primitives/command/createCurrency.test.ts +191 -0
- package/src/modules/primitives/command/createCurrency.ts +77 -0
- package/src/modules/primitives/command/createExchangeRate.test.ts +216 -0
- package/src/modules/primitives/command/createExchangeRate.ts +91 -0
- package/src/modules/primitives/command/createUnit.test.ts +214 -0
- package/src/modules/primitives/command/createUnit.ts +88 -0
- package/src/modules/primitives/command/deactivateCategory.test.ts +97 -0
- package/src/modules/primitives/command/deactivateCategory.ts +62 -0
- package/src/modules/primitives/command/deactivateCurrency.test.ts +85 -0
- package/src/modules/primitives/command/deactivateCurrency.ts +55 -0
- package/src/modules/primitives/command/deactivateUnit.test.ts +78 -0
- package/src/modules/primitives/command/deactivateUnit.ts +62 -0
- package/src/modules/primitives/command/setBaseCurrency.test.ts +98 -0
- package/src/modules/primitives/command/setBaseCurrency.ts +74 -0
- package/src/modules/primitives/command/setReferenceUnit.test.ts +108 -0
- package/src/modules/primitives/command/setReferenceUnit.ts +84 -0
- package/src/modules/primitives/db/currency.ts +30 -0
- package/src/modules/primitives/db/exchangeRate.ts +28 -0
- package/src/modules/primitives/db/unit.ts +32 -0
- package/src/modules/primitives/db/uomCategory.ts +32 -0
- package/src/modules/primitives/docs/commands/ActivateCategory.md +34 -0
- package/src/modules/primitives/docs/commands/ActivateCurrency.md +33 -0
- package/src/modules/primitives/docs/commands/ActivateUnit.md +34 -0
- package/src/modules/primitives/docs/commands/ConvertAmount.md +50 -0
- package/src/modules/primitives/docs/commands/ConvertQuantity.md +43 -0
- package/src/modules/primitives/docs/commands/CreateCategory.md +44 -0
- package/src/modules/primitives/docs/commands/CreateCurrency.md +47 -0
- package/src/modules/primitives/docs/commands/CreateExchangeRate.md +48 -0
- package/src/modules/primitives/docs/commands/CreateUnit.md +48 -0
- package/src/modules/primitives/docs/commands/DeactivateCategory.md +38 -0
- package/src/modules/primitives/docs/commands/DeactivateCurrency.md +38 -0
- package/src/modules/primitives/docs/commands/DeactivateUnit.md +38 -0
- package/src/modules/primitives/docs/commands/SetBaseCurrency.md +39 -0
- package/src/modules/primitives/docs/commands/SetReferenceUnit.md +43 -0
- package/src/modules/primitives/docs/features/currency-definitions.md +55 -0
- package/src/modules/primitives/docs/features/exchange-rates.md +61 -0
- package/src/modules/primitives/docs/features/unit-conversion.md +66 -0
- package/src/modules/primitives/docs/features/uom-categories.md +52 -0
- package/src/modules/primitives/docs/models/Currency.md +45 -0
- package/src/modules/primitives/docs/models/ExchangeRate.md +33 -0
- package/src/modules/primitives/docs/models/Unit.md +46 -0
- package/src/modules/primitives/docs/models/UoMCategory.md +44 -0
- package/src/modules/primitives/generated/kysely-tailordb.ts +95 -0
- package/src/modules/primitives/index.ts +40 -0
- package/src/modules/primitives/lib/errors.ts +138 -0
- package/src/modules/primitives/lib/types.ts +20 -0
- package/src/modules/primitives/module.ts +66 -0
- package/src/modules/primitives/permissions.ts +18 -0
- package/src/modules/primitives/tailor.config.ts +11 -0
- package/src/modules/primitives/testing/fixtures.ts +161 -0
- package/src/modules/product-management/.gitkeep +0 -0
- package/src/modules/purchase/.gitkeep +0 -0
- package/src/modules/sales/.gitkeep +0 -0
- package/src/modules/shared/createContext.test.ts +39 -0
- package/src/modules/shared/createContext.ts +15 -0
- package/src/modules/shared/defineCommand.test.ts +42 -0
- package/src/modules/shared/defineCommand.ts +19 -0
- package/src/modules/shared/definePermissions.test.ts +146 -0
- package/src/modules/shared/definePermissions.ts +94 -0
- package/src/modules/shared/entityTypes.ts +15 -0
- package/src/modules/shared/errors.ts +22 -0
- package/src/modules/shared/index.ts +1 -0
- package/src/modules/shared/internal.ts +13 -0
- package/src/modules/shared/requirePermission.test.ts +47 -0
- package/src/modules/shared/requirePermission.ts +8 -0
- package/src/modules/shared/types.ts +4 -0
- package/src/modules/supplier-management/.gitkeep +0 -0
- package/src/modules/supplier-portal/.gitkeep +0 -0
- package/src/modules/testing/index.ts +120 -0
- package/src/modules/user-management/README.md +38 -0
- package/src/modules/user-management/command/activateUser.test.ts +112 -0
- package/src/modules/user-management/command/activateUser.ts +67 -0
- package/src/modules/user-management/command/assignPermissionToRole.test.ts +119 -0
- package/src/modules/user-management/command/assignPermissionToRole.ts +87 -0
- package/src/modules/user-management/command/assignRoleToUser.test.ts +162 -0
- package/src/modules/user-management/command/assignRoleToUser.ts +93 -0
- package/src/modules/user-management/command/createPermission.test.ts +143 -0
- package/src/modules/user-management/command/createPermission.ts +66 -0
- package/src/modules/user-management/command/createRole.test.ts +115 -0
- package/src/modules/user-management/command/createRole.ts +52 -0
- package/src/modules/user-management/command/createUser.test.ts +198 -0
- package/src/modules/user-management/command/createUser.ts +85 -0
- package/src/modules/user-management/command/deactivateUser.test.ts +112 -0
- package/src/modules/user-management/command/deactivateUser.ts +67 -0
- package/src/modules/user-management/command/logAuditEvent.test.ts +179 -0
- package/src/modules/user-management/command/logAuditEvent.ts +59 -0
- package/src/modules/user-management/command/reactivateUser.test.ts +115 -0
- package/src/modules/user-management/command/reactivateUser.ts +67 -0
- package/src/modules/user-management/command/revokePermissionFromRole.test.ts +112 -0
- package/src/modules/user-management/command/revokePermissionFromRole.ts +81 -0
- package/src/modules/user-management/command/revokeRoleFromUser.test.ts +112 -0
- package/src/modules/user-management/command/revokeRoleFromUser.ts +81 -0
- package/src/modules/user-management/db/auditEvent.ts +47 -0
- package/src/modules/user-management/db/permission.ts +31 -0
- package/src/modules/user-management/db/role.ts +28 -0
- package/src/modules/user-management/db/rolePermission.ts +44 -0
- package/src/modules/user-management/db/user.ts +38 -0
- package/src/modules/user-management/db/userRole.ts +44 -0
- package/src/modules/user-management/docs/commands/ActivateUser.md +36 -0
- package/src/modules/user-management/docs/commands/AssignPermissionToRole.md +39 -0
- package/src/modules/user-management/docs/commands/AssignRoleToUser.md +43 -0
- package/src/modules/user-management/docs/commands/CreatePermission.md +35 -0
- package/src/modules/user-management/docs/commands/CreateRole.md +35 -0
- package/src/modules/user-management/docs/commands/CreateUser.md +41 -0
- package/src/modules/user-management/docs/commands/DeactivateUser.md +38 -0
- package/src/modules/user-management/docs/commands/LogAuditEvent.md +37 -0
- package/src/modules/user-management/docs/commands/ReactivateUser.md +37 -0
- package/src/modules/user-management/docs/commands/RevokePermissionFromRole.md +40 -0
- package/src/modules/user-management/docs/commands/RevokeRoleFromUser.md +40 -0
- package/src/modules/user-management/docs/features/audit-trail.md +80 -0
- package/src/modules/user-management/docs/features/role-based-access-control.md +76 -0
- package/src/modules/user-management/docs/features/user-account-management.md +64 -0
- package/src/modules/user-management/docs/models/AuditEvent.md +34 -0
- package/src/modules/user-management/docs/models/Permission.md +31 -0
- package/src/modules/user-management/docs/models/Role.md +31 -0
- package/src/modules/user-management/docs/models/RolePermission.md +33 -0
- package/src/modules/user-management/docs/models/User.md +47 -0
- package/src/modules/user-management/docs/models/UserRole.md +34 -0
- package/src/modules/user-management/docs/plans/2026-01-30-flattened-permissions-design.md +52 -0
- package/src/modules/user-management/executor/recomputeOnRolePermissionChange.ts +61 -0
- package/src/modules/user-management/generated/enums.ts +24 -0
- package/src/modules/user-management/generated/kysely-tailordb.ts +112 -0
- package/src/modules/user-management/index.ts +32 -0
- package/src/modules/user-management/lib/errors.ts +81 -0
- package/src/modules/user-management/lib/recomputeUserPermissions.ts +53 -0
- package/src/modules/user-management/lib/types.ts +31 -0
- package/src/modules/user-management/module.ts +77 -0
- package/src/modules/user-management/permissions.ts +15 -0
- package/src/modules/user-management/tailor.config.ts +11 -0
- package/src/modules/user-management/testing/fixtures.ts +98 -0
- package/src/schemas.ts +25 -0
- package/src/testing.ts +10 -0
- package/src/util.ts +3 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createDomainError } from "../../shared/internal";
|
|
2
|
+
|
|
3
|
+
export const UserNotFoundError = createDomainError(
|
|
4
|
+
"UserNotFoundError",
|
|
5
|
+
"USER_NOT_FOUND",
|
|
6
|
+
(userId: string) => `User not found: ${userId}`,
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
export const UserAlreadyExistsError = createDomainError(
|
|
10
|
+
"UserAlreadyExistsError",
|
|
11
|
+
"USER_ALREADY_EXISTS",
|
|
12
|
+
(email: string) => `User with email "${email}" already exists`,
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export const UserNotActiveError = createDomainError(
|
|
16
|
+
"UserNotActiveError",
|
|
17
|
+
"USER_NOT_ACTIVE",
|
|
18
|
+
(userId: string, status: string) => `User ${userId} is not active (current status: ${status})`,
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export const InvalidEmailError = createDomainError(
|
|
22
|
+
"InvalidEmailError",
|
|
23
|
+
"INVALID_EMAIL",
|
|
24
|
+
(email: string) => `Invalid email format: ${email}`,
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
export const MissingRequiredFieldError = createDomainError(
|
|
28
|
+
"MissingRequiredFieldError",
|
|
29
|
+
"MISSING_REQUIRED_FIELD",
|
|
30
|
+
(field: string) => `Missing required field: ${field}`,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export const InvalidStatusTransitionError = createDomainError(
|
|
34
|
+
"InvalidStatusTransitionError",
|
|
35
|
+
"INVALID_STATUS_TRANSITION",
|
|
36
|
+
(currentStatus: string, targetStatus: string) =>
|
|
37
|
+
`Invalid status transition from ${currentStatus} to ${targetStatus}`,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
export const PermissionNotFoundError = createDomainError(
|
|
41
|
+
"PermissionNotFoundError",
|
|
42
|
+
"PERMISSION_NOT_FOUND",
|
|
43
|
+
(permissionId: string) => `Permission not found: ${permissionId}`,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
export const DuplicatePermissionKeyError = createDomainError(
|
|
47
|
+
"DuplicatePermissionKeyError",
|
|
48
|
+
"DUPLICATE_PERMISSION_KEY",
|
|
49
|
+
(key: string) => `Permission with key "${key}" already exists`,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
export const InvalidPermissionKeyFormatError = createDomainError(
|
|
53
|
+
"InvalidPermissionKeyFormatError",
|
|
54
|
+
"INVALID_PERMISSION_KEY_FORMAT",
|
|
55
|
+
(key: string) => `Invalid permission key format: "${key}". Expected format: resource:action`,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
export const RoleNotFoundError = createDomainError(
|
|
59
|
+
"RoleNotFoundError",
|
|
60
|
+
"ROLE_NOT_FOUND",
|
|
61
|
+
(roleId: string) => `Role not found: ${roleId}`,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
export const DuplicateRoleNameError = createDomainError(
|
|
65
|
+
"DuplicateRoleNameError",
|
|
66
|
+
"DUPLICATE_ROLE_NAME",
|
|
67
|
+
(name: string) => `Role with name "${name}" already exists`,
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
export const AssignmentNotFoundError = createDomainError(
|
|
71
|
+
"AssignmentNotFoundError",
|
|
72
|
+
"ASSIGNMENT_NOT_FOUND",
|
|
73
|
+
(sourceType: string, sourceId: string, targetType: string, targetId: string) =>
|
|
74
|
+
`Assignment not found: ${sourceType} ${sourceId} -> ${targetType} ${targetId}`,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
export const InvalidEventTypeError = createDomainError(
|
|
78
|
+
"InvalidEventTypeError",
|
|
79
|
+
"INVALID_EVENT_TYPE",
|
|
80
|
+
(eventType: string) => `Invalid event type: ${eventType}`,
|
|
81
|
+
);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Kysely } from "kysely";
|
|
2
|
+
import { DB } from "../generated/kysely-tailordb";
|
|
3
|
+
import { User } from "./types";
|
|
4
|
+
|
|
5
|
+
export const recomputeUserPermissions = async <
|
|
6
|
+
T extends { User: object; UserRole: object; RolePermission: object; Permission: object },
|
|
7
|
+
>(
|
|
8
|
+
db: Kysely<T>,
|
|
9
|
+
userId: string,
|
|
10
|
+
): Promise<User<T>> => {
|
|
11
|
+
const _db = db as unknown as DB;
|
|
12
|
+
|
|
13
|
+
const permissionRows = await _db
|
|
14
|
+
.selectFrom("UserRole")
|
|
15
|
+
.innerJoin("RolePermission", "RolePermission.roleId", "UserRole.roleId")
|
|
16
|
+
.innerJoin("Permission", "Permission.id", "RolePermission.permissionId")
|
|
17
|
+
.select("Permission.key")
|
|
18
|
+
.where("UserRole.userId", "=", userId)
|
|
19
|
+
.execute();
|
|
20
|
+
|
|
21
|
+
const permissions = [...new Set(permissionRows.map((row) => row.key))].sort();
|
|
22
|
+
|
|
23
|
+
const updatedUser = await _db
|
|
24
|
+
.updateTable("User")
|
|
25
|
+
.set({ permissions, updatedAt: new Date() })
|
|
26
|
+
.where("id", "=", userId)
|
|
27
|
+
.returningAll()
|
|
28
|
+
.executeTakeFirstOrThrow();
|
|
29
|
+
|
|
30
|
+
return updatedUser as unknown as User<T>;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const recomputePermissionsForUsersWithRole = async <
|
|
34
|
+
T extends { User: object; UserRole: object; RolePermission: object; Permission: object },
|
|
35
|
+
>(
|
|
36
|
+
db: Kysely<T>,
|
|
37
|
+
roleId: string,
|
|
38
|
+
): Promise<User<T>[]> => {
|
|
39
|
+
const _db = db as unknown as DB;
|
|
40
|
+
|
|
41
|
+
const userRoles = await _db
|
|
42
|
+
.selectFrom("UserRole")
|
|
43
|
+
.select("userId")
|
|
44
|
+
.where("roleId", "=", roleId)
|
|
45
|
+
.execute();
|
|
46
|
+
|
|
47
|
+
const updatedUsers: User<T>[] = [];
|
|
48
|
+
for (const { userId } of userRoles) {
|
|
49
|
+
const user = await recomputeUserPermissions(db, userId);
|
|
50
|
+
updatedUsers.push(user);
|
|
51
|
+
}
|
|
52
|
+
return updatedUsers;
|
|
53
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { InferSchema, Selectable, Insertable, Updateable } from "../../shared/internal";
|
|
2
|
+
import type { DB } from "../generated/kysely-tailordb";
|
|
3
|
+
|
|
4
|
+
export type Schema = InferSchema<DB>;
|
|
5
|
+
|
|
6
|
+
export type User<T extends { User: object }> = Selectable<T["User"]>;
|
|
7
|
+
export type UserCreate<T extends { User: object }> = Insertable<T["User"]>;
|
|
8
|
+
export type UserUpdate<T extends { User: object }> = Updateable<T["User"]>;
|
|
9
|
+
|
|
10
|
+
export type Permission<T extends { Permission: object }> = Selectable<T["Permission"]>;
|
|
11
|
+
export type PermissionCreate<T extends { Permission: object }> = Insertable<T["Permission"]>;
|
|
12
|
+
export type PermissionUpdate<T extends { Permission: object }> = Updateable<T["Permission"]>;
|
|
13
|
+
|
|
14
|
+
export type Role<T extends { Role: object }> = Selectable<T["Role"]>;
|
|
15
|
+
export type RoleCreate<T extends { Role: object }> = Insertable<T["Role"]>;
|
|
16
|
+
export type RoleUpdate<T extends { Role: object }> = Updateable<T["Role"]>;
|
|
17
|
+
|
|
18
|
+
export type UserRole<T extends { UserRole: object }> = Selectable<T["UserRole"]>;
|
|
19
|
+
export type UserRoleCreate<T extends { UserRole: object }> = Insertable<T["UserRole"]>;
|
|
20
|
+
export type UserRoleUpdate<T extends { UserRole: object }> = Updateable<T["UserRole"]>;
|
|
21
|
+
|
|
22
|
+
export type RolePermission<T extends { RolePermission: object }> = Selectable<T["RolePermission"]>;
|
|
23
|
+
export type RolePermissionCreate<T extends { RolePermission: object }> = Insertable<
|
|
24
|
+
T["RolePermission"]
|
|
25
|
+
>;
|
|
26
|
+
export type RolePermissionUpdate<T extends { RolePermission: object }> = Updateable<
|
|
27
|
+
T["RolePermission"]
|
|
28
|
+
>;
|
|
29
|
+
|
|
30
|
+
export type AuditEvent<T extends { AuditEvent: object }> = Selectable<T["AuditEvent"]>;
|
|
31
|
+
export type AuditEventCreate<T extends { AuditEvent: object }> = Insertable<T["AuditEvent"]>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type TailorAnyDBField } from "@tailor-platform/sdk";
|
|
2
|
+
import { type EmptyFields, type FieldsToInsertable } from "../shared/internal";
|
|
3
|
+
import { makeCreateUser } from "./command/createUser";
|
|
4
|
+
import { makeCreateRole } from "./command/createRole";
|
|
5
|
+
import { makeCreatePermission } from "./command/createPermission";
|
|
6
|
+
import { activateUser } from "./command/activateUser";
|
|
7
|
+
import { deactivateUser } from "./command/deactivateUser";
|
|
8
|
+
import { reactivateUser } from "./command/reactivateUser";
|
|
9
|
+
import { assignPermissionToRole } from "./command/assignPermissionToRole";
|
|
10
|
+
import { revokePermissionFromRole } from "./command/revokePermissionFromRole";
|
|
11
|
+
import { assignRoleToUser } from "./command/assignRoleToUser";
|
|
12
|
+
import { revokeRoleFromUser } from "./command/revokeRoleFromUser";
|
|
13
|
+
import { logAuditEvent } from "./command/logAuditEvent";
|
|
14
|
+
import { createAuditEventType, CreateAuditEventTypeParams } from "./db/auditEvent";
|
|
15
|
+
import { createPermissionType, CreatePermissionTypeParams } from "./db/permission";
|
|
16
|
+
import { createRoleType, CreateRoleTypeParams } from "./db/role";
|
|
17
|
+
import { createRolePermissionType, CreateRolePermissionTypeParams } from "./db/rolePermission";
|
|
18
|
+
import { createUserType, CreateUserTypeParams } from "./db/user";
|
|
19
|
+
import { createUserRoleType, CreateUserRoleTypeParams } from "./db/userRole";
|
|
20
|
+
import {
|
|
21
|
+
recomputeOnRolePermissionCreated,
|
|
22
|
+
recomputeOnRolePermissionDeleted,
|
|
23
|
+
} from "./executor/recomputeOnRolePermissionChange";
|
|
24
|
+
|
|
25
|
+
export interface DefineModuleParams<
|
|
26
|
+
UF extends Record<string, TailorAnyDBField>,
|
|
27
|
+
RF extends Record<string, TailorAnyDBField>,
|
|
28
|
+
PF extends Record<string, TailorAnyDBField>,
|
|
29
|
+
> {
|
|
30
|
+
dbNamespace: string;
|
|
31
|
+
user?: CreateUserTypeParams<UF>;
|
|
32
|
+
permission?: CreatePermissionTypeParams<PF>;
|
|
33
|
+
role?: CreateRoleTypeParams<RF>;
|
|
34
|
+
userRole?: CreateUserRoleTypeParams;
|
|
35
|
+
rolePermission?: CreateRolePermissionTypeParams;
|
|
36
|
+
auditEvent?: CreateAuditEventTypeParams;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const defineModule = <
|
|
40
|
+
const UF extends Record<string, TailorAnyDBField> = EmptyFields,
|
|
41
|
+
const RF extends Record<string, TailorAnyDBField> = EmptyFields,
|
|
42
|
+
const PF extends Record<string, TailorAnyDBField> = EmptyFields,
|
|
43
|
+
>(
|
|
44
|
+
params: DefineModuleParams<UF, RF, PF>,
|
|
45
|
+
) => {
|
|
46
|
+
const user = createUserType(params.user ?? {});
|
|
47
|
+
const permission = createPermissionType(params.permission ?? {});
|
|
48
|
+
const role = createRoleType(params.role ?? {});
|
|
49
|
+
const userRole = createUserRoleType(params.userRole ?? {});
|
|
50
|
+
const rolePermission = createRolePermissionType(params.rolePermission ?? {});
|
|
51
|
+
const auditEvent = createAuditEventType(params.auditEvent ?? {});
|
|
52
|
+
|
|
53
|
+
const rolePermissionCreated = recomputeOnRolePermissionCreated({
|
|
54
|
+
namespace: params.dbNamespace,
|
|
55
|
+
});
|
|
56
|
+
const rolePermissionDeleted = recomputeOnRolePermissionDeleted({
|
|
57
|
+
namespace: params.dbNamespace,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
db: { user, permission, role, userRole, rolePermission, auditEvent },
|
|
62
|
+
executors: { rolePermissionCreated, rolePermissionDeleted },
|
|
63
|
+
commands: {
|
|
64
|
+
createUser: makeCreateUser<FieldsToInsertable<UF>>(),
|
|
65
|
+
createRole: makeCreateRole<FieldsToInsertable<RF>>(),
|
|
66
|
+
createPermission: makeCreatePermission<FieldsToInsertable<PF>>(),
|
|
67
|
+
activateUser,
|
|
68
|
+
deactivateUser,
|
|
69
|
+
reactivateUser,
|
|
70
|
+
assignPermissionToRole,
|
|
71
|
+
revokePermissionFromRole,
|
|
72
|
+
assignRoleToUser,
|
|
73
|
+
revokeRoleFromUser,
|
|
74
|
+
logAuditEvent,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { definePermissions } from "../shared/internal";
|
|
2
|
+
|
|
3
|
+
export const { permissions, own, all } = definePermissions("user-management", [
|
|
4
|
+
"createUser",
|
|
5
|
+
"activateUser",
|
|
6
|
+
"deactivateUser",
|
|
7
|
+
"reactivateUser",
|
|
8
|
+
"createPermission",
|
|
9
|
+
"createRole",
|
|
10
|
+
"assignPermissionToRole",
|
|
11
|
+
"revokePermissionFromRole",
|
|
12
|
+
"assignRoleToUser",
|
|
13
|
+
"revokeRoleFromUser",
|
|
14
|
+
"logAuditEvent",
|
|
15
|
+
] as const);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { defineConfig, defineGenerators } from "@tailor-platform/sdk";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
name: "user-management",
|
|
5
|
+
db: { "main-db": { files: [`./src/db/*.ts`] } },
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const generators = defineGenerators(
|
|
9
|
+
["@tailor-platform/kysely-type", { distPath: `./src/generated/kysely-tailordb.ts` }],
|
|
10
|
+
["@tailor-platform/enum-constants", { distPath: "./src/generated/enums.ts" }],
|
|
11
|
+
);
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AuditEvent,
|
|
3
|
+
Permission,
|
|
4
|
+
Role,
|
|
5
|
+
RolePermission,
|
|
6
|
+
Schema,
|
|
7
|
+
User,
|
|
8
|
+
UserRole,
|
|
9
|
+
} from "../lib/types";
|
|
10
|
+
|
|
11
|
+
export const pendingUser = {
|
|
12
|
+
id: "user-pending-1",
|
|
13
|
+
email: "pending@example.com",
|
|
14
|
+
name: "Pending User",
|
|
15
|
+
status: "PENDING",
|
|
16
|
+
permissions: null,
|
|
17
|
+
createdAt: new Date("2024-01-01T00:00:00.000Z"),
|
|
18
|
+
updatedAt: null,
|
|
19
|
+
} as const satisfies User<Schema>;
|
|
20
|
+
|
|
21
|
+
export const activeUser = {
|
|
22
|
+
id: "user-active-1",
|
|
23
|
+
email: "active@example.com",
|
|
24
|
+
name: "Active User",
|
|
25
|
+
status: "ACTIVE",
|
|
26
|
+
permissions: null,
|
|
27
|
+
createdAt: new Date("2024-01-01T00:00:00.000Z"),
|
|
28
|
+
updatedAt: new Date("2024-01-02T00:00:00.000Z"),
|
|
29
|
+
} as const satisfies User<Schema>;
|
|
30
|
+
|
|
31
|
+
export const inactiveUser = {
|
|
32
|
+
id: "user-inactive-1",
|
|
33
|
+
email: "inactive@example.com",
|
|
34
|
+
name: "Inactive User",
|
|
35
|
+
status: "INACTIVE",
|
|
36
|
+
permissions: null,
|
|
37
|
+
createdAt: new Date("2024-01-01T00:00:00.000Z"),
|
|
38
|
+
updatedAt: new Date("2024-01-03T00:00:00.000Z"),
|
|
39
|
+
} as const satisfies User<Schema>;
|
|
40
|
+
|
|
41
|
+
export const basePermission = {
|
|
42
|
+
id: "permission-1",
|
|
43
|
+
key: "orders:read",
|
|
44
|
+
description: "Permission to read orders",
|
|
45
|
+
createdAt: new Date("2024-01-01T00:00:00.000Z"),
|
|
46
|
+
updatedAt: null,
|
|
47
|
+
} as const satisfies Permission<Schema>;
|
|
48
|
+
|
|
49
|
+
export const writePermission = {
|
|
50
|
+
id: "permission-2",
|
|
51
|
+
key: "orders:write",
|
|
52
|
+
description: "Permission to write orders",
|
|
53
|
+
createdAt: new Date("2024-01-01T00:00:00.000Z"),
|
|
54
|
+
updatedAt: null,
|
|
55
|
+
} as const satisfies Permission<Schema>;
|
|
56
|
+
|
|
57
|
+
export const baseRole = {
|
|
58
|
+
id: "role-1",
|
|
59
|
+
name: "Order Manager",
|
|
60
|
+
description: "Role for managing orders",
|
|
61
|
+
createdAt: new Date("2024-01-01T00:00:00.000Z"),
|
|
62
|
+
updatedAt: null,
|
|
63
|
+
} as const satisfies Role<Schema>;
|
|
64
|
+
|
|
65
|
+
export const adminRole = {
|
|
66
|
+
id: "role-2",
|
|
67
|
+
name: "Admin",
|
|
68
|
+
description: "Administrator role",
|
|
69
|
+
createdAt: new Date("2024-01-01T00:00:00.000Z"),
|
|
70
|
+
updatedAt: null,
|
|
71
|
+
} as const satisfies Role<Schema>;
|
|
72
|
+
|
|
73
|
+
export const baseUserRole = {
|
|
74
|
+
id: "user-role-1",
|
|
75
|
+
userId: "user-active-1",
|
|
76
|
+
roleId: "role-1",
|
|
77
|
+
createdAt: new Date("2024-01-01T00:00:00.000Z"),
|
|
78
|
+
updatedAt: null,
|
|
79
|
+
} as const satisfies UserRole<Schema>;
|
|
80
|
+
|
|
81
|
+
export const baseRolePermission = {
|
|
82
|
+
id: "role-permission-1",
|
|
83
|
+
roleId: "role-1",
|
|
84
|
+
permissionId: "permission-1",
|
|
85
|
+
createdAt: new Date("2024-01-01T00:00:00.000Z"),
|
|
86
|
+
updatedAt: null,
|
|
87
|
+
} as const satisfies RolePermission<Schema>;
|
|
88
|
+
|
|
89
|
+
export const baseAuditEvent = {
|
|
90
|
+
id: "audit-event-1",
|
|
91
|
+
eventType: "USER_CREATED",
|
|
92
|
+
actorId: "user-active-1",
|
|
93
|
+
targetId: "user-pending-1",
|
|
94
|
+
targetType: "User",
|
|
95
|
+
payload: JSON.stringify({ email: "pending@example.com" }),
|
|
96
|
+
createdAt: new Date("2024-01-01T00:00:00.000Z"),
|
|
97
|
+
updatedAt: null,
|
|
98
|
+
} as const satisfies AuditEvent<Schema>;
|
package/src/schemas.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { PACKAGE_ROOT } from "./util.js";
|
|
3
|
+
|
|
4
|
+
const SCHEMAS_ROOT = path.join(PACKAGE_ROOT, "schemas");
|
|
5
|
+
|
|
6
|
+
export const MODULE_SCHEMAS = {
|
|
7
|
+
module: path.join(SCHEMAS_ROOT, "module", "module.yml"),
|
|
8
|
+
command: path.join(SCHEMAS_ROOT, "module", "command.yml"),
|
|
9
|
+
model: path.join(SCHEMAS_ROOT, "module", "model.yml"),
|
|
10
|
+
feature: path.join(SCHEMAS_ROOT, "module", "feature.yml"),
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
export const APP_COMPOSE_SCHEMAS = {
|
|
14
|
+
requirements: path.join(SCHEMAS_ROOT, "app-compose", "requirements.yml"),
|
|
15
|
+
actors: path.join(SCHEMAS_ROOT, "app-compose", "actors.yml"),
|
|
16
|
+
"business-flow": path.join(SCHEMAS_ROOT, "app-compose", "business-flow.yml"),
|
|
17
|
+
story: path.join(SCHEMAS_ROOT, "app-compose", "story.yml"),
|
|
18
|
+
screen: path.join(SCHEMAS_ROOT, "app-compose", "screen.yml"),
|
|
19
|
+
resolver: path.join(SCHEMAS_ROOT, "app-compose", "resolver.yml"),
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
export const ALL_SCHEMAS: Record<string, string> = {
|
|
23
|
+
...MODULE_SCHEMAS,
|
|
24
|
+
...APP_COMPOSE_SCHEMAS,
|
|
25
|
+
};
|
package/src/testing.ts
ADDED
package/src/util.ts
ADDED