Demo MCP App for SaaS financial planning with: - Interactive sliders for MRR, growth, churn, margin, and costs - 12-month projection charts (MRR, Gross Profit, Net Profit) - 5 pre-built scenario templates (Bootstrapped, VC Rocketship, etc.) - Template comparison overlay for strategy analysis - Light/dark theme support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
72 lines
1.7 KiB
TypeScript
72 lines
1.7 KiB
TypeScript
import type {
|
|
ScenarioInputs,
|
|
MonthlyProjection,
|
|
ScenarioSummary,
|
|
} from "../types.ts";
|
|
|
|
export function calculateProjections(
|
|
inputs: ScenarioInputs,
|
|
): MonthlyProjection[] {
|
|
const {
|
|
startingMRR,
|
|
monthlyGrowthRate,
|
|
monthlyChurnRate,
|
|
grossMargin,
|
|
fixedCosts,
|
|
} = inputs;
|
|
|
|
// Net growth rate (can be negative if churn > growth)
|
|
const netGrowthRate = (monthlyGrowthRate - monthlyChurnRate) / 100;
|
|
|
|
const projections: MonthlyProjection[] = [];
|
|
let cumulativeRevenue = 0;
|
|
|
|
for (let month = 1; month <= 12; month++) {
|
|
// MRR with compound growth
|
|
const mrr = startingMRR * Math.pow(1 + netGrowthRate, month);
|
|
|
|
// Profit calculations
|
|
const grossProfit = mrr * (grossMargin / 100);
|
|
const netProfit = grossProfit - fixedCosts;
|
|
|
|
// Cumulative revenue
|
|
cumulativeRevenue += mrr;
|
|
|
|
projections.push({
|
|
month,
|
|
mrr,
|
|
grossProfit,
|
|
netProfit,
|
|
cumulativeRevenue,
|
|
});
|
|
}
|
|
|
|
return projections;
|
|
}
|
|
|
|
export function calculateSummary(
|
|
projections: MonthlyProjection[],
|
|
inputs: ScenarioInputs,
|
|
): ScenarioSummary {
|
|
const endingMRR = projections[11].mrr;
|
|
const arr = endingMRR * 12;
|
|
const totalRevenue = projections.reduce((sum, p) => sum + p.mrr, 0);
|
|
const totalProfit = projections.reduce((sum, p) => sum + p.netProfit, 0);
|
|
const mrrGrowthPct =
|
|
((endingMRR - inputs.startingMRR) / inputs.startingMRR) * 100;
|
|
const avgMargin = (totalProfit / totalRevenue) * 100;
|
|
|
|
// Find first month where netProfit >= 0
|
|
const breakEvenProjection = projections.find((p) => p.netProfit >= 0);
|
|
const breakEvenMonth = breakEvenProjection?.month ?? null;
|
|
|
|
return {
|
|
endingMRR,
|
|
arr,
|
|
totalRevenue,
|
|
totalProfit,
|
|
mrrGrowthPct,
|
|
avgMargin,
|
|
breakEvenMonth,
|
|
};
|
|
}
|