Open
Conversation
-모든 FileRepository 구현체에 ReentrantLock 적용 - SpringDoc OpenAPI 의존성 추가
- UserStatus 업데이트 로직 및 PATCH 메서드 수정 - UserController 엔드포인트 변경 및 RequestBody 적용 - ChannelDto.Response 필드명 수정 (lastMessageAt)
- ChannelController 및 Service의 채널 생성 로직 수정 - UserController의 생성, 수정 메서드 RequestPart 어노테이션 적용 - 제공된 정적 리소스 파일 추가
- MessageController, ReadStatusController, BinaryContentController 로직 수정 - 연관된 Service 및 Entity 비즈니스 로직 수정
- Update 요청 DTO 필드명 변경 - RequestParam 어노테이션에 키(value) 지정 - 프론트엔드 연동 및 API 일관성 확보를 위한 리팩토링
- ErrorResponse 및 BusinessLogicException 기반의 공통 예외 응답 규격 적용 - 서비스 계층 내 하드코딩된 예외를 커스텀 예외로 교체 - BasicChannelService 참여자 목록 동기화 누락 해결 - 미사용 Import 제거 및 코드 최적화 진행
- BasicChannelService 채널 전체 조회 시 lastMessageAt 필드 누락 문제 해결 - 공개 및 비공개 채널의 최근 메시지 시간(Instant) 매핑 로직 적용 - 프라이빗 메서드 추출(getParticipantIds, getLastMessageAt)을 통한 코드 가독성 개선
- 내부 클래스로 관리되던 DTO를 도메인별 개별 클래스로 추출 - 어노테이션을 통한 요청 데이터 유효성 검증 로직 적용 - DTO 클래스 분리에 따른 연관 Service 및 Controller 참조 로직 수정
- build.gradle: Spring Data JPA 및 MapStruct 의존성 추가 - application.yaml: 데이터베이스 연결 및 JPA/SQL 디버깅 로그 설정 추가 - schema.sql: 초기 테이블 생성을 위한 데이터베이스 스키마 정의 파일 추가
- BaseEntity 추상 클래스 생성 및 JPA Auditing 적용 - 엔티티 간 ID 참조 방식을 객체 참조 기반의 연관관계 매핑으로 개편 - ManyToOne, OneToMany 설정 및 영속성 전이(cascade), 고아 객체 제거 적용 - JpaRepository 기반 레포지토리 재작성 및 기존(JCF, File) 구현체 삭제
- BinaryContentStorage 인터페이스 설계 및 로컬 구현체 추가 - ConditionalOnProperty 기반 스토리지 자동 빈 등록 설정 - 파일 다운로드 API 구현 및 ResponseEntity 반환 타입 적용
- Pageable을 활용한 오프셋 방식 페이지네이션 로직 적용 - 공통 응답 규격 PageResponse DTO 도입 및 데이터 직렬화 최적화
- N+1 문제 해결 및 OSIV 비활성화에 따른 쿼리 효율성 개선 - Transactional 경계 설정 및 변경 감지(Dirty Checking) 기반 로직 리팩토링
- ReadStatus 엔티티 업데이트 로직 수정 및 요청 DTO 필드 추가 - Channel 엔티티 (name, description) Nullable 허용 - 파일 다운로드 Content-Disposition 헤더 추가 및 로그인 401 상태 코드 반영 - ErrorResponse 수정
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.
프로젝트 마일스톤
요구사항
기본
API 명세
데이터베이스
discodeitdiscodeit_userdiscodeit1234PK: Primary KeyUK: Unique KeyNN: Not NullFK: Foreign KeyON DELETE CASCADE: 연관 엔티티 삭제 시 같이 삭제ON DELETE SET NULL: 연관 엔티티 삭제 시 NULL로 변경Spring Data JPA 적용하기
application.yml파일에 작성하세요.application.yml파일에 작성하세요.엔티티 정의하기
com.sprint.mission.discodeit.entity.baseJPA의 어노테이션을 활용해
createdAt,updatedAt속성이 자동으로 설정되도록 구현하세요.@CreatedDate,@LastModifiedDate클래스 다이어그램을 참고해 클래스 참조 관계를 수정하세요. 필요한 경우 생성자, update 메소드를 수정할 수 있습니다. 단, 아직 JPA Entity와 관련된 어노테이션은 작성하지 마세요.
화살표의 방향과 화살표 유무에 유의하세요.
ERD와 클래스 다이어그램을 토대로 연관관계 매핑 정보를 표로 정리해보세요.(이 내용은 PR에 첨부해주세요.)
JPA 주요 어노테이션을 활용해 ERD, 연관관계 매핑 정보를 도메인 모델에 반영해보세요.
@Entity,@Table@Column,@Enumerated@OneToMany,@OneToOne,@ManyToOne@JoinColumn,@JoinTableERD의 외래키 제약 조건과 연관관계 매핑 정보의 부모-자식 관계를 고려해 영속성 전이와 고아 객체를 정의하세요.
cascade,orphanRemoval레포지토리와 서비스에 JPA 도입하기
DTO 적극 도입하기
Entity를 Controller 까지 그대로 노출했을 때 발생할 수 있는 문제점에 대해 정리해보세요. DTO를 적극 도입했을 때 보일러플레이트 코드가 많아지지만, 그럼에도 불구하고 어떤 이점이 있는지 알 수 있을거에요.(이 내용은 PR에 첨부해주세요.)
다음의 클래스 다이어그램을 참고하여 DTO를 정의하세요.
com.sprint.mission.discodeit.mapperBinaryContent 저장 로직 고도화
데이터베이스에 이미지와 같은 파일을 저장하면 성능 상 불리한 점이 많습니다. 따라서 실제 바이너리 데이터는 별도의 공간에 저장하고, 데이터베이스에는 바이너리 데이터에 대한 메타 정보(파일명, 크기, 유형 등)만 저장하는 것이 좋습니다.
com.sprint.mission.discodeit.storageBinaryContentStorage
서비스 레이어에서 기존에 BinaryContent를 저장하던 로직을 BinaryContentStorage를 활용하도록 리팩토링하세요.
BinaryContentController에 파일을 다운로드하는 API를 추가하고, BinaryContentStorage에 로직을 위임하세요.
엔드포인트:
GET /api/binaryContents/{binaryContentId}/download요청
응답:
ResponseEntity<?>클래스 다이어그램
로컬 디스크 저장 방식으로 BinaryContentStorage 구현체를 구현하세요.
클래스 다이어그램
discodeit.storage.type값이local인 경우에만 Bean으로 등록되어야 합니다.Path root
discodeit.storage.local.root-path설정값을 정의하고, 이 값을 통해 주입합니다.void init()Path resolvePath(UUID){root}/{UUID}ResponseEntity<Resource> donwload(BinaryContentDto)get메소드를 통해 파일의 바이너리 데이터를 조회합니다.ResponseEntity<Resource>응답을 생성 후 반환합니다.페이징과 정렬
com.sprint.mission.discodeit.dto.responsecontent: 실제 데이터입니다.number: 페이지 번호입니다.size: 페이지의 크기입니다.totalElements: T 데이터의 총 갯수를 의미하며, null일 수 있습니다.Slice 또는 Page 객체로부터 DTO를 생성하는 Mapper를 구현하세요.
com.sprint.mission.discodeit.mapper심화
N+1 문제
읽기전용 트랜잭션 활용
프로덕션 환경에서는 OSIV를 비활성화하는 경우가 많습니다. 이때 서비스 레이어의 조회 메소드에서 발생할 수 있는 문제를 식별하고, 읽기 전용 트랜잭션을 활용해 문제를 해결해보세요.
OSIV 비활성화하기
페이지네이션 최적화
오프셋 페이지네이션과 커서 페이지네이션 방식의 차이에 대해 정리해보세요.
기존에 구현한 오프셋 페이지네이션을 커서 페이지네이션으로 리팩토링하세요.
다음의 API 명세를 준수하세요.
API 스펙을 준수한다면, 아래의 프론트엔드 코드와 호환됩니다.
MapStruct 적용
스크린샷
멘토에게