Skip to content

Lab3 refactoring#16

Merged
butvinm merged 21 commits intomasterfrom
lab3-refactoring
Jan 14, 2026
Merged

Lab3 refactoring#16
butvinm merged 21 commits intomasterfrom
lab3-refactoring

Conversation

@butvinm
Copy link
Member

@butvinm butvinm commented Jan 12, 2026

  • Independent database tables
  • Circuit braker handlers
  • Single Swagger UI on gateway

butvinm and others added 8 commits January 12, 2026 07:53
Add DELETE /internal/users/{userId}/data endpoint to divination-service
for cascade deletion of user data (spreads and interpretations).
This endpoint will be called by user-service before deleting a user
to ensure data cleanup across services.

Changes:
- Add InternalController with deleteUserData endpoint
- Add deleteUserData method to DivinationService
- Add deleteByAuthorId to SpreadRepository and InterpretationRepository
- Add unit and integration tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add DivinationServiceInternalClient interface for user-service to call
divination-service's internal cleanup endpoint. This client is used to
delete user data before deleting the user.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add synchronous Feign call to divination-service to delete user data
(spreads and interpretations) before deleting the user. User deletion
fails with 503 Service Unavailable if cleanup fails.

Changes:
- Add openfeign and resilience4j dependencies to user-service
- Enable Feign clients with @EnableFeignClients
- Inject DivinationServiceInternalClient into UserService
- Call cleanup endpoint in deleteUser method (fail on error)
- Add ServiceUnavailableException for cleanup failures
- Update tests with mocked Feign client
- Add Resilience4j configuration in highload-config

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove FK constraints from divination-service tables that reference
tables owned by other microservices (user-service, tarot-service):
- spread.layout_type_id -> layout_type.id
- spread.author_id -> user.id
- spread_card.card_id -> card.id
- interpretation.author_id -> user.id

Internal FKs (spread_card -> spread, interpretation -> spread) are
preserved for proper cascade delete within the same service.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove user, card, layout_type, and arcana_type table definitions
from test initialization since cross-service FKs are dropped.
Tests now only create divination-service owned tables (spread,
spread_card, interpretation) with internal FKs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add UserCascadeDeleteE2ETest to verify that deleting a user
correctly cascades to delete their spreads and interpretations
via the internal API call to divination-service.

Update CLAUDE.md:
- Document database independence (no cross-service FKs)
- Add internal API endpoint documentation
- Document cascade delete behavior for user deletion

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed DivinationServiceInternalClient to use name="divination-service"
(the actual Eureka registration) with contextId to differentiate from
other clients. Updated Resilience4j config accordingly.

This fixes the "Load balancer does not contain an instance" error
when user-service tries to call divination-service internal API.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The test expected 1 interpretation to remain after user deletion, but
the setup didn't create an interpretation by otherUser on their own
spread. Added the missing interpretation to match test expectations.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@github-actions
Copy link

github-actions bot commented Jan 12, 2026

Code Coverage Report

Overall Project 79.97% -1.99% 🍏
Files changed 90.49% 🍏

Module Coverage
user-service 81.78% -5.34% 🍏
divination-service 79.68% -1.12% 🍏
tarot-service 78.1% 🍏
Files
Module File Coverage
user-service SecurityConfig.kt 100% 🍏
UserController.kt 100% 🍏
GatewayAuthenticationFilter.kt 97.5% -2.5% 🍏
UserService.kt 96.14% 🍏
GlobalExceptionHandler.kt 55.36% -20.36%
UserServiceApplication.kt 23.08% 🍏
divination-service InterpretationController.kt 100% 🍏
InternalController.kt 100% 🍏
SecurityConfig.kt 100% 🍏
AuthorizationService.kt 100% 🍏
DivinationService.kt 93.55% 🍏
GatewayAuthenticationWebFilter.kt 92.42% -7.58% 🍏
SpreadController.kt 87.32% 🍏
GlobalExceptionHandler.kt 62.11% -10.16%
DivinationServiceApplication.kt 23.08% 🍏
SpreadRepository.kt 20% 🍏
InterpretationRepository.kt 10.34% 🍏
tarot-service TarotServiceApplication.kt 23.08% 🍏

butvinm and others added 13 commits January 12, 2026 10:19
Phase 1 of centralized Swagger UI implementation:
- Added springdoc-openapi-starter-webflux-ui:2.8.4 to gateway-service
- Created PROGRESS.md to track implementation progress

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 2 of centralized Swagger UI implementation:
- Updated highload-config with springdoc configuration for gateway
- Added OpenAPI proxy routes for user-service, tarot-service, divination-service
- Added public paths for Swagger UI access without authentication
- Swagger UI accessible at http://localhost:8080/swagger-ui.html with service dropdown

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 3 of centralized Swagger UI implementation:
- Changed user-service: webmvc-ui -> webmvc-api
- Changed tarot-service: webflux-ui -> webflux-api
- Changed divination-service: webflux-ui -> webflux-api

Services now only expose /api-docs for gateway proxying.
Swagger UI is accessible only at http://localhost:8080/swagger-ui.html

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 4 of centralized Swagger UI implementation:
- Added "API Documentation (Swagger UI)" section documenting:
  - Centralized Swagger UI URL and features
  - Architecture (gateway UI + backend API-only)
  - Configuration file locations
- Updated PROGRESS.md to mark all phases complete

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updated highload-config to remove auto-generated internal Docker IPs
from OpenAPI specs. Swagger UI now uses relative URLs, routing all
"Try it out" requests through the gateway.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The "Servers" dropdown in Swagger UI was showing internal Docker IPs
(e.g., 10.10.3.7:8082) which are not reachable from outside Docker.

Added OpenApiServerRewriteFilter that strips the "servers" array from
proxied OpenAPI responses. This makes Swagger UI use relative URLs,
so all "Try it out" requests correctly go through the gateway.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add @OpenAPIDefinition with gateway server URL to all services
- Add @Securityscheme for JWT bearer authentication
- Add @securityrequirement to enable Authorize button in Swagger UI
- Remove hacky OpenApiServerRewriteFilter
- Update highload-config with forward-headers-strategy

Note: Server URL is hardcoded to localhost:8080 - needs config for prod

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
These services have no tests, so test dependencies and JUnit configuration
are unnecessary.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…andling

Move circuit breaker error handling to shared fallback factories:
- Add ServiceUnavailableException with service name to shared-clients
- Add FeignFallbackFactories for UserService, TarotService, DivinationServiceInternal
- Update @FeignClient annotations with fallbackFactory attribute
- Add @componentscan to services for shared.client package
- Remove redundant circuit breaker exception handlers from GlobalExceptionHandler
- Simplify UserService by removing manual try-catch (fallback handles errors)

All services now return consistent error format:
{"error":"SERVICE_UNAVAILABLE","message":"Service '<name>' is temporarily unavailable",...}

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Upgrade testcontainers from 1.19.8 to 2.0.2
- Update module names: postgresql -> testcontainers-postgresql,
  junit-jupiter -> testcontainers-junit-jupiter
- Migrate PostgreSQLContainer import from org.testcontainers.containers
  to org.testcontainers.postgresql
- Update API usage: remove generic type parameter, use property access
  instead of getter method references (jdbcUrl, username, password)
- Fix UserServiceTest to use ServiceUnavailableException from shared-clients

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ctories

Remove complex FallbackFactory pattern and handle all errors in
GlobalExceptionHandler instead:

- Remove fallbackFactory from all @FeignClient annotations
- Delete FeignFallbackFactories.kt and ServiceUnavailableException.kt
- Add handlers for CallNotPermittedException (circuit open -> 503)
- Add handlers for NoFallbackAvailableException (unwrap and handle cause)
- FeignException.NotFound now correctly propagates as 404
- Other FeignExceptions return 503 (service unavailable)

This is simpler and follows the standard pattern of centralizing
error handling in GlobalExceptionHandler rather than spreading it
across multiple fallback factory classes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement FallbackFactory pattern for Feign clients with clear error handling:

- Add ServiceUnavailableException with serviceName field for clear error messages
- Create generic FeignFallbackFactory using dynamic proxy to avoid boilerplate
- Re-throw 4xx client errors (404, 400) to propagate business errors
- Throw ServiceUnavailableException for 5xx, connection errors, circuit open
- Simplify GlobalExceptionHandler to only handle ServiceUnavailableException

The fallback is explicit and returns meaningful error:
{"error":"SERVICE_UNAVAILABLE","message":"Service 'tarot-service' is temporarily unavailable"}

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>


Replace manual requireAdmin() and requireMediumOrAdmin() checks with
Spring Security's @PreAuthorize annotations. Gateway headers (X-User-Id,
X-User-Role) are now processed by custom filters that populate the
SecurityContext.

Changes:
- Add GatewayAuthenticationToken to shared-clients for reuse
- Add GatewayAuthenticationFilter (servlet) to user-service
- Add GatewayAuthenticationWebFilter (reactive) to divination-service
- Add AuthorizationService to divination-service for ownership checks
- Configure Spring Security filter chains for both services
- Update controllers to use @PreAuthorize annotations
- Add AccessDeniedException handlers to GlobalExceptionHandlers

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@butvinm butvinm merged commit 1bf57cf into master Jan 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant