feat: Add staged funding model, financial compute engine, annex slides and UI enhancements
Some checks failed
ci/woodpecker/push/integration Pipeline failed
ci/woodpecker/push/main Pipeline failed
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled

Restructure financial plan from single 200k SAFE to realistic staged funding
(25k Stammkapital, 25k Angel, 200k Wandeldarlehen, 1M Series A = 1.25M total).
Add 60-month compute engine with CAPEX/OPEX accounting, cash constraints,
hardware financing (30% upfront / 70% leasing), and revenue-based hiring caps.
Rebuild TheAskSlide with 4-event funding timeline, update i18n (DE/EN),
chat agent core messages, and add 15 new annex/technology slides with
supporting UI components (KPICard, RunwayGauge, WaterfallChart, etc.).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
BreakPilot Dev
2026-02-14 21:20:02 +01:00
parent ac1bb1d97b
commit b464366341
44 changed files with 5196 additions and 262 deletions

View File

@@ -0,0 +1,109 @@
'use client'
import { useState, useEffect, useCallback, useRef } from 'react'
import { FMScenario, FMResult, FMComputeResponse } from '../types'
export function useFinancialModel() {
const [scenarios, setScenarios] = useState<FMScenario[]>([])
const [activeScenarioId, setActiveScenarioId] = useState<string | null>(null)
const [compareMode, setCompareMode] = useState(false)
const [results, setResults] = useState<Map<string, FMComputeResponse>>(new Map())
const [loading, setLoading] = useState(true)
const [computing, setComputing] = useState(false)
const computeTimer = useRef<NodeJS.Timeout | null>(null)
// Load scenarios on mount
useEffect(() => {
async function load() {
try {
const res = await fetch('/api/financial-model')
if (res.ok) {
const data: FMScenario[] = await res.json()
setScenarios(data)
const defaultScenario = data.find(s => s.is_default) || data[0]
if (defaultScenario) {
setActiveScenarioId(defaultScenario.id)
}
}
} catch (err) {
console.error('Failed to load financial model:', err)
} finally {
setLoading(false)
}
}
load()
}, [])
// Compute when active scenario changes
useEffect(() => {
if (activeScenarioId && !results.has(activeScenarioId)) {
compute(activeScenarioId)
}
}, [activeScenarioId]) // eslint-disable-line react-hooks/exhaustive-deps
const compute = useCallback(async (scenarioId: string) => {
setComputing(true)
try {
const res = await fetch('/api/financial-model/compute', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ scenarioId }),
})
if (res.ok) {
const data: FMComputeResponse = await res.json()
setResults(prev => new Map(prev).set(scenarioId, data))
}
} catch (err) {
console.error('Compute failed:', err)
} finally {
setComputing(false)
}
}, [])
const updateAssumption = useCallback(async (scenarioId: string, key: string, value: number | number[]) => {
// Optimistic update in local state
setScenarios(prev => prev.map(s => {
if (s.id !== scenarioId) return s
return {
...s,
assumptions: s.assumptions.map(a => a.key === key ? { ...a, value } : a),
}
}))
// Save to DB
await fetch('/api/financial-model/assumptions', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ scenarioId, key, value }),
})
// Debounced recompute
if (computeTimer.current) clearTimeout(computeTimer.current)
computeTimer.current = setTimeout(() => compute(scenarioId), 300)
}, [compute])
const computeAll = useCallback(async () => {
for (const s of scenarios) {
await compute(s.id)
}
}, [scenarios, compute])
const activeScenario = scenarios.find(s => s.id === activeScenarioId) || null
const activeResults = activeScenarioId ? results.get(activeScenarioId) || null : null
return {
scenarios,
activeScenario,
activeScenarioId,
setActiveScenarioId,
activeResults,
results,
loading,
computing,
compareMode,
setCompareMode,
compute,
computeAll,
updateAssumption,
}
}