The calculator endpoint was open to anyone, and it has been collecting
spam submissions. Add a layered guard that runs before anything is
written to the DB or sent to the AI provider:
- Cloudflare Turnstile CAPTCHA, verified server-side (active when
TURNSTILE_* keys are configured; fails closed if unverifiable)
- Honeypot field that only bots fill in
- Signed, single-use form token enforcing a 4s minimum fill time
- Per-IP rate limiting (5 per 10 min, 25 per 24h)
Layers 2-4 need no configuration and work on their own, so submissions
are throttled immediately; adding Turnstile keys upgrades it to a full
challenge. Blocked submissions now stop the flow client-side instead of
silently showing a result.
Also sets `trust proxy` for correct client IPs behind nginx, caps the
JSON body at 32kb, and fixes a latent ReferenceError in the
"AI not configured" branch that called saveCalcSubmission() before the
variables it closes over were declared.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Clarify that annualIncome is the total per year, and payment frequency
describes the cash flow timing of installments — not a multiplier on income.
Include per-installment dollar amount so the model understands cash float correctly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Button loading spinner + disable on submit to prevent duplicate AI calls
- Email field and opt-in consent checkbox on calculator form (checked by default)
- Privacy assurance blurb below opt-in
- Refinement blurb on results screen explaining live cash-flow optimization
- calc_submissions SQLite table stores form inputs, computed results, AI text, email, opt-in
- GET /api/calc-submissions endpoint (x-admin-key protected) to retrieve submissions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- server.js: add /api/calculate endpoint using openai SDK with configurable
AI_API_URL, AI_API_KEY, AI_MODEL, AI_DEBUG env vars (works with any
OpenAI-compatible provider: NVIDIA NIM, Together AI, Groq, Ollama, etc.)
- app.js: make calculator submit handler async; call /api/calculate with
graceful fallback to client-side generated text if AI is unavailable
- package.json: add openai and dotenv dependencies
- AI_SETUP.md: rewrite to document new unified env var config with provider examples
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>