business-as-code 2.1.1 → 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 +18 -0
- package/README.md +2 -0
- package/package.json +7 -4
- 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/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/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 -87
- 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/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/src/queries.js
DELETED
|
@@ -1,414 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Live Queries & Views
|
|
3
|
-
*
|
|
4
|
-
* Query definitions for real-time analytics against ai-database (ClickHouse-backed).
|
|
5
|
-
* These are NOT batch reports - they're live, composable queries that execute
|
|
6
|
-
* in real-time against a performant OLAP database.
|
|
7
|
-
*
|
|
8
|
-
* @packageDocumentation
|
|
9
|
-
*/
|
|
10
|
-
// =============================================================================
|
|
11
|
-
// Metric Definitions (Standard SaaS Metrics as Queries)
|
|
12
|
-
// =============================================================================
|
|
13
|
-
/**
|
|
14
|
-
* Standard SaaS metric dimensions
|
|
15
|
-
*/
|
|
16
|
-
export const StandardDimensions = {
|
|
17
|
-
// Time
|
|
18
|
-
date: { name: 'date', field: 'date', type: 'date', description: 'Event date' },
|
|
19
|
-
month: { name: 'month', field: 'date', type: 'date', granularity: 'month', description: 'Month' },
|
|
20
|
-
quarter: { name: 'quarter', field: 'date', type: 'date', granularity: 'quarter', description: 'Quarter' },
|
|
21
|
-
year: { name: 'year', field: 'date', type: 'date', granularity: 'year', description: 'Year' },
|
|
22
|
-
// Customer
|
|
23
|
-
customerId: { name: 'customerId', field: 'customer_id', type: 'string', description: 'Customer ID' },
|
|
24
|
-
customerSegment: { name: 'customerSegment', field: 'customer_segment', type: 'string', description: 'Customer segment' },
|
|
25
|
-
plan: { name: 'plan', field: 'plan', type: 'string', description: 'Subscription plan' },
|
|
26
|
-
cohort: { name: 'cohort', field: 'cohort', type: 'string', description: 'Customer cohort' },
|
|
27
|
-
// Product
|
|
28
|
-
productId: { name: 'productId', field: 'product_id', type: 'string', description: 'Product ID' },
|
|
29
|
-
productName: { name: 'productName', field: 'product_name', type: 'string', description: 'Product name' },
|
|
30
|
-
feature: { name: 'feature', field: 'feature', type: 'string', description: 'Feature name' },
|
|
31
|
-
// Geography
|
|
32
|
-
country: { name: 'country', field: 'country', type: 'string', description: 'Country' },
|
|
33
|
-
region: { name: 'region', field: 'region', type: 'string', description: 'Region' },
|
|
34
|
-
// Channel
|
|
35
|
-
channel: { name: 'channel', field: 'channel', type: 'string', description: 'Acquisition channel' },
|
|
36
|
-
source: { name: 'source', field: 'source', type: 'string', description: 'Traffic source' },
|
|
37
|
-
campaign: { name: 'campaign', field: 'campaign', type: 'string', description: 'Marketing campaign' },
|
|
38
|
-
};
|
|
39
|
-
/**
|
|
40
|
-
* Standard SaaS metric measures
|
|
41
|
-
*/
|
|
42
|
-
export const StandardMeasures = {
|
|
43
|
-
// Revenue
|
|
44
|
-
revenue: { name: 'revenue', field: 'revenue', aggregate: 'sum', type: 'currency', description: 'Total revenue' },
|
|
45
|
-
mrr: { name: 'mrr', field: 'mrr', aggregate: 'sum', type: 'currency', description: 'Monthly recurring revenue' },
|
|
46
|
-
newMrr: { name: 'newMrr', field: 'new_mrr', aggregate: 'sum', type: 'currency', description: 'New MRR' },
|
|
47
|
-
expansionMrr: { name: 'expansionMrr', field: 'expansion_mrr', aggregate: 'sum', type: 'currency', description: 'Expansion MRR' },
|
|
48
|
-
contractionMrr: { name: 'contractionMrr', field: 'contraction_mrr', aggregate: 'sum', type: 'currency', description: 'Contraction MRR' },
|
|
49
|
-
churnedMrr: { name: 'churnedMrr', field: 'churned_mrr', aggregate: 'sum', type: 'currency', description: 'Churned MRR' },
|
|
50
|
-
// Customers
|
|
51
|
-
customers: { name: 'customers', field: 'customer_id', aggregate: 'countDistinct', type: 'number', description: 'Unique customers' },
|
|
52
|
-
newCustomers: { name: 'newCustomers', field: 'new_customer_id', aggregate: 'countDistinct', type: 'number', description: 'New customers' },
|
|
53
|
-
churnedCustomers: { name: 'churnedCustomers', field: 'churned_customer_id', aggregate: 'countDistinct', type: 'number', description: 'Churned customers' },
|
|
54
|
-
// Usage
|
|
55
|
-
events: { name: 'events', field: 'event_id', aggregate: 'count', type: 'number', description: 'Event count' },
|
|
56
|
-
sessions: { name: 'sessions', field: 'session_id', aggregate: 'countDistinct', type: 'number', description: 'Unique sessions' },
|
|
57
|
-
activeUsers: { name: 'activeUsers', field: 'user_id', aggregate: 'countDistinct', type: 'number', description: 'Active users' },
|
|
58
|
-
// Costs
|
|
59
|
-
cogs: { name: 'cogs', field: 'cogs', aggregate: 'sum', type: 'currency', description: 'Cost of goods sold' },
|
|
60
|
-
salesSpend: { name: 'salesSpend', field: 'sales_spend', aggregate: 'sum', type: 'currency', description: 'Sales spend' },
|
|
61
|
-
marketingSpend: { name: 'marketingSpend', field: 'marketing_spend', aggregate: 'sum', type: 'currency', description: 'Marketing spend' },
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Calculated SaaS metrics
|
|
65
|
-
*/
|
|
66
|
-
export const CalculatedMetrics = {
|
|
67
|
-
// Revenue metrics
|
|
68
|
-
arr: {
|
|
69
|
-
name: 'arr',
|
|
70
|
-
expression: 'mrr * 12',
|
|
71
|
-
measures: ['mrr'],
|
|
72
|
-
type: 'currency',
|
|
73
|
-
description: 'Annual recurring revenue',
|
|
74
|
-
},
|
|
75
|
-
netNewMrr: {
|
|
76
|
-
name: 'netNewMrr',
|
|
77
|
-
expression: 'newMrr + expansionMrr - contractionMrr - churnedMrr',
|
|
78
|
-
measures: ['newMrr', 'expansionMrr', 'contractionMrr', 'churnedMrr'],
|
|
79
|
-
type: 'currency',
|
|
80
|
-
description: 'Net new MRR',
|
|
81
|
-
},
|
|
82
|
-
arpu: {
|
|
83
|
-
name: 'arpu',
|
|
84
|
-
expression: 'mrr / customers',
|
|
85
|
-
measures: ['mrr', 'customers'],
|
|
86
|
-
type: 'currency',
|
|
87
|
-
description: 'Average revenue per user',
|
|
88
|
-
},
|
|
89
|
-
// Margin metrics
|
|
90
|
-
grossProfit: {
|
|
91
|
-
name: 'grossProfit',
|
|
92
|
-
expression: 'revenue - cogs',
|
|
93
|
-
measures: ['revenue', 'cogs'],
|
|
94
|
-
type: 'currency',
|
|
95
|
-
description: 'Gross profit',
|
|
96
|
-
},
|
|
97
|
-
grossMargin: {
|
|
98
|
-
name: 'grossMargin',
|
|
99
|
-
expression: '(revenue - cogs) / revenue * 100',
|
|
100
|
-
measures: ['revenue', 'cogs'],
|
|
101
|
-
type: 'percent',
|
|
102
|
-
description: 'Gross margin percentage',
|
|
103
|
-
},
|
|
104
|
-
// Efficiency metrics
|
|
105
|
-
cac: {
|
|
106
|
-
name: 'cac',
|
|
107
|
-
expression: '(salesSpend + marketingSpend) / newCustomers',
|
|
108
|
-
measures: ['salesSpend', 'marketingSpend', 'newCustomers'],
|
|
109
|
-
type: 'currency',
|
|
110
|
-
description: 'Customer acquisition cost',
|
|
111
|
-
},
|
|
112
|
-
ltv: {
|
|
113
|
-
name: 'ltv',
|
|
114
|
-
expression: 'arpu * grossMargin / 100 / churnRate',
|
|
115
|
-
measures: ['arpu', 'grossMargin'],
|
|
116
|
-
type: 'currency',
|
|
117
|
-
description: 'Customer lifetime value',
|
|
118
|
-
},
|
|
119
|
-
ltvCacRatio: {
|
|
120
|
-
name: 'ltvCacRatio',
|
|
121
|
-
expression: 'ltv / cac',
|
|
122
|
-
measures: ['ltv', 'cac'],
|
|
123
|
-
type: 'number',
|
|
124
|
-
description: 'LTV:CAC ratio',
|
|
125
|
-
},
|
|
126
|
-
// Churn metrics
|
|
127
|
-
customerChurnRate: {
|
|
128
|
-
name: 'customerChurnRate',
|
|
129
|
-
expression: 'churnedCustomers / customers * 100',
|
|
130
|
-
measures: ['churnedCustomers', 'customers'],
|
|
131
|
-
type: 'percent',
|
|
132
|
-
description: 'Customer churn rate',
|
|
133
|
-
},
|
|
134
|
-
revenueChurnRate: {
|
|
135
|
-
name: 'revenueChurnRate',
|
|
136
|
-
expression: 'churnedMrr / mrr * 100',
|
|
137
|
-
measures: ['churnedMrr', 'mrr'],
|
|
138
|
-
type: 'percent',
|
|
139
|
-
description: 'Revenue churn rate',
|
|
140
|
-
},
|
|
141
|
-
nrr: {
|
|
142
|
-
name: 'nrr',
|
|
143
|
-
expression: '(mrr + expansionMrr - contractionMrr - churnedMrr) / mrr * 100',
|
|
144
|
-
measures: ['mrr', 'expansionMrr', 'contractionMrr', 'churnedMrr'],
|
|
145
|
-
type: 'percent',
|
|
146
|
-
description: 'Net revenue retention',
|
|
147
|
-
},
|
|
148
|
-
// Growth metrics
|
|
149
|
-
quickRatio: {
|
|
150
|
-
name: 'quickRatio',
|
|
151
|
-
expression: '(newMrr + expansionMrr) / (contractionMrr + churnedMrr)',
|
|
152
|
-
measures: ['newMrr', 'expansionMrr', 'contractionMrr', 'churnedMrr'],
|
|
153
|
-
type: 'number',
|
|
154
|
-
description: 'SaaS Quick Ratio',
|
|
155
|
-
},
|
|
156
|
-
magicNumber: {
|
|
157
|
-
name: 'magicNumber',
|
|
158
|
-
expression: 'netNewMrr * 12 / (salesSpend + marketingSpend)',
|
|
159
|
-
measures: ['netNewMrr', 'salesSpend', 'marketingSpend'],
|
|
160
|
-
type: 'number',
|
|
161
|
-
description: 'Magic Number',
|
|
162
|
-
},
|
|
163
|
-
};
|
|
164
|
-
// =============================================================================
|
|
165
|
-
// Query Builder Functions
|
|
166
|
-
// =============================================================================
|
|
167
|
-
/**
|
|
168
|
-
* Create a query
|
|
169
|
-
*/
|
|
170
|
-
export function query(name, source) {
|
|
171
|
-
return new QueryBuilder(name, source);
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Fluent query builder
|
|
175
|
-
*/
|
|
176
|
-
export class QueryBuilder {
|
|
177
|
-
_query;
|
|
178
|
-
constructor(name, source) {
|
|
179
|
-
this._query = { name, source };
|
|
180
|
-
}
|
|
181
|
-
describe(description) {
|
|
182
|
-
this._query.description = description;
|
|
183
|
-
return this;
|
|
184
|
-
}
|
|
185
|
-
dimensions(...dims) {
|
|
186
|
-
this._query.dimensions = dims;
|
|
187
|
-
return this;
|
|
188
|
-
}
|
|
189
|
-
measures(...measures) {
|
|
190
|
-
this._query.measures = measures;
|
|
191
|
-
return this;
|
|
192
|
-
}
|
|
193
|
-
filter(field, operator, value) {
|
|
194
|
-
if (!this._query.filters)
|
|
195
|
-
this._query.filters = [];
|
|
196
|
-
this._query.filters.push({ field, operator, value });
|
|
197
|
-
return this;
|
|
198
|
-
}
|
|
199
|
-
where(filters) {
|
|
200
|
-
this._query.filters = filters;
|
|
201
|
-
return this;
|
|
202
|
-
}
|
|
203
|
-
timeRange(field, start, end, granularity) {
|
|
204
|
-
this._query.timeRange = { field, start, end, granularity };
|
|
205
|
-
return this;
|
|
206
|
-
}
|
|
207
|
-
last(duration, field = 'date') {
|
|
208
|
-
this._query.timeRange = { field, start: `-${duration}` };
|
|
209
|
-
return this;
|
|
210
|
-
}
|
|
211
|
-
sort(field, direction = 'desc') {
|
|
212
|
-
if (!this._query.sort)
|
|
213
|
-
this._query.sort = [];
|
|
214
|
-
this._query.sort.push({ field, direction });
|
|
215
|
-
return this;
|
|
216
|
-
}
|
|
217
|
-
limit(n) {
|
|
218
|
-
this._query.limit = n;
|
|
219
|
-
return this;
|
|
220
|
-
}
|
|
221
|
-
offset(n) {
|
|
222
|
-
this._query.offset = n;
|
|
223
|
-
return this;
|
|
224
|
-
}
|
|
225
|
-
tags(...tags) {
|
|
226
|
-
this._query.tags = tags;
|
|
227
|
-
return this;
|
|
228
|
-
}
|
|
229
|
-
owner(owner) {
|
|
230
|
-
this._query.owner = owner;
|
|
231
|
-
return this;
|
|
232
|
-
}
|
|
233
|
-
build() {
|
|
234
|
-
return { ...this._query };
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
// =============================================================================
|
|
238
|
-
// Pre-built SaaS Metric Queries
|
|
239
|
-
// =============================================================================
|
|
240
|
-
/**
|
|
241
|
-
* MRR Overview query
|
|
242
|
-
*/
|
|
243
|
-
export const MrrOverview = query('mrr_overview', 'revenue_events')
|
|
244
|
-
.describe('Monthly recurring revenue breakdown')
|
|
245
|
-
.dimensions('month')
|
|
246
|
-
.measures('mrr', 'newMrr', 'expansionMrr', 'contractionMrr', 'churnedMrr', 'netNewMrr')
|
|
247
|
-
.last('12m')
|
|
248
|
-
.sort('month', 'asc')
|
|
249
|
-
.build();
|
|
250
|
-
/**
|
|
251
|
-
* ARR by segment query
|
|
252
|
-
*/
|
|
253
|
-
export const ArrBySegment = query('arr_by_segment', 'revenue_events')
|
|
254
|
-
.describe('Annual recurring revenue by customer segment')
|
|
255
|
-
.dimensions('customerSegment')
|
|
256
|
-
.measures('arr', 'customers', 'arpu')
|
|
257
|
-
.last('1m')
|
|
258
|
-
.sort('arr', 'desc')
|
|
259
|
-
.build();
|
|
260
|
-
/**
|
|
261
|
-
* Customer cohort retention query
|
|
262
|
-
*/
|
|
263
|
-
export const CohortRetention = query('cohort_retention', 'customer_events')
|
|
264
|
-
.describe('Customer retention by signup cohort')
|
|
265
|
-
.dimensions('cohort', 'month')
|
|
266
|
-
.measures('customers', 'mrr')
|
|
267
|
-
.last('12m')
|
|
268
|
-
.sort('cohort', 'asc')
|
|
269
|
-
.build();
|
|
270
|
-
/**
|
|
271
|
-
* Unit economics query
|
|
272
|
-
*/
|
|
273
|
-
export const UnitEconomics = query('unit_economics', 'financial_events')
|
|
274
|
-
.describe('Key unit economics metrics')
|
|
275
|
-
.dimensions('month')
|
|
276
|
-
.measures('cac', 'ltv', 'ltvCacRatio', 'arpu', 'customerChurnRate')
|
|
277
|
-
.last('12m')
|
|
278
|
-
.sort('month', 'asc')
|
|
279
|
-
.build();
|
|
280
|
-
/**
|
|
281
|
-
* Revenue by channel query
|
|
282
|
-
*/
|
|
283
|
-
export const RevenueByChannel = query('revenue_by_channel', 'revenue_events')
|
|
284
|
-
.describe('Revenue breakdown by acquisition channel')
|
|
285
|
-
.dimensions('channel')
|
|
286
|
-
.measures('mrr', 'newCustomers', 'cac')
|
|
287
|
-
.last('3m')
|
|
288
|
-
.sort('mrr', 'desc')
|
|
289
|
-
.build();
|
|
290
|
-
/**
|
|
291
|
-
* Growth metrics query
|
|
292
|
-
*/
|
|
293
|
-
export const GrowthMetrics = query('growth_metrics', 'financial_events')
|
|
294
|
-
.describe('Key growth and efficiency metrics')
|
|
295
|
-
.dimensions('month')
|
|
296
|
-
.measures('mrr', 'netNewMrr', 'quickRatio', 'nrr', 'magicNumber')
|
|
297
|
-
.last('12m')
|
|
298
|
-
.sort('month', 'asc')
|
|
299
|
-
.build();
|
|
300
|
-
// =============================================================================
|
|
301
|
-
// View Builder
|
|
302
|
-
// =============================================================================
|
|
303
|
-
/**
|
|
304
|
-
* Create a view from a query
|
|
305
|
-
*/
|
|
306
|
-
export function view(name, queryDef) {
|
|
307
|
-
return new ViewBuilder(name, queryDef);
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* Fluent view builder
|
|
311
|
-
*/
|
|
312
|
-
export class ViewBuilder {
|
|
313
|
-
_view;
|
|
314
|
-
constructor(name, queryDef) {
|
|
315
|
-
this._view = { name, query: queryDef };
|
|
316
|
-
}
|
|
317
|
-
describe(description) {
|
|
318
|
-
this._view.description = description;
|
|
319
|
-
return this;
|
|
320
|
-
}
|
|
321
|
-
materialize(refreshInterval, retention) {
|
|
322
|
-
this._view.materialized = true;
|
|
323
|
-
this._view.refreshInterval = refreshInterval;
|
|
324
|
-
this._view.retention = retention;
|
|
325
|
-
return this;
|
|
326
|
-
}
|
|
327
|
-
public() {
|
|
328
|
-
this._view.public = true;
|
|
329
|
-
return this;
|
|
330
|
-
}
|
|
331
|
-
owner(owner) {
|
|
332
|
-
this._view.owner = owner;
|
|
333
|
-
return this;
|
|
334
|
-
}
|
|
335
|
-
tags(...tags) {
|
|
336
|
-
this._view.tags = tags;
|
|
337
|
-
return this;
|
|
338
|
-
}
|
|
339
|
-
build() {
|
|
340
|
-
return { ...this._view };
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
// =============================================================================
|
|
344
|
-
// Dashboard Builder
|
|
345
|
-
// =============================================================================
|
|
346
|
-
/**
|
|
347
|
-
* Create a dashboard
|
|
348
|
-
*/
|
|
349
|
-
export function dashboard(name) {
|
|
350
|
-
return new DashboardBuilder(name);
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* Fluent dashboard builder
|
|
354
|
-
*/
|
|
355
|
-
export class DashboardBuilder {
|
|
356
|
-
_dashboard;
|
|
357
|
-
constructor(name) {
|
|
358
|
-
this._dashboard = { name, views: [] };
|
|
359
|
-
}
|
|
360
|
-
describe(description) {
|
|
361
|
-
this._dashboard.description = description;
|
|
362
|
-
return this;
|
|
363
|
-
}
|
|
364
|
-
add(viewDef, options) {
|
|
365
|
-
this._dashboard.views.push(viewDef);
|
|
366
|
-
if (options && this._dashboard.layout) {
|
|
367
|
-
this._dashboard.layout.items.push({
|
|
368
|
-
viewName: viewDef.name,
|
|
369
|
-
x: options.x || 0,
|
|
370
|
-
y: options.y || 0,
|
|
371
|
-
width: options.width || 1,
|
|
372
|
-
height: options.height || 1,
|
|
373
|
-
visualization: options.visualization,
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
return this;
|
|
377
|
-
}
|
|
378
|
-
layout(columns, rows) {
|
|
379
|
-
this._dashboard.layout = { columns, rows, items: [] };
|
|
380
|
-
return this;
|
|
381
|
-
}
|
|
382
|
-
refresh(interval) {
|
|
383
|
-
this._dashboard.refreshInterval = interval;
|
|
384
|
-
return this;
|
|
385
|
-
}
|
|
386
|
-
owner(owner) {
|
|
387
|
-
this._dashboard.owner = owner;
|
|
388
|
-
return this;
|
|
389
|
-
}
|
|
390
|
-
tags(...tags) {
|
|
391
|
-
this._dashboard.tags = tags;
|
|
392
|
-
return this;
|
|
393
|
-
}
|
|
394
|
-
build() {
|
|
395
|
-
return { ...this._dashboard };
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
// =============================================================================
|
|
399
|
-
// Pre-built Dashboards
|
|
400
|
-
// =============================================================================
|
|
401
|
-
/**
|
|
402
|
-
* Executive SaaS Dashboard
|
|
403
|
-
*/
|
|
404
|
-
export const ExecutiveDashboard = dashboard('executive')
|
|
405
|
-
.describe('Executive overview of key SaaS metrics')
|
|
406
|
-
.layout(4, 3)
|
|
407
|
-
.add(view('mrr', MrrOverview).build(), { x: 0, y: 0, width: 2, height: 1, visualization: 'trend' })
|
|
408
|
-
.add(view('arr_segments', ArrBySegment).build(), { x: 2, y: 0, width: 2, height: 1, visualization: 'bar' })
|
|
409
|
-
.add(view('unit_econ', UnitEconomics).build(), { x: 0, y: 1, width: 2, height: 1, visualization: 'table' })
|
|
410
|
-
.add(view('growth', GrowthMetrics).build(), { x: 2, y: 1, width: 2, height: 1, visualization: 'line' })
|
|
411
|
-
.add(view('cohorts', CohortRetention).build(), { x: 0, y: 2, width: 4, height: 1, visualization: 'cohort' })
|
|
412
|
-
.refresh('5m')
|
|
413
|
-
.tags('executive', 'saas', 'metrics')
|
|
414
|
-
.build();
|
package/src/roles.js
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Business Roles - Bridges digital-workers and ai-database authorization
|
|
3
|
-
*
|
|
4
|
-
* Connects:
|
|
5
|
-
* - WorkerRole (business role: CEO, Engineer, Manager)
|
|
6
|
-
* - Authorization Role (FGA/RBAC: permissions, access control)
|
|
7
|
-
* - Task Assignment (who handles what in workflows/processes)
|
|
8
|
-
*
|
|
9
|
-
* @packageDocumentation
|
|
10
|
-
*/
|
|
11
|
-
// =============================================================================
|
|
12
|
-
// Standard Business Roles
|
|
13
|
-
// =============================================================================
|
|
14
|
-
/**
|
|
15
|
-
* Standard business roles with typical permissions
|
|
16
|
-
*/
|
|
17
|
-
export const StandardBusinessRoles = {
|
|
18
|
-
// Executive
|
|
19
|
-
ceo: {
|
|
20
|
-
type: 'ceo',
|
|
21
|
-
name: 'Chief Executive Officer',
|
|
22
|
-
level: 10,
|
|
23
|
-
permissions: { '*': ['manage'] },
|
|
24
|
-
canApprove: ['*'],
|
|
25
|
-
workerType: 'human',
|
|
26
|
-
},
|
|
27
|
-
cto: {
|
|
28
|
-
type: 'cto',
|
|
29
|
-
name: 'Chief Technology Officer',
|
|
30
|
-
level: 10,
|
|
31
|
-
department: 'Technology',
|
|
32
|
-
permissions: {
|
|
33
|
-
technology: ['manage'],
|
|
34
|
-
repository: ['manage'],
|
|
35
|
-
infrastructure: ['manage'],
|
|
36
|
-
},
|
|
37
|
-
canApprove: ['technical-decision', 'architecture', 'technology-budget'],
|
|
38
|
-
workerType: 'human',
|
|
39
|
-
},
|
|
40
|
-
cfo: {
|
|
41
|
-
type: 'cfo',
|
|
42
|
-
name: 'Chief Financial Officer',
|
|
43
|
-
level: 10,
|
|
44
|
-
department: 'Finance',
|
|
45
|
-
permissions: {
|
|
46
|
-
finance: ['manage'],
|
|
47
|
-
budget: ['manage'],
|
|
48
|
-
expense: ['manage'],
|
|
49
|
-
},
|
|
50
|
-
canApprove: ['expense', 'budget', 'financial-decision'],
|
|
51
|
-
workerType: 'human',
|
|
52
|
-
},
|
|
53
|
-
// Management
|
|
54
|
-
director: {
|
|
55
|
-
type: 'director',
|
|
56
|
-
level: 8,
|
|
57
|
-
permissions: {
|
|
58
|
-
team: ['manage'],
|
|
59
|
-
project: ['manage'],
|
|
60
|
-
budget: ['read', 'edit'],
|
|
61
|
-
},
|
|
62
|
-
canApprove: ['hiring', 'budget-under-50k', 'project'],
|
|
63
|
-
workerType: 'human',
|
|
64
|
-
},
|
|
65
|
-
manager: {
|
|
66
|
-
type: 'manager',
|
|
67
|
-
level: 6,
|
|
68
|
-
permissions: {
|
|
69
|
-
team: ['read', 'edit'],
|
|
70
|
-
project: ['read', 'edit', 'manage'],
|
|
71
|
-
},
|
|
72
|
-
canApprove: ['expense-under-5k', 'time-off', 'code-review'],
|
|
73
|
-
workerType: 'human',
|
|
74
|
-
},
|
|
75
|
-
lead: {
|
|
76
|
-
type: 'lead',
|
|
77
|
-
level: 5,
|
|
78
|
-
permissions: {
|
|
79
|
-
team: ['read'],
|
|
80
|
-
project: ['read', 'edit'],
|
|
81
|
-
repository: ['read', 'edit', 'act:merge'],
|
|
82
|
-
},
|
|
83
|
-
canDelegate: ['code-review', 'testing'],
|
|
84
|
-
workerType: 'hybrid',
|
|
85
|
-
},
|
|
86
|
-
// Individual Contributors
|
|
87
|
-
engineer: {
|
|
88
|
-
type: 'engineer',
|
|
89
|
-
level: 3,
|
|
90
|
-
department: 'Engineering',
|
|
91
|
-
permissions: {
|
|
92
|
-
repository: ['read', 'edit'],
|
|
93
|
-
project: ['read'],
|
|
94
|
-
},
|
|
95
|
-
canHandle: ['coding', 'code-review', 'bug-fix', 'testing'],
|
|
96
|
-
workerType: 'hybrid',
|
|
97
|
-
},
|
|
98
|
-
analyst: {
|
|
99
|
-
type: 'analyst',
|
|
100
|
-
level: 3,
|
|
101
|
-
permissions: {
|
|
102
|
-
data: ['read'],
|
|
103
|
-
report: ['read', 'edit'],
|
|
104
|
-
},
|
|
105
|
-
canHandle: ['data-analysis', 'reporting', 'research'],
|
|
106
|
-
workerType: 'hybrid',
|
|
107
|
-
},
|
|
108
|
-
// Operations
|
|
109
|
-
agent: {
|
|
110
|
-
type: 'agent',
|
|
111
|
-
level: 2,
|
|
112
|
-
permissions: {
|
|
113
|
-
ticket: ['read', 'edit', 'act:respond', 'act:escalate'],
|
|
114
|
-
customer: ['read'],
|
|
115
|
-
},
|
|
116
|
-
canHandle: ['customer-inquiry', 'support-ticket', 'basic-troubleshooting'],
|
|
117
|
-
workerType: 'ai', // AI-first
|
|
118
|
-
},
|
|
119
|
-
assistant: {
|
|
120
|
-
type: 'assistant',
|
|
121
|
-
level: 1,
|
|
122
|
-
permissions: {
|
|
123
|
-
calendar: ['read', 'edit'],
|
|
124
|
-
email: ['read', 'act:draft'],
|
|
125
|
-
task: ['read', 'edit'],
|
|
126
|
-
},
|
|
127
|
-
canHandle: ['scheduling', 'email-draft', 'task-management', 'research'],
|
|
128
|
-
workerType: 'ai', // AI-first
|
|
129
|
-
},
|
|
130
|
-
};
|
|
131
|
-
// =============================================================================
|
|
132
|
-
// Helper Functions
|
|
133
|
-
// =============================================================================
|
|
134
|
-
/**
|
|
135
|
-
* Create a business role from a standard template
|
|
136
|
-
*/
|
|
137
|
-
export function createBusinessRole(id, template, overrides) {
|
|
138
|
-
const standard = StandardBusinessRoles[template];
|
|
139
|
-
if (!standard) {
|
|
140
|
-
throw new Error(`Unknown role template: ${template}`);
|
|
141
|
-
}
|
|
142
|
-
return {
|
|
143
|
-
id,
|
|
144
|
-
name: standard.name || template,
|
|
145
|
-
type: standard.type || template,
|
|
146
|
-
...standard,
|
|
147
|
-
...overrides,
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Check if a role has permission for an action on a resource type
|
|
152
|
-
*/
|
|
153
|
-
export function hasPermission(role, resourceType, action) {
|
|
154
|
-
if (!role.permissions)
|
|
155
|
-
return false;
|
|
156
|
-
// Check wildcard permissions
|
|
157
|
-
const wildcardPerms = role.permissions['*'];
|
|
158
|
-
if (wildcardPerms) {
|
|
159
|
-
if (wildcardPerms.includes('manage') || wildcardPerms.includes('*'))
|
|
160
|
-
return true;
|
|
161
|
-
if (wildcardPerms.includes(action))
|
|
162
|
-
return true;
|
|
163
|
-
}
|
|
164
|
-
// Check resource-specific permissions
|
|
165
|
-
const resourcePerms = role.permissions[resourceType];
|
|
166
|
-
if (!resourcePerms)
|
|
167
|
-
return false;
|
|
168
|
-
// Check for exact match
|
|
169
|
-
if (resourcePerms.includes(action))
|
|
170
|
-
return true;
|
|
171
|
-
// Check for 'manage' which includes all actions
|
|
172
|
-
if (resourcePerms.includes('manage') || resourcePerms.includes('*'))
|
|
173
|
-
return true;
|
|
174
|
-
// Check for act:* pattern
|
|
175
|
-
if (action.startsWith('act:')) {
|
|
176
|
-
if (resourcePerms.includes('act:*'))
|
|
177
|
-
return true;
|
|
178
|
-
}
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Check if a role can handle a task type
|
|
183
|
-
*/
|
|
184
|
-
export function canHandleTask(role, taskType) {
|
|
185
|
-
if (!role.canHandle)
|
|
186
|
-
return false;
|
|
187
|
-
return role.canHandle.includes(taskType) || role.canHandle.includes('*');
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Check if a role can approve a request type
|
|
191
|
-
*/
|
|
192
|
-
export function canApproveRequest(role, requestType) {
|
|
193
|
-
if (!role.canApprove)
|
|
194
|
-
return false;
|
|
195
|
-
return role.canApprove.includes(requestType) || role.canApprove.includes('*');
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Check if a role can delegate a task type
|
|
199
|
-
*/
|
|
200
|
-
export function canDelegateTask(role, taskType) {
|
|
201
|
-
if (!role.canDelegate)
|
|
202
|
-
return false;
|
|
203
|
-
return role.canDelegate.includes(taskType) || role.canDelegate.includes('*');
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Find the best role for a task based on routing rules
|
|
207
|
-
*/
|
|
208
|
-
export function findRoleForTask(taskType, rules, context) {
|
|
209
|
-
const matchingRules = rules.filter(rule => rule.taskType === taskType);
|
|
210
|
-
if (matchingRules.length === 0)
|
|
211
|
-
return undefined;
|
|
212
|
-
// If there's an amount and escalation rules, check those
|
|
213
|
-
if (context?.amount) {
|
|
214
|
-
for (const rule of matchingRules) {
|
|
215
|
-
if (rule.escalateAbove && context.amount > rule.escalateAbove) {
|
|
216
|
-
// Find the escalated rule
|
|
217
|
-
const escalatedRule = rules.find(r => r.taskType === taskType && r.requiredRole === rule.escalateTo);
|
|
218
|
-
if (escalatedRule)
|
|
219
|
-
return escalatedRule;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
// Return the first matching rule
|
|
224
|
-
return matchingRules[0];
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Create a task assignment
|
|
228
|
-
*/
|
|
229
|
-
export function createTaskAssignment(taskId, taskType, assignee, options) {
|
|
230
|
-
return {
|
|
231
|
-
id: `assign_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`,
|
|
232
|
-
taskId,
|
|
233
|
-
taskType,
|
|
234
|
-
assignee,
|
|
235
|
-
status: 'assigned',
|
|
236
|
-
assignedAt: new Date(),
|
|
237
|
-
priority: 'normal',
|
|
238
|
-
...options,
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Transition task assignment status
|
|
243
|
-
*/
|
|
244
|
-
export function transitionTaskStatus(assignment, newStatus, options) {
|
|
245
|
-
const now = new Date();
|
|
246
|
-
return {
|
|
247
|
-
...assignment,
|
|
248
|
-
status: newStatus,
|
|
249
|
-
...(newStatus === 'in_progress' && !assignment.startedAt ? { startedAt: now } : {}),
|
|
250
|
-
...(newStatus === 'completed' || newStatus === 'failed' ? { completedAt: now } : {}),
|
|
251
|
-
...(options?.result ? { result: options.result } : {}),
|
|
252
|
-
...(options?.notes ? { notes: options.notes } : {}),
|
|
253
|
-
};
|
|
254
|
-
}
|