Jo4 Blog

Insights on URL shortening, link management, and web development from the Jo4 team.

Reporting UI Errors Without Blowing Up Prometheus

Piping frontend errors to a public backend endpoint is easy. Doing it without a metric-cardinality bomb or a log-injection hole takes a few deliberate choices.

· 5 min read
react observability webdev javascript

Alert on Brand-New Errors, Not Thresholds, with Redis

Count-threshold alerts never fire for the low-volume bug that hits one user. A first-seen detector using Redis SET NX EX alerts the moment a new error appears.

· 5 min read
observability redis grafana java

A Vulnerability Disclosure Policy for a Solo SaaS

Before any pen test or SOC 2 conversation, a product needs a way for researchers to report bugs. Here's the security.txt, PGP, and rotation setup we shipped.

· 5 min read
security saas webdev buildinpublic

Pacing Bulk Async Jobs Under an LLM Rate Limit

A bulk job fanned hundreds of async LLM calls onto a small pool at once and tripped the provider's rate limit. Retry helped; pacing the dispatch fixed it.

· 5 min read
java api performance ai

Versioned Content Fingerprints for Change Detection

How to tell if a web page actually changed — not just its markup — using a normalized, versioned hash. A small pattern that saves real work downstream.

· 6 min read
java architecture webdev api

Rate-Limit Failed Logins Without Locking Out Victims

The naive 'N failures and this account is locked' turns your brute-force defense into a denial-of-service tool. The fix is one decision: what you key on.

· 5 min read
security redis java webdev

OAuth client_credentials in Spring Boot for Prometheus Scrapes

How we added RFC 6749 §4.4 to our Spring Security stack so Prometheus could scrape /actuator/prometheus with a path-scoped CC bearer — and what schema relaxations were needed.

· 13 min read
oauth springboot security prometheus

Bound Spring MVC's Async Executor or Pay for It Under Load

Spring MVC ships a default async task executor with no bounds and no queue. Wire a real one and emit the saturation gauge, or your tail-latency stack pages you at 2 AM.

· 9 min read
springboot java performance observability

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.

· 7 min read
prometheus devops architecture cloudflare

Self-Healing Cloudflare CIDRs in DigitalOcean Firewalls

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.

· 8 min read
cloudflare devops githubactions automation

Your Sentry DSN Is a GitHub Variable, Not a Secret

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.

· 6 min read
githubactions security sentry devops

How to Plug Claude Routines Into Your SaaS With MCP

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.

· 10 min read
ai mcp oauth springboot

Why Your JPA Counter Column Keeps Resetting to Zero

Our denormalized click counters silently reset under load. The culprit was a one-line interaction between @Modifying @Query and @Version. Here's the fix.

· 6 min read
java springboot jpa debugging

The Security Audit That Found 4 Issues in One Weekend

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.

· 5 min read
security java springboot webdev

From 30-Second Polling to Real Push Notifications

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.

· 9 min read
mobile java reactnative architecture

The One-Character OAuth Bug That Broke Our API

Our OAuth scope parsing worked in tests but failed in production. A comma vs a space broke Pipedream. Here's the fix.

· 3 min read
authentication java debugging webdev

Async vs Sync Audit Logging: When to Use Which

When to use synchronous vs asynchronous audit logging in your application. A practical guide with real examples from production.

· 4 min read
java springboot async architecture

Implementing Per-Seat Team Billing with Stripe

Adding team plans to a SaaS is tricky. You need per-seat pricing, plan upgrades/downgrades, webhook handling, and graceful degradation when payments fail.

· 4 min read
stripe saas billing java springboot