diff --git a/nect-api/src/main/java/com/nect/api/domain/team/workspace/service/PostService.java b/nect-api/src/main/java/com/nect/api/domain/team/workspace/service/PostService.java index 89980a67..77dfdca5 100644 --- a/nect-api/src/main/java/com/nect/api/domain/team/workspace/service/PostService.java +++ b/nect-api/src/main/java/com/nect/api/domain/team/workspace/service/PostService.java @@ -275,34 +275,57 @@ public PostListResDto getPostList(Long projectId, Long userId, PostType type, in return new PostListResDto(mapped, pageInfo); } + // FREE만 조회 요청일 때는 FREE만 페이징 (DB Pageable 사용 금지) + if (type == PostType.FREE) { + List freePosts = postRepository.findFreePosts(projectId, baseSort); + return paginatePosts(sortPosts(freePosts), page, fixedSize); + } - // FREE만 페이지네이션 - Pageable pageable = PageRequest.of(page, fixedSize, baseSort); - Page freePage = postRepository.findFreePosts(projectId, pageable); + // 공지 + FREE 전체를 합쳐서 페이징 (type == null) + List notices = postRepository.findAllNotices(projectId, baseSort); + List freePosts = postRepository.findFreePosts(projectId, baseSort); - List result = new java.util.ArrayList<>(); + List combined = new ArrayList<>(notices.size() + freePosts.size()); + combined.addAll(sortPosts(notices)); + combined.addAll(sortPosts(freePosts)); - // page==0 일 때만 공지 전부 상단에 붙이기 - List notices = postRepository.findAllNotices(projectId, baseSort); - if (type == null && page == 0) { - result.addAll(notices.stream().map(this::toSummary).toList()); - } + return paginatePosts(combined, page, fixedSize); + } - // FREE 페이징 결과 붙이기 - result.addAll(freePage.getContent().stream().map(this::toSummary).toList()); + private PostListResDto paginatePosts(List posts, int page, int size) { + int totalElements = posts.size(); + int totalPages = totalElements == 0 ? 0 : (int) Math.ceil((double) totalElements / size); + int start = page * size; + int end = Math.min(start + size, totalElements); + boolean hasNext = end < totalElements; + + List result = (start >= totalElements) + ? List.of() + : posts.subList(start, end).stream() + .map(this::toSummary) + .toList(); - // pageInfo는 FREE 기준으로만 계산 (공지는 제외) PostListResDto.PageInfo pageInfo = new PostListResDto.PageInfo( - freePage.getNumber(), - freePage.getSize(), - freePage.getTotalElements() + + notices.size(), - freePage.getTotalPages(), - freePage.hasNext() + page, + size, + totalElements, + totalPages, + hasNext ); return new PostListResDto(result, pageInfo); } + private List sortPosts(List posts) { + return posts.stream() + .sorted((a, b) -> { + int cmp = b.getCreatedAt().compareTo(a.getCreatedAt()); + if (cmp != 0) return cmp; + return b.getId().compareTo(a.getId()); + }) + .toList(); + } + private PostListResDto.PostSummaryDto toSummary(Post p) { var u = p.getAuthor(); PostListResDto.AuthorDto authorDto = (u == null) diff --git a/nect-core/src/main/java/com/nect/core/repository/team/workspace/PostRepository.java b/nect-core/src/main/java/com/nect/core/repository/team/workspace/PostRepository.java index 3353970a..9c7fb7b8 100644 --- a/nect-core/src/main/java/com/nect/core/repository/team/workspace/PostRepository.java +++ b/nect-core/src/main/java/com/nect/core/repository/team/workspace/PostRepository.java @@ -33,6 +33,14 @@ public interface PostRepository extends JpaRepository { """) Page findFreePosts(@Param("projectId") Long projectId, Pageable pageable); + @Query(""" + select p from Post p + where p.project.id = :projectId + and p.deletedAt is null + and p.postType <> com.nect.core.entity.team.workspace.enums.PostType.NOTICE + """) + List findFreePosts(@Param("projectId") Long projectId, Sort sort); + @Query(""" select p from Post p where p.project.id = :projectId