Add global exception handler
Summary
- Add GlobalExceptionHandler (@RestControllerAdvice) to centralize error handling across all controllers
- Introduce ErrorResponse record providing a uniform JSON error shape (status, error, message, timestamp, fieldErrors)
- Replace raw Spring 500 responses with meaningful HTTP codes:
- IllegalStateException → 409 Conflict (e.g. duplicate waitlist email)
- EntityNotFoundException → 404 Not Found
- MethodArgumentNotValidException → 400 Bad Request with per-field validation details
- Unhandled exceptions → 500 Internal Server Error (generic message, no stack trace leaked)
Motivation
Previously, errors such as registering a duplicate email on the waitlist returned a generic 500 with a raw exception body. This change ensures all error responses are structured, predictable, and safe to consume by the frontend.
Error response format
{ "status": 409, "error": "Conflict", "message": "Email already registered on waitlist", "timestamp": "2026-04-09T13:00:00" }
For validation errors, a fieldErrors array is included:
{ "status": 400, "error": "Bad Request", "message": "Validation failed", "timestamp": "2026-04-09T13:00:00", "fieldErrors": [ { "field": "email", "message": "must not be blank" } ] }
Test plan
- GlobalExceptionHandlerTest — unit tests covering all four exception mappings (no Spring context required)
- Existing LandingControllerTest still passes