Skip to content

feat: 이미지 스토리지 설정 및 로직 구현 (#73)#74

Merged
hisonghy merged 1 commit intodevelopfrom
feat/73
Oct 8, 2025
Merged

feat: 이미지 스토리지 설정 및 로직 구현 (#73)#74
hisonghy merged 1 commit intodevelopfrom
feat/73

Conversation

@hisonghy
Copy link
Contributor

@hisonghy hisonghy commented Oct 2, 2025

📌 작업 내용 및 특이사항

✅ AWS S3 기반 이미지 스토리지 설정

  • application-storage.yml 파일을 구성해 S3 이미지 스토리지 설정을 추가했습니다.
  • S3Config, S3Properties 클래스를 구성했습니다.

[ S3 버킷 정책 ]

  1. 클라이언트는 Presigned URL을 이용해 S3에 직접 PUT 요청(이미지 업로드)을 수행하며,
    업로드된 객체 조회(GET)는 CloudFront를 통해서만 접근 가능합니다.
  2. 서버는 S3 객체에 대한 GET/DELETE 권한을 가지며,
    검증된 IAM User 또는 IAM Role을 통해서만 가능합니다.
    (Role은 EC2 권한에 직접 연결해주었으며, 로컬 환경용 IAM 사용자는 노션에 공유해두었습니다.)

[ 객체 수명 주기 ]

  1. 임시 경로(tmp/)에 업로드된 이미지 파일은 1일이 지나면 자동으로 삭제되도록 설정했습니다.

✅ Tika 라이브러리 추가

  • 업로드된 이미지의 MIME 판별을 위해 Apache Tika 라이브러리를 추가했습니다.
  • presigned url 발급 로직에서 이미지 파일의 contentType을 요청받지 않고, 업로드된 이미지 파일을 Tika로 판별해 MIME 데이터를 추출하도록 설계했습니다.

✅ CloudFront CDN 적용

  • 클라이언트는 S3에 직접 접근하지 않고 CloudFront CDN 도메인으로만 GET 할 수 있도록 설정했습니다.
  • S3 버킷은 공개 차단하고, OAC(Origin Access Control)CloudFront만 접근 하도록 보안을 강화했습니다.

✅ 이미지 기능 구현

  • 서버는 presign url 발급직접 객체 조회, 삭제, 복사 역할을 수행하고, 클라이언트는 업로드CDN 이미지 조회 역할을 담당하도록 했습니다.
    클라이언트는 임시 경로에 PUT으로 이미지를 업로드하고, 서버에서 confirm 이후 최종 경로에 복사하도록 설계했습니다.
  • image 패키지를 만들어 공통된 presign, confirm, cancel 기능을 구현했습니다.
    회원 프로필, 학습 로그, 여행 리포트 도메인에서 이미지가 필요한데, 각 도메인 별 이미지 관련 로직과 infra 모듈을 구현하지 않고 image 도메인 로직을 사용할 수 있도록 구현했습니다.
    추후 도메인 별 presign url 발급 API, 업로드된 이미지 confirm API, 업로드 과정에서 이슈 발생 시 취소 API는 구현해야합니다.
    confime 과정에서 S3 자체 에러가 아닌 이미지 도메인 정책에 어긋날 경우 업로드된 임시 파일을 삭제하도록 설계했습니다.
  • AWS S3 서버 내부 예외는 동일한 에러 코드로 클라이언트에 응답하고, 에러 상세 내용은 로깅 처리했습니다.

✅ ImageService 단위 테스트 추가

  • presign, confirm, cancel 로직 단위 테스트 추가했습니다.

🌱 관련 이슈


🔍 참고사항(선택)

  • jpg, jpeg, png, webp 이미지 파일의 확장자 및 MIME만 허용하도록 정책을 설계했습니다.
  • AWS S3 Bucket을 생성하고, 권한 및 정책을 설정했습니다.
  • 각 도메인 별 이미지 URL 필드를 저장할 때, CDN 도메인 주소 + ImageKey 형태로 저장되도록 리팩토링이 필요합니다.
  • S3_BUCKET_NAME, AWS_REGION, CDN_DOMAIN 정보는 노션에 공유하겠습니다.

📚 기타(선택)

@hisonghy hisonghy self-assigned this Oct 2, 2025
@hisonghy hisonghy added ⚙️chore 세팅 관련 ✨feature 구현, 개선 사항 관련 부분 labels Oct 2, 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.

고생하셨습니다. 몇가지 궁금한 내용이 있어서 코드 리뷰 남겼습니다. 확인 부탁드립니다!

@RequiredArgsConstructor
public enum TikaErrorCode implements ErrorCode {
TIKA_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "Tika 서버 에러가 발생했습니다."),
;
Copy link
Contributor

Choose a reason for hiding this comment

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

TikaErrorCode를 domain 계층이 아닌 infra 계층에 두신 이유가 있을까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TikaErrorCode를 domain 계층이 아닌 infra 계층에 두신 이유가 있을까요?

S3Tika는 외부 기술이고 여기서 발생하는 에러나 예외는 비즈니스 로직 흐름에서 도메인 정책을 위반해 발생하는게 아니라 외부 시스템 내부에서 발생하는 기술적인 예외로 판단해 infra 계층에 두었습니다.

기술 자체 에러, 예외를 domain 계층에서 관리하는 방법이 더 자연스러울까요?

Copy link
Contributor

Choose a reason for hiding this comment

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

TikaErrorCode를 domain 계층이 아닌 infra 계층에 두신 이유가 있을까요?

S3Tika는 외부 기술이고 여기서 발생하는 에러나 예외는 비즈니스 로직 흐름에서 도메인 정책을 위반해 발생하는게 아니라 외부 시스템 내부에서 발생하는 기술적인 예외로 판단해 infra 계층에 두었습니다.

기술 자체 에러, 예외를 domain 계층에서 관리하는 방법이 더 자연스러울까요?

외부 시스템 내부에서 발생하는 기술적인 예외이기 때문에, 지금처럼 infra 계층에 두는 것이 좋을 것 같아요.

저는 항상 에러 코드를 domain 계층에서만 관리했는데, infra 계층에 외부 시스템 관련 에러 코드를 별도로 정의하는 방식이 인상적이었습니다. 각 계층에서 발생하는 예외를 명확하게 처리할 수 있어서 책임 소재가 더 분명해지는 것 같습니다.

@hisonghy hisonghy force-pushed the feat/73 branch 3 times, most recently from a90a1c9 to b485b86 Compare October 5, 2025 02:16
@hisonghy
Copy link
Contributor Author

hisonghy commented Oct 8, 2025

고생하셨습니다. 몇가지 궁금한 내용이 있어서 코드 리뷰 남겼습니다. 확인 부탁드립니다!

코드 리뷰에 답변 남겼습니다
확인부탁드려요!

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.

코드 리뷰에 대한 답변 남겼습니다
확인부탁드려요

@RequiredArgsConstructor
public enum TikaErrorCode implements ErrorCode {
TIKA_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "Tika 서버 에러가 발생했습니다."),
;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TikaErrorCode를 domain 계층이 아닌 infra 계층에 두신 이유가 있을까요?

S3Tika는 외부 기술이고 여기서 발생하는 에러나 예외는 비즈니스 로직 흐름에서 도메인 정책을 위반해 발생하는게 아니라 외부 시스템 내부에서 발생하는 기술적인 예외로 판단해 infra 계층에 두었습니다.

기술 자체 에러, 예외를 domain 계층에서 관리하는 방법이 더 자연스러울까요?

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.

고생하셨습니다. 커밋 내용 병합 후 머지 부탁드립니다!

@hisonghy hisonghy closed this Oct 8, 2025
@hisonghy hisonghy reopened this Oct 8, 2025
* chore: AWS SDK v2 dependency, application-storage.yml, S3Config 설정
* chore: Tika dependency, TikaConfig 설정
* chore: application.yml CDN 설정

* feat: presigned url 발급 로직 구현
* feat: 업로드된 이미지를 검증하는 confirm 로직 구현
* feat: 이미지 업로드를 취소하는 로직 구현 (다중 이미지 업로드에서 예외 발생 시)
* feat: S3, Tika client, provider 클래스 구현

* feat: ImageConstants, ImageErrorCode, ImageKeyFactory, ImagePolicy 도메인 객체 추가

* feat: FilenameUtil 클래스 추가

* test: ImageService 단위 테스트 추가
@hisonghy hisonghy merged commit 794e2c7 into develop Oct 8, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚙️chore 세팅 관련 ✨feature 구현, 개선 사항 관련 부분

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨[FEAT]: 이미지 기능 구현

2 participants