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.
Files changed (260) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +2 -0
  3. package/package.json +16 -13
  4. package/src/dollar.ts +5 -2
  5. package/src/entities/organization.ts +31 -18
  6. package/src/goals.ts +78 -12
  7. package/src/index.ts +48 -18
  8. package/src/kpis.ts +62 -8
  9. package/src/metrics.ts +92 -79
  10. package/src/okrs.ts +120 -20
  11. package/src/organization.ts +12 -15
  12. package/src/process.ts +11 -12
  13. package/src/product.ts +8 -9
  14. package/src/queries.ts +238 -75
  15. package/src/roles.ts +62 -61
  16. package/src/workflow.ts +22 -15
  17. package/test/business.test.ts +282 -0
  18. package/test/dollar.test.ts +270 -0
  19. package/test/entities.test.ts +628 -0
  20. package/test/financials.test.ts +539 -0
  21. package/test/goals.test.ts +451 -0
  22. package/{src → test}/index.test.ts +1 -1
  23. package/test/kpis.test.ts +440 -0
  24. package/test/metrics.test.ts +744 -0
  25. package/test/okrs.test.ts +741 -0
  26. package/test/organization.test.ts +548 -0
  27. package/test/process.test.ts +503 -0
  28. package/test/product.test.ts +430 -0
  29. package/test/queries.test.ts +556 -0
  30. package/test/roles.test.ts +546 -0
  31. package/test/service.test.ts +450 -0
  32. package/test/types.test.ts +1141 -0
  33. package/test/vision.test.ts +214 -0
  34. package/test/workflow.test.ts +501 -0
  35. package/vitest.config.ts +47 -0
  36. package/.turbo/turbo-build.log +0 -5
  37. package/LICENSE +0 -21
  38. package/dist/business.d.ts +0 -62
  39. package/dist/business.d.ts.map +0 -1
  40. package/dist/business.js +0 -109
  41. package/dist/business.js.map +0 -1
  42. package/dist/canvas/activities.d.ts +0 -19
  43. package/dist/canvas/activities.d.ts.map +0 -1
  44. package/dist/canvas/activities.js +0 -20
  45. package/dist/canvas/activities.js.map +0 -1
  46. package/dist/canvas/channels.d.ts +0 -20
  47. package/dist/canvas/channels.d.ts.map +0 -1
  48. package/dist/canvas/channels.js +0 -21
  49. package/dist/canvas/channels.js.map +0 -1
  50. package/dist/canvas/relationships.d.ts +0 -20
  51. package/dist/canvas/relationships.d.ts.map +0 -1
  52. package/dist/canvas/relationships.js +0 -21
  53. package/dist/canvas/relationships.js.map +0 -1
  54. package/dist/canvas/resources.d.ts +0 -20
  55. package/dist/canvas/resources.d.ts.map +0 -1
  56. package/dist/canvas/resources.js +0 -30
  57. package/dist/canvas/resources.js.map +0 -1
  58. package/dist/canvas/revenue.d.ts +0 -22
  59. package/dist/canvas/revenue.d.ts.map +0 -1
  60. package/dist/canvas/revenue.js +0 -30
  61. package/dist/canvas/revenue.js.map +0 -1
  62. package/dist/canvas/segments.d.ts +0 -20
  63. package/dist/canvas/segments.d.ts.map +0 -1
  64. package/dist/canvas/segments.js +0 -28
  65. package/dist/canvas/segments.js.map +0 -1
  66. package/dist/canvas/types.d.ts +0 -232
  67. package/dist/canvas/types.d.ts.map +0 -1
  68. package/dist/canvas/types.js +0 -8
  69. package/dist/canvas/types.js.map +0 -1
  70. package/dist/canvas/value.d.ts +0 -20
  71. package/dist/canvas/value.d.ts.map +0 -1
  72. package/dist/canvas/value.js +0 -21
  73. package/dist/canvas/value.js.map +0 -1
  74. package/dist/dollar.d.ts +0 -60
  75. package/dist/dollar.d.ts.map +0 -1
  76. package/dist/dollar.js +0 -107
  77. package/dist/dollar.js.map +0 -1
  78. package/dist/entities/assets.d.ts +0 -21
  79. package/dist/entities/assets.d.ts.map +0 -1
  80. package/dist/entities/assets.js +0 -323
  81. package/dist/entities/assets.js.map +0 -1
  82. package/dist/entities/business.d.ts +0 -36
  83. package/dist/entities/business.d.ts.map +0 -1
  84. package/dist/entities/business.js +0 -370
  85. package/dist/entities/business.js.map +0 -1
  86. package/dist/entities/communication.d.ts +0 -21
  87. package/dist/entities/communication.d.ts.map +0 -1
  88. package/dist/entities/communication.js +0 -255
  89. package/dist/entities/communication.js.map +0 -1
  90. package/dist/entities/customers.d.ts +0 -58
  91. package/dist/entities/customers.d.ts.map +0 -1
  92. package/dist/entities/customers.js +0 -989
  93. package/dist/entities/customers.js.map +0 -1
  94. package/dist/entities/financials.d.ts +0 -59
  95. package/dist/entities/financials.d.ts.map +0 -1
  96. package/dist/entities/financials.js +0 -932
  97. package/dist/entities/financials.js.map +0 -1
  98. package/dist/entities/goals.d.ts +0 -58
  99. package/dist/entities/goals.d.ts.map +0 -1
  100. package/dist/entities/goals.js +0 -800
  101. package/dist/entities/goals.js.map +0 -1
  102. package/dist/entities/index.d.ts +0 -299
  103. package/dist/entities/index.d.ts.map +0 -1
  104. package/dist/entities/index.js +0 -198
  105. package/dist/entities/index.js.map +0 -1
  106. package/dist/entities/legal.d.ts +0 -21
  107. package/dist/entities/legal.d.ts.map +0 -1
  108. package/dist/entities/legal.js +0 -301
  109. package/dist/entities/legal.js.map +0 -1
  110. package/dist/entities/market.d.ts +0 -21
  111. package/dist/entities/market.d.ts.map +0 -1
  112. package/dist/entities/market.js +0 -301
  113. package/dist/entities/market.js.map +0 -1
  114. package/dist/entities/marketing.d.ts +0 -67
  115. package/dist/entities/marketing.d.ts.map +0 -1
  116. package/dist/entities/marketing.js +0 -1157
  117. package/dist/entities/marketing.js.map +0 -1
  118. package/dist/entities/offerings.d.ts +0 -51
  119. package/dist/entities/offerings.d.ts.map +0 -1
  120. package/dist/entities/offerings.js +0 -727
  121. package/dist/entities/offerings.js.map +0 -1
  122. package/dist/entities/operations.d.ts +0 -58
  123. package/dist/entities/operations.d.ts.map +0 -1
  124. package/dist/entities/operations.js +0 -787
  125. package/dist/entities/operations.js.map +0 -1
  126. package/dist/entities/organization.d.ts +0 -57
  127. package/dist/entities/organization.d.ts.map +0 -1
  128. package/dist/entities/organization.js +0 -807
  129. package/dist/entities/organization.js.map +0 -1
  130. package/dist/entities/partnerships.d.ts +0 -21
  131. package/dist/entities/partnerships.d.ts.map +0 -1
  132. package/dist/entities/partnerships.js +0 -300
  133. package/dist/entities/partnerships.js.map +0 -1
  134. package/dist/entities/planning.d.ts +0 -0
  135. package/dist/entities/planning.d.ts.map +0 -1
  136. package/dist/entities/planning.js +0 -271
  137. package/dist/entities/planning.js.map +0 -1
  138. package/dist/entities/projects.d.ts +0 -25
  139. package/dist/entities/projects.d.ts.map +0 -1
  140. package/dist/entities/projects.js +0 -349
  141. package/dist/entities/projects.js.map +0 -1
  142. package/dist/entities/risk.d.ts +0 -21
  143. package/dist/entities/risk.d.ts.map +0 -1
  144. package/dist/entities/risk.js +0 -293
  145. package/dist/entities/risk.js.map +0 -1
  146. package/dist/entities/sales.d.ts +0 -72
  147. package/dist/entities/sales.d.ts.map +0 -1
  148. package/dist/entities/sales.js +0 -1248
  149. package/dist/entities/sales.js.map +0 -1
  150. package/dist/financials.d.ts +0 -130
  151. package/dist/financials.d.ts.map +0 -1
  152. package/dist/financials.js +0 -297
  153. package/dist/financials.js.map +0 -1
  154. package/dist/goals.d.ts +0 -87
  155. package/dist/goals.d.ts.map +0 -1
  156. package/dist/goals.js +0 -215
  157. package/dist/goals.js.map +0 -1
  158. package/dist/index.d.ts +0 -97
  159. package/dist/index.d.ts.map +0 -1
  160. package/dist/index.js +0 -132
  161. package/dist/index.js.map +0 -1
  162. package/dist/kpis.d.ts +0 -118
  163. package/dist/kpis.d.ts.map +0 -1
  164. package/dist/kpis.js +0 -232
  165. package/dist/kpis.js.map +0 -1
  166. package/dist/metrics.d.ts +0 -448
  167. package/dist/metrics.d.ts.map +0 -1
  168. package/dist/metrics.js +0 -325
  169. package/dist/metrics.js.map +0 -1
  170. package/dist/okrs.d.ts +0 -123
  171. package/dist/okrs.d.ts.map +0 -1
  172. package/dist/okrs.js +0 -269
  173. package/dist/okrs.js.map +0 -1
  174. package/dist/organization.d.ts +0 -585
  175. package/dist/organization.d.ts.map +0 -1
  176. package/dist/organization.js +0 -173
  177. package/dist/organization.js.map +0 -1
  178. package/dist/process.d.ts +0 -112
  179. package/dist/process.d.ts.map +0 -1
  180. package/dist/process.js +0 -241
  181. package/dist/process.js.map +0 -1
  182. package/dist/product.d.ts +0 -85
  183. package/dist/product.d.ts.map +0 -1
  184. package/dist/product.js +0 -145
  185. package/dist/product.js.map +0 -1
  186. package/dist/queries.d.ts +0 -304
  187. package/dist/queries.d.ts.map +0 -1
  188. package/dist/queries.js +0 -415
  189. package/dist/queries.js.map +0 -1
  190. package/dist/roles.d.ts +0 -340
  191. package/dist/roles.d.ts.map +0 -1
  192. package/dist/roles.js +0 -255
  193. package/dist/roles.js.map +0 -1
  194. package/dist/service.d.ts +0 -61
  195. package/dist/service.d.ts.map +0 -1
  196. package/dist/service.js +0 -140
  197. package/dist/service.js.map +0 -1
  198. package/dist/types.d.ts +0 -459
  199. package/dist/types.d.ts.map +0 -1
  200. package/dist/types.js +0 -5
  201. package/dist/types.js.map +0 -1
  202. package/dist/vision.d.ts +0 -38
  203. package/dist/vision.d.ts.map +0 -1
  204. package/dist/vision.js +0 -68
  205. package/dist/vision.js.map +0 -1
  206. package/dist/workflow.d.ts +0 -115
  207. package/dist/workflow.d.ts.map +0 -1
  208. package/dist/workflow.js +0 -247
  209. package/dist/workflow.js.map +0 -1
  210. package/src/business.js +0 -108
  211. package/src/canvas/activities.ts +0 -32
  212. package/src/canvas/canvas.ts +0 -482
  213. package/src/canvas/channels.ts +0 -34
  214. package/src/canvas/costs.ts +0 -43
  215. package/src/canvas/economics.ts +0 -99
  216. package/src/canvas/index.ts +0 -206
  217. package/src/canvas/partnerships.ts +0 -34
  218. package/src/canvas/projections.ts +0 -141
  219. package/src/canvas/relationships.ts +0 -34
  220. package/src/canvas/resources.ts +0 -43
  221. package/src/canvas/revenue.ts +0 -56
  222. package/src/canvas/segments.ts +0 -42
  223. package/src/canvas/types.ts +0 -363
  224. package/src/canvas/value.ts +0 -34
  225. package/src/dollar.js +0 -106
  226. package/src/entities/assets.js +0 -322
  227. package/src/entities/business.js +0 -369
  228. package/src/entities/communication.js +0 -254
  229. package/src/entities/customers.js +0 -988
  230. package/src/entities/financials.js +0 -931
  231. package/src/entities/goals.js +0 -799
  232. package/src/entities/index.js +0 -197
  233. package/src/entities/legal.js +0 -300
  234. package/src/entities/market.js +0 -300
  235. package/src/entities/marketing.js +0 -1156
  236. package/src/entities/offerings.js +0 -726
  237. package/src/entities/operations.js +0 -786
  238. package/src/entities/organization.js +0 -806
  239. package/src/entities/partnerships.js +0 -299
  240. package/src/entities/planning.js +0 -270
  241. package/src/entities/projects.js +0 -348
  242. package/src/entities/risk.js +0 -292
  243. package/src/entities/sales.js +0 -1247
  244. package/src/financials.js +0 -296
  245. package/src/goals.js +0 -214
  246. package/src/index.js +0 -131
  247. package/src/index.test.js +0 -274
  248. package/src/kpis.js +0 -231
  249. package/src/metrics.js +0 -324
  250. package/src/okrs.js +0 -268
  251. package/src/organization.js +0 -172
  252. package/src/process.js +0 -240
  253. package/src/product.js +0 -144
  254. package/src/queries.js +0 -414
  255. package/src/roles.js +0 -254
  256. package/src/service.js +0 -139
  257. package/src/types.js +0 -4
  258. package/src/vision.js +0 -67
  259. package/src/workflow.js +0 -246
  260. 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
- }