South Florida construction/remodeling site (client: Jeffrey Reiss). Static marketing site + one serverless contact form.
_site. Templates are .njk.reiss-builds-html, deploys automatically from the 11ty branch (NOT main). Push to 11ty = production deploy.functions/api/contact.ts (the contact form handler).reiss-builds-leads (id 272ae673-1534-4776-b0bb-942ae93eab0c) — contact-form lead capture. Schema in migrations/0001_create_submissions.sql./admin (DecapCMS — NO working prod auth).package.json + CHANGELOG.md only (no footer version).gh (gh auth setup-git; authed as neilswhite)..git/index.lock recurs on this machine — run rm -f .git/index.lock before commits if it blocks.wrangler is logged in on this machine (Neil ran npx wrangler login). The Cloudflare MCP can list Workers/D1 but CANNOT set Pages secrets or D1 bindings — those are dashboard-only for Pages.Flow: /contact (Turnstile widget) → POST functions/api/contact.ts → honeypot + length/email validation → Turnstile verify → D1 insert (capture the lead, source of truth) → Resend email (best-effort notification) → record email_status on the row → redirect /thank-you/.
noreply@reissbuilds.com (Resend domain verified). Recipient: jeff@reissbuilds.com, overridable via LEAD_RECIPIENT env var (use in a Preview env to test to your own inbox). reply_to = the submitter's email.TURNSTILE_SECRET, RESEND_API_KEY, optional LEAD_RECIPIENT. Binding: DB → reiss-builds-leads.jeff@/j.ross@reissbuilds.com are Titan email (root MX). Resend uses only the send. subdomain + DKIM, so it does not affect Titan.The contact form is FIXED and deployed. Lead capture code is deployed but inactive until the D1 binding is added. Neil needs to do these in the Cloudflare dashboard, then Claude verifies:
reiss-builds-html → Settings → Bindings → Add → D1 database. Variable name DB (exact), database reiss-builds-leads. Save (Production).reissbuilds-pages (Sending, domain reissbuilds.com) → copy → delete old key → Settings → Variables and Secrets → Production → edit RESEND_API_KEY → paste → Save. (Old key re_d9yZYtrP_… is exposed in git history — must rotate.)After Neil confirms, Claude should: submit a test at /contact, then
npx wrangler d1 execute reiss-builds-leads --remote --command "SELECT id, created_at, first_name, last_name, email, email_status FROM submissions ORDER BY id DESC LIMIT 10"
— confirm the row exists with email_status = sent.
/admin/leads viewerBuild a page to browse + CSV-export captured leads from D1. Must sit behind Cloudflare Access (free Zero Trust) because it exposes customer PII — gate the function to refuse serving unless an Access JWT (Cf-Access-Jwt-Assertion) is present. This also fixes the long-broken DecapCMS /admin auth.
Contact form silently lost leads for ~a year. Root cause was three stacked failures: (1) Turnstile TURNSTILE_SECRET didn't match the site widget (invalid-input-secret) — rejected every submit at the spam gate; (2) Resend was on the onboarding@resend.dev sandbox (only delivers to account owner dev+github@agilemedia.agency) → 403 on every lead; (3) Resend domain unverified. All fixed 2026-07-20 (v1.2.1). Lead capture (v1.2.2) added so this can never silently happen again. Full detail in project memory (session_2026-07-18_email_diagnosis.md).