diff --git a/.github/workflows/cd-dev.yml b/.github/workflows/cd-dev.yml index 8955876c..b9cc04c0 100644 --- a/.github/workflows/cd-dev.yml +++ b/.github/workflows/cd-dev.yml @@ -1,76 +1,76 @@ -name: dev 서버 CD 실행 +# name: dev 서버 CD 실행 -on: - push: - branches: [ "develop" ] +# on: +# push: +# branches: [ "develop" ] -permissions: - contents: read +# permissions: +# contents: read -jobs: - deploy: - runs-on: ubuntu-latest - steps: +# jobs: +# deploy: +# runs-on: ubuntu-latest +# steps: - # repository checkout - - name: Checkout - uses: actions/checkout@v4 +# # repository checkout +# - name: Checkout +# uses: actions/checkout@v4 - # JDK 환경 설치 - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '17' - distribution: 'corretto' +# # JDK 환경 설치 +# - name: Set up JDK 17 +# uses: actions/setup-java@v4 +# with: +# java-version: '17' +# distribution: 'corretto' - # 환경 변수 설정 - - name: application.yml 파일 설정 - run: | - mkdir -p src/main/resources - echo "${{ secrets.APPLICATION_YML_DEV }}" > ./src/main/resources/application.yml +# # 환경 변수 설정 +# - name: application.yml 파일 설정 +# run: | +# mkdir -p src/main/resources +# echo "${{ secrets.APPLICATION_YML_DEV }}" > ./src/main/resources/application.yml - # Gradle 환경 설치 - - name: Setup Gradle - uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 +# # Gradle 환경 설치 +# - name: Setup Gradle +# uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 - # Gradle 권한 변경 - - name: Grant execute permission for gradlew - run: chmod +x gradlew +# # Gradle 권한 변경 +# - name: Grant execute permission for gradlew +# run: chmod +x gradlew - # Build 진행 - - name: Build with Gradle - run: ./gradlew clean build --stacktrace - shell: bash +# # Build 진행 +# - name: Build with Gradle +# run: ./gradlew clean build --stacktrace +# shell: bash - # docker build & push - - name: Docker build & push - run: | - docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} - docker build -t ${{ secrets.DOCKER_USERNAME }}/uble-dev -f ./Dockerfile . - docker push ${{ secrets.DOCKER_USERNAME }}/uble-dev:latest +# # docker build & push +# - name: Docker build & push +# run: | +# docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} +# docker build -t ${{ secrets.DOCKER_USERNAME }}/uble-dev -f ./Dockerfile . +# docker push ${{ secrets.DOCKER_USERNAME }}/uble-dev:latest - # 배포 - - name: EC2 Connect & Deploy - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.SERVER_IP_DEV }} - username: ${{ secrets.SSH_USER }} - key: ${{ secrets.SSH_PRIVATE_KEY }} - script_stop: true - script: | - # 모든 컨테이너 중지 및 제거 (컨테이너가 있는 경우) - sudo docker stop $(docker ps -a -q) || true - sudo docker rm -fv $(docker ps -aq) || true +# # 배포 +# - name: EC2 Connect & Deploy +# uses: appleboy/ssh-action@master +# with: +# host: ${{ secrets.SERVER_IP_DEV }} +# username: ${{ secrets.SSH_USER }} +# key: ${{ secrets.SSH_PRIVATE_KEY }} +# script_stop: true +# script: | +# # 모든 컨테이너 중지 및 제거 (컨테이너가 있는 경우) +# sudo docker stop $(docker ps -a -q) || true +# sudo docker rm -fv $(docker ps -aq) || true - # 이전 이미지 삭제 - sudo docker image rm ${{ secrets.DOCKER_USERNAME }}/uble-dev:latest || true +# # 이전 이미지 삭제 +# sudo docker image rm ${{ secrets.DOCKER_USERNAME }}/uble-dev:latest || true - # 최신 Docker 이미지 pull 받기 - sudo docker pull ${{ secrets.DOCKER_USERNAME }}/uble-dev:latest +# # 최신 Docker 이미지 pull 받기 +# sudo docker pull ${{ secrets.DOCKER_USERNAME }}/uble-dev:latest - # Docker 컨테이너 실행 - sudo docker run -d -p 8080:8080 ${{ secrets.DOCKER_USERNAME }}/uble-dev:latest +# # Docker 컨테이너 실행 +# sudo docker run -d -p 8080:8080 ${{ secrets.DOCKER_USERNAME }}/uble-dev:latest - # 불필요한 Docker 이미지 정리 - sudo docker image prune -f +# # 불필요한 Docker 이미지 정리 +# sudo docker image prune -f diff --git a/README.md b/README.md index 5289947f..bf8b0fa7 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,24 @@ -# UBLE BACK-END +# UBLE BACK-END REPOSITORY ## 프로젝트 소개 -- 프로젝트명 : Uble -- 프로젝트 주제 : LG U+ 멤버십 제휴처 안내 지도 서비스 -- 프로젝트 기간 : 2025.06.30 - 2025.08.08 + +
+ 탐험하는 귀여운 마스코트 +
+ +**🌐 서비스 바로가기** : https://www.u-ble.com + +**📊 관리자 페이지 바로가기** : https://admin.u-ble.com + +**💡 UBLE 이란?** : https://www.u-ble.com/intro + + +
+ +- **프로젝트명** : UBLE +- **프로젝트 주제** : LG U+ 멤버십 제휴처 안내 지도 서비스 +- **프로젝트 기간** : 2025.06.30 - 2025.08.08 + ## 🧑🏻‍💻 팀원 소개
@@ -63,12 +78,13 @@


## 💾 DB -### 1. RDB -ERD_BASIC 1 +📸 ERD : https://www.erdcloud.com/d/C9vcCB4kCHXRWWczR +### 1. PostgreSQL +Uble ERD (2)

-### 2. ES +### 2. Elasticsearch **1) 검색용 INDEX** ERD_SEARCH 1 @@ -82,7 +98,8 @@


## 🛠️ 시스템 아키텍처 -Group 427320386 +Group 427320387 + --- @@ -147,6 +164,18 @@


+## 📚 스터디 + + + +


+ ## ⚖️ 컨벤션 ### **[ PACKAGE STRUCTURE ]** @@ -168,6 +197,7 @@ ├─ 📁 common ├─ 📁 feedback ├─ 📁 pin + ├─ 📁 search ├─ 📁 store └─ 📁 users @@ -282,14 +312,7 @@ Ex. [UBLE-12] fix: 즐겨찾기 DTO 수정 | 스토어 | `5000` | | 북마크 | `6000` | | 피드백 | `7000` | - -


- -## [📚 Github Wiki]() -**STUDY** - +| 핀 | `8000` | +| 공통 | `9000` | --- diff --git a/src/main/java/com/ureca/uble/domain/auth/service/AuthService.java b/src/main/java/com/ureca/uble/domain/auth/service/AuthService.java index e0f25c0a..029c9260 100644 --- a/src/main/java/com/ureca/uble/domain/auth/service/AuthService.java +++ b/src/main/java/com/ureca/uble/domain/auth/service/AuthService.java @@ -19,6 +19,7 @@ import com.ureca.uble.domain.users.repository.UserRepository; import com.ureca.uble.entity.Token; import com.ureca.uble.entity.User; +import com.ureca.uble.entity.enums.Role; import com.ureca.uble.global.exception.GlobalException; import com.ureca.uble.global.security.jwt.JwtProvider; import com.ureca.uble.global.security.jwt.JwtValidator; @@ -70,6 +71,10 @@ public User login(String code, HttpServletResponse response) { jwtProvider.addAccessTokenHeader(response, accessToken); jwtProvider.addRefreshTokenCookie(response, refreshToken); + + if (user.getRole() == Role.TMP_USER){ + jwtProvider.addTmpCheckCookie(response); + } jwtProvider.addAuthCheckCookie(response); return user; diff --git a/src/main/java/com/ureca/uble/domain/users/controller/UserController.java b/src/main/java/com/ureca/uble/domain/users/controller/UserController.java index d70e5d98..83d8c23f 100644 --- a/src/main/java/com/ureca/uble/domain/users/controller/UserController.java +++ b/src/main/java/com/ureca/uble/domain/users/controller/UserController.java @@ -6,6 +6,7 @@ import com.ureca.uble.domain.users.service.UserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -30,11 +31,12 @@ public CommonResponse getUserInfo( @Operation(summary = "사용자 정보 최초 입력 & 수정", description = "사용자 정보를 수정합니다.") @PutMapping("/userInfo") public CommonResponseupdateUserInfo( + HttpServletResponse response, @Parameter(description = "사용자정보", required = true) @AuthenticationPrincipal Long userId, @Valid @RequestBody UpdateUserInfoReq request ){ - return CommonResponse.success(userService.updateUserInfo(userId, request)); + return CommonResponse.success(userService.updateUserInfo(response, userId, request)); } @Operation(summary = "제휴처 매장 추천 정보 조회", description = "사용자에게 맞는 제휴처 매장 추천 정보를 조회합니다.") diff --git a/src/main/java/com/ureca/uble/domain/users/service/UserService.java b/src/main/java/com/ureca/uble/domain/users/service/UserService.java index 95b366f0..47ef94d4 100644 --- a/src/main/java/com/ureca/uble/domain/users/service/UserService.java +++ b/src/main/java/com/ureca/uble/domain/users/service/UserService.java @@ -16,6 +16,9 @@ import com.ureca.uble.entity.UserCategory; import com.ureca.uble.entity.document.UsageHistoryDocument; import com.ureca.uble.global.exception.GlobalException; +import com.ureca.uble.global.security.jwt.JwtProvider; + +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.slf4j.MDC; import org.springframework.data.elasticsearch.client.elc.ElasticsearchAggregations; @@ -43,6 +46,7 @@ public class UserService { private final UsageHistoryDocumentRepository usageHistoryDocumentRepository; private final BrandRepository brandRepository; private final BookmarkRepository bookmarkRepository; + private final JwtProvider jwtProvider; /** * 사용자 정보 조회 @@ -62,7 +66,7 @@ public GetUserInfoRes getUserInfo(Long userId) { * 사용자 정보 갱신 */ @Transactional - public UpdateUserInfoRes updateUserInfo(Long userId, UpdateUserInfoReq request) { + public UpdateUserInfoRes updateUserInfo(HttpServletResponse response, Long userId, UpdateUserInfoReq request) { User user = findUser(userId); user.updateUserInfo( @@ -80,6 +84,8 @@ public UpdateUserInfoRes updateUserInfo(Long userId, UpdateUserInfoReq request) userCategoryRepository.save(userCategory); }); + jwtProvider.deleteTmpCheckCookie(response); + return UpdateUserInfoRes.of(user, request.getCategoryIds()); } diff --git a/src/main/java/com/ureca/uble/global/security/jwt/JwtProvider.java b/src/main/java/com/ureca/uble/global/security/jwt/JwtProvider.java index dd080118..20d58acf 100644 --- a/src/main/java/com/ureca/uble/global/security/jwt/JwtProvider.java +++ b/src/main/java/com/ureca/uble/global/security/jwt/JwtProvider.java @@ -88,6 +88,19 @@ public void addAuthCheckCookie(HttpServletResponse response) { response.addHeader("Set-Cookie", cookie.toString()); } + public void addTmpCheckCookie(HttpServletResponse response) { + ResponseCookie cookie = ResponseCookie.from("TmpCheck", "true") + .path("/") + .httpOnly(false) + .secure(isSecure) + .maxAge(REFRESH_TOKEN_VALIDITY_MILLIS / 1000) + .sameSite(sameSite) + .domain(cookieDomain.isBlank() ? null : cookieDomain) + .build(); + + response.addHeader("Set-Cookie", cookie.toString()); + } + public void deleteRefreshTokenCookie(HttpServletResponse response){ ResponseCookie cookie = ResponseCookie.from("refreshToken", "") .path("/") @@ -114,6 +127,21 @@ public void deleteAuthCheckCookie(HttpServletResponse response){ response.addHeader("Set-Cookie", cookie.toString()); } + public void deleteTmpCheckCookie(HttpServletResponse response){ + ResponseCookie cookie = ResponseCookie.from("TmpCheck", "") + .path("/") + .httpOnly(false) + .secure(isSecure) + .maxAge(0) + .sameSite(sameSite) + .domain(cookieDomain.isBlank() ? null : cookieDomain) + .build(); + + response.addHeader("Set-Cookie", cookie.toString()); + } + + + public LocalDateTime getRefreshTokenExpiry(String token){ Claims claims = Jwts.parser() .verifyWith(Keys.hmacShaKeyFor(secret.getBytes())) diff --git a/src/test/java/com/ureca/uble/domain/users/service/UserServiceTest.java b/src/test/java/com/ureca/uble/domain/users/service/UserServiceTest.java index dfc56b68..9f743efe 100644 --- a/src/test/java/com/ureca/uble/domain/users/service/UserServiceTest.java +++ b/src/test/java/com/ureca/uble/domain/users/service/UserServiceTest.java @@ -28,6 +28,9 @@ import com.ureca.uble.entity.enums.Gender; import com.ureca.uble.entity.enums.Rank; import com.ureca.uble.global.exception.GlobalException; +import com.ureca.uble.global.security.jwt.JwtProvider; + +import jakarta.servlet.http.HttpServletResponse; @ExtendWith(MockitoExtension.class) public class UserServiceTest { @@ -44,6 +47,12 @@ public class UserServiceTest { @InjectMocks private UserService userService; + @Mock + private HttpServletResponse response; + + @Mock + private JwtProvider jwtProvider; + @Test @DisplayName("사용자 ID로 사용자 정보를 조회한다.") void getUserInfoSuccess(){ @@ -105,9 +114,10 @@ void updateUserInfoSuccess(){ when(categoryRepository.findAllById(categoryIds)).thenReturn(List.of(cat1, cat2)); //when - UpdateUserInfoRes result = userService.updateUserInfo(userId, request); + UpdateUserInfoRes result = userService.updateUserInfo(response, userId, request); //then + verify(jwtProvider).deleteTmpCheckCookie(response); verify(user).updateUserInfo(Rank.VIP, Gender.FEMALE, LocalDate.of(1999, 1, 1), "123456787654321"); verify(userCategoryRepository).deleteByUser(user); verify(userCategoryRepository, times(2)).save(any(UserCategory.class)); @@ -126,7 +136,7 @@ void updateUserInfo_userNotFound(){ //when, then GlobalException ex = assertThrows(GlobalException.class, () -> - userService.updateUserInfo(123L, req) + userService.updateUserInfo(response,123L, req) ); assertThat(ex.getResultCode()).isEqualTo(UserErrorCode.USER_NOT_FOUND); }