Blog
What I learn while building. Technical deep-dives, honest numbers, and lessons from shipping solo.
No LLM in My Kids App's Mascot: Pre-Generated Dialogue Instead
Why Penny, the mascot in my kids' money board game, never calls an LLM at runtime: a pre-generated dialogue bank, a fallback chain, and a one-time batch job.
Supabase generateLink Doesn't Send Email: My Pastor Invites Never Arrived
Supabase invite link not working? auth.admin.generateLink returns the link and sends nothing. My SaaS threw it away, so new pastors never got access.
Turbo Stream Broadcasts Lost on Mobile: My Result Was Ready, the Screen Never Knew
Turbo Stream broadcast not received on mobile? Phones drop the Action Cable websocket when you switch apps. How I added cheap Stimulus pollers as a safety net.
My Bottleneck Was the Offer, Not SEO: A Two-Sided Marketplace Cold Start
I spent months on SEO for FastPass. The real problem was a two-sided marketplace cold start on the creator side. What my own build and database showed, and what I changed.
My Stripe Webhooks Were Failing 96% of the Time
FastPass moves money through Stripe webhooks. 96 percent of them were silently failing the signature check. The culprit was not Stripe. It was crypto in the edge runtime.
1,791 Pages, Zero Indexed
A canonical mistake collapsed my tool site from ~1,800 indexed pages to 2. The code was fine. The real fix was not more pages, it was authority.
I Emailed 312 Users Who Ignored My App. Their Replies Shipped Three Fixes in 48 Hours.
Dashboards told me retention was bad. Three user replies told me why: a deterministic filter, a cutout model eating clothes, and a quiz field nobody ever saved.
My Sitemap Advertised 11 Pages. The Site Had 56.
My prerendered SPA shipped around 50 indexable pages, but the sitemap listed only 11. The prerender step and the sitemap had quietly drifted into two lists.
The Soft 404 That Hid My Multi-Tenant SaaS From Google
Search Console flagged Soft 404s across all three domains of my church-website SaaS. The culprit was a tenant page that returned 200 with a 'not found' message. The fix was one line in the right file.
No Budget Cap on a Third-Party API
RapidAPI emailed me that my Amazon data plan was at 100% of its monthly quota. The plan has overage fees and no way to say 'stop at my budget,' so I put the cap in my own code: a Redis counter, a guard before every call, and a cache TTL bumped from 6 hours to 7 days.
My Sidekiq Worker OOM'd Four Times. I Fought It Four Ways Before Buying RAM.
A closet-dump upload burst kept OOM-killing OutfitMaker's Sidekiq worker. I answered with four escalating memory defenses over five days — a semaphore, a downscale, a malloc flag, a concurrency cut — before admitting the real fix was a bigger box. Here's which defenses I kept and which I undid.
The Failed Payments My Database Invented
OutfitMaker's subscriptions table was full of `incomplete` rows that looked exactly like broken checkouts losing me money. Stripe had never heard of any of them. The bug wasn't in my payment flow — it was in what I was counting, and it was pointing me at the wrong leak.
My AI Was Blind in Production for Weeks and Nothing Crashed
OutfitMaker's multimodal outfit suggestions were supposed to look at your actual clothes. In production they were running on text labels alone — 0 out of 25 items reaching the model with an image. No exception, no alert. Just a one-line log and a one-line Dockerfile fix.
Blocking 7,500 Disposable Email Domains
The day after I finally got my conversion rate to be trustworthy, it lied to me again — not a bug this time, but a wave of throwaway-email signups inflating the top of the funnel. The fix was a blocklist, a memoized Set, and one word in a validator: on: :create.
Why Every Funnel Event in My Analytics Read Zero
Pageviews tracked fine, but every funnel milestone in OutfitMaker — Signup, Activation, First Item Uploaded — sat at a flat zero. Three compounding bugs, then a fourth, all hiding behind a dashboard that looked merely quiet instead of broken.
I Added Circuit Breakers to a Rails App and Had to Patch the Gem Twice
Wrapping OutfitMaker's six external API calls in circuit breakers was the easy part. Making breaker_machines actually trip — and actually survive a worker restart — took two monkey patches and a lot of reading the gem's internals.
I Swapped Fashn for Gemini and Discovered Vertex AI Can't Return Images
Replacing OutfitMaker's virtual try-on engine looked like a service-object swap. It turned into a same-day cascade of five fixes, including discovering the Gemini API I was already using can't return images.
A Duplicate Turbo Frame Bug That Broke Three Features Silently
Two turbo-frame elements with the same id, one HTTP response, three dead features in OutfitMaker. No exception, no Honeybadger hit, no console error. Just a click that did nothing.
A TOCTOU Bug in My Gemini Rate Limiter
A read-then-write pattern in OutfitMaker's rate limiter let concurrent requests bypass the daily Gemini quota. The fix compresses to a single atomic increment, but understanding why takes a minute.
PWA Over Native for a Fashion App
Why I chose a Progressive Web App over native iOS/Android for OutfitMaker. Camera access works, installation works, and I don't need Apple's permission.
SEO for Indie Hackers: What Actually Worked
Real data from 4 months of SEO effort on OutfitMaker. The strategies that moved the needle and the ones that wasted my time.
Rails 8 Migration on a Live Product
Upgrading from Rails 7.1.5 to 8.1 with paying users. The strategy, the gotchas, and why I fixed 103 test failures before touching the Gemfile.
From Zero to First Paying Customer
First commit to first €7.99. The timeline, the numbers, what worked and what didn't on the path to revenue.
Hotwire Over React for a Solo Dev
Real-time features without a JavaScript framework. How Turbo Streams and Stimulus gave OutfitMaker everything it needed with a fraction of the complexity.
Multimodal AI for Outfit Suggestions
How sending actual photos to Gemini instead of text descriptions transformed OutfitMaker's suggestions from generic to genuinely useful.
How I Got ChatGPT to Recommend My Product
Traffic from chatgpt.com appeared in my analytics. Here's what GEO means for indie products, and the specific steps that worked.
Building in Public While Still Learning
The tension between sharing your work and not feeling like an expert. How one Reddit post brought 40 users in 24 hours.
My First State Machine in Rails
How OutfitMaker's outfit suggestion flow evolved from nested if/else into a proper state machine. The gem, the gotchas, and why it clarified everything.
Why I Switched from RSpec to Minitest
RSpec felt like too much ceremony for a solo project. Here's how I migrated 341 tests, what broke, and why simpler was better.