1 Dryvestment PDF Generation System
1.1 Overview
The Dryvestment app now includes a secure PDF generation system that allows users to export their investment briefs as professionally formatted PDF documents. The system implements multiple security layers to prevent abuse while maintaining ease of use.
1.2 Architecture
Dryvestment Frontend → Secure API Proxy → Hook-Typst-Export Service → PDF Output
1.2.1 Components
- Frontend Integration (
/public/dryvestment/)- Export PDF button in the interface
- Client-side validation and error handling
- Loading states and user feedback
- Secure API Proxy (
/functions/api/generate-pdf.ts)- Origin validation and rate limiting
- Input sanitization and content processing
- Authentication with downstream services
- PDF Generation Service (
hook-typst-export)- Converts markdown content to professionally formatted PDFs
- Includes Ethical Capital branding and disclaimers
- Handles text wrapping, pagination, and layout
1.3 Security Features
1.3.1 Multi-Layer Protection
- Origin Validation: Only allows requests from authorized domains
- Rate Limiting: 5 requests per hour per IP address
- Authentication: Bearer token validation between services
- Input Sanitization: Removes XSS vectors and malicious content
- Content Limits: 50KB maximum content size
- Source Verification: User-agent and request source validation
1.4 Usage
1.4.1 For Users
- Build an investment brief using the Dryvestment interface
- Review the generated content
- Accept the disclaimer when prompted
- Click the “Export PDF” button
- The PDF will download automatically
1.4.2 For Developers
1.4.2.1 API Endpoint
POST /api/generate-pdf
1.4.2.2 Request Format
{
"title": "Investment Brief Title",
"content": "Markdown formatted content...",
"venue": "Investment Committee",
"decisionMaker": "Board of Trustees"
}1.4.2.3 Response
- Success: PDF file download with appropriate headers
- Error: JSON response with error details and status codes
1.4.2.4 Error Codes
400: Invalid request format or missing fields403: Unauthorized origin or invalid authentication413: Content too large (>50KB)429: Rate limit exceeded503: PDF generation service unavailable
1.5 Implementation Details
1.5.1 Frontend Integration
The PDF generation is triggered by the generatePDF() function:
async function generatePDF() {
if (!ensureDisclaimerAccepted()) return;
if (!state.last) {
alert("Please build a brief first before generating a PDF.");
return;
}
const exportButton = document.getElementById('exportPDF');
exportButton.disabled = true;
exportButton.textContent = 'Generating PDF...';
try {
const response = await fetch('/api/generate-pdf', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
title: state.last.title || 'Investment Brief',
content: state.last.content || '',
venue: state.venue || 'Investment Committee',
decisionMaker: state.decisionMaker || 'Board of Trustees'
})
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
// Handle PDF download
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${(state.last.title || 'investment-brief').replace(/[^a-z0-9]/gi, '_')}.pdf`;
a.click();
URL.revokeObjectURL(url);
} catch (error) {
console.error('PDF generation failed:', error);
alert('PDF generation failed. Please try again.');
} finally {
exportButton.disabled = false;
exportButton.textContent = 'Export PDF';
}
}1.5.2 Security Configuration
Environment variables required:
# In Doppler (deployed to Cloudflare)
TYPST_EXPORT_TOKEN=<secure-bearer-token>
HOOK_TYPST_EXPORT_URL=https://hook-typst-export.srvo.workers.dev
ALLOWED_ORIGINS=https://labs.ethicic.com,https://labs-aw1.pages.dev1.5.3 Rate Limiting
The system implements per-IP rate limiting with the following parameters:
- Limit: 5 requests per hour per IP
- Window: 60 minutes (sliding)
- Storage: In-memory Map (resets on service restart)
- Response: 429 status with
Retry-Afterheader
1.6 PDF Output Features
1.6.1 Content Formatting
- Headings: Bold, purple text in uppercase
- Paragraphs: Clean typography with proper line spacing
- Lists: Bullet points with proper indentation
- Metadata: Context section with venue and decision maker details
1.6.2 Branding
- Colors: Ethical Capital brand purple (#581c87)
- Typography: Helvetica font family
- Layout: Professional margins and spacing
- Disclaimer: Ethical Capital Labs compliance disclaimer
1.6.3 Technical Specifications
- Page Size: US Letter (612 x 792 points)
- Margins: 54 points (0.75 inches)
- Font Sizes: 20pt headings, 12pt body text
- Line Spacing: 4pt between lines, 6-8pt between paragraphs
1.7 Deployment
The system is deployed across Cloudflare’s infrastructure:
- Frontend: Cloudflare Pages
- API Proxy: Cloudflare Functions
- PDF Service: Cloudflare Workers
- Secrets: Managed via Doppler integration
1.7.1 Build Process
# Build and deploy the labs site
npm run build
# Deploys to Cloudflare Pages automatically1.8 Monitoring and Debugging
1.8.1 Logs
- API Proxy: Cloudflare Functions logs
- PDF Service: Cloudflare Workers logs
- Rate Limiting: Console warnings for violations
1.8.2 Common Issues
- “Unauthorized origin”: Check domain whitelist in
ALLOWED_ORIGINS - “Rate limit exceeded”: User hit 5 requests/hour limit
- “Content too large”: Brief exceeds 50KB limit
- “PDF generation failed”: Check hook service availability
1.8.3 Testing
To test the system:
- Visit the Dryvestment app at https://labs.ethicic.com/dryvestment/
- Build a brief using the interface
- Click “Export PDF” and verify download
- Test error cases (no content, rapid requests, etc.)
1.9 Security Considerations
- All credentials are stored in Doppler and deployed securely
- No sensitive data is logged or stored persistently
- Rate limiting prevents abuse and resource exhaustion
- Input sanitization prevents XSS and injection attacks
- Origin validation ensures only authorized domains can access the API
1.10 Future Enhancements
Potential improvements for the system:
- Persistent Rate Limiting: Use Cloudflare KV for cross-instance limits
- Enhanced Formatting: Support for tables, images, and charts
- Template Customization: Different PDF layouts for different use cases
- Audit Logging: Track PDF generation for compliance purposes
- Batch Generation: Support for multiple briefs in one PDF