Things I learned
I keep this for myself, so the things that cost me an afternoon only ever cost one. Mostly configuration that is obvious in hindsight and documented nowhere in one piece. If you have wandered in and find something useful here, all the better.
- 11
My ISP blackholed Fastly and I spent a day blaming my code
GitHub loaded without styles and Reddit would not load at all. Not my cache, DNS or firewall: my ISP's route to one Fastly prefix was silently dropping packets, and a phone hotspot proved it in thirty seconds.
- 10
How to publish a closed testing app on Google Play
New personal Play accounts need 12 testers opted in for 14 straight days before production. The rule is really a retention problem, and internal testing is where you earn the right not to waste it.
- 09
What reviewing my own open-source repo taught me about scope
Reviewing Largs Hub like a stranger's codebase turned up bugs that were invisible rather than ugly. The bigger lesson was sizing: a fix that does not fit one reviewable pull request is a project, not an issue.
- 08
Replacing the Whisper API with whisper.cpp: cutting transcription costs to zero
Local transcription did not make my costs zero, it moved them. What it bought was permission to re-run the whole back catalog every time I changed how I segment verses.
- 07
The AWS bill I didn't expect: how a forgotten phone number in another region cost me
A phone number claimed in a region you never revisit bills a flat lease forever, too small to notice. Why the console hides it, the sweep that finds it, and the alarm that catches a dollar a month.
- 06
Push notifications in Expo with Firebase: a step by step setup
Expo's push service still delivers through FCM and APNs, so you need Firebase either way. The FCM V1 service account key is the step that trips everyone up, and none of it works in Expo Go.
- 05
Your S3 bucket is not a CDN: fixing slow images with CloudFront
Putting CloudFront in front of S3 gets you maybe a third of the win. The rest is Cache-Control on the objects, images sized to their slot, and a cache key that knows about your query strings.
- 04
Building a Rambox alternative in Electron
Why I built one on WebContentsView instead of webview, and the three bugs that taught me the most: orphaned session partitions, a domain check missing a dot, and hibernation that killed running work.
- 03
How to set up Resend as SMTP on Supabase
Supabase's built-in mailer only delivers to your own team and caps at two messages an hour. Swapping in Resend takes ten minutes, and the step everyone forgets is the rate limit.
- 02
Uploading images directly to S3 from Next.js
A Next.js route signs a short-lived upload URL and the browser sends the image straight to S3, so the file never passes through your server. Revised from a 2024 note for AWS SDK v3 and the App Router.
- 01
Twitter (X) OAuth 2.0 in a React app
Signing users in with X from a React app: the authorization code flow with PKCE, which credentials you actually need, and why the code exchange belongs on your server. Revised from a 2023 note.