Files
breakpilot-core/pitch-deck/lib/finanzplan/annual-kpis.ts
Benjamin Admin 06f868abeb
Some checks failed
Build pitch-deck / build-push-deploy (push) Failing after 40s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 37s
CI / test-python-voice (push) Successful in 36s
CI / test-bqas (push) Successful in 33s
fix(pitch-deck): replace all hardcoded financial numbers with computed values
All financial data now flows from the same compute engine (useFinancialModel).
No more hardcoded numbers in any slide — all values are derived from the
finanzplan database, ensuring consistency across all pitch deck versions.

- FinanzplanSlide: KPI table + charts now use computeAnnualKPIs() from FMResult[]
- BusinessModelSlide: bottom-up calc (customers × ACV = ARR) from compute engine
- AssumptionsSlide: Base case from compute, Bear/Bull scaled from Base
- New helper: lib/finanzplan/annual-kpis.ts for 60-month → 5-year aggregation
- PitchDeck: passes investorId to all financial slides for version-aware data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 08:48:37 +02:00

90 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { FMResult } from '../types'
export interface AnnualKPI {
year: number
mrr: number
arr: number
customers: number
arpu: number
employees: number
revenuePerEmployee: number
personnelCosts: number
totalRevenue: number
totalCosts: number
ebit: number
ebitMargin: number
taxes: number
netIncome: number
serverCostPerCustomer: number
grossMargin: number
burnRate: number
runway: number | null
cashBalance: number
}
const TAX_RATE = 0.30 // ~30% Körperschaftsteuer + Gewerbesteuer + Soli
/**
* Aggregates 60 monthly FMResult entries into 5 annual KPI rows (20262030).
* All values are derived — nothing is hardcoded.
*/
export function computeAnnualKPIs(results: FMResult[]): AnnualKPI[] {
if (!results || results.length === 0) return []
const years = [2026, 2027, 2028, 2029, 2030]
return years.map(year => {
const yearResults = results.filter(r => r.year === year)
if (yearResults.length === 0) {
return emptyKPI(year)
}
const dec = yearResults[yearResults.length - 1] // December snapshot
const totalRevenue = yearResults.reduce((s, r) => s + r.revenue_eur, 0)
const personnelCosts = yearResults.reduce((s, r) => s + r.personnel_eur, 0)
const totalCogs = yearResults.reduce((s, r) => s + r.cogs_eur, 0)
const totalInfra = yearResults.reduce((s, r) => s + r.infra_eur, 0)
const totalMarketing = yearResults.reduce((s, r) => s + r.marketing_eur, 0)
const totalCosts = yearResults.reduce((s, r) => s + r.total_costs_eur, 0)
const ebit = totalRevenue - totalCosts
const ebitMargin = totalRevenue > 0 ? (ebit / totalRevenue) * 100 : 0
const taxes = ebit > 0 ? Math.round(ebit * TAX_RATE) : 0
const netIncome = ebit - taxes
const serverCost = dec.total_customers > 0
? Math.round((totalInfra / 12) / dec.total_customers)
: 0
return {
year,
mrr: Math.round(dec.mrr_eur),
arr: Math.round(dec.arr_eur),
customers: Math.round(dec.total_customers),
arpu: dec.total_customers > 0 ? Math.round(dec.mrr_eur / dec.total_customers) : 0,
employees: Math.round(dec.employees_count),
revenuePerEmployee: dec.employees_count > 0 ? Math.round(totalRevenue / dec.employees_count) : 0,
personnelCosts: Math.round(personnelCosts),
totalRevenue: Math.round(totalRevenue),
totalCosts: Math.round(totalCosts),
ebit: Math.round(ebit),
ebitMargin: Math.round(ebitMargin),
taxes,
netIncome: Math.round(netIncome),
serverCostPerCustomer: serverCost,
grossMargin: Math.round(dec.gross_margin_pct),
burnRate: Math.round(dec.burn_rate_eur),
runway: dec.runway_months > 999 ? null : Math.round(dec.runway_months),
cashBalance: Math.round(dec.cash_balance_eur),
}
})
}
function emptyKPI(year: number): AnnualKPI {
return {
year, mrr: 0, arr: 0, customers: 0, arpu: 0, employees: 0,
revenuePerEmployee: 0, personnelCosts: 0, totalRevenue: 0, totalCosts: 0,
ebit: 0, ebitMargin: 0, taxes: 0, netIncome: 0,
serverCostPerCustomer: 0, grossMargin: 0, burnRate: 0, runway: null, cashBalance: 0,
}
}