3838import com .cotato .nextstation .domain .journal .service .query .JournalCardQueryService ;
3939import com .cotato .nextstation .domain .member .exception .MemberErrorCode ;
4040import com .cotato .nextstation .domain .member .service .query .MemberExistenceQueryService ;
41+ import com .cotato .nextstation .domain .place .dto .response .HistoricalPlaceInfoResponse ;
4142import com .cotato .nextstation .domain .place .dto .response .PlaceInfoResponse ;
4243import com .cotato .nextstation .domain .place .service .query .PlaceInfoQueryService ;
4344import com .cotato .nextstation .domain .stamp .service .query .MemberStampQueryService ;
5960import java .util .LinkedHashMap ;
6061import java .util .List ;
6162import java .util .Map ;
63+ import java .util .Objects ;
6264import java .util .Set ;
6365import java .util .stream .Collectors ;
6466
@@ -550,14 +552,10 @@ private List<CoursePlaceDetailResponse> resolveCoursePlaces(List<CoursePlace> co
550552 }
551553
552554 List <Long > placeIds = coursePlaces .stream ().map (CoursePlace ::getPlaceId ).toList ();
553- Map <Long , PlaceInfoResponse > placeById = placeInfoQueryService .getPlaceInfos (placeIds ).stream ()
554- .collect (Collectors .toMap (PlaceInfoResponse ::placeId , place -> place ));
555-
556- // 코스에 담긴 장소가 조회되지 않는 건 데이터 정합성이 깨진 상태다(장소 재시딩 등).
557- // 조용히 빠지면 아무도 모르는 데다, 그 코스는 순서 변경 저장까지 막힌다.
558- // PATCH /courses/{courseId}가 기존 장소 구성과 정확히 일치할 것을 요구하는데,
559- // 프론트는 빠진 장소를 모른 채 남은 것만 보내서 INVALID_COURSE_PLACES가 된다.
560- // 실제로 찍히면 course_places를 정리해야 한다.
555+ Map <Long , HistoricalPlaceInfoResponse > placeById = placeInfoQueryService .getHistoricalPlaceInfos (placeIds ).stream ()
556+ .collect (Collectors .toMap (HistoricalPlaceInfoResponse ::placeId , place -> place ));
557+
558+ // 장소가 실제로 사라진 경우만 누락으로 본다. 반려·삭제는 historical 조회가 상태와 함께 반환한다.
561559 if (placeById .size () != coursePlaces .size ()) {
562560 List <Long > missingPlaceIds = placeIds .stream ()
563561 .filter (placeId -> !placeById .containsKey (placeId ))
@@ -566,7 +564,7 @@ private List<CoursePlaceDetailResponse> resolveCoursePlaces(List<CoursePlace> co
566564 coursePlaces .get (0 ).getCourseId (), missingPlaceIds );
567565 }
568566
569- // 조회되지 않은 장소는 지도 핀도 못 찍고 목록에도 채울 내용이 없어 제외한다.
567+ // 실제로 삭제된 레코드는 지도 핀과 목록을 채울 정보가 없어 제외한다.
570568 return coursePlaces .stream ()
571569 .filter (coursePlace -> placeById .containsKey (coursePlace .getPlaceId ()))
572570 .map (coursePlace -> courseConverter .toCoursePlaceDetailResponse (
@@ -620,25 +618,27 @@ private Map<Long, List<Long>> groupPlaceIdsByCourse(List<Long> courseIds) {
620618 ));
621619 }
622620
623- // 카드 배경은 코스의 첫 장소 이미지를 쓴다. 장소 이미지가 없을 때의 폴백은 장소 조회 쪽에서 처리된다 .
621+ // 공개 코스 카드의 배경은 코스 순서상 첫 승인 장소 이미지를 사용한다 .
624622 private Map <Long , String > resolveCoverImages (Map <Long , List <Long >> placeIdsByCourse ) {
625- Map <Long , Long > firstPlaceByCourse = new LinkedHashMap <>();
626- placeIdsByCourse .forEach ((courseId , placeIds ) -> {
627- if (!placeIds .isEmpty ()) {
628- firstPlaceByCourse .put (courseId , placeIds .get (0 ));
629- }
630- });
631- if (firstPlaceByCourse .isEmpty ()) {
623+ List <Long > candidatePlaceIds = placeIdsByCourse .values ().stream ()
624+ .flatMap (List ::stream )
625+ .distinct ()
626+ .toList ();
627+ if (candidatePlaceIds .isEmpty ()) {
632628 return Map .of ();
633629 }
634630
635- Map <Long , String > imageUrlByPlace = placeInfoQueryService .getPlaceInfos (List . copyOf ( firstPlaceByCourse . values ()) )
631+ Map <Long , String > imageUrlByPlace = placeInfoQueryService .getPlaceInfos (candidatePlaceIds )
636632 .stream ()
637633 .filter (place -> place .imageUrl () != null )
638634 .collect (Collectors .toMap (PlaceInfoResponse ::placeId , PlaceInfoResponse ::imageUrl ));
639635
640636 Map <Long , String > result = new LinkedHashMap <>();
641- firstPlaceByCourse .forEach ((courseId , placeId ) -> result .put (courseId , imageUrlByPlace .get (placeId )));
637+ placeIdsByCourse .forEach ((courseId , placeIds ) -> result .put (courseId , placeIds .stream ()
638+ .map (imageUrlByPlace ::get )
639+ .filter (Objects ::nonNull )
640+ .findFirst ()
641+ .orElse (null )));
642642 return result ;
643643 }
644644
0 commit comments