Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.pinHouse.server.platform.home.application.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

import java.util.List;

@Schema(name = "[응답][홈] 홈 화면 공고 목록 조회 응답", description = "홈 화면에서 마감임박 공고 목록을 조회하기 위한 DTO입니다. SliceResponse와 유사한 구조에 region 필드를 추가했습니다.")
@Builder
public record HomeNoticeListResponse(

@Schema(description = "공통 지역", example = "성남시")
String region,

@Schema(description = "공고 목록")
List<HomeNoticeResponse> content,

@Schema(description = "다음 페이지 존재 여부", example = "true")
boolean hasNext,

@Schema(description = "전체 공고 개수", example = "100")
long totalElements

) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.pinHouse.server.platform.home.application.dto;

import com.pinHouse.server.core.util.DateUtil;
import com.pinHouse.server.platform.housing.notice.domain.entity.NoticeDocument;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

@Schema(name = "[응답][홈] 개별 공고 정보", description = "홈 화면의 개별 공고 정보입니다.")
@Builder
public record HomeNoticeResponse(

@Schema(description = "공고ID", example = "101")
String id,

@Schema(description = "공고 썸네일 URL", example = "https://example.jpg")
String thumbnailUrl,

@Schema(description = "공고명", example = "2025 청년 행복주택 공고")
String name,

@Schema(description = "공급주체", example = "LH")
String supplier,

@Schema(description = "공급 주택 개수", example = "3")
Integer complexes,

@Schema(description = "공급유형", example = "영구임대")
String type,

@Schema(description = "주택유형", example = "아파트")
String housingType,

@Schema(description = "모집 공고일", example = "2025년 10월 5일")
String announcePeriod,

@Schema(description = "모집 일정", example = "2025년 10월 3일 ~ 11월 3일")
String applyPeriod,

@Schema(description = "좋아요 여부", example = "false")
boolean liked

) {

/**
* NoticeDocument와 좋아요 여부로부터 HomeNoticeResponse를 생성
*/
public static HomeNoticeResponse from(NoticeDocument notice, boolean liked) {
String period = DateUtil.formatDate(notice.getApplyStart(), notice.getApplyEnd());

return HomeNoticeResponse.builder()
.id(notice.getId())
.thumbnailUrl(notice.getThumbnail())
.name(notice.getTitle())
.supplier(notice.getAgency())
.complexes(notice.getMeta().getTotalComplexCount())
.announcePeriod(notice.getAnnounceDate().toString())
.applyPeriod(period)
.type(notice.getSupplyType())
.housingType(notice.getHouseType())
.liked(liked)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
import com.pinHouse.server.core.response.response.CustomException;
import com.pinHouse.server.core.response.response.pageable.SliceRequest;
import com.pinHouse.server.core.response.response.pageable.SliceResponse;
import com.pinHouse.server.platform.home.application.dto.HomeNoticeListResponse;
import com.pinHouse.server.platform.home.application.dto.HomeNoticeResponse;
import com.pinHouse.server.platform.home.application.usecase.HomeUseCase;
import com.pinHouse.server.platform.housing.notice.application.dto.NoticeListRequest;
import com.pinHouse.server.platform.housing.notice.application.dto.NoticeListResponse;
import com.pinHouse.server.platform.housing.notice.domain.entity.NoticeDocument;
import com.pinHouse.server.platform.housing.notice.domain.repository.NoticeDocumentRepository;
import com.pinHouse.server.platform.like.application.usecase.LikeQueryUseCase;
Expand Down Expand Up @@ -51,7 +52,7 @@ public class HomeService implements HomeUseCase {
* - PinPoint의 address에서 광역 단위와 시/군/구를 추출하여 해당 지역의 마감임박 공고를 조회
*/
@Override
public SliceResponse<NoticeListResponse> getDeadlineApproachingNotices(
public HomeNoticeListResponse getDeadlineApproachingNotices(
String pinpointId,
SliceRequest sliceRequest,
UUID userId
Expand Down Expand Up @@ -88,15 +89,21 @@ public SliceResponse<NoticeListResponse> getDeadlineApproachingNotices(
// 좋아요 상태 조회
List<String> likedNoticeIds = likeService.getLikeNoticeIds(userId);

// DTO 변환
List<NoticeListResponse> content = page.getContent().stream()
// DTO 변환 (개별 공고 정보)
List<HomeNoticeResponse> content = page.getContent().stream()
.map(notice -> {
boolean isLiked = likedNoticeIds.contains(notice.getId());
return NoticeListResponse.from(notice, isLiked);
return HomeNoticeResponse.from(notice, isLiked);
})
.toList();

return SliceResponse.from(new SliceImpl<>(content, pageable, page.hasNext()), page.getTotalElements());
// 최종 응답 생성 (region + content + 페이징 정보)
return HomeNoticeListResponse.builder()
.region(county)
.content(content)
.hasNext(page.hasNext())
.totalElements(page.getTotalElements())
.build();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import com.pinHouse.server.core.response.response.pageable.SliceRequest;
import com.pinHouse.server.core.response.response.pageable.SliceResponse;
import com.pinHouse.server.platform.home.application.dto.HomeNoticeListResponse;
import com.pinHouse.server.platform.housing.notice.application.dto.NoticeListRequest;
import com.pinHouse.server.platform.housing.notice.application.dto.NoticeListResponse;
import com.pinHouse.server.platform.search.application.dto.NoticeSearchFilterType;
import com.pinHouse.server.platform.search.application.dto.NoticeSearchResultResponse;
import com.pinHouse.server.platform.search.application.dto.NoticeSearchSortType;
Expand All @@ -20,9 +20,9 @@ public interface HomeUseCase {
* @param pinpointId PinPoint ID (해당 지역의 공고를 조회)
* @param sliceRequest 페이징 정보
* @param userId 사용자 ID (좋아요 정보 조회용, null 가능)
* @return 해당 지역의 마감임박순으로 정렬된 공고 목록
* @return 해당 지역의 마감임박순으로 정렬된 공고 목록 (region + notices 배열)
*/
SliceResponse<NoticeListResponse> getDeadlineApproachingNotices(
HomeNoticeListResponse getDeadlineApproachingNotices(
String pinpointId,
SliceRequest sliceRequest,
UUID userId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import com.pinHouse.server.core.response.response.ApiResponse;
import com.pinHouse.server.core.response.response.pageable.SliceRequest;
import com.pinHouse.server.core.response.response.pageable.SliceResponse;
import com.pinHouse.server.platform.home.application.dto.HomeNoticeListResponse;
import com.pinHouse.server.platform.home.application.usecase.HomeUseCase;
import com.pinHouse.server.platform.home.presentation.swagger.HomeApiSpec;
import com.pinHouse.server.platform.housing.notice.application.dto.NoticeListResponse;
import com.pinHouse.server.platform.search.application.dto.NoticeSearchFilterType;
import com.pinHouse.server.platform.search.application.dto.NoticeSearchResultResponse;
import com.pinHouse.server.platform.search.application.dto.NoticeSearchSortType;
Expand Down Expand Up @@ -37,7 +37,7 @@ public class HomeApi implements HomeApiSpec {
@Override
@CheckLogin
@GetMapping("/notice")
public ApiResponse<SliceResponse<NoticeListResponse>> getDeadlineApproachingNotices(
public ApiResponse<HomeNoticeListResponse> getDeadlineApproachingNotices(
@RequestParam String pinpointId,
SliceRequest sliceRequest,
@AuthenticationPrincipal PrincipalDetails principalDetails
Expand All @@ -46,7 +46,7 @@ public ApiResponse<SliceResponse<NoticeListResponse>> getDeadlineApproachingNoti
UUID userId = principalDetails.getId();

// 서비스 호출
SliceResponse<NoticeListResponse> response = homeService.getDeadlineApproachingNotices(
HomeNoticeListResponse response = homeService.getDeadlineApproachingNotices(
pinpointId,
sliceRequest,
userId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.pinHouse.server.core.response.response.ApiResponse;
import com.pinHouse.server.core.response.response.pageable.SliceRequest;
import com.pinHouse.server.core.response.response.pageable.SliceResponse;
import com.pinHouse.server.platform.housing.notice.application.dto.NoticeListResponse;
import com.pinHouse.server.platform.home.application.dto.HomeNoticeListResponse;
import com.pinHouse.server.platform.search.application.dto.NoticeSearchFilterType;
import com.pinHouse.server.platform.search.application.dto.NoticeSearchResultResponse;
import com.pinHouse.server.platform.search.application.dto.NoticeSearchSortType;
Expand All @@ -22,9 +22,10 @@ public interface HomeApiSpec {
description = "PinPoint의 지역을 기반으로 마감임박순으로 정렬된 공고 목록을 조회하는 API 입니다. " +
"PinPoint의 주소에서 광역 단위(시/도)를 추출하여 해당 지역의 모집중인 공고만 조회합니다. " +
"본인의 PinPoint만 사용 가능하며, 다른 사용자의 PinPoint ID를 사용하면 400 에러가 발생합니다. " +
"좋아요 정보가 포함됩니다."
"응답 구조: 공통 지역(region) + 공고 목록 배열(content) + 페이징 정보(hasNext, totalElements). " +
"SliceResponse와 유사한 구조이지만 region 필드가 추가되었습니다."
)
ApiResponse<SliceResponse<NoticeListResponse>> getDeadlineApproachingNotices(
ApiResponse<HomeNoticeListResponse> getDeadlineApproachingNotices(
@Parameter(description = "PinPoint ID", example = "83ec36ce-8fc1-4f62-8983-397c2729fc22")
@RequestParam String pinpointId,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,17 @@ public List<ComplexDocument> loadComplexes(String noticeId) {
return repository.findByNoticeId(noticeId);
}

/// 공고 기반 목록 조회 (정렬된 유닛타입 포함)
@Override
@Transactional(readOnly = true)
public List<ComplexDocument> loadSortedComplexes(
String noticeId,
com.pinHouse.server.platform.housing.notice.application.dto.UnitTypeSortType sortType
) {
log.debug("정렬된 단지 목록 조회 - noticeId: {}, sortType: {}", noticeId, sortType);
return repository.findSortedComplexesWithUnitTypes(noticeId, sortType);
}

/// 유닛타입 ID 목록으로 단지 목록 조회
@Override
@Transactional(readOnly = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public interface ComplexUseCase {
/// 공고 내부 목록 조회
List<ComplexDocument> loadComplexes(String noticeId);

/// 공고 내부 목록 조회 (정렬된 유닛타입 포함)
List<ComplexDocument> loadSortedComplexes(String noticeId, com.pinHouse.server.platform.housing.notice.application.dto.UnitTypeSortType sortType);

/// 유닛타입 ID 목록으로 단지 목록 조회
List<ComplexDocument> findComplexesByUnitTypeIds(List<String> typeIds);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import java.util.List;

public interface ComplexDocumentRepository extends MongoRepository<ComplexDocument, String> {
public interface ComplexDocumentRepository extends MongoRepository<ComplexDocument, String>, CustomComplexDocumentRepository {

List<ComplexDocument> findByNoticeId(String noticeId);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.pinHouse.server.platform.housing.complex.domain.repository;

import com.pinHouse.server.platform.housing.complex.domain.entity.ComplexDocument;
import com.pinHouse.server.platform.housing.notice.application.dto.UnitTypeSortType;

import java.util.List;

/**
* ComplexDocument 커스텀 Repository
* MongoDB Aggregation을 사용한 복잡한 쿼리 처리
*/
public interface CustomComplexDocumentRepository {

/**
* 공고에 속한 모든 단지와 유닛타입을 정렬하여 조회
*
* @param noticeId 공고 ID
* @param sortType 정렬 기준
* @return 정렬된 단지 목록 (각 단지의 unitTypes도 정렬됨)
*/
List<ComplexDocument> findSortedComplexesWithUnitTypes(String noticeId, UnitTypeSortType sortType);
}
Loading
Loading