things I've built
Products
Besides writing, I ship software. One is open source, one is a template you can license.
Palang
Duplicate request suppression for Spring Boot.
A user taps “Pay” twice, a flaky network makes the mobile client retry, or a webhook is redelivered, and the charge happens twice. Palang makes the second request return the first one's response instead of executing again. The client sends an Idempotency-Key; the first request runs and every later request with that key gets the original response back, byte for byte, without the controller being touched.
Apache-2.0 · Java 21 · Spring Boot 3.3+ · v0.4.0
install
implementation 'com.rrmadon:palang-idempotency-spring-boot-starter:0.4.0'
implementation 'com.rrmadon:palang-ratelimit-spring-boot-starter:0.4.0'
# application.yml
palang:
idempotency:
store: redisTake only the starter you need; neither depends on the other. Maven coordinates and a JitPack option are in the README.
What it guarantees
The key alone is never trusted. Payloads are fingerprinted with SHA-256, so reusing one key for two different requests is reported rather than silently answered with the wrong response.
| Situation | Result |
|---|---|
| Same key, same payload, first call | Runs normally |
| Same key, same payload, later call | Original response replayed, with an Idempotency-Replayed: true header |
| Same key, different payload | 409 — a client bug, not a duplicate |
| Same key, original still running | 409 with Retry-After |
| Original returned 5xx | Key released; the retry gets a real attempt |
| No key present | Passes through unguarded (configurable) |
| GET, HEAD, DELETE | Untouched |
Choosing a store
memory (the default) guards one JVM. With more than one replica, three duplicates can land on three instances and all three execute, so use redis. Claiming a key in Redis is a Lua script, not SETNX followed by GET: those two calls are each atomic but not atomic together, and that gap is where a duplicate slips through.
Modules
| Module | Purpose |
|---|---|
| palang-core | Store and key-resolution SPI. No Spring dependency. |
| palang-idempotency-spring-boot-starter | Auto-configured servlet filter for duplicate suppression. |
| palang-ratelimit-spring-boot-starter | Auto-configured servlet filter for request-rate limiting, via Bucket4j. |
| palang-testkit | MutableClock and ConcurrentCallers for testing concurrent duplicates. |
| palang-bom | Version alignment. |
PadelClub
A white-label app for padel & tennis clubs.
A complete source-code template for a club app: court booking, open play, membership, tournaments, coaches and match history. The mobile app runs against a real Spring Boot backend that is included, and you rebrand it from one theme file.
Commercial license · one purchase covers every club or brand you build with it
What's in the box
| Folder | Stack | Purpose |
|---|---|---|
| mobile/ | React Native + Expo + TypeScript | Player-facing app for iOS and Android |
| backend/ | Spring Boot + PostgreSQL + JWT | REST API: auth, venues, bookings, membership, coaches, tournaments, match history, players, open play |
| mock-api/ | TypeScript repository layer | Reference for the swap-to-real-API pattern |
What the app does
- Court booking with day, hour, court and length picker
- Open play and matchmaking
- Tournaments and registration
- Membership plans
- Coaches and session booking
- Match history and player profiles
- Sign in with Apple, email sign-up, password reset
- Notifications
straight talk: not included
- A real payment gateway (payment is mocked)
- Push notifications (mocked)
- Promo-code validation at checkout (the backend rejects a booking made with a promo applied)
- The Next.js admin dashboard, which is a separate product
- Multi-tenancy: v1 is one club per deployment, multi-tenant is planned for a later version
License in one paragraph
One purchase lets you use, modify and extend the source, and build and operate white-labeled club apps for yourself or your clients, with no per-deployment fee. You can't resell or redistribute the source code as a standalone product or template. The full terms ship with the code.



