How I Built a Microservices App With Spring Boot (And What Broke Along the Way)
When I started the Lumora project during my Capgemini training, I thought microservices would be straightforward.
Spoiler: They were not.
The Idea
A car wash booking platform where:
- Customers book services
- Payments are processed via Stripe
- Admins manage bookings and users
- Everything communicates through an API Gateway
Simple enough, right? Wrong.
The Architecture (That I Redesigned Three Times)
My first attempt had everything in one Spring Boot app. My mentor looked at it and said: "This is a monolith. We're building microservices."
Back to the drawing board.
Final architecture:
| Service | Responsibility |
|---|---|
user-service | Auth, registration, JWT |
booking-service | Create/manage bookings |
payment-service | Stripe integration |
notification-service | Email on booking + password reset |
api-gateway | Routes all traffic |
config-server | Central configuration |
eureka-server | Service discovery |
The Part That Broke Everything: JWT + API Gateway
I had each service validate JWT tokens independently. This meant:
- Every service imported the same JWT library
- Token secret was duplicated across config files
- One typo = authentication fails silently
Fix: Moved JWT validation to the API Gateway only. Services trust the gateway. One source of truth.
// Gateway filter - validate once, forward with user info @Component public class AuthFilter implements GlobalFilter { public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String token = exchange.getRequest().getHeaders().getFirst("Authorization"); // validate and attach user context return chain.filter(exchange); } }
Stripe Integration — Easier Than I Expected
I was terrified of payment integration. Turned out Stripe's Java SDK is incredibly well documented.
The scary part wasn't Stripe — it was making sure the payment-service and booking-service stayed in sync. If a payment succeeded but the booking update failed, we'd have a ghost payment.
I handled this with a simple event-based approach using Feign Client callbacks. Not perfect, but it worked for the scope of this project.
What I Learned
- Config Server saves you from config hell. Centralise early.
- Service discovery with Eureka feels like magic — until it doesn't register and you spend 2 hours debugging port conflicts.
- SLF4J logging with correlation IDs makes debugging distributed systems actually possible.
- Mockito tests forced me to think about dependencies in a way unit tests on monoliths never did.
Would I Use Microservices for Every Project?
No. Absolutely not.
For a small project, this was massively over-engineered. But the goal was to learn — and I learned more from this one project than from months of tutorials.
If you're learning Spring Boot, build a monolith first. Then break it apart. You'll understand why microservices exist, not just how to use them.
The app is live (locally 😅). Stripe works. JWT works. Eureka registers all five services.
And honestly? That feeling when all five services start up and talk to each other for the first time?
Pure magic. ✨