이용일 sprint7 늦은제출#165
Hidden character warning
Conversation
* Re:Zero * FileRepository created * 복구완료 * 스프린트미션3 세í시작��세팅시작점 * bean 추가 작업(미완성) * 다시만들어낸 Bean(메인ì�은 너무 어렵다) * configBean * 롬복?êRombok+Time+Status * 고도화전 중간저장 * DTO find 작업중 * ë유저서비스 find고도화 작업중 * 아DTO작업에서 막힘 * ì 미완성 제출 * 베이스코드 받아옴 --------- Co-authored-by: 이용일 <lyi980403> # Conflicts: # build.gradle # src/main/java/com/sprint/mission/discodeit/DiscodeitApplication.java # src/main/java/com/sprint/mission/discodeit/dto/data/ChannelDto.java # src/main/java/com/sprint/mission/discodeit/dto/data/UserDto.java # src/main/java/com/sprint/mission/discodeit/dto/request/BinaryContentCreateRequest.java # src/main/java/com/sprint/mission/discodeit/dto/request/LoginRequest.java # src/main/java/com/sprint/mission/discodeit/dto/request/MessageCreateRequest.java # src/main/java/com/sprint/mission/discodeit/dto/request/MessageUpdateRequest.java # src/main/java/com/sprint/mission/discodeit/dto/request/PrivateChannelCreateRequest.java # src/main/java/com/sprint/mission/discodeit/dto/request/PublicChannelCreateRequest.java # src/main/java/com/sprint/mission/discodeit/dto/request/PublicChannelUpdateRequest.java # src/main/java/com/sprint/mission/discodeit/dto/request/ReadStatusCreateRequest.java # src/main/java/com/sprint/mission/discodeit/dto/request/ReadStatusUpdateRequest.java # src/main/java/com/sprint/mission/discodeit/dto/request/UserCreateRequest.java # src/main/java/com/sprint/mission/discodeit/dto/request/UserStatusCreateRequest.java # src/main/java/com/sprint/mission/discodeit/dto/request/UserStatusUpdateRequest.java # src/main/java/com/sprint/mission/discodeit/dto/request/UserUpdateRequest.java # src/main/java/com/sprint/mission/discodeit/entity/BinaryContent.java # src/main/java/com/sprint/mission/discodeit/entity/Channel.java # src/main/java/com/sprint/mission/discodeit/entity/ChannelType.java # src/main/java/com/sprint/mission/discodeit/entity/Message.java # src/main/java/com/sprint/mission/discodeit/entity/ReadStatus.java # src/main/java/com/sprint/mission/discodeit/entity/User.java # src/main/java/com/sprint/mission/discodeit/entity/UserStatus.java # src/main/java/com/sprint/mission/discodeit/repository/BinaryContentRepository.java # src/main/java/com/sprint/mission/discodeit/repository/ChannelRepository.java # src/main/java/com/sprint/mission/discodeit/repository/MessageRepository.java # src/main/java/com/sprint/mission/discodeit/repository/ReadStatusRepository.java # src/main/java/com/sprint/mission/discodeit/repository/UserRepository.java # src/main/java/com/sprint/mission/discodeit/repository/UserStatusRepository.java # src/main/java/com/sprint/mission/discodeit/service/AuthService.java # src/main/java/com/sprint/mission/discodeit/service/BinaryContentService.java # src/main/java/com/sprint/mission/discodeit/service/ChannelService.java # src/main/java/com/sprint/mission/discodeit/service/MessageService.java # src/main/java/com/sprint/mission/discodeit/service/ReadStatusService.java # src/main/java/com/sprint/mission/discodeit/service/UserService.java # src/main/java/com/sprint/mission/discodeit/service/UserStatusService.java # src/main/java/com/sprint/mission/discodeit/service/basic/BasicAuthService.java # src/main/java/com/sprint/mission/discodeit/service/basic/BasicBinaryContentService.java # src/main/java/com/sprint/mission/discodeit/service/basic/BasicChannelService.java # src/main/java/com/sprint/mission/discodeit/service/basic/BasicMessageService.java # src/main/java/com/sprint/mission/discodeit/service/basic/BasicReadStatusService.java # src/main/java/com/sprint/mission/discodeit/service/basic/BasicUserService.java # src/main/java/com/sprint/mission/discodeit/service/basic/BasicUserStatusService.java # src/main/resources/application.yaml
joonfluence
left a comment
There was a problem hiding this comment.
PR 리뷰: 이용일 sprint7
전체 요약
Spring Boot 프로파일 기반 설정 분리, Logback 로깅 구성, 커스텀 예외 처리 체계(DiscodeitException 계층), Spring Validation, Actuator, 그리고 서비스/레포지토리/컨트롤러/통합 테스트를 추가한 스프린트7 구현입니다. 전반적으로 예외 계층 설계와 테스트 구조가 잘 잡혀 있지만, 보안 취약점(운영 DB 자격증명 하드코딩) 및 불필요한 파일 커밋 등 반드시 수정이 필요한 사항이 있습니다.
[P2] 커밋에 포함되어서는 안 되는 파일들
PR에 다음과 같이 커밋에 포함되어서는 안 되는 파일들이 있습니다:
.logs/app-2026-03-27.log,.logs/app-2026-04-05.log,.logs/app.log— 런타임에 생성되는 로그 파일.discodeit/storage/c1bdadbd-...,c35a78db-...— 로컬 바이너리 스토리지 데이터tatus—git log명령어 출력 결과가 실수로 파일로 커밋된 것으로 보입니다truct만 하면 끝—less명령어 매뉴얼이 실수로 파일로 커밋됨src/main/resources/fe_bundle_1.2.3.zip, 각종 PNG 이미지 등 바이너리 파일
.gitignore에 .logs/, .discodeit/, *.log 등을 추가하고 해당 파일들을 정리해 주세요.
| datasource: | ||
| url: jdbc:postgresql://prod-server/mydb # 운영용 DB | ||
| username: prod_user | ||
| password: prod_password |
There was a problem hiding this comment.
[P1] 운영 환경 DB 자격증명 하드코딩 — 반드시 수정 필요
운영 DB의 username과 password가 소스 코드에 직접 노출되어 있습니다. 퍼블릭 저장소에 올라갈 경우 즉각적인 보안 사고로 이어질 수 있으며, 프라이빗 저장소라도 Git 히스토리에 영구적으로 남습니다. 환경 변수 또는 외부 시크릿 관리를 통해 주입받도록 변경해주세요.
| password: prod_password | |
| username: ${DB_USERNAME} | |
| password: ${DB_PASSWORD} |
| @@ -0,0 +1,2 @@ | |||
| server: | |||
There was a problem hiding this comment.
[P2] .properties 파일에 YAML 형식으로 작성됨
application.properties 파일은 key=value 형식을 사용해야 합니다. 현재 YAML 형식으로 작성되어 있어 Spring Boot가 이 설정을 올바르게 파싱하지 못합니다. 이미 application-dev.yaml이 있으므로 이 파일을 제거하거나, 아래와 같이 올바른 형식으로 수정해 주세요.
| server: | |
| server.port=8080 |
| username: sa | ||
| password: | ||
|
|
||
| main: |
There was a problem hiding this comment.
[P2] YAML 들여쓰기 오류 — spring.main 설정이 datasource.password 하위에 위치함
spring.main.allow-bean-definition-overriding을 설정하려는 의도였겠지만, 현재 들여쓰기 구조에서는 spring.datasource.password.main.allow-bean-definition-overriding으로 파싱됩니다. 빈 오버라이딩 설정이 실제로 적용되지 않을 수 있습니다. main: 블록을 spring: 직하위로 이동시켜 주세요:
spring:
datasource:
url: ...
username: sa
password:
main:
allow-bean-definition-overriding: true| </appender> | ||
|
|
||
| <!-- Root에 연결 --> | ||
| <root level="info"> |
There was a problem hiding this comment.
[P3] 프로파일별 로그 레벨 미적용
요구사항에서 개발 환경은 debug, 운영 환경은 info 레벨로 설정하라고 명시되어 있지만, 현재 <root level="info">로 항상 고정되어 있습니다. <springProfile> 태그를 활용해 프로파일별 로그 레벨을 분기해 주세요:
<springProfile name="dev">
<root level="debug">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</springProfile>
<springProfile name="prod">
<root level="info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</springProfile>|
|
||
| logging: | ||
| level: | ||
| com.your.package: info No newline at end of file |
There was a problem hiding this comment.
[P3] 패키지명 플레이스홀더가 실제 패키지명으로 대체되지 않음
com.your.package는 템플릿의 예시 값으로, 이 상태에서는 로깅 설정이 아무 효과도 없습니다. 실제 프로젝트 패키지명으로 교체해 주세요.
| com.your.package: info | |
| com.sprint.mission.discodeit: info |
| String exceptionType, | ||
| int status | ||
| ) { | ||
| public static ErrorResponse of(DiscodeitException e, String path) { |
There was a problem hiding this comment.
[P4] path 파라미터를 받지만 사용하지 않음
of(DiscodeitException e, String path) 메서드에서 path를 파라미터로 받지만 ErrorResponse 생성 시 전혀 사용하지 않습니다. ErrorResponse 레코드에 path 필드를 추가하거나, 사용하지 않는 파라미터를 제거하는 것을 고려해 보세요.
| log.error("처리되지 않은 예외 발생: path={}, message={}", | ||
| request.getRequestURI(), e.getMessage()); | ||
| return ResponseEntity | ||
| .status(500) |
There was a problem hiding this comment.
[P4] 이미 import된 클래스를 풀 패키지명으로 사용
파일 상단에 import java.time.Instant;와 import java.util.Map;이 이미 선언되어 있는데, 메서드 내에서 java.time.Instant.now(), java.util.Map.of()처럼 풀 패키지명으로 사용하고 있습니다. 단순 일관성 문제입니다.
| .status(500) | |
| Instant.now(), |
요구사항
기본 요구사항
프로파일 기반 설정 관리
[x] 개발, 운영 환경에 대한 프로파일을 구성하세요.
[x] application-dev.yaml, application-prod.yaml 파일을 생성하세요.
[x] 다음과 같은 설정값을 프로파일별로 분리하세요.
[x] 데이터베이스 연결 정보
[x] 서버 포트
로그 관리
[x] Lombok의 @slf4j 어노테이션을 활용해 로깅을 쉽게 추가할 수 있도록 구성하세요.
[x] application.yaml에 기본 로깅 레벨을 설정하세요.
기본적으로 info 레벨로 설정합니다.
[x] 환경 별 적절한 로깅 레벨을 프로파일 별로 설정해보세요.
SQL 로그를 보기위해 설정했던 레벨은 유지합니다.
우리가 작성한 프로젝트의 로그는 개발 환경에서 debug, 운영 환경에서는 info 레벨로 설정합니다.
[x] Spring Boot의 기본 로깅 구현체인 Logback의 설정 파일을 구성하세요.
[x] logback-spring.xml 파일을 생성하세요.
[x] 다음 예시와 같은 로그 메시지를 출력하기 위한 로깅 패턴과 출력 방식을 커스터마이징하세요.
[x] 콘솔과 파일에 동시에 로그를 기록하도록 설정하세요.
[x] 파일은 {프로젝트 루트}/.logs 경로에 저장되도록 설정하세요.
[x] 로그 파일은 일자별로 롤링되도록 구성하세요.
[x] 로그 파일은 30일간 보관하도록 구성하세요.
[x] 서비스 레이어와 컨트롤러 레이어의 주요 메소드에 로깅을 추가하세요.
[x] 로깅 레벨을 적절히 사용하세요: ERROR, WARN, INFO, DEBUG
[x] 다음과 같은 메소드에 로깅을 추가하세요:
[x] 사용자 생성/수정/삭제
[x] 채널 생성/수정/삭제
[x] 메시지 생성/수정/삭제
[x] 파일 업로드/다운로드
예외 처리 고도화
[x] 커스텀 예외를 설계하고 구현하세요.
[x] ErrorCode Enum 클래스를 통해 예외 코드명과 메시지를 정의하세요.
[x] 모든 예외의 기본이 되는 DiscodeitException 클래스를 정의하세요.
클래스 다이어그램
[x] DiscodeitException을 상속하는 주요 도메인 별 메인 예외 클래스를 정의하세요.
[x] 도메인 메인 예외 클래스를 상속하는 구체적인 예외 클래스를 정의하세요.
UserNotFoundException, UserAlreadyExistException 등 필요한 예외를 정의하세요.
[x] 기존에 구현했던 예외를 커스텀 예외로 대체하세요.
NoSuchElementException
IllegalArgumentException
…
[x] ErrorResponse를 통해 일관된 예외 응답을 정의하세요.
클래스 다이어그램
3gqeampkw-image.png
int status: HTTP 상태코드
String exceptionType: 발생한 예외의 클래스 이름
[x] 앞서 정의한 ErrorResponse와 @RestControllerAdvice를 활용해 예외를 처리하는 예외 핸들러를 구현하세요.
모든 핸들러는 일관된 응답(ErrorResponse)을 가져야 합니다.
유효성 검사
[x] Spring Validation 의존성을 추가하세요.
[x] 주요 Request DTO에 제약 조건 관련 어노테이션을 추구하세요.
@NotNull, @notblank, @SiZe, @Email 등
[x] 컨트롤러에 @Valid 를 사용해 요청 데이터를 검증하세요.
[x] 검증 실패 시 발생하는 MethodArgumentNotValidException을 전역 예외 핸들러에서 처리하세요.
[x] 유효성 검증 실패 시 상세한 오류 메시지를 포함한 응답을 반환하세요.
Actuator
[x] Spring Boot Actuator 의존성을 추가하세요.
[x] 기본 Actuator 엔트포인트를 설정하세요.
health, info, metrics, loggers
[x] Actuator info를 위한 애플리케이션 정보를 추가하세요.
애플리케이션 이름: Discodeit
애플리케이션 버전: 1.7.0
자바 버전: 17
스프링 부트 버전: 3.4.0
주요 설정 정보
데이터소스: url, 드라이버 클래스 이름
jpa: ddl-auto
storage 설정: type, path
multipart 설정: max-file-size, max-request-size
[x] Spring Boot 서버를 실행 후 각종 정보를 확인해보세요.
/actuator/info
/actuator/metrics
/actuator/health
/actuator/loggers
단위 테스트
[x] 서비스 레이어의 주요 메소드에 대한 단위 테스트를 작성하세요.
[x] 다음 서비스의 핵심 메소드에 대해 각각 최소 2개 이상(성공, 실패)의 테스트 케이스를 작성하세요.
[x] UserService: create, update, delete 메소드
[x] ChannelService: create(PUBLIC, PRIVATE), update, delete, findByUserId 메소드
[x] MessageService: create, update, delete, findByChannelId 메소드
[x] Mockito를 활용해 Repository 의존성을 모의(mock)하세요.
[x] BDDMockito를 활용해 테스트 가독성을 높이세요.
슬라이스 테스트
[x] 레포지토리 레이어의 슬라이스 테스트를 작성하세요.
[x] @DataJpaTest를 활용해 테스트를 구현하세요.
[x] 테스트 환경을 구성하는 프로파일을 구성하세요.
[x] application-test.yaml을 생성하세요.
[x] 데이터소스는 H2 인메모리 데이터 베이스를 사용하고, PostgreSQL 호환 모드로 설정하세요.
[x] H2 데이터베이스를 위해 필요한 의존성을 추가하세요.
[x] 테스트 시작 시 스키마를 새로 생성하도록 설정하세요.
[x] 디버깅에 용이하도록 로그 레벨을 적절히 설정하세요.
[x] 테스트 실행 간 test 프로파일을 활성화 하세요.
[x] JPA Audit 기능을 활성화 하기 위해 테스트 클래스에 @EnableJpaAuditing을 추가하세요.
[x] 주요 레포지토리(User, Channel, Message)의 주요 쿼리 메소드에 대해 각각 최소 2개 이상(성공, 실패)의 테스트 케이스를 작성하세요.
[x] 커스텀 쿼리 메소드
[x] 페이징 및 정렬 메소드
[x] 컨트롤러 레이어의 슬라이스 테스트를 작성하세요.
[x] @WebMvcTest를 활용해 테스트를 구현하세요.
[x] WebMvcTest에서 자동으로 등록되지 않는 유형의 Bean이 필요하다면 @import를 활용해 추가하세요.
[x] 주요 컨트롤러(User, Channel, Message)에 대해 최소 2개 이상(성공, 실패)의 테스트 케이스를 작성하세요.
[x] MockMvc를 활용해 컨트롤러를 테스트하세요.
[x] 서비스 레이어를 모의(mock)하여 컨트롤러 로직만 테스트하세요.
[x] JSON 응답을 검증하는 테스트를 포함하세요.
통합 테스트
[x] 통합 테스트 환경을 구성하세요.
[ ] @SpringBootTest를 활용해 Spring 애플리케이션 컨텍스트를 로드하세요.
[x] H2 인메모리 데이터베이스를 활용하세요.
[ ] 테스트용 프로파일을 구성하세요.
[ ] 주요 API 엔드포인트에 대한 통합 테스트를 작성하세요.
[ ] 주요 API에 대해 최소 2개 이상의 테스트 케이스를 작성하세요.
[ ] 사용자 관련 API (생성, 수정, 삭제, 목록 조회)
[ ] 채널 관련 API (생성, 수정, 삭제)
[ ] 메시지 관련 API (생성, 수정, 삭제, 목록 조회)
[ ] 각 테스트는 @transactional을 활용해 독립적으로 실행하세요.
심화
주요 변경사항
스크린샷
멘토에게