-
Notifications
You must be signed in to change notification settings - Fork 0
[Fix] 1차 스프린트 ERD 수정 #76
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
|
""" WalkthroughERD 변경에 따라 도메인 엔티티, DB 마이그레이션, 시드 데이터, 예외 코드, 테스트 코드가 대폭 수정되었습니다. 메뉴, 북마크, 가격, 할인, 관심지역 등 기존 도메인 및 관련 테스트가 삭제되고, Article, Cheer 등 신규 엔티티 및 DB 테이블이 도입되었으며, Store와 Member 구조가 재정의되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Member
participant Store
participant Cheer
participant Article
User->>Member: 회원 가입/조회
User->>Store: 매장 조회
User->>Cheer: 매장에 Cheer 등록/조회
User->>Article: 기사(Article) 조회
Cheer->>Member: 회원 참조
Cheer->>Store: 매장 참조
Assessment against linked issues
Suggested labels
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 |
|
📌 최신 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: 7
🔭 Outside diff range comments (1)
src/main/java/eatda/domain/member/Member.java (1)
70-75: 생성자에서 createdAt 필드가 설정되지 않는 문제가 있습니다.세 번째 생성자에서는
createdAt필드가 설정되지 않아 null 상태로 남게 됩니다. 이는@Column(nullable = false)설정과 충돌하여 데이터베이스 제약 조건 위반을 초래할 수 있습니다.다음과 같이 수정하세요:
public Member(String nickname, String mobilePhoneNumber, boolean optInMarketing) { validateOptInMarketing(optInMarketing); this.nickname = nickname; this.mobilePhoneNumber = new MobilePhoneNumber(mobilePhoneNumber); this.optInMarketing = optInMarketing; + this.createdAt = LocalDateTime.now(); }
♻️ Duplicate comments (2)
src/main/resources/db/seed/local/V2__local_init_data.sql (1)
11-17: Store 데이터의 일관성 문제가 있습니다.dev 환경 seed 데이터와 동일한 문제가 있습니다. name과 category가 일치하지 않고, 모든 store가 동일한 place_url을 사용하고 있습니다.
src/main/java/eatda/domain/store/Store.java (1)
53-54: createdAt 필드 처리 방식을 개선하세요.Cheer 엔티티와 동일하게
@CreationTimestamp사용을 권장합니다.Also applies to: 74-74
🧹 Nitpick comments (5)
src/test/java/eatda/domain/store/StoreCategoryTest.java (1)
14-31: 테스트 커버리지를 개선할 수 있습니다.현재
from()메서드만 테스트되고 있습니다.isValid()메서드와 모든 enum 값에 대한 테스트를 추가하는 것을 고려해보세요.다음과 같은 테스트 추가를 고려해보세요:
@Nested @DisplayName("isValid 메서드 테스트") class IsValidMethod { @Test void 유효한_이름이면_true를_반환한다() { assertThat(StoreCategory.isValid("한식")).isTrue(); assertThat(StoreCategory.isValid("양식")).isTrue(); } @Test void 유효하지_않은_이름이면_false를_반환한다() { assertThat(StoreCategory.isValid("없는카테고리")).isFalse(); assertThat(StoreCategory.isValid(null)).isFalse(); } } @Test void 모든_카테고리가_정상적으로_변환된다() { Arrays.stream(StoreCategory.values()) .forEach(category -> assertThat(StoreCategory.from(category.getCategoryName())) .isEqualTo(category)); }src/main/java/eatda/domain/store/Cheer.java (1)
47-48: createdAt 필드는 JPA 어노테이션을 사용하는 것이 좋습니다.생성자에서 직접 설정하는 대신
@CreationTimestamp또는@PrePersist를 사용하면 테스트가 용이하고 일관성이 향상됩니다.+import org.hibernate.annotations.CreationTimestamp; @Column(name = "created_at", nullable = false) +@CreationTimestamp private LocalDateTime createdAt;그리고 생성자에서 해당 라인을 제거하세요:
-this.createdAt = LocalDateTime.now();Also applies to: 60-60
src/main/resources/db/seed/dev/V2__dev_init_data.sql (1)
12-25: 모든 store가 동일한 place_url을 사용하고 있습니다.각 store마다 고유한 place_url을 사용하거나, 개발용 더미 URL이라도 구분 가능하게 만드는 것이 좋습니다.
src/main/resources/db/migration/V1__init.sql (2)
7-7: 전화번호 컬럼 길이가 과도합니다.전화번호는 국제 표기를 포함해도 20자 이내(예:
+821012345678)면 충분합니다.VARCHAR(255)는 불필요하게 큰 Row 길이를 유발합니다.- `phone_number` VARCHAR(255) NULL, + `phone_number` VARCHAR(20) NULL, ... - `phone_number` VARCHAR(255) NOT NULL, + `phone_number` VARCHAR(20) NOT NULL,Also applies to: 18-18
23-24: 위도·경도 DOUBLE 사용 시 부동소수 오차 가능성지리 좌표는
DECIMAL(9,6)(1cm 단위) 정도면 충분하며, DOUBLE은 불필요한 오차와 인덱스 효율 저하가 있습니다.- `latitude` DOUBLE NOT NULL, - `longitude` DOUBLE NOT NULL, + `latitude` DECIMAL(9,6) NOT NULL, + `longitude` DECIMAL(9,6) NOT NULL,
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (26)
src/main/java/eatda/domain/article/Article.java(1 hunks)src/main/java/eatda/domain/bookmark/Bookmark.java(0 hunks)src/main/java/eatda/domain/member/Member.java(2 hunks)src/main/java/eatda/domain/menu/Discount.java(0 hunks)src/main/java/eatda/domain/menu/Menu.java(0 hunks)src/main/java/eatda/domain/menu/Price.java(0 hunks)src/main/java/eatda/domain/store/Cheer.java(1 hunks)src/main/java/eatda/domain/store/Store.java(2 hunks)src/main/java/eatda/domain/store/StoreCategory.java(1 hunks)src/main/java/eatda/domain/store/StoreHours.java(0 hunks)src/main/java/eatda/domain/store/StorePhoneNumber.java(0 hunks)src/main/java/eatda/enums/InterestArea.java(0 hunks)src/main/java/eatda/exception/BusinessErrorCode.java(1 hunks)src/main/resources/db/migration/V1__init.sql(1 hunks)src/main/resources/db/seed/dev/V2__dev_init_data.sql(1 hunks)src/main/resources/db/seed/local/V2__local_init_data.sql(1 hunks)src/test/java/eatda/domain/bookmark/BookmarkTest.java(0 hunks)src/test/java/eatda/domain/menu/DiscountTest.java(0 hunks)src/test/java/eatda/domain/menu/MenuTest.java(0 hunks)src/test/java/eatda/domain/menu/PriceTest.java(0 hunks)src/test/java/eatda/domain/store/CheerTest.java(1 hunks)src/test/java/eatda/domain/store/StoreCategoryTest.java(1 hunks)src/test/java/eatda/domain/store/StoreHoursTest.java(0 hunks)src/test/java/eatda/domain/store/StorePhoneNumberTest.java(0 hunks)src/test/java/eatda/domain/store/StoreTest.java(0 hunks)src/test/java/eatda/enums/InterestAreaTest.java(0 hunks)
💤 Files with no reviewable changes (15)
- src/test/java/eatda/enums/InterestAreaTest.java
- src/test/java/eatda/domain/bookmark/BookmarkTest.java
- src/test/java/eatda/domain/store/StorePhoneNumberTest.java
- src/main/java/eatda/domain/store/StorePhoneNumber.java
- src/main/java/eatda/domain/menu/Price.java
- src/test/java/eatda/domain/menu/MenuTest.java
- src/test/java/eatda/domain/menu/PriceTest.java
- src/main/java/eatda/domain/bookmark/Bookmark.java
- src/test/java/eatda/domain/menu/DiscountTest.java
- src/test/java/eatda/domain/store/StoreTest.java
- src/main/java/eatda/domain/store/StoreHours.java
- src/test/java/eatda/domain/store/StoreHoursTest.java
- src/main/java/eatda/enums/InterestArea.java
- src/main/java/eatda/domain/menu/Discount.java
- src/main/java/eatda/domain/menu/Menu.java
🧰 Additional context used
🧠 Learnings (1)
src/main/java/eatda/domain/store/Store.java (1)
Learnt from: leegwichan
PR: YAPP-Github/26th-Web-Team-1-BE#60
File: src/main/java/eatda/domain/store/Coordinates.java:23-37
Timestamp: 2025-07-09T08:05:00.393Z
Learning: In Coordinates.java domain class, the developer prefers to manage Seoul coordinate boundary constants (latitude/longitude limits) in the domain layer through public static getter methods, as these represent domain rules rather than infrastructure concerns. This approach prioritizes domain integrity over strict encapsulation.
⏰ 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 (9)
src/main/java/eatda/domain/article/Article.java (2)
39-45: 엔티티 생성자 구현이 적절합니다.생성 시점에
createdAt을 자동으로 설정하는 구현이 올바릅니다. PR 목적에 따라 추가적인 유효성 검증 없이 단순하게 구현된 점도 적절합니다.
30-34: URL 및 이미지 키 길이 검토 결과시드 데이터 기준으로 확인한 최대 길이:
article_url최대 11자image_key최대 7자현재 설정된
length = 511은 시드 데이터 범위에서 충분히 여유가 있습니다.
다만 실제 운영 환경의 URL 및 이미지 키 길이가 더 길어질 가능성이 있으므로, 운영 DB나 로그 등을 통해 실제 사용 길이를 검토한 후 필요 시 길이 제한을 조정해 주세요.src/main/java/eatda/domain/store/StoreCategory.java (2)
1-1: 도메인 패키지로의 이동이 적절합니다.
StoreCategory를eatda.enums에서eatda.domain.store로 이동한 것은 도메인 중심 구조로의 개선으로 보입니다.
28-36: from() 메서드 구현이 견고합니다.null과 빈 문자열에 대한 검증, 그리고 적절한 비즈니스 예외 처리가 잘 구현되어 있습니다.
src/test/java/eatda/domain/store/StoreCategoryTest.java (1)
1-1: 패키지 변경이 올바르게 적용되었습니다.
StoreCategory클래스의 패키지 변경에 맞춰 테스트 클래스의 패키지도 적절히 업데이트되었습니다.src/main/java/eatda/domain/member/Member.java (1)
45-46: createdAt 필드 추가가 적절합니다.멤버 생성 시점을 추적하기 위한
createdAt필드 추가는 도메인 모델 개선에 적합합니다.src/test/java/eatda/domain/store/CheerTest.java (2)
18-29: 테스트용 기본 인스턴스 설정이 적절합니다.새로운 도메인 모델 구조에 맞춰
Member와Store의 기본 인스턴스가 올바르게 구성되었습니다. Store의 빌더 패턴 사용도 적절합니다.
34-42: 설명 유효성 검증 테스트가 올바르게 구현되었습니다.null과 빈 문자열에 대한 검증 테스트가 적절히 구현되어 있고, 비즈니스 예외 코드도 정확히 확인하고 있습니다.
src/main/java/eatda/domain/store/Store.java (1)
56-75: Builder 패턴이 깔끔하게 구현되었습니다.필수 필드들이 모두 포함되어 있고, Coordinates 객체 생성도 적절하게 처리되었습니다.
lvalentine6
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.
이번 PR도 고생하셨습니다. 🎉
어제 같이 논의한 ERD 구조대로 잘 반영되어 있는 것 같아요!
다만 지금은 일정상 넘어가도 될 것 같지만,
외부 API나 어드민 입력이라고 해도 예외적인 값이 들어올 수 있어서
추후에는 유효성 검토가 필요하다고 생각해요.
그리고 Sonar에서 테스트 커버리지가 기준치(80%)를 만족하지 못한다고 하던데,
유효성 검증 로직이 없다 보니 커버리지가 자연스럽게 낮게 나온 것 같아요.
이럴 경우엔 통과 기준 비율을 낮추는 게 나을지
아니면 기본적인 검증이라도 추가해서 맞추는 게 좋을지 고민이 되네요.
어떻게 생각하시나요?
| this.socialId = socialId; | ||
| this.email = email; | ||
| this.nickname = nickname; | ||
| this.createdAt = LocalDateTime.now(); |
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.
여기도 @PrePersist를 사용하는게 어떨까요???
| this.subtitle = subtitle; | ||
| this.articleUrl = articleUrl; | ||
| this.imageKey = imageKey; | ||
| this.createdAt = LocalDateTime.now(); |
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.
[제안]
createdAt 필드는 아래처럼 @PrePersist를 활용하면 JPA 생명주기와도 맞고 테스트도 더 수월할 것 같아요!
@PrePersist
protected void onCreate() {
this.createdAt = LocalDateTime.now();
}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.
좋은 아이디어라고 생각합니다.
모든 Entity마다 해당 메서드가 있는 것은 불편하다고 생각해서 AuditingEntity로 해당 부분을 분리했습니다. 확인 한 번 부탁드립니다!
- cheer 의 image_key 값의 null 허용 - cheer 의 is_admin 값의 기본 값을 false 로 설정 - 초기 삽입 데이터 이름에 맞춰 일부 수정
- id 값을 받지 않도록 함
- created_at 을 관리하는 Entity 를 추상 클래스로 분리
📄 Terraform Plan Summary🛡️ Common InfrastructureStatus: ✅ No Changes 🛠️ Development EnvironmentStatus: ✅ No Changes 📋 Full Results: View in Actions |
|
📌 최신 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: 1
♻️ Duplicate comments (3)
src/main/resources/db/seed/local/V2__local_init_data.sql (2)
18-19: 일부 store 레코드에서 road_address가 빈 문자열로 설정되어 있습니다.개발 환경과 동일한 문제로, Store ID 4와 7에서
road_address가 빈 문자열('')로 설정되어 있습니다. 로컬 환경에서도 일관성 있는 데이터 사용을 권장합니다.
27-34: 모든 cheer 레코드에서 동일한 image_key를 사용하고 있습니다.개발 환경과 동일한 문제로, 모든 응원 메시지에서 'default.jpg'를 사용하고 있습니다. 로컬 개발 환경에서도 다양한 이미지 키를 사용하는 것이 좋습니다.
src/main/resources/db/migration/V1__init.sql (1)
8-8:opt_in_marketing의 NULL 허용은 3-State 버그를 유발할 수 있습니다.마케팅 수신 동의는 명확한
true/false값을 가져야 하며,NULL을 허용하면 "동의/비동의/미정" 3-State 로직이 생겨 서비스 및 통계 로직에 문제가 발생할 수 있습니다.
🧹 Nitpick comments (4)
src/main/java/eatda/domain/AuditingEntity.java (2)
16-19: 시간대 일관성을 위해 UTC 시간 사용을 고려하세요.현재
LocalDateTime.now()를 사용하면 서버의 시스템 시간대를 따르게 되어 서버 환경에 따라 다른 시간이 기록될 수 있습니다. 글로벌 서비스를 고려한다면 UTC 시간 사용을 권장합니다.- this.createdAt = LocalDateTime.now(); + this.createdAt = LocalDateTime.now(ZoneOffset.UTC);추가로 import 문도 수정해야 합니다:
import java.time.LocalDateTime; +import java.time.ZoneOffset;
11-20: 업데이트 시간 추적 기능 추가를 고려하세요.생성시간만 추적하고 있지만, 엔티티가 수정되었을 때의 시간도 추적하는 것이 일반적입니다. 완전한 감사 기능을 위해
updatedAt필드와@PreUpdate콜백 추가를 고려해보세요.@Getter @MappedSuperclass public abstract class AuditingEntity { @Column(name = "created_at", nullable = false) private LocalDateTime createdAt; + + @Column(name = "updated_at", nullable = false) + private LocalDateTime updatedAt; @PrePersist protected void onCreate() { this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedAt = LocalDateTime.now(); } }src/main/resources/db/seed/dev/V2__dev_init_data.sql (1)
27-34: 모든 cheer 레코드에서 동일한 image_key를 사용하고 있습니다.모든 응원 메시지에서 'default.jpg'를 사용하고 있는데, 개발 환경에서도 다양한 이미지 키를 사용하여 더 현실적인 테스트 데이터를 만드는 것이 좋습니다.
-VALUES (1, 1, 1, '정말 맛있어요! 강추합니다!', 'default.jpg', true), - (2, 2, 2, '서비스가 훌륭해요!', 'default.jpg', true), - (3, 3, 3, '여기 음식이 정말 맛있어요!', 'default.jpg', true), - (4, 4, 4, '분위기가 너무 좋아요!', 'default.jpg', true), - (5, 5, 5, '디저트가 정말 맛있어요!', 'default.jpg', true), - (6, 6, 6, '커피가 정말 맛있어요!', 'default.jpg', false), - (7, 7, 7, '패스트푸드가 빠르고 맛있어요!', 'default.jpg', false); +VALUES (1, 1, 1, '정말 맛있어요! 강추합니다!', 'cheer/korean_restaurant_1.jpg', true), + (2, 2, 2, '서비스가 훌륭해요!', 'cheer/western_restaurant_1.jpg', true), + (3, 3, 3, '여기 음식이 정말 맛있어요!', 'cheer/chinese_restaurant_1.jpg', true), + (4, 4, 4, '분위기가 너무 좋아요!', 'cheer/western_restaurant_2.jpg', true), + (5, 5, 5, '디저트가 정말 맛있어요!', 'cheer/dessert_cafe_1.jpg', true), + (6, 6, 6, '커피가 정말 맛있어요!', 'cheer/coffee_shop_1.jpg', false), + (7, 7, 7, '패스트푸드가 빠르고 맛있어요!', 'cheer/fast_food_1.jpg', false);src/main/resources/db/migration/V1__init.sql (1)
48-49: article 테이블의 URL 필드들이 장문의 URL을 지원하지 못할 수 있습니다.
article_url이 VARCHAR(511)로 설정되어 있는데, 현대 웹에서는 쿼리 파라미터가 많은 긴 URL이 일반적입니다. URL 단축 서비스를 사용하지 않는다면 더 긴 길이를 고려해야 합니다.- `article_url` VARCHAR(511) NOT NULL, + `article_url` VARCHAR(2048) NOT NULL,
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/main/java/eatda/domain/AuditingEntity.java(1 hunks)src/main/java/eatda/domain/article/Article.java(1 hunks)src/main/java/eatda/domain/member/Member.java(3 hunks)src/main/java/eatda/domain/store/Cheer.java(1 hunks)src/main/java/eatda/domain/store/Store.java(2 hunks)src/main/resources/db/migration/V1__init.sql(1 hunks)src/main/resources/db/seed/dev/V2__dev_init_data.sql(1 hunks)src/main/resources/db/seed/local/V2__local_init_data.sql(1 hunks)src/test/java/eatda/domain/store/CheerTest.java(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- src/main/java/eatda/domain/member/Member.java
- src/test/java/eatda/domain/store/CheerTest.java
- src/main/java/eatda/domain/store/Store.java
- src/main/java/eatda/domain/article/Article.java
- src/main/java/eatda/domain/store/Cheer.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 (1)
src/main/resources/db/migration/V1__init.sql (1)
35-35: image_key 컬럼의 NULL 허용은 비즈니스 로직에서 지원됨을 확인했습니다.-src/main/java/eatda/domain/store/Cheer.java
• validateImageKey(String imageKey) 메서드에서
- imageKey == null일 경우 예외 없이 통과
- imageKey가 공백만으로 이루어진 경우 BusinessErrorCode.INVALID_CHEER_IMAGE_KEY 예외 발생
- src/test/java/eatda/domain/store/CheerTest.java
• 공백 문자열에 대한 예외 처리를 검증하는 테스트가 존재
• imageKey가 null일 때도 예외 없이 객체가 생성됨을 비즈니스 요구사항에 부합→ DB 마이그레이션 스크립트(
image_key VARCHAR(511) NULL)와 도메인 로직이 일치합니다.
|
🎉 This PR is included in version 1.4.0-develop.19 🎉 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 📦🚀 |


✨ 개요
🧾 관련 이슈
closed #75
🔍 참고 사항 (선택)
리뷰 요구 사항
작업 내용
Summary by CodeRabbit
신규 기능
리팩터링
버그 수정
데이터베이스
테스트