The ROI calculator accepted the email field with no validation at all and
stored whatever arrived, which is where the spam submissions were putting
shell-command payloads. Nothing was executable — there is no child_process
or eval in the codebase and all writes are parameterized — but the junk was
being persisted, and the field is the obvious place to stop it.
Adds security.validateEmail(), deliberately stricter than RFC 5322: the
local part is limited to the characters real addresses use, which excludes
every shell metacharacter (; | & ` $ ( ) < > \ " ' space) and CSV-injection
lead-ins. Also rejects control characters (including the CR/LF used for
mail-header injection), caps lengths at 254/64/253, rejects non-strings,
and normalizes to trimmed lowercase before storage.
Applied to /api/calculate (optional field — empty is fine, present must be
valid) and to /api/leads, replacing its much weaker regex. The client
mirrors the check for immediate feedback; the server remains authoritative.
Also hardens the /api/leads required-field checks, which called .trim() on
unvalidated input and returned a 500 rather than a 400 when a bot posted a
non-string.
Trade-off: RFC-legal but vanishingly rare addresses (foo!bar$baz@x.com, a
leading + in the local part) are rejected. Those characters are the
injection surface.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
- New article: articles/hoa-reserve-fund-health-score.html
- Updated articles/index.html with new card (newest first)
- Updated sitemap.xml with new URL entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New article: articles/hoa-board-meeting-financial-questions.html
- Updated articles/index.html with new card (newest first)
- Updated sitemap.xml with new URL entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New article: articles/hoa-cash-flow-management-mistakes.html
- Updated articles/index.html with new card (newest first)
- Updated sitemap.xml with new URL entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Nav and footer now use the logo SVG alone (it already contains the
HOA LedgerIQ wordmark) at correct aspect ratio, dropping the
redundant text spans and the 36x36 square sizing that shrank it
- Privacy and Terms pages: replaced V1 dark-theme inline colors
(white headings, light gray body) with dark ink colors for the
V2 white background
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implements the revised website enhancement requirements:
- Light, clean Apple-style layout (system font stack, pill buttons,
generous whitespace) with a dark AI showcase section
- SEO foundation: meta description, Open Graph, Twitter Card, and
JSON-LD (SoftwareApplication, Organization, FAQPage)
- Native HTML pricing tiers (Starter $29 / Professional $79 /
Enterprise custom) with monthly-annual toggle, replacing the
uncrawlable iframe; pulled from app.hoaledgeriq.com/pricing
- New sections: How It Works (3 steps), trust bar, FAQ accordion,
spreadsheet comparison table, closing CTA
- Mobile hamburger menu (nav previously disappeared under 640px)
- Pillar pages surfaced in footer (investment, reserve studies,
assessment calculator)
- Performance: deferred Chatwoot load, image dimensions, preload
hints, no blocking webfont
- Accessibility: skip link, aria states, prefers-reduced-motion
- ROI calculator preserved (same IDs/handlers in app.js); new v2.js
for hamburger, billing toggle, section highlighting, GA4 events
- Legacy article styles retained so Insights pages keep working
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- New article: articles/hoa-financial-transparency.html
- Updated articles/index.html with new card (newest first)
- Updated sitemap.xml with new URL entry and fixed malformed burnout entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New article: articles/hoa-treasurer-burnout-guide.html
- Updated articles/index.html with new card (newest first)
- Updated sitemap.xml with new URL entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New article: articles/hoa-reserve-fund-cd-laddering.html
- Updated articles/index.html with new card (newest first)
- Updated sitemap.xml with new URL entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New article: articles/hoa-budget-season-guide.html
- Updated articles/index.html with new card (newest first)
- Updated sitemap.xml with new URL entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New article: articles/hoa-special-assessments-prevention.html
- Updated articles/index.html with new card (newest first)
- Updated sitemap.xml with new URL entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace display:none/flex slide toggling with CSS grid stacking so all
slides always occupy the same layout cell. The container height is now
fixed at the tallest image height — no more text jumping below the
carousel as slides change. Also enables the existing opacity fade
transition which was previously blocked by display:none.
Affects: index.html, articles/why-we-built-hoa-ledgeriq.html,
articles/hoa-financial-blind-spots.html, and all future articles.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create articles/ directory with hub index page (newest-first card grid)
- Add Article 1: "Why We Built HOA LedgerIQ" (March 16, 2026, founder story)
- Add Article 2: "5 Financial Blind Spots Putting Your HOA at Risk" (April 1, 2026, use case)
- Both articles include screenshot carousel, article CTA, prev/next nav, and full SEO meta
- Add blog/article CSS to styles.css (hub hero, card grid, article prose, showcase, CTA)
- Add "Insights" nav link to index.html, reserve-study-software.html, investment-management.html
- Add "Insights" to footer Pages column on all pages (index.html gets a Pages column added)
- Add articles/ pages to sitemap.xml with appropriate priorities and lastmod dates
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>