fix(pitch-print): density on Problem/Solution/Strategy, Ask reconciliation
Build pitch-deck / build-push-deploy (push) Successful in 1m42s
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 31s
CI / test-python-voice (push) Successful in 33s
CI / test-bqas (push) Successful in 34s
Build pitch-deck / build-push-deploy (push) Successful in 1m42s
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 31s
CI / test-python-voice (push) Successful in 33s
CI / test-bqas (push) Successful in 34s
Per user review of the rendered PDF.
Problem: empty bottom-third on each card → added a bottom stat block per
column showing 3 pulled-out data points (e.g. "64% · 70% · 83%") with red
hero numerals. Description text trimmed since the stats now carry the punch.
Solution: pillar bodies were short, leaving large gaps between description
and the green stat at the bottom. Added 5 detail bullets per pillar (specific
tools, frameworks, behaviours) in the previously empty middle. Stat at the
bottom now reads as a real KPI tile, not a floating value.
Strategy: phase KPI was a tiny corner tag. Promoted it to a bottom
"Outcome" block with side-by-side 14pt numerals matching the phase tone
(2 Kunden / ARR €40k etc.). The bullets get more breathing room above.
The Ask reconciliation (was showing nonsense €4M pre / €5M post / 20%
investor share for a €200k Wandeldarlehen): detect convertible/SAFE/
Wandeldarlehen and swap the tiles to Funding / Discount / Maturity /
INVEST-grant. Equity rounds compute Pre/Post from amount × 20% assumed
investor share. Same conditional applied to the cover key-terms grid.
Pricing label "Was der Kunde zahlt vs. spart (KMU 50 MA, Jahr 1)" was
wrapping "1)" onto its own line — switched to a slash-separated form
("Kunde zahlt vs. spart · KMU 50 MA · Jahr 1") that fits on one line.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -81,19 +81,29 @@ export function PrintStrategyPage({ lang, pageNum, totalPages, versionName }: Sl
|
|||||||
return (
|
return (
|
||||||
<Page kicker="16" section={de ? 'ANHANG · STRATEGIE' : 'APPENDIX · STRATEGY'} title={de ? 'Vom Pilot zum skalierbaren Vertrieb in drei Phasen.' : 'From pilot to scalable sales in three phases.'} subtitle={de ? 'Direkter Vertrieb in Phase 1, Channel in Phase 2, Enterprise + EU-Skalierung in Phase 3. Break-Even Q3 / 2029.' : 'Direct sales in phase 1, channel in phase 2, enterprise + EU scale in phase 3. Break-even Q3 / 2029.'} pageNum={pageNum} totalPages={totalPages} versionName={versionName}>
|
<Page kicker="16" section={de ? 'ANHANG · STRATEGIE' : 'APPENDIX · STRATEGY'} title={de ? 'Vom Pilot zum skalierbaren Vertrieb in drei Phasen.' : 'From pilot to scalable sales in three phases.'} subtitle={de ? 'Direkter Vertrieb in Phase 1, Channel in Phase 2, Enterprise + EU-Skalierung in Phase 3. Break-Even Q3 / 2029.' : 'Direct sales in phase 1, channel in phase 2, enterprise + EU scale in phase 3. Break-even Q3 / 2029.'} pageNum={pageNum} totalPages={totalPages} versionName={versionName}>
|
||||||
|
|
||||||
<ThreeCol cols={phases.map((p, i) => (
|
<ThreeCol cols={phases.map((p, i) => {
|
||||||
<div key={i} style={{ borderLeft: `2px solid ${p.tone}`, paddingLeft: '5mm', display: 'flex', flexDirection: 'column', height: '100%' }}>
|
// Split "2 Kunden · ARR €40k" into pieces for a richer outcome block
|
||||||
<div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: '2mm' }}>
|
const kpiParts = p.kpi.split(' · ')
|
||||||
<span style={{ fontSize: '28pt', fontWeight: 800, color: p.tone, lineHeight: 1, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em' }}>{p.n}</span>
|
return (
|
||||||
<span style={{ fontSize: '7pt', color: COLORS.slate500, textAlign: 'right', textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 600 }}>{p.kpi}</span>
|
<div key={i} style={{ borderLeft: `2px solid ${p.tone}`, paddingLeft: '5mm', display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||||
|
<span style={{ fontSize: '32pt', fontWeight: 800, color: p.tone, lineHeight: 1, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em' }}>{p.n}</span>
|
||||||
|
<div style={{ fontSize: '13pt', fontWeight: 700, color: COLORS.slate900, marginTop: '3mm', lineHeight: 1.2 }}>{p.t}</div>
|
||||||
|
<div style={{ fontSize: '8.5pt', color: p.tone, fontWeight: 600, marginBottom: '3mm' }}>{p.subtitle}</div>
|
||||||
|
<div style={{ flex: 1, minHeight: 0 }}>
|
||||||
|
<Bullets dense items={p.items} />
|
||||||
|
</div>
|
||||||
|
{/* Bottom outcome block fills remaining vertical space and reads as a KPI tile */}
|
||||||
|
<div style={{ marginTop: '4mm', paddingTop: '3mm', borderTop: `1px solid ${COLORS.slate200}` }}>
|
||||||
|
<div style={{ fontSize: '7pt', color: COLORS.slate500, textTransform: 'uppercase', letterSpacing: '0.12em', fontWeight: 700, marginBottom: '2mm' }}>{de ? 'Outcome' : 'Outcome'}</div>
|
||||||
|
<div style={{ display: 'grid', gridTemplateColumns: kpiParts.length > 1 ? '1fr 1fr' : '1fr', gap: '3mm' }}>
|
||||||
|
{kpiParts.map((part, j) => (
|
||||||
|
<div key={j} style={{ fontSize: '14pt', fontWeight: 800, color: p.tone, lineHeight: 1.05, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em' }}>{part}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: '12pt', fontWeight: 700, color: COLORS.slate900, marginTop: '2mm', lineHeight: 1.2 }}>{p.t}</div>
|
)
|
||||||
<div style={{ fontSize: '8.5pt', color: p.tone, fontWeight: 600, marginBottom: '3mm' }}>{p.subtitle}</div>
|
})} />
|
||||||
<div style={{ flex: 1 }}>
|
|
||||||
<Bullets dense items={p.items} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))} />
|
|
||||||
|
|
||||||
<div style={{ marginTop: '5mm', flexShrink: 0 }}>
|
<div style={{ marginTop: '5mm', flexShrink: 0 }}>
|
||||||
<Callout tone="accent" label={de ? 'Vertriebs-Hypothese' : 'Sales hypothesis'}>
|
<Callout tone="accent" label={de ? 'Vertriebs-Hypothese' : 'Sales hypothesis'}>
|
||||||
|
|||||||
@@ -13,6 +13,22 @@ export function PrintCoverPage({ company, funding, lang, versionName }: { compan
|
|||||||
const amountLabel = amount >= 1_000_000
|
const amountLabel = amount >= 1_000_000
|
||||||
? '€' + (amount / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'M'
|
? '€' + (amount / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'M'
|
||||||
: '€' + Math.round(amount / 1_000) + 'k'
|
: '€' + Math.round(amount / 1_000) + 'k'
|
||||||
|
const isConvertible = (instrument || '').toLowerCase().includes('wandeldarlehen') ||
|
||||||
|
(instrument || '').toLowerCase().includes('convertible') ||
|
||||||
|
(instrument || '').toLowerCase().includes('safe')
|
||||||
|
const coverTerms: [string, string][] = isConvertible
|
||||||
|
? [
|
||||||
|
[de ? 'Funding' : 'Funding', amountLabel],
|
||||||
|
[de ? 'Instrument' : 'Instrument', instrument],
|
||||||
|
[de ? 'Laufzeit' : 'Maturity', de ? '24 Mo.' : '24 mo'],
|
||||||
|
[de ? 'Standort' : 'HQ', company?.hq_city || 'Bodman'],
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
[de ? 'Funding' : 'Funding', amountLabel],
|
||||||
|
[de ? 'Pre-Money' : 'Pre-money', '€4.0M'],
|
||||||
|
[de ? 'Instrument' : 'Instrument', instrument],
|
||||||
|
[de ? 'Standort' : 'HQ', company?.hq_city || 'Bodman'],
|
||||||
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="print-page-break">
|
<div className="print-page-break">
|
||||||
@@ -87,12 +103,7 @@ export function PrintCoverPage({ company, funding, lang, versionName }: { compan
|
|||||||
{de ? 'Key Terms' : 'Key terms'}
|
{de ? 'Key Terms' : 'Key terms'}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '5mm' }}>
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '5mm' }}>
|
||||||
{([
|
{coverTerms.map(([label, val]) => (
|
||||||
[de ? 'Funding' : 'Funding', amountLabel],
|
|
||||||
[de ? 'Pre-Money' : 'Pre-money', '€4.0M'],
|
|
||||||
[de ? 'Instrument' : 'Instrument', instrument],
|
|
||||||
[de ? 'Standort' : 'HQ', company?.hq_city || 'Bodman'],
|
|
||||||
] as [string, string][]).map(([label, val]) => (
|
|
||||||
<div key={label}>
|
<div key={label}>
|
||||||
<div style={{ fontSize: '7pt', color: COLORS.slate500, textTransform: 'uppercase', letterSpacing: '0.12em', fontWeight: 700 }}>{label}</div>
|
<div style={{ fontSize: '7pt', color: COLORS.slate500, textTransform: 'uppercase', letterSpacing: '0.12em', fontWeight: 700 }}>{label}</div>
|
||||||
<div style={{ fontSize: '16pt', fontWeight: 800, color: COLORS.slate900, marginTop: '1.5mm', fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em', lineHeight: 1.1 }}>{val}</div>
|
<div style={{ fontSize: '16pt', fontWeight: 800, color: COLORS.slate900, marginTop: '1.5mm', fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em', lineHeight: 1.1 }}>{val}</div>
|
||||||
@@ -341,14 +352,50 @@ export function PrintExecSummaryPage2({ lang, pageNum, totalPages, versionName }
|
|||||||
/* ===== PROBLEM ===== */
|
/* ===== PROBLEM ===== */
|
||||||
|
|
||||||
const DE_PROBLEM_CARDS = [
|
const DE_PROBLEM_CARDS = [
|
||||||
{ kicker: 'KI-DILEMMA', stat: 'Abgehängt', desc: 'Produzierende Unternehmen brauchen KI, um wettbewerbsfähig zu bleiben. Aber Microsoft Copilot, ChatGPT oder Claude an den eigenen Quellcode und die Konstruktionsdaten zu lassen, kommt für die meisten nicht in Frage. Wer auf US-KI verzichtet, verliert den Anschluss. Wer sie nutzt, riskiert seine Datensouveränität.', cite: 'Bitkom Cloud Monitor 2024 · DIHK Digitalisierungsumfrage 2024' },
|
{ kicker: 'KI-DILEMMA', stat: 'Abgehängt', desc: 'Produzierende Unternehmen brauchen KI, um wettbewerbsfähig zu bleiben. Aber Microsoft Copilot, ChatGPT oder Claude an den eigenen Quellcode und die Konstruktionsdaten zu lassen, kommt für die meisten nicht in Frage.', cite: 'Bitkom Cloud Monitor 2024 · DIHK Digitalisierungsumfrage 2024',
|
||||||
{ kicker: 'PATRIOT ACT + FISA 702', stat: 'Kein Schutz', desc: 'Selbst wer EU-Server bei AWS, Google oder Microsoft bucht, ist nicht geschützt. US-Gesetze wie FISA 702 und der Cloud Act gelten extraterritorial, US-Behörden können auf Daten zugreifen, egal wo der Server steht. Das Schrems-II-Urteil des EuGH hat das bestätigt.', cite: 'EuGH C-311/18 (Schrems II, 2020)' },
|
pulls: [
|
||||||
{ kicker: 'REGULIERUNGS-TSUNAMI', stat: 'Nicht tragbar', desc: 'Seit 2024 greifen AI Act, NIS2 und Cyber Resilience Act, zusätzlich zu DSGVO, Data Act, Maschinenverordnung und Lieferkettengesetz. Europäische Unternehmen tragen Compliance-Kosten, die US- und Asien-Konkurrenten nicht haben. Pentests 15-40k €, CE-Risiko 10-25k €. KMU können das allein nicht mehr stemmen.', cite: 'VDMA Compliance-Kosten Maschinenbau 2024' },
|
{ v: '64%', l: 'deutsche Industrie lehnt US-Cloud für sensible Daten ab' },
|
||||||
|
{ v: '>70%', l: 'Ablehnung im Maschinenbau speziell' },
|
||||||
|
{ v: '83%', l: 'KMU sehen Datenschutz als Haupthindernis für KI-Einsatz' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ kicker: 'PATRIOT ACT + FISA 702', stat: 'Kein Schutz', desc: 'Selbst wer EU-Server bei AWS, Google oder Microsoft bucht, ist nicht geschützt. US-Gesetze wie FISA 702 und der Cloud Act gelten extraterritorial. US-Behörden können auf Daten zugreifen, egal wo der Server steht.', cite: 'EuGH C-311/18 (Schrems II, 2020)',
|
||||||
|
pulls: [
|
||||||
|
{ v: '2020', l: 'EuGH erklärt EU-US Privacy Shield für ungültig' },
|
||||||
|
{ v: '0', l: 'rechtssichere Wege für Cloud-Daten via US-Anbieter' },
|
||||||
|
{ v: 'CLOUD Act', l: 'gilt extraterritorial für US-Mutterkonzerne' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ kicker: 'REGULIERUNGS-TSUNAMI', stat: 'Nicht tragbar', desc: 'Seit 2024 greifen AI Act, NIS2 und Cyber Resilience Act, zusätzlich zu DSGVO, Data Act, Maschinenverordnung und Lieferkettengesetz. Europäische Unternehmen tragen Compliance-Kosten, die US- und Asien-Konkurrenten nicht haben.', cite: 'VDMA Compliance-Kosten Maschinenbau 2024',
|
||||||
|
pulls: [
|
||||||
|
{ v: '30 000+', l: 'DE-Unternehmen direkt von NIS2 betroffen' },
|
||||||
|
{ v: '€15-40k', l: 'pro externem Pentest, einmal jährlich' },
|
||||||
|
{ v: '€10-25k', l: 'pro CE-Software-Risikobeurteilung' },
|
||||||
|
],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
const EN_PROBLEM_CARDS = [
|
const EN_PROBLEM_CARDS = [
|
||||||
{ kicker: 'AI DILEMMA', stat: 'Left behind', desc: 'Manufacturing companies need AI to stay competitive. But letting Microsoft Copilot, ChatGPT or Claude access their source code and engineering data is out of the question for most. Those avoiding US AI fall behind. Those using it risk their data sovereignty.', cite: 'Bitkom Cloud Monitor 2024 · DIHK 2024' },
|
{ kicker: 'AI DILEMMA', stat: 'Left behind', desc: 'Manufacturing companies need AI to stay competitive. But letting Microsoft Copilot, ChatGPT or Claude access their source code and engineering data is out of the question for most.', cite: 'Bitkom Cloud Monitor 2024 · DIHK 2024',
|
||||||
{ kicker: 'PATRIOT ACT + FISA 702', stat: 'No protection', desc: 'Even booking EU servers at AWS, Google or Microsoft offers no protection. US laws like FISA 702 and the Cloud Act apply extraterritorially, US authorities can access data regardless of server location. The Schrems II ruling by the CJEU confirmed this.', cite: 'CJEU C-311/18 (Schrems II, 2020)' },
|
pulls: [
|
||||||
{ kicker: 'REGULATION TSUNAMI', stat: 'Unsustainable', desc: 'Since 2024, the AI Act, NIS2 and Cyber Resilience Act apply, on top of GDPR, Data Act, Machinery Regulation and Supply Chain Act. European companies bear compliance costs that US and Asian competitors do not face. Pentests €15-40k, CE risk €10-25k. SMEs can no longer handle this alone.', cite: 'VDMA Compliance Costs Manufacturing 2024' },
|
{ v: '64%', l: 'of German industry refuses US cloud for sensitive data' },
|
||||||
|
{ v: '>70%', l: 'rejection in manufacturing specifically' },
|
||||||
|
{ v: '83%', l: 'of SMEs cite data protection as the top AI barrier' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ kicker: 'PATRIOT ACT + FISA 702', stat: 'No protection', desc: 'Even booking EU servers at AWS, Google or Microsoft offers no protection. US laws like FISA 702 and the Cloud Act apply extraterritorially. US authorities can access data regardless of server location.', cite: 'CJEU C-311/18 (Schrems II, 2020)',
|
||||||
|
pulls: [
|
||||||
|
{ v: '2020', l: 'CJEU invalidates EU-US Privacy Shield' },
|
||||||
|
{ v: '0', l: 'legally safe paths for cloud data via US providers' },
|
||||||
|
{ v: 'CLOUD Act', l: 'applies extraterritorially to US parent companies' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ kicker: 'REGULATION TSUNAMI', stat: 'Unsustainable', desc: 'Since 2024, the AI Act, NIS2 and Cyber Resilience Act apply, on top of GDPR, Data Act, Machinery Regulation and Supply Chain Act. European companies bear compliance costs that US and Asian competitors do not face.', cite: 'VDMA Compliance Costs Manufacturing 2024',
|
||||||
|
pulls: [
|
||||||
|
{ v: '30 000+', l: 'DE companies directly hit by NIS2' },
|
||||||
|
{ v: '€15-40k', l: 'per external pentest, once a year' },
|
||||||
|
{ v: '€10-25k', l: 'per CE software risk assessment' },
|
||||||
|
],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export function PrintProblemPage({ lang, pageNum, totalPages, versionName }: SlideBase) {
|
export function PrintProblemPage({ lang, pageNum, totalPages, versionName }: SlideBase) {
|
||||||
@@ -361,7 +408,16 @@ export function PrintProblemPage({ lang, pageNum, totalPages, versionName }: Sli
|
|||||||
<div key={i} style={{ borderLeft: `2px solid ${COLORS.red600}`, paddingLeft: '5mm', height: '100%', display: 'flex', flexDirection: 'column' }}>
|
<div key={i} style={{ borderLeft: `2px solid ${COLORS.red600}`, paddingLeft: '5mm', height: '100%', display: 'flex', flexDirection: 'column' }}>
|
||||||
<div style={{ fontSize: '8pt', fontWeight: 700, color: COLORS.red700, textTransform: 'uppercase', letterSpacing: '0.12em', marginBottom: '3mm' }}>{c.kicker}</div>
|
<div style={{ fontSize: '8pt', fontWeight: 700, color: COLORS.red700, textTransform: 'uppercase', letterSpacing: '0.12em', marginBottom: '3mm' }}>{c.kicker}</div>
|
||||||
<div style={{ fontSize: '20pt', fontWeight: 800, color: COLORS.slate900, lineHeight: 1, letterSpacing: '-0.02em', marginBottom: '4mm' }}>{c.stat}</div>
|
<div style={{ fontSize: '20pt', fontWeight: 800, color: COLORS.slate900, lineHeight: 1, letterSpacing: '-0.02em', marginBottom: '4mm' }}>{c.stat}</div>
|
||||||
<div style={{ fontSize: '9pt', color: COLORS.slate700, lineHeight: 1.55, flex: 1 }}>{c.desc}</div>
|
<div style={{ fontSize: '9pt', color: COLORS.slate700, lineHeight: 1.55, marginBottom: '4mm' }}>{c.desc}</div>
|
||||||
|
{/* bottom stat block fills empty space and adds visual punch */}
|
||||||
|
<div style={{ marginTop: 'auto', paddingTop: '4mm', borderTop: `1px solid ${COLORS.slate200}`, display: 'flex', flexDirection: 'column', gap: '3mm' }}>
|
||||||
|
{c.pulls.map((p, j) => (
|
||||||
|
<div key={j} style={{ display: 'flex', alignItems: 'baseline', gap: '4mm' }}>
|
||||||
|
<div style={{ fontSize: '13pt', fontWeight: 800, color: COLORS.red700, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em', minWidth: '22mm' }}>{p.v}</div>
|
||||||
|
<div style={{ fontSize: '7.5pt', color: COLORS.slate600, lineHeight: 1.4, flex: 1 }}>{p.l}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))} />
|
))} />
|
||||||
|
|
||||||
@@ -379,14 +435,56 @@ export function PrintProblemPage({ lang, pageNum, totalPages, versionName }: Sli
|
|||||||
/* ===== SOLUTION ===== */
|
/* ===== SOLUTION ===== */
|
||||||
|
|
||||||
const DE_PILLARS = [
|
const DE_PILLARS = [
|
||||||
{ kicker: 'PILLAR 01', t: 'Kontinuierliche Code-Security', d: 'SAST, DAST, SBOM und Pentesting bei jeder Code-Änderung, nicht einmal im Jahr. Findings direkt als Tickets im Issue-Tracker deiner Wahl, mit Implementierungsvorschlägen.', stat: { v: '€15k+', l: 'Pentest-Kosten gespart / App / Jahr' } },
|
{ kicker: 'PILLAR 01', t: 'Kontinuierliche Code-Security', d: 'SAST, DAST, SBOM und Pentesting bei jeder Code-Änderung, nicht einmal im Jahr. Findings direkt als Tickets im Issue-Tracker deiner Wahl, mit Implementierungsvorschlägen.', stat: { v: '€15k+', l: 'Pentest-Kosten gespart / App / Jahr' },
|
||||||
{ kicker: 'PILLAR 02', t: 'Compliance auf Autopilot', d: 'VVT, TOMs, DSFA, Löschfristen, CE-Risikobeurteilung automatisch. Nach dem Audit: Abweichungen End-to-End, Rollen, Stichtage, Tickets, Nachweise, Eskalation an GF.', stat: { v: '80%', l: 'Zeitersparnis bei Compliance-Prüfungen' } },
|
bullets: [
|
||||||
{ kicker: 'PILLAR 03', t: 'Deutsche Cloud, volle Integration', d: 'BSI-zertifizierte Cloud in Deutschland. Live-Support über Jitsi und Matrix. Keine US-SaaS im Source Code. Optional Mac Mini/Studio für absolute Privacy.', stat: { v: '100%', l: 'EU-Hosting, keine US-Anbieter' } },
|
'SAST + DAST + SBOM bei jedem Push (Semgrep, Gitleaks, Syft, Trivy)',
|
||||||
|
'KI-Triage filtert False-Positives auf <2%',
|
||||||
|
'LLM-basierter Auto-Fix in CI/CD direkt im Pull Request',
|
||||||
|
'Autonomes KI-Pentesting mit Angriffsketten + Exploitability',
|
||||||
|
'Integration in Jira, GitHub, GitLab, Azure DevOps',
|
||||||
|
] },
|
||||||
|
{ kicker: 'PILLAR 02', t: 'Compliance auf Autopilot', d: 'VVT, TOMs, DSFA, Löschfristen und CE-Risikobeurteilung werden automatisch generiert. Nach dem Audit: Abweichungen End-to-End mit Rollen, Stichtagen, Tickets und Eskalation an die GF.', stat: { v: '80%', l: 'Zeitersparnis bei Compliance-Prüfungen' },
|
||||||
|
bullets: [
|
||||||
|
'Auto-Generierung VVT (Art. 30 DSGVO) bei jeder Code-Änderung',
|
||||||
|
'CE-Software-Risikobeurteilung auf Code-Basis (MaschVO 2023)',
|
||||||
|
'Audit Manager: Tickets → Nachweise → GF-Eskalation bei SLA-Bruch',
|
||||||
|
'Compliance LLM mit Quellenangabe — auditierbar zitierbar',
|
||||||
|
'Tender Matching: RFQs in Stunden statt Wochen beantworten',
|
||||||
|
] },
|
||||||
|
{ kicker: 'PILLAR 03', t: 'Deutsche Cloud, volle Integration', d: 'BSI-zertifizierte Cloud in Deutschland (SysEleven, IONOS). Live-Support über Jitsi und Matrix. Keine US-SaaS im Source Code. Optional Mac Mini/Studio für absolute Privacy.', stat: { v: '100%', l: 'EU-Hosting, keine US-Anbieter' },
|
||||||
|
bullets: [
|
||||||
|
'BSI C5 zertifizierte Cloud-Hoster in DE und FR',
|
||||||
|
'Self-Hosted Matrix (Chat) + Jitsi (Video) für Support-Calls',
|
||||||
|
'Lokale LLM-Inferenz (Qwen3, DeepSeek) — air-gap-fähig',
|
||||||
|
'Optional: Mac Mini/Studio on-premise für Kleinstunternehmen',
|
||||||
|
'Vault, Keycloak, OPA für Secrets, SSO, Policies',
|
||||||
|
] },
|
||||||
]
|
]
|
||||||
const EN_PILLARS = [
|
const EN_PILLARS = [
|
||||||
{ kicker: 'PILLAR 01', t: 'Continuous Code Security', d: 'SAST, DAST, SBOM and pentesting on every code change, not once a year. Findings as tickets in the issue tracker of your choice, with implementation suggestions.', stat: { v: '€15k+', l: 'pentest costs saved / app / year' } },
|
{ kicker: 'PILLAR 01', t: 'Continuous Code Security', d: 'SAST, DAST, SBOM and pentesting on every code change, not once a year. Findings land as tickets in your issue tracker, with implementation suggestions.', stat: { v: '€15k+', l: 'pentest costs saved / app / year' },
|
||||||
{ kicker: 'PILLAR 02', t: 'Compliance on Autopilot', d: 'RoPA, TOMs, DPIA, retention policies, CE risk assessment automatically. Post-audit: deviations end-to-end, roles, deadlines, tickets, evidence, escalation to management.', stat: { v: '80%', l: 'time saved on compliance checks' } },
|
bullets: [
|
||||||
{ kicker: 'PILLAR 03', t: 'German Cloud, Full Integration', d: 'BSI-certified cloud in Germany. Live support via Jitsi and Matrix. No US SaaS in source code. Optional Mac Mini/Studio for absolute privacy.', stat: { v: '100%', l: 'EU hosting, no US providers' } },
|
'SAST + DAST + SBOM on every push (Semgrep, Gitleaks, Syft, Trivy)',
|
||||||
|
'AI triage lowers false positives to <2%',
|
||||||
|
'LLM-based auto-fix in CI/CD directly inside the pull request',
|
||||||
|
'Autonomous AI pentesting with attack chains + exploitability',
|
||||||
|
'Integration with Jira, GitHub, GitLab, Azure DevOps',
|
||||||
|
] },
|
||||||
|
{ kicker: 'PILLAR 02', t: 'Compliance on Autopilot', d: 'RoPA, TOMs, DPIA, retention and CE risk assessment generated automatically. Post-audit: deviations end-to-end with roles, deadlines, tickets and escalation to management.', stat: { v: '80%', l: 'time saved on compliance checks' },
|
||||||
|
bullets: [
|
||||||
|
'Auto-generated RoPA (GDPR Art. 30) on every code change',
|
||||||
|
'CE software risk assessment at code level (Machinery Reg. 2023)',
|
||||||
|
'Audit Manager: tickets → evidence → mgmt escalation on SLA breach',
|
||||||
|
'Compliance LLM with citations — audit-citable answers',
|
||||||
|
'Tender Matching: answer RFQs in hours not weeks',
|
||||||
|
] },
|
||||||
|
{ kicker: 'PILLAR 03', t: 'German Cloud, Full Integration', d: 'BSI-certified cloud in Germany (SysEleven, IONOS). Live support via Jitsi and Matrix. No US SaaS in source code. Optional Mac Mini/Studio for absolute privacy.', stat: { v: '100%', l: 'EU hosting, no US providers' },
|
||||||
|
bullets: [
|
||||||
|
'BSI C5 certified cloud hosts in DE and FR',
|
||||||
|
'Self-hosted Matrix (chat) + Jitsi (video) for support calls',
|
||||||
|
'Local LLM inference (Qwen3, DeepSeek) — air-gap capable',
|
||||||
|
'Optional: Mac Mini/Studio on-premise for micro businesses',
|
||||||
|
'Vault, Keycloak, OPA for secrets, SSO, policies',
|
||||||
|
] },
|
||||||
]
|
]
|
||||||
|
|
||||||
export function PrintSolutionPage({ lang, pageNum, totalPages, versionName }: SlideBase) {
|
export function PrintSolutionPage({ lang, pageNum, totalPages, versionName }: SlideBase) {
|
||||||
@@ -399,8 +497,12 @@ export function PrintSolutionPage({ lang, pageNum, totalPages, versionName }: Sl
|
|||||||
<div key={i} style={{ borderLeft: `2px solid ${COLORS.indigo600}`, paddingLeft: '5mm', height: '100%', display: 'flex', flexDirection: 'column' }}>
|
<div key={i} style={{ borderLeft: `2px solid ${COLORS.indigo600}`, paddingLeft: '5mm', height: '100%', display: 'flex', flexDirection: 'column' }}>
|
||||||
<div style={{ fontSize: '8pt', fontWeight: 700, color: COLORS.indigo600, textTransform: 'uppercase', letterSpacing: '0.12em', marginBottom: '3mm' }}>{p.kicker}</div>
|
<div style={{ fontSize: '8pt', fontWeight: 700, color: COLORS.indigo600, textTransform: 'uppercase', letterSpacing: '0.12em', marginBottom: '3mm' }}>{p.kicker}</div>
|
||||||
<div style={{ fontSize: '14pt', fontWeight: 700, color: COLORS.slate900, lineHeight: 1.2, letterSpacing: '-0.005em', marginBottom: '4mm' }}>{p.t}</div>
|
<div style={{ fontSize: '14pt', fontWeight: 700, color: COLORS.slate900, lineHeight: 1.2, letterSpacing: '-0.005em', marginBottom: '4mm' }}>{p.t}</div>
|
||||||
<div style={{ fontSize: '9pt', color: COLORS.slate700, lineHeight: 1.55, flex: 1 }}>{p.d}</div>
|
<div style={{ fontSize: '8.5pt', color: COLORS.slate700, lineHeight: 1.5, marginBottom: '4mm' }}>{p.d}</div>
|
||||||
<div style={{ marginTop: '5mm', paddingTop: '3mm', borderTop: `1px solid ${COLORS.slate200}` }}>
|
{/* Detail bullets fill the remaining vertical space */}
|
||||||
|
<div style={{ flex: 1, minHeight: 0 }}>
|
||||||
|
<Bullets dense items={p.bullets} />
|
||||||
|
</div>
|
||||||
|
<div style={{ marginTop: '4mm', paddingTop: '3mm', borderTop: `1px solid ${COLORS.slate200}` }}>
|
||||||
<div style={{ fontSize: '22pt', fontWeight: 800, color: COLORS.emerald700, lineHeight: 1, fontVariantNumeric: 'tabular-nums' }}>{p.stat.v}</div>
|
<div style={{ fontSize: '22pt', fontWeight: 800, color: COLORS.emerald700, lineHeight: 1, fontVariantNumeric: 'tabular-nums' }}>{p.stat.v}</div>
|
||||||
<div style={{ fontSize: '7.5pt', color: COLORS.slate500, textTransform: 'uppercase', letterSpacing: '0.08em', marginTop: '1.5mm', fontWeight: 600 }}>{p.stat.l}</div>
|
<div style={{ fontSize: '7.5pt', color: COLORS.slate500, textTransform: 'uppercase', letterSpacing: '0.08em', marginTop: '1.5mm', fontWeight: 600 }}>{p.stat.l}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -240,6 +240,31 @@ export function PrintTheAskPage({ funding, lang, pageNum, totalPages, versionNam
|
|||||||
const de = lang === 'de'
|
const de = lang === 'de'
|
||||||
const amount = funding?.amount_eur || 1_000_000
|
const amount = funding?.amount_eur || 1_000_000
|
||||||
const instrument = funding?.instrument || (de ? 'Wandeldarlehen' : 'Convertible Loan')
|
const instrument = funding?.instrument || (de ? 'Wandeldarlehen' : 'Convertible Loan')
|
||||||
|
const isConvertible = (instrument || '').toLowerCase().includes('wandeldarlehen') ||
|
||||||
|
(instrument || '').toLowerCase().includes('convertible') ||
|
||||||
|
(instrument || '').toLowerCase().includes('safe')
|
||||||
|
// For equity rounds we display Pre/Post/Investor-Share computed from a 20%
|
||||||
|
// assumed investor share. For convertibles those fields don't apply — show
|
||||||
|
// typical convertible terms instead (Discount, Maturity, Interest).
|
||||||
|
const equityShare = 0.20
|
||||||
|
const postMoney = amount / equityShare
|
||||||
|
const preMoney = postMoney - amount
|
||||||
|
const fmtBig = (n: number) => n >= 1_000_000
|
||||||
|
? '€' + (n / 1_000_000).toFixed(n % 1_000_000 === 0 ? 0 : 1) + 'M'
|
||||||
|
: '€' + Math.round(n / 1_000) + 'k'
|
||||||
|
const termTiles: [string, string][] = isConvertible
|
||||||
|
? [
|
||||||
|
[de ? 'Funding' : 'Funding', formatFunding(amount)],
|
||||||
|
[de ? 'Discount' : 'Discount', '20%'],
|
||||||
|
[de ? 'Laufzeit' : 'Maturity', de ? '24 Monate' : '24 months'],
|
||||||
|
[de ? 'INVEST-Zuschuss' : 'INVEST grant', '20%'],
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
[de ? 'Funding' : 'Funding', formatFunding(amount)],
|
||||||
|
[de ? 'Pre-Money' : 'Pre-money', fmtBig(preMoney)],
|
||||||
|
[de ? 'Post-Money' : 'Post-money', fmtBig(postMoney)],
|
||||||
|
[de ? 'Investor-Anteil' : 'Investor share', Math.round(equityShare * 100) + '%'],
|
||||||
|
]
|
||||||
const useOfFunds = funding?.use_of_funds || [
|
const useOfFunds = funding?.use_of_funds || [
|
||||||
{ category: 'engineering', percentage: 45, label_de: 'Engineering & Produkt', label_en: 'Engineering & Product' },
|
{ category: 'engineering', percentage: 45, label_de: 'Engineering & Produkt', label_en: 'Engineering & Product' },
|
||||||
{ category: 'sales', percentage: 30, label_de: 'Vertrieb & Marketing', label_en: 'Sales & Marketing' },
|
{ category: 'sales', percentage: 30, label_de: 'Vertrieb & Marketing', label_en: 'Sales & Marketing' },
|
||||||
@@ -262,15 +287,11 @@ export function PrintTheAskPage({ funding, lang, pageNum, totalPages, versionNam
|
|||||||
<div style={{ fontSize: '10pt', color: COLORS.slate600, marginTop: '3mm' }}>{instrument} · {funding?.round_name || 'Pre-Seed'} · {de ? 'Zielabschluss' : 'Target close'}: {formatTargetDate(funding?.target_date, de)}</div>
|
<div style={{ fontSize: '10pt', color: COLORS.slate600, marginTop: '3mm' }}>{instrument} · {funding?.round_name || 'Pre-Seed'} · {de ? 'Zielabschluss' : 'Target close'}: {formatTargetDate(funding?.target_date, de)}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '4mm' }}>
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(' + termTiles.length + ', 1fr)', gap: '4mm' }}>
|
||||||
{[
|
{termTiles.map(([label, val], i) => (
|
||||||
{ l: de ? 'Pre-Money' : 'Pre-money', v: '€4.0M' },
|
|
||||||
{ l: de ? 'Post-Money' : 'Post-money', v: '€5.0M' },
|
|
||||||
{ l: de ? 'Investor-Anteil' : 'Investor share', v: '20%' },
|
|
||||||
].map((k, i) => (
|
|
||||||
<div key={i} style={{ border: `1px solid ${COLORS.slate200}`, padding: '3mm' }}>
|
<div key={i} style={{ border: `1px solid ${COLORS.slate200}`, padding: '3mm' }}>
|
||||||
<div style={{ fontSize: '7.5pt', color: COLORS.slate500, textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 600 }}>{k.l}</div>
|
<div style={{ fontSize: '7.5pt', color: COLORS.slate500, textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 600 }}>{label}</div>
|
||||||
<div style={{ fontSize: '16pt', fontWeight: 800, color: COLORS.slate900, marginTop: '1mm', fontVariantNumeric: 'tabular-nums' }}>{k.v}</div>
|
<div style={{ fontSize: '16pt', fontWeight: 800, color: COLORS.slate900, marginTop: '1mm', fontVariantNumeric: 'tabular-nums' }}>{val}</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ export function PrintBusinessModelPage({ lang, pageNum, totalPages, versionName
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div style={{ fontSize: '8pt', fontWeight: 700, color: COLORS.slate500, textTransform: 'uppercase', letterSpacing: '0.1em', marginBottom: '2mm' }}>{de ? 'Was der Kunde zahlt vs. spart (KMU 50 MA, Jahr 1)' : 'What customer pays vs. saves (SME 50 emp., year 1)'}</div>
|
<div style={{ fontSize: '8pt', fontWeight: 700, color: COLORS.slate500, textTransform: 'uppercase', letterSpacing: '0.1em', marginBottom: '2mm' }}>{de ? 'Kunde zahlt vs. spart · KMU 50 MA · Jahr 1' : 'Customer pays vs. saves · SME 50 emp. · Y1'}</div>
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '0' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '0' }}>
|
||||||
<StatLine label={de ? 'Kunde zahlt' : 'Customer pays'} value="€25.000" tone="accent" />
|
<StatLine label={de ? 'Kunde zahlt' : 'Customer pays'} value="€25.000" tone="accent" />
|
||||||
<StatLine label={de ? 'Spart: Pentests' : 'Saves: pentests'} value="€13.000" tone="positive" />
|
<StatLine label={de ? 'Spart: Pentests' : 'Saves: pentests'} value="€13.000" tone="positive" />
|
||||||
|
|||||||
Reference in New Issue
Block a user