WRITING / 29 ENTRIES
Notes from the build.
Web development, remote work, and what I learn shipping products — written down so I (and maybe you) don’t relearn it twice.
FEATURED
ALL ENTRIES
Disk Fills Up at 3am: How to Actually Diagnose It
df -h says 0 bytes free. Nothing obvious changed. Here's the sequence of commands I run — in order — to find the actual cause before it becomes a repeat incident.
JWT Refresh Tokens: Where Short Expiry Goes Wrong
Short-lived access tokens feel secure. Refresh tokens that last 30 days and can't be invalidated mean your sessions are effectively permanent. Here's where that assumption breaks — and what the implementation actually looks like.
Flask Rate Limiting Behind nginx: You're Rate-Limiting the Wrong IP
Flask-Limiter looks correct in development. Behind nginx in production, request.remote_addr returns the proxy's address — so your per-IP limits apply to a single bucket shared by all users.
SQL Injection in 2026: What SQLAlchemy Still Can't Protect Against
SQLAlchemy's ORM parameterizes filter conditions and insert values. It does not parameterize column names, table names, or any raw SQL you write with text(). Four patterns appear regularly in Flask apps where the ORM assumption silently breaks.
Vue 3.5's useTemplateRef Makes DOM Animation Code Cleaner
The old ref<HTMLElement | null>(null) pattern works, but TypeScript fights you at every null check that can never actually happen. useTemplateRef removes the noise and makes composable-level DOM access finally clean.
Vue 3.4's defineModel: The v-model Boilerplate Is Gone
Building custom form components in Vue 3 meant writing the same four lines every time: modelValue prop, update:modelValue emit, computed getter, computed setter. defineModel collapses all of it into one macro call.
Migrating from Nuxt 3 to Nuxt 4: What Actually Broke
I migrated this portfolio from Nuxt 3 to Nuxt 4 over a weekend. The big changes are well documented. Here's what caught me off guard — and the order to do it in.
What Nuxt 4 Actually Changed (and What to Do About It)
I built this portfolio on Nuxt 4 instead of 3. Most tutorials are still written for 3. Here's what bit me — the srcDir default, the import.meta.client migration, and why compatibilityDate exists.
Drag-and-Drop File Upload in Vue 3 Without a Library
Every PDF tool on this site needs a file drop zone. I built one without a library — and spent more time on the dragenter/dragleave child-element bug than on everything else combined.
The Two Lines That Make Lenis and GSAP ScrollTrigger Work Together
GSAP ScrollTrigger reads window.scrollY. Lenis overrides window.scrollY. The result is animations triggering at the wrong position — until you sync them through the GSAP ticker.
Vue 3 Composables: The Right Pattern for Wrapping Third-Party Libraries
Every time I reach for a complex third-party library in Vue, I wrap it in a composable. Here's the full pattern — lifecycle, singletons, SSR guards — from building the PDF tools on this site.
Convert Images to PDF (and Back) Without Installing Anything
A practical guide to bundling photos into a single PDF, extracting images from PDFs, and resizing them — all from your browser, all without uploads.
How to Compress a PDF Without Wrecking the Quality
Why PDFs balloon to 50MB when they shouldn't, what compression actually does to your file, and how to shrink one without turning the text into mush.
How to Merge PDFs Without Uploading Them to a Random Website
Most online PDF mergers want your files on their servers. Here's how to combine PDFs locally — fast, free, and without sending your documents into the void.
How Software Developers Can Actually Get Remote Jobs in 2025
Remote jobs are more competitive than ever. This guide breaks down what really works for developers trying to land remote roles in 2025.
Smooth Scroll Animations with GSAP and Nuxt 3
Learn how to create buttery-smooth scroll animations using GSAP's ScrollTrigger plugin in a Nuxt 3 application.
Mastering TypeScript in Vue 3: A Practical Guide
TypeScript and Vue 3 are a perfect match. Here's how to leverage TypeScript's power without fighting the framework.
Implementing Dark Mode with System Preference Support
Build a robust dark mode system that respects user preferences, persists across sessions, and handles system theme changes.