Scrape Prometheus Over the VPC, Not Through Cloudflare
We routed our Prometheus scrape through Cloudflare's edge with a WAF rule + OAuth gate. Both droplets shared a DO VPC. Here's the simpler architecture we should have built first.
Insights on URL shortening, link management, and web development from the Jo4 team.
We routed our Prometheus scrape through Cloudflare's edge with a WAF rule + OAuth gate. Both droplets shared a DO VPC. Here's the simpler architecture we should have built first.
A PromQL ratio that's 0/0 when traffic is quiet + humanizePercentage on nil + noDataState=NoData = repeating 4-hourly Slack noise. Here's the asymmetric fix.
Hardcoded Cloudflare IP ranges in your DO firewall go stale every couple of years. Here's how to fetch them live in CI so drift is impossible.
DSNs are public identifiers embedded in your client bundle. Storing them as GitHub Secrets is cargo-cult security. Here's what actually belongs in each.
Pin folderUid in your Grafana dashboard provisioning and the container exits 1 with 'folder already exists.' Here's the surprising ordering and the one-line fix.
You sed-i a file Docker bind-mounted into a container, the host file updates, the container keeps reading the old content. Here's why — and how to do it right.
Your apt-lock wait loop will lie to you. On DigitalOcean's Ubuntu 24.04 droplets, the contention isn't where you think — and pgrep only sees half of it.
We shipped an MCP server so Claude routines can shorten links, pull stats, and manage Jo4 accounts. Turns out it's mostly OAuth — here's the recipe that worked.
Replacing 30s polling with SSE sounds easy. The hard part is reconnect, auth, RTK Query cache patching, and not blowing up on tab background.
Add a second app instance and your SSE stream only sees events from the pod the user is on. Here's the Redis pub/sub fan-out that fixes it.
Our backend hit Auth0's /userinfo as a fallback for missing JWT claims — thousands of external calls per day. The right fix was on the Auth0 side.
Adding a single trusted-source rule to a previously-open DO managed Postgres flips the entire DB into enforcement mode. We learned this the hard way.
Our denormalized click counters silently reset under load. The culprit was a one-line interaction between @Modifying @Query and @Version. Here's the fix.
We back up Postgres nightly to DigitalOcean Spaces. Every Sunday a separate workflow restores the latest dump into a sandbox. Here's the pipeline.
Stripe webhooks can't reset yearly subscribers. FREE users never trigger a payment at all. Here's the @Scheduled job that resets every account on the 1st.
Our LLM-backed URL safety classifier silently returned empty strings on hard pages. The token budget wasn't the problem we thought it was.
How we built a per-user rate limiter for our Groq LLM endpoint using a Redis sorted set and a 15-line Lua script. Atomic, fast, and fail-open by design.
How we added four metrics to a Spring Boot 3.4 scheduler in under an hour. No Prometheus operator, no Grafana dashboards, no YAML hell. Just counters and a timer.
Our dev.to crosspost script had two time windows that were supposed to align. A publishAfter bypass broke the invariant and turned every CI run into a Slack spam cannon.
Building an embeddable stats widget that works inside anyone's iframe without breaking their CSP or yours. Here's the full tutorial with code.
Spring Security's blanket headers were breaking embeds, leaking stack traces, and conflicting with custom CSP. Here's how I found and fixed all four issues in one weekend.
My affiliate tracking links were returning HTML instead of 302 redirects. The SPA was swallowing every URL. Here's how a Cloudflare Worker fixed it at the edge.
3,059 lines of Cloudflare Worker tests using Vitest and vi.stubGlobal, no miniflare required. Here's why lightweight unit tests catch the bugs that matter.
14 lines fixed a maddening flaky test. Auth0 SPA SDK writes tokens to localStorage after handleRedirectCallback(), but Playwright snapshots state before the write completes.
We deleted 10,000 lines of Terraform and added 1,637 lines of Playwright E2E tests. Here are the 5 things that took longer than writing the actual tests.
A brand clicks 'Accept' on a bid, but the bid stays in SUBMITTED state. The root cause: notification failures were rolling back the entire transaction.
Two endpoints, two opposite behaviors for inactive campaigns — and both are correct. Here's why pixel tracking returns 200 while postbacks return 400.
235 lines of changes to add FTC disclosure acknowledgment as a server-side gate. Small diff, legally critical. Here's why a checkbox isn't enough.
How we modeled bid negotiations as a state machine with display priority, bid templates, and a security fix for a timing-attack oracle. 1,782 lines of tests.
How we built a full affiliate marketplace with Stripe Connect integration where jo4 never holds or moves a single dollar. 14 database tables, 27 services, 81 test files.
Our mobile app hammered the server every 30 seconds for notifications. We ripped it out and built direct FCM + APNs push. Here's every step.
A 5-line config that plays a sound notification when Claude Code finishes a task or needs your input. Tiny hack, massive quality-of-life upgrade.
How we built a tile-merging game with level-ups, marshmallow animations, and an AI autoplay that uses expectimax search with corner-lock strategy.
Need a custom printable calendar? Our free PDF generator has year, month, and weekly views with day filtering. No signup, no ads, works offline.
Referral marketing tools start at $29/mo and don't include link tracking. We already had the link infrastructure. So we built Referral Kit.
You already have Stripe working perfectly. Then Apple says your mobile app needs IAP. Here's how I integrated RevenueCat with a Spring Boot backend without losing my mind.
Google Play rejected our AAB with a signing key mismatch. The culprit was a lazy regex quantifier in our release script that swapped debug and release signing configs.
You deleted the URL. Redis says it's gone. But users click it and still get redirected. The culprit: stale Cloudflare CDN cache that nobody told to purge.
Fire Meta Pixel on every short link click without touching your destination site. Perfect for affiliate marketers and advertisers.
Your EAS build works. Now App Store Connect wants screenshots in exact dimensions, export compliance declarations, and privacy questionnaires. Here's what nobody told you.
Our mobile CI/CD went from 'push to Play Store' to 'push to both stores simultaneously' with parallel EAS builds. Here's the workflow.
We added AdSense to every page. Conversions dropped. Here's why utility pages and ads don't mix, and where ads actually make sense.
Auth0's free tier includes 25,000 MAU. Their paid Essentials plan starts at 500 MAU. Yes, you read that right. Here's how to think about Auth0 pricing as a startup.
EAS makes iOS builds easy, they said. Just run one command, they said. Here's the 4-hour rabbit hole I fell into with provisioning profiles, Sign in with Apple, and Services IDs.
We built a complex settlement system with hold windows, clawbacks, and carry-forwards. Then we deleted it all. Here's why simpler won.
Our OAuth scope parsing worked in tests but failed in production. A comma vs a space broke Pipedream. Here's the fix.
A 405 from bot scanners, a filter ordering misfire, and a race condition in user creation. All in one commit. Here's what went wrong.
Our dev.to sync tool republished unchanged articles daily. The root cause: comparing updatedAt against published_at instead of edited_at.
Our URL shortener showed 'Link Not Found' on Safari but worked fine on Chrome. The root cause: a browser-level JS execution difference.
A senior dev once told me: 'Every side project is born from spite.' He was right. Here's the story of building jo4.io.
When to use synchronous vs asynchronous audit logging in your application. A practical guide with real examples from production.
A practical decision guide for choosing between ElastiCache and MemoryDB. TL;DR: If your data is ephemeral, use ElastiCache.
Using PreToolUse hooks to block dangerous git commands and cd in Claude Code. Keep your AI assistant productive without losing control.
How I built jo4.io - a developer-friendly URL shortener with full API access and white-label support. Why Bit.ly pricing made me do it.
OAuth2 with PKCE, REST hooks, a spam filter disaster, and a near-closed ticket. The full story of building and shipping our Zapier integration.
Learn how to use Jo4 for URL shortening, QR codes, and link analytics. A complete guide to managing your links effectively.
Enterprise referral platforms want $300/mo minimum. Here's how I built invite link tracking for my SaaS using a URL shortener and $0 extra spend.
We built 20 utility tools and made them completely free. No signup, no ads, no catch. Here's the full list and why we did it.
ClawHub integration took 30 minutes. The hardest part? Keeping up with their domain name changes. From calwd to openclaw to clawhub - we've seen it all.
Pipedream doesn't have a developer dashboard. You email their team directly. Sounds scary? It's actually the fastest integration process we've experienced.
Auto-crossposting sounds simple until you deal with duplicates, stale dates, and race conditions. Here's how we made it bulletproof.
Three days to get a 'simple' OAuth integration working with Zapier. Here's what I learned about filter chains, race conditions, and PKCE.
Writing blog posts is easy. Publishing them consistently is hard. Here's how we built a homebrewed CMS that handles the classic producer-consumer problem.
Your API is getting hammered. Same endpoints, same responses, thousands of requests. Here's how I used Cloudflare Cache Rules to serve API responses from the edge.
Production bug report: 'Why does the webhook error say Executing an update/delete query?' Here's how an innocent-looking @Async method broke everything.
Adding team plans to a SaaS is tricky. You need per-seat pricing, plan upgrades/downgrades, webhook handling, and graceful degradation when payments fail.
Spent an hour debugging why verified users were getting blocked. The culprit? Auth0 doesn't include email_verified in access tokens by default.
After solving all the code issues with Zapier OAuth, I hit one more wall: Cloudflare's Bot Fight Mode. Here's the fix.