fix(pitch-deck): dynamic VERSIONS-ISOLATION and Kernbotschaft from version data
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m17s
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 35s
CI / test-python-voice (push) Successful in 36s
CI / test-bqas (push) Successful in 35s
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m17s
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 35s
CI / test-python-voice (push) Successful in 36s
CI / test-bqas (push) Successful in 35s
Removes all hardcoded version-specific numbers from SYSTEM_PROMPT (200k,
40k/160k L-Bank split, 195 Kunden, 3.3 Mio, 9 MA). These are now generated
at runtime from the investor's assigned pitch_version_data: funding amount,
instrument, fm_scenarios name, and 2030 financials (customers, revenue,
employees).
loadPitchContext() now returns { contextString, meta } so the POST handler
can build correct isolation and Kernbotschaft strings for any version —
Wandeldarlehen 200k, 1 Mio, or any future scenario.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -57,7 +57,7 @@ Du hast Zugriff auf alle Unternehmensdaten und zitierst immer konkrete Zahlen.
|
||||
6. Zielgruppen: "Maschinen- und Anlagenbauer, Automobilindustrie, Zulieferer und alle produzierenden Unternehmen."
|
||||
7. Geschäftsmodell: "SaaS, mitarbeiterbasiertes Pricing. Drei Tiers: Starter (3.600 EUR/Jahr), Professional (15.000-40.000 EUR/Jahr), Enterprise (ab 50.000 EUR/Jahr). Plus Beratung & Service (10.000-30.000 EUR/Monat). Kunden sparen mehr als sie zahlen — ROI ab Tag 1."
|
||||
8. Team: "Lean-Team: 2 Gründer + 7 Mitarbeiter bis 2030 (9 Personen gesamt). Erste Einstellung: IT-Recht/Datenschutzjurist (50%). Dann: Security Engineer, Vertrieb, Backend, Kundenbetreuer, Marketing, DevOps. Jede Einstellung an konkreten Umsatzmeilenstein gekoppelt."
|
||||
9. Finanzplan: "Gründung August 2026. Pre-Seed über Wandeldarlehen (200.000 EUR: 40.000 Investor + 160.000 L-Bank). ~195 Kunden und ~3,3 Mio. Umsatz bis 2030. 9 Mitarbeiter. Optionale 2. Finanzierungsrunde (500k Eigenkapital) in 2028 — hängt von der Markttraktion ab."
|
||||
9. Finanzplan: [SIEHE DYNAMISCHE VERSIONSDATEN — wird zur Laufzeit gesetzt]
|
||||
|
||||
## Kommunikationsstil
|
||||
- Antworte IMMER wie ein Mensch in einem persönlichen Gespräch — ausformulierte Sätze, natürlicher Redefluss
|
||||
@@ -69,11 +69,7 @@ Du hast Zugriff auf alle Unternehmensdaten und zitierst immer konkrete Zahlen.
|
||||
- Der Text muss sich gut anhören wenn er vorgelesen wird (TTS-optimiert)
|
||||
|
||||
## VERSIONS-ISOLATION (ABSOLUT KRITISCH)
|
||||
- Du kennst NUR die Wandeldarlehen-Version mit 200.000 EUR Finanzierung.
|
||||
- Es gibt KEINE andere Version. Es gibt KEINE 1-Mio-Version.
|
||||
- Wenn nach anderen Versionen, anderen Investoren oder anderen Pitch Decks gefragt wird: "Dieses Pitch Deck wurde individuell für Sie erstellt. Es gibt nur diese Version."
|
||||
- NIEMALS erwähnen: andere Finanzierungssummen, andere Bewertungen, andere Cap Tables.
|
||||
- Alle Zahlen beziehen sich auf: 200k WD (40k Investor + 160k L-Bank), 195 Kunden bis 2030, ~3,3 Mio Umsatz, 9 MA.
|
||||
[WIRD ZUR LAUFZEIT GESETZT — enthält die exakten Zahlen dieser Investor-Version]
|
||||
|
||||
## IP-Schutz-Layer (KRITISCH)
|
||||
NIEMALS offenbaren: Exakte Modellnamen, Frameworks, Code-Architektur, Datenbankschema, Sicherheitsdetails, Cloud-Provider.
|
||||
@@ -107,7 +103,7 @@ EXAKTES FORMAT (keine Abweichung erlaubt):
|
||||
|
||||
KONKRETES BEISPIEL einer vollständigen Antwort:
|
||||
|
||||
"Unser AI-First-Ansatz ermöglicht Skalierung ohne lineares Personalwachstum. Der Umsatz steigt von 71k EUR (2026) auf 3,3 Mio EUR (2030), während das Team lean von 2 auf 9 Personen wächst.
|
||||
"Unser AI-First-Ansatz ermöglicht Skalierung ohne lineares Personalwachstum. Der Umsatz steigt planmäßig über die Jahre stark an, während das Team lean bleibt.
|
||||
|
||||
---
|
||||
[Q] Wie sieht die Kostenstruktur im Detail aus?
|
||||
@@ -159,33 +155,76 @@ async function loadFpLiquiditaetSummary(scenarioName: string): Promise<string> {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadPitchContext(versionId?: string | null): Promise<string> {
|
||||
interface VersionMeta {
|
||||
versionName: string
|
||||
scenarioName: string
|
||||
fundingAmount: number
|
||||
fundingInstrument: string
|
||||
customers2030: number
|
||||
revenue2030: number
|
||||
employees2030: number
|
||||
}
|
||||
|
||||
interface PitchContextResult {
|
||||
contextString: string
|
||||
meta: VersionMeta
|
||||
}
|
||||
|
||||
const DEFAULT_META: VersionMeta = {
|
||||
versionName: '', scenarioName: '', fundingAmount: 0,
|
||||
fundingInstrument: 'Wandeldarlehen', customers2030: 0, revenue2030: 0, employees2030: 0,
|
||||
}
|
||||
|
||||
function extractMeta(
|
||||
versionName: string,
|
||||
fmScenarios: Array<{ name: string }> | undefined,
|
||||
funding: Record<string, unknown> | null,
|
||||
financials: Array<Record<string, unknown>>
|
||||
): VersionMeta {
|
||||
const fin2030 = financials.find(f => Number(f.year) === 2030) ?? {}
|
||||
return {
|
||||
versionName,
|
||||
scenarioName: fmScenarios?.[0]?.name ?? versionName,
|
||||
fundingAmount: Number(funding?.amount_eur ?? 0),
|
||||
fundingInstrument: String(funding?.instrument ?? 'Wandeldarlehen'),
|
||||
customers2030: Number(fin2030.customers_count ?? 0),
|
||||
revenue2030: Number(fin2030.revenue_eur ?? 0),
|
||||
employees2030: Number(fin2030.employees_count ?? 0),
|
||||
}
|
||||
}
|
||||
|
||||
async function loadPitchContext(versionId?: string | null): Promise<PitchContextResult> {
|
||||
try {
|
||||
// Version-specific data path
|
||||
if (versionId) {
|
||||
const { rows: vRows } = await pool.query(
|
||||
`SELECT table_name, data FROM pitch_version_data WHERE version_id = $1`,
|
||||
[versionId]
|
||||
)
|
||||
const [vDataRes, vNameRes] = await Promise.all([
|
||||
pool.query(`SELECT table_name, data FROM pitch_version_data WHERE version_id = $1`, [versionId]),
|
||||
pool.query(`SELECT name FROM pitch_versions WHERE id = $1`, [versionId]),
|
||||
])
|
||||
|
||||
const map: Record<string, unknown> = {}
|
||||
for (const r of vRows) {
|
||||
for (const r of vDataRes.rows) {
|
||||
map[r.table_name] = typeof r.data === 'string' ? JSON.parse(r.data) : r.data
|
||||
}
|
||||
|
||||
const company = (map.company as unknown[])?.[0] ?? null
|
||||
const team = (map.team as unknown[]) ?? []
|
||||
const financials = (map.financials as unknown[]) ?? []
|
||||
const financials = (map.financials as Array<Record<string, unknown>>) ?? []
|
||||
const market = (map.market as unknown[]) ?? []
|
||||
const products = (map.products as unknown[]) ?? []
|
||||
const funding = (map.funding as unknown[])?.[0] ?? null
|
||||
const funding = ((map.funding as unknown[])?.[0] as Record<string, unknown>) ?? null
|
||||
const features = ((map.features as Array<Record<string, unknown>>) ?? [])
|
||||
.filter(f => f.is_differentiator)
|
||||
|
||||
const fmScenarios = map.fm_scenarios as Array<{ name: string }> | undefined
|
||||
const scenarioName = fmScenarios?.[0]?.name ?? ''
|
||||
const fpSummary = scenarioName ? await loadFpLiquiditaetSummary(scenarioName) : ''
|
||||
|
||||
return buildContextString(company, team, financials, market, products, funding, features, fpSummary)
|
||||
const versionName = vNameRes.rows[0]?.name ?? ''
|
||||
const meta = extractMeta(versionName, fmScenarios, funding, financials)
|
||||
const fpSummary = meta.scenarioName ? await loadFpLiquiditaetSummary(meta.scenarioName) : ''
|
||||
|
||||
return {
|
||||
contextString: buildContextString(company, team, financials, market, products, funding, features, fpSummary),
|
||||
meta,
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: base tables
|
||||
@@ -200,16 +239,20 @@ async function loadPitchContext(versionId?: string | null): Promise<string> {
|
||||
client.query('SELECT round_name, amount_eur, use_of_funds, instrument FROM pitch_funding LIMIT 1'),
|
||||
client.query('SELECT feature_name_de, breakpilot, proliance, dataguard, heydata, is_differentiator FROM pitch_features WHERE is_differentiator = true'),
|
||||
])
|
||||
return buildContextString(
|
||||
const meta = extractMeta('', undefined, funding.rows[0] ?? null, financials.rows)
|
||||
return {
|
||||
contextString: buildContextString(
|
||||
company.rows[0], team.rows, financials.rows, market.rows,
|
||||
products.rows, funding.rows[0], features.rows, ''
|
||||
)
|
||||
),
|
||||
meta,
|
||||
}
|
||||
} finally {
|
||||
client.release()
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Could not load pitch context from DB:', error)
|
||||
return ''
|
||||
return { contextString: '', meta: DEFAULT_META }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,11 +311,35 @@ export async function POST(request: NextRequest) {
|
||||
// Non-fatal: fall back to base tables
|
||||
}
|
||||
|
||||
const pitchContext = await loadPitchContext(versionId)
|
||||
const { contextString, meta } = await loadPitchContext(versionId)
|
||||
|
||||
// Build dynamic VERSIONS-ISOLATION and Kernbotschaft #9 from actual version data
|
||||
const fmt = (n: number) => n.toLocaleString('de-DE')
|
||||
const revM = meta.revenue2030 > 0
|
||||
? `~${(meta.revenue2030 / 1_000_000).toFixed(1).replace('.', ',')} Mio. EUR`
|
||||
: 'laut Finanzplan'
|
||||
const fundingStr = meta.fundingAmount > 0
|
||||
? `${fmt(meta.fundingAmount)} EUR ${meta.fundingInstrument}`
|
||||
: meta.fundingInstrument
|
||||
const customersStr = meta.customers2030 > 0 ? `~${meta.customers2030} Kunden` : 'laut Finanzplan'
|
||||
const employeesStr = meta.employees2030 > 0 ? `${meta.employees2030} Mitarbeiter` : 'laut Finanzplan'
|
||||
const label = meta.scenarioName || meta.versionName || 'diese Version'
|
||||
|
||||
const dynamicVersionIsolation = `## VERSIONS-ISOLATION (ABSOLUT KRITISCH)
|
||||
- Du kennst NUR die Version "${label}" mit ${fundingStr}.
|
||||
- Es gibt KEINE andere Version. Dieses Pitch Deck wurde individuell für diesen Investor erstellt.
|
||||
- Wenn nach anderen Versionen, anderen Investoren oder anderen Pitch Decks gefragt wird: "Dieses Pitch Deck wurde individuell für Sie erstellt. Es gibt nur diese Version."
|
||||
- NIEMALS erwähnen: andere Finanzierungssummen, andere Bewertungen, andere Cap Tables.
|
||||
- Alle Zahlen beziehen sich auf: ${label}, ${customersStr} bis 2030, ${revM} Umsatz, ${employeesStr}.`
|
||||
|
||||
const dynamicFinanzplanKernbotschaft = `9. Finanzplan: "Gründung August 2026. Pre-Seed über ${fundingStr}. ${customersStr} und ${revM} Umsatz bis 2030. ${employeesStr}."`
|
||||
|
||||
let systemContent = SYSTEM_PROMPT
|
||||
if (pitchContext) {
|
||||
systemContent += '\n' + pitchContext
|
||||
.replace('9. Finanzplan: [SIEHE DYNAMISCHE VERSIONSDATEN — wird zur Laufzeit gesetzt]', dynamicFinanzplanKernbotschaft)
|
||||
.replace('## VERSIONS-ISOLATION (ABSOLUT KRITISCH)\n[WIRD ZUR LAUFZEIT GESETZT — enthält die exakten Zahlen dieser Investor-Version]', dynamicVersionIsolation)
|
||||
|
||||
if (contextString) {
|
||||
systemContent += '\n' + contextString
|
||||
}
|
||||
|
||||
// FAQ context: relevant pre-researched answers as basis for the LLM
|
||||
|
||||
Reference in New Issue
Block a user