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.Code is deployed. Two features wait on Cloudflare/Resend dashboard steps Neil must do (no safe CLI/API path for a git-deployed Pages project). All code fails safe until then. After Neil confirms each, Claude verifies.
A) Activate lead capture (v1.2.2) — REQUIRED for leads to store:
reiss-builds-html → Settings → Bindings → Add → D1 database. Variable name DB (exact), database reiss-builds-leads. Save (Production).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"email_status = sent.B) Turn on /admin/leads viewer (v1.3.0 — BUILT + DEPLOYED, returns 403 until configured):
reissbuilds.com, path /admin*. Add a policy allowing the right emails (e.g. jeff@ + neil). Copy the Application Audience (AUD) tag and your team domain (<team>.cloudflareaccess.com).CF_ACCESS_TEAM_DOMAIN = <team> (or full <team>.cloudflareaccess.com), CF_ACCESS_AUD = the AUD tag. Save → Redeploy./admin path.C) Security hygiene (non-blocking — form works today): rotate exposed Resend key. resend.com/api-keys → create reissbuilds-pages (Sending, domain reissbuilds.com) → copy → delete old key re_d9yZYtrP_… → Pages → Variables and Secrets → Production → edit RESEND_API_KEY → paste → Save → Redeploy.
/admin/leads viewer — BUILT (v1.3.0, 2026-07-21)functions/admin/leads.ts — server-rendered Pages Function. Verifies the Cloudflare Access JWT (RS256 sig vs team JWKS + iss/aud/exp), fails closed (403) if the JWT or the CF_ACCESS_* env vars are missing/invalid. Renders a newest-first table of D1 submissions and exports CSV via ?format=csv. Read-only (no delete in v1). PII responses are no-store + noindex; all output HTML-escaped; CSV guarded against formula injection. Activate via RESUME step B above.
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).