Skip to content

Comments

[이다솔] Sprint4#138

Open
LeeDyol wants to merge 188 commits intocodeit-bootcamp-spring:이다솔from
LeeDyol:sprint4
Open

[이다솔] Sprint4#138
LeeDyol wants to merge 188 commits intocodeit-bootcamp-spring:이다솔from
LeeDyol:sprint4

Conversation

@LeeDyol
Copy link
Collaborator

@LeeDyol LeeDyol commented Feb 11, 2026

요구사항

기본

  • DiscodeitApplication 테스트 로직 삭제
  • 서비스 로직을 활용한 웹 API 구현 (@RequestMapping 활용)
  • 웹 API 예외 전역 처리 (@RestControllerAdvice)

웹 API 요구사항

  • 사용자 관리 (등록, 수정, 삭제, 전체 조회, 온라인 상태 업데이트)
  • 권한 관리 (로그인 기능)
  • 채널 관리 (공개 / 비공개 채널 생성, 공개 채널 수정, 삭제, 사용자별 채널 목록 조회)
  • 메시지 관리 (전송, 수정, 삭제, 채널별 메시지 목록 조회)
  • 메시지 수신 정보 관리 (생성, 수정, 조회)
  • 바이너리 파일 다운로드 (단건 및 다건 조회)

심화

  • 제공된 정적 리소스를 활용한 사용자 목록 화면 서빙
  • 생성형 AI를 활용한 커스텀 사용자 목록 화면 구현 (custom-list.html)

주요 변경사항

  • 스트림 내부에서 DB를 반복 호출하던 로직을 Map 기반의 인메모리 조회 방식으로 개선
  • 스트림 내부에서 수행되던 DB 저장 및 수정 로직을 스트림 밖으로 분리하여 함수성 프로그래밍의 순수성 유지

스크린샷

Discodeit.postman_collection.json

멘토에게

  • 셀프 코드 리뷰를 통해 질문 이어가겠습니다.

LeeDyol added 30 commits January 9, 2026 11:11
Comment on lines +27 to +33
// 첨부 파일 단건 조회
@RequestMapping(value = "/find", method = RequestMethod.GET)
public ResponseEntity<BinaryContentEntity> findById (@RequestParam UUID binaryContentId) {
BinaryContentEntity binaryContent = binaryContentService.findEntityById(binaryContentId);

return ResponseEntity.ok(binaryContent);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

RESTFul API에서 GET이 이미 자원에 대한 조회의 의미를 내포하기 때문에 /find 굳이 추가할 필요 없습니다!

Copy link
Collaborator

@joonfluence joonfluence left a comment

Choose a reason for hiding this comment

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

LGTM

Comment on lines +16 to +20
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class ChannelController {
private final ChannelService channelService;
Copy link
Collaborator

Choose a reason for hiding this comment

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

v1 버저닝을 추가 해주는 것도 좋습니다 (계속 버전이 변화될 수 있기 때문에) 나중에 추가하긴 어렵거든요

Comment on lines +30 to +36
// 비공개 채널 생성
@RequestMapping(value = "/channel/private", method = RequestMethod.POST)
public ResponseEntity<ChannelResponseDTO> createPrivateChannel(@RequestBody PrivateChannelCreateRequestDTO privateChannelCreateRequestDTO) {
ChannelResponseDTO newChannel = channelService.createPrivateChannel(privateChannelCreateRequestDTO);

return ResponseEntity.status(HttpStatus.CREATED).body(newChannel);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

과제에서 요구사항 대로 하신 것 같아 이해하지만, [POST] "/api/channels/public, private" private, public을 Body 값 안에 넣어서 처리하는 방식이 더 깔끔할 것 같긴 합니다. 정말 분리되어야 하면 모르겠지만 거의 구현 코드가 비슷할거거든요

Copy link
Collaborator

Choose a reason for hiding this comment

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

ChannelResponseDTO 별도로 선언해주신 것 좋네요 👍

Comment on lines +48 to +59
userRepository.findById(privateChannelCreateRequestDTO.userId())
.orElseThrow(() -> new IllegalArgumentException("해당 사용자가 존재하지 않습니다."));

ChannelEntity newChannel = new ChannelEntity(privateChannelCreateRequestDTO);
channelRepository.save(newChannel);

List<ReadStatusEntity> newReadStatues = newChannel.getMembers().stream()
.map(memberId -> new ReadStatusCreateRequestDTO(memberId, newChannel.getId()))
.map(ReadStatusEntity::new)
.toList();

newReadStatues.forEach(readStatusRepository::save);
Copy link
Collaborator

Choose a reason for hiding this comment

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

각각을 별도 private 메서드로 분리해도 좋겠네요

  1. valiateUserExists
  2. createChannel
  3. ...

Comment on lines +200 to +213
public ChannelResponseDTO toResponseDTO(ChannelEntity channel) {
return ChannelResponseDTO.builder()
.id(channel.getId())
.userId(channel.getUserId())
.channelName(channel.getChannelName())
// 비공개 채널일 때만 member 리스트 반환
.members((channel.getType() == ChannelType.PRIVATE)? channel.getMembers() : List.of())
.channelType(channel.getType())
.description(channel.getDescription())
.createdAt(channel.getCreatedAt())
.updatedAt(channel.getUpdatedAt())
.lastMessageAt(messageRepository.getLastMessageAt(channel.getId()))
.build();
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

ResponseDto로 변환하는 역할이 Service의 책임일까요? 한번 고민해보시면 좋을 것 같습니다!

.orElseThrow(() -> new IllegalArgumentException("해당 채널이 존재하지 않습니다."));

// Private 채널은 채널 참여자만 조회 가능
if (targetChannel.getType() == ChannelType.PRIVATE &&
Copy link
Collaborator

Choose a reason for hiding this comment

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

ChannelType.PRIVATE.equals(targetChannel.getType())

});

// 삭제된 사용자가 발행한 메시지 연쇄 삭제
List<MessageEntity> deleteMessages = messageRepository.findAll().stream()
Copy link
Collaborator

Choose a reason for hiding this comment

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

messagesTodelete

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants