-
Notifications
You must be signed in to change notification settings - Fork 0
[Feat] 스토리 상세 조회 기능 구현 #87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
""" Walkthrough이 변경사항은 Story API에 스토리 상세 조회 기능을 추가하고, 스토리 목록 조회에 페이지 크기(size) 파라미터를 도입하여 유연하게 조회할 수 있도록 했습니다. 또한, 관련 서비스 및 예외처리를 확장하고, 워크플로우 트리거 조건과 시드 데이터의 이미지 경로를 개선했습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Controller
participant Service
participant Repository
participant ImageService
Client->>Controller: GET /api/stories?size=5
Controller->>Service: getPagedStoryPreviews(size)
Service->>Repository: findStories(PageRequest.of(0, size))
Repository-->>Service: List<Story>
Service->>ImageService: getPresignedUrl(imageKey)
ImageService-->>Service: imageUrl
Service-->>Controller: StoriesResponse
Controller-->>Client: 200 OK + StoriesResponse
Client->>Controller: GET /api/stories/{storyId}
Controller->>Service: getStory(storyId)
Service->>Repository: findById(storyId)
alt Story exists
Repository-->>Service: Story
Service->>ImageService: getPresignedUrl(imageKey)
ImageService-->>Service: imageUrl
Service-->>Controller: StoryResponse
Controller-->>Client: 200 OK + StoryResponse
else Story not found
Repository-->>Service: null
Service-->>Controller: throws BusinessException(STORY_NOT_FOUND)
Controller-->>Client: 404 Not Found + ErrorResponse
end
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
📄 Terraform Plan Summary🛡️ Common InfrastructureStatus: ✅ No Changes 🛠️ Development EnvironmentStatus: ✅ No Changes 📋 Full Results: View in Actions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🔭 Outside diff range comments (1)
src/test/java/eatda/service/story/StoryServiceTest.java (1)
31-41: 중복된 서비스 초기화
StoryService가@Autowired로 주입받고 있으면서 동시에@BeforeEach에서 수동으로 생성하고 있습니다. 이는 혼란을 야기할 수 있으므로 하나의 방식만 사용해야 합니다.Spring 컨텍스트를 사용하는 경우:
- @BeforeEach - void setUp() { - storyService = new StoryService(storeService, imageService, storyRepository, memberRepository); - }또는 수동 초기화를 사용하는 경우:
- @Autowired private StoryService storyService;
🧹 Nitpick comments (2)
.github/workflows/sonarcloud.yml (1)
22-23: 전체 히스토리 체크아웃으로 Sonar 정확도 향상, 속도 영향 검토 필요
fetch-depth: 0을 추가해 전체 git 히스토리를 내려받도록 변경하신 점 👍 SonarCloud에서 blame 정보와 커버리지 히스토리를 제대로 잡는 데 도움이 됩니다.
다만 저장소가 커질수록 체크아웃 시간이 늘어날 수 있으니, 필요 시lfs: false설정이나 캐시 최적화도 함께 고려해 보세요..github/workflows/terraform-plan.yml (1)
5-6: 경로 필터로 불필요한 Terraform Plan 실행 방지—👍
paths조건을 추가해terraform/**,terraform-bootstrap/**변경 시에만 실행되도록 한 점이 CI 비용 절감에 효과적입니다.
추가로, 직접main브랜치에 push 되는 경우에도 Plan 확인이 필요하다면push:트리거에 동일한 필터를 넣는 방안도 검토해 주세요.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
.github/workflows/automatic-erd.yml(1 hunks).github/workflows/sonarcloud.yml(1 hunks).github/workflows/terraform-plan.yml(1 hunks)src/main/java/eatda/controller/story/StoryController.java(2 hunks)src/main/java/eatda/exception/BusinessErrorCode.java(1 hunks)src/main/java/eatda/service/story/StoryService.java(3 hunks)src/main/resources/db/seed/dev/V2__dev_init_data.sql(1 hunks)src/main/resources/db/seed/dev/V4__dev_add_story_data.sql(1 hunks)src/main/resources/db/seed/local/V2__local_init_data.sql(1 hunks)src/main/resources/db/seed/local/V4__local_add_story_data.sql(1 hunks)src/test/java/eatda/controller/story/StoryControllerTest.java(3 hunks)src/test/java/eatda/document/story/StoryDocumentTest.java(3 hunks)src/test/java/eatda/service/story/StoryServiceTest.java(4 hunks)
🧰 Additional context used
🧠 Learnings (4)
src/main/resources/db/seed/dev/V2__dev_init_data.sql (1)
Learnt from: lvalentine6
PR: YAPP-Github/26th-Web-Team-1-BE#76
File: src/main/java/eatda/domain/store/Cheer.java:50-61
Timestamp: 2025-07-15T09:42:54.091Z
Learning: Cheer 엔티티의 생성자는 데이터베이스 시딩을 위해 의도적으로 ID 매개변수를 받도록 설계되었습니다. 시드 데이터에서 명시적으로 ID를 설정하기 때문에 이 패턴이 필요합니다.
src/main/resources/db/seed/local/V2__local_init_data.sql (1)
Learnt from: lvalentine6
PR: YAPP-Github/26th-Web-Team-1-BE#76
File: src/main/java/eatda/domain/store/Cheer.java:50-61
Timestamp: 2025-07-15T09:42:54.091Z
Learning: Cheer 엔티티의 생성자는 데이터베이스 시딩을 위해 의도적으로 ID 매개변수를 받도록 설계되었습니다. 시드 데이터에서 명시적으로 ID를 설정하기 때문에 이 패턴이 필요합니다.
src/main/java/eatda/controller/story/StoryController.java (1)
Learnt from: leegwichan
PR: YAPP-Github/26th-Web-Team-1-BE#60
File: src/main/java/eatda/controller/store/StoreController.java:18-21
Timestamp: 2025-07-09T08:05:53.497Z
Learning: Spring Boot 컨트롤러에서 LoginMember 등의 인증 파라미터는 메서드 내에서 직접 사용되지 않더라도 접근 제어(인증된 사용자만 접근 가능)를 위해 필요할 수 있다. 이는 보안상 유효한 패턴이다.
src/test/java/eatda/controller/story/StoryControllerTest.java (1)
Learnt from: leegwichan
PR: YAPP-Github/26th-Web-Team-1-BE#60
File: src/test/java/eatda/controller/store/StoreControllerTest.java:10-32
Timestamp: 2025-07-09T07:56:50.612Z
Learning: 컨트롤러 테스트에서 MockitoBean으로 의존성을 모킹한 경우, 상세한 비즈니스 로직 검증보다는 컨트롤러 계층의 동작(라우팅, 파라미터 처리, 응답 구조 등)을 검증하는 것이 더 적절합니다. 모킹된 데이터에 대한 상세 검증은 의미가 없기 때문입니다.
🧬 Code Graph Analysis (1)
src/main/java/eatda/controller/story/StoryController.java (1)
src/main/java/eatda/controller/web/auth/AuthMemberArgumentResolver.java (1)
RequiredArgsConstructor(14-36)
🔇 Additional comments (12)
.github/workflows/automatic-erd.yml (1)
5-6: DB 마이그레이션 변경 시에만 ERD 생성—구현 적절
src/main/resources/db/migration/**경로로 한정하여 워크플로우 빈번 실행을 줄인 점 좋습니다.
특정 브랜치 외 타깃으로 ERD가 필요한 경우(예: hotfix)도 있을 수 있으니, 향후 필요 시 브랜치 배열에 추가만 하면 될 것 같습니다.src/main/resources/db/seed/dev/V2__dev_init_data.sql (2)
28-34: 이미지 경로 구조 개선이 잘 적용되었습니다cheer 테이블의 image_key 값들이 'default.jpg'에서 'cheer/dummy/N.jpg' 형태로 체계적으로 변경되어 카테고리별 이미지 관리가 가능해졌습니다. 각 레코드마다 고유한 이미지 파일을 참조하도록 개선되었습니다.
37-39: article 테이블의 이미지 경로 구조화가 완료되었습니다article 테이블의 image_key 값들이 일관되게 'article/dummy/N.jpg' 형태로 변경되어 cheer 테이블과 동일한 구조를 따르고 있습니다. 체계적인 이미지 관리를 위한 좋은 변경사항입니다.
src/main/resources/db/seed/local/V2__local_init_data.sql (1)
28-34: 로컬 환경 시드 데이터의 일관성 유지가 완료되었습니다개발 환경과 동일한 이미지 경로 구조로 변경되어 환경 간 일관성이 유지되었습니다. 이는 개발 및 테스트 과정에서 예상치 못한 차이를 방지하는 좋은 접근 방식입니다.
Also applies to: 37-39
src/main/java/eatda/exception/BusinessErrorCode.java (1)
50-50: HTTP 상태 코드가 의미론적으로 적절하게 수정되었습니다STORY_NOT_FOUND 에러에 HttpStatus.NOT_FOUND를 명시적으로 지정한 것은 RESTful API 설계 원칙에 부합하는 개선사항입니다. 존재하지 않는 리소스 조회 시 404 상태 코드를 반환하는 것이 표준적인 접근 방식입니다.
src/main/resources/db/seed/local/V4__local_add_story_data.sql (1)
3-9: 스토리 이미지 경로 구조가 일관되게 정리되었습니다'story/preview/'에서 'story/dummy/'로 변경되어 다른 테이블들과 동일한 네이밍 컨벤션을 따르게 되었습니다. 모든 스토리 레코드가 일관되게 업데이트되어 체계적인 이미지 관리가 가능해졌습니다.
src/main/resources/db/seed/dev/V4__dev_add_story_data.sql (1)
3-5: 개발 환경 스토리 데이터의 일관성이 유지되었습니다로컬 환경과 동일한 이미지 경로 구조로 변경되어 환경 간 일관성이 확보되었습니다. 'story/dummy/' 경로 사용으로 다른 테이블들과 통일된 네이밍 컨벤션을 따르고 있습니다.
src/main/java/eatda/service/story/StoryService.java (1)
84-97: 구현이 적절합니다!스토리 상세 조회 메서드가 표준 패턴을 잘 따르고 있으며, 에러 처리도 적절합니다.
src/main/java/eatda/controller/story/StoryController.java (2)
34-38: 페이지네이션 파라미터 추가가 적절합니다!size 파라미터의 검증 조건과 기본값 설정이 적절하며, 공개 엔드포인트로 인증이 필요 없는 것도 타당합니다.
40-44: 스토리 상세 조회 엔드포인트가 잘 구현되었습니다!RESTful 규칙을 잘 따르고 있으며, 공개 엔드포인트로 구현한 것이 적절합니다.
src/test/java/eatda/service/story/StoryServiceTest.java (1)
121-161: 스토리 상세 조회 테스트가 잘 작성되었습니다!성공 케이스와 실패 케이스를 모두 포함하여 포괄적인 테스트 커버리지를 제공합니다.
src/test/java/eatda/controller/story/StoryControllerTest.java (1)
82-130: GetStory 테스트 클래스가 잘 구성되었습니다!성공 케이스와 404 에러 케이스를 모두 다루며, 컨트롤러의 실제 동작과 일치하는 테스트를 제공합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
.github/workflows/terraform-plan.yml (1)
3-7: Terraform 코드로 한정된 트리거 필터 👍 — 루트 위치.tf파일 여부만 재확인 권장
paths필터로 워크플로우 실행이 Terraform 디렉터리 변경 시에만 일어나도록 제한한 점은 빌드 자원 절약에 도움이 됩니다. 다만 레포 루트나 다른 위치에.tf파일이 존재할 가능성이 있다면 추가 패턴을 포함할지 검토해 주세요..github/workflows/automatic-erd.yml (1)
3-7: ERD 자동 생성 워크플로우 범위를 마이그레이션 스크립트 변경으로 한정필요한 경우에만 실행되도록 최적화된 점 좋습니다. 다만 PR 단위로만 실행되므로
main/develop에 직접 커밋되는 경우 ERD 페이지가 갱신되지 않을 수 있습니다. 병합 이후 최신 ERD를 보장하려면push트리거(같은 경로 필터 포함) 추가를 고려해 보세요.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
.github/workflows/automatic-erd.yml(1 hunks).github/workflows/sonarcloud.yml(1 hunks).github/workflows/terraform-plan.yml(1 hunks)src/main/java/eatda/controller/story/StoryController.java(2 hunks)src/main/java/eatda/exception/BusinessErrorCode.java(1 hunks)src/main/java/eatda/service/story/StoryService.java(3 hunks)src/main/resources/db/seed/dev/V2__dev_init_data.sql(1 hunks)src/main/resources/db/seed/dev/V4__dev_add_story_data.sql(1 hunks)src/main/resources/db/seed/local/V2__local_init_data.sql(1 hunks)src/main/resources/db/seed/local/V4__local_add_story_data.sql(1 hunks)src/test/java/eatda/controller/story/StoryControllerTest.java(3 hunks)src/test/java/eatda/document/story/StoryDocumentTest.java(3 hunks)src/test/java/eatda/service/story/StoryServiceTest.java(4 hunks)
🧰 Additional context used
🧠 Learnings (4)
src/main/resources/db/seed/local/V2__local_init_data.sql (1)
Learnt from: lvalentine6
PR: YAPP-Github/26th-Web-Team-1-BE#76
File: src/main/java/eatda/domain/store/Cheer.java:50-61
Timestamp: 2025-07-15T09:42:54.091Z
Learning: Cheer 엔티티의 생성자는 데이터베이스 시딩을 위해 의도적으로 ID 매개변수를 받도록 설계되었습니다. 시드 데이터에서 명시적으로 ID를 설정하기 때문에 이 패턴이 필요합니다.
src/main/resources/db/seed/dev/V2__dev_init_data.sql (1)
Learnt from: lvalentine6
PR: YAPP-Github/26th-Web-Team-1-BE#76
File: src/main/java/eatda/domain/store/Cheer.java:50-61
Timestamp: 2025-07-15T09:42:54.091Z
Learning: Cheer 엔티티의 생성자는 데이터베이스 시딩을 위해 의도적으로 ID 매개변수를 받도록 설계되었습니다. 시드 데이터에서 명시적으로 ID를 설정하기 때문에 이 패턴이 필요합니다.
src/main/java/eatda/controller/story/StoryController.java (1)
Learnt from: leegwichan
PR: YAPP-Github/26th-Web-Team-1-BE#60
File: src/main/java/eatda/controller/store/StoreController.java:18-21
Timestamp: 2025-07-09T08:05:53.497Z
Learning: Spring Boot 컨트롤러에서 LoginMember 등의 인증 파라미터는 메서드 내에서 직접 사용되지 않더라도 접근 제어(인증된 사용자만 접근 가능)를 위해 필요할 수 있다. 이는 보안상 유효한 패턴이다.
src/test/java/eatda/controller/story/StoryControllerTest.java (1)
Learnt from: leegwichan
PR: YAPP-Github/26th-Web-Team-1-BE#60
File: src/test/java/eatda/controller/store/StoreControllerTest.java:10-32
Timestamp: 2025-07-09T07:56:50.612Z
Learning: 컨트롤러 테스트에서 MockitoBean으로 의존성을 모킹한 경우, 상세한 비즈니스 로직 검증보다는 컨트롤러 계층의 동작(라우팅, 파라미터 처리, 응답 구조 등)을 검증하는 것이 더 적절합니다. 모킹된 데이터에 대한 상세 검증은 의미가 없기 때문입니다.
🧬 Code Graph Analysis (1)
src/main/java/eatda/controller/story/StoryController.java (1)
src/main/java/eatda/controller/web/auth/AuthMemberArgumentResolver.java (1)
RequiredArgsConstructor(14-36)
🔇 Additional comments (21)
.github/workflows/sonarcloud.yml (1)
22-24: SonarCloud 분석을 위한fetch-depth: 0설정 환영전체 Git 히스토리를 가져오면 Sonar 추적(블레임)·커버리지 기준선 계산이 정확해집니다. CI 시간/트래픽 증가가 미미하다면 그대로 유지해도 무방합니다.
src/main/resources/db/seed/dev/V4__dev_add_story_data.sql (1)
3-5: 이미지 경로 통일로 더 나은 개발 환경 제공image_key 값을 'story/dummy/' 경로로 통일하여 더 실제적인 dummy 이미지를 사용하도록 개선하였습니다. 이는 스토리 상세 조회 기능과 함께 더 나은 개발 환경을 제공할 것으로 보입니다.
src/main/resources/db/seed/local/V4__local_add_story_data.sql (1)
3-9: 환경간 이미지 경로 일관성 확보로컬 환경의 시드 데이터도 개발 환경과 동일하게 'story/dummy/' 경로로 통일하여 환경간 일관성을 확보했습니다. 이는 개발 과정에서 환경간 차이로 인한 혼란을 줄이는 좋은 접근입니다.
src/main/resources/db/seed/dev/V2__dev_init_data.sql (2)
28-34: 응원(Cheer) 데이터의 이미지 경로 개선'default.jpg'에서 'cheer/dummy/' 경로로 변경하여 더 구체적이고 실제적인 이미지 경로를 제공합니다. 이는 개발 환경에서 더 나은 시각적 피드백을 제공할 것입니다.
37-39: 기사(Article) 데이터의 이미지 경로 개선기사 데이터의 이미지 경로도 'article/dummy/' 경로로 통일하여 전체적인 이미지 경로 구조를 일관성 있게 개선했습니다.
src/main/resources/db/seed/local/V2__local_init_data.sql (2)
28-34: 로컬 환경 응원 데이터의 이미지 경로 통일개발 환경과 동일하게 'cheer/dummy/' 경로로 통일하여 환경간 일관성을 확보했습니다. 이는 개발 과정에서 환경 전환 시 발생할 수 있는 혼란을 줄입니다.
37-39: 로컬 환경 기사 데이터의 이미지 경로 통일기사 데이터의 이미지 경로도 개발 환경과 동일하게 'article/dummy/' 경로로 통일했습니다. 전체적인 이미지 경로 구조의 일관성을 유지하는 좋은 접근입니다.
src/main/java/eatda/exception/BusinessErrorCode.java (1)
50-50: 스토리 미발견 에러의 HTTP 상태 코드 개선
STORY_NOT_FOUND에러 코드에 명시적으로HttpStatus.NOT_FOUND(404)를 설정하여 REST API 표준을 준수하도록 개선했습니다. 존재하지 않는 리소스에 대한 요청 시 적절한 HTTP 상태 코드를 반환하여 클라이언트가 더 명확하게 에러 상황을 파악할 수 있습니다.src/main/java/eatda/controller/story/StoryController.java (3)
5-6: validation 어노테이션 import가 적절합니다.Min, Max 어노테이션을 사용하여 size 파라미터의 범위를 적절히 제한했습니다.
35-38: pagination 기능 구현이 잘 되었습니다.size 파라미터에 적절한 validation (최소 1, 최대 50)과 기본값 5를 설정했습니다. 서비스 레이어로 파라미터를 전달하는 것도 올바릅니다.
40-44: 새로운 상세 조회 엔드포인트가 잘 구현되었습니다.PathVariable을 사용하여 storyId를 받고, 서비스 레이어의 getStory 메소드를 호출하는 구조가 적절합니다.
src/main/java/eatda/service/story/StoryService.java (2)
70-71: 동적 페이지 크기 지원이 잘 구현되었습니다.하드코딩된 PAGE_SIZE 대신 파라미터로 받은 size를 사용하여 유연성이 향상되었습니다.
84-97: 새로운 스토리 상세 조회 기능이 잘 구현되었습니다.
@Transactional(readOnly = true)어노테이션 적절히 사용- Optional을 사용한 예외 처리가 올바름
- StoryResponse 객체 생성 시 필요한 모든 필드 포함
- imageService를 통한 presigned URL 생성 로직 적절함
src/test/java/eatda/service/story/StoryServiceTest.java (3)
38-41: 테스트 초기화가 개선되었습니다.@beforeeach 메소드를 사용하여 중복된 초기화 코드를 제거하고 테스트 구조를 개선했습니다.
106-117: 기존 테스트 업데이트가 적절합니다.
- size 파라미터(5) 추가로 새로운 메소드 시그니처에 맞춤
- 이미지 URL 변경사항 반영
containsExactlyInAnyOrder사용으로 순서에 무관한 검증 수행
121-161: 새로운 GetStory 테스트 클래스가 잘 구현되었습니다.
- 성공 시나리오: 모든 필드를 검증하여 완전성 확보
- 실패 시나리오: 존재하지 않는 ID에 대한 예외 처리 검증
- 테스트 데이터가 현실적이고 의미있음
- 이미지 서비스 모킹 적절함
src/test/java/eatda/document/story/StoryDocumentTest.java (2)
163-171: 기존 문서화 테스트 업데이트가 적절합니다.getPagedStoryPreviews 메소드에 size 파라미터(5)를 추가하고 요청에 queryParam을 포함시켜 새로운 API 스펙을 올바르게 반영했습니다.
179-253: 새로운 스토리 상세 조회 API 문서화가 완벽합니다.
- 요청/응답 메타데이터 완전함
- 모든 응답 필드에 대한 설명 포함
- 성공 시나리오에서 모든 필드 검증
- 실패 시나리오에서 적절한 에러 응답 검증
- RestDocs 문서 생성을 위한 설정 완료
src/test/java/eatda/controller/story/StoryControllerTest.java (3)
29-53: 테스트 구조 개선이 잘 되었습니다.nested 클래스로 테스트를 구성하여 가독성과 유지보수성이 향상되었습니다.
55-80: 스토리 목록 조회 테스트가 적절합니다.
- size 파라미터(5) 추가로 새로운 API 스펙 반영
- 모킹된 응답 데이터 검증
- 응답 구조와 데이터 검증 적절함
82-130: 새로운 스토리 상세 조회 테스트가 완벽합니다.
- 성공 시나리오: 모든 응답 필드 검증
- 실패 시나리오: 404 응답과 에러 메시지 검증
- pathParam 사용으로 RESTful API 패턴 올바르게 테스트
- 모킹과 검증 로직 적절함
leegwichan
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/noti 정말 API 공장처럼 찍어내고 계시네요 ㅋㅋ
제안 사항, 수정 사항 남겼으니 확인 부탁드릴께요!
|
|
||
| @GetMapping("api/stories") | ||
| public ResponseEntity<StoriesResponse> getStories() { | ||
| public ResponseEntity<StoriesResponse> getStories(@RequestParam(defaultValue = "5") @Min(1) @Max(50) int size) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
| public StoriesResponse getPagedStoryPreviews(int size) { | ||
| Pageable pageable = PageRequest.of(PAGE_START_NUMBER, size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[제안] Pageable에 이런 게 있더라구요!
| public StoriesResponse getPagedStoryPreviews(int size) { | |
| Pageable pageable = PageRequest.of(PAGE_START_NUMBER, size); | |
| public StoriesResponse getPagedStoryPreviews(int size) { | |
| Pageable pageable = PageRequest.of(Pageable.ofSize(size)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋은 제안 감사합니다!
컴파일 에러가 나는데 어엄.. 이 방식을 말씀하신거겠죠??
Pageable pageable = Pageable.ofSize(size);
1차 배포후에 다른 페이지가 필요하다고 할수도 있으니... 지금은 이대로 가겠습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- V2 파일 바뀌었으니, 머지하지 전에 개발 DB 리셋 한 번 부탁드려요!
- 그리고 개발 DB 리셋하면 FE 한테도 알려주면 좋을 것 같아요!
| @BeforeEach | ||
| void setUp() { | ||
| storyService = new StoryService(storeService, imageService, storyRepository, memberRepository); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 부분 없어도 테스트 정상 작동 하지 않나요?
| Response response = given(document) | ||
| .pathParam("storyId", storyId) | ||
| .when() | ||
| .get("/api/stories/{storyId}"); | ||
|
|
||
| response.then() | ||
| .statusCode(200) | ||
| .body("storeKakaoId", equalTo("123456")) | ||
| .body("category", equalTo("한식")) | ||
| .body("storeName", equalTo("진또곱창집")) | ||
| .body("storeAddress", equalTo("서울특별시 성동구 성수동1가")) | ||
| .body("description", equalTo("곱창은 여기")) | ||
| .body("imageUrl", equalTo("https://s3.bucket.com/story1.jpg")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[제안] Document Test는 문서 작성을 위해서 만드는 테스트여서 statusCode(200) 까지만 검증해도 좋을 것 같은데, 승로님은 어떻게 생각하시나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋은 의견 감사합니다! 저도 문서 테스트의 검증 범위에 대해 다시 한번 생각해볼 수 있었는데요.
현재 컨트롤러 테스트가 별도로 존재하긴 하지만, 문서 테스트에서 응답 필드에 대한 상세 검증을 제거하면,
API 명세가 변경되었을 때 컨트롤러 테스트만 수정되고 문서는 갱신되지 않아
실제 구현과 문서 간 불일치가 생길 수 있어 추가를 해보았습니다ㅋㅋㅋ
약간의 중복은 있더라도, 문서 신뢰성과 구현 일치성을 동시에 보장할 수 있다는 점에서 지금 구조도 나쁘지 않은 선택인 것 같아요 😄
| Response response = given() | ||
| .queryParam("size", 5) | ||
| .when() | ||
| .get("/api/stories"); | ||
|
|
||
| response.then() | ||
| .statusCode(200) | ||
| .body("stories.size()", equalTo(2)) | ||
| .body("stories[0].storyId", equalTo(1)) | ||
| .body("stories[0].imageUrl", equalTo("https://s3.bucket.com/story/dummy/1.jpg")); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런 방식도 있어요!
| Response response = given() | |
| .queryParam("size", 5) | |
| .when() | |
| .get("/api/stories"); | |
| response.then() | |
| .statusCode(200) | |
| .body("stories.size()", equalTo(2)) | |
| .body("stories[0].storyId", equalTo(1)) | |
| .body("stories[0].imageUrl", equalTo("https://s3.bucket.com/story/dummy/1.jpg")); | |
| } | |
| StoriesResponse response = given() | |
| .queryParam("size", 5) | |
| .when() | |
| .get("/api/stories") | |
| .then().statusCode(200) | |
| .extract().as(StoriesResponse.class); | |
| assertAll( | |
| () -> assertThat(response.stories()).hasSize(2), | |
| .... | |
| ); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오 DTO로 역직렬화 해서 사용하는 방식이군요!
이게 더 깔끔하고 좋은것 같아요!!
| RestDocsResponse responseDocument = response() | ||
| .responseBodyField( | ||
| fieldWithPath("storeKakaoId").description("가게의 카카오 ID"), | ||
| fieldWithPath("category").description("가게 카테고리"), | ||
| fieldWithPath("storeName").description("가게 이름"), | ||
| fieldWithPath("storeAddress").description("가게 주소"), | ||
| fieldWithPath("description").description("스토리 내용"), | ||
| fieldWithPath("imageUrl").description("스토리 이미지 URL") | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
반...여.ㅇ했스빈다...
|
📌 최신 ERD가 자동 생성되었습니다. 👉 ERD 보러가기 |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/main/resources/db/migration/V3__add_story_table.sql (1)
1-14: 스토리 테이블 스키마가 주소 분리 요구사항에 맞게 잘 설계되었습니다.도로명 주소와 지번 주소를 분리한 스키마 설계가 적절하며, 모든 필드의 데이터 타입과 제약 조건이 합리적입니다. 다만
member_id에 대한 외래키 제약 조건 추가를 고려해보시기 바랍니다.외래키 제약 조건을 추가하여 데이터 무결성을 보장하는 것을 고려해보세요:
ALTER TABLE `story` ADD CONSTRAINT `fk_story_member_id` FOREIGN KEY (`member_id`) REFERENCES `member` (`id`) ON DELETE CASCADE;src/main/java/eatda/domain/story/Story.java (1)
148-162: 주소 파싱 메서드의 견고성을 개선해주세요.현재 구현은 기본적인 경계 검사를 포함하고 있지만, 다음과 같은 개선사항을 고려해보세요:
- 중복 코드 제거: 두 메서드 모두 동일한 문자열 분할 로직을 사용합니다.
- 매직 넘버 제거: 하드코딩된 인덱스(1, 2)를 상수로 정의해주세요.
- 반환값 개선: 빈 문자열 대신
Optional<String>을 사용하는 것을 고려해보세요.- 주소 형식 검증: 예상되는 주소 형식에 대한 문서화나 검증을 추가해주세요.
+ private static final int DISTRICT_INDEX = 1; + private static final int NEIGHBORHOOD_INDEX = 2; + + private String[] parseAddressParts() { + return storeLotNumberAddress.split("\\s+"); + } + public String getAddressDistrict() { - String[] addressParts = storeLotNumberAddress.split(" "); - if (addressParts.length < 2) { + String[] addressParts = parseAddressParts(); + if (addressParts.length <= DISTRICT_INDEX) { return ""; } - return addressParts[1]; + return addressParts[DISTRICT_INDEX]; } public String getAddressNeighborhood() { - String[] addressParts = storeLotNumberAddress.split(" "); - if (addressParts.length < 3) { + String[] addressParts = parseAddressParts(); + if (addressParts.length <= NEIGHBORHOOD_INDEX) { return ""; } - return addressParts[2]; + return addressParts[NEIGHBORHOOD_INDEX]; }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
src/main/java/eatda/controller/story/FilteredSearchResult.java(1 hunks)src/main/java/eatda/controller/story/StoryResponse.java(1 hunks)src/main/java/eatda/domain/story/Story.java(5 hunks)src/main/java/eatda/service/story/StoryService.java(4 hunks)src/main/resources/db/migration/V3__add_story_table.sql(1 hunks)src/main/resources/db/seed/dev/V4__dev_add_story_data.sql(1 hunks)src/main/resources/db/seed/local/V4__local_add_story_data.sql(1 hunks)src/test/java/eatda/controller/story/StoryControllerTest.java(3 hunks)src/test/java/eatda/document/story/StoryDocumentTest.java(3 hunks)src/test/java/eatda/domain/story/StoryTest.java(8 hunks)src/test/java/eatda/service/story/StoryServiceTest.java(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- src/main/resources/db/seed/dev/V4__dev_add_story_data.sql
- src/test/java/eatda/service/story/StoryServiceTest.java
- src/main/java/eatda/service/story/StoryService.java
- src/test/java/eatda/document/story/StoryDocumentTest.java
- src/test/java/eatda/controller/story/StoryControllerTest.java
⏰ 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 (10)
src/main/resources/db/seed/local/V4__local_add_story_data.sql (1)
1-22: 주소 필드 분리 및 더미 데이터 업데이트가 적절하게 구현되었습니다.단일 주소 필드를 도로명 주소와 지번 주소로 분리한 스키마 변경에 맞춰 시드 데이터가 정확하게 업데이트되었습니다. 이미지 키도
story/preview/에서story/dummy/로 일관되게 변경되어 실제 이미지 파일과의 매핑이 개선되었습니다.src/main/java/eatda/controller/story/StoryResponse.java (1)
3-12: 주소 필드를 의미론적으로 명확한 구/동 단위로 분리한 개선사항입니다.단일
storeAddress필드를storeDistrict와storeNeighborhood로 분리하여 클라이언트에서 위치 정보를 더 세밀하게 활용할 수 있도록 개선되었습니다. 이는 UI에서 지역별 필터링이나 표시에 유용할 것입니다.src/main/java/eatda/controller/story/FilteredSearchResult.java (1)
3-10: 도메인 모델과 일관성 있는 주소 필드 분리가 적용되었습니다.단일
address필드를roadAddress와lotNumberAddress로 분리하여 Story 엔티티의 구조와 일치하도록 개선되었습니다. 이는 검색 결과에서 더 상세한 주소 정보를 제공할 수 있게 합니다.src/test/java/eatda/domain/story/StoryTest.java (3)
21-35: 도메인 모델 변경에 맞춰 테스트가 적절히 업데이트되었습니다.Story 생성 테스트에서 분리된 주소 필드(
storeRoadAddress,storeLotNumberAddress)를 정확히 사용하고 있으며, 실제 한국 주소 형식을 사용한 테스트 데이터가 현실적입니다.
97-128: 주소 필드 분리에 따른 검증 로직이 완전히 테스트되었습니다.기존 단일 주소 검증 테스트를 도로명 주소와 지번 주소 각각에 대한 별도 테스트로 분리하여 두 필드 모두 필수값임을 확인하고 있습니다. 테스트 메서드명도 명확하게 작성되어 테스트 의도를 잘 표현하고 있습니다.
42-56: 모든 검증 테스트가 새로운 주소 필드 구조에 맞게 업데이트되었습니다.회원 검증, 가게 정보 검증, 스토리 검증 등 모든 테스트 케이스에서 분리된 주소 필드를 일관되게 사용하고 있어 테스트 커버리지가 잘 유지되고 있습니다.
Also applies to: 63-94, 131-184
src/main/java/eatda/domain/story/Story.java (4)
41-45: 주소 필드 분리가 적절하게 구현되었습니다.도로명 주소와 지번 주소를 별도 필드로 분리하여 더 세밀한 주소 정보 관리가 가능해졌습니다. 컬럼 매핑과 필수 제약 조건 설정이 올바르게 적용되었습니다.
57-79: 생성자 업데이트가 올바르게 구현되었습니다.새로운 주소 필드들을 포함하도록 생성자가 적절히 수정되었으며, 매개변수 순서와 필드 할당이 논리적으로 구성되었습니다.
87-99: 검증 메서드 리팩토링이 깔끔하게 수행되었습니다.두 개의 주소 필드를 각각 검증하도록 메서드가 적절히 업데이트되었으며, 기존 검증 패턴을 일관되게 유지하고 있습니다.
118-128: 주소 검증 메서드들이 일관되게 구현되었습니다.두 주소 유형에 대한 별도 검증 메서드가 동일한 패턴으로 구현되었으며, 기존 검증 메서드들과 일관성을 유지하고 있습니다.
|
🎉 This PR is included in version 1.4.0-develop.24 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 1.5.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |




✨ 개요
🧾 관련 이슈
#84
🔍 참고 사항 (선택)
Summary by CodeRabbit
신규 기능
버그 수정
데이터베이스
테스트
CI/CD