- Regulatory landscape footer: text-xs text-white/50 (was text-[9px] text-white/20)
- New POST /api/admin/import-fp endpoint to import fp_* data from JSON dump
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
POST /api/admin/migrate creates all fp_* tables on production DB.
Admin-only, creates tables with IF NOT EXISTS for safe re-runs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GitHub avatar (github.com/mighty840) saved as /team/sharang-parnerkar.jpg.
Team-data JSON for both draft versions (Wandeldarlehen and The Ask 1 Mio)
was updated out-of-band via the admin API:
- Bio lengthened (~640 chars DE/EN) to match Benjamin's depth — now
covers the ETO tenure (3→60 org scale), ETOPay, ViviSwap/MiCA,
enterprise AI on AWS/Azure/SysEleven, embedded Rust work, and the
ferrite-sdk open-source project.
- photo_url switched from empty to /team/sharang-parnerkar.jpg.
- Expertise tags unchanged.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Compute endpoint now returns cached results if available (single SELECT
instead of DELETE + 60 INSERTs)
- When recompute is needed, batch all 60 rows into a single INSERT
- Reduces DB calls from 61 to 2 (cached) or 3 (recompute)
- Fixes timeout/blank financial slides for investors
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The SDK Live Demo was janky: AnimatePresence mode="wait" unmounted the
current Image before mounting the next, so every advance forced a cold
fetch and left an empty black frame until the new image decoded. Only
the first three screenshots had priority; the rest fetched lazily, so
the first pass through the carousel repeatedly stalled.
Replaces the single swap-in/swap-out Image with a stack of 23 images
layered in an aspect-[1920/1080] container. Cross-fades are now pure
CSS opacity on always-mounted nodes, so there is no unmount and no gap.
Key details:
- priority on the first 3 (triggers <link rel="preload">); loading=eager
on the remaining 20 so the browser starts all fetches at mount rather
than deferring via IntersectionObserver.
- sizes="(max-width: 1024px) 100vw, 1024px" lets next/image serve the
actual displayed resolution instead of the 1920 hint — fewer bytes,
faster first paint.
- Load-gated reveal: a new `shown` state trails `current` until the
target image fires onLoadingComplete. If the user clicks ahead of
the network, the previous loaded screenshot stays visible — no more
black flashes before images arrive.
Second pass through the carousel is instant (images are in-cache).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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).