Skip to content

Conversation

@leegwichan
Copy link
Member

@leegwichan leegwichan commented Aug 12, 2025

✨ 개요

  • 응원 도메인을 바탕으로 응원 등록 API에서 응원 태그 추가

🧾 관련 이슈

closed #158

🔍 참고 사항 (선택)

Summary by CodeRabbit

  • 신기능
    • 응원 등록에 태그 선택/전송 기능을 추가했습니다. 응원 상세 응답에도 태그가 포함됩니다.
    • 요청에 태그를 제공하지 않으면 빈 목록으로 반환되어 UI에서 안정적으로 표시됩니다.
  • 문서화
    • 응원 등록/조회 API에 tags 필드를 추가하고 예시 및 설명을 갱신했습니다.
  • 테스트
    • 태그 전송과 응답 반영을 검증하는 테스트를 추가/보강했습니다.

@coderabbitai
Copy link

coderabbitai bot commented Aug 12, 2025

Walkthrough

응원 등록 흐름에 태그를 추가했습니다. 요청/응답 DTO에 tags 필드를 도입하고 서비스에서 CheerTag 엔티티를 생성·저장하도록 CheerTagRepository를 추가했으며, 관련 테스트와 REST Docs를 태그 스키마에 맞게 업데이트했습니다.

Changes

Cohort / File(s) Summary
Controller DTO: Register Request
src/main/java/eatda/controller/cheer/CheerRegisterRequest.java
요청 레코드에 List<CheerTagName> tags 추가 및 tags() 오버라이드로 null 시 Collections.emptyList() 반환.
Controller DTO: Response
src/main/java/eatda/controller/cheer/CheerResponse.java
응답 레코드에 List<CheerTagName> tags 추가. 생성자 시그니처 변경: CheerResponse(Cheer, List<CheerTag>, Store, String)CheerTagCheerTagName 매핑 헬퍼 추가.
Repository
src/main/java/eatda/repository/cheer/CheerTagRepository.java
CheerTagJpaRepository<CheerTag, Long> 신규 추가.
Service
src/main/java/eatda/service/cheer/CheerService.java
요청의 태그로 CheerTag 엔티티 생성 및 cheerTagRepository.saveAll(...) 저장; 응답 생성 시 저장된 CheerTag 목록 포함.
Tests: Controller & Docs
src/test/java/eatda/controller/cheer/CheerControllerTest.java, src/test/java/eatda/document/store/CheerDocumentTest.java
요청/응답에 태그 포함하도록 테스트 및 REST Docs 갱신; 태그 전달/반환 검증 추가.
Tests: Service
src/test/java/eatda/service/cheer/CheerServiceTest.java
서비스 테스트에 태그 인자 및 반환 검증 추가.
Tests: Base wiring
src/test/java/eatda/controller/BaseControllerTest.java, src/test/java/eatda/service/BaseServiceTest.java
테스트 컨텍스트에 CheerTagRepository 주입 필드 추가.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Controller
  participant Service
  participant StoreRepo as StoreRepository
  participant CheerRepo as CheerRepository
  participant TagRepo as CheerTagRepository

  Client->>Controller: POST /cheers (storeKakaoId, storeName, description, tags[])
  Controller->>Service: registerCheer(request)
  Service->>StoreRepo: findOrCreateStore(...)
  StoreRepo-->>Service: Store
  Service->>CheerRepo: save(Cheer)
  CheerRepo-->>Service: Cheer
  Service->>TagRepo: saveAll(toCheerTags(Cheer, request.tags))
  TagRepo-->>Service: List<CheerTag>
  Service-->>Controller: new CheerResponse(Cheer, cheerTags, Store, imageUrl)
  Controller-->>Client: 200 OK (with tags[])
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
응원 등록 API에서 태그까지 같이 저장하도록 변경 (#158)

Assessment against linked issues: Out-of-scope changes

(해당 없음)

Possibly related issues

Poem

새 태그 달린 응원 한 줄, 깡총깡총 띄워요
가게 빛을 모아모아, 해시처럼 묶어요 ✨
깃털 같은 리스트들, 빈값도 챙겨요
저장소로 폴짝! 응답으로 콩닥!
오늘도 토끼는 코드밭에 꽃태그를 심어요 🐰🌸

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7e727c1 and fb898f6.

📒 Files selected for processing (1)
  • src/test/java/eatda/controller/cheer/CheerControllerTest.java (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/test/java/eatda/controller/cheer/CheerControllerTest.java
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/PRODUCT-238

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link

📌 최신 ERD가 자동 생성되었습니다.

👉 ERD 보러가기

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
src/main/java/eatda/repository/cheer/CheerTagRepository.java (1)

6-8: 기본 JPA 리포지토리 추가 적절 — 선택적으로 조회 편의 메서드 제안

현재 요구사항에는 충분합니다. 향후 사용성을 높이려면 cheerId 기준 조회 메서드를 추가해도 좋습니다.

다음 메서드를 추가하면 컨트롤러/서비스에서 조회가 간결해집니다.

 package eatda.repository.cheer;

 import eatda.domain.cheer.CheerTag;
 import org.springframework.data.jpa.repository.JpaRepository;
+import java.util.List;

 public interface CheerTagRepository extends JpaRepository<CheerTag, Long> {
+    List<CheerTag> findAllByCheerId(Long cheerId);
 }
src/main/java/eatda/domain/cheer/CheerTagName.java (1)

24-24: 불필요한 세미콜론 제거 필요

enum 정의 끝에 불필요한 세미콜론이 있습니다.

-    MANY_NEARBY_ATTRACTIONS(CheerTagCategory.PRACTICAL);
-    ;
+    MANY_NEARBY_ATTRACTIONS(CheerTagCategory.PRACTICAL);
src/main/java/eatda/domain/cheer/CheerTagNames.java (2)

19-26: 유효성 검사 로직 개선 제안

유효성 검사가 두 개의 별도 메서드로 잘 분리되어 있지만, 성능을 개선할 수 있습니다.

다음과 같이 리팩터링하여 중복 스트림 연산을 줄일 수 있습니다:

 private void validate(List<CheerTagName> cheerTagNames) {
-    if (isDuplicated(cheerTagNames)) {
-        throw new BusinessException(BusinessErrorCode.CHEER_TAGS_DUPLICATED);
-    }
-    if (countMaxCountByType(cheerTagNames) > MAX_CHEER_TAGS_PER_TYPE) {
-        throw new BusinessException(BusinessErrorCode.EXCEED_CHEER_TAGS_PER_TYPE);
-    }
+    Map<CheerTagType, Long> countByType = cheerTagNames.stream()
+        .collect(Collectors.groupingBy(CheerTagName::getType, Collectors.counting()));
+    
+    if (countByType.values().stream().mapToLong(Long::longValue).sum() != cheerTagNames.size()) {
+        throw new BusinessException(BusinessErrorCode.CHEER_TAGS_DUPLICATED);
+    }
+    
+    if (countByType.values().stream().max(Long::compareTo).orElse(0L) > MAX_CHEER_TAGS_PER_TYPE) {
+        throw new BusinessException(BusinessErrorCode.EXCEED_CHEER_TAGS_PER_TYPE);
+    }
 }

12-12: 필드 접근 제한자 개선 제안

cheerTagNames 필드를 private final로 선언하여 불변성을 보장하는 것이 좋습니다.

- private List<CheerTagName> cheerTagNames;
+ private final List<CheerTagName> cheerTagNames;
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc9036f and c6df6e4.

📒 Files selected for processing (18)
  • src/main/java/eatda/controller/cheer/CheerRegisterRequest.java (1 hunks)
  • src/main/java/eatda/controller/cheer/CheerResponse.java (1 hunks)
  • src/main/java/eatda/domain/cheer/CheerTag.java (1 hunks)
  • src/main/java/eatda/domain/cheer/CheerTagName.java (1 hunks)
  • src/main/java/eatda/domain/cheer/CheerTagNames.java (1 hunks)
  • src/main/java/eatda/exception/BusinessErrorCode.java (2 hunks)
  • src/main/java/eatda/repository/cheer/CheerTagRepository.java (1 hunks)
  • src/main/java/eatda/service/cheer/CheerService.java (2 hunks)
  • src/main/resources/db/migration/V6__add_cheer_tag_table.sql (1 hunks)
  • src/main/resources/db/seed/dev/V7__dev_add_tag_data.sql (1 hunks)
  • src/main/resources/db/seed/local/V7__local_add_tag_data.sql (1 hunks)
  • src/main/resources/db/seed/prod/V7__prod_add_tag_data.sql (1 hunks)
  • src/test/java/eatda/controller/BaseControllerTest.java (2 hunks)
  • src/test/java/eatda/controller/cheer/CheerControllerTest.java (3 hunks)
  • src/test/java/eatda/document/store/CheerDocumentTest.java (3 hunks)
  • src/test/java/eatda/domain/cheer/CheerTagNamesTest.java (1 hunks)
  • src/test/java/eatda/service/BaseServiceTest.java (2 hunks)
  • src/test/java/eatda/service/cheer/CheerServiceTest.java (9 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/java/eatda/service/cheer/CheerService.java (1)
src/main/java/eatda/domain/cheer/CheerTagNames.java (1)
  • CheerTagNames (8-49)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (41)
src/main/resources/db/migration/V6__add_cheer_tag_table.sql (1)

3-5: 엔티티 매핑과 컬럼 정의 일치 여부 확인

name 컬럼이 VARCHAR(63)으로 정의되어 있습니다. JPA 엔티티에서 Enum을 저장할 때 @Enumerated(EnumType.STRING)을 사용하고, 필요 시 @Column(length = 63)로 길이를 명시했는지 확인해 주세요. 길이 불일치 시 스키마 검증이나 마이그레이션 시 경고가 발생할 수 있습니다.

src/main/resources/db/seed/prod/V7__prod_add_tag_data.sql (1)

1-1: Prod 시드 생략 의도 및 실행기 동작 확인 필요

파일이 주석만 포함하고 있어 실행 시 아무 작업도 하지 않습니다. 환경별 시드 실행기가 빈 파일(주석만 있는 파일)을 허용하는지, 또는 Prod 환경에서 시드 대상 스크립트로 인식되지 않는지 확인해 주세요. 불필요한 빈 실행으로 인한 배포 파이프라인 경고를 방지할 수 있습니다.

src/main/resources/db/seed/local/V7__local_add_tag_data.sql (1)

1-12: 시드 태그·Enum·cheer_id 무결성 검증 완료

  • 로컬 시드(V7__local_add_tag_data.sql)에 사용된 모든 태그가 CheerTagName enum 상수와 완전히 일치합니다.
  • cheer_id(1,2,4,5,6,7) 역시 로컬/개발 시드에 모두 정의되어 있어 누락이 없습니다.
  • enum에만 존재하는 추가 상수(ENERGETIC, GOOD_FOR_DRINKING, GROUP_RESERVATION, LARGE_PARKING, OLD_STORE_MOOD, PET_FRIENDLY, YOUTUBE_FAMOUS)는 정보용이며, 현재 시드에 반드시 반영할 필요는 없습니다.

이상으로 더 이상 조치가 필요하지 않습니다.

src/main/resources/db/seed/dev/V7__dev_add_tag_data.sql (1)

1-12: dev 시드에서도 Enum/Seed 일치성 및 cheer_id 유효성 검증 필요

로컬 시드와 동일하게 아래 사항을 dev 경로에 대해서도 확인해 주세요:

  • CheerTagName(Enum)과 src/main/resources/db/seed/dev/V7__dev_add_tag_data.sql에 정의된 태그 목록이 완전히 일치하는지
  • V7__dev_add_tag_data.sql에서 참조하는 cheer_id 값들이 실제 dev용 cheer 엔티티 시드 파일(cheer 데이터를 삽입하는 SQL)에 모두 존재하는지

현재 dev용 cheer 엔티티 시드 파일이 확인되지 않아 자동 스크립트 검증이 불가했습니다. 파일명을 다시 한 번 확인하신 뒤, 위 두 가지 항목을 수동으로 점검 부탁드립니다.

src/main/java/eatda/exception/BusinessErrorCode.java (1)

32-35: 응원 태그 관련 에러 코드 추가 적절

중복 방지(CHEER_TAGS_DUPLICATED) 및 타입별 최대 개수 초과(EXCEED_CHEER_TAGS_PER_TYPE)를 Bad Request로 표준화한 점 좋습니다. 서비스/도메인에서 해당 코드로 일관되게 예외를 변환하는지 테스트로 보강되었는지 확인만 부탁드립니다.

src/test/java/eatda/controller/BaseControllerTest.java (1)

23-24: 테스트 인프라에 CheerTagRepository 주입 추가 적절

태그 기능 테스트를 위한 리포지토리 주입이 베이스 테스트에 포함되어 있어 재사용성이 좋습니다.

Also applies to: 81-83

src/test/java/eatda/service/BaseServiceTest.java (1)

15-16: 서비스 테스트 기반에 CheerTagRepository 주입 추가 적절

서비스 계층에서 태그 저장/검증을 다루는 테스트에 필요한 의존성이 잘 반영되었습니다.

Also applies to: 75-77

src/test/java/eatda/controller/cheer/CheerControllerTest.java (2)

8-8: import문 추가가 적절하게 처리됨

새로운 태그 기능을 위한 CheerTagNameList import가 올바르게 추가되었습니다.

Also applies to: 14-14


27-28: 테스트에서 태그 목록 전달이 올바르게 구현됨

CheerRegisterRequest 생성자의 새로운 시그니처에 맞춰 태그 목록을 전달하고 있으며, 두 개의 서로 다른 태그(GOOD_FOR_DATING, CLEAN_RESTROOM)를 사용하여 태그 기능을 적절히 테스트하고 있습니다.

Also applies to: 47-48

src/test/java/eatda/domain/cheer/CheerTagNamesTest.java (3)

21-26: 카테고리별 최대 개수 검증 테스트가 올바름

각 카테고리(MOOD, PRACTICAL)에서 2개씩 총 4개의 태그를 사용하여 정상 케이스를 테스트하고 있습니다. 비즈니스 로직에 따른 적절한 테스트입니다.


37-43: 카테고리별 최대 개수 초과 검증이 정확함

MOOD 카테고리에서 3개의 태그를 사용하여 최대 개수(2개) 초과 시 예외가 발생하는지 확인하고 있으며, 올바른 에러 코드를 검증하고 있습니다.


47-52: 중복 태그 검증이 적절히 구현됨

동일한 태그를 중복으로 사용했을 때 CHEER_TAGS_DUPLICATED 예외가 발생하는지 확인하는 테스트가 올바르게 작성되었습니다.

src/main/java/eatda/service/cheer/CheerService.java (4)

11-12: 새로운 의존성 추가가 적절함

태그 기능을 위한 CheerTag, CheerTagNames, CheerTagRepository import가 올바르게 추가되었습니다.

Also applies to: 19-19


38-38: CheerTagRepository 의존성 주입이 올바름

새로운 태그 기능을 위한 리포지토리가 적절히 주입되었습니다.


46-46: 태그 검증 로직이 적절한 위치에 배치됨

요청에서 태그를 추출하여 CheerTagNames로 변환하면서 검증을 수행하는 것이 비즈니스 로직 관점에서 올바른 위치입니다.


53-54: 태그 저장 및 응답 생성 로직이 올바름

응원 저장 후 태그들을 저장하고, 저장된 태그들을 포함하여 응답을 생성하는 흐름이 적절합니다. 트랜잭션 내에서 일관성 있게 처리되고 있습니다.

src/test/java/eatda/service/cheer/CheerServiceTest.java (3)

13-13: 테스트용 import 추가가 적절함

태그 기능 테스트를 위한 CheerTagNameList import가 올바르게 추가되었습니다.

Also applies to: 22-22


45-46: 모든 테스트에서 태그 파라미터가 일관되게 적용됨

모든 CheerRegisterRequest 생성에서 동일한 태그 목록(GOOD_FOR_DATING, CLEAN_RESTROOM)을 사용하여 일관성 있는 테스트가 작성되었습니다.

Also applies to: 64-65, 81-82, 105-106, 129-130


95-97: 태그 응답 검증이 올바르게 구현됨

response.tags()에 대해 containsExactlyInAnyOrder를 사용하여 순서에 관계없이 태그가 올바르게 반환되는지 검증하고 있어 적절한 테스트 방식입니다.

Also applies to: 120-122, 143-145

src/main/java/eatda/domain/cheer/CheerTagName.java (2)

8-23: 태그 분류가 비즈니스 요구사항에 적합함

MOOD와 PRACTICAL로 태그를 분류하고 각 카테고리에 적절한 태그들을 정의했습니다. 실제 음식점 응원 서비스에서 사용할 수 있는 의미 있는 태그들로 구성되어 있습니다.


32-34: 중첩 enum 정의가 적절함

CheerTagCategory를 중첩 enum으로 정의하여 관련 타입들을 한 곳에서 관리할 수 있도록 한 설계가 좋습니다.

src/test/java/eatda/document/store/CheerDocumentTest.java (3)

26-26: 문서화 테스트를 위한 import 추가가 올바름

API 문서 생성을 위해 CheerTagName import가 적절히 추가되었습니다.


71-72: API 문서에 태그 필드가 올바르게 추가됨

요청과 응답 모두에 태그 필드가 ARRAY 타입으로 문서화되어 API 사용자가 이해하기 쉽게 작성되었습니다.

Also applies to: 80-81


86-89: 문서화 테스트에서 태그가 일관되게 사용됨

성공 케이스와 실패 케이스 모두에서 동일한 태그 목록을 사용하여 문서의 일관성이 유지되었습니다.

Also applies to: 118-119

src/main/java/eatda/controller/cheer/CheerResponse.java (3)

4-7: 새로운 태그 기능을 위한 타입 추가가 적절함

CheerTag, CheerTagName, List import와 record에 tags 필드 추가가 올바르게 구현되었습니다.

Also applies to: 14-14


17-25: 생성자 시그니처 변경이 적절함

CheerTag 리스트를 받아서 CheerTagName 리스트로 변환하는 생성자로 변경되어 도메인 계층과 프레젠테이션 계층 간의 적절한 분리가 이루어졌습니다.


27-31: 헬퍼 메서드가 깔끔하게 구현됨

CheerTag에서 CheerTagName으로 변환하는 로직이 별도 메서드로 분리되어 코드 가독성이 좋습니다.

src/main/java/eatda/controller/cheer/CheerRegisterRequest.java (3)

3-5: 새로운 기능을 위한 import가 적절함

태그 기능 구현을 위한 필요한 import들이 올바르게 추가되었습니다.


11-11: record에 태그 필드 추가가 올바름

List<CheerTagName> tags 필드가 적절하게 추가되어 API 확장이 이루어졌습니다.


14-20: null 안전성 처리가 적절함

클라이언트에서 태그를 전달하지 않을 경우를 대비한 null 체크와 빈 리스트 반환이 올바르게 구현되었습니다. TODO 주석도 향후 작업 계획을 명확하게 보여줍니다.

src/main/java/eatda/domain/cheer/CheerTag.java (5)

1-17: 적절한 패키지 구조와 import 구성

JPA 엔티티에 필요한 모든 import가 적절히 구성되어 있고, 패키지 구조도 도메인별로 잘 정리되어 있습니다.


18-21: JPA 엔티티 어노테이션 설정 확인

테이블 매핑과 Lombok 어노테이션이 적절히 설정되어 있습니다. @NoArgsConstructor(access = AccessLevel.PROTECTED)는 JPA 요구사항과 도메인 무결성을 모두 만족합니다.


24-26: 기본 키 전략 적절함

GenerationType.IDENTITY 전략이 적절히 설정되어 있습니다.


32-34: 열거형 저장 방식과 컬럼 제약 조건 적절함

@Enumerated(EnumType.STRING) 사용으로 데이터베이스 호환성을 보장하고, length=63 제약으로 적절한 크기를 설정했습니다.


36-39: 생성자 구현 적절함

필수 필드만을 받는 생성자가 잘 구현되어 있으며, 도메인 객체 생성 시 무결성을 보장합니다.

src/main/java/eatda/domain/cheer/CheerTagNames.java (6)

1-7: import 구성 적절함

필요한 모든 클래스가 적절히 import되어 있습니다.


10-10: 상수값 검증 필요

MAX_CHEER_TAGS_PER_TYPE = 2로 설정되어 있는데, 이 값이 비즈니스 요구사항과 일치하는지 확인이 필요합니다.

해당 상수값이 올바른 비즈니스 룰인지 문서나 이슈를 통해 확인해주세요. 2개가 적절한 최대값인지 검증이 필요합니다.


14-17: 생성자에서 방어적 복사 적절함

입력 유효성 검사 후 List.copyOf()를 사용한 방어적 복사가 잘 구현되어 있습니다.


28-33: 중복 검사 로직 올바름

distinct() 연산 후 크기 비교를 통한 중복 검사 로직이 정확합니다.


35-42: 타입별 최대 개수 계산 로직 올바름

Collectors.groupingBycounting()을 사용한 타입별 개수 계산과 최대값 추출 로직이 정확합니다.


44-48: CheerTag 생성 로직 적절함

스트림을 사용하여 각 태그 이름을 CheerTag 엔티티로 변환하는 로직이 깔끔하게 구현되어 있습니다.

@leegwichan
Copy link
Member Author

Docs에 태그 종류 마크타운 형식으로 정리해서 추가 예정

Copy link
Member

@lvalentine6 lvalentine6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번 PR도 고생하셨습니다! 🧇
몇가지 코멘트를 남겼는데 선택적으로 반영해주세요!!

.orElseGet(() -> storeRepository.save(result.toStore())); // TODO 상점 조회/저장 동시성 이슈 해결
Cheer cheer = cheerRepository.save(new Cheer(member, store, request.description(), imageKey));
return new CheerResponse(cheer, imageStorage.getPreSignedUrl(imageKey), store);
List<CheerTag> cheerTags = cheerTagRepository.saveAll(cheerTagNames.toCheerTags(cheer));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[선택 및 질문]
지금 방식도 충분히 좋지만 영속성 전이를 이용하는것도 좋을것 같은데 어떻게 생각하시는지 의견이 궁금해요 😄

## Cheer 엔티티
@OneToMany(mappedBy = "cheer", cascade = CascadeType.ALL, orphanRemoval = true)
private List<CheerTag> cheerTags = new ArrayList<>();

public void addTags(CheerTagNames cheerTagNames) {
    List<CheerTag> newTags = cheerTagNames.toCheerTags(this);
    this.cheerTags.addAll(newTags);
}
사용
Cheer cheer = new Cheer(member, store, request.description(), imageKey);
cheer.addTags(cheerTagNames);
cheerRepository.save(cheer);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 일단은 조회 시에도 N+1 문제가 발생할 것 같아요. (물론 최적화가 안된 부분도 많아서 크게 상관 없을 수 있지만요)
  2. 영속성 전이를 코드를 간결하게 사용할 수 있다는 면에서 좋다고 생각해요! 하지만 특정 부분을 사용할 때마다 SQL이 어떻게 나가는지가 예측하기 어렵다는 단점이 있다고 생각합니다. 그래서 일단은 익숙한 방식으로 빠르게 구현했습니다.

저도 코드를 간결하게 작성하는 것을 좋아하는 입장에서 선호합니다! 하지만 이것을 사용하려면 테스트를 진행하면서 SQL이 최적화된 상태로 나가는지 체크해야 되는 복잡함이 있다고 생각합니다.
그래서 일단은 기존의 OneToMany를 사용해서 빠르게 구현하고, 추후 빠르게 개선하도록 하겠습니다!

if (tags == null) {
return Collections.emptyList();
}
return tags;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[선택]
접근자 오버라이드도 좋지만 컴펙트 생성자를 만들어서 처리하는건 어떨까요??

public CheerRegisterRequest {
        if (tags == null) {
            tags = Collections.emptyList();
        }
    }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ObjectMapper를 이용해서 Request Body JSON을 CheerRegisterRequest로 파싱하는 것으로 알고 있습니다.
ObjectMapper의 구현 방식에 따라서 필도로 주입하기도 하고, 생성자를 이용해 주입하기도 해서 아마 내부 구현이 어떤지에 따라 의도한대로 작동할 수도 안할수도 있다고 알고 있습니다.

그래서 Record의 getter를 이용해서 오버라이딩하여 일시적으로 처리했습니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/test/java/eatda/controller/cheer/CheerControllerTest.java (2)

27-30: 태그 리스트 중복 생성 제거 및 케이스 확장 제안

현재 테스트 내에서 동일한 태그 리스트를 여러 곳에서 직접 생성하고 있습니다. 가독성과 유지보수를 위해 상단에 지역 변수로 추출하거나 공용 헬퍼로 분리하는 것을 권장합니다.

다음과 같이 간단히 정리할 수 있습니다:

-            Store store = storeGenerator.generate("123", "서울시 노원구 월계3동 123-45");
-            CheerRegisterRequest request = new CheerRegisterRequest(store.getKakaoId(), store.getName(), "맛있어요!",
-                    List.of(CheerTagName.INSTAGRAMMABLE, CheerTagName.CLEAN_RESTROOM));
+            Store store = storeGenerator.generate("123", "서울시 노원구 월계3동 123-45");
+            List<CheerTagName> tags = List.of(CheerTagName.INSTAGRAMMABLE, CheerTagName.CLEAN_RESTROOM);
+            CheerRegisterRequest request = new CheerRegisterRequest(
+                    store.getKakaoId(), store.getName(), "맛있어요!", tags);

추가로 제안:

  • 태그가 빈 배열([]) 혹은 null인 경우도 등록이 정상 동작하는지 테스트 케이스를 보강해 주세요. 본 PR에서 DTO가 null 가드를 제공한다고 하였으므로, 이를 회귀 테스트로 고정하면 좋습니다.
  • 의도적으로 2-파라미터 storeGenerator.generate(주소만) 호출과 3-파라미터(구/동 포함) 호출을 섞어 사용하신 것이라면 주석으로 의도를 남기거나 한 형태로 통일하는 것을 권장합니다.

원하시면 null/빈 태그 케이스 테스트 메서드 초안을 함께 드리겠습니다.


52-54: 중복 코드 최소화 제안 (태그 리스트 상수/헬퍼화)

두 테스트에서 동일 태그 리스트를 중복 생성합니다. 지역 변수 추출 또는 테스트 클래스의 private 헬퍼 메서드로 공통화하면 유지보수성이 좋아집니다.

예시:

-            CheerRegisterRequest request = new CheerRegisterRequest(store.getKakaoId(), store.getName(), "맛있어요!",
-                    List.of(CheerTagName.INSTAGRAMMABLE, CheerTagName.CLEAN_RESTROOM));
+            List<CheerTagName> tags = List.of(CheerTagName.INSTAGRAMMABLE, CheerTagName.CLEAN_RESTROOM);
+            CheerRegisterRequest request = new CheerRegisterRequest(
+                    store.getKakaoId(), store.getName(), "맛있어요!", tags);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c6df6e4 and 7e727c1.

📒 Files selected for processing (4)
  • src/test/java/eatda/controller/BaseControllerTest.java (2 hunks)
  • src/test/java/eatda/controller/cheer/CheerControllerTest.java (4 hunks)
  • src/test/java/eatda/service/BaseServiceTest.java (2 hunks)
  • src/test/java/eatda/service/cheer/CheerServiceTest.java (9 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/test/java/eatda/controller/BaseControllerTest.java
  • src/test/java/eatda/service/cheer/CheerServiceTest.java
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: leegwichan
PR: YAPP-Github/26th-Web-Team-1-BE#159
File: src/main/java/eatda/domain/cheer/CheerTag.java:28-30
Timestamp: 2025-08-12T03:22:34.003Z
Learning: CheerTag와 Cheer 엔티티 간의 연관관계는 의도적으로 단방향 매핑(ManyToOne)으로 설계되었습니다. Cheer 엔티티에서 CheerTag 컬렉션으로의 양방향 매핑(OneToMany)은 불필요합니다.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (4)
src/test/java/eatda/service/BaseServiceTest.java (2)

14-14: CheerTagRepository import 추가 적절

태그 기능 테스트를 위한 레포지토리 의존성 추가, 방향성 일치합니다.


71-73: 확인: DatabaseCleaner가 CheerTag(cheer_tag) 테이블까지 정리합니다

src/test/java/eatda/DatabaseCleaner.java를 확인한 결과, INFORMATION_SCHEMA.TABLES에서 모든 테이블을 조회한 뒤 REFERENTIAL_INTEGRITY를 비활성화하고 각 테이블에 TRUNCATE TABLE %s RESTART IDENTITY를 실행합니다. 따라서 cheer_tag 테이블도 포함되어 테스트 간 FK 제약/중복 데이터로 인한 간섭 우려는 없습니다.

  • 확인한 파일: src/test/java/eatda/DatabaseCleaner.java
  • 검토 요청(권장): src/test/java/eatda/service/BaseServiceTest.java (71-73) — CheerTagRepository가 @Autowired 되어 있으므로, 테스트들이 Cheer 엔티티의 역방향 컬렉션(OneToMany)을 참조하지 않는지 한 번 더 확인해 주세요 (설계상 CheerTag → Cheer 단방향 매핑).
src/test/java/eatda/controller/cheer/CheerControllerTest.java (2)

8-8: 태그 enum import 반영 OK

요청/응답에 태그를 검증하기 위한 import 추가, 적절합니다.


15-15: 표준 컬렉션 import 반영 OK

테스트에서 태그 리스트 생성을 위해 필요한 import 추가, 문제 없습니다.

@sonarqubecloud
Copy link

@leegwichan leegwichan merged commit 8d683aa into develop Aug 15, 2025
4 checks passed
@leegwichan leegwichan deleted the feat/PRODUCT-238 branch August 15, 2025 08:57
@github-actions
Copy link

🎉 This PR is included in version 1.4.0-develop.83 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@github-actions
Copy link

🎉 This PR is included in version 1.8.0-develop.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@github-actions
Copy link

🎉 This PR is included in version 1.8.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[PRODUCT-238] [Feat] '응원 등록 API'에 응원 태그 추가

3 participants