Skip to content

Comments

feat: 멤버, 학습로그 이미지 presigned URL 발급 및 컨펌 기능 구현 (#76)#78

Merged
hisonghy merged 1 commit intodevelopfrom
feat/76
Oct 11, 2025
Merged

feat: 멤버, 학습로그 이미지 presigned URL 발급 및 컨펌 기능 구현 (#76)#78
hisonghy merged 1 commit intodevelopfrom
feat/76

Conversation

@hisonghy
Copy link
Contributor

@hisonghy hisonghy commented Oct 9, 2025

📌 작업 내용 및 특이사항

✅ StudyLog 엔티티 필드 추가

  • StudyLog 엔티티에 image_url 필드를 추가했습니다.
  • 기본 이미지가 존재하지 않고 이미지를 등록하지 않을 수 있기 때문에 image_url 필드는 NULL이 허용되도록 구성했습니다.
  • DB 마이그레이션을 위해 V3__add_image_url_column_to_study_log.sql 파일을 추가했습니다.

✅ Member 프로필 이미지 관련 기능 구현

  • 멤버 프로필 이미지를 S3에 업로드하기 위한 Presigned PUT URL을 발급하는 기능을 구현했습니다.
  • 클라이언트에서 업로드를 수행하고, 업로드된 이미지를 검증 및 확정하는 confirm 기능을 구현했습니다.
  • 멤버 프로필 이미지 업로드 흐름은 다음과 같이 설계했습니다.
1) 멤버 수정 화면에서 수정하기 버튼을 클릭합니다.

2) 이때 만약 프로필 이미지를 변경했다면 해당 파일이름과 함께 본 API를 호출합니다.(예: abc.jpeg 형태)
2-1) 프로필 이미지를 변경하지 않았으면 멤버 수정 API를 호출합니다. (닉네임 또는 카테고리를 수정했을 경우)

3) 서버는 업로드에 사용할 Presigned PUT URL과 임시 키(tmpKey)를 반환합니다.

4) 클라이언트는 반환된 Presigned URL로 이미지를 S3에 업로드합니다.

5) 업로드가 정상 완료되면 즉시 프로필 이미지 Confirm API를 호출하여 이미지를 검증 및 확정하고 멤버 프로필에 적용합니다.

6) 이후 다른 수정 사항이 있다면 멤버 수정 API를 호출합니다. (닉네임 또는 카테고리도 수정했을 경우)
  • confirm API 대신 업로드이후 멤버 수정 API에서 변경된 이미지 작업을 수행해도 되지만

✅ StudyLog 이미지 관련 기능 구현

  • 학습로그 이미지를 S3에 업로드하기 위한 Presigned PUT URL을 발급하는 기능을 구현했습니다.
  • 클라이언트에서 업로드를 수행하고, 업로드된 이미지를 검증 및 확정하는 confirm 기능을 구현했습니다.
  • 학습로그 이미지 업로드 흐름은 다음과 같이 설계했습니다.
1) 먼저 학습 로그 생성 API를 호출해 StudyLogId를 응답받습니다.

2) 사용자가 이미지를 첨부했을 경우, 생성 시 받은 StudyLogId를 PathVariable로 전달하여
업로드용 파일명 정보를 함께 Presigned URL 발급 API를 요청합니다.
서버는 업로드에 사용할 Presigned PUT URL과 임시키(tmpKey)를 반환합니다.

3) 반환받은 Presigned URL로 PUT 요청을 통해 이미지를 S3에 업로드합니다.

4) 업로드가 정상적으로 완료되면 바로 학습 로그 이미지 Confirm API를 호출합니다.
이때 Presigned URL 발급 API에서 반환받은 임시키(tmpKey)를 함께 요청합니다.
서버는 업로드된 이미지를 검증(크키/MIME)하고 확정합니다.
  • 학습 로그 이미지는 생성 시 함께 등록해야 하지만, 엔티티 ID가 생성되기 전에는 존재하지 않아 최종 저장 경로(예: study-logs/{studyLogId}/...)를 확정할 수 없습니다.
    따라서 먼저 학습 로그를 생성해 ID를 발급받은 뒤 이미지가 존재한다면 Presigned URL을 요청하고 Confrim API를 요청하는 흐름으로 우선 설계했습니다.
    추후 더 좋은 방법을 찾아보고 리팩토링하는 방향으로 생각중입니다.

✅ ImageUrlUtil 추가

  • 기존 global.resolverCdnUrlResolver를 제거했습니다.
  • 이미지의 최종 경로를 생성하고, 최종 경로에서 이미지 키를 추출하는 책임은 image 도메인에서 담당하는 게 적절하다고 판단해 ImageServiceCdnUrlResovler를 의존하던 부분을 없애고 image.domain.utilImageUrlUtil를 추가해 순수 함수로 해당 로직을 처리하도록 변경했습니다.
  • 이에 따라 ImageService.confirm()에서 **finalKey(최종 이미지 키)**를 반환하지 않고 최종 이미지 경로를 반환하도록 수정했습니다.
  • 최종 경로를 생성하는 build() 메서드와 최종 경로에서 이미지 키를 추출하는 extractKey() 메서드를 정의했습니다.
  • extractKey()는 유효하지 않은 경로일 경우 Optional.empty()를 반환하고, 호출부에서는 이를 감안해 삭제/갱신 로직을 건너뛰도록 처리했습니다.
    예를 들어 멤버의 프로필 이미지가 카카오 프로필 URL이면 우리 스토리지 경로가 아니기 때문에 extractKey()에서 빈 값을 반환하고, S3 삭제를 수행하지않도록 구성했습니다.

✅ 이미지 정리 기능 추가

  • 이미지를 변경할 경우, S3 스토리지에 남아있는 과거 이미지 파일을 정리하기 위해 ImageServicecleanup 기능을 추가했습니다.
  • 새로운 이미지 경로로 변경하기 전에 기존 이미지 URL에서 키를 추출해 해당 S3 객체를 안전하게 삭제하도록 처리했습니다.
  • 정리(삭제) 전에 객체 존재 여부를 별도로 조회하지 않도록 구성했습니다.
    S3 삭제는 멱등이어서 대상이 없어도 예외 없이 성공 처리되므로, 별도의 존재 확인이나 예외 처리가 불필요하다고 판단했습니다.
  • 회원 탈퇴 로직에도 해당 기능을 추가해 탈퇴 시 잔여 프로필 이미지를 제거하도록 했습니다.
  • 현재 학습 로그는 별도 삭제 API가 없고 배치로 일괄 삭제되므로, 추후 StudyLog 삭제 시점에 이미지도 함께 제거되도록 리팩토링이 필요합니다.

✅ 테스트 코드 작성

  • 멤버 프로필 이미지 Presigned URL 발급 및 confirm 통합/단위 테스트를 작성했습니다.
  • 학습 로그 Presigned URL 발급 및 confirm 통합/단위 테스트를 작성했습니다.
  • ImageService cleanup 기능 단위 테스트를 작성했습니다.

🌱 관련 이슈


🔍 참고사항(선택)

  • 이미지 타입(Content-Type/MIME)은 JPG, JPEG, PNG, WEBP 만 허용하도록 정책을 구성했습니다.
  • 이미지 최대 크기는 5MB로 구성했습니다.

📚 기타(선택)

@hisonghy hisonghy self-assigned this Oct 9, 2025
@hisonghy hisonghy added ✨feature 구현, 개선 사항 관련 부분 🪄refactor 기능 개선 및 리팩토링 labels Oct 9, 2025
Copy link
Contributor

@chaiminwoo0223 chaiminwoo0223 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다. 코드 리뷰 확인 부탁드립니다!

Copy link
Contributor Author

@hisonghy hisonghy left a comment

Choose a reason for hiding this comment

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

코드 리뷰 확인했습니다.
수정내용 바로 반영해서 PR 올리도록 하겠습니다!

Copy link
Contributor Author

@hisonghy hisonghy left a comment

Choose a reason for hiding this comment

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

코드 리뷰 내용 반영해두었습니다.
확인부탁드려요!

Copy link
Contributor

@chaiminwoo0223 chaiminwoo0223 left a comment

Choose a reason for hiding this comment

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

수정된 내용 모두 확인했습니다. 고생하셨습니다.
커밋 병합 후 머지 부탁드립니다!

* feat: 학습로그 엔티티 image_url 필드 추가
* feat: Flyway V3__add_image_url_column_to_study_log.sql 추가

* feat: 멤버 프로필 이미지 Presigned URL 발급/confirm 기능 추가
* feat: 학습로그 이미지 Presigned URL 발급/confirm 기능 추가

* feat: ImageService에 cleanup 기능 추가
* refactor: 기존 CdnUrlResolver 클래스를 삭제하고, image.domain.util에 ImageUrlUtil 클래스 추가

* refactor: 회원 탈퇴 로직에 이미지 삭제 기능 추가

* test: 멤버 프로필 이미지 Presigned URL 발급 및 confirm 기능 통합/단위 테스트 추가
* test: 학습로그 이미지 Presigned URL 발급 및 confirm 기능 통합/단위 테스트 추가
* test: ImageService cleanup 단위 테스트 추가
@hisonghy hisonghy merged commit a09d9ac into develop Oct 11, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨feature 구현, 개선 사항 관련 부분 🪄refactor 기능 개선 및 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨[FEAT]: Member, StudyLog 이미지 presigned url 발급 및 컨펌 API 구현

2 participants