Skip to content

FEAT: 채팅 사진 전송·조회 및 AI 이미지 답장#68

Merged
oofrog merged 7 commits into
developfrom
feat/#65
Jul 26, 2026
Merged

FEAT: 채팅 사진 전송·조회 및 AI 이미지 답장#68
oofrog merged 7 commits into
developfrom
feat/#65

Conversation

@seokMini-2

Copy link
Copy Markdown
Collaborator

Summary

  • 채팅방 사진 전송/조회와, 그 사진에 대한 AI 답장을 구현했습니다

Related Issue

Describe your code

  • 작업 내용 (What I Did) :
  • 사진 전송, 저장, 조회 multipart 로 확장
  • JPEG/PNG 10MB 검증
  • chat_photo 엔티티 신규
  • 캐릭터 삭제 FK 위반 수정: 하드 삭제 시 chat_photo를 chat_message보다 먼저 삭제
  • history의 사진 메시지 content → "[사진]" (AI 400 방지)
  • 실패 구분: S3 객체 없음=스킵 / AI 일시오류=재시도 (텍스트 경로 재시도 복구)
  • S3 업로드를 트랜잭션 밖으로 분리 (ChatMessageWriter 신규) — 업로드 중 DB 커넥션 점유 제거
  • multipart max-request-size 10→12MB
  • 스크린샷/결과 (Optional) :
스크린샷 2026-07-26 033342
  • 논의사항/질문 (To Reviewers) :
  • application.yml 변경했습니다.
  • CharacterHardDeleteService 1줄 추가
  • AI 도메인파일은 수정하지 않고 주입/재사용만 했습니다,

Checklist

  • 리뷰어 등록

@seokMini-2 seokMini-2 self-assigned this Jul 26, 2026
@seokMini-2 seokMini-2 added the FEAT 기능 구현 label Jul 26, 2026
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 89c0d57c-668d-4aa1-9f7b-2f5199803c0d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#65

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

🛡️ 문제점

  • 없음

💡 개선 사항

  • ChatMessageService에서 중복되는 chatRoomFinder.getOwnedRoom 호출을 제거하여 불필요한 방 소유권 검사를 피하세요.
  • MessageType 내부에 헬퍼 메서드를 추가하여 반복되는 MessageType.IMAGEMessageType.TEXT_IMAGE 검사를 추출하세요.
  • 유지보수성 향상을 위해 AiImageChatClientChatMessageService 전반에 걸쳐 MIME 타입 및 헤더 문자열 상수를 중앙 집중화하세요.

@hyeonky0w0 hyeonky0w0 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

수고하셨습니다. 코멘트 확인부탁드립니다
추가로 (이건 반영 안하셔도 되는데 보안상.. 걸리는 부분이 있어서 그냥 말씀드립니다.)현재는 이미지 업로드가 Content-Type만 확인하고 있어 실제로는 JPEG/PNG가 아닌 파일도 이미지인 것처럼 업로드할 수 있을 것 같습니다. 파일 내용까지 함께 확인해 실제 이미지인지 검증하면 더 안전할 것 같습니다.

String photoUrl = null;
if (hasImage) {
validateImageType(image);
photoUrl = s3Uploader.upload(image, CHAT_PHOTO_DIR + "/" + chatRoomId);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

S3 업로드 후 DB 저장이 실패하면 사진 객체만 S3에 남을 수 있을 것 같습니다. saveUserMessage()에서 예외가 발생한 경우 업로드한 객체를 삭제하는 보상 처리를 추가하면 좋을 것 같습니다.

relationshipRepository.findByCharacterId(characterId).ifPresent(relationship -> {
proactiveContactScheduleRepository.deleteByRelationshipId(relationship.getId());
chatRoomRepository.findByRelationshipId(relationship.getId()).ifPresent(chatRoom -> {
chatPhotoRepository.deleteByChatRoomId(chatRoom.getId());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

현재 하드 삭제에서는 chat_photo DB 데이터만 삭제하고 실제 S3 객체는 삭제하지 않는 것 같습니다. 사진 URL을 먼저 조회해 둔 뒤 S3 객체까지 삭제하거나, 별도의 비동기 정리 작업을 두는 방식이 필요해 보입니다.

.contentType(MediaType.MULTIPART_FORM_DATA)
.body(body)
.retrieve()
.onStatus(HttpStatusCode::isError, (req, res) -> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

현재는 S3에 사진이 없는 경우를 제외하면 모든 오류를 다시 시도하도록 되어 있습니다. 그래서 요청 내용이 잘못된 4xx 오류처럼 다시 보내도 해결되지 않는 경우까지 계속 재시도될 수 있습니다. 네트워크 오류나 타임아웃, AI 서버의 5xx 오류만 재시도하고, 4xx 오류는 재시도하지 않고 건너뛰도록 구분하면 좋을 것 같습니다.

@github-actions

Copy link
Copy Markdown

🛡️ Issues

  • 문제 없음

💡 Improvements

  • ChatMessageWriter가 이미 다시 쿼리하므로 ChatMessageService.sendMessage에서 getOwnedRoom을 제거하여 불필요한 DB 쿼리를 피하세요.
  • AiImageChatClient의 하드코딩된 120초 이미지 읽기 타임아웃을 일관된 구성을 위해 AiServerProperties로 이동시키세요.
  • 클라이언트가 제공하는 MultipartFile.getContentType()의 MIME 타입을 신뢰하기보다 실제 파일 확장자 또는 매직 바이트를 확인하세요.

@github-actions

Copy link
Copy Markdown

💡 Improvements

  • ChatMessageService.sendMessage에서 chatRoomFinder.getOwnedRoom을 검증과 저장 시점에 중복 호출하지 않도록 파라미터로 넘겨 재사용하세요.
  • splitIntoChunksloadPhotoUrls에서 중복되는 메시지의 이미지 포함 여부 조건식을 MessageType.hasImage() 메서드로 추출하세요.
  • hasImageMagicBytes의 파일 시그니처 16진수 바이트 값(0xFF, 0xD8, 0x89 등)을 상수명으로 선언하여 가독성을 높이세요.

@oofrog
oofrog merged commit 3066c07 into develop Jul 26, 2026
2 checks passed
@oofrog
oofrog deleted the feat/#65 branch July 26, 2026 13:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FEAT 기능 구현

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ [FEAT] 사진 채팅 전송 구현

3 participants