← All entries

Thursday, May 7, 2026

Day 35 — Building the founding-barn funnel in a day

We shipped a full founding-barn acquisition funnel today — outreach email, landing page, self-serve Stripe checkout with a lifetime discount, live cohort counter, and graceful UX when the last spot fills. Plus: closing out a post-launch routing bug that had been on the list since day one.

4 min read

Daily entry

Day 35of building EquinePilot

Currently Day 77 · founder build log

Milestones reached

  • founding-barn-program
  • signup-routing-fix

Day 35. Three days past launch. I wanted to write about the founding-barn program today because it's the first time I've shipped a complete acquisition funnel in a single session — from outreach email all the way through to a confirmed Stripe subscription at a special price — and that felt worth marking.

The pitch: 10 barns, 50% off Suite, forever

The founding-barn program is simple: the first 10 barns to sign up get the Suite tier at $39.50/month instead of $79 — for life. Billed from day one, no trial cliff, no expiration. In exchange for taking a leap of faith on software that's three days old.

The "for life" framing matters more than the price. A 50% discount that expires in six months is a trial with extra steps. A permanent discount says: you believed in this when it was new, and we're not going to take that back. It's a different kind of relationship.

What I actually built

I started with the outreach email — the thing that kicks the whole funnel off. Warm HTML, three subject-line options, merge tags for personalization. It went through two rounds of iteration before it felt right. I cut the cohort from 25 to 10 (25 was aspirational, 10 is classically tight — scarce enough to mean something). I flipped the pricing from "six months free" to "50% off for life" once I worked through the implications. And I dropped the "book a 15-minute call" CTA entirely.

That last change deserves a note. Equestrian barn owners are notoriously communication-averse. They run physical operations — horses, staff, clients, schedules — and their inbox is already full of things that need a response. Any hint of a call is a conversion killer. The new CTA goes straight to a claim URL.

The landing page (/founding) backs that up: a hero explaining the offer, a form for inbound interest, and — added in a second commit — a live counter. "3 of 10 spots claimed." It revalidates every 60 seconds. When the cohort fills, the entire page swaps: the CTA becomes "continue to standard signup" so late arrivals convert rather than bounce.

The signup flow wires it all together. ?founder=FOUNDER10 on the signup URL forces the page into founding-barn mode — Suite tier locked, direct-purchase, no trial toggle, a banner explaining what they're getting. On submit, the API validates the code, checks the cohort count, sets a foundingMember flag on the barn, and attaches a Stripe coupon to the checkout session. Two independent guards on the cap: app-side count check, and Stripe's max_redemptions as a backstop for any race condition.

The whole thing, from outreach HTML to working Stripe checkout, in one session.

A routing bug that had been on the list

While I was in the signup flow anyway, I closed out a bug that's been sitting in the known-issues list since before launch. After signup, the "Go to your barn" button was routing to the app root — which meant anyone who already had a different barn's session active in their browser got silently redirected into that other barn's dashboard. Not a crash, just quietly wrong.

The fix: route to /login?email=<theirs> instead, and update middleware to let that URL render even when a different user is active. The login page prefills the email. Same-email sessions still skip the login page. Clean.

Also fixed: "Go to your barn" was building its URL from getAppUrl(), which resolves to the production domain. So anyone signing up on a preview deploy got a "Go to your barn" link that pointed to production. Now it uses a relative path on the success screen and VERCEL_BRANCH_URL in emails, so the links stay in whatever environment the signup happened in.

The boring infrastructure that makes previews trustworthy

Three more commits tightened branch preview fidelity: preview emails now show a yellow banner and a "[Preview]" sender prefix so they're never confused with real emails, the marketing site reads signup URLs from an env var rather than hardcoding production, and a prebuild script on the web app queries the Vercel API to find the matching stablesync preview URL for the current branch.

That last one is more annoying than it sounds. Vercel branch URLs aren't deterministic across projects — each project truncates and hashes long branch names independently — so you can't construct the URL from the branch name. You have to ask Vercel's API. It falls back to the production URL on any error so it can't break a build, but when it works, a PR's marketing-site preview routes to that PR's StableSync preview automatically.

None of that is visible to users. But it's the kind of thing that, once it's in place, makes testing a preview actually meaningful rather than a game of "am I sure this isn't hitting production?"

What's next

CourseWalk implementation starts soon — the planning doc is already in the repo, the schema migration landed two days ago. The founding-barn funnel will run in parallel; once the email goes out, the counter and claim flow are live and ready.

Thirty-five days in. Still building.