Open
Conversation
[변경사항 요약] - 제공 받은 프론트엔드 빌드 산출물을 static/ 디렉토리에 추가하여 Spring 기반 정적 리소스 서빙 구성 - OpenAPI 스펙 요구사항에 맞춰 Swagger 설정 및 DTO 필드명을 camelCase 기준으로 정리 - ChannelDto.Response의 memberIds → participantIds로 변경하여 프론트엔드 응답 필드명과 일치 - UserStatusDto의 lastActiveAt 관련 필드명을 newLastActiveAt으로 수정 - UserDto.Response의 isOnline → online으로 변경하여 프론트엔드 응답 파싱 오류 방지 - PRIVATE 채널에서 참여자가 1명만 남을 경우 프론트 크래시 방지를 위한 임시 필터링 로직 추가 ※ 정적 리소스 연동 후 화면 기반 테스트를 통해 API 응답 구조 불일치로 발생하는 런타임 오류를 보완함
- Dockerfile 제거 - Railway 환경변수(RAILPACK_JDK_VERSION)를 통한 JDK 버전 설정 - plain.jar 생성 방지를 위해 Gradle jar task 비활성화 - bootJar만 생성되도록 설정하여 Railway 실행 아티팩트 충돌 방지 ※ Docker 이미지 기반 배포에서 Railway 기본 Railpack 배포 방식으로 전환
[변경사항 요약] - BaseEntity를 entity/base 패키지로 이동하고 BaseUpdatableEntity 도입 - 엔티티 공통 필드 상속 구조 정립 - UUID 기반 참조 제거 후 객체 참조(User, Channel 등) 방식으로 전환 - Serializable 인터페이스 제거 (JPA 도입 대비) - 엔티티 구조 변경에 따른 서비스 및 Repository 계층 전반 리팩터링
[변경사항 요약] - ERD 기반으로 도메인 엔티티에 JPA 매핑 정보 반영 - @entity, @table 적용 - @column, @Enumerated 적용 - @manytoone, @OnetoOne, @onetomany 연관관계 매핑 - @joincolumn, @jointable 설정 - 부모-자식 관계 및 생명주기 경계를 고려하여 영속성 전이 정책 정의 - Aggregate 내부 관계에 cascade 적용 - 고아 객체 제거(orphanRemoval) 설정 - DB 외래키 제약 조건과 객체 그래프 간 책임 경계 정리 - 단순 참조 관계는 DB FK에 위임 - 강한 생명주기 종속 관계는 JPA 레벨에서 관리
[변경사항 요약] - FileRepository, JCFRepository 삭제 및 관련 의존성 제거 - JpaRepository 상속 및 도메인별 쿼리 메서드 적용 - 영속성 컨텍스트 특징(변경 감지, 지연 로딩) 반영 및 서비스 로직 리팩터링 - @transactional을 활용한 트랜잭션 경계 설정 및 데이터 일관성 보장"
[변경사항 요약] - 기존 Inner Record 기반 DTO 구조를 Flat 형식으로 분리 및 재구성 - MapStruct 라이브러리 도입을 통한 Entity-DTO 매핑 자동화 및 간소화 - 매퍼 컴포넌트 도입과 DTO 구조 재구성에 따른 Service, Controller 리팩터링 수행
[변경사항 요약]
- BinaryContent에서 bytes 제거 및 로컬 파일 시스템 저장 방식 도입
- BinaryContentStorage 인터페이스 및 Local 디스크 구현체 추가
- Message, ReadStatus 엔티티 생성자 기반 리팩토링 (assign 메서드 제거)
- .gitignore 수정: .idea 폴더 전체 제외 및 uploads 경로 추가
- 파일 다운로드 API 구현 (GET /api/binaryContents/{id}/download)"
[변경사항 요약] - API v1.1 명세 및 정적 리소스 v1.1.4 도입에 따른 도메인 로직 및 컨트롤러 일부 리팩터링 - 유저 상태(UserStatus) 매핑 오류 수정 및 API 규격에 맞는 데이터 응답 구조 정합성 확보
[주요 변경사항]
- N+1 문제 해결: Fetch Join 및 @EntityGraph를 활용하여 연관 엔티티 일괄 조회 최적화
- 페이지네이션 리팩토링: 기존 오프셋 방식에서 커서 기반 페이지네이션으로 전환 (v1.2 스펙 준수)
- OSIV 비활성화 대응: open-in-view: false 설정 및 서비스 레이어 조회 메서드 전용 트랜잭션 적용
- 정적 리소스 v1.2.4 호환성 이슈 보고:
* 현상: 메시지 생성 시 응답 DTO의 lastMessageAt이 null로 반환되어 프론트엔드 읽음 처리 하이라이트가 무한 반복되는 현상 식별
* 원인 분석: 메시지 저장 시점과 매퍼의 최신 메시지 조회 시점 간의 영속성 컨텍스트 불일치 의심
* 특이사항: 해당 이슈는 현재 진행 중이며, 임시 조치 대신 구조적인 해결을 위해 추가 분석 예정
- API v1.2 사양 준수: PageResponse 구조 변경 및 관련 Controller/Service/Repository 전면 리팩토링
[주요 변경사항] 1. DTO 구조 개선: ReadStatus/Message 응답 시 객체 대신 UUID 식별자 반환하도록 수정 (정적 리소스 규격 준수) 2. 연관관계 정규화: Message-BinaryContent 관계를 @manytomany에서 1:N(@onetomany) 단방향 매핑으로 변경 3. N+1 문제 해결: ChannelMapper 내 DB 조회 로직 제거 및 Service 레이어에서 Map을 활용한 Batch Fetching 적용 4. 데이터 정합성 보장: saveAndFlush() 적용으로 JPA Auditing 시점 동기화 (createdAt null 이슈 방지) 5. 페이지네이션 교정: PageResponse 내 nextCursor 값을 페이지 번호에서 마지막 요소의 createdAt(Instant)으로 수정
[주요 변경사항] 1. 커서 기반 페이징 정합성 확보 - 요청(cursor)과 응답(nextCursor) 기준을 모두 Instant로 통일하여 정합성 해결 2. N+1 문제 추가 해결 및 최적화 - 채널 조회: Channel-ReadStatus-User 연관 객체 일괄 조회를 통해 지연 로딩 방지 - 메시지 조회: Author Fetch Join 및 Attachments @batchsize 적용으로 DTO 변환 시 쿼리 폭탄 방어 - 메모리 페이징 방지: 컬렉션 Fetch Join을 제거하여 실제 DB 레벨 페이징(Limit) 활성화 3. 도메인 로직 및 매핑 규격 수정 - 채널 수정 API: Dirty Checking이 정상 동작하도록 수정하여 기능 복구 - 매핑 준수: Message-BinaryContent 관계를 조인 테이블 기반 1:N 단방향 매핑으로 유지
[주요 변경사항] - 컨트롤러 및 서비스 레이어 주요 메서드(생성/수정/삭제 등) 로깅 추가 - logback-spring.xml을 통한 로그 패턴 및 파일 롤링(30일) 설정 - 환경별(dev, prod) 로깅 레벨 차등 적용 (debug/info) - 콘솔 및 파일(.logs/) 동시 기록 설정
[예외 구조 고도화] - 최상위 DiscodeitException 중심의 도메인별 예외 계층 설계 - User, Channel, Message, BinaryContent 등 도메인별 상세 예외 클래스 구현 - ErrorCode Enum을 통한 HTTP 상태 코드 및 에러 메시지 표준화 - 예외 상황 추적을 위한 details(Map) 필드 도입 및 데이터 캡슐화 [전역 예외 처리 및 응답 표준화] - @RestControllerAdvice 기반 GlobalExceptionHandler 구현 - 모든 예외 응답을 ErrorResponseDto 규격으로 단일화 - 기존 BusinessException을 DiscodeitException 및 세부 예외로 전면 리팩터링 - NoSuchElementException 등 표준 예외를 커스텀 예외로 교체하여 의미 명확화 [레거시 제거 및 코드 최적화] - JPA 전환으로 불필요해진 File/JCF 기반 Repository 및 Service 전량 제거 - ServiceFactory 및 관련 레거시 로직 삭제를 통한 의존성 정돈
[주요 변경사항] - RuntimeException과 Exception 핸들러를 분리하여 타입 안정성 확보 - 에러 성격에 따른 로깅 레벨 차별화 (warn/error) 및 스택 트레이스 최적화
[주요 변경사항] - Actuator 의존성 추가 및 주요 엔드포인트(health, info, metrics, loggers) 노출 - 서비스 상태 모니터링 체계 구축
[피드백 1 반영] - MethodArgumentNotValidException 발생 시 모든 검증 에러 메시지를 결합하여 반환하도록 수정 - ErrorResponse의 details 필드에 검증 실패 데이터(RejectedValue) 포함하도록 개선 [피드백 2 반영] - 컨트롤러와 서비스 간 중복 로그 제거 및 로그 포맷 통일 (Controller: REQUEST, Service: SUCCESS)
[주요 변경 사항] - UserService: create(성공/중복 실패), update(성공), delete(성공/ID 미존재 실패) 테스트 작성 - ChannelService: create(PUBLIC/PRIVATE 성공), update(성공/ID 미존재 실패), delete(성공), findByUserId(성공) 테스트 작성 - MessageService: create(유저 미존재 실패), update(성공), delete(성공), findByChannelId(성공) 테스트 작성 - Mockito를 활용한 Repository 의존성 모의(Mocking) 및 BDDMockito 기반 Given-When-Then 패턴 적용
[주요 변경 사항] - UserController: create(성공), delete(ID 미존재 400 실패) 테스트 작성 - ChannelController: createPublic(성공), createPrivate(성공), update(ID 미존재 400 실패) 테스트 작성 - MessageController: create(작성자 미존재 400 실패), update(성공/중첩 DTO 검증) 테스트 작성 - Repository: @DataJpaTest 기반 주요 쿼리 메서드 및 페이징/정렬 테스트 작성 - Environment: application-test.yaml(H2 PostgreSQL 호환 모드) 설정 및 `@EnableJpaAuditing` 적용
[주요 변경 사항] - `BaseIntegrationTest`: `@SpringBootTest`, `@AutoConfigureMockMvc`, `@Transactional` 등 공통 테스트 설정을 정의하고, `MockMvc`와 `ObjectMapper` 인스턴스를 제공하여 통합 테스트 클래스들이 상속받아 사용할 수 있도록 구조화 - User API: `MockMultipartFile`을 활용한 사용자 생성 및 중복 이메일 가입 실패 시나리오 검증, 가입 후 전체 목록 조회를 통한 데이터 정합성 확인 - Channel API: 공개 채널 생성 성공 및 이름 길이 제약 조건 위반에 따른 `400 Bad Request` 예외 처리 검증 - Message API: 메시지 전송 시 실제 `User`와 `Channel` 엔티티를 DB에 준비하여 연관 관계 통합 검증, 공백 내용 전송 시 실패 케이스 및 페이징 응답 구조(`$.content[0]`) 검증 - 리포지토리 테스트: `@DataJpaTest` 슬라이스 테스트 시 `@Import(JpaAuditConfig.class)`를 추가하여 JPA Auditing(`createdAt`) 누락 문제 해결 - 테스트 독립성: `@Transactional` 어노테이션을 활용하여 각 테스트 케이스 종료 후 자동 롤백을 통해 데이터 격리 환경 구축
[주요 변경사항] - UUID 기반의 요청 ID 생성 및 MDC 주입 인터셉터 구현 - 응답 헤더(Discodeit-Request-ID)에 요청 ID 포함 - WebMvcConfig를 통한 인터셉터 등록 및 설정 - Logback 패턴 고도화: [ID | METHOD | URL] 정보 추가
[Spring Boot Admin] - 신규 모듈(admin) 생성 및 Admin Server(9090 포트) 구현 - discodeit 프로젝트에 Admin Client 의존성 및 프로파일별(dev, prod) 설정 추가 - 실시간 메트릭 모니터링 체계 구축 [JaCoCo] - JaCoCo 플러그인 도입 및 테스트 리포트 자동 생성 설정 - basic 서비스 패키지 대상 테스트 코드 보강으로 커버리지 76% 달성
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
기본 요구사항
프로파일 기반 설정 관리
application-dev.yaml,application-prod.yaml파일을 생성하세요.로그 관리
@Slf4j어노테이션을 활용해 로깅을 쉽게 추가할 수 있도록 구성하세요.application.yaml에 기본 로깅 레벨을 설정하세요.info레벨로 설정합니다.debug, 운영 환경에서는info레벨로 설정합니다.logback-spring.xml파일을 생성하세요.다음 예시와 같은 로그 메시지를 출력하기 위한 로깅 패턴과 출력 방식을 커스터마이징하세요.
로그 출력 예시
콘솔과 파일에 동시에 로그를 기록하도록 설정하세요.
{프로젝트 루트}/.logs경로에 저장되도록 설정하세요.로그 파일은 일자별로 롤링되도록 구성하세요.
로그 파일은 30일간 보관하도록 구성하세요.
예외 처리 고도화
커스텀 예외를 설계하고 구현하세요.
패키지명:
com.sprint.mission.discodeit.exception[.{도메인}]ErrorCodeEnum 클래스를 통해 예외 코드명과 메시지를 정의하세요.모든 예외의 기본이 되는
DiscodeitException클래스를 정의하세요.details는 예외 발생 상황에 대한 추가정보를 저장하기 위한 속성입니다.DiscodeitException을 상속하는 주요 도메인 별 메인 예외 클래스를 정의하세요.UserException,ChannelException등도메인 메인 예외 클래스를 상속하는 구체적인 예외 클래스를 정의하세요.
UserNotFoundException,UserAlreadyExistException등 필요한 예외를 정의하세요.기존에 구현했던 예외를 커스텀 예외로 대체하세요.
NoSuchElementExceptionIllegalArgumentExceptionErrorResponse를 통해 일관된 예외 응답을 정의하세요.int status: HTTP 상태코드String exceptionType: 발생한 예외의 클래스 이름앞서 정의한
ErrorResponse와@RestControllerAdvice를 활용해 예외를 처리하는 예외 핸들러를 구현하세요.ErrorResponse)을 가져야 합니다.유효성 검사
@NotNull,@NotBlank,@Size,@Email등@Valid를 사용해 요청 데이터를 검증하세요.MethodArgumentNotValidException을 전역 예외 핸들러에서 처리하세요.Actuator
Discodeit1.7.0173.4.0/actuator/info/actuator/metrics/actuator/health/actuator/loggers단위 테스트
Mockito를 활용해 Repository 의존성을 모의(mock)하세요.BDDMockito를 활용해 테스트 가독성을 높이세요.슬라이스 테스트
@DataJpaTest를 활용해 테스트를 구현하세요.application-test.yaml을 생성하세요.test프로파일을 활성화 하세요.@EnableJpaAuditing을 추가하세요.@WebMvcTest를 활용해 테스트를 구현하세요.WebMvcTest에서 자동으로 등록되지 않는 유형의 Bean이 필요하다면@Import를 활용해 추가하세요.예시
주요 컨트롤러(User, Channel, Message)에 대해 최소 2개 이상(성공, 실패)의 테스트 케이스를 작성하세요.
MockMvc를 활용해 컨트롤러를 테스트하세요.
서비스 레이어를 모의(mock)하여 컨트롤러 로직만 테스트하세요.
JSON 응답을 검증하는 테스트를 포함하세요.
통합 테스트
@SpringBootTest를 활용해 Spring 애플리케이션 컨텍스트를 로드하세요.@Transactional을 활용해 독립적으로 실행하세요.심화 요구사항
MDC를 활용한 로깅 고도화
MDCLoggingInterceptorcom.**.discodeit.configDiscodeit-Request-IDWebMvcConfigurer를 통해MDCLoggingInterceptor를 등록하세요.WebMvcConfigcom.**.discodeit.config로그 출력 예시
Spring Boot Admin을 활용한 메트릭 가시화
Spring Boot Admin 서버를 구현할 모듈을 생성하세요.
admin모듈의 메인 클래스에@EnableAdminServer어노테이션을 추가하고, 서버는 9090번 포트로 설정합니다.admin서버 실행 후 [localhost:9090/applications](http://localhost:9090/applications) 에 접속해봅니다.discodeit 프로젝트에 Spring Boot Admin Client를 적용합니다.
의존성을 추가합니다.
dependencies { ... implementation 'de.codecentric:spring-boot-admin-starter-client:3.4.5 }admin 서버에 등록될 수 있도록 설정 정보를 추가합니다.
discodeit 서버를 실행하고, admin 대시보드에 discodeit 인스턴스가 추가되었는지 확인합니다.
admin 대시보드 화면을 조작해보면서 각종 메트릭 정보를 확인해보세요.
테스트 커버리지 관리
JaCoCo 플러그인을 추가하세요.
테스트 실행 후 생성된 리포트를 분석해보세요.
build/reports/jacoco경로에서 확인할 수 있습니다.com.sprint.mission.discodeit.service.basic패키지에 대해서 60% 이상의 코드 커버리지를 달성하세요.