diff --git a/src/main/java/com/example/egobook_be/domain/auth/controller/AuthControllerDocs.java b/src/main/java/com/example/egobook_be/domain/auth/controller/AuthControllerDocs.java index 3fa0760..65cd554 100644 --- a/src/main/java/com/example/egobook_be/domain/auth/controller/AuthControllerDocs.java +++ b/src/main/java/com/example/egobook_be/domain/auth/controller/AuthControllerDocs.java @@ -23,7 +23,7 @@ public interface AuthControllerDocs { 사용자가 앱을 처음 설치하고 실행했을 때 호출되는 API입니다. - **기능**: 기기 고유 ID(UUID)를 등록하고, **초기 토큰 3종(Access, Refresh, Recover)**을 발급합니다. - - **주의**: + - **주의**: 1. 이미 등록된 기기라면 에러가 발생합니다. (로그인 API 사용 권장) 2. 등록된 기기임을 클라이언트에서 확인할 때, recoverToken의 여부를 확인하세요. (recoverToken이 없다면 처음 로그인 한 것임) """) @@ -105,11 +105,11 @@ public interface AuthControllerDocs { @Operation(summary = "Google 회원가입 (소셜 계정 연동)", description = """ 안드로이드 앱에서 Google 로그인을 수행한 후, 발급받은 **ID Token**을 전송하여 회원가입을 수행합니다. - - **기능**: + - **기능**: 1. Google ID Token의 서명 및 Audience(Client ID)를 검증합니다. 2. 검증된 정보로 신규 가입을 진행하고 **Access, Refresh Token**을 발급합니다. - - **주의사항**: + - **주의사항**: 1. **Google 로그인은 Recover Token을 발급하지 않습니다.** (Response의 recoverToken 값은 null입니다.) - 이유: 계정 복구 및 신원 증명은 Google이 담당하기 때문입니다. 2. 이미 가입된 Google 계정이라면 409 Conflict 에러가 발생합니다. diff --git a/src/main/java/com/example/egobook_be/domain/auth/dto/res/JwtTokenResDto.java b/src/main/java/com/example/egobook_be/domain/auth/dto/res/JwtTokenResDto.java index 670c217..e3c37c9 100644 --- a/src/main/java/com/example/egobook_be/domain/auth/dto/res/JwtTokenResDto.java +++ b/src/main/java/com/example/egobook_be/domain/auth/dto/res/JwtTokenResDto.java @@ -11,6 +11,7 @@ public record JwtTokenResDto( String accessToken, String refreshToken, - String recoverToken // 회원가입 시에만 값 존재하며, 로그인 시에는 null + String recoverToken, // 회원가입 시에만 값 존재하며, 로그인 시에는 null + String email ) { } diff --git a/src/main/java/com/example/egobook_be/domain/auth/sevice/AuthService.java b/src/main/java/com/example/egobook_be/domain/auth/sevice/AuthService.java index a84b2b7..0f23e85 100644 --- a/src/main/java/com/example/egobook_be/domain/auth/sevice/AuthService.java +++ b/src/main/java/com/example/egobook_be/domain/auth/sevice/AuthService.java @@ -33,7 +33,6 @@ import com.example.egobook_be.global.security.CustomUserDetails; import com.example.egobook_be.global.util.module.RedisValue; import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; -import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -81,8 +80,6 @@ public class AuthService { * **주의사항** * 1. Google 계정은 Recover Token을 발급하지 않는다. * 2. Google Sub값을 해싱하여, AuthAccount Table의 HashedDeviceUid 컬럼에 저장한다. - * @param reqDto - * @return */ @Transactional public JwtTokenResDto registerGoogle(GoogleJoinReqDto reqDto){ @@ -139,7 +136,7 @@ public JwtTokenResDto registerGoogle(GoogleJoinReqDto reqDto){ * 8. 클라이언트에게 토큰 반환 * - Google 로그인이므로 recoverToken은 null을 반환한다. */ - return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), null); + return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), null, email); } @@ -202,7 +199,7 @@ public JwtTokenResDto registerGuest(GuestJoinReqDto reqDto){ * 10. 클라이언트에게 토큰을 반환 * recoverToken은 회원가입, refreshToken 재발급 시에만 발급된다. */ - return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), recoverTokenInfo.token()); + return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), recoverTokenInfo.token(), null); } @@ -230,7 +227,7 @@ public JwtTokenResDto refreshToken(RefreshReqDto reqDto){ // 기존 AccessToken Redis 블랙리스트에 추가 addAccessTokenInRedisBlackList(reqDto.accessToken()); TokenInfo newAccessTokenInfo = jwtUtil.createAccessToken(redisValue.userId(), redisValue.authAccountId(), redisValue.subject(), redisValue.role()); - return buildJwtTokenResDto(newAccessTokenInfo.token(), reqDto.refreshToken(), null); + return buildJwtTokenResDto(newAccessTokenInfo.token(), reqDto.refreshToken(), null, null); } /* @@ -275,7 +272,7 @@ public JwtTokenResDto refreshToken(RefreshReqDto reqDto){ // 7. Access Token 재생성 후 Access, Refresh Token 반환 TokenInfo newAccessTokenInfo = jwtUtil.createAccessToken(user.getId(), authAccount.getId(), subject, user.getRole()); - return buildJwtTokenResDto(newAccessTokenInfo.token(), reqDto.refreshToken(), null); + return buildJwtTokenResDto(newAccessTokenInfo.token(), reqDto.refreshToken(), null, null); } /** HttpServletRequest에 들어있는 AccessToken 추출 및 블랙리스트 등록 */ @@ -371,7 +368,7 @@ public JwtTokenResDto recertificationGuestToken(GuestRecertificationReqDto reqDt registerToRedis(newHashedRefreshToken, newRedisValue, newRefreshTokenInfo.expiresAt()); // 9. 결과 반환 - return buildJwtTokenResDto(newAccessTokenInfo.token(), newRefreshTokenInfo.token(), newRecoverTokenInfo.token()); + return buildJwtTokenResDto(newAccessTokenInfo.token(), newRefreshTokenInfo.token(), newRecoverTokenInfo.token(), null); } /** @@ -421,7 +418,7 @@ public JwtTokenResDto recertificationGoogleToken(GoogleRecertificationReqDto req processRefreshTokenSaving(user, authAccount, refreshTokenInfo); // 6. 반환 - return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), null); + return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), null, user.getEmail()); } /** @@ -489,7 +486,7 @@ public JwtTokenResDto linkGoogleAccount(Long userId, GoogleJoinReqDto reqDto) { processRefreshTokenSaving(user, googleAuthAccount, refreshTokenInfo); // 9. 반환 (Google이므로 Recover Token은 비워놓고 반환한다) - return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), null); + return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), null, user.getEmail()); } @@ -503,7 +500,6 @@ public JwtTokenResDto linkGoogleAccount(Long userId, GoogleJoinReqDto reqDto) { * - email은 선택적으로 넣을 수 있다. * - User 생성 후, userRepository에 save()까지 수행한 결과물을 반환한다. * @param email : Guest-null, Google-Token에 있는 Google Email 설정 - * @return */ private User createUser(String email){ /* @@ -540,7 +536,6 @@ private User createUser(String email){ * @param user 연동할 user * @param provider 해당 회원가입 주체 * @param hashedDeviceUid Guest->hashedDeviceUid, Google->hashedGoogleId - * @return */ private AuthAccount createAuthAccount(User user, Provider provider, String hashedDeviceUid){ AuthAccount authAccount = AuthAccount.builder() @@ -559,7 +554,6 @@ private AuthAccount createAuthAccount(User user, Provider provider, String hashe * (1) authAccount.deviceUid -> refreshTokenBackup.deviceUid (authAccount 테이블이 deviceUid를 관리하는 책임자이다.) * (2) TokenInfo.token -> refreshTokenBackup.tokenValue * (3) TokenInfo.expiresAt -> refreshTokenBackup.expiresAt - * * [ 신규 추가 로직 ] * (1) RefreshTokenBackup 새로 생성하여 authAccount.updateRefreshTokenBackup(...)으로 연결 * -> 영속성 컨텍스트의 Dirty Checking으로 트랜잭션 종료 시 Update됨 @@ -594,9 +588,6 @@ private void updateRefreshTokenBackupTable(AuthAccount authAccount, String hashe /** * key, value, expiresAt(절대시간)을 입력받아 redis에 등록해주는 함수 - * @param key - * @param value - * @param expiresAt */ private void registerToRedis(String key, RedisValue value, LocalDateTime expiresAt){ long ttlInMillis = getDurationInMillis(expiresAt); // 현재 ~ refreshToken의 만료시간까지 남은 밀리초 계산 @@ -611,7 +602,6 @@ private void registerToRedis(String key, RedisValue value, LocalDateTime expires /** * LocalDateTime (절대시간)까지 남은 시간을 millis로 반환해주는 함수 * @param at : 목표 절대 시간 - * @return */ private long getDurationInMillis(LocalDateTime at){ return Duration.between(LocalDateTime.now(), at).toMillis(); // 밀리초로 변환 @@ -619,13 +609,13 @@ private long getDurationInMillis(LocalDateTime at){ /** * JwtTokenResDto를 빌드하는 함수 - * @return */ - private JwtTokenResDto buildJwtTokenResDto(String accessToken, String refreshToken, String recoverToken){ + private JwtTokenResDto buildJwtTokenResDto(String accessToken, String refreshToken, String recoverToken, String email){ return JwtTokenResDto.builder() .accessToken(accessToken) .refreshToken(refreshToken) .recoverToken(recoverToken) + .email(email) .build(); } @@ -676,9 +666,6 @@ private CustomUserDetails buildCustomUserDetails(User user, AuthAccount authAcco /** * 모든 토큰들을 발급한 뒤, Refresh Token을 Table, Redis에 저장하는 Process를 수행해주는 함수 - * @param user - * @param authAccount - * @param refreshTokenInfo */ private void processRefreshTokenSaving(User user, AuthAccount authAccount, TokenInfo refreshTokenInfo){ // 1. Refresh Token을 RefreshTokenBackup Table에 추가(Update) @@ -705,7 +692,6 @@ private void processRefreshTokenSaving(User user, AuthAccount authAccount, Token * (1) 기본 UserItem 인스턴스 생성 * (2) 기본 Ability 인스턴스 생성 * (3) UserTerm 인스턴스 생성 - * @param user */ private void allocateUser(User user){ // 1. 사용자 UserItems 생성 @@ -747,7 +733,6 @@ private List createDefaultUserItems(User user){ /** * user 생성 시 ability 생성 로직 (능력치) * @param user 연동할 user - * @return */ private Ability createDefaultAbility(User user) { Ability ability = Ability.builder() diff --git a/src/main/java/com/example/egobook_be/domain/home/controller/HomeControllerDocs.java b/src/main/java/com/example/egobook_be/domain/home/controller/HomeControllerDocs.java index b1919ba..5cb8e23 100644 --- a/src/main/java/com/example/egobook_be/domain/home/controller/HomeControllerDocs.java +++ b/src/main/java/com/example/egobook_be/domain/home/controller/HomeControllerDocs.java @@ -82,7 +82,10 @@ ResponseEntity> getHomeAbilities( @Operation(summary = "사용자 설정/계정 페이지 정보 조회", description = """ 홈 화면의 '설정(계정)' 탭에 필요한 데이터를 조회합니다. - 현재는 사용자 계정 ID(Account Code)를 반환합니다. + + [ 반환 데이터 ] + 1. 사용자 계정 ID(Account Code) + 2. 사용자 이메일 (Google 연동 했을 시에만 반환됩니다) """) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "조회 성공", content = @Content(schema = @Schema(implementation = HomeSettingResDto.class))) diff --git a/src/main/java/com/example/egobook_be/domain/home/dto/HomeSettingResDto.java b/src/main/java/com/example/egobook_be/domain/home/dto/HomeSettingResDto.java index 158b112..cc0b2fd 100644 --- a/src/main/java/com/example/egobook_be/domain/home/dto/HomeSettingResDto.java +++ b/src/main/java/com/example/egobook_be/domain/home/dto/HomeSettingResDto.java @@ -1,11 +1,15 @@ package com.example.egobook_be.domain.home.dto; +import com.fasterxml.jackson.annotation.JsonInclude; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; @Builder public record HomeSettingResDto( @Schema(description = "사용자 고유 계정 ID (Account Code)", example = "EGO-123456") - String accountCode + String accountCode, + @Schema(description = "사용자 Email", example = "example@google.com") + @JsonInclude(JsonInclude.Include.NON_NULL) + String userEmail ) { } diff --git a/src/main/java/com/example/egobook_be/domain/home/mapper/HomeMapper.java b/src/main/java/com/example/egobook_be/domain/home/mapper/HomeMapper.java index 358d806..7c36393 100644 --- a/src/main/java/com/example/egobook_be/domain/home/mapper/HomeMapper.java +++ b/src/main/java/com/example/egobook_be/domain/home/mapper/HomeMapper.java @@ -92,6 +92,7 @@ private HomeAbilityResDto.AbilityInfo toAbilityInfo(AbilityStat abilityStat) { public HomeSettingResDto toHomeSettingResDto(User user) { return HomeSettingResDto.builder() + .userEmail(user.getEmail()) .accountCode(user.getAccountCode()) .build(); } diff --git a/src/main/java/com/example/egobook_be/domain/terms/entity/Term.java b/src/main/java/com/example/egobook_be/domain/terms/entity/Term.java index 1096fe0..3708edf 100644 --- a/src/main/java/com/example/egobook_be/domain/terms/entity/Term.java +++ b/src/main/java/com/example/egobook_be/domain/terms/entity/Term.java @@ -30,9 +30,7 @@ public class Term extends BaseTimeEntity { @Builder.Default private TermVersion termVersion = TermVersion.V1; - // 대용량 텍스트 저장을 위해 Lob 사용 - @Lob - @Column(name = "context", nullable = false, columnDefinition = "LONGTEXT") + @Column(name = "context", nullable = false) private String context; @Column(name = "required", nullable = false) diff --git a/src/main/java/com/example/egobook_be/domain/terms/enums/TermTemplate.java b/src/main/java/com/example/egobook_be/domain/terms/enums/TermTemplate.java index 0a28fc9..5c8b5c3 100644 --- a/src/main/java/com/example/egobook_be/domain/terms/enums/TermTemplate.java +++ b/src/main/java/com/example/egobook_be/domain/terms/enums/TermTemplate.java @@ -10,26 +10,14 @@ public enum TermTemplate { TERM_OF_SERVICE( TermType.TERM_OF_SERVICE, "서비스 이용 약관", - """ - 서비스 이용 약관 임시 내용 - """, + "https://bevel-beetle-a49.notion.site/2f638a539ac5801aa872e99ec4282f28?source=copy_link", true ), TERM_OF_PRIVACY_POLICY( TermType.TERM_OF_PRIVACY_POLICY, - "개인정보 처리 방침", - """ - 개인정보 처리 방침 임시 내용 - """, + "개인정보 수집 및 이용", + "https://bevel-beetle-a49.notion.site/2f638a539ac58059b9a1c883ad7d7164?source=copy_link", true - ), - TERM_OF_PERSONAL_INFO_CONSENT( - TermType.TERM_OF_PERSONAL_INFO_CONSENT, - "개인정보 이용 동의 약관", - """ - 개인정보 이용 동의 약관 임시 내용 - """, - false ); private final TermType termType;