business-as-code 2.1.3 → 2.3.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.
- package/CHANGELOG.md +10 -0
- package/README.md +2 -0
- package/package.json +16 -13
- package/src/dollar.ts +5 -2
- package/src/entities/organization.ts +31 -18
- package/src/goals.ts +78 -12
- package/src/index.ts +48 -18
- package/src/kpis.ts +62 -8
- package/src/metrics.ts +92 -79
- package/src/okrs.ts +120 -20
- package/src/organization.ts +12 -15
- package/src/process.ts +11 -12
- package/src/product.ts +8 -9
- package/src/queries.ts +238 -75
- package/src/roles.ts +62 -61
- package/src/workflow.ts +22 -15
- package/test/business.test.ts +282 -0
- package/test/dollar.test.ts +270 -0
- package/test/entities.test.ts +628 -0
- package/test/financials.test.ts +539 -0
- package/test/goals.test.ts +451 -0
- package/{src → test}/index.test.ts +1 -1
- package/test/kpis.test.ts +440 -0
- package/test/metrics.test.ts +744 -0
- package/test/okrs.test.ts +741 -0
- package/test/organization.test.ts +548 -0
- package/test/process.test.ts +503 -0
- package/test/product.test.ts +430 -0
- package/test/queries.test.ts +556 -0
- package/test/roles.test.ts +546 -0
- package/test/service.test.ts +450 -0
- package/test/types.test.ts +1141 -0
- package/test/vision.test.ts +214 -0
- package/test/workflow.test.ts +501 -0
- package/vitest.config.ts +47 -0
- package/.turbo/turbo-build.log +0 -5
- package/LICENSE +0 -21
- package/dist/business.d.ts +0 -62
- package/dist/business.d.ts.map +0 -1
- package/dist/business.js +0 -109
- package/dist/business.js.map +0 -1
- package/dist/canvas/activities.d.ts +0 -19
- package/dist/canvas/activities.d.ts.map +0 -1
- package/dist/canvas/activities.js +0 -20
- package/dist/canvas/activities.js.map +0 -1
- package/dist/canvas/channels.d.ts +0 -20
- package/dist/canvas/channels.d.ts.map +0 -1
- package/dist/canvas/channels.js +0 -21
- package/dist/canvas/channels.js.map +0 -1
- package/dist/canvas/relationships.d.ts +0 -20
- package/dist/canvas/relationships.d.ts.map +0 -1
- package/dist/canvas/relationships.js +0 -21
- package/dist/canvas/relationships.js.map +0 -1
- package/dist/canvas/resources.d.ts +0 -20
- package/dist/canvas/resources.d.ts.map +0 -1
- package/dist/canvas/resources.js +0 -30
- package/dist/canvas/resources.js.map +0 -1
- package/dist/canvas/revenue.d.ts +0 -22
- package/dist/canvas/revenue.d.ts.map +0 -1
- package/dist/canvas/revenue.js +0 -30
- package/dist/canvas/revenue.js.map +0 -1
- package/dist/canvas/segments.d.ts +0 -20
- package/dist/canvas/segments.d.ts.map +0 -1
- package/dist/canvas/segments.js +0 -28
- package/dist/canvas/segments.js.map +0 -1
- package/dist/canvas/types.d.ts +0 -232
- package/dist/canvas/types.d.ts.map +0 -1
- package/dist/canvas/types.js +0 -8
- package/dist/canvas/types.js.map +0 -1
- package/dist/canvas/value.d.ts +0 -20
- package/dist/canvas/value.d.ts.map +0 -1
- package/dist/canvas/value.js +0 -21
- package/dist/canvas/value.js.map +0 -1
- package/dist/dollar.d.ts +0 -60
- package/dist/dollar.d.ts.map +0 -1
- package/dist/dollar.js +0 -107
- package/dist/dollar.js.map +0 -1
- package/dist/entities/assets.d.ts +0 -21
- package/dist/entities/assets.d.ts.map +0 -1
- package/dist/entities/assets.js +0 -323
- package/dist/entities/assets.js.map +0 -1
- package/dist/entities/business.d.ts +0 -36
- package/dist/entities/business.d.ts.map +0 -1
- package/dist/entities/business.js +0 -370
- package/dist/entities/business.js.map +0 -1
- package/dist/entities/communication.d.ts +0 -21
- package/dist/entities/communication.d.ts.map +0 -1
- package/dist/entities/communication.js +0 -255
- package/dist/entities/communication.js.map +0 -1
- package/dist/entities/customers.d.ts +0 -58
- package/dist/entities/customers.d.ts.map +0 -1
- package/dist/entities/customers.js +0 -989
- package/dist/entities/customers.js.map +0 -1
- package/dist/entities/financials.d.ts +0 -59
- package/dist/entities/financials.d.ts.map +0 -1
- package/dist/entities/financials.js +0 -932
- package/dist/entities/financials.js.map +0 -1
- package/dist/entities/goals.d.ts +0 -58
- package/dist/entities/goals.d.ts.map +0 -1
- package/dist/entities/goals.js +0 -800
- package/dist/entities/goals.js.map +0 -1
- package/dist/entities/index.d.ts +0 -299
- package/dist/entities/index.d.ts.map +0 -1
- package/dist/entities/index.js +0 -198
- package/dist/entities/index.js.map +0 -1
- package/dist/entities/legal.d.ts +0 -21
- package/dist/entities/legal.d.ts.map +0 -1
- package/dist/entities/legal.js +0 -301
- package/dist/entities/legal.js.map +0 -1
- package/dist/entities/market.d.ts +0 -21
- package/dist/entities/market.d.ts.map +0 -1
- package/dist/entities/market.js +0 -301
- package/dist/entities/market.js.map +0 -1
- package/dist/entities/marketing.d.ts +0 -67
- package/dist/entities/marketing.d.ts.map +0 -1
- package/dist/entities/marketing.js +0 -1157
- package/dist/entities/marketing.js.map +0 -1
- package/dist/entities/offerings.d.ts +0 -51
- package/dist/entities/offerings.d.ts.map +0 -1
- package/dist/entities/offerings.js +0 -727
- package/dist/entities/offerings.js.map +0 -1
- package/dist/entities/operations.d.ts +0 -58
- package/dist/entities/operations.d.ts.map +0 -1
- package/dist/entities/operations.js +0 -787
- package/dist/entities/operations.js.map +0 -1
- package/dist/entities/organization.d.ts +0 -57
- package/dist/entities/organization.d.ts.map +0 -1
- package/dist/entities/organization.js +0 -807
- package/dist/entities/organization.js.map +0 -1
- package/dist/entities/partnerships.d.ts +0 -21
- package/dist/entities/partnerships.d.ts.map +0 -1
- package/dist/entities/partnerships.js +0 -300
- package/dist/entities/partnerships.js.map +0 -1
- package/dist/entities/planning.d.ts +0 -0
- package/dist/entities/planning.d.ts.map +0 -1
- package/dist/entities/planning.js +0 -271
- package/dist/entities/planning.js.map +0 -1
- package/dist/entities/projects.d.ts +0 -25
- package/dist/entities/projects.d.ts.map +0 -1
- package/dist/entities/projects.js +0 -349
- package/dist/entities/projects.js.map +0 -1
- package/dist/entities/risk.d.ts +0 -21
- package/dist/entities/risk.d.ts.map +0 -1
- package/dist/entities/risk.js +0 -293
- package/dist/entities/risk.js.map +0 -1
- package/dist/entities/sales.d.ts +0 -72
- package/dist/entities/sales.d.ts.map +0 -1
- package/dist/entities/sales.js +0 -1248
- package/dist/entities/sales.js.map +0 -1
- package/dist/financials.d.ts +0 -130
- package/dist/financials.d.ts.map +0 -1
- package/dist/financials.js +0 -297
- package/dist/financials.js.map +0 -1
- package/dist/goals.d.ts +0 -87
- package/dist/goals.d.ts.map +0 -1
- package/dist/goals.js +0 -215
- package/dist/goals.js.map +0 -1
- package/dist/index.d.ts +0 -97
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -132
- package/dist/index.js.map +0 -1
- package/dist/kpis.d.ts +0 -118
- package/dist/kpis.d.ts.map +0 -1
- package/dist/kpis.js +0 -232
- package/dist/kpis.js.map +0 -1
- package/dist/metrics.d.ts +0 -448
- package/dist/metrics.d.ts.map +0 -1
- package/dist/metrics.js +0 -325
- package/dist/metrics.js.map +0 -1
- package/dist/okrs.d.ts +0 -123
- package/dist/okrs.d.ts.map +0 -1
- package/dist/okrs.js +0 -269
- package/dist/okrs.js.map +0 -1
- package/dist/organization.d.ts +0 -585
- package/dist/organization.d.ts.map +0 -1
- package/dist/organization.js +0 -173
- package/dist/organization.js.map +0 -1
- package/dist/process.d.ts +0 -112
- package/dist/process.d.ts.map +0 -1
- package/dist/process.js +0 -241
- package/dist/process.js.map +0 -1
- package/dist/product.d.ts +0 -85
- package/dist/product.d.ts.map +0 -1
- package/dist/product.js +0 -145
- package/dist/product.js.map +0 -1
- package/dist/queries.d.ts +0 -304
- package/dist/queries.d.ts.map +0 -1
- package/dist/queries.js +0 -415
- package/dist/queries.js.map +0 -1
- package/dist/roles.d.ts +0 -340
- package/dist/roles.d.ts.map +0 -1
- package/dist/roles.js +0 -255
- package/dist/roles.js.map +0 -1
- package/dist/service.d.ts +0 -61
- package/dist/service.d.ts.map +0 -1
- package/dist/service.js +0 -140
- package/dist/service.js.map +0 -1
- package/dist/types.d.ts +0 -459
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -5
- package/dist/types.js.map +0 -1
- package/dist/vision.d.ts +0 -38
- package/dist/vision.d.ts.map +0 -1
- package/dist/vision.js +0 -68
- package/dist/vision.js.map +0 -1
- package/dist/workflow.d.ts +0 -115
- package/dist/workflow.d.ts.map +0 -1
- package/dist/workflow.js +0 -247
- package/dist/workflow.js.map +0 -1
- package/src/business.js +0 -108
- package/src/canvas/activities.ts +0 -32
- package/src/canvas/canvas.ts +0 -482
- package/src/canvas/channels.ts +0 -34
- package/src/canvas/costs.ts +0 -43
- package/src/canvas/economics.ts +0 -99
- package/src/canvas/index.ts +0 -206
- package/src/canvas/partnerships.ts +0 -34
- package/src/canvas/projections.ts +0 -141
- package/src/canvas/relationships.ts +0 -34
- package/src/canvas/resources.ts +0 -43
- package/src/canvas/revenue.ts +0 -56
- package/src/canvas/segments.ts +0 -42
- package/src/canvas/types.ts +0 -363
- package/src/canvas/value.ts +0 -34
- package/src/dollar.js +0 -106
- package/src/entities/assets.js +0 -322
- package/src/entities/business.js +0 -369
- package/src/entities/communication.js +0 -254
- package/src/entities/customers.js +0 -988
- package/src/entities/financials.js +0 -931
- package/src/entities/goals.js +0 -799
- package/src/entities/index.js +0 -197
- package/src/entities/legal.js +0 -300
- package/src/entities/market.js +0 -300
- package/src/entities/marketing.js +0 -1156
- package/src/entities/offerings.js +0 -726
- package/src/entities/operations.js +0 -786
- package/src/entities/organization.js +0 -806
- package/src/entities/partnerships.js +0 -299
- package/src/entities/planning.js +0 -270
- package/src/entities/projects.js +0 -348
- package/src/entities/risk.js +0 -292
- package/src/entities/sales.js +0 -1247
- package/src/financials.js +0 -296
- package/src/goals.js +0 -214
- package/src/index.js +0 -131
- package/src/index.test.js +0 -274
- package/src/kpis.js +0 -231
- package/src/metrics.js +0 -324
- package/src/okrs.js +0 -268
- package/src/organization.js +0 -172
- package/src/process.js +0 -240
- package/src/product.js +0 -144
- package/src/queries.js +0 -414
- package/src/roles.js +0 -254
- package/src/service.js +0 -139
- package/src/types.js +0 -4
- package/src/vision.js +0 -67
- package/src/workflow.js +0 -246
- package/tests/canvas.test.ts +0 -842
package/src/organization.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Organization Structure - Flows to FGA/RBAC
|
|
3
|
-
*
|
|
4
|
-
* Defines the complete organizational hierarchy:
|
|
5
|
-
*
|
|
6
|
-
* Organization
|
|
7
|
-
* └── Department
|
|
8
|
-
* └── Team
|
|
9
|
-
* └── Position (Role + Worker)
|
|
10
|
-
* └── Permissions (FGA/RBAC)
|
|
11
|
-
*
|
|
12
|
-
* This structure enables:
|
|
13
|
-
* - Hierarchical permission inheritance
|
|
14
|
-
* - Role-based task assignment
|
|
15
|
-
* - Approval chains based on org structure
|
|
16
|
-
* - Resource access control based on department/team
|
|
17
|
-
*
|
|
18
|
-
* @packageDocumentation
|
|
19
|
-
*/
|
|
20
|
-
/**
|
|
21
|
-
* Resolve permissions for a position in the org hierarchy
|
|
22
|
-
*/
|
|
23
|
-
export function resolvePermissions(org, positionId) {
|
|
24
|
-
// Find the position
|
|
25
|
-
let position;
|
|
26
|
-
let team;
|
|
27
|
-
let department;
|
|
28
|
-
// Search through hierarchy
|
|
29
|
-
for (const dept of org.departments || []) {
|
|
30
|
-
for (const t of dept.teams || []) {
|
|
31
|
-
const pos = t.positions?.find(p => p.id === positionId);
|
|
32
|
-
if (pos) {
|
|
33
|
-
position = pos;
|
|
34
|
-
team = t;
|
|
35
|
-
department = dept;
|
|
36
|
-
break;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (position)
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
// Also check standalone teams
|
|
43
|
-
if (!position) {
|
|
44
|
-
for (const t of org.teams || []) {
|
|
45
|
-
const pos = t.positions?.find(p => p.id === positionId);
|
|
46
|
-
if (pos) {
|
|
47
|
-
position = pos;
|
|
48
|
-
team = t;
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (!position)
|
|
54
|
-
return null;
|
|
55
|
-
// Find the role
|
|
56
|
-
const role = org.roles?.find(r => r.id === position.roleId);
|
|
57
|
-
// Build inheritance chain
|
|
58
|
-
const inheritanceChain = [];
|
|
59
|
-
const permissions = {};
|
|
60
|
-
const resourcePermissions = {};
|
|
61
|
-
const canApprove = [];
|
|
62
|
-
const canHandle = [];
|
|
63
|
-
// 1. Department defaults
|
|
64
|
-
if (department?.defaultPermissions) {
|
|
65
|
-
inheritanceChain.push(`department:${department.id}`);
|
|
66
|
-
mergePermissions(permissions, department.defaultPermissions);
|
|
67
|
-
}
|
|
68
|
-
// 2. Team defaults
|
|
69
|
-
if (team?.defaultPermissions) {
|
|
70
|
-
inheritanceChain.push(`team:${team.id}`);
|
|
71
|
-
mergePermissions(permissions, team.defaultPermissions);
|
|
72
|
-
}
|
|
73
|
-
// 3. Team resources (scoped permissions)
|
|
74
|
-
if (team?.resources) {
|
|
75
|
-
for (const [resourceType, resourceIds] of Object.entries(team.resources)) {
|
|
76
|
-
if (resourceIds) {
|
|
77
|
-
for (const resourceId of resourceIds) {
|
|
78
|
-
const key = `${resourceType}:${resourceId}`;
|
|
79
|
-
resourcePermissions[key] = resourcePermissions[key] || {};
|
|
80
|
-
mergePermissions(resourcePermissions[key], team.defaultPermissions || {});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
// 4. Role permissions
|
|
86
|
-
if (role?.permissions) {
|
|
87
|
-
inheritanceChain.push(`role:${role.id}`);
|
|
88
|
-
mergePermissions(permissions, role.permissions);
|
|
89
|
-
}
|
|
90
|
-
// 5. Role capabilities
|
|
91
|
-
if (role?.canApprove) {
|
|
92
|
-
canApprove.push(...role.canApprove);
|
|
93
|
-
}
|
|
94
|
-
if (role?.canHandle) {
|
|
95
|
-
canHandle.push(...role.canHandle);
|
|
96
|
-
}
|
|
97
|
-
// 6. Position-specific permissions
|
|
98
|
-
if (position.additionalPermissions) {
|
|
99
|
-
inheritanceChain.push(`position:${position.id}`);
|
|
100
|
-
mergePermissions(permissions, position.additionalPermissions);
|
|
101
|
-
// Handle resource-specific permissions
|
|
102
|
-
for (const [key, perms] of Object.entries(position.additionalPermissions)) {
|
|
103
|
-
if (key.includes(':')) {
|
|
104
|
-
resourcePermissions[key] = resourcePermissions[key] || {};
|
|
105
|
-
resourcePermissions[key] = { ...resourcePermissions[key], _direct: perms };
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return {
|
|
110
|
-
workerId: position.workerId || '',
|
|
111
|
-
positionId: position.id,
|
|
112
|
-
permissions,
|
|
113
|
-
resourcePermissions,
|
|
114
|
-
canApprove: [...new Set(canApprove)],
|
|
115
|
-
canHandle: [...new Set(canHandle)],
|
|
116
|
-
inheritanceChain,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Merge permissions into target
|
|
121
|
-
*/
|
|
122
|
-
function mergePermissions(target, source) {
|
|
123
|
-
for (const [key, perms] of Object.entries(source)) {
|
|
124
|
-
if (!target[key]) {
|
|
125
|
-
target[key] = [];
|
|
126
|
-
}
|
|
127
|
-
for (const perm of perms) {
|
|
128
|
-
if (!target[key].includes(perm)) {
|
|
129
|
-
target[key].push(perm);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Get approval chain for a request
|
|
136
|
-
*/
|
|
137
|
-
export function getApprovalChainForRequest(org, requestType, amount) {
|
|
138
|
-
const chain = org.approvalChains?.find(c => c.type === requestType && c.active !== false);
|
|
139
|
-
if (!chain)
|
|
140
|
-
return [];
|
|
141
|
-
// Find the appropriate level based on amount
|
|
142
|
-
const levels = [...chain.levels].sort((a, b) => (a.threshold || 0) - (b.threshold || 0));
|
|
143
|
-
for (const level of levels.reverse()) {
|
|
144
|
-
if (amount === undefined || (level.threshold && amount <= level.threshold)) {
|
|
145
|
-
return level.approvers;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
// Return highest level if amount exceeds all thresholds
|
|
149
|
-
return levels[levels.length - 1]?.approvers || [];
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Find manager for a position (follows reportsTo chain)
|
|
153
|
-
*/
|
|
154
|
-
export function findManager(org, positionId) {
|
|
155
|
-
// Find the position
|
|
156
|
-
for (const dept of org.departments || []) {
|
|
157
|
-
for (const team of dept.teams || []) {
|
|
158
|
-
const position = team.positions?.find(p => p.id === positionId);
|
|
159
|
-
if (position?.reportsTo) {
|
|
160
|
-
// Find the manager position
|
|
161
|
-
for (const d of org.departments || []) {
|
|
162
|
-
for (const t of d.teams || []) {
|
|
163
|
-
const manager = t.positions?.find(p => p.id === position.reportsTo);
|
|
164
|
-
if (manager)
|
|
165
|
-
return manager;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return null;
|
|
172
|
-
}
|
package/src/process.js
DELETED
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Business process definition and management
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Define a business process with steps, inputs, outputs, and metrics
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```ts
|
|
9
|
-
* const process = Process({
|
|
10
|
-
* name: 'Customer Onboarding',
|
|
11
|
-
* description: 'Process for onboarding new customers',
|
|
12
|
-
* category: 'core',
|
|
13
|
-
* owner: 'Customer Success Team',
|
|
14
|
-
* steps: [
|
|
15
|
-
* {
|
|
16
|
-
* order: 1,
|
|
17
|
-
* name: 'Welcome Email',
|
|
18
|
-
* description: 'Send personalized welcome email',
|
|
19
|
-
* responsible: 'CS Manager',
|
|
20
|
-
* duration: '5 minutes',
|
|
21
|
-
* automationLevel: 'automated',
|
|
22
|
-
* },
|
|
23
|
-
* {
|
|
24
|
-
* order: 2,
|
|
25
|
-
* name: 'Initial Setup Call',
|
|
26
|
-
* description: 'Schedule and conduct setup call',
|
|
27
|
-
* responsible: 'CS Rep',
|
|
28
|
-
* duration: '30 minutes',
|
|
29
|
-
* automationLevel: 'manual',
|
|
30
|
-
* },
|
|
31
|
-
* {
|
|
32
|
-
* order: 3,
|
|
33
|
-
* name: 'Account Configuration',
|
|
34
|
-
* description: 'Configure customer account settings',
|
|
35
|
-
* responsible: 'CS Rep',
|
|
36
|
-
* duration: '15 minutes',
|
|
37
|
-
* automationLevel: 'semi-automated',
|
|
38
|
-
* },
|
|
39
|
-
* ],
|
|
40
|
-
* inputs: ['Customer Information', 'Subscription Plan'],
|
|
41
|
-
* outputs: ['Configured Account', 'Training Materials'],
|
|
42
|
-
* metrics: [
|
|
43
|
-
* {
|
|
44
|
-
* name: 'Time to First Value',
|
|
45
|
-
* description: 'Time from signup to first successful use',
|
|
46
|
-
* target: 24,
|
|
47
|
-
* unit: 'hours',
|
|
48
|
-
* },
|
|
49
|
-
* {
|
|
50
|
-
* name: 'Onboarding Completion Rate',
|
|
51
|
-
* description: 'Percentage of customers completing onboarding',
|
|
52
|
-
* target: 90,
|
|
53
|
-
* unit: 'percent',
|
|
54
|
-
* },
|
|
55
|
-
* ],
|
|
56
|
-
* })
|
|
57
|
-
* ```
|
|
58
|
-
*/
|
|
59
|
-
export function Process(definition) {
|
|
60
|
-
if (!definition.name) {
|
|
61
|
-
throw new Error('Process name is required');
|
|
62
|
-
}
|
|
63
|
-
return {
|
|
64
|
-
...definition,
|
|
65
|
-
category: definition.category || 'support',
|
|
66
|
-
steps: definition.steps || [],
|
|
67
|
-
inputs: definition.inputs || [],
|
|
68
|
-
outputs: definition.outputs || [],
|
|
69
|
-
metrics: definition.metrics || [],
|
|
70
|
-
metadata: definition.metadata || {},
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Get process steps in order
|
|
75
|
-
*/
|
|
76
|
-
export function getStepsInOrder(process) {
|
|
77
|
-
return [...(process.steps || [])].sort((a, b) => a.order - b.order);
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Get steps by automation level
|
|
81
|
-
*/
|
|
82
|
-
export function getStepsByAutomationLevel(process, level) {
|
|
83
|
-
return process.steps?.filter(step => step.automationLevel === level) || [];
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Calculate total process duration in minutes
|
|
87
|
-
*/
|
|
88
|
-
export function calculateTotalDuration(process) {
|
|
89
|
-
return (process.steps?.reduce((total, step) => {
|
|
90
|
-
return total + parseDurationToMinutes(step.duration);
|
|
91
|
-
}, 0) || 0);
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Parse duration string to minutes
|
|
95
|
-
*/
|
|
96
|
-
function parseDurationToMinutes(duration) {
|
|
97
|
-
if (!duration)
|
|
98
|
-
return 0;
|
|
99
|
-
const lower = duration.toLowerCase();
|
|
100
|
-
const match = lower.match(/(\d+)\s*(minute|minutes|min|hour|hours|hr|day|days|week|weeks)/);
|
|
101
|
-
if (!match)
|
|
102
|
-
return 0;
|
|
103
|
-
const value = parseInt(match[1] || '0', 10);
|
|
104
|
-
const unit = match[2];
|
|
105
|
-
switch (unit) {
|
|
106
|
-
case 'minute':
|
|
107
|
-
case 'minutes':
|
|
108
|
-
case 'min':
|
|
109
|
-
return value;
|
|
110
|
-
case 'hour':
|
|
111
|
-
case 'hours':
|
|
112
|
-
case 'hr':
|
|
113
|
-
return value * 60;
|
|
114
|
-
case 'day':
|
|
115
|
-
case 'days':
|
|
116
|
-
return value * 60 * 24;
|
|
117
|
-
case 'week':
|
|
118
|
-
case 'weeks':
|
|
119
|
-
return value * 60 * 24 * 7;
|
|
120
|
-
default:
|
|
121
|
-
return 0;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Format minutes to human-readable duration
|
|
126
|
-
*/
|
|
127
|
-
export function formatDuration(minutes) {
|
|
128
|
-
if (minutes < 60) {
|
|
129
|
-
return `${minutes} minutes`;
|
|
130
|
-
}
|
|
131
|
-
else if (minutes < 60 * 24) {
|
|
132
|
-
const hours = Math.floor(minutes / 60);
|
|
133
|
-
const mins = minutes % 60;
|
|
134
|
-
return mins > 0 ? `${hours} hours ${mins} minutes` : `${hours} hours`;
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
const days = Math.floor(minutes / (60 * 24));
|
|
138
|
-
const hours = Math.floor((minutes % (60 * 24)) / 60);
|
|
139
|
-
return hours > 0 ? `${days} days ${hours} hours` : `${days} days`;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Calculate automation percentage
|
|
144
|
-
*/
|
|
145
|
-
export function calculateAutomationPercentage(process) {
|
|
146
|
-
if (!process.steps || process.steps.length === 0)
|
|
147
|
-
return 0;
|
|
148
|
-
const automatedSteps = process.steps.filter(step => step.automationLevel === 'automated' || step.automationLevel === 'semi-automated').length;
|
|
149
|
-
return (automatedSteps / process.steps.length) * 100;
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Get metric by name
|
|
153
|
-
*/
|
|
154
|
-
export function getMetric(process, name) {
|
|
155
|
-
return process.metrics?.find(m => m.name === name);
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Check if metric meets target
|
|
159
|
-
*/
|
|
160
|
-
export function meetsTarget(metric) {
|
|
161
|
-
if (metric.target === undefined || metric.current === undefined)
|
|
162
|
-
return false;
|
|
163
|
-
return metric.current >= metric.target;
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Calculate metric achievement percentage
|
|
167
|
-
*/
|
|
168
|
-
export function calculateMetricAchievement(metric) {
|
|
169
|
-
if (metric.target === undefined || metric.current === undefined)
|
|
170
|
-
return 0;
|
|
171
|
-
if (metric.target === 0)
|
|
172
|
-
return 100;
|
|
173
|
-
return (metric.current / metric.target) * 100;
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Update metric current value
|
|
177
|
-
*/
|
|
178
|
-
export function updateMetric(process, metricName, currentValue) {
|
|
179
|
-
const metrics = process.metrics?.map(m => m.name === metricName ? { ...m, current: currentValue } : m);
|
|
180
|
-
return {
|
|
181
|
-
...process,
|
|
182
|
-
metrics,
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Add step to process
|
|
187
|
-
*/
|
|
188
|
-
export function addStep(process, step) {
|
|
189
|
-
return {
|
|
190
|
-
...process,
|
|
191
|
-
steps: [...(process.steps || []), step],
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Remove step from process
|
|
196
|
-
*/
|
|
197
|
-
export function removeStep(process, stepOrder) {
|
|
198
|
-
return {
|
|
199
|
-
...process,
|
|
200
|
-
steps: process.steps?.filter(s => s.order !== stepOrder),
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Validate process definition
|
|
205
|
-
*/
|
|
206
|
-
export function validateProcess(process) {
|
|
207
|
-
const errors = [];
|
|
208
|
-
if (!process.name) {
|
|
209
|
-
errors.push('Process name is required');
|
|
210
|
-
}
|
|
211
|
-
if (process.steps) {
|
|
212
|
-
const orders = new Set();
|
|
213
|
-
for (const step of process.steps) {
|
|
214
|
-
if (!step.name) {
|
|
215
|
-
errors.push(`Step at order ${step.order} must have a name`);
|
|
216
|
-
}
|
|
217
|
-
if (orders.has(step.order)) {
|
|
218
|
-
errors.push(`Duplicate step order: ${step.order}`);
|
|
219
|
-
}
|
|
220
|
-
orders.add(step.order);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
if (process.metrics) {
|
|
224
|
-
for (const metric of process.metrics) {
|
|
225
|
-
if (!metric.name) {
|
|
226
|
-
errors.push('Metric must have a name');
|
|
227
|
-
}
|
|
228
|
-
if (metric.target !== undefined && metric.target < 0) {
|
|
229
|
-
errors.push(`Metric ${metric.name} target cannot be negative`);
|
|
230
|
-
}
|
|
231
|
-
if (metric.current !== undefined && metric.current < 0) {
|
|
232
|
-
errors.push(`Metric ${metric.name} current value cannot be negative`);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return {
|
|
237
|
-
valid: errors.length === 0,
|
|
238
|
-
errors,
|
|
239
|
-
};
|
|
240
|
-
}
|
package/src/product.js
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Product definition and management
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Define a product with pricing, features, and roadmap
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```ts
|
|
9
|
-
* const product = Product({
|
|
10
|
-
* name: 'Widget Pro',
|
|
11
|
-
* description: 'Enterprise-grade widget management platform',
|
|
12
|
-
* category: 'SaaS',
|
|
13
|
-
* targetSegment: 'Enterprise',
|
|
14
|
-
* valueProposition: 'Reduce widget management costs by 50%',
|
|
15
|
-
* pricingModel: 'subscription',
|
|
16
|
-
* price: 99,
|
|
17
|
-
* currency: 'USD',
|
|
18
|
-
* cogs: 20,
|
|
19
|
-
* features: [
|
|
20
|
-
* 'Unlimited widgets',
|
|
21
|
-
* 'Advanced analytics',
|
|
22
|
-
* 'API access',
|
|
23
|
-
* '24/7 support',
|
|
24
|
-
* ],
|
|
25
|
-
* roadmap: [
|
|
26
|
-
* {
|
|
27
|
-
* name: 'Mobile app',
|
|
28
|
-
* description: 'Native iOS and Android apps',
|
|
29
|
-
* targetDate: new Date('2024-09-01'),
|
|
30
|
-
* priority: 'high',
|
|
31
|
-
* status: 'in-progress',
|
|
32
|
-
* },
|
|
33
|
-
* {
|
|
34
|
-
* name: 'AI-powered insights',
|
|
35
|
-
* description: 'Automated widget optimization suggestions',
|
|
36
|
-
* targetDate: new Date('2024-12-01'),
|
|
37
|
-
* priority: 'high',
|
|
38
|
-
* status: 'planned',
|
|
39
|
-
* },
|
|
40
|
-
* ],
|
|
41
|
-
* })
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
|
-
export function Product(definition) {
|
|
45
|
-
if (!definition.name) {
|
|
46
|
-
throw new Error('Product name is required');
|
|
47
|
-
}
|
|
48
|
-
return {
|
|
49
|
-
...definition,
|
|
50
|
-
pricingModel: definition.pricingModel || 'one-time',
|
|
51
|
-
currency: definition.currency || 'USD',
|
|
52
|
-
features: definition.features || [],
|
|
53
|
-
roadmap: definition.roadmap || [],
|
|
54
|
-
metadata: definition.metadata || {},
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Calculate gross margin for a product
|
|
59
|
-
*/
|
|
60
|
-
export function calculateGrossMargin(product) {
|
|
61
|
-
if (!product.price || !product.cogs)
|
|
62
|
-
return 0;
|
|
63
|
-
return ((product.price - product.cogs) / product.price) * 100;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Calculate gross profit for a product
|
|
67
|
-
*/
|
|
68
|
-
export function calculateGrossProfit(product, unitsSold) {
|
|
69
|
-
if (!product.price || !product.cogs)
|
|
70
|
-
return 0;
|
|
71
|
-
return (product.price - product.cogs) * unitsSold;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Get roadmap items by status
|
|
75
|
-
*/
|
|
76
|
-
export function getRoadmapByStatus(product, status) {
|
|
77
|
-
return product.roadmap?.filter(item => item.status === status) || [];
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Get roadmap items by priority
|
|
81
|
-
*/
|
|
82
|
-
export function getRoadmapByPriority(product, priority) {
|
|
83
|
-
return product.roadmap?.filter(item => item.priority === priority) || [];
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Get overdue roadmap items
|
|
87
|
-
*/
|
|
88
|
-
export function getOverdueRoadmapItems(product) {
|
|
89
|
-
const now = new Date();
|
|
90
|
-
return (product.roadmap?.filter(item => item.targetDate &&
|
|
91
|
-
item.targetDate < now &&
|
|
92
|
-
item.status !== 'completed' &&
|
|
93
|
-
item.status !== 'cancelled') || []);
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Update roadmap item status
|
|
97
|
-
*/
|
|
98
|
-
export function updateRoadmapItem(product, itemName, updates) {
|
|
99
|
-
const roadmap = product.roadmap?.map(item => item.name === itemName ? { ...item, ...updates } : item);
|
|
100
|
-
return {
|
|
101
|
-
...product,
|
|
102
|
-
roadmap,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Add feature to product
|
|
107
|
-
*/
|
|
108
|
-
export function addFeature(product, feature) {
|
|
109
|
-
return {
|
|
110
|
-
...product,
|
|
111
|
-
features: [...(product.features || []), feature],
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Remove feature from product
|
|
116
|
-
*/
|
|
117
|
-
export function removeFeature(product, feature) {
|
|
118
|
-
return {
|
|
119
|
-
...product,
|
|
120
|
-
features: product.features?.filter(f => f !== feature) || [],
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Validate product definition
|
|
125
|
-
*/
|
|
126
|
-
export function validateProduct(product) {
|
|
127
|
-
const errors = [];
|
|
128
|
-
if (!product.name) {
|
|
129
|
-
errors.push('Product name is required');
|
|
130
|
-
}
|
|
131
|
-
if (product.price && product.price < 0) {
|
|
132
|
-
errors.push('Product price cannot be negative');
|
|
133
|
-
}
|
|
134
|
-
if (product.cogs && product.cogs < 0) {
|
|
135
|
-
errors.push('Product COGS cannot be negative');
|
|
136
|
-
}
|
|
137
|
-
if (product.price && product.cogs && product.cogs > product.price) {
|
|
138
|
-
errors.push('Product COGS cannot exceed price');
|
|
139
|
-
}
|
|
140
|
-
return {
|
|
141
|
-
valid: errors.length === 0,
|
|
142
|
-
errors,
|
|
143
|
-
};
|
|
144
|
-
}
|