Adds an OVH-backed branch to /api/presenter/tts so the German presenter
narration is synthesized by OVH AI Endpoints' nvr-tts-de-de (NVIDIA Riva)
reached through the LiteLLM passthrough at /tts-ovh/audio/*, which
injects the OVH API token server-side.
- DE requests now hit ${LITELLM_URL}/tts-ovh/audio/v1/tts/text_to_audio
with the documented body shape (encoding=1, language_code=de-DE,
voice_name=German-DE-Male-1, sample_rate_hz=22050) and return the
audio/wav bytes upstream serves (confirmed RIFF-framed in a smoke test).
- EN continues to hit compliance-tts-service until OVH_TTS_URL_EN is set,
making the eventual EN switch a single env flip.
- OVH and voice/url/sample-rate parameters are env-overridable
(OVH_TTS_URL_DE, OVH_TTS_VOICE_DE, OVH_TTS_SAMPLE_RATE,
OVH_TTS_URL_EN, OVH_TTS_VOICE_EN) so retuning doesn't need a redeploy.
- Defensive: OVH failures surface as 502 (no silent fallback) so upstream
issues are visible during this test rollout.
- wrapPcmAsWav() helper is kept as a safety net in case OVH ever returns
bare PCM instead of a full WAV.
Adds X-TTS-Source response header (ovh | compliance) to make
provenance observable from DevTools.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Photo extracted from CV and placed in public/team/
- Team data updated via MCP (both versions):
- Bio: 18+ years industry/strategy, SVP at ETO GRUPPE,
60 employees, M&A, 11 patents, VDMA/CyberLAGO memberships
- Role: CEO & Gründer (was CEO & Co-Founder)
- Expertise tags: Strategie & M&A, DSGVO/AI Act/CRA,
IoT & Embedded, Web3 & Blockchain, 11 Patente
- photo_url set to /team/benjamin-boenisch.png
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The SDK Live Demo slide renders screenshots via next/image from
/public/screenshots/*.png. Because /screenshots was not on the
PUBLIC_PATHS list, every request was 307-redirected to /auth, and the
next/image optimizer responded with
HTTP 400 "The requested resource isn't a valid image."
leaving the slide with empty dark frames (surfaced in the pitch preview).
next/image also bypasses middleware itself (see the matcher), but the
server-side fetch it performs for the source URL does hit middleware
and carries no investor cookie, so whitelisting the path is required
even for authenticated viewers.
These PNGs are public marketing assets — there's no reason to gate them.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The SDK live-demo slide renders a fake browser URL bar to frame each
screenshot. It used admin.breakpilot.ai, but the actual demo instance
investors should be able to reach lives on admin-dev.breakpilot.ai.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Investors who lost their session or whose invite token was already used
can now enter their email on /auth to receive a fresh access link,
without needing a manual re-invite from an admin.
- New /api/auth/request-link endpoint looks up the investor by email,
issues a new pitch_magic_links row, and emails the link via the
existing sendMagicLinkEmail path. Response is generic regardless of
whether the email exists (enumeration resistance) and silently no-ops
for revoked investors.
- Rate-limited both per-IP (authVerify preset) and per-email (magicLink
preset, 3/hour — same ceiling as admin-invite/resend).
- /auth page now renders an email form; submits to the new endpoint and
shows a generic "if invited, link sent" confirmation.
- Route-level tests cover validation, normalization, unknown email,
revoked investor, and both rate-limit paths.
- End-to-end regression test wires request-link + verify against an
in-memory fake DB and asserts the full flow: original invite used →
replay rejected → email submission → fresh link → verify succeeds.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- USP as slide title (GradientText) above
- Circle doubled to 380px with spinning ring
- Infinity symbol (∞) in center hub instead of text
- Compliance left, Code right inside circle — larger font
- 4 cards in corners (220px wide, larger text, ~5 lines each)
- Cards spread to corners (top/bottom, left/right)
- Dashed SVG lines connecting circle to cards
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Large spinning circle (320px) with USP hub in center
- Compliance items left, Code items right inside circle
- 4 arrows pointing outward to capability cards
- 2 cards left (RFQ, Bidirectional), 2 cards right (Process, Continuous)
- Longer descriptions (~5 lines per card)
- Grid layout: cards | circle | cards
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace broken absolute positioning with clean grid layout:
- Top: Compliance card | BreakPilot hub (spinning) | Code card
- Arrows + sync labels between cards
- Bottom: 4 capability cards in a row
- No more floating text, no overlapping elements
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Cover: remove "für den Maschinenbau" from tagline
- Problem subtitle: Maschinenbauer → Deutsche und europäische Unternehmen
- New USP slide after Solution: bridge between compliance docs/audits
and actual code implementation — RFQ verification, bidirectional sync,
automated process compliance, continuous instead of annual checks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
faqMatch (undefined) → faqMatches[0]. The undefined variable caused
a ReferenceError after streaming completed, which the catch block
turned into "Verbindung fehlgeschlagen" for every subsequent message.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Admins in preview mode can now use /api/chat and other investor
endpoints without needing a separate investor login.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Regulatorien + Branche moved to top header row
- Branche: white/70 instead of white/30 for readability
- Regulatorien: indigo color instead of grey
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove colored dot legend row (redundant with column headers)
- Stagger column headers on 2 rows (odd/even) to save space
- Last column: Reg. → Regulatorien
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Column headers: centered text labels instead of icons
- Remove colored dots from headers
- Last column: # → Reg. (Regulierungen)
- Consistent column width for last column
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- grid items-stretch so cards match height
- Smaller avatar (16->64px) to free vertical space
- Equity moved to a top-right pill (compact); decimals collapsed via equityDisplay()
- Profile link icon auto-detects GitHub vs LinkedIn vs generic
- Expertise tags get their own divider strip at card bottom — cleaner hierarchy
- Card background lightened from 0.08 to 0.04 with subtle hover border
Bio text itself shortened on the data side (both draft versions via admin API).
- Add Nginx SSL server block for pitch-deck on port 3012
- Route through Nginx instead of direct container port
- Restore secure cookie flag (requires HTTPS)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
HTTP access on local network was blocked by secure cookie flag when
NODE_ENV=production. Now requires explicit opt-in via env var.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Setup instructions for the pitch version MCP server.
.mcp.json contains the admin secret and is gitignored.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stdio MCP server that wraps the pitch-deck admin API, exposing 11 tools:
list_versions, create_version, get_version, get_table_data,
update_table_data, commit_version, fork_version, diff_versions,
list_investors, assign_version, invite_investor.
Authenticates via PITCH_ADMIN_SECRET bearer token against the deployed
pitch-deck API. All existing auth, validation, and audit logging is
reused — the MCP server is a thin adapter.
Usage: add to ~/.claude/settings.json mcpServers, set PITCH_API_URL
and PITCH_ADMIN_SECRET env vars. See mcp-server/README.md (to be added).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces raw JSON textarea in version editor with proper form UIs:
- Company: single-record form with side-by-side DE/EN tagline + mission
- Team: expandable card list with bilingual role/bio, expertise tags
- Financials: year-by-year table with numeric inputs
- Market: TAM/SAM/SOM row table
- Competitors: card list with strengths/weaknesses tag arrays
- Features: card list with DE/EN names + checkbox matrix
- Milestones: card list with DE/EN title/description + status dropdown
- Metrics: card list with DE/EN labels
- Funding: form + nested use_of_funds table
- Products: card list with DE/EN capabilities + feature tag arrays
- FM Scenarios: card list with color picker
- FM Assumptions: row table
Shared editor primitives (components/pitch-admin/editors/):
BilingualField, FormField, ArrayField, RowTable, CardList
"Edit as JSON" toggle preserved as escape hatch on every tab.
Preview: admin clicks "Preview" on version editor → opens
/pitch-preview/[versionId] in new tab showing the full pitch deck
with that version's data. Admin-cookie gated (no investor auth).
Yellow "PREVIEW MODE" banner at top.
Also fixes the [object Object] inline table type cast in FM editor.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Arrays of objects (funding_schedule, founder_salary_schedule, etc.)
now render as editable tables with per-field inputs, add/remove row
buttons, instead of a raw JSON string in a single text input.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>