business-as-code 2.1.3 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/.turbo/turbo-build.log +4 -5
  2. package/CHANGELOG.md +53 -0
  3. package/README.md +2 -0
  4. package/dist/dollar.d.ts.map +1 -1
  5. package/dist/dollar.js +2 -2
  6. package/dist/dollar.js.map +1 -1
  7. package/dist/entities/organization.d.ts +4 -0
  8. package/dist/entities/organization.d.ts.map +1 -1
  9. package/dist/entities/organization.js +27 -18
  10. package/dist/entities/organization.js.map +1 -1
  11. package/dist/entities/planning.d.ts +87 -0
  12. package/dist/finance/account.d.ts +44 -0
  13. package/dist/finance/account.d.ts.map +1 -0
  14. package/dist/finance/account.js +6 -0
  15. package/dist/finance/account.js.map +1 -0
  16. package/dist/finance/authority.d.ts +78 -0
  17. package/dist/finance/authority.d.ts.map +1 -0
  18. package/dist/finance/authority.js +27 -0
  19. package/dist/finance/authority.js.map +1 -0
  20. package/dist/finance/card.d.ts +36 -0
  21. package/dist/finance/card.d.ts.map +1 -0
  22. package/dist/finance/card.js +6 -0
  23. package/dist/finance/card.js.map +1 -0
  24. package/dist/finance/identity.d.ts +30 -0
  25. package/dist/finance/identity.d.ts.map +1 -0
  26. package/dist/finance/identity.js +8 -0
  27. package/dist/finance/identity.js.map +1 -0
  28. package/dist/finance/index.d.ts +36 -0
  29. package/dist/finance/index.d.ts.map +1 -0
  30. package/dist/finance/index.js +22 -0
  31. package/dist/finance/index.js.map +1 -0
  32. package/dist/finance/ledger.d.ts +24 -0
  33. package/dist/finance/ledger.d.ts.map +1 -0
  34. package/dist/finance/ledger.js +8 -0
  35. package/dist/finance/ledger.js.map +1 -0
  36. package/dist/finance/merchant.d.ts +129 -0
  37. package/dist/finance/merchant.d.ts.map +1 -0
  38. package/dist/finance/merchant.js +21 -0
  39. package/dist/finance/merchant.js.map +1 -0
  40. package/dist/finance/outcome-contract.d.ts +139 -0
  41. package/dist/finance/outcome-contract.d.ts.map +1 -0
  42. package/dist/finance/outcome-contract.js +27 -0
  43. package/dist/finance/outcome-contract.js.map +1 -0
  44. package/dist/finance/port.d.ts +121 -0
  45. package/dist/finance/port.d.ts.map +1 -0
  46. package/dist/finance/port.js +10 -0
  47. package/dist/finance/port.js.map +1 -0
  48. package/dist/finance/pricing.d.ts +154 -0
  49. package/dist/finance/pricing.d.ts.map +1 -0
  50. package/dist/finance/pricing.js +79 -0
  51. package/dist/finance/pricing.js.map +1 -0
  52. package/dist/finance/proof-predicate.d.ts +92 -0
  53. package/dist/finance/proof-predicate.d.ts.map +1 -0
  54. package/dist/finance/proof-predicate.js +80 -0
  55. package/dist/finance/proof-predicate.js.map +1 -0
  56. package/dist/finance/refund.d.ts +44 -0
  57. package/dist/finance/refund.d.ts.map +1 -0
  58. package/dist/finance/refund.js +41 -0
  59. package/dist/finance/refund.js.map +1 -0
  60. package/dist/finance/sla.d.ts +25 -0
  61. package/dist/finance/sla.d.ts.map +1 -0
  62. package/dist/finance/sla.js +7 -0
  63. package/dist/finance/sla.js.map +1 -0
  64. package/dist/finance/types.d.ts +79 -0
  65. package/dist/finance/types.d.ts.map +1 -0
  66. package/dist/finance/types.js +8 -0
  67. package/dist/{canvas → finance}/types.js.map +1 -1
  68. package/dist/goals.d.ts +19 -0
  69. package/dist/goals.d.ts.map +1 -1
  70. package/dist/goals.js +81 -12
  71. package/dist/goals.js.map +1 -1
  72. package/dist/index.d.ts +12 -8
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +19 -7
  75. package/dist/index.js.map +1 -1
  76. package/dist/kpis.d.ts +19 -0
  77. package/dist/kpis.d.ts.map +1 -1
  78. package/dist/kpis.js +71 -6
  79. package/dist/kpis.js.map +1 -1
  80. package/dist/metrics.d.ts.map +1 -1
  81. package/dist/metrics.js +29 -24
  82. package/dist/metrics.js.map +1 -1
  83. package/dist/okrs.d.ts +34 -0
  84. package/dist/okrs.d.ts.map +1 -1
  85. package/dist/okrs.js +135 -13
  86. package/dist/okrs.js.map +1 -1
  87. package/dist/organization.d.ts.map +1 -1
  88. package/dist/organization.js +11 -11
  89. package/dist/organization.js.map +1 -1
  90. package/dist/process.d.ts.map +1 -1
  91. package/dist/process.js +13 -12
  92. package/dist/process.js.map +1 -1
  93. package/dist/product.d.ts.map +1 -1
  94. package/dist/product.js +9 -9
  95. package/dist/product.js.map +1 -1
  96. package/dist/queries.d.ts.map +1 -1
  97. package/dist/queries.js +194 -32
  98. package/dist/queries.js.map +1 -1
  99. package/dist/roles.d.ts +25 -31
  100. package/dist/roles.d.ts.map +1 -1
  101. package/dist/roles.js +37 -10
  102. package/dist/roles.js.map +1 -1
  103. package/dist/workflow.d.ts.map +1 -1
  104. package/dist/workflow.js +13 -12
  105. package/dist/workflow.js.map +1 -1
  106. package/package.json +20 -13
  107. package/src/dollar.ts +5 -2
  108. package/src/entities/organization.ts +31 -18
  109. package/src/finance/account.ts +48 -0
  110. package/src/finance/authority.ts +42 -0
  111. package/src/finance/card.ts +38 -0
  112. package/src/finance/identity.ts +31 -0
  113. package/src/finance/index.ts +117 -0
  114. package/src/finance/ledger.ts +26 -0
  115. package/src/finance/merchant.ts +127 -0
  116. package/src/finance/outcome-contract.ts +157 -0
  117. package/src/finance/port.ts +144 -0
  118. package/src/finance/pricing.ts +197 -0
  119. package/src/finance/proof-predicate.ts +106 -0
  120. package/src/finance/refund.ts +52 -0
  121. package/src/finance/sla.ts +33 -0
  122. package/src/finance/types.ts +75 -0
  123. package/src/goals.ts +78 -12
  124. package/src/index.ts +48 -18
  125. package/src/kpis.ts +62 -8
  126. package/src/metrics.ts +92 -79
  127. package/src/okrs.ts +120 -20
  128. package/src/organization.ts +12 -15
  129. package/src/process.ts +11 -12
  130. package/src/product.ts +8 -9
  131. package/src/queries.ts +238 -75
  132. package/src/roles.ts +62 -61
  133. package/src/workflow.ts +22 -15
  134. package/test/business.test.ts +282 -0
  135. package/test/dollar.test.ts +270 -0
  136. package/test/entities.test.ts +628 -0
  137. package/test/financials.test.ts +539 -0
  138. package/test/goals.test.ts +451 -0
  139. package/{src → test}/index.test.ts +1 -1
  140. package/test/kpis.test.ts +440 -0
  141. package/test/metrics.test.ts +744 -0
  142. package/test/okrs.test.ts +741 -0
  143. package/test/organization.test.ts +548 -0
  144. package/test/process.test.ts +503 -0
  145. package/test/product.test.ts +430 -0
  146. package/test/queries.test.ts +556 -0
  147. package/test/roles.test.ts +546 -0
  148. package/test/service.test.ts +450 -0
  149. package/test/types.test.ts +1141 -0
  150. package/test/vision.test.ts +214 -0
  151. package/test/workflow.test.ts +501 -0
  152. package/vitest.config.ts +47 -0
  153. package/LICENSE +0 -21
  154. package/dist/canvas/activities.d.ts +0 -19
  155. package/dist/canvas/activities.d.ts.map +0 -1
  156. package/dist/canvas/activities.js +0 -20
  157. package/dist/canvas/activities.js.map +0 -1
  158. package/dist/canvas/channels.d.ts +0 -20
  159. package/dist/canvas/channels.d.ts.map +0 -1
  160. package/dist/canvas/channels.js +0 -21
  161. package/dist/canvas/channels.js.map +0 -1
  162. package/dist/canvas/relationships.d.ts +0 -20
  163. package/dist/canvas/relationships.d.ts.map +0 -1
  164. package/dist/canvas/relationships.js +0 -21
  165. package/dist/canvas/relationships.js.map +0 -1
  166. package/dist/canvas/resources.d.ts +0 -20
  167. package/dist/canvas/resources.d.ts.map +0 -1
  168. package/dist/canvas/resources.js +0 -30
  169. package/dist/canvas/resources.js.map +0 -1
  170. package/dist/canvas/revenue.d.ts +0 -22
  171. package/dist/canvas/revenue.d.ts.map +0 -1
  172. package/dist/canvas/revenue.js +0 -30
  173. package/dist/canvas/revenue.js.map +0 -1
  174. package/dist/canvas/segments.d.ts +0 -20
  175. package/dist/canvas/segments.d.ts.map +0 -1
  176. package/dist/canvas/segments.js +0 -28
  177. package/dist/canvas/segments.js.map +0 -1
  178. package/dist/canvas/types.d.ts +0 -232
  179. package/dist/canvas/types.d.ts.map +0 -1
  180. package/dist/canvas/types.js +0 -8
  181. package/dist/canvas/value.d.ts +0 -20
  182. package/dist/canvas/value.d.ts.map +0 -1
  183. package/dist/canvas/value.js +0 -21
  184. package/dist/canvas/value.js.map +0 -1
  185. package/src/business.js +0 -108
  186. package/src/canvas/activities.ts +0 -32
  187. package/src/canvas/canvas.ts +0 -482
  188. package/src/canvas/channels.ts +0 -34
  189. package/src/canvas/costs.ts +0 -43
  190. package/src/canvas/economics.ts +0 -99
  191. package/src/canvas/index.ts +0 -206
  192. package/src/canvas/partnerships.ts +0 -34
  193. package/src/canvas/projections.ts +0 -141
  194. package/src/canvas/relationships.ts +0 -34
  195. package/src/canvas/resources.ts +0 -43
  196. package/src/canvas/revenue.ts +0 -56
  197. package/src/canvas/segments.ts +0 -42
  198. package/src/canvas/types.ts +0 -363
  199. package/src/canvas/value.ts +0 -34
  200. package/src/dollar.js +0 -106
  201. package/src/entities/assets.js +0 -322
  202. package/src/entities/business.js +0 -369
  203. package/src/entities/communication.js +0 -254
  204. package/src/entities/customers.js +0 -988
  205. package/src/entities/financials.js +0 -931
  206. package/src/entities/goals.js +0 -799
  207. package/src/entities/index.js +0 -197
  208. package/src/entities/legal.js +0 -300
  209. package/src/entities/market.js +0 -300
  210. package/src/entities/marketing.js +0 -1156
  211. package/src/entities/offerings.js +0 -726
  212. package/src/entities/operations.js +0 -786
  213. package/src/entities/organization.js +0 -806
  214. package/src/entities/partnerships.js +0 -299
  215. package/src/entities/planning.js +0 -270
  216. package/src/entities/projects.js +0 -348
  217. package/src/entities/risk.js +0 -292
  218. package/src/entities/sales.js +0 -1247
  219. package/src/financials.js +0 -296
  220. package/src/goals.js +0 -214
  221. package/src/index.js +0 -131
  222. package/src/index.test.js +0 -274
  223. package/src/kpis.js +0 -231
  224. package/src/metrics.js +0 -324
  225. package/src/okrs.js +0 -268
  226. package/src/organization.js +0 -172
  227. package/src/process.js +0 -240
  228. package/src/product.js +0 -144
  229. package/src/queries.js +0 -414
  230. package/src/roles.js +0 -254
  231. package/src/service.js +0 -139
  232. package/src/types.js +0 -4
  233. package/src/vision.js +0 -67
  234. package/src/workflow.js +0 -246
  235. package/tests/canvas.test.ts +0 -842
@@ -1,482 +0,0 @@
1
- /**
2
- * Business Model Canvas
3
- *
4
- * Functions for creating, validating, and analyzing the Business Model Canvas.
5
- */
6
-
7
- import type {
8
- BusinessModelCanvas,
9
- CanvasValidation,
10
- CanvasSummary,
11
- CanvasStrengthAnalysis,
12
- CanvasGaps,
13
- CustomerSegment,
14
- ValueProposition,
15
- Channel,
16
- CustomerRelationship,
17
- RevenueStream,
18
- KeyResource,
19
- KeyActivity,
20
- KeyPartnership,
21
- CostItem,
22
- } from './types.js'
23
-
24
- export interface CreateCanvasInput {
25
- name: string
26
- customerSegments: CustomerSegment[]
27
- valuePropositions: ValueProposition[]
28
- channels: Channel[]
29
- customerRelationships: CustomerRelationship[]
30
- revenueStreams: RevenueStream[]
31
- keyResources: KeyResource[]
32
- keyActivities: KeyActivity[]
33
- keyPartnerships: KeyPartnership[]
34
- costStructure: CostItem[]
35
- metadata?: Record<string, unknown>
36
- }
37
-
38
- /**
39
- * Create a Business Model Canvas
40
- */
41
- export function createCanvas(input: CreateCanvasInput): BusinessModelCanvas {
42
- return {
43
- name: input.name,
44
- customerSegments: input.customerSegments,
45
- valuePropositions: input.valuePropositions,
46
- channels: input.channels,
47
- customerRelationships: input.customerRelationships,
48
- revenueStreams: input.revenueStreams,
49
- keyResources: input.keyResources,
50
- keyActivities: input.keyActivities,
51
- keyPartnerships: input.keyPartnerships,
52
- costStructure: input.costStructure,
53
- metadata: input.metadata,
54
- }
55
- }
56
-
57
- /**
58
- * Validate canvas completeness
59
- */
60
- export function validateCanvas(canvas: BusinessModelCanvas): CanvasValidation {
61
- const missingBlocks: string[] = []
62
- const warnings: string[] = []
63
-
64
- // Check each building block
65
- if (canvas.customerSegments.length === 0) {
66
- missingBlocks.push('customerSegments')
67
- }
68
-
69
- if (canvas.valuePropositions.length === 0) {
70
- missingBlocks.push('valuePropositions')
71
- }
72
-
73
- if (canvas.channels.length === 0) {
74
- missingBlocks.push('channels')
75
- }
76
-
77
- if (canvas.customerRelationships.length === 0) {
78
- missingBlocks.push('customerRelationships')
79
- }
80
-
81
- if (canvas.revenueStreams.length === 0) {
82
- missingBlocks.push('revenueStreams')
83
- }
84
-
85
- if (canvas.keyResources.length === 0) {
86
- missingBlocks.push('keyResources')
87
- }
88
-
89
- if (canvas.keyActivities.length === 0) {
90
- missingBlocks.push('keyActivities')
91
- }
92
-
93
- if (canvas.keyPartnerships.length === 0) {
94
- missingBlocks.push('keyPartnerships')
95
- }
96
-
97
- if (canvas.costStructure.length === 0) {
98
- missingBlocks.push('costStructure')
99
- }
100
-
101
- // Add warnings for incomplete data
102
- if (canvas.customerSegments.some(s => !s.size)) {
103
- warnings.push('Some customer segments are missing size estimates')
104
- }
105
-
106
- if (canvas.revenueStreams.some(r => !r.price && !r.pricePerUnit)) {
107
- warnings.push('Some revenue streams are missing pricing information')
108
- }
109
-
110
- return {
111
- isComplete: missingBlocks.length === 0,
112
- missingBlocks,
113
- warnings,
114
- }
115
- }
116
-
117
- /**
118
- * Generate canvas summary with key metrics
119
- */
120
- export function generateCanvasSummary(canvas: BusinessModelCanvas): CanvasSummary {
121
- // Calculate Total Addressable Market (TAM)
122
- const totalAddressableMarket = canvas.customerSegments.reduce((sum, segment) => {
123
- if (segment.size && segment.revenuePerCustomer) {
124
- return sum + segment.size * segment.revenuePerCustomer
125
- }
126
- return sum
127
- }, 0)
128
-
129
- // Calculate projected annual revenue from revenue streams
130
- const projectedAnnualRevenue = canvas.revenueStreams.reduce((sum, stream) => {
131
- return sum + (stream.annualRevenue ?? 0)
132
- }, 0)
133
-
134
- // Calculate total annual costs
135
- const totalAnnualCosts = canvas.costStructure.reduce((sum, cost) => {
136
- if (cost.amount) {
137
- // Normalize to annual
138
- const multiplier = cost.period === 'monthly' ? 12 : cost.period === 'quarterly' ? 4 : 1
139
- return sum + cost.amount * multiplier
140
- }
141
- if (cost.estimatedTotal) {
142
- return sum + cost.estimatedTotal
143
- }
144
- return sum
145
- }, 0)
146
-
147
- // Calculate projected profit
148
- const projectedProfit = projectedAnnualRevenue - totalAnnualCosts
149
-
150
- return {
151
- totalAddressableMarket,
152
- projectedAnnualRevenue,
153
- totalAnnualCosts,
154
- projectedProfit,
155
- }
156
- }
157
-
158
- /**
159
- * Analyze canvas strength
160
- */
161
- export function analyzeCanvasStrength(canvas: BusinessModelCanvas): CanvasStrengthAnalysis {
162
- const blockScores: Record<string, number> = {}
163
- const strengths: string[] = []
164
- const weaknesses: string[] = []
165
-
166
- // Score customer segments (0-100)
167
- const segmentScore = scoreCustomerSegments(canvas.customerSegments)
168
- blockScores['customerSegments'] = segmentScore
169
- if (segmentScore >= 70) {
170
- strengths.push('Well-defined customer segments')
171
- } else if (segmentScore < 40) {
172
- weaknesses.push('Customer segments need more definition')
173
- }
174
-
175
- // Score value propositions
176
- const valueScore = scoreValuePropositions(canvas.valuePropositions)
177
- blockScores['valuePropositions'] = valueScore
178
- if (valueScore >= 70) {
179
- strengths.push('Strong value propositions')
180
- } else if (valueScore < 40) {
181
- weaknesses.push('Value propositions need strengthening')
182
- }
183
-
184
- // Score channels
185
- const channelScore = scoreChannels(canvas.channels)
186
- blockScores['channels'] = channelScore
187
- if (channelScore >= 70) {
188
- strengths.push('Diverse channel strategy')
189
- } else if (channelScore < 40) {
190
- weaknesses.push('Limited channel coverage')
191
- }
192
-
193
- // Score relationships
194
- const relationshipScore = scoreRelationships(canvas.customerRelationships)
195
- blockScores['customerRelationships'] = relationshipScore
196
- if (relationshipScore >= 70) {
197
- strengths.push('Strong customer relationship strategy')
198
- } else if (relationshipScore < 40) {
199
- weaknesses.push('Customer relationship strategy needs work')
200
- }
201
-
202
- // Score revenue streams
203
- const revenueScore = scoreRevenueStreams(canvas.revenueStreams)
204
- blockScores['revenueStreams'] = revenueScore
205
- if (revenueScore >= 70) {
206
- strengths.push('Solid revenue model')
207
- } else if (revenueScore < 40) {
208
- weaknesses.push('Revenue model needs development')
209
- }
210
-
211
- // Score resources
212
- const resourceScore = scoreResources(canvas.keyResources)
213
- blockScores['keyResources'] = resourceScore
214
- if (resourceScore >= 70) {
215
- strengths.push('Strong resource base')
216
- } else if (resourceScore < 40) {
217
- weaknesses.push('Key resources are lacking')
218
- }
219
-
220
- // Score activities
221
- const activityScore = scoreActivities(canvas.keyActivities)
222
- blockScores['keyActivities'] = activityScore
223
- if (activityScore >= 70) {
224
- strengths.push('Clear key activities')
225
- } else if (activityScore < 40) {
226
- weaknesses.push('Key activities need clarification')
227
- }
228
-
229
- // Score partnerships
230
- const partnershipScore = scorePartnerships(canvas.keyPartnerships)
231
- blockScores['keyPartnerships'] = partnershipScore
232
- if (partnershipScore >= 70) {
233
- strengths.push('Strong partnership ecosystem')
234
- } else if (partnershipScore < 40) {
235
- weaknesses.push('Partnership strategy needs development')
236
- }
237
-
238
- // Score cost structure
239
- const costScore = scoreCostStructure(canvas.costStructure)
240
- blockScores['costStructure'] = costScore
241
- if (costScore >= 70) {
242
- strengths.push('Well-understood cost structure')
243
- } else if (costScore < 40) {
244
- weaknesses.push('Cost structure needs more detail')
245
- }
246
-
247
- // Calculate overall score
248
- const scores = Object.values(blockScores)
249
- const overallScore = scores.reduce((sum, s) => sum + s, 0) / scores.length
250
-
251
- return {
252
- overallScore,
253
- strengths,
254
- weaknesses,
255
- blockScores,
256
- }
257
- }
258
-
259
- /**
260
- * Identify gaps in the canvas
261
- */
262
- export function identifyCanvasGaps(canvas: BusinessModelCanvas): CanvasGaps {
263
- const criticalGaps: string[] = []
264
- const warnings: string[] = []
265
- const recommendations: string[] = []
266
-
267
- // Check for critical gaps (empty building blocks)
268
- if (canvas.valuePropositions.length === 0) {
269
- criticalGaps.push('valuePropositions')
270
- recommendations.push('Define at least one clear value proposition for your target customers')
271
- }
272
-
273
- if (canvas.customerSegments.length === 0) {
274
- criticalGaps.push('customerSegments')
275
- recommendations.push('Identify and define your target customer segments')
276
- }
277
-
278
- if (canvas.revenueStreams.length === 0) {
279
- criticalGaps.push('revenueStreams')
280
- recommendations.push('Define how you will generate revenue from your customers')
281
- }
282
-
283
- if (canvas.customerRelationships.length === 0) {
284
- criticalGaps.push('customerRelationships')
285
- recommendations.push('Define how you will acquire, retain, and grow customer relationships')
286
- }
287
-
288
- if (canvas.keyResources.length === 0) {
289
- criticalGaps.push('keyResources')
290
- recommendations.push('Identify the key resources required to deliver your value proposition')
291
- }
292
-
293
- if (canvas.keyActivities.length === 0) {
294
- criticalGaps.push('keyActivities')
295
- recommendations.push('Define the key activities required to operate your business')
296
- }
297
-
298
- if (canvas.keyPartnerships.length === 0) {
299
- criticalGaps.push('keyPartnerships')
300
- recommendations.push('Consider strategic partnerships that could enhance your business')
301
- }
302
-
303
- if (canvas.channels.length === 0) {
304
- criticalGaps.push('channels')
305
- recommendations.push('Define channels to reach and serve your customers')
306
- }
307
-
308
- if (canvas.costStructure.length === 0) {
309
- criticalGaps.push('costStructure')
310
- recommendations.push('Map out your cost structure to understand your business economics')
311
- }
312
-
313
- // Check for warnings (incomplete data)
314
- const hasRecurringRevenue = canvas.revenueStreams.some(r => r.type === 'recurring')
315
- if (!hasRecurringRevenue && canvas.revenueStreams.length > 0) {
316
- warnings.push('No recurring revenue streams - consider subscription or usage-based models')
317
- recommendations.push('Explore recurring revenue models for more predictable cash flow')
318
- }
319
-
320
- const hasIntellectualProperty = canvas.keyResources.some(r => r.type === 'intellectual')
321
- if (!hasIntellectualProperty && canvas.keyResources.length > 0) {
322
- warnings.push('No intellectual property identified - consider what makes your offering unique')
323
- recommendations.push('Identify and protect your intellectual property assets')
324
- }
325
-
326
- return {
327
- criticalGaps,
328
- warnings,
329
- recommendations,
330
- }
331
- }
332
-
333
- // =============================================================================
334
- // Helper scoring functions
335
- // =============================================================================
336
-
337
- function scoreCustomerSegments(segments: CustomerSegment[]): number {
338
- if (segments.length === 0) return 0
339
- let score = 30 // Base score for having segments
340
-
341
- // Add points for segment details
342
- const hasSize = segments.some(s => s.size)
343
- const hasRevenue = segments.some(s => s.revenuePerCustomer)
344
- const hasCharacteristics = segments.some(s => s.characteristics && s.characteristics.length > 0)
345
-
346
- if (hasSize) score += 20
347
- if (hasRevenue) score += 25
348
- if (hasCharacteristics) score += 15
349
-
350
- // Bonus for multiple segments
351
- if (segments.length >= 2) score += 10
352
-
353
- return Math.min(score, 100)
354
- }
355
-
356
- function scoreValuePropositions(props: ValueProposition[]): number {
357
- if (props.length === 0) return 0
358
- let score = 30
359
-
360
- const hasBenefits = props.some(p => p.benefits.length >= 2)
361
- const hasValueType = props.some(p => p.valueType)
362
- const hasSegmentFit = props.some(p => p.segmentFit)
363
- const hasQuantified = props.some(p => p.quantifiedValue)
364
-
365
- if (hasBenefits) score += 20
366
- if (hasValueType) score += 15
367
- if (hasSegmentFit) score += 20
368
- if (hasQuantified) score += 15
369
-
370
- return Math.min(score, 100)
371
- }
372
-
373
- function scoreChannels(channels: Channel[]): number {
374
- if (channels.length === 0) return 0
375
- let score = 30
376
-
377
- const hasPhases = channels.some(c => c.phases && c.phases.length > 0)
378
- const hasCost = channels.some(c => c.costPerAcquisition)
379
- const hasMultipleTypes = new Set(channels.map(c => c.type)).size >= 2
380
-
381
- if (hasPhases) score += 20
382
- if (hasCost) score += 25
383
- if (hasMultipleTypes) score += 25
384
-
385
- return Math.min(score, 100)
386
- }
387
-
388
- function scoreRelationships(relationships: CustomerRelationship[]): number {
389
- if (relationships.length === 0) return 0
390
- let score = 40
391
-
392
- const hasAutomation = relationships.some(r => r.automationLevel)
393
- const hasSegment = relationships.some(r => r.segment)
394
- const hasMultipleTypes = new Set(relationships.map(r => r.type)).size >= 2
395
-
396
- if (hasAutomation) score += 20
397
- if (hasSegment) score += 20
398
- if (hasMultipleTypes) score += 20
399
-
400
- return Math.min(score, 100)
401
- }
402
-
403
- function scoreRevenueStreams(streams: RevenueStream[]): number {
404
- if (streams.length === 0) return 0
405
- let score = 30
406
-
407
- const hasRecurring = streams.some(s => s.type === 'recurring')
408
- const hasPrice = streams.some(s => s.price || s.pricePerUnit)
409
- const hasCustomers = streams.some(s => s.activeCustomers)
410
- const hasTiers = streams.some(s => s.tiers && s.tiers.length > 0)
411
-
412
- if (hasRecurring) score += 25
413
- if (hasPrice) score += 20
414
- if (hasCustomers) score += 15
415
- if (hasTiers) score += 10
416
-
417
- return Math.min(score, 100)
418
- }
419
-
420
- function scoreResources(resources: KeyResource[]): number {
421
- if (resources.length === 0) return 0
422
- let score = 30
423
-
424
- const hasIntellectual = resources.some(r => r.type === 'intellectual')
425
- const hasHuman = resources.some(r => r.type === 'human')
426
- const hasCost = resources.some(r => r.totalCost || r.cost)
427
- const hasMultipleTypes = new Set(resources.map(r => r.type)).size >= 2
428
-
429
- if (hasIntellectual) score += 20
430
- if (hasHuman) score += 15
431
- if (hasCost) score += 20
432
- if (hasMultipleTypes) score += 15
433
-
434
- return Math.min(score, 100)
435
- }
436
-
437
- function scoreActivities(activities: KeyActivity[]): number {
438
- if (activities.length === 0) return 0
439
- let score = 40
440
-
441
- const hasResources = activities.some(a => a.resources && a.resources.length > 0)
442
- const hasMetrics = activities.some(a => a.metrics && a.metrics.length > 0)
443
- const hasDescription = activities.some(a => a.description)
444
-
445
- if (hasResources) score += 20
446
- if (hasMetrics) score += 25
447
- if (hasDescription) score += 15
448
-
449
- return Math.min(score, 100)
450
- }
451
-
452
- function scorePartnerships(partnerships: KeyPartnership[]): number {
453
- if (partnerships.length === 0) return 0
454
- let score = 40
455
-
456
- const hasBenefits = partnerships.some(p => p.benefits && p.benefits.length > 0)
457
- const hasPurpose = partnerships.some(p => p.purpose)
458
- const hasContract = partnerships.some(p => p.contractValue)
459
-
460
- if (hasBenefits) score += 20
461
- if (hasPurpose) score += 20
462
- if (hasContract) score += 20
463
-
464
- return Math.min(score, 100)
465
- }
466
-
467
- function scoreCostStructure(costs: CostItem[]): number {
468
- if (costs.length === 0) return 0
469
- let score = 30
470
-
471
- const hasFixed = costs.some(c => c.category === 'fixed')
472
- const hasVariable = costs.some(c => c.category === 'variable')
473
- const hasAmounts = costs.some(c => c.amount || c.estimatedTotal)
474
- const hasPeriod = costs.some(c => c.period)
475
-
476
- if (hasFixed) score += 15
477
- if (hasVariable) score += 20
478
- if (hasAmounts) score += 25
479
- if (hasPeriod) score += 10
480
-
481
- return Math.min(score, 100)
482
- }
@@ -1,34 +0,0 @@
1
- /**
2
- * Channels
3
- *
4
- * Functions for creating and working with channels.
5
- */
6
-
7
- import type { Channel, ChannelType, ChannelPhase } from './types.js'
8
-
9
- export interface CreateChannelInput {
10
- name: string
11
- type: ChannelType
12
- phases?: ChannelPhase[]
13
- costPerAcquisition?: number
14
- partnerType?: string
15
- revenueShare?: number
16
- conversionRate?: number
17
- }
18
-
19
- /**
20
- * Create a channel
21
- */
22
- export function createChannel(input: CreateChannelInput): Channel {
23
- const { name, type, phases, costPerAcquisition, partnerType, revenueShare, conversionRate } = input
24
-
25
- return {
26
- name,
27
- type,
28
- phases,
29
- costPerAcquisition,
30
- partnerType,
31
- revenueShare,
32
- conversionRate,
33
- }
34
- }
@@ -1,43 +0,0 @@
1
- /**
2
- * Cost Structure
3
- *
4
- * Functions for creating and working with cost items.
5
- */
6
-
7
- import type { CostItem, CostCategory } from './types.js'
8
-
9
- export interface CreateCostItemInput {
10
- name: string
11
- category: CostCategory
12
- amount?: number
13
- period?: 'monthly' | 'quarterly' | 'annual'
14
- unitCost?: number
15
- unitName?: string
16
- volumeEstimate?: number
17
- }
18
-
19
- /**
20
- * Create a cost item
21
- */
22
- export function createCostItem(input: CreateCostItemInput): CostItem {
23
- const { name, category, amount, period, unitCost, unitName, volumeEstimate } = input
24
-
25
- // Calculate estimated total for variable costs
26
- let estimatedTotal: number | undefined
27
- if (unitCost !== undefined && volumeEstimate !== undefined) {
28
- estimatedTotal = unitCost * volumeEstimate
29
- } else if (amount !== undefined) {
30
- estimatedTotal = amount
31
- }
32
-
33
- return {
34
- name,
35
- category,
36
- amount,
37
- period,
38
- unitCost,
39
- unitName,
40
- volumeEstimate,
41
- estimatedTotal,
42
- }
43
- }
@@ -1,99 +0,0 @@
1
- /**
2
- * Unit Economics
3
- *
4
- * Functions for calculating unit economics: LTV, CAC, margins, etc.
5
- */
6
-
7
- import type {
8
- UnitEconomics,
9
- LTVInput,
10
- CACInput,
11
- UnitEconomicsInput,
12
- Margins,
13
- MarginsInput,
14
- } from './types.js'
15
-
16
- /**
17
- * Calculate Customer Lifetime Value (LTV)
18
- *
19
- * LTV = ARPU * Gross Margin / Churn Rate
20
- */
21
- export function calculateLTV(input: LTVInput): number {
22
- const { averageRevenuePerUser, grossMargin, churnRate } = input
23
-
24
- if (churnRate === 0) {
25
- return Infinity
26
- }
27
-
28
- return (averageRevenuePerUser * grossMargin) / churnRate
29
- }
30
-
31
- /**
32
- * Calculate Customer Acquisition Cost (CAC)
33
- *
34
- * CAC = (Marketing Spend + Sales Spend) / New Customers
35
- */
36
- export function calculateCAC(input: CACInput): number {
37
- const { marketingSpend, salesSpend, newCustomers } = input
38
-
39
- if (newCustomers === 0) {
40
- return 0
41
- }
42
-
43
- return (marketingSpend + salesSpend) / newCustomers
44
- }
45
-
46
- /**
47
- * Calculate comprehensive unit economics
48
- */
49
- export function calculateUnitEconomics(input: UnitEconomicsInput): UnitEconomics {
50
- const ltv = calculateLTV({
51
- averageRevenuePerUser: input.averageRevenuePerUser,
52
- grossMargin: input.grossMargin,
53
- churnRate: input.churnRate,
54
- })
55
-
56
- const cac = calculateCAC({
57
- marketingSpend: input.marketingSpend,
58
- salesSpend: input.salesSpend,
59
- newCustomers: input.newCustomers,
60
- })
61
-
62
- const ltvCacRatio = cac === 0 ? 0 : ltv / cac
63
-
64
- // Payback months = CAC / (ARPU * Gross Margin)
65
- const monthlyGrossProfit = input.averageRevenuePerUser * input.grossMargin
66
- const paybackMonths = monthlyGrossProfit === 0 ? Infinity : cac / monthlyGrossProfit
67
-
68
- return {
69
- ltv,
70
- cac,
71
- ltvCacRatio,
72
- paybackMonths,
73
- }
74
- }
75
-
76
- /**
77
- * Calculate margins
78
- */
79
- export function calculateMargins(input: MarginsInput): Margins {
80
- const { revenue, cogs, operatingExpenses, taxes = 0 } = input
81
-
82
- const grossProfit = revenue - cogs
83
- const grossMargin = revenue === 0 ? 0 : grossProfit / revenue
84
-
85
- const operatingIncome = grossProfit - operatingExpenses
86
- const operatingMargin = revenue === 0 ? 0 : operatingIncome / revenue
87
-
88
- const netIncome = operatingIncome - taxes
89
- const netMargin = revenue === 0 ? 0 : netIncome / revenue
90
-
91
- return {
92
- grossMargin,
93
- grossProfit,
94
- operatingMargin,
95
- operatingIncome,
96
- netMargin,
97
- netIncome,
98
- }
99
- }