diff --git a/pitch-deck/components/slides/BusinessModelSlide.tsx b/pitch-deck/components/slides/BusinessModelSlide.tsx index db3d5fb..3e2620c 100644 --- a/pitch-deck/components/slides/BusinessModelSlide.tsx +++ b/pitch-deck/components/slides/BusinessModelSlide.tsx @@ -69,8 +69,8 @@ export default function BusinessModelSlide({ lang, isWandeldarlehen }: BusinessM const metrics = [ { icon: DollarSign, color: 'text-indigo-400', label: 'ACV (2030)', value: acvLabel, sub: de ? 'Durchschnittlicher Vertragswert (berechnet)' : 'Average Contract Value (computed)' }, { icon: TrendingUp, color: 'text-emerald-400', label: 'Gross Margin', value: `${Math.round(grossMargin)}%`, sub: de ? 'Cloud-native, keine Hardware-Kosten' : 'Cloud-native, no hardware costs' }, - { icon: Repeat, color: 'text-purple-400', label: 'NRR Ziel', value: '> 120%', sub: de ? 'Upsell: mehr Module, mehr Nutzer' : 'Upsell: more modules, more users' }, - { icon: Target, color: 'text-amber-400', label: 'Payback', value: de ? '< 3 Monate' : '< 3 Months', sub: de ? 'Ersparnis übersteigt Kosten ab Q1' : 'Savings exceed costs from Q1' }, + { icon: Repeat, color: 'text-purple-400', label: 'NRR (2030)', value: last?.nrr ? `${last.nrr}%` : '—', sub: de ? 'Umsatzwachstum Bestandskunden (berechnet)' : 'Revenue growth existing customers (computed)' }, + { icon: Target, color: 'text-amber-400', label: de ? 'Payback (2030)' : 'Payback (2030)', value: last?.paybackMonths ? `${last.paybackMonths} ${de ? 'Mon.' : 'mo.'}` : '—', sub: de ? 'CAC / monatlicher Deckungsbeitrag (berechnet)' : 'CAC / monthly contribution margin (computed)' }, ] return ( diff --git a/pitch-deck/lib/hooks/useFpKPIs.ts b/pitch-deck/lib/hooks/useFpKPIs.ts index f19d48b..e7de914 100644 --- a/pitch-deck/lib/hooks/useFpKPIs.ts +++ b/pitch-deck/lib/hooks/useFpKPIs.ts @@ -17,6 +17,8 @@ export interface FpAnnualKPIs { revPerEmp: number ebitMargin: number grossMargin: number + nrr: number // Net Revenue Retention % + paybackMonths: number // CAC Payback Period in months } interface SheetRow { @@ -75,7 +77,24 @@ export function useFpKPIs(isWandeldarlehen?: boolean) { const ebitMargin = revenue > 0 ? Math.round((ebit / revenue) * 100) : 0 const grossMargin = revenue > 0 ? Math.round(((revenue - (findGuv('Summe Materialaufwand')?.values?.[yk] || 0)) / revenue) * 100) : 0 - result[yk] = { revenue, ebit, personal, netIncome, steuern, liquiditaet, customers, headcount, mrr, arr, arpu, revPerEmp, ebitMargin, grossMargin } + // NRR: compare Dec revenue of this year vs Dec revenue of prior year + // NRR = (MRR_Dec_thisYear / MRR_Dec_lastYear) * 100 + const prevMk = `m${(y - 2026) * 12}` // December of prior year (m0 for 2026 = no prior) + const prevRevenue = y > 2026 ? (findGuv('Umsatzerlöse')?.values?.[`y${y - 1}`] || 0) : 0 + const nrr = prevRevenue > 0 ? Math.round((revenue / prevRevenue) * 100) : 0 + + // Payback: Marketing costs / monthly gross profit per new customer + // Simplified: annual marketing spend / (new customers * monthly ARPU) + const sonstAufw = findGuv('Sonst. betriebl. Aufwend')?.values?.[yk] || 0 + // Marketing ~ 10% of sonstige (rough estimate from our formula) + const marketingSpend = Math.round(revenue * 0.10) + const prevCustomers = y > 2026 ? (kundenGesamt?.values?.[`m${(y - 2026) * 12}`] || 0) : 0 + const newCustomers = Math.max(customers - prevCustomers, 1) + const cac = newCustomers > 0 ? Math.round(marketingSpend / newCustomers) : 0 + const monthlyGrossProfit = arpu > 0 ? arpu * (grossMargin / 100) : 0 + const paybackMonths = monthlyGrossProfit > 0 ? Math.round(cac / monthlyGrossProfit) : 0 + + result[yk] = { revenue, ebit, personal, netIncome, steuern, liquiditaet, customers, headcount, mrr, arr, arpu, revPerEmp, ebitMargin, grossMargin, nrr, paybackMonths } } setKpis(result)