feat(pitch-deck): add passwordless investor auth, audit logs, snapshots & PWA
Some checks failed
CI / go-lint (pull_request) Failing after 17s
CI / python-lint (pull_request) Failing after 12s
CI / nodejs-lint (pull_request) Failing after 7s
CI / test-go-consent (pull_request) Failing after 11s
CI / test-python-voice (pull_request) Failing after 11s
CI / test-bqas (pull_request) Failing after 11s
CI / Deploy (pull_request) Has been skipped
Some checks failed
CI / go-lint (pull_request) Failing after 17s
CI / python-lint (pull_request) Failing after 12s
CI / nodejs-lint (pull_request) Failing after 7s
CI / test-go-consent (pull_request) Failing after 11s
CI / test-python-voice (pull_request) Failing after 11s
CI / test-bqas (pull_request) Failing after 11s
CI / Deploy (pull_request) Has been skipped
Implement a complete investor access system for the pitch deck: - Passwordless magic link auth (jose JWT + nodemailer SMTP) - Per-investor audit logging (slide views, assumption changes, chat) - Financial model snapshot persistence (auto-save/restore per investor) - PWA support (manifest, service worker, offline caching, icons) - Security safeguards (watermark overlay, rate limiting, anti-scraping headers, content protection, single-session enforcement) - Admin API for invite/revoke/audit-log management - Integrated into docker-compose.coolify.yml for production deployment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,9 @@ import { AnimatePresence } from 'framer-motion'
|
||||
import { useSlideNavigation } from '@/lib/hooks/useSlideNavigation'
|
||||
import { useKeyboard } from '@/lib/hooks/useKeyboard'
|
||||
import { usePitchData } from '@/lib/hooks/usePitchData'
|
||||
import { useAuditTracker } from '@/lib/hooks/useAuditTracker'
|
||||
import { Language, PitchData } from '@/lib/types'
|
||||
import { Investor } from '@/lib/hooks/useAuth'
|
||||
|
||||
import ParticleBackground from './ParticleBackground'
|
||||
import ProgressBar from './ProgressBar'
|
||||
@@ -14,6 +16,7 @@ import NavigationFAB from './NavigationFAB'
|
||||
import ChatFAB from './ChatFAB'
|
||||
import SlideOverview from './SlideOverview'
|
||||
import SlideContainer from './SlideContainer'
|
||||
import Watermark from './Watermark'
|
||||
|
||||
import CoverSlide from './slides/CoverSlide'
|
||||
import ProblemSlide from './slides/ProblemSlide'
|
||||
@@ -38,13 +41,22 @@ import AIPipelineSlide from './slides/AIPipelineSlide'
|
||||
interface PitchDeckProps {
|
||||
lang: Language
|
||||
onToggleLanguage: () => void
|
||||
investor: Investor | null
|
||||
onLogout: () => void
|
||||
}
|
||||
|
||||
export default function PitchDeck({ lang, onToggleLanguage }: PitchDeckProps) {
|
||||
export default function PitchDeck({ lang, onToggleLanguage, investor, onLogout }: PitchDeckProps) {
|
||||
const { data, loading, error } = usePitchData()
|
||||
const nav = useSlideNavigation()
|
||||
const [fabOpen, setFabOpen] = useState(false)
|
||||
|
||||
// Audit tracking
|
||||
useAuditTracker({
|
||||
investorId: investor?.id || null,
|
||||
currentSlide: nav.currentSlide,
|
||||
enabled: !!investor,
|
||||
})
|
||||
|
||||
const toggleFullscreen = useCallback(() => {
|
||||
if (!document.fullscreenElement) {
|
||||
document.documentElement.requestFullscreen()
|
||||
@@ -117,7 +129,7 @@ export default function PitchDeck({ lang, onToggleLanguage }: PitchDeckProps) {
|
||||
case 'team':
|
||||
return <TeamSlide lang={lang} team={data.team} />
|
||||
case 'financials':
|
||||
return <FinancialsSlide lang={lang} />
|
||||
return <FinancialsSlide lang={lang} investorId={investor?.id || null} />
|
||||
case 'the-ask':
|
||||
return <TheAskSlide lang={lang} funding={data.funding} />
|
||||
case 'ai-qa':
|
||||
@@ -140,10 +152,16 @@ export default function PitchDeck({ lang, onToggleLanguage }: PitchDeckProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-screen relative overflow-hidden bg-gradient-to-br from-slate-950 via-[#0a0a1a] to-slate-950">
|
||||
<div
|
||||
className="h-screen relative overflow-hidden bg-gradient-to-br from-slate-950 via-[#0a0a1a] to-slate-950 select-none"
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
>
|
||||
<ParticleBackground />
|
||||
<ProgressBar current={nav.currentIndex} total={nav.totalSlides} />
|
||||
|
||||
{/* Investor watermark */}
|
||||
{investor && <Watermark text={investor.email} />}
|
||||
|
||||
<SlideContainer slideKey={nav.currentSlide} direction={nav.direction}>
|
||||
{renderSlide()}
|
||||
</SlideContainer>
|
||||
|
||||
Reference in New Issue
Block a user