Fixes
Real bugs from real indie projects, traced to root cause and solved.
19 fixes · all from production
Payments & billing 2
One subscription across web and mobile (Stripe + RevenueCat + Supabase)
Pay on web or mobile, unlock both, never double-charge, by making one Supabase column the source of truth instead of reconciling two billing systems.
3 min read →
Stripe + Gelato print-on-demand, end to end
Let users buy a real printed poster of what they made: render at print resolution, host it, charge with Stripe, and create the Gelato order from the webhook, not the browser.
3 min read →
Supabase & data 5
The Supabase free-tier keepalive that actually works
A free-tier Supabase project pauses after a week idle, and the obvious keepalive cron still let it sleep. The reason: the request was getting a 401 at the gateway. Here is the endpoint that returns 200 with the anon key.
2 min read →
Supabase Realtime breaks on remount unless the channel is unique
A Realtime subscription works once, then throws or goes silent when the component remounts. The cause is two subscriptions fighting over the same channel name. Clean up on unmount, and make the name unique per mount.
1 min read →
Use signed URLs, never public storage URLs
A public Supabase bucket is the quick way to show user uploads, and a permanent data leak. Private bucket, owner-scoped policies, and short-lived signed URLs give you the same convenience without handing out forever-links.
2 min read →
Account deletion that satisfies the app stores (and GDPR)
Apple and Google require in-app account deletion. The traps are the order you delete in and trusting a client-supplied id. Here's the Supabase version that doesn't orphan storage or delete the wrong user.
2 min read →
Rate limiting in Postgres, no Redis
You don't need Redis or a third-party service to rate-limit a Supabase app. One table, one atomic upsert, and a security-definer function keyed to the user. Race-safe and impossible to bypass.
2 min read →
Cloudflare & deploy 6
When wrangler dies behind a corporate proxy, use the API
Wrangler and other vendor CLIs hang or throw TLS errors behind a corporate proxy that intercepts HTTPS. Skip the CLI and drive the Cloudflare REST API directly with curl and a scoped token.
2 min read →
A Pages custom domain added by API gets stuck on 'CNAME record not set'
Attach a custom domain to a Cloudflare Pages project through the API and it can sit at pending forever. The dashboard auto-creates the DNS record; the API doesn't, and a Pages-scoped token can't either.
2 min read →
Your Cloudflare Pages env vars do nothing (Direct Upload vs Git build)
You set a PUBLIC_ variable in the Pages dashboard, redeploy, and the build still can't see it. The reason: a Direct Upload project builds in your CI, not on Cloudflare, so the dashboard env vars never reach the build.
2 min read →
Your Cloudflare build passes locally but silently fails in CI
A Vite alias that reached outside the repo root built fine locally but failed on Cloudflare Pages for weeks, while the old bundle kept serving.
2 min read →
A stale vite.config.js silently overrode my vite.config.ts
Edits to vite.config.ts had no effect because a compiled vite.config.js sat next to it, and Vite loads the .js in preference to the .ts.
1 min read →
Hosting public images from a locked-down Windows box
Behind a corporate proxy, wrangler and the throwaway upload hosts all failed. GitHub plus jsDelivr was the dependable free image host.
2 min read →
Windows & tooling 2
PowerShell mangles quotes in CLI args, so pass JSON by file
A curl or gh command with inline JSON works in bash and cmd but the payload arrives corrupted from PowerShell. PowerShell rewrites embedded double quotes when handing args to native executables. Pass the payload by file or stdin instead.
2 min read →
PowerShell globbing mangles Expo Router [id] file paths
Reading and writing files at bracketed paths like app/[id]/index.tsx failed because PowerShell treats [id] as a wildcard character class.
1 min read →
Marketing ops 1
More 3
Pin a card footer to the bottom of an equal-height grid
Cards in a grid have different amounts of text, so their prices and links land at ragged heights. Two CSS lines pin every footer to the bottom, no fixed heights and no JavaScript.
2 min read →
Search Console rejects a bare sitemap filename
Submitting sitemap.xml to a Search Console domain property fails or just won't take. A domain property wants the full absolute URL, not the filename.
1 min read →
The hidden attribute stops working when CSS sets display
A modal with the hidden attribute rendered open on every page load and refused to close. The cause: a one-line CSS display rule silently overrides the hidden attribute, and a one-line attribute selector fixes it.
2 min read →