From 38cc01ccaa19b1e1d9b7a1c47d0254e5ca3890ac Mon Sep 17 00:00:00 2001 From: yaaan7 Date: Tue, 16 Jun 2026 16:31:05 +0900 Subject: [PATCH 01/10] =?UTF-8?q?fix:=20ALL,HOT,HOME,=20FESTIVAL=20?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=B6=95=EC=A0=9C=20=EA=B8=B0=EA=B0=84?= =?UTF-8?q?=EC=9D=84=20=EA=B3=A0=EB=A0=A4=ED=95=98=EC=97=AC=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/CommunityRepository.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/main/java/issueissyu/backend/domain/community/repository/CommunityRepository.java b/src/main/java/issueissyu/backend/domain/community/repository/CommunityRepository.java index a7cd180..bfbb112 100644 --- a/src/main/java/issueissyu/backend/domain/community/repository/CommunityRepository.java +++ b/src/main/java/issueissyu/backend/domain/community/repository/CommunityRepository.java @@ -47,6 +47,15 @@ public interface CommunityRepository extends JpaRepository { join fetch c.pin p join fetch p.user where c.communityType = :type + and ( + :type <> issueissyu.backend.domain.community.enums.CommunityType.FESTIVAL + or exists ( + select 1 + from EventPin ep + where ep.pin = p + and CURRENT_TIMESTAMP between ep.eventStartTime and ep.eventEndTime + ) + ) and exists ( select 1 from PinLocation pl @@ -80,6 +89,18 @@ List findFeedByTypeAndRegion( join fetch c.pin p join fetch p.user where c.communityType in :types + and ( + c.communityType not in ( + issueissyu.backend.domain.community.enums.CommunityType.STORE, + issueissyu.backend.domain.community.enums.CommunityType.FESTIVAL + ) + or exists ( + select 1 + from EventPin ep + where ep.pin = p + and CURRENT_TIMESTAMP between ep.eventStartTime and ep.eventEndTime + ) + ) and exists ( select 1 from PinLocation pl @@ -175,6 +196,18 @@ List findCardnewsFeedByTypesWithImages( where ( ( c.communityType in :regionTypes + and ( + c.communityType not in ( + issueissyu.backend.domain.community.enums.CommunityType.STORE, + issueissyu.backend.domain.community.enums.CommunityType.FESTIVAL + ) + or exists ( + select 1 + from EventPin ep + where ep.pin = p + and CURRENT_TIMESTAMP between ep.eventStartTime and ep.eventEndTime + ) + ) and exists ( select 1 from PinLocation pl @@ -221,6 +254,18 @@ List findFeedByRegionOrGlobalTypes( where ( ( c.communityType in :regionTypes + and ( + c.communityType not in ( + issueissyu.backend.domain.community.enums.CommunityType.STORE, + issueissyu.backend.domain.community.enums.CommunityType.FESTIVAL + ) + or exists ( + select 1 + from EventPin ep + where ep.pin = p + and CURRENT_TIMESTAMP between ep.eventStartTime and ep.eventEndTime + ) + ) and exists ( select 1 from PinLocation pl From c8b69904479e2857b199af932c377cffee6620ec Mon Sep 17 00:00:00 2001 From: yaaan7 Date: Tue, 16 Jun 2026 16:43:39 +0900 Subject: [PATCH 02/10] =?UTF-8?q?fix:=20STORE=20=EB=8F=84=20=EA=B8=B0?= =?UTF-8?q?=EA=B0=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/community/repository/CommunityRepository.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/issueissyu/backend/domain/community/repository/CommunityRepository.java b/src/main/java/issueissyu/backend/domain/community/repository/CommunityRepository.java index bfbb112..ca97f94 100644 --- a/src/main/java/issueissyu/backend/domain/community/repository/CommunityRepository.java +++ b/src/main/java/issueissyu/backend/domain/community/repository/CommunityRepository.java @@ -48,7 +48,10 @@ public interface CommunityRepository extends JpaRepository { join fetch p.user where c.communityType = :type and ( - :type <> issueissyu.backend.domain.community.enums.CommunityType.FESTIVAL + :type not in ( + issueissyu.backend.domain.community.enums.CommunityType.STORE, + issueissyu.backend.domain.community.enums.CommunityType.FESTIVAL + ) or exists ( select 1 from EventPin ep From 9860560f54f5a26bc1a00988b6c10176b26d88ca Mon Sep 17 00:00:00 2001 From: yaaan7 Date: Tue, 16 Jun 2026 17:01:30 +0900 Subject: [PATCH 03/10] =?UTF-8?q?fix:=20now()=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../community/repository/CommunityRepository.java | 12 ++++++++---- .../query/CommunityHotQueryServiceImpl.java | 2 ++ .../service/query/CommunityQueryServiceImpl.java | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/main/java/issueissyu/backend/domain/community/repository/CommunityRepository.java b/src/main/java/issueissyu/backend/domain/community/repository/CommunityRepository.java index ca97f94..28e5fb5 100644 --- a/src/main/java/issueissyu/backend/domain/community/repository/CommunityRepository.java +++ b/src/main/java/issueissyu/backend/domain/community/repository/CommunityRepository.java @@ -56,7 +56,7 @@ or exists ( select 1 from EventPin ep where ep.pin = p - and CURRENT_TIMESTAMP between ep.eventStartTime and ep.eventEndTime + and :now between ep.eventStartTime and ep.eventEndTime ) ) and exists ( @@ -74,6 +74,7 @@ and exists ( """) List findFeedByTypeAndRegion( @Param("type") CommunityType type, + @Param("now") LocalDateTime now, @Param("locationId") Long locationId, @Param("cursorCreatedAt") LocalDateTime cursorCreatedAt, @Param("cursorId") Long cursorId, @@ -101,7 +102,7 @@ or exists ( select 1 from EventPin ep where ep.pin = p - and CURRENT_TIMESTAMP between ep.eventStartTime and ep.eventEndTime + and :now between ep.eventStartTime and ep.eventEndTime ) ) and exists ( @@ -119,6 +120,7 @@ and exists ( """) List findFeedByTypesAndRegion( @Param("types") Collection types, + @Param("now") LocalDateTime now, @Param("locationId") Long locationId, @Param("cursorCreatedAt") LocalDateTime cursorCreatedAt, @Param("cursorId") Long cursorId, @@ -208,7 +210,7 @@ or exists ( select 1 from EventPin ep where ep.pin = p - and CURRENT_TIMESTAMP between ep.eventStartTime and ep.eventEndTime + and :now between ep.eventStartTime and ep.eventEndTime ) ) and exists ( @@ -230,6 +232,7 @@ and exists ( List findFeedByRegionOrGlobalTypes( @Param("regionTypes") Collection regionTypes, @Param("globalTypes") Collection globalTypes, + @Param("now") LocalDateTime now, @Param("locationId") Long locationId, @Param("cursorCreatedAt") LocalDateTime cursorCreatedAt, @Param("cursorId") Long cursorId, @@ -266,7 +269,7 @@ or exists ( select 1 from EventPin ep where ep.pin = p - and CURRENT_TIMESTAMP between ep.eventStartTime and ep.eventEndTime + and :now between ep.eventStartTime and ep.eventEndTime ) ) and exists ( @@ -289,6 +292,7 @@ and exists ( List findHotFeedByRegionOrGlobalTypes( @Param("regionTypes") Collection regionTypes, @Param("globalTypes") Collection globalTypes, + @Param("now") LocalDateTime now, @Param("locationId") Long locationId, @Param("since") LocalDateTime since, @Param("cursorPopularity") Double cursorPopularity, diff --git a/src/main/java/issueissyu/backend/domain/community/service/query/CommunityHotQueryServiceImpl.java b/src/main/java/issueissyu/backend/domain/community/service/query/CommunityHotQueryServiceImpl.java index cdb1588..bdd4d6f 100644 --- a/src/main/java/issueissyu/backend/domain/community/service/query/CommunityHotQueryServiceImpl.java +++ b/src/main/java/issueissyu/backend/domain/community/service/query/CommunityHotQueryServiceImpl.java @@ -34,12 +34,14 @@ public class CommunityHotQueryServiceImpl implements CommunityHotQueryService { @Override public Optional findTopHotInRegion(Long locationId) { + LocalDateTime now = LocalDateTime.now(); LocalDateTime since = LocalDateTime.now().minusDays(HOT_DAYS); Pageable limit = PageRequest.of(0, 1); List communities = communityRepository.findHotFeedByRegionOrGlobalTypes( REGION_BASED_FEED_TYPES, GLOBAL_FEED_TYPES, + now, locationId, since, null, diff --git a/src/main/java/issueissyu/backend/domain/community/service/query/CommunityQueryServiceImpl.java b/src/main/java/issueissyu/backend/domain/community/service/query/CommunityQueryServiceImpl.java index b15fe1c..3a9b93d 100644 --- a/src/main/java/issueissyu/backend/domain/community/service/query/CommunityQueryServiceImpl.java +++ b/src/main/java/issueissyu/backend/domain/community/service/query/CommunityQueryServiceImpl.java @@ -249,10 +249,12 @@ public CommunityQueryService.CommunityDetailResult getCommunityDetail( private List fetchCommunities(CommunityTab tab, Long locationId, CursorKey cursorKey) { Pageable limit = PageRequest.of(0, sizeWithLookahead(cursorKey.requestSize())); + LocalDateTime now = LocalDateTime.now(); return switch (tab) { case ISSUE -> communityRepository.findFeedByTypeAndRegion( CommunityType.ISSUE, + now, locationId, cursorKey.createdAt(), cursorKey.communityId(), @@ -261,6 +263,7 @@ private List fetchCommunities(CommunityTab tab, Long locationId, Curs case STORE -> communityRepository.findFeedByTypeAndRegion( CommunityType.STORE, + now, locationId, cursorKey.createdAt(), cursorKey.communityId(), @@ -269,6 +272,7 @@ private List fetchCommunities(CommunityTab tab, Long locationId, Curs case COMMUNICATION -> communityRepository.findFeedByTypeAndRegion( CommunityType.COMMUNICATION, + now, locationId, cursorKey.createdAt(), cursorKey.communityId(), @@ -277,6 +281,7 @@ private List fetchCommunities(CommunityTab tab, Long locationId, Curs case FESTIVAL -> communityRepository.findFeedByTypeAndRegion( CommunityType.FESTIVAL, + now, locationId, cursorKey.createdAt(), cursorKey.communityId(), @@ -307,6 +312,7 @@ private List fetchCommunities(CommunityTab tab, Long locationId, Curs case ALL -> communityRepository.findFeedByRegionOrGlobalTypes( REGION_BASED_FEED_TYPES, GLOBAL_FEED_TYPES, + now, locationId, cursorKey.createdAt(), cursorKey.communityId(), @@ -344,9 +350,11 @@ private boolean usesRegion(CommunityTab tab) { private List fetchStorePromotions(Long locationId, int storeSize) { int resolvedSize = Math.min(Math.max(1, storeSize), MAX_STORE_SIZE); Pageable limit = PageRequest.of(0, resolvedSize); + LocalDateTime now = LocalDateTime.now(); List communities = communityRepository.findFeedByTypeAndRegion( CommunityType.STORE, + now, locationId, null, null, @@ -357,12 +365,14 @@ private List fetchStorePromotions(Long locationId, int } private List fetchHotPreviews(Long locationId) { + LocalDateTime now = LocalDateTime.now(); LocalDateTime since = LocalDateTime.now().minusDays(HOT_DAYS); Pageable limit = PageRequest.of(0, HOT_PREVIEW_SIZE); return toFeedItems(communityRepository.findHotFeedByRegionOrGlobalTypes( REGION_BASED_FEED_TYPES, GLOBAL_FEED_TYPES, + now, locationId, since, null, @@ -374,9 +384,11 @@ private List fetchHotPreviews(Long locationId) { private CommunityCursorPageResDTO fetchRecentNews(Long locationId, String recentCursor, int recentSize) { CursorKey cursorKey = CursorKey.parse(recentCursor, recentSize); Pageable limit = PageRequest.of(0, sizeWithLookahead(cursorKey.requestSize())); + LocalDateTime now = LocalDateTime.now(); List communities = communityRepository.findFeedByTypesAndRegion( REGION_BASED_FEED_TYPES, + now, locationId, cursorKey.createdAt(), cursorKey.communityId(), @@ -715,12 +727,14 @@ private String resolveWriterProfileUrl(CommunityType type, Pin pin) { private CommunityCursorPageResDTO getHotFeed(Long locationId, String cursor, int size) { HotCursorKey cursorKey = HotCursorKey.parse(cursor, size); + LocalDateTime now = LocalDateTime.now(); LocalDateTime since = LocalDateTime.now().minusDays(HOT_DAYS); Pageable limit = PageRequest.of(0, sizeWithLookahead(size)); List communities = communityRepository.findHotFeedByRegionOrGlobalTypes( REGION_BASED_FEED_TYPES, GLOBAL_FEED_TYPES, + now, locationId, since, cursorKey.popularity(), From 27da6554ddfb690f435e008ac06b3ec7d85814eb Mon Sep 17 00:00:00 2001 From: taerimiiii Date: Tue, 16 Jun 2026 21:27:00 +0900 Subject: [PATCH 04/10] =?UTF-8?q?feat:=20=EB=82=B4=20=EC=8B=9C=EB=AF=BC?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=EC=82=AC=20=EC=A1=B0=ED=9A=8C=20API=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserController.java | 16 ++++ .../user/dto/res/UserMySolverItemResDTO.java | 11 +++ .../user/dto/res/UserMySolversResDTO.java | 5 ++ .../user/exception/code/UserErrorCode.java | 2 + .../user/exception/code/UserSuccessCode.java | 1 + .../repository/UserMySolverRepository.java | 51 +++++++++++ .../user/repository/UserMySolverRow.java | 17 ++++ .../service/query/UserSolverQueryService.java | 8 ++ .../query/UserSolverQueryServiceImpl.java | 86 +++++++++++++++++++ .../user/support/UserSolverCursorCodec.java | 55 ++++++++++++ 10 files changed, 252 insertions(+) create mode 100644 src/main/java/issueissyu/backend/domain/user/dto/res/UserMySolverItemResDTO.java create mode 100644 src/main/java/issueissyu/backend/domain/user/dto/res/UserMySolversResDTO.java create mode 100644 src/main/java/issueissyu/backend/domain/user/repository/UserMySolverRepository.java create mode 100644 src/main/java/issueissyu/backend/domain/user/repository/UserMySolverRow.java create mode 100644 src/main/java/issueissyu/backend/domain/user/service/query/UserSolverQueryService.java create mode 100644 src/main/java/issueissyu/backend/domain/user/service/query/UserSolverQueryServiceImpl.java create mode 100644 src/main/java/issueissyu/backend/domain/user/support/UserSolverCursorCodec.java diff --git a/src/main/java/issueissyu/backend/domain/user/controller/UserController.java b/src/main/java/issueissyu/backend/domain/user/controller/UserController.java index 8912d0f..e22be6c 100644 --- a/src/main/java/issueissyu/backend/domain/user/controller/UserController.java +++ b/src/main/java/issueissyu/backend/domain/user/controller/UserController.java @@ -8,12 +8,14 @@ import issueissyu.backend.domain.user.dto.res.UserAlarmStateResDTO; import issueissyu.backend.domain.user.dto.res.UserAlarmToggleResDTO; import issueissyu.backend.domain.user.dto.res.UserMyPinsResDTO; +import issueissyu.backend.domain.user.dto.res.UserMySolversResDTO; import issueissyu.backend.domain.user.enums.UserAlarmType; import issueissyu.backend.domain.alarm.exception.code.AlarmSuccessCode; import issueissyu.backend.domain.user.exception.code.UserSuccessCode; import issueissyu.backend.domain.user.service.command.UserCommandService; import issueissyu.backend.domain.user.service.query.UserAlarmStateQueryService; import issueissyu.backend.domain.user.service.query.UserPinQueryService; +import issueissyu.backend.domain.user.service.query.UserSolverQueryService; import issueissyu.backend.global.api.ApiResponse; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -33,6 +35,7 @@ public class UserController { private final UserPinQueryService userPinQueryService; + private final UserSolverQueryService userSolverQueryService; private final UserAlarmStateQueryService userAlarmStateQueryService; private final UserCommandService userCommandService; @@ -87,4 +90,17 @@ public ApiResponse getMyPins( @RequestParam(required = false) String cursor) { return ApiResponse.onSuccess(UserSuccessCode.USER_PIN_200, userPinQueryService.getMyPins(uid, size, cursor)); } + + @Operation( + summary = "내 시민해결사 참여 핀 조회", + description = + "로그인한 사용자가 시민해결사(EN_ROUTE)로 참여 중인 핀을 problem_solver.created_at 내림차순으로 커서 페이징 조회합니다.") + @GetMapping("/me/solvers") + public ApiResponse getMySolvers( + @AuthenticationPrincipal String uid, + @RequestParam(required = false) Integer size, + @RequestParam(required = false) String cursor) { + return ApiResponse.onSuccess( + UserSuccessCode.USER_SOLVER_200, userSolverQueryService.getMySolvers(uid, size, cursor)); + } } diff --git a/src/main/java/issueissyu/backend/domain/user/dto/res/UserMySolverItemResDTO.java b/src/main/java/issueissyu/backend/domain/user/dto/res/UserMySolverItemResDTO.java new file mode 100644 index 0000000..e3e1639 --- /dev/null +++ b/src/main/java/issueissyu/backend/domain/user/dto/res/UserMySolverItemResDTO.java @@ -0,0 +1,11 @@ +package issueissyu.backend.domain.user.dto.res; + +import com.fasterxml.jackson.annotation.JsonFormat; +import java.time.LocalDateTime; + +public record UserMySolverItemResDTO( + Long pinId, + String pinTitle, + String pinDetailAddress, + String issuePinState, + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSSSS") LocalDateTime createdAt) {} diff --git a/src/main/java/issueissyu/backend/domain/user/dto/res/UserMySolversResDTO.java b/src/main/java/issueissyu/backend/domain/user/dto/res/UserMySolversResDTO.java new file mode 100644 index 0000000..f910d25 --- /dev/null +++ b/src/main/java/issueissyu/backend/domain/user/dto/res/UserMySolversResDTO.java @@ -0,0 +1,5 @@ +package issueissyu.backend.domain.user.dto.res; + +import java.util.List; + +public record UserMySolversResDTO(List pins, UserMyPinPageInfoResDTO pageInfo) {} diff --git a/src/main/java/issueissyu/backend/domain/user/exception/code/UserErrorCode.java b/src/main/java/issueissyu/backend/domain/user/exception/code/UserErrorCode.java index 235e1ac..9024cf8 100644 --- a/src/main/java/issueissyu/backend/domain/user/exception/code/UserErrorCode.java +++ b/src/main/java/issueissyu/backend/domain/user/exception/code/UserErrorCode.java @@ -11,6 +11,8 @@ public enum UserErrorCode implements BaseErrorCode { USER_PIN_400_1(HttpStatus.BAD_REQUEST, "USER_PIN_400_1", "조회 불가능한 사이즈 입니다."), USER_PIN_400_2(HttpStatus.BAD_REQUEST, "USER_PIN_400_2", "조회 불가능한 cursor 입니다."), + USER_SOLVER_400_1(HttpStatus.BAD_REQUEST, "USER_SOLVER_400_1", "조회 불가능한 사이즈 입니다."), + USER_SOLVER_400_2(HttpStatus.BAD_REQUEST, "USER_SOLVER_400_2", "조회 불가능한 cursor 입니다."), USER_NICKNAME_400(HttpStatus.BAD_REQUEST, "USER_NICKNAME_400", "닉네임은 15자 이내의 영문, 숫자, 한글만 사용 가능합니다."), USER_NICKNAME_409(HttpStatus.CONFLICT, "USER_NICKNAME_409", "이미 사용 중인 닉네임입니다."), USER_ALARM_400(HttpStatus.BAD_REQUEST, "USER_ALARM_400", "존재하지 않는 알람 설정입니다."); diff --git a/src/main/java/issueissyu/backend/domain/user/exception/code/UserSuccessCode.java b/src/main/java/issueissyu/backend/domain/user/exception/code/UserSuccessCode.java index 522bb36..4ddb088 100644 --- a/src/main/java/issueissyu/backend/domain/user/exception/code/UserSuccessCode.java +++ b/src/main/java/issueissyu/backend/domain/user/exception/code/UserSuccessCode.java @@ -10,6 +10,7 @@ public enum UserSuccessCode implements BaseSuccessCode { USER_PIN_200(HttpStatus.OK, "USER_PIN_200", "내 핀 조회에 성공했습니다."), + USER_SOLVER_200(HttpStatus.OK, "USER_SOLVER_200", "내 시민해결사 조회에 성공했습니다."), USER_NICKNAME_200(HttpStatus.OK, "USER_NICKNAME_200", "닉네임 변경에 성공했습니다."), USER_ALARM_200_1(HttpStatus.OK, "USER_ALARM_200_1", "핀 좋아요 알람 비/활성화에 성공했습니다."), USER_ALARM_200_2(HttpStatus.OK, "USER_ALARM_200_2", "이벤트 알람 비/활성화에 성공했습니다."), diff --git a/src/main/java/issueissyu/backend/domain/user/repository/UserMySolverRepository.java b/src/main/java/issueissyu/backend/domain/user/repository/UserMySolverRepository.java new file mode 100644 index 0000000..1b44a74 --- /dev/null +++ b/src/main/java/issueissyu/backend/domain/user/repository/UserMySolverRepository.java @@ -0,0 +1,51 @@ +package issueissyu.backend.domain.user.repository; + +import issueissyu.backend.domain.issue.entity.ProblemSolver; +import java.time.LocalDateTime; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface UserMySolverRepository extends JpaRepository { + + @Query( + value = + """ + SELECT p.pin_id AS pinId, + p.pin_title AS pinTitle, + pl.detail_address AS pinDetailAddress, + ip.issue_pin_state AS issuePinState, + ps.created_at AS createdAt, + ps.problem_solver_id AS problemSolverId + FROM problem_solver ps + JOIN issue_pin ip ON ip.issue_pin_id = ps.issue_pin_id + JOIN pin p ON p.pin_id = ip.pin_id + LEFT JOIN LATERAL ( + SELECT pl2.detail_address + FROM pin_location pl2 + WHERE pl2.pin_id = p.pin_id + ORDER BY pl2.pin_location_id ASC + LIMIT 1 + ) pl ON TRUE + WHERE ps.uid = :uid + AND ps.problem_solve_state = 'EN_ROUTE' + AND ( + NOT CAST(:applyCursor AS boolean) + OR ps.created_at < CAST(:cursorCreatedAt AS timestamp) + OR ( + ps.created_at = CAST(:cursorCreatedAt AS timestamp) + AND ps.problem_solver_id < :cursorProblemSolverId + ) + ) + ORDER BY ps.created_at DESC, ps.problem_solver_id DESC + LIMIT :limit + """, + nativeQuery = true) + List findMySolvers( + @Param("uid") String uid, + @Param("applyCursor") boolean applyCursor, + @Param("cursorCreatedAt") LocalDateTime cursorCreatedAt, + @Param("cursorProblemSolverId") long cursorProblemSolverId, + @Param("limit") int limit); +} diff --git a/src/main/java/issueissyu/backend/domain/user/repository/UserMySolverRow.java b/src/main/java/issueissyu/backend/domain/user/repository/UserMySolverRow.java new file mode 100644 index 0000000..fa95c53 --- /dev/null +++ b/src/main/java/issueissyu/backend/domain/user/repository/UserMySolverRow.java @@ -0,0 +1,17 @@ +package issueissyu.backend.domain.user.repository; + +import java.time.LocalDateTime; + +public interface UserMySolverRow { + Long getPinId(); + + String getPinTitle(); + + String getPinDetailAddress(); + + String getIssuePinState(); + + LocalDateTime getCreatedAt(); + + Long getProblemSolverId(); +} diff --git a/src/main/java/issueissyu/backend/domain/user/service/query/UserSolverQueryService.java b/src/main/java/issueissyu/backend/domain/user/service/query/UserSolverQueryService.java new file mode 100644 index 0000000..360ff48 --- /dev/null +++ b/src/main/java/issueissyu/backend/domain/user/service/query/UserSolverQueryService.java @@ -0,0 +1,8 @@ +package issueissyu.backend.domain.user.service.query; + +import issueissyu.backend.domain.user.dto.res.UserMySolversResDTO; + +public interface UserSolverQueryService { + + UserMySolversResDTO getMySolvers(String uid, Integer size, String cursor); +} diff --git a/src/main/java/issueissyu/backend/domain/user/service/query/UserSolverQueryServiceImpl.java b/src/main/java/issueissyu/backend/domain/user/service/query/UserSolverQueryServiceImpl.java new file mode 100644 index 0000000..5f9f7f9 --- /dev/null +++ b/src/main/java/issueissyu/backend/domain/user/service/query/UserSolverQueryServiceImpl.java @@ -0,0 +1,86 @@ +package issueissyu.backend.domain.user.service.query; + +import issueissyu.backend.domain.user.dto.res.UserMyPinPageInfoResDTO; +import issueissyu.backend.domain.user.dto.res.UserMySolverItemResDTO; +import issueissyu.backend.domain.user.dto.res.UserMySolversResDTO; +import issueissyu.backend.domain.user.exception.UserException; +import issueissyu.backend.domain.user.exception.code.UserErrorCode; +import issueissyu.backend.domain.user.repository.UserMySolverRepository; +import issueissyu.backend.domain.user.repository.UserMySolverRow; +import issueissyu.backend.domain.user.repository.UserRepository; +import issueissyu.backend.domain.user.support.UserSolverCursorCodec; +import issueissyu.backend.global.api.code.GeneralErrorCode; +import issueissyu.backend.global.exception.GeneralException; +import java.time.LocalDateTime; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class UserSolverQueryServiceImpl implements UserSolverQueryService { + + private static final int SIZE_DEFAULT = 10; + private static final int SIZE_MIN = 1; + private static final int SIZE_MAX = 100; + + private static final LocalDateTime CURSOR_DUMMY_TIME = LocalDateTime.of(1970, 1, 1, 0, 0, 0); + + private final UserRepository userRepository; + private final UserMySolverRepository userMySolverRepository; + private final UserSolverCursorCodec userSolverCursorCodec; + + @Override + public UserMySolversResDTO getMySolvers(String uid, Integer size, String cursor) { + int pageSize = resolveSize(size); + + userRepository.findById(uid).orElseThrow(() -> GeneralException.of(GeneralErrorCode.USER_NOT_FOUND)); + + boolean applyCursor = StringUtils.hasText(cursor); + LocalDateTime cursorCreatedAt = CURSOR_DUMMY_TIME; + long cursorProblemSolverId = 0L; + if (applyCursor) { + UserSolverCursorCodec.Decoded decoded = userSolverCursorCodec.decode(cursor.trim()); + cursorCreatedAt = decoded.createdAt(); + cursorProblemSolverId = decoded.problemSolverId(); + } + + List rows = + userMySolverRepository.findMySolvers( + uid, applyCursor, cursorCreatedAt, cursorProblemSolverId, pageSize + 1); + + boolean hasNext = rows.size() > pageSize; + List pageRows = hasNext ? rows.subList(0, pageSize) : rows; + + List pins = + pageRows.stream() + .map( + r -> + new UserMySolverItemResDTO( + r.getPinId(), + r.getPinTitle(), + r.getPinDetailAddress(), + r.getIssuePinState(), + r.getCreatedAt())) + .toList(); + + String nextCursor = null; + if (hasNext && !pageRows.isEmpty()) { + UserMySolverRow last = pageRows.get(pageRows.size() - 1); + nextCursor = userSolverCursorCodec.encode(last.getCreatedAt(), last.getProblemSolverId()); + } + + return new UserMySolversResDTO(pins, new UserMyPinPageInfoResDTO(hasNext, nextCursor)); + } + + private int resolveSize(Integer size) { + int s = size == null ? SIZE_DEFAULT : size; + if (s < SIZE_MIN || s > SIZE_MAX) { + throw UserException.of(UserErrorCode.USER_SOLVER_400_1); + } + return s; + } +} diff --git a/src/main/java/issueissyu/backend/domain/user/support/UserSolverCursorCodec.java b/src/main/java/issueissyu/backend/domain/user/support/UserSolverCursorCodec.java new file mode 100644 index 0000000..fa50a97 --- /dev/null +++ b/src/main/java/issueissyu/backend/domain/user/support/UserSolverCursorCodec.java @@ -0,0 +1,55 @@ +package issueissyu.backend.domain.user.support; + +import issueissyu.backend.domain.user.exception.UserException; +import issueissyu.backend.domain.user.exception.code.UserErrorCode; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoField; +import java.util.Base64; +import org.springframework.stereotype.Component; + +@Component +public class UserSolverCursorCodec { + + private static final DateTimeFormatter CURSOR_TIME = + new DateTimeFormatterBuilder() + .appendPattern("yyyy-MM-dd HH:mm:ss") + .appendFraction(ChronoField.NANO_OF_SECOND, 6, 9, true) + .toFormatter(); + + public record Decoded(LocalDateTime createdAt, long problemSolverId) {} + + public String encode(LocalDateTime createdAt, long problemSolverId) { + String raw = createdAt.format(CURSOR_TIME) + ":" + problemSolverId; + return Base64.getUrlEncoder() + .withoutPadding() + .encodeToString(raw.getBytes(StandardCharsets.UTF_8)); + } + + public Decoded decode(String cursor) { + if (cursor == null || cursor.isBlank()) { + throw UserException.of(UserErrorCode.USER_SOLVER_400_2); + } + try { + String raw = new String(Base64.getUrlDecoder().decode(cursor.trim()), StandardCharsets.UTF_8); + int delim = raw.lastIndexOf(':'); + if (delim < 0 || delim == raw.length() - 1) { + throw UserException.of(UserErrorCode.USER_SOLVER_400_2); + } + String createdAtRaw = raw.substring(0, delim); + String problemSolverIdRaw = raw.substring(delim + 1); + long problemSolverId = Long.parseLong(problemSolverIdRaw); + if (problemSolverId <= 0) { + throw UserException.of(UserErrorCode.USER_SOLVER_400_2); + } + LocalDateTime createdAt = LocalDateTime.parse(createdAtRaw, CURSOR_TIME); + return new Decoded(createdAt, problemSolverId); + } catch (UserException e) { + throw e; + } catch (Exception e) { + throw UserException.of(UserErrorCode.USER_SOLVER_400_2); + } + } +} From 122b13966e548b7fd589e7c886bba8a43e74f42b Mon Sep 17 00:00:00 2001 From: taerimiiii Date: Tue, 16 Jun 2026 21:35:49 +0900 Subject: [PATCH 05/10] =?UTF-8?q?fix:=20=EC=95=8C=EB=9E=8C=20=EC=A0=84?= =?UTF-8?q?=EC=86=A1=20=EC=8B=9C=EA=B0=84=20=EC=98=81=EC=97=AD=20=EC=A1=B0?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/alarm/controller/UserAlarmController.java | 4 ++-- .../service/command/RegionalAlarmCommandServiceImpl.java | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/issueissyu/backend/domain/alarm/controller/UserAlarmController.java b/src/main/java/issueissyu/backend/domain/alarm/controller/UserAlarmController.java index 84f3e45..e2b57e8 100644 --- a/src/main/java/issueissyu/backend/domain/alarm/controller/UserAlarmController.java +++ b/src/main/java/issueissyu/backend/domain/alarm/controller/UserAlarmController.java @@ -85,7 +85,7 @@ public ApiResponse sendLikeAlarm( description = """ 동네 인증 지역의 축제(FESTIVAL) 핀에 대한 푸시 알람을 요청자에게 전송합니다. - event_start_time 이 현재 시각 ±12시간 이내인 핀만 대상이며, 제목·본문은 서버에서 고정값으로 생성합니다. + event_start_time 이 현재 시각 24시간 이내인 핀만 대상이며, 제목·본문은 서버에서 고정값으로 생성합니다. user.event_alarm_active 가 false 이면 EVENT_ALARM_403 을 반환합니다. EVENT_ALARM_404_1(동네 인증 없음), EVENT_ALARM_404_2(대상 축제 없음), EVENT_ALARM_404_3(커뮤니티 없음). 알람 클릭 시 GET /api/communities/{communityId} 로 이동합니다. @@ -101,7 +101,7 @@ public ApiResponse sendEventAlarm(@AuthenticationPrincipal description = """ 동네 인증 지역의 가게(STORE) 핀에 대한 푸시 알람을 요청자에게 전송합니다. - event_start_time 이 현재 시각 ±12시간 이내인 핀만 대상이며, 제목·본문은 서버에서 고정값으로 생성합니다. + event_start_time 이 현재 시각 24시간 이내인 핀만 대상이며, 제목·본문은 서버에서 고정값으로 생성합니다. user.store_alarm_active 가 false 이면 STORE_ALARM_403 을 반환합니다. 알람 클릭 시 GET /api/communities/{communityId} 로 이동합니다. """) diff --git a/src/main/java/issueissyu/backend/domain/alarm/service/command/RegionalAlarmCommandServiceImpl.java b/src/main/java/issueissyu/backend/domain/alarm/service/command/RegionalAlarmCommandServiceImpl.java index 4e92332..1b0134d 100644 --- a/src/main/java/issueissyu/backend/domain/alarm/service/command/RegionalAlarmCommandServiceImpl.java +++ b/src/main/java/issueissyu/backend/domain/alarm/service/command/RegionalAlarmCommandServiceImpl.java @@ -183,10 +183,9 @@ private void dispatchFcmBatch(List payloads, String alar fcmService.sendNotificationsBatchAsync(payloads); log.info("[RegionalAlarm] {} FCM batch dispatched count={}", alarmType, payloads.size()); } - private static LocalDateTime[] alarmTimeWindow() { LocalDateTime now = LocalDateTime.now(); - return new LocalDateTime[] {now.minusHours(12), now.plusHours(12)}; + return new LocalDateTime[] {now.minusHours(24), now}; } private User findUser(String uid) { From 1011b9108fe8d560f233e07ce9cc4d9b7c3d311b Mon Sep 17 00:00:00 2001 From: taerimiiii Date: Tue, 16 Jun 2026 21:43:19 +0900 Subject: [PATCH 06/10] =?UTF-8?q?fix:=20=EC=82=AC=EC=9A=A9=20=EA=B8=B0?= =?UTF-8?q?=EC=A4=80=20=EC=8B=9C=EA=B0=84=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../alarm/service/command/RegionalAlarmCommandServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/issueissyu/backend/domain/alarm/service/command/RegionalAlarmCommandServiceImpl.java b/src/main/java/issueissyu/backend/domain/alarm/service/command/RegionalAlarmCommandServiceImpl.java index 1b0134d..1c17144 100644 --- a/src/main/java/issueissyu/backend/domain/alarm/service/command/RegionalAlarmCommandServiceImpl.java +++ b/src/main/java/issueissyu/backend/domain/alarm/service/command/RegionalAlarmCommandServiceImpl.java @@ -184,7 +184,7 @@ private void dispatchFcmBatch(List payloads, String alar log.info("[RegionalAlarm] {} FCM batch dispatched count={}", alarmType, payloads.size()); } private static LocalDateTime[] alarmTimeWindow() { - LocalDateTime now = LocalDateTime.now(); + LocalDateTime now = LocalDateTime.now(java.time.ZoneId.of("Asia/Seoul")); return new LocalDateTime[] {now.minusHours(24), now}; } From 721d7ac17838bffd07616d848f7e365f9abd5ba0 Mon Sep 17 00:00:00 2001 From: taerimiiii Date: Tue, 16 Jun 2026 21:47:28 +0900 Subject: [PATCH 07/10] =?UTF-8?q?refactor:=20=EB=A9=94=EB=AA=A8=EB=A6=AC?= =?UTF-8?q?=20=EB=B0=8F=20=EC=98=A4=EB=B2=84=ED=97=A4=EB=93=9C=20=EB=B0=A9?= =?UTF-8?q?=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/user/service/query/UserSolverQueryServiceImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/issueissyu/backend/domain/user/service/query/UserSolverQueryServiceImpl.java b/src/main/java/issueissyu/backend/domain/user/service/query/UserSolverQueryServiceImpl.java index 5f9f7f9..6f2d578 100644 --- a/src/main/java/issueissyu/backend/domain/user/service/query/UserSolverQueryServiceImpl.java +++ b/src/main/java/issueissyu/backend/domain/user/service/query/UserSolverQueryServiceImpl.java @@ -37,7 +37,9 @@ public class UserSolverQueryServiceImpl implements UserSolverQueryService { public UserMySolversResDTO getMySolvers(String uid, Integer size, String cursor) { int pageSize = resolveSize(size); - userRepository.findById(uid).orElseThrow(() -> GeneralException.of(GeneralErrorCode.USER_NOT_FOUND)); + if (!userRepository.existsById(uid)) { + throw GeneralException.of(GeneralErrorCode.USER_NOT_FOUND); + } boolean applyCursor = StringUtils.hasText(cursor); LocalDateTime cursorCreatedAt = CURSOR_DUMMY_TIME; From 63d68eed1e3471e507b405acbd3c3260d20c3522 Mon Sep 17 00:00:00 2001 From: taerimiiii Date: Tue, 16 Jun 2026 22:12:39 +0900 Subject: [PATCH 08/10] =?UTF-8?q?fix:=20=EC=8B=9D=EB=B3=84=EC=9E=90=20?= =?UTF-8?q?=EC=86=8C=EB=AC=B8=EC=9E=90=20=EB=A7=A4=ED=95=91=20=EB=B0=A9?= =?UTF-8?q?=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/repository/UserMySolverRepository.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/issueissyu/backend/domain/user/repository/UserMySolverRepository.java b/src/main/java/issueissyu/backend/domain/user/repository/UserMySolverRepository.java index 1b44a74..5e84d83 100644 --- a/src/main/java/issueissyu/backend/domain/user/repository/UserMySolverRepository.java +++ b/src/main/java/issueissyu/backend/domain/user/repository/UserMySolverRepository.java @@ -12,12 +12,12 @@ public interface UserMySolverRepository extends JpaRepository Date: Tue, 16 Jun 2026 22:20:47 +0900 Subject: [PATCH 09/10] =?UTF-8?q?fix:=20PostgreSQL=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=ED=83=80=EC=9E=84=EC=A1=B4=EA=B3=BC=20=EA=B4=80=EA=B3=84?= =?UTF-8?q?=EC=97=86=EC=9D=B4=20KST=20=EA=B8=B0=EC=A4=80=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../location/repository/PinLocationRepository.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/issueissyu/backend/domain/location/repository/PinLocationRepository.java b/src/main/java/issueissyu/backend/domain/location/repository/PinLocationRepository.java index 3a8d37a..bc7b144 100644 --- a/src/main/java/issueissyu/backend/domain/location/repository/PinLocationRepository.java +++ b/src/main/java/issueissyu/backend/domain/location/repository/PinLocationRepository.java @@ -46,7 +46,7 @@ public interface PinLocationRepository extends JpaRepository INNER JOIN location l ON pl.location_id = l.location_id LEFT JOIN communication_pin cp ON cp.pin_id = p.pin_id LEFT JOIN event_pin ep ON ep.pin_id = p.pin_id - WHERE p.created_at >= NOW() - INTERVAL '1 year' + WHERE p.created_at >= (NOW() AT TIME ZONE 'Asia/Seoul') - INTERVAL '1 year' AND ST_Within( pl.pin_point, ST_MakeEnvelope(:swLng, :swLat, :neLng, :neLat, 4326) @@ -55,10 +55,10 @@ AND ST_Within( p.pin_type = 'ISSUE' OR (p.pin_type = 'COMMUNICATION' AND cp.communication_pin_id IS NOT NULL - AND COALESCE(cp.updated_at, cp.created_at) >= NOW() - INTERVAL '1 month') + AND COALESCE(cp.updated_at, cp.created_at) >= (NOW() AT TIME ZONE 'Asia/Seoul') - INTERVAL '1 month') OR (p.pin_type IN ('STORE', 'FESTIVAL') AND ep.event_pin_id IS NOT NULL - AND NOW() BETWEEN ep.event_start_time AND ep.event_end_time) + AND (NOW() AT TIME ZONE 'Asia/Seoul') BETWEEN ep.event_start_time AND ep.event_end_time) ) AND (:pinTypeFilter IS NULL OR p.pin_type = :pinTypeFilter) """, nativeQuery = true) @@ -85,7 +85,7 @@ List findPinsInBoundingBox( INNER JOIN location l ON pl.location_id = l.location_id LEFT JOIN communication_pin cp ON cp.pin_id = p.pin_id LEFT JOIN event_pin ep ON ep.pin_id = p.pin_id - WHERE p.created_at >= NOW() - INTERVAL '1 year' + WHERE p.created_at >= (NOW() AT TIME ZONE 'Asia/Seoul') - INTERVAL '1 year' AND ST_Within( pl.pin_point, ST_MakeEnvelope(:swLng, :swLat, :neLng, :neLat, 4326) @@ -94,10 +94,10 @@ AND ST_Within( p.pin_type = 'ISSUE' OR (p.pin_type = 'COMMUNICATION' AND cp.communication_pin_id IS NOT NULL - AND COALESCE(cp.updated_at, cp.created_at) >= NOW() - INTERVAL '1 month') + AND COALESCE(cp.updated_at, cp.created_at) >= (NOW() AT TIME ZONE 'Asia/Seoul') - INTERVAL '1 month') OR (p.pin_type IN ('STORE', 'FESTIVAL') AND ep.event_pin_id IS NOT NULL - AND NOW() BETWEEN ep.event_start_time AND ep.event_end_time) + AND (NOW() AT TIME ZONE 'Asia/Seoul') BETWEEN ep.event_start_time AND ep.event_end_time) ) AND (:pinTypeFilter IS NULL OR p.pin_type = :pinTypeFilter) ORDER BY clusterLat, clusterLng, p.pin_id From f97a55b794b5148ae01c219278775d52bd76ce00 Mon Sep 17 00:00:00 2001 From: taerimiiii Date: Tue, 16 Jun 2026 22:24:24 +0900 Subject: [PATCH 10/10] =?UTF-8?q?fix:=20=EC=BB=A4=EB=AE=A4=EB=8B=88?= =?UTF-8?q?=ED=8B=B0=20=ED=95=84=ED=84=B0=EB=A7=81=20=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=EC=9D=84=20KST=20=ED=83=80=EC=9E=84=EC=A1=B4=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=EC=9C=BC=EB=A1=9C=20=EB=AA=85=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/query/CommunityHotQueryServiceImpl.java | 2 +- .../service/query/CommunityQueryServiceImpl.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/issueissyu/backend/domain/community/service/query/CommunityHotQueryServiceImpl.java b/src/main/java/issueissyu/backend/domain/community/service/query/CommunityHotQueryServiceImpl.java index bdd4d6f..82d32a8 100644 --- a/src/main/java/issueissyu/backend/domain/community/service/query/CommunityHotQueryServiceImpl.java +++ b/src/main/java/issueissyu/backend/domain/community/service/query/CommunityHotQueryServiceImpl.java @@ -34,7 +34,7 @@ public class CommunityHotQueryServiceImpl implements CommunityHotQueryService { @Override public Optional findTopHotInRegion(Long locationId) { - LocalDateTime now = LocalDateTime.now(); + LocalDateTime now = LocalDateTime.now(java.time.ZoneId.of("Asia/Seoul")); LocalDateTime since = LocalDateTime.now().minusDays(HOT_DAYS); Pageable limit = PageRequest.of(0, 1); diff --git a/src/main/java/issueissyu/backend/domain/community/service/query/CommunityQueryServiceImpl.java b/src/main/java/issueissyu/backend/domain/community/service/query/CommunityQueryServiceImpl.java index 3a9b93d..e7cc1f0 100644 --- a/src/main/java/issueissyu/backend/domain/community/service/query/CommunityQueryServiceImpl.java +++ b/src/main/java/issueissyu/backend/domain/community/service/query/CommunityQueryServiceImpl.java @@ -249,7 +249,7 @@ public CommunityQueryService.CommunityDetailResult getCommunityDetail( private List fetchCommunities(CommunityTab tab, Long locationId, CursorKey cursorKey) { Pageable limit = PageRequest.of(0, sizeWithLookahead(cursorKey.requestSize())); - LocalDateTime now = LocalDateTime.now(); + LocalDateTime now = LocalDateTime.now(java.time.ZoneId.of("Asia/Seoul")); return switch (tab) { case ISSUE -> communityRepository.findFeedByTypeAndRegion( @@ -350,7 +350,7 @@ private boolean usesRegion(CommunityTab tab) { private List fetchStorePromotions(Long locationId, int storeSize) { int resolvedSize = Math.min(Math.max(1, storeSize), MAX_STORE_SIZE); Pageable limit = PageRequest.of(0, resolvedSize); - LocalDateTime now = LocalDateTime.now(); + LocalDateTime now = LocalDateTime.now(java.time.ZoneId.of("Asia/Seoul")); List communities = communityRepository.findFeedByTypeAndRegion( CommunityType.STORE, @@ -365,7 +365,7 @@ private List fetchStorePromotions(Long locationId, int } private List fetchHotPreviews(Long locationId) { - LocalDateTime now = LocalDateTime.now(); + LocalDateTime now = LocalDateTime.now(java.time.ZoneId.of("Asia/Seoul")); LocalDateTime since = LocalDateTime.now().minusDays(HOT_DAYS); Pageable limit = PageRequest.of(0, HOT_PREVIEW_SIZE); @@ -384,7 +384,7 @@ private List fetchHotPreviews(Long locationId) { private CommunityCursorPageResDTO fetchRecentNews(Long locationId, String recentCursor, int recentSize) { CursorKey cursorKey = CursorKey.parse(recentCursor, recentSize); Pageable limit = PageRequest.of(0, sizeWithLookahead(cursorKey.requestSize())); - LocalDateTime now = LocalDateTime.now(); + LocalDateTime now = LocalDateTime.now(java.time.ZoneId.of("Asia/Seoul")); List communities = communityRepository.findFeedByTypesAndRegion( REGION_BASED_FEED_TYPES, @@ -727,7 +727,7 @@ private String resolveWriterProfileUrl(CommunityType type, Pin pin) { private CommunityCursorPageResDTO getHotFeed(Long locationId, String cursor, int size) { HotCursorKey cursorKey = HotCursorKey.parse(cursor, size); - LocalDateTime now = LocalDateTime.now(); + LocalDateTime now = LocalDateTime.now(java.time.ZoneId.of("Asia/Seoul")); LocalDateTime since = LocalDateTime.now().minusDays(HOT_DAYS); Pageable limit = PageRequest.of(0, sizeWithLookahead(size));