Skip to content

Conversation

@jsoonworld
Copy link
Member

📄 Work Description

  • 메시지 도메인 객체(Message)의 템플릿 타입 및 포맷된 메시지 필드 추가
  • 정적 팩토리 메서드 Message.of(...)를 통해 포맷된 메시지 객체 생성
  • 템플릿 타입 비교 메서드 isSameType(...) 추가
  • Message 도메인 객체의 메시지 생성, 포맷 결과, 타입 비교 기능에 대한 단위 테스트 MessageTest 작성

💬 To Reviewers

  • 메시지 포맷 결과가 잘 저장되고 타입 비교가 정확히 동작하는지 확인 부탁드립니다.
  • 테스트 코드의 정상/예외 흐름 커버리지가 충분한지 검토해 주세요.

📷 Screenshot

스크린샷 2025-03-27 오후 11 40 26

⚙️ ISSUE

✅ PR check list

  • Reviewers
  • Assignees
  • Labels

BaseException과 Exception 처리만으로 충분하므로,
UnsupportedOperationException, HttpMediaTypeNotSupportedException,
SocketTimeoutException에 대한 별도 핸들러를 제거함.
- INVALID_USER_NAME 메시지에 공백 허용 여부를 명확히 표현
- 클래스명 PushToken → FcmToken 으로 명확히 표현
- 생성자, 팩토리 메서드 등 관련 메서드명 일괄 수정
- 예외 코드도 FCM_TOKEN_NOT_NULL 로 변경
- @Embedded 필드 타입을 PushToken → FcmToken으로 수정
- 클래스명 변경에 따른 필드 타입 일관성 유지
- FcmToken 클래스명 변경에 따라 테스트 클래스 및 내부 테스트 대상 수정
- 예외 메시지 검증 시 FCM_TOKEN_NOT_NULL 에 맞춰 assert 문 수정
- PUSH_TOKEN_NOT_NULL → FCM_TOKEN_NOT_NULL 로 수정하여 도메인 명확성 확보
- @DisplayName 어노테이션을 "푸시 토큰 테스트" → "FCM 토큰 테스트"로 변경
스크랩 상태에 대한 유효성 검사 및 중복 상태 예외를 처리하기 위한 ScrapErrorCode 열거형을 구현하였습니다.
- scrapped/unscrapped 외 상태에 대한 예외 정의
- 이미 스크랩된 상태 또는 스크랩되지 않은 상태에 대한 예외 정의
- [SCRAP ERROR] prefix 포함한 에러 메시지 포맷 구성
ScrapErrorCode를 인자로 받아 스크랩 관련 예외를 처리할 수 있도록 ScrapException을 정의하였습니다.
- 공통 예외 상위 클래스(BaseException) 상속
- 스크랩 도메인 전용 예외 처리 지원
- 사용자(User)와 연관된 스크랩 정보를 저장하는 Scrap 엔티티 정의
- 스크랩 상태 관리(SCRAPPED/UNSCRAPPED)를 위한 ScrapStatus Enum과 연동
- 스크랩 생성 정적 팩토리 메서드 `of(User user)` 제공
- 상태 전이 메서드(scrap, unscrap) 및 상태 확인 메서드(isScrapped, isUnscrapped) 추가
- 불필요한 Scraps 클래스 제거
- SCRAPPED, UNSCRAPPED 두 가지 상태를 정의하는 ScrapStatus Enum 구현
- 문자열 입력으로부터 Enum 매핑 기능(from) 및 유효성 검증 메서드(isValid) 제공
- 동일 상태로의 중복 전이를 방지하는 scrap(), unscrap() 메서드 구현
- 상태 확인 메서드(isScrapped, isUnscrapped) 및 Jackson 직렬화/역직렬화 설정 추가
- 잘못된 상태 입력 또는 중복 전이 시 ScrapException 발생 처리
- from() 메서드의 유효/무효 입력값 처리 검증
- scrap(), unscrap() 전이 메서드 정상 동작 및 예외 케이스 테스트
- isScrapped(), isValid() 등의 유틸성 메서드에 대한 테스트 포함
- 대소문자 구분 없이 상태 변환 가능함을 검증
- ScrapStatus 입력값이 null인 경우를 명확히 처리하기 위해 SCRAP_STATUS_CANNOT_BE_NULL 코드 추가
- from() 메서드 내 null 체크와 연계하여 예외 메시지 명확화
- 입력값이 null일 경우 ScrapStatus.from()에서 NPE 방지를 위해 명시적 검증 로직 추가
- ScrapException을 통해 SCRAP_STATUS_CANNOT_BE_NULL 예외 코드 반환
- null 검증 책임을 분리한 validateNotNull() 메서드로 구현
- ScrapStatus.from(null) 호출 시 ScrapException 발생 여부 테스트
- isValid(null) 호출 시 false 반환 테스트 추가
- null 입력값 처리 로직에 대한 테스트 커버리지 보완
- 메인 메시지 null 여부 및 유효성 검증 에러 추가
- 메시지 포맷 시 파라미터 누락 및 값 누락에 대한 에러 정의
- 공통 인터페이스 ErrorCode 구현
- 메시지 관련 예외 처리를 위한 MessageException 클래스 정의
- BaseException 상속 및 MessageErrorCode 기반 생성자 구현
- 템플릿 내 플레이스홀더를 파라미터로 치환하는 포맷 메서드 정의
- 포맷팅 필요 여부에 따라 파라미터 검증 및 치환 수행
- 누락된 파라미터나 값이 있을 경우 MessageException 발생
- MessageTemplate 인터페이스 구현을 위한 추상 클래스 설계
- 사용자에게 보여줄 메인 메시지를 Enum 형태로 정의
- 각 항목은 포맷팅이 필요 없는 고정 메시지로 구성
- AbstractMessageTemplate 상속을 통해 포맷팅 기능 확장
- 메시지 전송 대상 구분을 위한 타입 정의
- 스크랩한 사용자(SCRAPPED_USER)와 전체 사용자(ALL_USERS) 구분
- 메인/서브 메시지 및 타겟 유형을 조합한 템플릿 타입 정의
- 메시지 종류별로 메인 메시지, 서브 메시지, 대상 사용자 연결
- 각 템플릿 타입에서 메시지 포맷 메서드(main, sub) 제공
- 사용자 이름을 포함하는 메시지 본문(SubMessage) 템플릿 정의
- 포맷팅이 필요한 메시지로 구성되어 파라미터 기반 치환 수행
- AbstractMessageTemplate 상속으로 포맷팅 로직 재사용
- Messages → Message로 클래스명 단수형으로 변경하여 의미 명확화
- 동일한 필드(mainMessage, subMessage)는 유지
- 기존 Messages 클래스 제거 및 새로운 Message 클래스 적용
- 메시지 문자열을 반환하는 value 메서드 정의
- 포맷팅 필요 여부를 판단하는 needsFormatting 메서드 정의
- 파라미터 기반 포맷을 수행하는 format 메서드 포함
- AbstractMessageTemplate, MainMessage, SubMessage 등에서 구현 예정
- Messages 클래스명을 Message로 변경함에 따라 필드 타입 및 import 구문 수정
- 관련 JPA 매핑 어노테이션 유지 (cascade, orphanRemoval 등)
- MessageTemplateType의 main/sub 메시지 포맷 정상 동작 테스트
- 파라미터 누락, 잘못된 키, null 값 등에 대한 예외 케이스 검증
- 포맷이 불필요한 메인 메시지와 여분 파라미터 무시 동작 확인
- AbstractMessageTemplate의 중복 플레이스홀더 처리 테스트 포함
- messageTemplateType 필드 추가 및 Enum 매핑 처리
- formattedMainMessage, formattedSubMessage 필드 추가
- MessageTemplateType 기반 메시지 생성을 위한 of 정적 메서드 구현
- 동일 템플릿 타입 비교를 위한 isSameType 메서드 추가
- MessageTemplateType을 기반으로 Message 객체 생성 기능 테스트
- main/sub 메시지 포맷 정상 동작 여부 검증
- 포맷 파라미터 누락, null 값, 잘못된 키 등의 예외 케이스 검증
- isSameType 메서드를 통한 템플릿 타입 비교 기능 테스트
@jsoonworld jsoonworld added ✨ feat 새로운 기능 추가 🦊장순🦊 labels Mar 27, 2025
@jsoonworld jsoonworld self-assigned this Mar 27, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements the Message entity along with supporting enums, templates, and error handling to manage formatted messages and their types. Key changes include the addition of the Message domain object with factory and type-comparison methods, creation of new MessageTemplate-related enums and abstract classes, and removal of the obsolete Messages entity and Scrap-related legacy code.

Reviewed Changes

Copilot reviewed 29 out of 29 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/main/java/org/terning/scrap/domain/Scraps.java Removal of an unused Scrap entity
src/main/java/org/terning/scrap/domain/ScrapStatus.java Addition of ScrapStatus enum to manage scrap status logic
src/main/java/org/terning/scrap/domain/Scrap.java New Scrap entity with scrap/unscrap logic using ScrapStatus
src/main/java/org/terning/scrap/common/failure/ScrapException.java New exception class for scrap errors
src/main/java/org/terning/scrap/common/failure/ScrapErrorCode.java New error codes for scrap domain failures
src/main/java/org/terning/notification/domain/Notifications.java Update to reference the new Message entity instead of Messages
src/main/java/org/terning/message/** New and updated message domain objects, enums, and templates for formatted messaging
src/main/java/org/terning/global/failure/GlobalExceptionHandler.java Removal of several exception handling methods
Comments suppressed due to low confidence (2)

src/main/java/org/terning/global/failure/GlobalExceptionHandler.java:27

  • The removal of multiple exception handlers (e.g., for UnsupportedOperationException, HttpMediaTypeNotSupportedException, and SocketTimeoutException) may leave these error cases unhandled; please verify that alternative exception handling mechanisms are in place.
    @ExceptionHandler(UnsupportedOperationException.class)

src/main/java/org/terning/notification/domain/Notifications.java:35

  • The field has been renamed from 'messages' to 'message' to reflect the singular new Message entity; ensure that all usage sites and documentation are updated accordingly.
    private Message message;

Copy link
Contributor

@junggyo1020 junggyo1020 left a comment

Choose a reason for hiding this comment

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

Message 도메인으로 메세지 타입과 결과를 함께 관리하는 구조가 좋은 것 같아요!
현재 메인과 서브 메세지가 모두 null을 허용하고 있는 상태인데 formatting을 할 때 null값을 처리하는게 의미가 있을까 싶어서 이부분도 나중에 이야기해보면 좋을 것 같아요!!

Comment on lines +33 to +34
public static Message of(MessageTemplateType template, String formattedMainMessage, String formattedSubMessage) {
return new Message(template, formattedMainMessage, formattedSubMessage);
Copy link
Contributor

Choose a reason for hiding this comment

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

현재 포맷된 메세지를 외부에서 주입하도록 되어있는데요!
포맷 로직까지 내부에서 처리하면 불변셩이나 사용성 측면에서 조금 더 깔끔해질 수 있다는 생각입니다! 어떻게 생각하시나요?

Copy link
Member Author

Choose a reason for hiding this comment

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

피드백 감사합니다! 😊

현재는 포맷된 메시지를 외부에서 주입하는 방식인데, 말씀처럼 포맷 로직까지 내부에서 처리한다면 생성 책임이 더 명확해지고 불변성과 사용성 측면에서도 이점이 많을 것 같다는 생각이 들었습니다.

특히 Message.of(template, params)처럼 메시지가 자기 역할을 수행하는 구조로 리팩토링하면, 외부에서 포맷을 일일이 처리하지 않아도 되어 응집도가 더 높아질 수 있겠네요!

다만 포맷 로직을 Message가 직접 갖게 되면 템플릿 구조나 파라미터 요구사항을 더 많이 알아야 하기 때문에, 객체 간 결합도에 대한 고민도 함께 가져가야 할 것 같습니다.

말씀 주신 방향으로 리팩토링 적용해보면서 메시지 도메인의 책임과 경계를 더 깔끔하게 정리해보겠습니다 🙌

Comment on lines +37 to +39
public boolean isSameType(MessageTemplateType otherTemplate) {
return this.messageTemplateType == otherTemplate;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

해당 메서드는 구체적으로 어떨때 사용하는 걸까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

피드백 감사합니다! 😊

isSameType() 메서드는 특정 메시지가 주어진 MessageTemplateType과 동일한 템플릿에 기반해 생성된 것인지를 판단하기 위한 용도로 사용됩니다.

예를 들어, 유저에게 이미 동일한 템플릿의 알림이 발송된 이력이 있는지를 확인하거나, 특정 템플릿 타입의 메시지를 선별적으로 처리해야 할 때 유용하게 쓰일 수 있습니다.

아직 실제 사용처가 많지는 않지만, 이후 알림 중복 여부 체크나 템플릿별 처리 분기 로직 등에서 활용될 가능성을 고려해서 정의해두었습니다.

불필요하다고 판단되면 제거하거나 테스트 시점까지 보류해보는 것도 고려하고 있습니다 :)

@jsoonworld jsoonworld merged commit 37ac7de into develop Mar 29, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[✨ feat] 메세지 엔티티 구현

3 participants