From 746302296c284ee33bb3ec2e1e9b0c3107dc820c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=99=8D=EC=84=B1=ED=9C=98?= Date: Mon, 10 Aug 2026 17:03:03 +0900 Subject: [PATCH 1/4] fix: remove . --- .github/workflows/deploy-production.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index d20eaad..88a0f9a 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -82,7 +82,7 @@ jobs: with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ${{ .env.AWS_REGION }} + aws-region: ${{ env.AWS_REGION }} - name: S3 업로드 (변경된 것만 선택적 업로드) if: steps.filter.outputs.backend == 'true' || steps.filter.outputs.frontend == 'true' From 73758fe69522f0708802f80ac72f312f69860ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=99=8D=EC=84=B1=ED=9C=98?= Date: Mon, 10 Aug 2026 17:07:38 +0900 Subject: [PATCH 2/4] ci: trigger backend deployment pipeline for multi-instance EC2 servers --- .../src/main/java/com/momogo/api/MomogoApiApplication.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/momogo-api/src/main/java/com/momogo/api/MomogoApiApplication.java b/momogo-api/src/main/java/com/momogo/api/MomogoApiApplication.java index 07382be..b4e3bfd 100644 --- a/momogo-api/src/main/java/com/momogo/api/MomogoApiApplication.java +++ b/momogo-api/src/main/java/com/momogo/api/MomogoApiApplication.java @@ -6,6 +6,10 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.scheduling.annotation.EnableScheduling; +/** + * MoMoGo API Application Engine + * Trigger CI/CD Multi-Instance Production Deployment + */ @SpringBootApplication(scanBasePackages = "com.momogo") @EntityScan(basePackages = "com.momogo.core.domain") @EnableJpaRepositories(basePackages = "com.momogo.core.domain") From 2eaf1fa74f9e2cb532f167c63b2b5aa8dc8c394e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=99=8D=EC=84=B1=ED=9C=98?= Date: Tue, 11 Aug 2026 16:10:53 +0900 Subject: [PATCH 3/4] fix(auth/space): resolve role downgrade issue and handle missing idempotency header - Update AuthServiceImpl to use fresh DB user data during token refresh instead of stale refresh token claims - Evict Redis user cache (UserCacheEvictEvent) on space creation, joining, and role changes in SpaceServiceImpl - Allow 'Idempotency-Key' in SecurityConfig CORS configuration - Make 'Idempotency-Key' request header optional with backend UUID fallback in ProblemController and RoomProblemController - Add generateUUID fallback helper for non-secure contexts in SpacePage.tsx --- .../com/momogo/api/auth/config/SecurityConfig.java | 3 ++- .../momogo/api/auth/service/AuthServiceImpl.java | 8 ++++++-- .../com/momogo/api/problem/ProblemController.java | 5 +++-- .../com/momogo/api/room/RoomProblemController.java | 5 +++-- .../core/domain/space/service/SpaceServiceImpl.java | 6 +++++- momogo-frontend/src/pages/SpacePage.tsx | 13 ++++++++++++- 6 files changed, 31 insertions(+), 9 deletions(-) diff --git a/momogo-api/src/main/java/com/momogo/api/auth/config/SecurityConfig.java b/momogo-api/src/main/java/com/momogo/api/auth/config/SecurityConfig.java index 0f978f6..1518f2b 100644 --- a/momogo-api/src/main/java/com/momogo/api/auth/config/SecurityConfig.java +++ b/momogo-api/src/main/java/com/momogo/api/auth/config/SecurityConfig.java @@ -225,7 +225,8 @@ public CorsConfigurationSource corsConfigurationSource() { "X-XSRF-TOKEN", "X-Requested-With", "Accept", - "Last-Event-ID" + "Last-Event-ID", + "Idempotency-Key" )); configuration.setExposedHeaders(List.of( diff --git a/momogo-api/src/main/java/com/momogo/api/auth/service/AuthServiceImpl.java b/momogo-api/src/main/java/com/momogo/api/auth/service/AuthServiceImpl.java index cf90adf..06a2f60 100644 --- a/momogo-api/src/main/java/com/momogo/api/auth/service/AuthServiceImpl.java +++ b/momogo-api/src/main/java/com/momogo/api/auth/service/AuthServiceImpl.java @@ -9,10 +9,12 @@ import com.momogo.api.auth.util.PasswordGenerator; import com.momogo.core.common.exception.BusinessException; import com.momogo.core.common.exception.GlobalErrorCode; +import com.momogo.core.domain.user.dto.response.UserResponse; import com.momogo.core.domain.user.entity.User; import com.momogo.core.domain.user.entity.enums.SocialType; import com.momogo.core.domain.user.event.TemporaryPasswordGeneratedEvent; import com.momogo.core.domain.user.exception.UserErrorCode; +import com.momogo.core.domain.user.mapper.UserMapper; import com.momogo.core.domain.user.repository.UserRepository; import com.momogo.core.common.util.EmailFormatter; import lombok.RequiredArgsConstructor; @@ -33,6 +35,7 @@ public class AuthServiceImpl implements AuthService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; + private final UserMapper userMapper; // Jwt private final JwtTokenProvider jwtTokenProvider; @@ -61,13 +64,14 @@ public JwtDto refresh(String refreshToken) { } try { - MoMoGoUserDetails userDetails = jwtTokenProvider.parseAccessToken(refreshToken); + UserResponse userResponse = userMapper.toResponse(user); + MoMoGoUserDetails userDetails = new MoMoGoUserDetails(userResponse, null); String newAccessToken = jwtTokenProvider.generateAccessToken(userDetails); String newRefreshToken = jwtTokenProvider.generateRefreshToken(userDetails); JwtInformation next = new JwtInformation( - current.user(), + userResponse, newAccessToken, newRefreshToken ); diff --git a/momogo-api/src/main/java/com/momogo/api/problem/ProblemController.java b/momogo-api/src/main/java/com/momogo/api/problem/ProblemController.java index 342020a..46c8862 100644 --- a/momogo-api/src/main/java/com/momogo/api/problem/ProblemController.java +++ b/momogo-api/src/main/java/com/momogo/api/problem/ProblemController.java @@ -120,10 +120,11 @@ public ResponseEntity deleteProblem( @PreAuthorize("hasRole('ADMIN')") public ResponseEntity> createProblemsByAi( @PathVariable UUID spaceId, - @RequestHeader("Idempotency-Key") UUID idempotencyKey, + @RequestHeader(value = "Idempotency-Key", required = false) UUID idempotencyKey, @RequestBody @Valid ProblemAiCreateRequest request) { - List response = problemService.createProblemsByAi(spaceId, idempotencyKey, request); + UUID key = (idempotencyKey != null) ? idempotencyKey : UUID.randomUUID(); + List response = problemService.createProblemsByAi(spaceId, key, request); return ResponseEntity .status(HttpStatus.CREATED) diff --git a/momogo-api/src/main/java/com/momogo/api/room/RoomProblemController.java b/momogo-api/src/main/java/com/momogo/api/room/RoomProblemController.java index 141ccf3..0e21724 100644 --- a/momogo-api/src/main/java/com/momogo/api/room/RoomProblemController.java +++ b/momogo-api/src/main/java/com/momogo/api/room/RoomProblemController.java @@ -90,11 +90,12 @@ public ResponseEntity deleteRoomProblem( public ResponseEntity> createRoomProblemsByAi( @AuthenticationPrincipal MoMoGoUserDetails userDetails, @PathVariable UUID roomId, - @RequestHeader("Idempotency-Key") UUID idempotencyKey, + @RequestHeader(value = "Idempotency-Key", required = false) UUID idempotencyKey, @Valid @RequestBody RoomProblemAiCreateRequest request) { + UUID key = (idempotencyKey != null) ? idempotencyKey : UUID.randomUUID(); List response = roomProblemService. - createRoomProblemsByAi(userDetails.getUserResponse().id(), roomId, idempotencyKey, request); + createRoomProblemsByAi(userDetails.getUserResponse().id(), roomId, key, request); return ResponseEntity .status(HttpStatus.CREATED) diff --git a/momogo-core/src/main/java/com/momogo/core/domain/space/service/SpaceServiceImpl.java b/momogo-core/src/main/java/com/momogo/core/domain/space/service/SpaceServiceImpl.java index 167e350..652e457 100644 --- a/momogo-core/src/main/java/com/momogo/core/domain/space/service/SpaceServiceImpl.java +++ b/momogo-core/src/main/java/com/momogo/core/domain/space/service/SpaceServiceImpl.java @@ -14,6 +14,7 @@ import com.momogo.core.domain.space.repository.SpaceRepository; import com.momogo.core.domain.user.entity.User; import com.momogo.core.domain.user.entity.enums.UserRole; +import com.momogo.core.domain.user.event.UserCacheEvictEvent; import com.momogo.core.domain.user.repository.UserRepository; import java.time.OffsetDateTime; import java.util.List; @@ -60,7 +61,8 @@ public Space createSpace(UUID userId, SpaceCreateRequest request) { Space savedSpace = spaceRepository.save(space); // 개설한 유저의 공간 정보 및 역할을 ADMIN으로 업데이트 - user.joinSpace(savedSpace, UserRole.ADMIN); + user.joinSpace(savedSpace, UserRole.ADMIN); + eventPublisher.publishEvent(new UserCacheEvictEvent(user.getEmail())); return savedSpace; } @@ -87,6 +89,7 @@ public void joinSpace(UUID userId, UUID spaceId, String password) { // 공간 가입 처리 user.joinSpace(space, UserRole.USER); + eventPublisher.publishEvent(new UserCacheEvictEvent(user.getEmail())); // 공간 ADMIN에게 알림을 보내기 위한 이벤트 발행 eventPublisher.publishEvent(new SpaceUserJoinedEvent(spaceId, userId)); @@ -190,6 +193,7 @@ public void changeUserRole(UUID adminUserId, UUID spaceId, UUID targetUserId, Us // 권한 변경 targetUser.changeRole(role); + eventPublisher.publishEvent(new UserCacheEvictEvent(targetUser.getEmail())); // 권한이 변경된 유저에게 알림을 보내기 위한 이벤트 발행 eventPublisher.publishEvent(new SpaceUserRoleChangedEvent(targetUserId, spaceId, role)); diff --git a/momogo-frontend/src/pages/SpacePage.tsx b/momogo-frontend/src/pages/SpacePage.tsx index 9ed286f..6c8ddd8 100644 --- a/momogo-frontend/src/pages/SpacePage.tsx +++ b/momogo-frontend/src/pages/SpacePage.tsx @@ -3,6 +3,17 @@ import type { UserResponse } from '../types/user'; import type { SpaceResponse } from '../types/space'; import { request, getAccessToken, connectNotificationSse } from '../services/api'; +const generateUUID = (): string => { + if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { + return crypto.randomUUID(); + } + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c === 'x' ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +}; + interface SpacePageProps { user: UserResponse; space: SpaceResponse; @@ -470,7 +481,7 @@ export const SpacePage: React.FC = ({ user, space, onBack, showT setLoading(true); await request(`/api/spaces/${space.id}/problems/ai`, { method: 'POST', - headers: { 'Idempotency-Key': crypto.randomUUID() }, + headers: { 'Idempotency-Key': generateUUID() }, body: JSON.stringify({ categoryId: aiCategory, referenceText: aiRefData, From 9aba17d4e79ffc8307c229cdf201415486459561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=99=8D=EC=84=B1=ED=9C=98?= Date: Tue, 11 Aug 2026 16:13:45 +0900 Subject: [PATCH 4/4] fix: add forward-headers-strategy --- momogo-api/src/main/resources/application.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/momogo-api/src/main/resources/application.yaml b/momogo-api/src/main/resources/application.yaml index bc734a5..479cd59 100644 --- a/momogo-api/src/main/resources/application.yaml +++ b/momogo-api/src/main/resources/application.yaml @@ -152,6 +152,7 @@ app: server: port: 8080 + forward-headers-strategy: framework # monitoring management: