Closes Issues: #2101, #2102, #2104
- #2101 (Availability): Needed a way for frontends to accurately check if an event has spots available, how many are left, and if the event has passed, without needing authentication.
- #2102 (Registration): Needed an authenticated API endpoint to register users for events, enforcing validation (duplicate registrations, capacity) and returning a clean response.
- #2104 (Concurrency): Concurrent registrations could overbook an event beyond its capacity, leading to data inconsistency and a poor user experience.
-
Event Model & Optimistic Locking (
Event.java)- Added a
@Versionfield to theEvententity for optimistic locking. This acts as a safety net if a race condition sneaks past the pessimistic lock. - Cleaned up redundant fields (
maxAttendees,currentAttendees), as they duplicated the existingcapacityandregisteredCount. - Added an
isEventPast()helper to let the frontend know an event has passed.
- Added a
-
Availability API (
EventAvailabilityResponse.java&EventController.java)- Opened
GET /api/events/{id}/availabilityto public access inSecurityConfig. - Populated the response with
maxAttendees,currentAttendees, andavailabilityStatusas per #2101 requirements (implemented via@JsonPropertyaliases for backward compatibility). - Added an
eventPassedflag to offload logic for "past events" directly to the frontend.
- Opened
-
Registration API (
RegistrationResponse.java&EventController.java)- Created a clean
RegistrationResponseDTO to prevent leaking internal entity fields (like full attendee lists) to the client. - Updated
EventService.registerUserForEvent()to handle business validation and return a 409 Conflict if a user is already registered (throwsRegistrationConflictException) or if the event is full (EventFullException). - Fixed
SecurityConfigto return a401 Unauthorizedinstead of the default403 Forbiddenon missing/invalid JWT tokens.
- Created a clean
-
Concurrency Handling (
EventService.java)- Implemented a "belt-and-suspenders" concurrency model:
- Pessimistic write lock (
SELECT ... FOR UPDATE) on theEventrow to serialize concurrent registration requests. - Retry Loop: Wrapped the registration transaction in a retry loop (max 3 retries) for
ObjectOptimisticLockingFailureException. If transient contention causes an optimistic lock failure, it transparently retries. If all retries fail, a user-friendly 409 error is returned.
- Pessimistic write lock (
- Implemented a "belt-and-suspenders" concurrency model:
-
Error Handling (
GlobalExceptionHandler.java)- Added a handler for
EventFullExceptionto properly return409 Conflictinstead of500 Internal Server Error.
- Added a handler for
- Unit & Integration Tests:
EventRegistrationTests.java: Added/updated 10 test cases covering public availability access, JSON payload accuracy, unauthorized registration blocks, duplicate registration blocks, and event full rejection.EventRegistrationConcurrencyIntegrationTest.java: Added invariant-based concurrency tests (e.g., verifying that exactlycapacityregistrations succeed out of2 * capacitythreads racing).
- Test Results: 13/13 tests passing successfully in the local build (
mvn clean test).
- Java code formatting is clean, well-commented with Javadocs explaining complex concurrency logic.
- Proper use of DTOs vs Entities in controllers.
- Commit conventions outlined in
CONTRIBUTING.mdare supported (changes broken down logically).