TIL

Today I Learned — short, focused write-ups, usually under 300 words.

Payments4 min read

Making Stripe Webhook Handlers Idempotent After a Duplicate Purchase Grant

TIL that Stripe can and will deliver the same webhook event more than once, and a handler that reacts to checkout.session.completed by granting access will happily grant it twice — the fix was recording processed event IDs and treating the handler as a set operation, not an append.

#Stripe
Backend4 min read

Serving Premium Downloads Without Exposing the File's Real Storage URL

TIL how to replace a guessable direct-download link with a permission-checked, time-limited presigned URL, so the object storage path a purchased asset actually lives at is never sent to the client.

#Security
Real-time5 min read

Server-Sent Events Instead of WebSockets for Live Vote Counts

TIL that live vote tallies only need server-to-client push, not a full-duplex protocol — swapping a hand-rolled WebSocket setup for Server-Sent Events dropped the reconnection logic entirely and simplified the reverse proxy config.

#Server-Sent Events
Backend4 min read

Live Poll Results Without WebSockets: Server-Sent Events in a Node.js API

TIL that once vote writes were race-free, the results screen still felt dead until a manual refresh — switching from client polling to Server-Sent Events made results update instantly without the bidirectional complexity WebSockets would have added for a channel that only ever sends in one direction.

#Node.js
Backend4 min read

Preventing Duplicate Votes in a Polling API Under Concurrent Requests

TIL that a 'check if the user already voted, then write' guard is racy under concurrent requests — the fix was a unique compound index plus an atomic $inc, so MongoDB rejects the duplicate instead of the app trying to catch it first.

#MongoDB
Frontend2 min read

A global color-scheme: dark leaks into print/PDF output unless you override it

TIL that setting color-scheme: dark once on html/body for a dark-themed site makes the browser paint its default canvas background dark everywhere that property cascades — including print and PDF output — unless @media print resets it.

#CSS
Architecture2 min read

Webhooks retry, so make the receiver idempotent — not the sender reliable

TIL that webhook delivery is at-least-once, not exactly-once. Instead of trying to prevent duplicate deliveries, derive a deterministic ID from the event and let the receiver refuse to redo work it already did.

#Webhooks
Next.js3 min read

A JSX expression-container attribute silently loses its value in next-mdx-remote

TIL that generating attr={"..."} into MDX source instead of attr="..." made a prop come back as an empty object on every render, with no error anywhere in the pipeline — found while writing the Obsidian-callout preprocessor for this site.

#Next.js
Search2 min read

One Fuse.js index can search five different content types at once

TIL that a single flat Fuse.js index with weighted keys is enough to search blog posts, TIL entries, projects, case studies, and snippets together — no separate index or backend needed per collection.

#Fuse.js
Backend3 min read

A Dead WebSocket in a Broadcast List Breaks the Whole Broadcast Loop

TIL that looping over every connected WebSocket client and sending a message throws on the first one that's already gone, which silently drops the update for everyone still connected after it in the list — the fix is a try/except per connection, not around the loop.

#WebSockets
Backend2 min read

A 'Hidden' S3 URL Isn't Access Control — Short-Lived Signed URLs Are

TIL that a private-looking direct download URL for a purchased file is still a public URL forever, and the fix is generating a signed, expiring link on demand after checking ownership server-side.

#Next.js
React2 min read

useOptimistic auto-reverts on failure — a hand-rolled optimistic hook doesn't

TIL why React's useOptimistic hook doesn't need explicit rollback code when a server call fails, while a manual optimistic-update hook built on plain useState does.

#React
SEO2 min read

AEO vs SEO, and what I changed here to be more AEO-friendly

TIL: Answer Engine Optimization (AEO) optimizes for being the answer an AI cites, not just ranking in a list of blue links — and most of what makes a Next.js site AEO-friendly is stuff good SEO already wants.

#AEO
Browser Extension2 min read

MutationObserver re-triggers on your own injected DOM — guard against it

TIL a MutationObserver watching a third-party page fires again on the elements your own extension code just injected, causing an infinite injection loop unless the injection function is idempotent.

#Chrome Extension
Backend3 min read

Debugging Problems That Only Appear in Production

TIL that a bug I couldn't reproduce locally turned out to depend on a real difference between environments — request concurrency — that my local setup structurally couldn't produce, no matter how hard I tried to repro it.

#Debugging
DevOps2 min read

Using Traefik as a Reverse Proxy for a Self-Hosted Stack

TIL that manually editing an Nginx config and restarting it for every new service didn't scale past a handful of containers — Traefik's label-based routing removed that step entirely by discovering services automatically.

#Docker
DevOps2 min read

Using Docker for Application Deployment: The Boring Win I Underrated

TIL that 'works on my machine' stopped being a real category of bug the day I containerized the API, not because Docker is clever but because it removed an entire class of environment-drift I'd been debugging manually.

#Docker
Frontend2 min read

Using Framer Alongside a Development Workflow, Not Instead of One

TIL that building the Clonify Framer plugin taught me Framer is a genuinely different target than a normal web build — its plugin runtime and code-component model don't map 1:1 onto React conventions.

#React
React2 min read

Turning Figma Designs Into Reusable React Components

TIL that building each screen straight from its Figma frame produced pixel-accurate but unreusable components — the fix was designing the component API from the design system's tokens, not from any one screen.

#React
Mobile3 min read

Designing a Delivery App for Unreliable Networks, Not Just Offline

TIL that 'handle offline' undersold the actual problem — the failure mode that hurt drivers most was a flaky, half-connected state, not a clean offline/online boundary.

#React Native
Backend2 min read

Choosing Object Storage Instead of the Database for Application Images

TIL that storing delivery-proof photos as base64 blobs in MongoDB worked fine at low volume and turned into slow queries and ballooning backups once real usage kicked in.

#File Storage
DevOps2 min read

Choosing Node.js Hosting for a SaaS: What Actually Mattered vs. What I Thought Would

TIL that I picked Render for a Node.js API expecting the deciding factor to be price, and the thing that actually mattered day to day turned out to be deploy simplicity and predictable cold-start behavior.

#Node.js
Architecture3 min read

Designing a Complete Delivery-Management System as a Solo Developer

TIL that a system spanning a browser extension, a React Native app, an API, and a database only stayed maintainable solo because I treated the API as the one real product and everything else as a thin client of it.

#Architecture
Mobile3 min read

Building Photo Proof of Delivery: Camera to Dashboard, End to End

TIL that the hard part of a photo-proof-of-delivery feature isn't the camera or the upload individually — it's making sure a completed delivery can never end up without its proof attached.

#React Native
Frontend3 min read

Designing a Dispatch Management Dashboard for Real Operations, Not a Generic Admin Panel

TIL that a dispatch dashboard built around 'show all the order fields' overwhelmed the person actually using it — the redesign that worked started from what a dispatcher needs to decide, not what data exists.

#React
Chrome Extensions2 min read

Writing a Reliable Regex for Extracting Delivery Times

TIL that a regex tuned against a handful of examples ('DELIVERY TIME: 2:00 PM') broke on real data within a day because of extra whitespace and inconsistent AM/PM casing I hadn't accounted for.

#JavaScript
Chrome Extensions2 min read

Extracting Delivery Information from Dynamically Rendered HTML

TIL that a content script querying the DOM immediately on page load found nothing, because the POS's order details render client-side, after the content script's own 'document_idle' point had already passed.

#Chrome Extension
Next.js1 min read

Route Handlers can return a plain Response, not just NextResponse

TIL you don't need NextResponse for a simple Route Handler — a standard Web API Response works fine, which matters for things like hand-rolled RSS/XML endpoints.

#Next.js
Architecture3 min read

Building a POS Integration Without Controlling the POS

TIL that integrating with a system you don't own means designing for its changes, not just its current behavior — the architecture that survived was the one that assumed the POS would break the integration eventually.

#Architecture
Chrome Extensions3 min read

Connecting a Chrome Extension to a Node.js API

TIL that a fetch call from a content script that worked fine in the console failed silently from the actual extension, because content scripts run in an isolated world with their own CORS and CSP rules.

#Chrome Extension
Chrome Extensions2 min read

Injecting Custom UI Into a Website You Don't Own

TIL that a naive injected panel kept getting wiped out by the host page's own re-renders — the fix was watching for that, not fighting it, and mounting into a container the host page has no reason to touch.

#Chrome Extension
Chrome Extensions3 min read

Reading Data from an Existing Web App with a Chrome Content Script

TIL that a content script reading order data straight from the DOM breaks every time the POS ships a markup change — the fix was reading from the most stable layer available, not the most convenient one.

#Chrome Extension
Chrome Extensions2 min read

Building a Chrome Extension with Manifest V3

TIL that MV3's move from persistent background pages to event-driven service workers means you can't hold long-lived in-memory state the way old extension tutorials assume — it gets killed and restarted constantly.

#Chrome Extension
Frontend2 min read

Converting API Timestamps to the User's Local Time Instead of Hardcoding Dubai Time

TIL that hardcoding a UTC+4 offset for timestamps because most orders happened to be local worked right up until a driver or a server ended up in a different timezone.

#JavaScript
Mobile2 min read

Understanding UnknownHostException in Android (and Why the API 'Worked Locally')

TIL that an Android UnknownHostException on a hostname that resolved fine everywhere else usually isn't a DNS problem at all — it's the app pointed at a hostname that only ever existed on my dev machine.

#React Native
Mobile3 min read

Debugging Production API Failures by Reading the Client's Error, Not the Server's Logs

TIL that when a mobile app reports 'network error' against a production API, the fastest path to the actual cause is the client-side error object, not tailing server logs that show nothing wrong.

#React Native
Mobile2 min read

Debugging an Android-Only FormData Upload Failure

TIL an upload that worked reliably on iOS and failed intermittently on Android came down to a missing file extension on the filename I was generating — Android's multipart parsing cared, iOS's didn't.

#React Native
Mobile2 min read

Uploading Images from React Native to a Node.js API

TIL that a multipart upload from React Native needs the file described as an object with uri/name/type, not sent as a raw file:// string — an easy mismatch to miss since it fails silently on some devices.

#React Native
Mobile2 min read

Understanding React Native File URIs Before You Try to Upload One

TIL that a file:// URI from Expo's camera isn't a file you can send as-is — it's a path into a cache directory the OS can clear, and the upload code needs to treat it that way.

#React Native
Mobile2 min read

Android-Specific React Native Problems That Never Show Up on iOS

TIL that a React Native feature working perfectly in the iOS simulator is not evidence it'll work on Android — cleartext traffic, back-button handling, and permission dialogs all diverge silently.

#React Native
Mobile2 min read

Building React Native Apps with Expo: What the Managed Workflow Actually Buys You

TIL that starting a React Native app in Expo's managed workflow paid off immediately for camera/location access, but I still had to understand what 'ejecting' would cost before I needed it.

#React Native
Architecture2 min read

Designing One API for Both a Web Dashboard and a Mobile App

TIL that a REST API originally shaped around the web dashboard's screens needed real redesign, not just new endpoints, once a React Native app started consuming it too.

#Node.js
Backend2 min read

Building Authentication Into a Full-Stack App Without Reinventing Sessions Badly

TIL that storing a JWT in localStorage for an app that also needed server-rendered authenticated pages was the wrong call, and cookie-based sessions were less work, not more.

#Authentication
Backend2 min read

Building Applications with Payload CMS Instead of a Custom Admin Panel

TIL that hand-rolling an admin panel for content the client needed to edit themselves cost more time than adopting Payload CMS's schema-as-code approach, even with its own learning curve.

#Payload CMS
Backend3 min read

Debugging a MongoDB/WiredTiger Cache Pressure Issue in Production

TIL that intermittent MongoDB slowdowns that don't show up in query logs can be a WiredTiger cache eviction problem, not a query problem — and the fix was a resource limit, not an index.

#MongoDB
Backend3 min read

Designing MongoDB Schemas with Mongoose Without Fighting Yourself Later

TIL that a MongoDB collection modeled around how a screen displayed data instead of how the data actually related caused a rewrite once a second screen needed the same data differently.

#MongoDB
Backend2 min read

Building REST APIs with Node.js and Express That Don't Fall Apart at Route 40

TIL that an Express API without a consistent response/error shape is fine at 10 routes and a real liability at 40 — the fix was boring middleware, not a framework change.

#Node.js
React2 min read

Using RTK Query for API Communication Instead of Hand-Rolled Fetching

TIL that most of my hand-written loading/error/cache state was solving a problem RTK Query already solves, and the switch removed more bugs than it added dependencies.

#React
React2 min read

Building Reusable React Components Across Web and Mobile

TIL sharing components across a React web app and a React Native app only works if you split presentation from platform primitives from day one — retrofitting it later means rewriting most of your UI layer.

#React
React3 min read

Moving from PHP to React: What Actually Changes

TIL the hard part of moving from PHP to React isn't JSX syntax — it's unlearning page-per-request thinking and stopping the urge to mutate the DOM yourself.

#PHP