- Add footer links for Impressum, Privacy Policy, Terms of Service
- Create legal pages: /impressum, /privacy, /terms (Austrian/EU compliant)
- Add EU hosting badge highlighting GDPR compliance and EU data residency
- Add Express routes for legal pages with caching headers
- All pages use consistent dark theme design matching landing page
- Docker healthcheck: Use Node.js instead of curl (not installed in slim image)
- Pricing: Change from USD ($) to EUR (€) in frontend and backend Stripe integration
- Static assets: Add Cache-Control headers (1 day) for /public and /docs files
- Remove duplicate text/html from nginx gzip_types (fixes nginx -t warning)
- Update hardcoded API version from 0.2.0 to 0.2.1 to match package.json
- Update logrotate config: daily rotation, 7 days retention, improved postrotate
- Add Docker logging configuration with size/file limits
- Update sitemap.xml to include /v1/health endpoint
- Add proper 404 handling (JSON for API paths, HTML for browser paths)
- Create optimized nginx config with gzip, cache headers, specific locations
- Add logrotate configuration for DocFast logs
- Add security headers and static asset caching
- Replace JSON file storage with PostgreSQL (pg package)
- Add db.ts service for connection pool and schema init
- Rewrite keys.ts, verification.ts, usage.ts for async PostgreSQL
- Update all routes for async function signatures
- Add migration script (scripts/migrate-to-postgres.mjs)
- Update docker-compose.yml with DATABASE_* env vars
- Change SLA from 99.9% to 99.5% in landing page
Inline script was already extracted to swagger-init.js (BUG-004/005).
Helmet defaults allow style-src unsafe-inline and font-src https,
so Google Fonts and inline styles work without custom directives.
- Fix swagger-ui symlink in Dockerfile (was pointing to /opt/docfast instead of /app)
- Add CSP directives to allow inline scripts/styles and Google Fonts
- Add email-change.ts route with rate limiting (3/hr) and verification
- Add updateKeyEmail to keys service
- Add email-change route to index.ts with CORS support
- Launch BROWSER_COUNT separate Chromium instances (default: 2)
- Each with PAGES_PER_BROWSER pages (default: 8, 16 total)
- Round-robin distribution across browser instances
- Independent restart scheduling per browser
- Updated health endpoint to show per-browser stats
- docker-compose: added BROWSER_COUNT and PAGES_PER_BROWSER env vars
Investor Directive 1: Key recovery now shows key in browser after email verification code.
- Removed sendRecoveryEmail function entirely
- Recovery endpoint returns apiKey in JSON response (shown once in browser)
- Added full recovery modal UI (email → code → key displayed)
- Added "Lost your API key?" links throughout signup flow
Investor Directive 3: Rate limits adjusted to match server capacity.
- Global rate limit: 100/min → 30/min (server handles ~28 PDFs/min)
- CORS: recover routes now restricted to docfast.dev origin
- POST /v1/recover: request recovery code
- POST /v1/recover/verify: verify code, receive key via email
- Key sent via email only (not in API response) for security
- Rate limited to 3 attempts per hour
- Non-enumerable: same response whether email exists or not
- DKIM-signed emails via postfix/opendkim
- Signup now requires email verification before API key is revealed
- Verification token sent via email (Resend) with console fallback
- GET /verify?token=xxx shows API key in styled HTML page
- Handles expired (24h), invalid, and already-verified tokens
- Frontend modal shows 'check your email' instead of key
- Keeps existing rate limiting
- Added CORS middleware allowing docfast.dev origin
- Added app.set('trust proxy', 1) to fix ERR_ERL_UNEXPECTED_X_FORWARDED_FOR
- The rate limiter was crashing on every proxied request through nginx
- Added /v1/signup/free endpoint for instant API key provisioning
- Built unified key store (services/keys.ts) with file-based persistence
- Refactored auth middleware to use key store (no more hardcoded env keys)
- Refactored usage middleware to check key tier from store
- Updated billing to use key store for Pro key provisioning
- Landing page: replaced mailto: link with signup modal
- Landing page: Pro checkout button now properly calls /v1/billing/checkout
- Added Docker volume for persistent key storage
- Success page now renders HTML instead of raw JSON
- Tested: signup → key → PDF generation works end-to-end