From c01d9575e394f68565aa17587bade7ddf218517e Mon Sep 17 00:00:00 2001 From: rud15dns Date: Wed, 4 Feb 2026 17:42:57 +0900 Subject: [PATCH 01/15] =?UTF-8?q?fix:=20Redis=20=EB=91=90=20=EA=B0=9C?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 18 +++++--- .../server/global/config/RedisConfig.java | 44 ++++++++++++++++++- src/main/resources/application-local.yaml | 6 --- src/main/resources/application-prod.yaml | 5 --- 4 files changed, 55 insertions(+), 18 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index ea6a907..0389f53 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,24 +14,32 @@ services: JWT_SECRET_KEY: ${JWT_SECRET_KEY} ADMIN_SECRET: ${ADMIN_SECRET} KAKAO_APP_KEY: ${KAKAO_APP_KEY} - REDIS_HOST: redis - REDIS_PORT: 6379 + COOLSMS_API_KEY: ${COOLSMS_API_KEY} COOLSMS_API_SECRET: ${COOLSMS_API_SECRET} COOLSMS_SENDER: ${COOLSMS_SENDER} depends_on: - - redis + - redis-chat + - redis-auth networks: - spring-boot-app-network - redis: # Redis 서비스 추가! + redis-chat: image: redis:7-alpine - container_name: redis + container_name: redis-chat ports: - "6379:6379" networks: - spring-boot-app-network + redis-auth: + image: redis:7-alpine + container_name: redis-auth + ports: + - "6380:6379" + networks: + - spring-boot-app-network + networks: spring-boot-app-network: driver: bridge \ No newline at end of file diff --git a/src/main/java/com/meetkey/server/global/config/RedisConfig.java b/src/main/java/com/meetkey/server/global/config/RedisConfig.java index 4795044..0b2bd2c 100644 --- a/src/main/java/com/meetkey/server/global/config/RedisConfig.java +++ b/src/main/java/com/meetkey/server/global/config/RedisConfig.java @@ -3,16 +3,20 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { - @Bean public ObjectMapper redisObjectMapper() { ObjectMapper mapper = new ObjectMapper(); @@ -21,8 +25,35 @@ public ObjectMapper redisObjectMapper() { return mapper; } + // 채팅용 (port: 6379) + @Bean + @Primary + public RedisConnectionFactory chatRedisConnectionFactory() { + RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); + config.setHostName("redis-chat"); + config.setPort(6379); + + LettuceConnectionFactory factory = new LettuceConnectionFactory(config); + factory.afterPropertiesSet(); + return factory; + } + + // SMS/Refresh토큰용 Redis + @Bean + public RedisConnectionFactory authRedisConnectionFactory(){ + RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); + config.setHostName("redis-auth"); + config.setPort(6379); + + LettuceConnectionFactory factory = new LettuceConnectionFactory(config); + factory.afterPropertiesSet(); + return factory; + } + @Bean - public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory, ObjectMapper redisObjectMapper) { + public RedisTemplate redisTemplate( + @Qualifier("chatRedisConnectionFactory") RedisConnectionFactory connectionFactory, + ObjectMapper redisObjectMapper) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); @@ -35,6 +66,15 @@ public RedisTemplate redisTemplate(RedisConnectionFactory connec return template; } + + // SMS, RefreshToken용 + @Bean + public StringRedisTemplate stringRedisTemplate( + @Qualifier("authRedisConnectionFactory") RedisConnectionFactory connectionFactory) { + StringRedisTemplate template = new StringRedisTemplate(); + template.setConnectionFactory(connectionFactory); + return template; + } } diff --git a/src/main/resources/application-local.yaml b/src/main/resources/application-local.yaml index 6e66b8d..f1dd370 100644 --- a/src/main/resources/application-local.yaml +++ b/src/main/resources/application-local.yaml @@ -1,10 +1,4 @@ - spring: - data: - redis: - host: ${REDIS_HOST:localhost} - port: ${REDIS_PORT:6379} - jwt: secret: ${JWT_SECRET_KEY:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} diff --git a/src/main/resources/application-prod.yaml b/src/main/resources/application-prod.yaml index 9b282d2..3fd45b2 100644 --- a/src/main/resources/application-prod.yaml +++ b/src/main/resources/application-prod.yaml @@ -1,9 +1,4 @@ spring: - data: - redis: - host: ${REDIS_HOST:localhost} - port: ${REDIS_PORT:6379} - jwt: secret: ${JWT_SECRET_KEY:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} From f21b02e44e2823a9468dde5e414c07cb72df7630 Mon Sep 17 00:00:00 2001 From: rud15dns Date: Wed, 4 Feb 2026 19:04:35 +0900 Subject: [PATCH 02/15] =?UTF-8?q?fix:=20=ED=99=98=EA=B2=BD=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 14 +++++++++++++- .../meetkey/server/global/config/RedisConfig.java | 10 ++++++++-- src/main/resources/application-local.yaml | 6 ++++++ src/main/resources/application-prod.yaml | 6 ++++++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e302bc6..cb9f2c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,15 @@ jobs: test: runs-on: ubuntu-latest + services: + redis-chat: + image: redis:7-alpine + ports: + - 6379:6379 + redis-auth: + image: redis:7-alpine + ports: + - 6380:6379 steps: - uses: actions/checkout@v3 @@ -21,4 +30,7 @@ jobs: run: chmod +x gradlew - name: Run tests - run: ./gradlew test --stacktrace --no-daemon \ No newline at end of file + run: ./gradlew test --stacktrace --no-daemon + env: + SPRING_DATA_REDIS_CHAT_HOST: localhost + SPRING_DATA_REDIS_AUTH_HOST: localhost \ No newline at end of file diff --git a/src/main/java/com/meetkey/server/global/config/RedisConfig.java b/src/main/java/com/meetkey/server/global/config/RedisConfig.java index 0b2bd2c..891d7f0 100644 --- a/src/main/java/com/meetkey/server/global/config/RedisConfig.java +++ b/src/main/java/com/meetkey/server/global/config/RedisConfig.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @@ -17,6 +18,11 @@ @Configuration public class RedisConfig { + @Value("${spring.data.redis.chat.host}") + private String chatHost; + @Value("${spring.data.redis.auth.host}") + private String authHost; + @Bean public ObjectMapper redisObjectMapper() { ObjectMapper mapper = new ObjectMapper(); @@ -30,7 +36,7 @@ public ObjectMapper redisObjectMapper() { @Primary public RedisConnectionFactory chatRedisConnectionFactory() { RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); - config.setHostName("redis-chat"); + config.setHostName(chatHost); config.setPort(6379); LettuceConnectionFactory factory = new LettuceConnectionFactory(config); @@ -42,7 +48,7 @@ public RedisConnectionFactory chatRedisConnectionFactory() { @Bean public RedisConnectionFactory authRedisConnectionFactory(){ RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); - config.setHostName("redis-auth"); + config.setHostName(authHost); config.setPort(6379); LettuceConnectionFactory factory = new LettuceConnectionFactory(config); diff --git a/src/main/resources/application-local.yaml b/src/main/resources/application-local.yaml index f1dd370..5f2e91a 100644 --- a/src/main/resources/application-local.yaml +++ b/src/main/resources/application-local.yaml @@ -1,4 +1,10 @@ spring: + data: + redis: + chat: + host: localhost + auth: + host: localhost jwt: secret: ${JWT_SECRET_KEY:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} diff --git a/src/main/resources/application-prod.yaml b/src/main/resources/application-prod.yaml index 3fd45b2..3e10a2d 100644 --- a/src/main/resources/application-prod.yaml +++ b/src/main/resources/application-prod.yaml @@ -1,4 +1,10 @@ spring: + data: + redis: + chat: + host: redis-chat + auth: + host: redis-auth jwt: secret: ${JWT_SECRET_KEY:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} From 44b081429f053071f8ac5e031604a39201364e8c Mon Sep 17 00:00:00 2001 From: rud15dns Date: Wed, 4 Feb 2026 19:44:51 +0900 Subject: [PATCH 03/15] =?UTF-8?q?fix:=20redisSubscriberConfig=EC=9D=98=20r?= =?UTF-8?q?edisFactory=EB=A5=BC=20redisConfig=EC=9D=98=20chatRedisConnecti?= =?UTF-8?q?onFactory=EC=99=80=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 4 +++- .../chat/message/redis/RedisSubscriberConfig.java | 10 ++++++++-- .../com/meetkey/server/global/config/RedisConfig.java | 9 +++++++-- src/main/resources/application-local.yaml | 2 ++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb9f2c7..cc05c92 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,4 +33,6 @@ jobs: run: ./gradlew test --stacktrace --no-daemon env: SPRING_DATA_REDIS_CHAT_HOST: localhost - SPRING_DATA_REDIS_AUTH_HOST: localhost \ No newline at end of file + SPRING_DATA_REDIS_CHAT_PORT: 6379 + SPRING_DATA_REDIS_AUTH_HOST: localhost + SPRING_DATA_REDIS_AUTH_PORT: 6380 \ No newline at end of file diff --git a/src/main/java/com/meetkey/server/domain/chat/message/redis/RedisSubscriberConfig.java b/src/main/java/com/meetkey/server/domain/chat/message/redis/RedisSubscriberConfig.java index a50dd14..5ce6768 100644 --- a/src/main/java/com/meetkey/server/domain/chat/message/redis/RedisSubscriberConfig.java +++ b/src/main/java/com/meetkey/server/domain/chat/message/redis/RedisSubscriberConfig.java @@ -1,6 +1,6 @@ package com.meetkey.server.domain.chat.message.redis; -import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; @@ -8,12 +8,18 @@ import org.springframework.data.redis.listener.RedisMessageListenerContainer; @Configuration -@RequiredArgsConstructor public class RedisSubscriberConfig { private final RedisConnectionFactory connectionFactory; private final ChatRedisSubscriber chatRedisSubscriber; + public RedisSubscriberConfig( + @Qualifier("chatRedisConnectionFactory") RedisConnectionFactory connectionFactory, + ChatRedisSubscriber chatRedisSubscriber) { + this.connectionFactory = connectionFactory; + this.chatRedisSubscriber = chatRedisSubscriber; + } + @Bean public RedisMessageListenerContainer redisMessageListenerContainer() { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); diff --git a/src/main/java/com/meetkey/server/global/config/RedisConfig.java b/src/main/java/com/meetkey/server/global/config/RedisConfig.java index 891d7f0..bf72534 100644 --- a/src/main/java/com/meetkey/server/global/config/RedisConfig.java +++ b/src/main/java/com/meetkey/server/global/config/RedisConfig.java @@ -23,6 +23,11 @@ public class RedisConfig { @Value("${spring.data.redis.auth.host}") private String authHost; + @Value("${spring.data.redis.chat.port:6379}") + private int chatPort; + @Value("${spring.data.redis.auth.port:6379}") + private int authPort; + @Bean public ObjectMapper redisObjectMapper() { ObjectMapper mapper = new ObjectMapper(); @@ -37,7 +42,7 @@ public ObjectMapper redisObjectMapper() { public RedisConnectionFactory chatRedisConnectionFactory() { RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); config.setHostName(chatHost); - config.setPort(6379); + config.setPort(chatPort); LettuceConnectionFactory factory = new LettuceConnectionFactory(config); factory.afterPropertiesSet(); @@ -49,7 +54,7 @@ public RedisConnectionFactory chatRedisConnectionFactory() { public RedisConnectionFactory authRedisConnectionFactory(){ RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); config.setHostName(authHost); - config.setPort(6379); + config.setPort(authPort); LettuceConnectionFactory factory = new LettuceConnectionFactory(config); factory.afterPropertiesSet(); diff --git a/src/main/resources/application-local.yaml b/src/main/resources/application-local.yaml index 5f2e91a..3841fcc 100644 --- a/src/main/resources/application-local.yaml +++ b/src/main/resources/application-local.yaml @@ -3,8 +3,10 @@ spring: redis: chat: host: localhost + port: 6379 auth: host: localhost + port: 6380 jwt: secret: ${JWT_SECRET_KEY:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} From e52b7da1ff70afcf3c468ded38bf6c59d1d5d5c7 Mon Sep 17 00:00:00 2001 From: rud15dns Date: Wed, 4 Feb 2026 23:09:48 +0900 Subject: [PATCH 04/15] =?UTF-8?q?fix:=20record=20->=20static=20class=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD,=20jackson=20=EC=A7=81=EB=A0=AC=ED=99=94=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + .../auth/controller/AuthController.java | 10 +++++ .../domain/auth/service/AuthService.java | 4 +- .../server/global/config/RedisConfig.java | 42 ++++++++++++++++++ .../security/oauth/OauthOidcHelper.java | 6 +-- .../oauth/apple/AppleOauthClient.java | 2 +- .../global/security/oauth/dto/OidcDTO.java | 44 ++++++++++++------- .../oauth/kakao/KakaoOauthClient.java | 3 +- 8 files changed, 90 insertions(+), 22 deletions(-) diff --git a/build.gradle b/build.gradle index 545a655..266f899 100644 --- a/build.gradle +++ b/build.gradle @@ -57,6 +57,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-redis' + implementation 'com.fasterxml.jackson.module:jackson-module-parameter-names' implementation 'org.springframework.boot:spring-boot-starter-security' diff --git a/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java b/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java index 5a2914f..d9cef3c 100644 --- a/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java +++ b/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java @@ -15,6 +15,7 @@ import com.meetkey.server.global.security.jwt.dto.JwtResDTO; import com.meetkey.server.global.security.oauth.dto.OauthReqDTO; +import com.meetkey.server.global.security.oauth.kakao.KakaoOauthClient; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -37,6 +38,7 @@ public class AuthController { private final AuthService authService; private final SmsService smsService; + private final KakaoOauthClient kakaoOauthClient; @Value("${admin.secret}") @@ -140,4 +142,12 @@ public ResponseEntity> verifyAuthCode( .body(BasicResponse.success(CommonSuccessStatus._OK, true)); } + + @GetMapping("/test/kakao-keys") + public ResponseEntity getKeys() { + // 호출할 때마다 로그를 찍어서 캐시 동작 확인 + System.out.println("Calling AppleOauthClient..."); + return ResponseEntity.ok(kakaoOauthClient.getKakaoOIDCOpenKeys()); + } + } diff --git a/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java b/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java index f295476..2e57810 100644 --- a/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java +++ b/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java @@ -169,7 +169,7 @@ private String getAppleProviderIdFromIdToken(String idToken){ response ); - return payload.sub(); + return payload.getSub(); } private String getKakaoProviderIdFromIdToken(String idToken){ @@ -181,7 +181,7 @@ private String getKakaoProviderIdFromIdToken(String idToken){ response ); - return payload.sub(); + return payload.getSub(); } } diff --git a/src/main/java/com/meetkey/server/global/config/RedisConfig.java b/src/main/java/com/meetkey/server/global/config/RedisConfig.java index bf72534..c58a6aa 100644 --- a/src/main/java/com/meetkey/server/global/config/RedisConfig.java +++ b/src/main/java/com/meetkey/server/global/config/RedisConfig.java @@ -1,22 +1,30 @@ package com.meetkey.server.global.config; +import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; +import java.time.Duration; + @Configuration +@EnableCaching public class RedisConfig { @Value("${spring.data.redis.chat.host}") private String chatHost; @@ -86,6 +94,40 @@ public StringRedisTemplate stringRedisTemplate( template.setConnectionFactory(connectionFactory); return template; } + + // OIDC 공개용 키 저장 + @Bean + public RedisCacheManager oidcCacheManager( + @Qualifier("authRedisConnectionFactory") RedisConnectionFactory connectionFactory + ){ + ObjectMapper cacheMapper = new ObjectMapper(); + cacheMapper.registerModule(new JavaTimeModule()); + cacheMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + + // 타입 정보 활성화 + cacheMapper.activateDefaultTyping( + cacheMapper.getPolymorphicTypeValidator(), + ObjectMapper.DefaultTyping.NON_FINAL, + JsonTypeInfo.As.PROPERTY + ); + + RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() + .serializeKeysWith( + RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()) + ) + .serializeValuesWith( + RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(cacheMapper)) + ) + // 키 앞에 "jwk:" 접두사를 붙임 + .computePrefixWith(cacheName -> "jwk:" + cacheName + "::") + .entryTtl(Duration.ofDays(3)); + + return RedisCacheManager.RedisCacheManagerBuilder + .fromConnectionFactory(connectionFactory) + .cacheDefaults(config) + .build(); + } + } diff --git a/src/main/java/com/meetkey/server/global/security/oauth/OauthOidcHelper.java b/src/main/java/com/meetkey/server/global/security/oauth/OauthOidcHelper.java index 77ef2fa..2cc7dae 100644 --- a/src/main/java/com/meetkey/server/global/security/oauth/OauthOidcHelper.java +++ b/src/main/java/com/meetkey/server/global/security/oauth/OauthOidcHelper.java @@ -20,12 +20,12 @@ public OidcDTO.OIDCDecodePayload getPayloadFromIdToken( // kid 에 맞는 공개키를 가져옴 OidcDTO.OIDCPublicKey publicKey = - response.keys().stream() - .filter(o -> o.kid().equals(kid)) + response.getKeys().stream() + .filter(o -> o.getKid().equals(kid)) .findFirst() .orElseThrow(); - return jwtOIDCProvider.getOIDCTokenBody(token, publicKey.n(), publicKey.e()); + return jwtOIDCProvider.getOIDCTokenBody(token, publicKey.getN(), publicKey.getE()); } } diff --git a/src/main/java/com/meetkey/server/global/security/oauth/apple/AppleOauthClient.java b/src/main/java/com/meetkey/server/global/security/oauth/apple/AppleOauthClient.java index df6578e..f10d28c 100644 --- a/src/main/java/com/meetkey/server/global/security/oauth/apple/AppleOauthClient.java +++ b/src/main/java/com/meetkey/server/global/security/oauth/apple/AppleOauthClient.java @@ -12,7 +12,7 @@ configuration = OauthConfig.class ) public interface AppleOauthClient { - // @Cacheable(cacheNames = "AppleOICD", cacheManager = "oidcCacheManager") + @Cacheable(cacheNames = "AppleOICD", cacheManager = "oidcCacheManager") @GetMapping("/auth/keys") OidcDTO.OIDCPublicKeys getAppleOIDCOpenKeys(); } diff --git a/src/main/java/com/meetkey/server/global/security/oauth/dto/OidcDTO.java b/src/main/java/com/meetkey/server/global/security/oauth/dto/OidcDTO.java index 194ab2f..1e69699 100644 --- a/src/main/java/com/meetkey/server/global/security/oauth/dto/OidcDTO.java +++ b/src/main/java/com/meetkey/server/global/security/oauth/dto/OidcDTO.java @@ -1,29 +1,43 @@ package com.meetkey.server.global.security.oauth.dto; +import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; import java.util.List; import java.util.Set; public class OidcDTO { + @Getter @Builder - public record OIDCDecodePayload ( - String iss, - Set aud, - String sub - ){} + @NoArgsConstructor + @AllArgsConstructor + public static class OIDCDecodePayload { + private String iss; + private Set aud; + private String sub; + } + @Getter @Builder - public record OIDCPublicKey ( - // JWK - String kid, - String alg, - String n, - String e - ){} + @NoArgsConstructor + @AllArgsConstructor + public static class OIDCPublicKey { + private String kid; + private String kty; + private String alg; + private String use; + private String n; + private String e; + } + // 인증서버가 ID 토큰 서명 시 사용한 공개키 목록을 담은 JWK 배열 + @Getter @Builder - public record OIDCPublicKeys( - List keys // 인증서버가 ID 토큰 서명 시 사용한 공개키 목록을 담은 JWK 배열 - ){} + @NoArgsConstructor + @AllArgsConstructor + public static class OIDCPublicKeys { + private List keys; + } } diff --git a/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOauthClient.java b/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOauthClient.java index a792f2f..5fdf82f 100644 --- a/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOauthClient.java +++ b/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOauthClient.java @@ -2,6 +2,7 @@ import com.meetkey.server.global.config.OauthConfig; import com.meetkey.server.global.security.oauth.dto.OidcDTO; +import org.springframework.cache.annotation.Cacheable; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @@ -11,7 +12,7 @@ configuration = OauthConfig.class ) public interface KakaoOauthClient { - // @Cacheable(cacheNames = "KakaoOICD", cacheManager = "oidcCacheManager") + @Cacheable(cacheNames = "KakaoOICD", cacheManager = "oidcCacheManager") @GetMapping("/.well-known/jwks.json") OidcDTO.OIDCPublicKeys getKakaoOIDCOpenKeys(); } From 57765a560b0e122e8dc00affaf81c88affca6e0b Mon Sep 17 00:00:00 2001 From: rud15dns Date: Wed, 4 Feb 2026 23:19:29 +0900 Subject: [PATCH 05/15] =?UTF-8?q?fix:=20FeignClient=EC=97=90=EC=84=9C=20Ca?= =?UTF-8?q?cheable=20=EC=A0=81=EC=9A=A9=20=EC=95=88=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/auth/controller/AuthController.java | 8 +++----- .../server/domain/auth/service/AuthService.java | 6 +++--- .../security/oauth/apple/AppleOauthClient.java | 3 ++- .../security/oauth/kakao/KakaoOauthClient.java | 1 - .../security/oauth/kakao/KakaoOidcService.java | 17 +++++++++++++++++ 5 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOidcService.java diff --git a/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java b/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java index d9cef3c..36165bb 100644 --- a/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java +++ b/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java @@ -11,11 +11,10 @@ import com.meetkey.server.global.apiPayload.status.CommonErrorStatus; import com.meetkey.server.global.apiPayload.status.CommonSuccessStatus; import com.meetkey.server.global.security.CustomUserDetails; -import com.meetkey.server.global.security.jwt.JwtUtil; import com.meetkey.server.global.security.jwt.dto.JwtResDTO; import com.meetkey.server.global.security.oauth.dto.OauthReqDTO; -import com.meetkey.server.global.security.oauth.kakao.KakaoOauthClient; +import com.meetkey.server.global.security.oauth.kakao.KakaoOidcService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -38,7 +37,7 @@ public class AuthController { private final AuthService authService; private final SmsService smsService; - private final KakaoOauthClient kakaoOauthClient; + private final KakaoOidcService kakaoOidcService; @Value("${admin.secret}") @@ -146,8 +145,7 @@ public ResponseEntity> verifyAuthCode( @GetMapping("/test/kakao-keys") public ResponseEntity getKeys() { // 호출할 때마다 로그를 찍어서 캐시 동작 확인 - System.out.println("Calling AppleOauthClient..."); - return ResponseEntity.ok(kakaoOauthClient.getKakaoOIDCOpenKeys()); + return ResponseEntity.ok(kakaoOidcService.getKakaoOIDCOpenKeys()); } } diff --git a/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java b/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java index 2e57810..9a3f4bd 100644 --- a/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java +++ b/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java @@ -17,7 +17,7 @@ import com.meetkey.server.domain.auth.exception.AuthErrorStatus; import com.meetkey.server.domain.auth.exception.AuthException; import com.meetkey.server.global.security.oauth.dto.OidcDTO; -import com.meetkey.server.global.security.oauth.kakao.KakaoOauthClient; +import com.meetkey.server.global.security.oauth.kakao.KakaoOidcService; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -35,7 +35,7 @@ public class AuthService { @Value(("{apple.app-key}")) private String appleAppKey; - private final KakaoOauthClient kakaoClient; + private final KakaoOidcService kakaoOidcService; private final AppleOauthClient appleClient; private final OauthOidcHelper oAuthOIDCHelper; @@ -173,7 +173,7 @@ private String getAppleProviderIdFromIdToken(String idToken){ } private String getKakaoProviderIdFromIdToken(String idToken){ - OidcDTO.OIDCPublicKeys response = kakaoClient.getKakaoOIDCOpenKeys(); + OidcDTO.OIDCPublicKeys response = kakaoOidcService.getKakaoOIDCOpenKeys(); OidcDTO.OIDCDecodePayload payload = oAuthOIDCHelper.getPayloadFromIdToken( idToken, "https://kauth.kakao.com", diff --git a/src/main/java/com/meetkey/server/global/security/oauth/apple/AppleOauthClient.java b/src/main/java/com/meetkey/server/global/security/oauth/apple/AppleOauthClient.java index f10d28c..fb86e89 100644 --- a/src/main/java/com/meetkey/server/global/security/oauth/apple/AppleOauthClient.java +++ b/src/main/java/com/meetkey/server/global/security/oauth/apple/AppleOauthClient.java @@ -6,13 +6,14 @@ import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; +// 애플도 나중에 연결되면 @Cacheable없애고 Service단 하나 만들어야 함. @FeignClient( name = "AppleOauthClient", url = "https://appleid.apple.com", configuration = OauthConfig.class ) public interface AppleOauthClient { - @Cacheable(cacheNames = "AppleOICD", cacheManager = "oidcCacheManager") + // @Cacheable(cacheNames = "AppleOICD", cacheManager = "oidcCacheManager") @GetMapping("/auth/keys") OidcDTO.OIDCPublicKeys getAppleOIDCOpenKeys(); } diff --git a/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOauthClient.java b/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOauthClient.java index 5fdf82f..cf2efa6 100644 --- a/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOauthClient.java +++ b/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOauthClient.java @@ -12,7 +12,6 @@ configuration = OauthConfig.class ) public interface KakaoOauthClient { - @Cacheable(cacheNames = "KakaoOICD", cacheManager = "oidcCacheManager") @GetMapping("/.well-known/jwks.json") OidcDTO.OIDCPublicKeys getKakaoOIDCOpenKeys(); } diff --git a/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOidcService.java b/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOidcService.java new file mode 100644 index 0000000..e03d974 --- /dev/null +++ b/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOidcService.java @@ -0,0 +1,17 @@ +package com.meetkey.server.global.security.oauth.kakao; + +import com.meetkey.server.global.security.oauth.dto.OidcDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class KakaoOidcService { + private final KakaoOauthClient kakaoOauthClient; + + @Cacheable(cacheNames = "KakaoOICD", cacheManager = "oidcCacheManager") + public OidcDTO.OIDCPublicKeys getKakaoOIDCOpenKeys(){ + return kakaoOauthClient.getKakaoOIDCOpenKeys(); + }; +} From 1353e8f162fd4f6a9929e64814c6e1009cb4887a Mon Sep 17 00:00:00 2001 From: rud15dns Date: Wed, 4 Feb 2026 23:43:13 +0900 Subject: [PATCH 06/15] =?UTF-8?q?fix:=20service=20->=20FeignClient?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20(Caching=20=EB=90=98=EB=8A=94?= =?UTF-8?q?=20=EA=B1=B0=20=ED=99=95=EC=9D=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/controller/AuthController.java | 12 ++--------- .../domain/auth/service/AuthService.java | 6 +++--- .../server/global/config/FeignConfig.java | 20 +++++++++++++++++++ .../oauth/apple/AppleOauthClient.java | 1 - .../oauth/kakao/KakaoOauthClient.java | 4 +++- .../oauth/kakao/KakaoOidcService.java | 17 ---------------- src/main/resources/application-local.yaml | 2 +- 7 files changed, 29 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/meetkey/server/global/config/FeignConfig.java delete mode 100644 src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOidcService.java diff --git a/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java b/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java index 36165bb..682966f 100644 --- a/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java +++ b/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java @@ -14,7 +14,7 @@ import com.meetkey.server.global.security.jwt.dto.JwtResDTO; import com.meetkey.server.global.security.oauth.dto.OauthReqDTO; -import com.meetkey.server.global.security.oauth.kakao.KakaoOidcService; +import com.meetkey.server.global.security.oauth.kakao.KakaoOauthClient; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -37,7 +37,7 @@ public class AuthController { private final AuthService authService; private final SmsService smsService; - private final KakaoOidcService kakaoOidcService; + private final KakaoOauthClient kakaoOauthClient; @Value("${admin.secret}") @@ -140,12 +140,4 @@ public ResponseEntity> verifyAuthCode( .ok() .body(BasicResponse.success(CommonSuccessStatus._OK, true)); } - - - @GetMapping("/test/kakao-keys") - public ResponseEntity getKeys() { - // 호출할 때마다 로그를 찍어서 캐시 동작 확인 - return ResponseEntity.ok(kakaoOidcService.getKakaoOIDCOpenKeys()); - } - } diff --git a/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java b/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java index 9a3f4bd..84c54b3 100644 --- a/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java +++ b/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java @@ -17,7 +17,7 @@ import com.meetkey.server.domain.auth.exception.AuthErrorStatus; import com.meetkey.server.domain.auth.exception.AuthException; import com.meetkey.server.global.security.oauth.dto.OidcDTO; -import com.meetkey.server.global.security.oauth.kakao.KakaoOidcService; +import com.meetkey.server.global.security.oauth.kakao.KakaoOauthClient; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -35,7 +35,7 @@ public class AuthService { @Value(("{apple.app-key}")) private String appleAppKey; - private final KakaoOidcService kakaoOidcService; + private final KakaoOauthClient kakaoOauthClient; private final AppleOauthClient appleClient; private final OauthOidcHelper oAuthOIDCHelper; @@ -173,7 +173,7 @@ private String getAppleProviderIdFromIdToken(String idToken){ } private String getKakaoProviderIdFromIdToken(String idToken){ - OidcDTO.OIDCPublicKeys response = kakaoOidcService.getKakaoOIDCOpenKeys(); + OidcDTO.OIDCPublicKeys response = kakaoOauthClient.getKakaoOIDCOpenKeys(); OidcDTO.OIDCDecodePayload payload = oAuthOIDCHelper.getPayloadFromIdToken( idToken, "https://kauth.kakao.com", diff --git a/src/main/java/com/meetkey/server/global/config/FeignConfig.java b/src/main/java/com/meetkey/server/global/config/FeignConfig.java new file mode 100644 index 0000000..29ff5ec --- /dev/null +++ b/src/main/java/com/meetkey/server/global/config/FeignConfig.java @@ -0,0 +1,20 @@ +package com.meetkey.server.global.config; + +import feign.Logger; +import feign.slf4j.Slf4jLogger; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class FeignConfig { + + @Bean + Logger.Level feignLoggerLevel() { + return Logger.Level.FULL; + } + + @Bean + public Logger feignLogger() { + return new Slf4jLogger(); + } +} \ No newline at end of file diff --git a/src/main/java/com/meetkey/server/global/security/oauth/apple/AppleOauthClient.java b/src/main/java/com/meetkey/server/global/security/oauth/apple/AppleOauthClient.java index fb86e89..df6578e 100644 --- a/src/main/java/com/meetkey/server/global/security/oauth/apple/AppleOauthClient.java +++ b/src/main/java/com/meetkey/server/global/security/oauth/apple/AppleOauthClient.java @@ -6,7 +6,6 @@ import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; -// 애플도 나중에 연결되면 @Cacheable없애고 Service단 하나 만들어야 함. @FeignClient( name = "AppleOauthClient", url = "https://appleid.apple.com", diff --git a/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOauthClient.java b/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOauthClient.java index cf2efa6..b1dad2f 100644 --- a/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOauthClient.java +++ b/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOauthClient.java @@ -1,5 +1,6 @@ package com.meetkey.server.global.security.oauth.kakao; +import com.meetkey.server.global.config.FeignConfig; import com.meetkey.server.global.config.OauthConfig; import com.meetkey.server.global.security.oauth.dto.OidcDTO; import org.springframework.cache.annotation.Cacheable; @@ -9,9 +10,10 @@ @FeignClient( name = "KakaoAuthClient", url = "https://kauth.kakao.com", - configuration = OauthConfig.class + configuration = {OauthConfig.class, FeignConfig.class} ) public interface KakaoOauthClient { + @Cacheable(cacheNames = "KakaoOICD", cacheManager = "oidcCacheManager") @GetMapping("/.well-known/jwks.json") OidcDTO.OIDCPublicKeys getKakaoOIDCOpenKeys(); } diff --git a/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOidcService.java b/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOidcService.java deleted file mode 100644 index e03d974..0000000 --- a/src/main/java/com/meetkey/server/global/security/oauth/kakao/KakaoOidcService.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.meetkey.server.global.security.oauth.kakao; - -import com.meetkey.server.global.security.oauth.dto.OidcDTO; -import lombok.RequiredArgsConstructor; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class KakaoOidcService { - private final KakaoOauthClient kakaoOauthClient; - - @Cacheable(cacheNames = "KakaoOICD", cacheManager = "oidcCacheManager") - public OidcDTO.OIDCPublicKeys getKakaoOIDCOpenKeys(){ - return kakaoOauthClient.getKakaoOIDCOpenKeys(); - }; -} diff --git a/src/main/resources/application-local.yaml b/src/main/resources/application-local.yaml index 3841fcc..c60f232 100644 --- a/src/main/resources/application-local.yaml +++ b/src/main/resources/application-local.yaml @@ -45,4 +45,4 @@ cloud: aws: credentials: access-key: ${AWS_ACCESS_KEY:} - secret-key: ${AWS_SECRET_KEY:} + secret-key: ${AWS_SECRET_KEY:} \ No newline at end of file From 9a0af441494d9307f72591b8fb8232b7618f3c5a Mon Sep 17 00:00:00 2001 From: rud15dns Date: Thu, 5 Feb 2026 00:09:10 +0900 Subject: [PATCH 07/15] =?UTF-8?q?fix:=20static=20class=20->=20dto=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD,=20mapper=20=EC=BB=A4=EC=8A=A4=ED=85=80?= =?UTF-8?q?=ED=99=94=ED=95=98=EC=97=AC=20=EC=A7=81=EB=A0=AC=ED=99=94=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/controller/AuthController.java | 13 ++++-- .../domain/auth/service/AuthService.java | 4 +- .../config/RecordSupportingTypeResolver.java | 22 +++++++++ .../server/global/config/RedisConfig.java | 14 ++---- .../security/oauth/OauthOidcHelper.java | 6 +-- .../global/security/oauth/dto/OidcDTO.java | 46 +++++++------------ 6 files changed, 58 insertions(+), 47 deletions(-) create mode 100644 src/main/java/com/meetkey/server/global/config/RecordSupportingTypeResolver.java diff --git a/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java b/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java index 682966f..8835b46 100644 --- a/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java +++ b/src/main/java/com/meetkey/server/domain/auth/controller/AuthController.java @@ -2,11 +2,7 @@ import com.meetkey.server.domain.auth.service.AuthService; import com.meetkey.server.domain.auth.service.SmsService; -import com.meetkey.server.domain.member.entity.Member; import com.meetkey.server.domain.member.enums.Provider; -import com.meetkey.server.domain.member.enums.Role; -import com.meetkey.server.domain.member.repository.MemberRepository; -import com.meetkey.server.domain.member.service.MemberService; import com.meetkey.server.global.apiPayload.response.BasicResponse; import com.meetkey.server.global.apiPayload.status.CommonErrorStatus; import com.meetkey.server.global.apiPayload.status.CommonSuccessStatus; @@ -14,6 +10,7 @@ import com.meetkey.server.global.security.jwt.dto.JwtResDTO; import com.meetkey.server.global.security.oauth.dto.OauthReqDTO; +import com.meetkey.server.global.security.oauth.dto.OidcDTO; import com.meetkey.server.global.security.oauth.kakao.KakaoOauthClient; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -140,4 +137,12 @@ public ResponseEntity> verifyAuthCode( .ok() .body(BasicResponse.success(CommonSuccessStatus._OK, true)); } + + // OIDC Cache 설정 확인 테스트 + @GetMapping("/test/kakao-keys") + public ResponseEntity getKeys() { + OidcDTO.OIDCPublicKeys keys = kakaoOauthClient.getKakaoOIDCOpenKeys(); + + return ResponseEntity.ok(keys); + } } diff --git a/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java b/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java index 84c54b3..99519ea 100644 --- a/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java +++ b/src/main/java/com/meetkey/server/domain/auth/service/AuthService.java @@ -169,7 +169,7 @@ private String getAppleProviderIdFromIdToken(String idToken){ response ); - return payload.getSub(); + return payload.sub(); } private String getKakaoProviderIdFromIdToken(String idToken){ @@ -181,7 +181,7 @@ private String getKakaoProviderIdFromIdToken(String idToken){ response ); - return payload.getSub(); + return payload.sub(); } } diff --git a/src/main/java/com/meetkey/server/global/config/RecordSupportingTypeResolver.java b/src/main/java/com/meetkey/server/global/config/RecordSupportingTypeResolver.java new file mode 100644 index 0000000..6d359a9 --- /dev/null +++ b/src/main/java/com/meetkey/server/global/config/RecordSupportingTypeResolver.java @@ -0,0 +1,22 @@ +package com.meetkey.server.global.config; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; + +public class RecordSupportingTypeResolver extends ObjectMapper.DefaultTypeResolverBuilder { + public RecordSupportingTypeResolver(ObjectMapper.DefaultTyping t, PolymorphicTypeValidator ptv) { + super(t, ptv); + } + + @Override + public boolean useForType(JavaType t){ + boolean isRecord = t.getRawClass().isRecord(); + boolean superResult = super.useForType(t); + + if (isRecord) { + return true; + } + return superResult; + } +} diff --git a/src/main/java/com/meetkey/server/global/config/RedisConfig.java b/src/main/java/com/meetkey/server/global/config/RedisConfig.java index c58a6aa..2fc21b2 100644 --- a/src/main/java/com/meetkey/server/global/config/RedisConfig.java +++ b/src/main/java/com/meetkey/server/global/config/RedisConfig.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; @@ -101,15 +102,10 @@ public RedisCacheManager oidcCacheManager( @Qualifier("authRedisConnectionFactory") RedisConnectionFactory connectionFactory ){ ObjectMapper cacheMapper = new ObjectMapper(); - cacheMapper.registerModule(new JavaTimeModule()); - cacheMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); - - // 타입 정보 활성화 - cacheMapper.activateDefaultTyping( - cacheMapper.getPolymorphicTypeValidator(), - ObjectMapper.DefaultTyping.NON_FINAL, - JsonTypeInfo.As.PROPERTY - ); + RecordSupportingTypeResolver typeResolver = new RecordSupportingTypeResolver(ObjectMapper.DefaultTyping.NON_FINAL, cacheMapper.getPolymorphicTypeValidator()); + StdTypeResolverBuilder initializedResolver = typeResolver.init(JsonTypeInfo.Id.CLASS, null); + initializedResolver = initializedResolver.inclusion(JsonTypeInfo.As.PROPERTY); + cacheMapper.setDefaultTyping(initializedResolver); RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith( diff --git a/src/main/java/com/meetkey/server/global/security/oauth/OauthOidcHelper.java b/src/main/java/com/meetkey/server/global/security/oauth/OauthOidcHelper.java index 2cc7dae..77ef2fa 100644 --- a/src/main/java/com/meetkey/server/global/security/oauth/OauthOidcHelper.java +++ b/src/main/java/com/meetkey/server/global/security/oauth/OauthOidcHelper.java @@ -20,12 +20,12 @@ public OidcDTO.OIDCDecodePayload getPayloadFromIdToken( // kid 에 맞는 공개키를 가져옴 OidcDTO.OIDCPublicKey publicKey = - response.getKeys().stream() - .filter(o -> o.getKid().equals(kid)) + response.keys().stream() + .filter(o -> o.kid().equals(kid)) .findFirst() .orElseThrow(); - return jwtOIDCProvider.getOIDCTokenBody(token, publicKey.getN(), publicKey.getE()); + return jwtOIDCProvider.getOIDCTokenBody(token, publicKey.n(), publicKey.e()); } } diff --git a/src/main/java/com/meetkey/server/global/security/oauth/dto/OidcDTO.java b/src/main/java/com/meetkey/server/global/security/oauth/dto/OidcDTO.java index 1e69699..02e3d12 100644 --- a/src/main/java/com/meetkey/server/global/security/oauth/dto/OidcDTO.java +++ b/src/main/java/com/meetkey/server/global/security/oauth/dto/OidcDTO.java @@ -1,43 +1,31 @@ package com.meetkey.server.global.security.oauth.dto; -import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; import java.util.List; import java.util.Set; public class OidcDTO { - @Getter @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class OIDCDecodePayload { - private String iss; - private Set aud; - private String sub; - } + public record OIDCDecodePayload ( + String iss, + Set aud, + String sub + ){} - @Getter @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class OIDCPublicKey { - private String kid; - private String kty; - private String alg; - private String use; - private String n; - private String e; - } + public record OIDCPublicKey ( + // JWK + String kid, + String kty, + String alg, + String use, + String n, + String e + ){} - // 인증서버가 ID 토큰 서명 시 사용한 공개키 목록을 담은 JWK 배열 - @Getter @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class OIDCPublicKeys { - private List keys; - } + public record OIDCPublicKeys( + List keys // 인증서버가 ID 토큰 서명 시 사용한 공개키 목록을 담은 JWK 배열 + ){} } From 06c8571e84ea35237aeb9287014d12d9ed1311ff Mon Sep 17 00:00:00 2001 From: rud15dns Date: Thu, 5 Feb 2026 00:11:20 +0900 Subject: [PATCH 08/15] =?UTF-8?q?fix:=20redis=20=EA=B4=80=EB=A0=A8=20cd.ya?= =?UTF-8?q?ml=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index e6aa963..9f28744 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -63,5 +63,8 @@ jobs: export COOLSMS_API_SECRET=${{ secrets.COOLSMS_API_SECRET }} export COOLSMS_SENDER=${{ secrets.COOLSMS_SENDER }} + # Spring Boot 앱만 pull docker compose -f docker-compose.yml pull spring-boot-app - docker compose -f docker-compose.yml up -d --no-deps spring-boot-app + + # 전체 재시작 (Redis는 변경 없으면 그대로 유지됨) + docker compose -f docker-compose.yml up -d From 36d0de628481c01b471bc395635c00aa4051fc1f Mon Sep 17 00:00:00 2001 From: rud15dns Date: Thu, 5 Feb 2026 00:22:09 +0900 Subject: [PATCH 09/15] =?UTF-8?q?fix:=20ci=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc05c92..617a71c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,7 @@ jobs: - name: Run tests run: ./gradlew test --stacktrace --no-daemon env: + SPRING_PROFILES_ACTIVE: local SPRING_DATA_REDIS_CHAT_HOST: localhost SPRING_DATA_REDIS_CHAT_PORT: 6379 SPRING_DATA_REDIS_AUTH_HOST: localhost From 9a5c6308a511972e7f1c29be2c34fab979791b02 Mon Sep 17 00:00:00 2001 From: rud15dns Date: Thu, 5 Feb 2026 18:34:41 +0900 Subject: [PATCH 10/15] =?UTF-8?q?fix:=20fcm=20=EB=B0=B0=ED=8F=AC=20?= =?UTF-8?q?=ED=99=98=EA=B2=BD=20=EA=B5=AC=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd.yml | 2 + .github/workflows/ci.yml | 14 +------ docker-compose.yml | 19 +++------ .../message/redis/RedisSubscriberConfig.java | 2 +- .../server/global/config/FcmConfig.java | 13 +++++- .../server/global/config/RedisConfig.java | 40 +++++-------------- src/main/resources/application-local.yaml | 6 +-- src/main/resources/application-prod.yaml | 6 +-- 8 files changed, 37 insertions(+), 65 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 9f28744..85fa530 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -63,6 +63,8 @@ jobs: export COOLSMS_API_SECRET=${{ secrets.COOLSMS_API_SECRET }} export COOLSMS_SENDER=${{ secrets.COOLSMS_SENDER }} + export FCM_KEY_PATH=/app/firebase/${{ secrets.FCM_FILE_NAME }} + # Spring Boot 앱만 pull docker compose -f docker-compose.yml pull spring-boot-app diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 617a71c..663e64e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,14 +8,10 @@ jobs: runs-on: ubuntu-latest services: - redis-chat: + redis: image: redis:7-alpine ports: - 6379:6379 - redis-auth: - image: redis:7-alpine - ports: - - 6380:6379 steps: - uses: actions/checkout@v3 @@ -30,10 +26,4 @@ jobs: run: chmod +x gradlew - name: Run tests - run: ./gradlew test --stacktrace --no-daemon - env: - SPRING_PROFILES_ACTIVE: local - SPRING_DATA_REDIS_CHAT_HOST: localhost - SPRING_DATA_REDIS_CHAT_PORT: 6379 - SPRING_DATA_REDIS_AUTH_HOST: localhost - SPRING_DATA_REDIS_AUTH_PORT: 6380 \ No newline at end of file + run: ./gradlew test --stacktrace --no-daemon \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 0389f53..7df5846 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,7 @@ services: - "80:8080" environment: SPRING_PROFILES_ACTIVE: prod + FCM_KEY_PATH: ${FCM_KEY_PATH} S3_BUCKET: ${S3_BUCKET} DB_URL: ${DB_URL} DB_USERNAME: ${DB_USERNAME} @@ -14,32 +15,24 @@ services: JWT_SECRET_KEY: ${JWT_SECRET_KEY} ADMIN_SECRET: ${ADMIN_SECRET} KAKAO_APP_KEY: ${KAKAO_APP_KEY} - COOLSMS_API_KEY: ${COOLSMS_API_KEY} COOLSMS_API_SECRET: ${COOLSMS_API_SECRET} COOLSMS_SENDER: ${COOLSMS_SENDER} + volumes: + - /home/ec2-user/app/firebase:/app/firebase:ro depends_on: - - redis-chat - - redis-auth + - redis networks: - spring-boot-app-network - redis-chat: + redis: image: redis:7-alpine - container_name: redis-chat + container_name: redis ports: - "6379:6379" networks: - spring-boot-app-network - redis-auth: - image: redis:7-alpine - container_name: redis-auth - ports: - - "6380:6379" - networks: - - spring-boot-app-network - networks: spring-boot-app-network: driver: bridge \ No newline at end of file diff --git a/src/main/java/com/meetkey/server/domain/chat/message/redis/RedisSubscriberConfig.java b/src/main/java/com/meetkey/server/domain/chat/message/redis/RedisSubscriberConfig.java index 5ce6768..d2433ed 100644 --- a/src/main/java/com/meetkey/server/domain/chat/message/redis/RedisSubscriberConfig.java +++ b/src/main/java/com/meetkey/server/domain/chat/message/redis/RedisSubscriberConfig.java @@ -14,7 +14,7 @@ public class RedisSubscriberConfig { private final ChatRedisSubscriber chatRedisSubscriber; public RedisSubscriberConfig( - @Qualifier("chatRedisConnectionFactory") RedisConnectionFactory connectionFactory, + RedisConnectionFactory connectionFactory, ChatRedisSubscriber chatRedisSubscriber) { this.connectionFactory = connectionFactory; this.chatRedisSubscriber = chatRedisSubscriber; diff --git a/src/main/java/com/meetkey/server/global/config/FcmConfig.java b/src/main/java/com/meetkey/server/global/config/FcmConfig.java index 2dd99d1..55b4589 100644 --- a/src/main/java/com/meetkey/server/global/config/FcmConfig.java +++ b/src/main/java/com/meetkey/server/global/config/FcmConfig.java @@ -6,8 +6,11 @@ import jakarta.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.ResourceLoader; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; @@ -20,7 +23,7 @@ public class FcmConfig { @PostConstruct public void init() { try { - InputStream serviceAccount = new ClassPathResource(fcmKeyPath).getInputStream(); + InputStream serviceAccount = getResourceStream(); FirebaseOptions options = FirebaseOptions.builder() .setCredentials(GoogleCredentials.fromStream(serviceAccount)) .build(); @@ -31,4 +34,12 @@ public void init() { throw new RuntimeException("FCM 초기화 실패", e); } } + + private InputStream getResourceStream() throws IOException { + // 경로가 /로 시작하면 외부 파일 시스템(prod), 아니면 클래스패스(local)에서 읽도록 구성 + if (fcmKeyPath.startsWith("/")) { + return new FileInputStream(fcmKeyPath); + } + return new ClassPathResource(fcmKeyPath).getInputStream(); + } } diff --git a/src/main/java/com/meetkey/server/global/config/RedisConfig.java b/src/main/java/com/meetkey/server/global/config/RedisConfig.java index 2fc21b2..edf5431 100644 --- a/src/main/java/com/meetkey/server/global/config/RedisConfig.java +++ b/src/main/java/com/meetkey/server/global/config/RedisConfig.java @@ -5,12 +5,10 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; @@ -27,15 +25,11 @@ @Configuration @EnableCaching public class RedisConfig { - @Value("${spring.data.redis.chat.host}") - private String chatHost; - @Value("${spring.data.redis.auth.host}") - private String authHost; + @Value("${spring.data.redis.host}") + private String host; - @Value("${spring.data.redis.chat.port:6379}") - private int chatPort; - @Value("${spring.data.redis.auth.port:6379}") - private int authPort; + @Value("${spring.data.redis.port}") + private int port; @Bean public ObjectMapper redisObjectMapper() { @@ -45,25 +39,11 @@ public ObjectMapper redisObjectMapper() { return mapper; } - // 채팅용 (port: 6379) @Bean - @Primary - public RedisConnectionFactory chatRedisConnectionFactory() { + public RedisConnectionFactory RedisConnectionFactory(){ RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); - config.setHostName(chatHost); - config.setPort(chatPort); - - LettuceConnectionFactory factory = new LettuceConnectionFactory(config); - factory.afterPropertiesSet(); - return factory; - } - - // SMS/Refresh토큰용 Redis - @Bean - public RedisConnectionFactory authRedisConnectionFactory(){ - RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); - config.setHostName(authHost); - config.setPort(authPort); + config.setHostName(host); + config.setPort(port); LettuceConnectionFactory factory = new LettuceConnectionFactory(config); factory.afterPropertiesSet(); @@ -72,7 +52,7 @@ public RedisConnectionFactory authRedisConnectionFactory(){ @Bean public RedisTemplate redisTemplate( - @Qualifier("chatRedisConnectionFactory") RedisConnectionFactory connectionFactory, + RedisConnectionFactory connectionFactory, ObjectMapper redisObjectMapper) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); @@ -90,7 +70,7 @@ public RedisTemplate redisTemplate( // SMS, RefreshToken용 @Bean public StringRedisTemplate stringRedisTemplate( - @Qualifier("authRedisConnectionFactory") RedisConnectionFactory connectionFactory) { + RedisConnectionFactory connectionFactory) { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(connectionFactory); return template; @@ -99,7 +79,7 @@ public StringRedisTemplate stringRedisTemplate( // OIDC 공개용 키 저장 @Bean public RedisCacheManager oidcCacheManager( - @Qualifier("authRedisConnectionFactory") RedisConnectionFactory connectionFactory + RedisConnectionFactory connectionFactory ){ ObjectMapper cacheMapper = new ObjectMapper(); RecordSupportingTypeResolver typeResolver = new RecordSupportingTypeResolver(ObjectMapper.DefaultTyping.NON_FINAL, cacheMapper.getPolymorphicTypeValidator()); diff --git a/src/main/resources/application-local.yaml b/src/main/resources/application-local.yaml index 9c19eb9..b2e2106 100644 --- a/src/main/resources/application-local.yaml +++ b/src/main/resources/application-local.yaml @@ -1,10 +1,8 @@ - spring: data: redis: - host: ${REDIS_HOST:localhost} - port: ${REDIS_PORT:6379} - + host: localhost + port: 6379 jwt: secret: ${JWT_SECRET_KEY:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} diff --git a/src/main/resources/application-prod.yaml b/src/main/resources/application-prod.yaml index 3e10a2d..e825d0c 100644 --- a/src/main/resources/application-prod.yaml +++ b/src/main/resources/application-prod.yaml @@ -1,10 +1,8 @@ spring: data: redis: - chat: - host: redis-chat - auth: - host: redis-auth + host: redis + port: 6379 jwt: secret: ${JWT_SECRET_KEY:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} From 5ddcf690c52728b457a1e9440646af91cd67bbb8 Mon Sep 17 00:00:00 2001 From: rud15dns Date: Thu, 5 Feb 2026 18:38:30 +0900 Subject: [PATCH 11/15] =?UTF-8?q?fix:=20fcm=20config=EC=97=90=20profile=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/meetkey/server/global/config/FcmConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/meetkey/server/global/config/FcmConfig.java b/src/main/java/com/meetkey/server/global/config/FcmConfig.java index 55b4589..f027c59 100644 --- a/src/main/java/com/meetkey/server/global/config/FcmConfig.java +++ b/src/main/java/com/meetkey/server/global/config/FcmConfig.java @@ -15,6 +15,7 @@ import java.io.InputStream; @Configuration +@Profile({"local", "prod"}) public class FcmConfig { @Value("${fcm.key.path}") From ee0647833efd66fc71ab36478e95701aa547c1a8 Mon Sep 17 00:00:00 2001 From: rud15dns Date: Thu, 5 Feb 2026 18:43:25 +0900 Subject: [PATCH 12/15] =?UTF-8?q?fix:=20ci=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 663e64e..75f9327 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,5 +25,12 @@ jobs: - name: Grant permission for gradlew run: chmod +x gradlew + - name: Create dummy FCM file for test + run: | + mkdir -p src/main/resources/firebase + echo '{"type": "service_account", "project_id": "test"}' > src/main/resources/firebase/test.json + - name: Run tests + env: + FCM_KEY_PATH: firebase/test.json run: ./gradlew test --stacktrace --no-daemon \ No newline at end of file From 847f51ffbd2fe0d8b40d40861d48b98d32f9d976 Mon Sep 17 00:00:00 2001 From: rud15dns Date: Thu, 5 Feb 2026 18:48:35 +0900 Subject: [PATCH 13/15] =?UTF-8?q?fix:=20test=20yaml=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 7 +-- .../server/global/config/FcmConfig.java | 2 +- src/main/resources/application-test.yaml | 52 +++++++++++++++++++ 3 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 src/main/resources/application-test.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75f9327..c8bea31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,12 +25,7 @@ jobs: - name: Grant permission for gradlew run: chmod +x gradlew - - name: Create dummy FCM file for test - run: | - mkdir -p src/main/resources/firebase - echo '{"type": "service_account", "project_id": "test"}' > src/main/resources/firebase/test.json - - name: Run tests env: - FCM_KEY_PATH: firebase/test.json + SPRING_PROFILES_ACTIVE: test run: ./gradlew test --stacktrace --no-daemon \ No newline at end of file diff --git a/src/main/java/com/meetkey/server/global/config/FcmConfig.java b/src/main/java/com/meetkey/server/global/config/FcmConfig.java index f027c59..4fe563c 100644 --- a/src/main/java/com/meetkey/server/global/config/FcmConfig.java +++ b/src/main/java/com/meetkey/server/global/config/FcmConfig.java @@ -15,7 +15,7 @@ import java.io.InputStream; @Configuration -@Profile({"local", "prod"}) +@Profile("!test") public class FcmConfig { @Value("${fcm.key.path}") diff --git a/src/main/resources/application-test.yaml b/src/main/resources/application-test.yaml new file mode 100644 index 0000000..396e67b --- /dev/null +++ b/src/main/resources/application-test.yaml @@ -0,0 +1,52 @@ +spring: + spring: + config: + activate: + on-profile: test + data: + redis: + host: localhost + port: 6379 + jwt: + secret: ${JWT_SECRET_KEY:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} + + application: + name: server + + datasource: + url: ${DB_URL:} + username: ${DB_USERNAME:} + password: ${DB_PW:} + driver-class-name: ${DB_DRIVER:} + + jpa: + hibernate: + ddl-auto: update + database-platform: org.hibernate.dialect.MySQL8Dialect + properties: + hibernate: + format_sql: true + +coolsms: + api-key: ${COOLSMS_API_KEY:} + api-secret: ${COOLSMS_API_SECRET:} + sender: ${COOLSMS_SENDER:} + +admin: + secret: ${ADMIN_SECRET:} + +kakao: + app-key: ${KAKAO_APP_KEY:} + +apple: + app-key: ${APPLE_APP_KEY:} + +cloud: + aws: + credentials: + access-key: ${AWS_ACCESS_KEY:} + secret-key: ${AWS_SECRET_KEY:} + +fcm: + key: + path: "dummy-path"" From 43ffa86c8f0020724d7bbd65da17419eb3a9a61e Mon Sep 17 00:00:00 2001 From: rud15dns Date: Thu, 5 Feb 2026 18:51:04 +0900 Subject: [PATCH 14/15] =?UTF-8?q?fix:=20test.yaml=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-test.yaml b/src/main/resources/application-test.yaml index 396e67b..0872f09 100644 --- a/src/main/resources/application-test.yaml +++ b/src/main/resources/application-test.yaml @@ -49,4 +49,4 @@ cloud: fcm: key: - path: "dummy-path"" + path: "dummy-path" From 28ae65ce1a112dc9b7642a69956ba32be042ed1e Mon Sep 17 00:00:00 2001 From: rud15dns Date: Thu, 5 Feb 2026 18:54:34 +0900 Subject: [PATCH 15/15] =?UTF-8?q?fix:=20test=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/com/meetkey/server/ServerApplicationTests.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/com/meetkey/server/ServerApplicationTests.java b/src/test/java/com/meetkey/server/ServerApplicationTests.java index 1ba2d46..d7ebcc4 100644 --- a/src/test/java/com/meetkey/server/ServerApplicationTests.java +++ b/src/test/java/com/meetkey/server/ServerApplicationTests.java @@ -2,8 +2,10 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; @SpringBootTest +@ActiveProfiles("test") class ServerApplicationTests { @Test