All Service Leads.
A roofing-lead marketplace with live Stripe checkout, now growing into prepaid leads and live call transfers. I designed the platform and, with two collaborators, took it to production in April 2026 on Express/Node, Netlify Functions and Supabase Postgres, with Twilio SMS and Resend email.
The Problem
Roofing contractors often pay lead-gen platforms for stale, shared leads under opaque pricing. The economics break for the buyer, the experience breaks for the homeowner, and nobody owns the relationship.
All Service Leads is built around a simple inversion: one flat price per lead or per call, paid once upfront, with no contract and nothing that renews. A contractor picks a ZIP code and a radius, pays, and gets leads from homeowners who asked about their own roof, or takes the call live when a homeowner is connected.
Architecture
Single deployment surface (Netlify), single domain (allserviceleads.com), single Postgres (Supabase). Functions handle the API; the rest is static. Every secret lives in Netlify env, every external write is wrapped in a try/catch so a Twilio outage never 500s the lead form.
[ Visitor / Contractor ] │ ┌─────────────────────┴─────────────────────┐ │ │ /rr-lp.html /dashboard (intake form) (buyer portal) │ │ └─────────────────────┬─────────────────────┘ ▼ Netlify Functions (Express) ┌──────────────┬──────────────┬──────────────┬──────────────┐ ▼ ▼ ▼ ▼ ▼ leads orders stripe coupons admin /intake /checkout /webhook /validate CRUD + refund │ │ │ │ │ └──────────────┴──────────────┴──┬───────────┴──────────────┘ ▼ Supabase Postgres (transaction pooler · RLS) tenant-isolated tables · service vs anon roles │ ┌──────────────────────┼──────────────────────┐ ▼ ▼ ▼ Stripe (live) Twilio (toll-free) Resend (verified) payments + webhook SMS lead-blast transactional
Hardest Engineering Decisions
Server-authoritative promo logic
Promo handling lives entirely server-side. The client never sees the rules, the codes, or the discount math — it gets a final price and a yes/no on whether a code applied. Per-user usage caps, max-quantity limits, and per-code constraints are all enforced on the server before any payment intent is created. Codes that aren't meant to be public are kept out of the rendered HTML so view-source can't enumerate them.
Meta Pixel + CAPI deduplication
Browser Pixel + server-side Conversions API (via Stape gateway) both fire Lead when a homeowner completes the intake form. To prevent Meta from double-counting, every browser/server pair shares a deterministic event_id tied to the new lead's record. Meta dedups on collision and the attribution stays clean.
Serverless + Postgres pooling
Short-lived serverless functions cold-starting fresh DB connections on every invocation = pool exhaustion at scale. Solution: route Postgres through a transaction pooler with prepared-statement caching disabled on the client. Skip the latter and you get a stream of duplicate-prepared-statement errors on every cold start.
Live Operations
This is not a portfolio toy — it processes real card payments and sends SMS to real numbers. That changes the engineering bar.
Auto-deploy from GitHub
Auto-deploys from GitHub on every push to the production branch. Push-before-deploy is the rule; no CLI deploys to production.
Row-level security
RLS enabled on every database table. Service role for server, anon role for client, never the other way around.
Stripe live + webhook
Live Stripe; webhook signature-verifies every event and reconciles order state. Everything else assumes the webhook is the source of truth, not the client.
Twilio toll-free
Verified toll-free number for outbound notifications. Lead-capture SMS blast fans out to a recipient list held in a single env var — editable without redeploying.
Daily watcher
Scheduled trigger pings Twilio once per day; pushes an ntfy alert if the toll-free verification status changes.
Restore-deploy drill
One restoreSiteDeploy call rolls live back to any prior bundle in seconds — free, no rebuild credits, no DNS churn. Tested in anger; see incident below.
Incident: The Rogue CLI Deploy
One night earlier this year, admin lead rows stopped being clickable in production. Black-box smoke-test passed (200s everywhere), but interaction logic was missing from the live admin bundle. Worth telling because the response shape is the differentiator.
Live admin missing UI handlers
Auto-deploy chain looked clean on GitHub, but the host's build history showed a CLI deploy fired earlier in the night with no commit reference and no committer — fingerprint of someone running deploy --prod off a stale local checkout.
Stale checkout, deployed to prod
A CLI deploy from an old local checkout went straight to production. It carried no commit hash and silently overwrote part of the admin UI's handlers.
One API call, instant rollback
restoreSiteDeploy against the last clean auto-deploy bundle. Live restored in seconds, no rebuild, no credits charged. Wrote a permanent recipe so this fix is one paste away next time.
Spec'd a watch daemon
Drafted a periodic Python daemon that watches deploy hooks and alerts on any deploy that doesn't trace back to a commit. Build deferred.
Git-before-deploy is now non-negotiable. Any change goes to source control first; anything that lands on prod without tracing back to a commit on the active production branch gets rolled back on sight.
What I'd Do Differently
- Stage branch deploys. All experiments now go through branch deploys with auto-publish off. Easy to burn through a host's deploy quota when every iteration goes straight to prod — branch-deploy isolation makes the iteration cheap and the production pipeline calm.
- Keep the test harness off live communication APIs. Leftover placeholder numbers in seed scripts can fire real failed-delivery events against a real toll-free number, which hurts carrier verification standing. Mock mode + reserved test numbers belong in any seed/CI path.
- Keep the e2e suite in lockstep with the billing model. When the pricing model flipped to upfront-at-create, a handful of older test assertions kept passing while testing the wrong invariant. Easy to miss, worth a sweep.
Wheaton Valet Cleaners →
Multi-brand Next.js 16 client build: one codebase, 26 routes, Resend and OpenPhone intake, ongoing SEO.