DEV Community

krrrt
krrrt

Posted on

I Built 15 Digital Products in a Week Using Claude — Here's What Actually Broke

Over the past week I built and shipped 15 digital products — 2 Chrome extensions, a resume scanner, a UI template, and 11 SaaS starter kits with genuinely different architectures: invoicing, feature flags with percentage rollouts, outbound webhooks with HMAC signing, usage-based billing via Stripe, and one that ships a real browser extension alongside the web app.

Everything was built through Claude. But the part worth writing about isn't the generation — it's what testing actually surfaced.

Bug #1: A hash function that wasn't as random as it looked

The feature-flag starter needed deterministic percentage rollouts — the same user should always get the same result for a given flag, computed by hashing flagKey:distinctId into a 0-99 bucket.

The first version used a simple polynomial rolling hash:

\js
let hash = 0;
for (let i = 0; i < seed.length; i++) {
hash = (hash * 31 + seed.charCodeAt(i)) >>> 0;
}
\
\

Looked fine in isolation. But a test script checking independence between two different flags for the same user turned up a problem: users "in" one flag's rollout were suspiciously likely to also be in an unrelated flag's rollout.

The cause: two strings of the same length differing by one character in the same position produce hashes that differ by a fixed offset with this kind of hash — not an independent, unpredictable one. "flagA:user-0" and "flagB:user-0" differ by a constant delta, and that delta is the same regardless of the user number.

Fixed by switching to FNV-1a:

\js
let hash = 0x811c9dc5;
for (let i = 0; i < seed.length; i++) {
hash ^= seed.charCodeAt(i);
hash = Math.imul(hash, 0x01000193);
}
hash = hash >>> 0;
\
\

Re-ran the independence test: two unrelated flags for the same 1,000 simulated users now disagreed about 47% of the time — right where independent 50/50 decisions should land.

Bug #2: Building on an API that got deprecated mid-build

The usage-based billing starter needed to report metered usage to Stripe. I started implementing it against stripe.subscriptionItems.createUsageRecord() — the classic approach for metered billing.

Turns out Stripe fully deprecated that approach in 2025 in favor of a new Billing Meters system. The old flow (attach a metered price directly to a subscription item, report usage against that item) doesn't exist anymore for new integrations — you now create a Meter object first, then report usage against a customer ID via stripe.billing.meterEvents.create().

Had to redo the schema (no longer need to track a subscription item ID at all — usage reports against the customer directly) and the reporting call. A reminder that "I've seen this pattern before" isn't the same as "this pattern is still current."

What's actually live

12 of the 15 are live under one storefront if you want to look at the code or the live demos: https://whop.com/table-export-tools/products/

Happy to go deeper on any of the architectures — team-based billing vs. per-user billing, CORS setup for a browser extension talking to an API, HMAC signing for outbound webhooks, whatever's interesting.

Top comments (0)