From 4808e87853e33308a04c30a40dd3a364ada3c25f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=ED=9D=AC=EC=A7=84?= Date: Mon, 18 Aug 2025 15:50:25 +0900 Subject: [PATCH 1/8] =?UTF-8?q?[refactor]=20=EC=95=88=EC=93=B0=EB=8A=94=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C=20(#1?= =?UTF-8?q?62)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/konkuk/thip/common/exception/code/ErrorCode.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/konkuk/thip/common/exception/code/ErrorCode.java b/src/main/java/konkuk/thip/common/exception/code/ErrorCode.java index 0c4d9577b..ef76ea025 100644 --- a/src/main/java/konkuk/thip/common/exception/code/ErrorCode.java +++ b/src/main/java/konkuk/thip/common/exception/code/ErrorCode.java @@ -156,7 +156,6 @@ public enum ErrorCode implements ResponseCode { TAG_NOT_FOUND(HttpStatus.NOT_FOUND, 160002, "존재하지 않는 TAG 입니다."), INVALID_FEED_COMMAND(HttpStatus.BAD_REQUEST, 160003, "유효하지 않은 FEED 생성/수정 요청 입니다."), FEED_ACCESS_FORBIDDEN(HttpStatus.FORBIDDEN, 160004, "피드 접근 권한이 없습니다."), - DUPLICATED_FEEDS_IN_COLLECTION(HttpStatus.INTERNAL_SERVER_ERROR, 160005, "중복된 피드가 존재합니다."), FEED_ALREADY_SAVED(HttpStatus.BAD_REQUEST, 160006, "사용자가 이미 저장한 피드입니다."), FEED_NOT_SAVED_CANNOT_DELETE(HttpStatus.BAD_REQUEST, 160007, "사용자가 저장하지 않은 피드는 저장삭제 할 수 없습니다."), FEED_CAN_NOT_SHOW_PRIVATE_ONE(HttpStatus.BAD_REQUEST, 160008, "비공개 피드는 피드 작성자 이외에는 조회할 수 없습니다."), From 84f63112131a12e7aae1c397decac23c6194229c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=ED=9D=AC=EC=A7=84?= Date: Mon, 18 Aug 2025 15:50:51 +0900 Subject: [PATCH 2/8] [refactor] FeedQueryPersistenceAdapter.existsSavedFeedByUserIdAndFeedId (#162) --- .../FeedQueryPersistenceAdapter.java | 47 ++----------------- 1 file changed, 4 insertions(+), 43 deletions(-) diff --git a/src/main/java/konkuk/thip/feed/adapter/out/persistence/FeedQueryPersistenceAdapter.java b/src/main/java/konkuk/thip/feed/adapter/out/persistence/FeedQueryPersistenceAdapter.java index 1f39070ce..ea880cef8 100644 --- a/src/main/java/konkuk/thip/feed/adapter/out/persistence/FeedQueryPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/feed/adapter/out/persistence/FeedQueryPersistenceAdapter.java @@ -1,34 +1,22 @@ package konkuk.thip.feed.adapter.out.persistence; import konkuk.thip.common.entity.StatusType; -import konkuk.thip.common.exception.EntityNotFoundException; import konkuk.thip.common.util.Cursor; import konkuk.thip.common.util.CursorBasedList; -import konkuk.thip.feed.adapter.out.jpa.FeedJpaEntity; -import konkuk.thip.feed.adapter.out.jpa.SavedFeedJpaEntity; -import konkuk.thip.feed.adapter.out.jpa.TagJpaEntity; import konkuk.thip.feed.adapter.out.mapper.FeedMapper; import konkuk.thip.feed.adapter.out.persistence.repository.FeedJpaRepository; import konkuk.thip.feed.adapter.out.persistence.repository.FeedTag.FeedTagJpaRepository; import konkuk.thip.feed.adapter.out.persistence.repository.SavedFeedJpaRepository; import konkuk.thip.feed.application.port.out.FeedQueryPort; import konkuk.thip.feed.application.port.out.dto.TagCategoryQueryDto; -import konkuk.thip.feed.application.port.out.dto.FeedIdAndTagProjection; import konkuk.thip.feed.application.port.out.dto.FeedQueryDto; -import konkuk.thip.feed.domain.Feed; -import konkuk.thip.feed.domain.SavedFeeds; -import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; import java.time.LocalDateTime; import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; - -import static konkuk.thip.common.exception.code.ErrorCode.USER_NOT_FOUND; @Repository @RequiredArgsConstructor @@ -112,40 +100,13 @@ public int countPublicFeedsByUserId(Long userId) { } @Override - public SavedFeeds findSavedFeedsByUserId(Long userId) { - UserJpaEntity user = userJpaRepository.findById(userId) - .orElseThrow(() -> new EntityNotFoundException(USER_NOT_FOUND)); - - List savedFeedEntities = - savedFeedJpaRepository.findAllByUserId(user.getUserId()); - - List feedIds = savedFeedEntities.stream() - .map(entity -> entity.getFeedJpaEntity().getPostId()) - .toList(); - - // Projection 기반 조회 - List results = feedTagJpaRepository.findFeedIdAndTagsByFeedIds(feedIds); - - Map> feedTagsMap = results.stream() - .collect(Collectors.groupingBy( - FeedIdAndTagProjection::getFeedId, - Collectors.mapping(FeedIdAndTagProjection::getTagJpaEntity, Collectors.toList()) - )); - - List feeds = savedFeedEntities.stream() - .map(entity -> { - FeedJpaEntity feedJpa = entity.getFeedJpaEntity(); - List tags = feedTagsMap.getOrDefault(feedJpa.getPostId(), List.of()); - return feedMapper.toDomainEntity(feedJpa, tags); - }) - .toList(); - - return new SavedFeeds(feeds); + public Set findSavedFeedIdsByUserIdAndFeedIds(Set feedIds, Long userId) { + return savedFeedJpaRepository.findSavedFeedIdsByUserIdAndFeedIds(userId, feedIds); } @Override - public Set findSavedFeedIdsByUserIdAndFeedIds(Set feedIds, Long userId) { - return savedFeedJpaRepository.findSavedFeedIdsByUserIdAndFeedIds(userId, feedIds); + public boolean existsSavedFeedByUserIdAndFeedId(Long userId, Long feedId) { + return savedFeedJpaRepository.existsByUserIdAndFeedId(userId, feedId); } @Override From 03b42493d6074611b9e0e93a7883c073098fc1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=ED=9D=AC=EC=A7=84?= Date: Mon, 18 Aug 2025 15:51:00 +0900 Subject: [PATCH 3/8] [refactor] FeedQueryPort.existsSavedFeedByUserIdAndFeedId (#162) --- .../thip/feed/application/port/out/FeedQueryPort.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/konkuk/thip/feed/application/port/out/FeedQueryPort.java b/src/main/java/konkuk/thip/feed/application/port/out/FeedQueryPort.java index aa71dc8b8..b4d7a903d 100644 --- a/src/main/java/konkuk/thip/feed/application/port/out/FeedQueryPort.java +++ b/src/main/java/konkuk/thip/feed/application/port/out/FeedQueryPort.java @@ -4,7 +4,6 @@ import konkuk.thip.common.util.CursorBasedList; import konkuk.thip.feed.application.port.out.dto.TagCategoryQueryDto; import konkuk.thip.feed.application.port.out.dto.FeedQueryDto; -import konkuk.thip.feed.domain.SavedFeeds; import java.util.List; import java.util.Set; @@ -36,11 +35,10 @@ public interface FeedQueryPort { /** * 저장된 피드 조회 */ - SavedFeeds findSavedFeedsByUserId(Long userId); Set findSavedFeedIdsByUserIdAndFeedIds(Set feedIds, Long userId); - List findAllTags(); + boolean existsSavedFeedByUserIdAndFeedId(Long userId, Long feedId); /** * 특정 책으로 작성된 피드 조회 @@ -50,4 +48,9 @@ public interface FeedQueryPort { CursorBasedList findFeedsByBookIsbnOrderByLatest(String isbn, Long userId, Cursor cursor); List findLatestPublicFeedCreatorsIn(Set userIds, int size); + + /** + * 모든 태그 조회 + */ + List findAllTags(); } From c4bde1930d6e795864228f3f696514b2589c2f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=ED=9D=AC=EC=A7=84?= Date: Mon, 18 Aug 2025 15:51:22 +0900 Subject: [PATCH 4/8] =?UTF-8?q?[refactor]=20FeedSavedService=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=A0=80=EC=9E=A5=EC=97=AC=EB=B6=80=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95=20=20(#162)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/service/FeedSavedService.java | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/main/java/konkuk/thip/feed/application/service/FeedSavedService.java b/src/main/java/konkuk/thip/feed/application/service/FeedSavedService.java index 80116c054..0169faa54 100644 --- a/src/main/java/konkuk/thip/feed/application/service/FeedSavedService.java +++ b/src/main/java/konkuk/thip/feed/application/service/FeedSavedService.java @@ -1,16 +1,18 @@ package konkuk.thip.feed.application.service; +import konkuk.thip.common.exception.BusinessException; import konkuk.thip.feed.application.port.in.FeedSavedUseCase; import konkuk.thip.feed.application.port.in.dto.FeedIsSavedCommand; import konkuk.thip.feed.application.port.in.dto.FeedIsSavedResult; import konkuk.thip.feed.application.port.out.FeedCommandPort; import konkuk.thip.feed.application.port.out.FeedQueryPort; import konkuk.thip.feed.domain.Feed; -import konkuk.thip.feed.domain.SavedFeeds; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import static konkuk.thip.common.exception.code.ErrorCode.*; + @Service @RequiredArgsConstructor public class FeedSavedService implements FeedSavedUseCase { @@ -20,24 +22,31 @@ public class FeedSavedService implements FeedSavedUseCase { @Override @Transactional - public FeedIsSavedResult changeSavedFeed(FeedIsSavedCommand feedIsSavedCommand) { + public FeedIsSavedResult changeSavedFeed(FeedIsSavedCommand command) { // 1. 피드 검증 및 조회 - Feed feed = feedCommandPort.getByIdOrThrow(feedIsSavedCommand.feedId()); + Feed feed = feedCommandPort.getByIdOrThrow(command.feedId()); - // 2. 유저가 저장한 피드 목록 조회 - SavedFeeds savedFeeds = feedQueryPort.findSavedFeedsByUserId(feedIsSavedCommand.userId()); + // 2. 유저가 해당 피드를 저장했는지 여부 조회 + boolean alreadySaved = feedQueryPort.existsSavedFeedByUserIdAndFeedId(command.userId(), feed.getId()); + validateSaveFeedAction(command.isSaved(), alreadySaved); - if (feedIsSavedCommand.isSaved()) { - // 저장 요청 시 이미 저장되어 있으면 예외 발생 - savedFeeds.validateNotAlreadySaved(feed); - feedCommandPort.saveSavedFeed(feedIsSavedCommand.userId(), feed.getId()); + if (command.isSaved()) { + feedCommandPort.saveSavedFeed(command.userId(), feed.getId()); } else { - // 삭제 요청 시 저장되어 있지 않으면 예외 발생 - savedFeeds.validateCanDelete(feed); - feedCommandPort.deleteSavedFeed(feedIsSavedCommand.userId(), feed.getId()); + feedCommandPort.deleteSavedFeed(command.userId(), feed.getId()); } - return FeedIsSavedResult.of(feed.getId(), feedIsSavedCommand.isSaved()); + return FeedIsSavedResult.of(feed.getId(), command.isSaved()); + } + + private void validateSaveFeedAction(boolean isSaveRequest, boolean alreadySaved) { + if (isSaveRequest && alreadySaved) { + // 이미 저장되어 있는 피드를 다시 저장하려는 경우 예외 처리 + throw new BusinessException(FEED_ALREADY_SAVED); + } else if (!isSaveRequest && !alreadySaved) { + // 저장되지 않은 피드를 삭제하려는 경우 예외 처리 + throw new BusinessException(FEED_NOT_SAVED_CANNOT_DELETE); + } } } From c349c2dd57165c125e0da205e0ccfeb85f02e45d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=ED=9D=AC=EC=A7=84?= Date: Mon, 18 Aug 2025 15:51:37 +0900 Subject: [PATCH 5/8] [refactor] SavedFeedJpaRepository.existsByUserIdAndFeedId (#162) --- .../out/persistence/repository/SavedFeedJpaRepository.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/SavedFeedJpaRepository.java b/src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/SavedFeedJpaRepository.java index 9e4824066..d4b399f22 100644 --- a/src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/SavedFeedJpaRepository.java +++ b/src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/SavedFeedJpaRepository.java @@ -24,4 +24,8 @@ public interface SavedFeedJpaRepository extends JpaRepository 0 THEN true ELSE false END FROM SavedFeedJpaEntity s " + + "WHERE s.userJpaEntity.userId = :userId AND s.feedJpaEntity.postId = :feedId") + boolean existsByUserIdAndFeedId(Long userId, Long feedId); } From d11416c52ecb3656ff54140c90ab92357e8443c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=ED=9D=AC=EC=A7=84?= Date: Mon, 18 Aug 2025 15:51:50 +0900 Subject: [PATCH 6/8] =?UTF-8?q?[refactor]=20=EC=9D=BC=EA=B8=89=EC=BB=AC?= =?UTF-8?q?=EB=A0=89=EC=85=98=EC=82=AD=EC=A0=9C=20=20(#162)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../konkuk/thip/feed/domain/SavedFeeds.java | 42 ------------------- 1 file changed, 42 deletions(-) delete mode 100644 src/main/java/konkuk/thip/feed/domain/SavedFeeds.java diff --git a/src/main/java/konkuk/thip/feed/domain/SavedFeeds.java b/src/main/java/konkuk/thip/feed/domain/SavedFeeds.java deleted file mode 100644 index e5c739477..000000000 --- a/src/main/java/konkuk/thip/feed/domain/SavedFeeds.java +++ /dev/null @@ -1,42 +0,0 @@ -package konkuk.thip.feed.domain; - -import konkuk.thip.common.exception.InvalidStateException; -import lombok.Getter; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static konkuk.thip.common.exception.code.ErrorCode.*; - -@Getter -public class SavedFeeds { - - private final Set feeds; - - public SavedFeeds(List feeds) { - Set feedSet = new HashSet<>(feeds); - if (feedSet.size() != feeds.size()) { - throw new InvalidStateException(DUPLICATED_FEEDS_IN_COLLECTION); - } - this.feeds = Collections.unmodifiableSet(feedSet); - } - - // 중복 저장 검증 - public void validateNotAlreadySaved(Feed feed) { - if (feeds.contains(feed)) { - throw new InvalidStateException(FEED_ALREADY_SAVED); - } - } - - // 삭제 가능 여부 검증 - public void validateCanDelete(Feed feed) { - if (!feeds.contains(feed)) { - throw new InvalidStateException(FEED_NOT_SAVED_CANNOT_DELETE); - } - } - -} - - From 5199172553e1cb4d2f243cf4c9208ae7548937fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=ED=9D=AC=EC=A7=84?= Date: Mon, 18 Aug 2025 20:05:48 +0900 Subject: [PATCH 7/8] =?UTF-8?q?[refactor]=20=EB=9F=B0=ED=83=80=EC=9E=84=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EB=B0=94=EC=9D=B8?= =?UTF-8?q?=EB=94=A9=20=EC=8B=A4=ED=8C=A8=20=EB=B0=A9=EC=A7=80=20(#162)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../out/persistence/repository/SavedBookJpaRepository.java | 3 ++- .../out/persistence/repository/SavedFeedJpaRepository.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/konkuk/thip/book/adapter/out/persistence/repository/SavedBookJpaRepository.java b/src/main/java/konkuk/thip/book/adapter/out/persistence/repository/SavedBookJpaRepository.java index 234b9bfd4..6038ecc7d 100644 --- a/src/main/java/konkuk/thip/book/adapter/out/persistence/repository/SavedBookJpaRepository.java +++ b/src/main/java/konkuk/thip/book/adapter/out/persistence/repository/SavedBookJpaRepository.java @@ -4,11 +4,12 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface SavedBookJpaRepository extends JpaRepository { @Query("SELECT CASE WHEN COUNT(s) > 0 THEN true ELSE false END FROM SavedBookJpaEntity s " + "WHERE s.userJpaEntity.userId = :userId AND s.bookJpaEntity.bookId = :bookId") - boolean existsByUserIdAndBookId(Long userId, Long bookId); + boolean existsByUserIdAndBookId(@Param("userId") Long userId, @Param("bookId") Long bookId); @Modifying(clearAutomatically = true, flushAutomatically = true) @Query("DELETE FROM SavedBookJpaEntity s WHERE s.userJpaEntity.userId = :userId AND s.bookJpaEntity.bookId = :bookId") diff --git a/src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/SavedFeedJpaRepository.java b/src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/SavedFeedJpaRepository.java index d4b399f22..c10a53f7d 100644 --- a/src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/SavedFeedJpaRepository.java +++ b/src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/SavedFeedJpaRepository.java @@ -27,5 +27,5 @@ public interface SavedFeedJpaRepository extends JpaRepository 0 THEN true ELSE false END FROM SavedFeedJpaEntity s " + "WHERE s.userJpaEntity.userId = :userId AND s.feedJpaEntity.postId = :feedId") - boolean existsByUserIdAndFeedId(Long userId, Long feedId); + boolean existsByUserIdAndFeedId(@Param("userId") Long userId, @Param("feedId") Long feedId); } From 0ac4b6d935be2be020d6a0a4c00e478038f18486 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Mon, 18 Aug 2025 22:15:18 +0900 Subject: [PATCH 8/8] =?UTF-8?q?[fix]=20server=20=EC=BB=A8=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EB=84=88=EB=A7=8C=20=EB=82=B4=EB=A6=AC=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95=20(#162)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd-workflow-dev.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cd-workflow-dev.yml b/.github/workflows/cd-workflow-dev.yml index 5a04c00db..dfbaccd1a 100644 --- a/.github/workflows/cd-workflow-dev.yml +++ b/.github/workflows/cd-workflow-dev.yml @@ -68,7 +68,9 @@ jobs: cd ${{ env.COMPOSE_PATH }} echo "✋🏻Stopping existing container and Cleaning up old images" - sudo docker-compose down --rmi all +# sudo docker-compose down --rmi all + sudo docker-compose stop ${{ secrets.DOCKER_IMAGE }} + sudo docker rm -f ${{ secrets.DOCKER_IMAGE }} sudo docker ps -a