DEV Community

HL
HL

Posted on

I tested my SaaS boilerplate against real Stripe, Supabase, and Resend accounts — here's what a "build passing" doesn't tell you

Most boilerplates get shipped the moment npm run build goes green. Mine almost did too — until I decided to actually verify it against live test accounts instead of trusting the compiler. That decision surfaced three real bugs that would have hit the very first real user, none of which TypeScript or a clean build ever flagged.

Here's what I found, and why "it compiles" is a much weaker claim than it sounds.

Bug 1: a Stripe API change that TypeScript didn't catch

The webhook handler for customer.subscription.updated read subscription.current_period_end directly off the event payload:


current_period_end: new Date(subscription.current_period_end * 1000).toISOString()
```



This type-checked fine and even worked when called via `stripe.subscriptions.retrieve()` in a different code path. It crashed — `RangeError: Invalid time value` — only on the raw webhook event payload.

The reason: Stripe recently moved `current_period_end` off the top-level `Subscription` object and onto each `SubscriptionItem`, as part of their flexible billing / multiple-prices-per-subscription changes. A live SDK call to `retrieve()` apparently still exposes a compatibility value, but the raw JSON in a webhook event does not — it's just `undefined` there. `undefined * 1000` is `NaN`, and `new Date(NaN).toISOString()` throws.

TypeScript never caught it, either directly (my installed SDK's type definitions for `Subscription` still declared the field) or after I fixed it by reading `subscription.items.data[0].current_period_end` instead — at that point the *types* hadn't caught up to the *API's* own change yet, and `SubscriptionItem` wasn't typed with the field even though the real API returns it. I only found this because I ran a real subscription through a real webhook, inspected the raw payload with `curl`, and watched it 500.

## Bug 2: a silent failure in auth, not a loud one

Supabase's built-in auth email sender is rate-limited by default — reasonably so, it's meant for early development, not production traffic. I hit that limit a few times while testing signup flows.

What surprised me: when the limit is hit, `supabase.auth.signUp()` doesn't just fail to send the confirmation email — it fails the entire signup, and *no user gets created at all*. No error visible in a cursory glance at the UI, nothing in the account. If I hadn't gone and checked via the admin API afterward, I'd have shipped a product where signups silently vanish above a low, undocumented threshold, until custom SMTP is configured.

## Bug 3: text you can't see, only sometimes

The landing page rendered fine — on my machine, in the theme I usually test in. A dark-mode system rendered the hero heading as dark navy text on a background that defaulted to near-black, because I'd never set an explicit `background-color` on `<body>`. `text-gray-900` doesn't help you when the background isn't `white` — it's just as invisible as the wrong thing.

## What actually caught these

Not the compiler. Not `tsc --noEmit`. Not even a clean `next build`, which passed the whole time bug #1 was live. What caught all three:

- Real test accounts on Stripe, Supabase, and Resend
- A real webhook listener (`stripe listen`) forwarding real events to a locally running server
- A real signup, a real test-card payment, real emails sent and inspected via the Resend API
- A screenshot taken in an actual browser, at actual default settings — not just "the dev server started without errors"

None of this is exotic tooling. It's the difference between "the code type-checks" and "the product works," and for anything selling itself as production-ready, that gap is exactly where the bugs a paying user finds tend to live.

---

If you're curious about the product this came out of — a B2B prospecting CRM template (Next.js 14, Supabase with RLS-enforced multi-tenancy, Stripe subscriptions + billing portal, Resend campaign emails with signed unsubscribe and webhook-based tracking) — it's for sale [here](https://elhugolouis.gumroad.com/l/ivnari), tested the way described above before I put a price on it.
Enter fullscreen mode Exit fullscreen mode

Top comments (0)