feat: impl resizing image logic - #59
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthrough이미지 검증과 리사이징을 Changes이미지 처리 및 저장
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant UserServiceImpl
participant StorageService
participant ImageProcessor
participant LocalStorageService
participant S3StorageService
UserServiceImpl->>StorageService: 프로필 이미지와 ImageResizeSpec.PROFILE 전달
StorageService->>ImageProcessor: 이미지 검증 및 리사이징 요청
ImageProcessor-->>StorageService: 처리된 바이트, 확장자 및 MIME 타입 반환
StorageService->>LocalStorageService: 처리 결과 저장
StorageService->>S3StorageService: 처리 결과 저장
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (5)
momogo-core/build.gradle (1)
34-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winThumbnailator 패치 버전을 확인하세요.
net.coobird:thumbnailator:0.4.20은 사용할 수 있지만, 현재 Maven Central에는0.4.21이 등록되어 있습니다. (repo1.maven.org)가능하면
0.4.21로 업그레이드하고 이미지 포맷, EXIF, 리사이징 회귀 테스트를 실행하세요. 최신 패치 사용은 유지보수성을 높입니다. 반면 동작 변경 가능성이 있으므로ImageProcessor흐름의 호환성 확인이 필요합니다.
0.4.20을 유지해야 한다면 호환성 또는 운영 검증 결과를 문서화하세요.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@momogo-core/build.gradle` at line 34, Update the Thumbnailator dependency in the build.gradle implementation declaration from 0.4.20 to 0.4.21, then verify ImageProcessor compatibility by running image-format, EXIF, and resizing regression tests.Source: MCP tools
momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java (3)
34-36: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value프로필 규격 상수를 설정값으로 분리하는 방안을 고려해주세요.
ImageProcessor는common.util패키지의 범용 컴포넌트입니다. 그런데PROFILE_TARGET_WIDTH,PROFILE_TARGET_HEIGHT,OUTPUT_QUALITY는 프로필 이미지라는 특정 도메인 정책입니다. 지금은 프로필 업로드만 존재하므로 동작에 문제는 없습니다.다만 썸네일이나 방 대표 이미지처럼 다른 규격이 추가되면, 이 클래스를 수정해야 하거나 유사 클래스가 복제됩니다. 두 가지 대안이 있습니다.
validateImage(stream, filename, contentType, targetWidth, targetHeight)형태로 규격을 파라미터화합니다. 장점은 단순함이고, 단점은 호출부가 규격을 알아야 한다는 점입니다.- 규격을
@ConfigurationProperties레코드로 묶어 주입합니다. 장점은 환경별 조정이 가능한 점이고, 단점은 클래스가 하나 늘어나는 점입니다.YAGNI 관점에서 지금 당장 필요한 변경은 아닙니다. 두 번째 이미지 규격이 생기는 시점에 적용하면 충분합니다.
Also applies to: 104-105
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java` around lines 34 - 36, Defer changes to PROFILE_TARGET_WIDTH, PROFILE_TARGET_HEIGHT, and OUTPUT_QUALITY in ImageProcessor; no implementation change is required until a second image specification is introduced.
58-58: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
maxMarkSize네이밍이 실제 역할과 맞지 않습니다.이 값은
readWithLimit에 전달되는 업로드 허용 최대 바이트 수입니다. "mark"는InputStream#mark(int)의 마크 버퍼 크기를 연상시킵니다. 현재 코드는mark/reset을 전혀 사용하지 않으므로 이름이 오해를 만듭니다. 이전 구현에서mark기반이었다면 남은 흔적일 수 있습니다.
maxUploadSize와 프로퍼티 키app.file.upload.max-size로 바꾸는 편이 의도를 정확히 전달합니다. 프로퍼티 키를 변경하면 설정 파일도 함께 수정해야 합니다.Also applies to: 62-62, 67-67, 89-89
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java` at line 58, Rename the ImageProcessor field maxMarkSize to maxUploadSize and update all references, including the constructor assignment and readWithLimit call. Change the associated configuration property key to app.file.upload.max-size, and update the corresponding application configuration entries to match.
201-202: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win확장자 파싱이 두 저장소 구현에 중복되었습니다. 근본 원인은
ImageValidationResult의 정보 부족입니다.
ImageProcessor.validateImage는 이미 확장자를 파싱하고, 화이트리스트로 검증하고, 실제 포맷과 교차 검증합니다. 그런데ImageValidationResult는 그 결과를 노출하지 않습니다. 그래서 두 저장소가originalFileName을 다시 파싱합니다.이 구조는 세 가지 부작용을 만듭니다.
- DRY 위반: 동일한 6줄이 두 파일에 복제되었습니다. 확장자 정책이 바뀌면 세 곳을 수정해야 합니다.
- 도달 불가 방어 코드:
originalFileName != null && originalFileName.contains(".")검사는validateImage가 이미 통과시킨 뒤에 실행됩니다. 항상 참입니다. 읽는 사람은extension이 빈 문자열이 될 수 있다고 오해합니다.- 정보 손실: 저장 파일명 확장자는 원본 파일명에서 오고,
Content-Type은 감지된 포맷에서 옵니다. 두 값의 출처가 다르면 향후 출력 포맷을 정규화할 때 어긋납니다.수정 방향 — 각 위치에서 필요한 변경은 다음과 같습니다.
momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java#L201-L202:ImageValidationResult에 확장자 필드를 추가하고,validateImage가 검증된ext를 채워 반환하도록 변경합니다.InputStream대신byte[] data를 노출하면 S3 쪽의readAllBytes()재복사도 사라집니다.momogo-core/src/main/java/com/momogo/core/common/storage/LocalStorageService.java#L44-L50: 로컬 확장자 파싱 블록을 삭제하고validationResult.extension()을 사용합니다.momogo-core/src/main/java/com/momogo/core/common/storage/S3StorageService.java#L51-L57: 동일하게 파싱 블록을 삭제하고validationResult.extension()을 사용합니다.♻️ 리팩터링 예시
ImageProcessor.java:- public record ImageValidationResult(InputStream inputStream, String detectedContentType) { + public record ImageValidationResult(byte[] data, String detectedContentType, String extension) { + public InputStream inputStream() { + return new ByteArrayInputStream(data); + } }String detectedMimeType = FORMAT_TO_MIME_TYPE.get(dimension.format()); - return new ImageValidationResult(new ByteArrayInputStream(resizedBytes), detectedMimeType); + return new ImageValidationResult(resizedBytes, detectedMimeType, "." + ext);
LocalStorageService.java:- try (InputStream validatedStream = validationResult.inputStream()) { - String extension = ""; - if (originalFileName != null && originalFileName.contains(".")) { - extension = originalFileName.substring(originalFileName.lastIndexOf(".")); - } - - String savedFileName = UUID.randomUUID() + extension; + String savedFileName = UUID.randomUUID() + validationResult.extension();
S3StorageService.java:- try (InputStream validatedStream = validationResult.inputStream()) { - String extension = ""; - if (originalFileName != null && originalFileName.contains(".")) { - extension = originalFileName.substring(originalFileName.lastIndexOf(".")); - } - - String savedFileName = UUID.randomUUID() + extension; - String key = directory + "/" + savedFileName; - - byte[] bytes = validatedStream.readAllBytes(); + String savedFileName = UUID.randomUUID() + validationResult.extension(); + String key = directory + "/" + savedFileName; + byte[] bytes = validationResult.data();참고 개념 — 레코드로
byte[]를 노출하면 배열이 가변이므로equals/hashCode가 참조 기준으로 동작합니다. 값 비교가 필요하면 접근자에서clone()을 반환하거나ByteBuffer.wrap(...).asReadOnlyBuffer()를 쓰는 방법이 있습니다. 이 용례에서는 단일 소비 후 폐기되므로 실제 문제는 없습니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java` around lines 201 - 202, The extension parsing logic is duplicated across storage implementations because ImageValidationResult does not expose the validated extension. In momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java (lines 201-202), add an extension field to the ImageValidationResult record and update the validateImage method to populate this field with the validated extension; optionally replace InputStream with byte[] data to eliminate downstream readAllBytes() copies. In momogo-core/src/main/java/com/momogo/core/common/storage/LocalStorageService.java (lines 44-50), remove the local extension parsing block and replace it with a call to validationResult.extension(). In momogo-core/src/main/java/com/momogo/core/common/storage/S3StorageService.java (lines 51-57), remove the duplicate extension parsing block and replace it with a call to validationResult.extension(). This consolidates the single source of truth for the validated extension and eliminates the unreachable defensive checks in both storage services.momogo-core/src/main/java/com/momogo/core/common/storage/S3StorageService.java (1)
58-58: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
directory형식을 구현 단에서 맞추는 편이 좋습니다.현재 호출부는 상수
PROFILE_IMAGE_DIR만 전달합니다. 하지만LocalStorageService는resolveSafely(uploadRoot, directory)에서null/blank를 거부하고 경로 조작 후보를 검지만,S3StorageService는directory + "/"로null이면"null/...",../가 있으면 그 값 그대로 S3 객체 키에 넣습니다. 저장소 교체 시 같은 입력에 대한 동작이 달라지지 않도록StorageService#upload계약에서 사용할 수 있는directory형식을 문서화하거나 함께 검증하세요.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@momogo-core/src/main/java/com/momogo/core/common/storage/S3StorageService.java` at line 58, StorageService#upload의 directory 입력 계약이 구현마다 달라 S3에서 null, blank, 또는 경로 조작 값이 그대로 사용됩니다. StorageService#upload 계약에 허용되는 directory 형식을 문서화하고, S3StorageService의 키 생성 경로에서 LocalStorageService의 null/blank 및 안전성 검증과 동일하게 검증하도록 수정하세요.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java`:
- Around line 111-127: Update resizeImage so resizing failures no longer return
originalBytes; propagate the exception to the caller instead of treating the
image as successfully processed. Preserve the existing resize behavior, and
ensure WebP write failures follow the exception path rather than saving the
original payload.
---
Nitpick comments:
In `@momogo-core/build.gradle`:
- Line 34: Update the Thumbnailator dependency in the build.gradle
implementation declaration from 0.4.20 to 0.4.21, then verify ImageProcessor
compatibility by running image-format, EXIF, and resizing regression tests.
In
`@momogo-core/src/main/java/com/momogo/core/common/storage/S3StorageService.java`:
- Line 58: StorageService#upload의 directory 입력 계약이 구현마다 달라 S3에서 null, blank, 또는
경로 조작 값이 그대로 사용됩니다. StorageService#upload 계약에 허용되는 directory 형식을 문서화하고,
S3StorageService의 키 생성 경로에서 LocalStorageService의 null/blank 및 안전성 검증과 동일하게 검증하도록
수정하세요.
In `@momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java`:
- Around line 34-36: Defer changes to PROFILE_TARGET_WIDTH,
PROFILE_TARGET_HEIGHT, and OUTPUT_QUALITY in ImageProcessor; no implementation
change is required until a second image specification is introduced.
- Line 58: Rename the ImageProcessor field maxMarkSize to maxUploadSize and
update all references, including the constructor assignment and readWithLimit
call. Change the associated configuration property key to
app.file.upload.max-size, and update the corresponding application configuration
entries to match.
- Around line 201-202: The extension parsing logic is duplicated across storage
implementations because ImageValidationResult does not expose the validated
extension. In
momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java (lines
201-202), add an extension field to the ImageValidationResult record and update
the validateImage method to populate this field with the validated extension;
optionally replace InputStream with byte[] data to eliminate downstream
readAllBytes() copies. In
momogo-core/src/main/java/com/momogo/core/common/storage/LocalStorageService.java
(lines 44-50), remove the local extension parsing block and replace it with a
call to validationResult.extension(). In
momogo-core/src/main/java/com/momogo/core/common/storage/S3StorageService.java
(lines 51-57), remove the duplicate extension parsing block and replace it with
a call to validationResult.extension(). This consolidates the single source of
truth for the validated extension and eliminates the unreachable defensive
checks in both storage services.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: d82ca148-58a1-488e-91c3-9855590621bb
📒 Files selected for processing (5)
momogo-core/build.gradlemomogo-core/src/main/java/com/momogo/core/common/storage/LocalStorageService.javamomogo-core/src/main/java/com/momogo/core/common/storage/S3StorageService.javamomogo-core/src/main/java/com/momogo/core/common/util/ImageFileValidator.javamomogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java
💤 Files with no reviewable changes (1)
- momogo-core/src/main/java/com/momogo/core/common/util/ImageFileValidator.java
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java (2)
198-205: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
ImageValidationResultrecord의data필드가 방어적 복사 없이 원본 배열 참조를 그대로 노출합니다.
record ImageValidationResult(byte[] data, ...)는 배열을 그대로 저장하고, 자동 생성된data()접근자도 같은 참조를 반환합니다. 호출자(S3StorageService)가validationResult.data()로 얻은 배열을 수정하면 내부 상태가 오염될 수 있습니다. record는 불변을 지향하지만, 배열 필드는 자동으로 불변이 되지 않는 Java의 잘 알려진 함정입니다.생성자에서
data.clone()으로 방어적 복사를 하거나, 접근자를 재정의해 복사본을 반환하는 방법을 고려하십시오.♻️ 제안하는 수정
public record ImageValidationResult(byte[] data, String detectedContentType, String extension) { + public ImageValidationResult(byte[] data, String detectedContentType, String extension) { + this.data = data.clone(); + this.detectedContentType = detectedContentType; + this.extension = extension; + } + + `@Override` + public byte[] data() { + return data.clone(); + } + public InputStream inputStream() { return new ByteArrayInputStream(data); } }이미 검증이 끝난 데이터를 저장소 레이어로 넘기는 경계 지점이므로, 불변성을 보장하면 향후 유지보수 시 실수를 예방할 수 있습니다. As per path instructions,
**/main/**/*.java는 "클린코드, 리팩토링" 관점을 확인해야 합니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java` around lines 198 - 205, Update the ImageValidationResult record to defensively copy its byte-array data both when storing it and when exposing it through data(), preventing callers such as S3StorageService from mutating the internal state. Keep inputStream() reading from the protected data.Source: Path instructions
58-68: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
DataSize를int로 캐스팅하면 큰 설정값에서 오버플로우가 발생할 수 있습니다.
this.maxFileSize = (int) maxFileSize.toBytes();에서, 운영 환경에서app.file.upload.max-file-size를 2GB 이상으로 설정하면int캐스팅 시 값이 음수로 오버플로우됩니다. 그러면readWithLimit의totalBytes + bytesRead > limit검사가 첫 조각부터 항상 참이 되어, 모든 업로드가 즉시 거부됩니다.기본값 10MB에서는 문제가 없지만, 설정 실수에 취약한 구조입니다.
maxFileSize필드를long으로 유지하면 이 문제를 근본적으로 방지할 수 있습니다.♻️ 제안하는 수정
private final Set<String> allowedExtensions; - private final int maxFileSize; + private final long maxFileSize; public ImageProcessor( `@Value`("${app.file.upload.allowed-extensions}") List<String> allowedExtensions, `@Value`("${app.file.upload.max-file-size:10MB}") DataSize maxFileSize ) { this.allowedExtensions = allowedExtensions.stream() .map(String::toLowerCase) .collect(Collectors.toUnmodifiableSet()); - this.maxFileSize = (int) maxFileSize.toBytes(); + this.maxFileSize = maxFileSize.toBytes(); }그리고
readWithLimit(InputStream inputStream, long limit)으로 시그니처를 맞추고 내부totalBytes도long으로 변경해야 합니다.Java 21 기준으로 볼 때, 설정값을 신뢰할 수 없는 외부 입력처럼 다루고 방어적으로 타입을 넓히는 것이 실무에서 더 안전한 습관입니다. As per path instructions,
**/main/**/*.java는 "실무 활용 가능성, 불필요한 로직, 클린코드, 리팩토링"을 확인해야 합니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java` around lines 58 - 68, ImageProcessor의 maxFileSize를 int에서 long으로 변경하고, 생성자에서 DataSize.toBytes()를 손실 없이 보존하도록 할당하세요. readWithLimit(InputStream, long)의 limit과 내부 totalBytes도 long으로 맞춰 2GB 이상 설정에서도 오버플로우 없이 크기 검사가 동작하도록 수정하세요.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@momogo-core/src/main/java/com/momogo/core/common/util/StorageDirectoryValidator.java`:
- Around line 18-22: Update the path validation in StorageDirectoryValidator to
inspect normalized.split("/", -1) and reject only segments exactly equal to
"..", while continuing to reject absolute paths. Preserve valid directory names
such as archive..2026 and update the related comment if needed to describe the
segment-based validation.
- Around line 20-25: Update StorageDirectoryValidator.validate() to produce the
same canonical path semantics as resolveSafely(): remove "." segments, empty
segments, and duplicate slashes while retaining the existing traversal and
absolute-path rejection. Ensure the normalized directory returned by validate()
is identical for LocalStorageService and S3StorageService, and add coverage for
inputs such as images/./profile and images//profile.
---
Nitpick comments:
In `@momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java`:
- Around line 198-205: Update the ImageValidationResult record to defensively
copy its byte-array data both when storing it and when exposing it through
data(), preventing callers such as S3StorageService from mutating the internal
state. Keep inputStream() reading from the protected data.
- Around line 58-68: ImageProcessor의 maxFileSize를 int에서 long으로 변경하고, 생성자에서
DataSize.toBytes()를 손실 없이 보존하도록 할당하세요. readWithLimit(InputStream, long)의 limit과
내부 totalBytes도 long으로 맞춰 2GB 이상 설정에서도 오버플로우 없이 크기 검사가 동작하도록 수정하세요.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 65102035-4656-41ef-864a-8a017f4c4531
📒 Files selected for processing (6)
momogo-api/src/main/resources/application.yamlmomogo-core/build.gradlemomogo-core/src/main/java/com/momogo/core/common/storage/LocalStorageService.javamomogo-core/src/main/java/com/momogo/core/common/storage/S3StorageService.javamomogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.javamomogo-core/src/main/java/com/momogo/core/common/util/StorageDirectoryValidator.java
🚧 Files skipped from review as they are similar to previous changes (3)
- momogo-core/build.gradle
- momogo-core/src/main/java/com/momogo/core/common/storage/LocalStorageService.java
- momogo-core/src/main/java/com/momogo/core/common/storage/S3StorageService.java
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java (3)
77-107: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift이미지 처리 계약을 고정하는 테스트를 추가하세요.
이 변경은 입력 허용 여부, 확장자/포맷 교차 검증, 픽셀 제한, 리사이징 결과, MIME 타입 및 실패 예외를 동시에 변경합니다. 제공된 변경 범위에 테스트가 없어 저장소에 잘못된 바이트가 저장되거나 크기 계약이 깨져도 발견하기 어렵습니다.
최소한 다음 테스트를 추가하세요.
- 큰 가로·세로 이미지가 중앙 크롭 후 기대한 크기를 갖는지 확인
- 300보다 작은 이미지의 업스케일 정책 확인
- 확장자와 실제 포맷 불일치 거부
- 최대 바이트 및 최대 픽셀 경계값 확인
- JPEG, PNG, WebP의 실제 reader/writer 동작 확인
- 헤더는 유효하지만 픽셀 데이터가 잘린 이미지의 예외 코드 확인
As per path instructions: 꼭 필요한 부분에 집중하고, 문제점과 대안을 제시했습니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java` around lines 77 - 107, ImageProcessor.validateImage and its related format, size, and resize behavior lack contract tests. Add focused tests covering centered cropping of oversized images, the defined policy for upscaling images smaller than 300px, extension/actual-format mismatches, exact maximum byte and pixel boundaries, real JPEG/PNG/WebP reader-writer compatibility, and truncated pixel data with the expected BusinessException error code.Source: Path instructions
110-120: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win프로필 이미지 크기 계약을 현재 동작과 맞게 정리하세요.
현재 구현은 원본의 짧은 변과
PROFILE_TARGET_SIZE중 작은 값으로 출력하므로,targetSize = 300이더라도 200×400 이미지는 200×200으로 저장됩니다. 즉, 26행의 “300*300” 규격 문서와 112행의 동작 불일치입니다.
- 고정 300×300을 목표로 한다면 112행을
int targetSize = profileTargetSize;로 바꾸세요. 이후 업스케일 정책을 결정하고 테스트/문서를 함께 맞춰야 합니다.- 최대 크기를 목표로 한다면 상수명을
PROFILE_MAX_SIZE로 바꾸고 문서도 300×300이 아닌 상한 규격으로 수정하세요.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java` around lines 110 - 120, 프로필 이미지 크기 계약과 resizeImage의 현재 동작이 일치하지 않습니다. 고정 300×300 규격을 유지하려면 resizeImage의 targetSize 계산에서 원본 치수의 최소값을 제거하고 profileTargetSize를 직접 사용하도록 변경한 뒤, 업스케일 허용 여부를 결정해 관련 테스트와 문서를 맞추세요. 최대 크기 정책을 유지하려면 profileTargetSize와 관련 문서 및 상수명을 PROFILE_MAX_SIZE로 정리하고 상한 규격을 명시하세요.Sources: Path instructions, MCP tools
137-171: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win업로드 오류가
INTERNAL_SERVER_ERROR로 겹치지 않게 예외 범주를 분리하세요.
detectAndValidateFormat은getWidth(0)/getHeight(0)만 읽어 헤더 차원까지 확인하지만, 원본 스트림의 전체 픽셀을 아직 디코드하지 않습니다. 잘린 image는 여기서 통과한 뒤 ThumbnailatortoOutputStream에서 디코드 실패가 발생할 수 있습니다. 현재 메서드는 이 실패도 공통INTERNAL_SERVER_ERROR로 처리하므로, 잘못된 클라이언트 입력이 500 응답과 서버 오류 로그를 일으킵니다.입력 기반 디코딩 실패는
INVALID_INPUT으로 보내고, writer/서버 설정 실패만INTERNAL_SERVER_ERROR로 남겨주세요. 재시도도 하지 않는 리사이징 실패를 retryable 내부 오류처럼 보이면 사용자가 불안정 서버 경험을 얻습니다. 간단한 대안은 검증 단계에서 전체 디코드만 먼저 수행하는 것입니다. 기존ImageDimension을 그대로 쓰기 위해 원본BufferedImage를 저장하면 메모리 수명/메서드 계약 변경까지 고려해야 합니다. 이 방식은 CPU/메모리 비용이 더 들지만 구현이 쉽습니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java` around lines 137 - 171, detectAndValidateFormat에서 헤더 크기만 확인하지 말고 원본 이미지 전체 디코딩을 수행해 잘린 이미지와 같은 입력 오류를 검증 단계에서 INVALID_INPUT으로 처리하세요. 기존 ImageDimension 반환 계약과 픽셀 제한 검사는 유지하고, 입력 디코딩 실패가 공통 INTERNAL_SERVER_ERROR로 변환되지 않도록 예외 범주를 분리하세요. 리사이징 과정의 writer 또는 서버 설정 오류만 내부 서버 오류로 남겨야 합니다.Sources: Path instructions, MCP tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@momogo-core/src/main/java/com/momogo/core/common/util/StorageDirectoryValidator.java`:
- Around line 22-25: Update StorageDirectoryValidator.validate to reject
absolute paths before normalizing separators or calling split: reject inputs
beginning with "/" or "\" and Windows drive-absolute forms such as a drive
letter followed by a separator. Preserve relative-path validation, and
explicitly apply the existing policy for "/" and "."; add or update tests for
these cases.
---
Outside diff comments:
In `@momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java`:
- Around line 77-107: ImageProcessor.validateImage and its related format, size,
and resize behavior lack contract tests. Add focused tests covering centered
cropping of oversized images, the defined policy for upscaling images smaller
than 300px, extension/actual-format mismatches, exact maximum byte and pixel
boundaries, real JPEG/PNG/WebP reader-writer compatibility, and truncated pixel
data with the expected BusinessException error code.
- Around line 110-120: 프로필 이미지 크기 계약과 resizeImage의 현재 동작이 일치하지 않습니다. 고정 300×300
규격을 유지하려면 resizeImage의 targetSize 계산에서 원본 치수의 최소값을 제거하고 profileTargetSize를 직접
사용하도록 변경한 뒤, 업스케일 허용 여부를 결정해 관련 테스트와 문서를 맞추세요. 최대 크기 정책을 유지하려면
profileTargetSize와 관련 문서 및 상수명을 PROFILE_MAX_SIZE로 정리하고 상한 규격을 명시하세요.
- Around line 137-171: detectAndValidateFormat에서 헤더 크기만 확인하지 말고 원본 이미지 전체 디코딩을
수행해 잘린 이미지와 같은 입력 오류를 검증 단계에서 INVALID_INPUT으로 처리하세요. 기존 ImageDimension 반환 계약과 픽셀
제한 검사는 유지하고, 입력 디코딩 실패가 공통 INTERNAL_SERVER_ERROR로 변환되지 않도록 예외 범주를 분리하세요. 리사이징
과정의 writer 또는 서버 설정 오류만 내부 서버 오류로 남겨야 합니다.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 0e0175ce-fccf-4439-aadd-15284f350df6
📒 Files selected for processing (5)
momogo-core/build.gradlemomogo-core/src/main/java/com/momogo/core/common/storage/LocalStorageService.javamomogo-core/src/main/java/com/momogo/core/common/storage/S3StorageService.javamomogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.javamomogo-core/src/main/java/com/momogo/core/common/util/StorageDirectoryValidator.java
🚧 Files skipped from review as they are similar to previous changes (2)
- momogo-core/src/main/java/com/momogo/core/common/storage/LocalStorageService.java
- momogo-core/src/main/java/com/momogo/core/common/storage/S3StorageService.java
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
momogo-core/src/main/java/com/momogo/core/common/util/StorageDirectoryValidator.java (1)
34-45: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win잘못된 파일 시스템 경로를
BusinessException으로 매핑하세요.
StorageDirectoryValidator.validate()는..만 차단하고 NUL 같은 Java 21Path에서 거부되는 경로 문자는 그대로 반환합니다.LocalStorageService.resolveSafely()는base.resolve(...).normalize()에서InvalidPathException을 던질 수 있는데, 이는 unchecked 예외이고LocalStorageService.upload()의catch (IOException)보다 앞서 발생하므로FILE_UPLOAD_FAILED로 내려가지 않습니다. 현재 공통 처리기는 이 unchecked 예외를 내부 오류로 반환합니다.resolveSafely()에서InvalidPathException까지 잡거나 validator에서 파일 시스템 경로 규칙을 검증하세요.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@momogo-core/src/main/java/com/momogo/core/common/util/StorageDirectoryValidator.java` around lines 34 - 45, Update StorageDirectoryValidator.validate() or LocalStorageService.resolveSafely() so Java 21-invalid path input, including NUL characters, is rejected and mapped to the existing BusinessException/invalid-input flow before Path resolution can throw InvalidPathException. Ensure LocalStorageService.upload() does not expose this unchecked exception as an internal error or FILE_UPLOAD_FAILED.Sources: Path instructions, MCP tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In
`@momogo-core/src/main/java/com/momogo/core/common/util/StorageDirectoryValidator.java`:
- Around line 34-45: Update StorageDirectoryValidator.validate() or
LocalStorageService.resolveSafely() so Java 21-invalid path input, including NUL
characters, is rejected and mapped to the existing
BusinessException/invalid-input flow before Path resolution can throw
InvalidPathException. Ensure LocalStorageService.upload() does not expose this
unchecked exception as an internal error or FILE_UPLOAD_FAILED.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 49c44983-9cfa-4f76-9f10-3ce2bb236b62
📒 Files selected for processing (2)
momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.javamomogo-core/src/main/java/com/momogo/core/common/util/StorageDirectoryValidator.java
🚧 Files skipped from review as they are similar to previous changes (1)
- momogo-core/src/main/java/com/momogo/core/common/util/ImageProcessor.java
idktomorrow
left a comment
There was a problem hiding this comment.
그 외 크게 문제될 부분은 없어보입니다 작성하시느라 고생 많으셨습니다! ❤️
Junkov0
left a comment
There was a problem hiding this comment.
전체적으로 코드 잘 구성하신 것 같습니다!
LGTM
…vent inputStream leak on early exception
… into feature/image-resizing
…izPlatform/MoMoGo into feature/image-resizing # Conflicts: # momogo-core/src/main/java/com/momogo/core/common/util/storage/ImageProcessor.java
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@momogo-core/src/main/java/com/momogo/core/common/util/storage/ImageProcessor.java`:
- Around line 127-143: Update resizeImage in ImageProcessor so resize or
encoding exceptions are converted to the project’s BusinessException instead of
returning originalBytes; use INVALID_INPUT for invalid image data and
FILE_UPLOAD_FAILED for encoder or processing failures when distinguishable.
Ensure LocalStorageService and S3StorageService propagate this exception so
storage writes are not attempted, and add coverage verifying no upload occurs
after resize failure.
In
`@momogo-core/src/main/java/com/momogo/core/common/util/storage/ImageResizeSpec.java`:
- Around line 7-18: The affected sites are
momogo-core/src/main/java/com/momogo/core/common/util/storage/ImageResizeSpec.java:7-18
and
momogo-core/src/main/java/com/momogo/core/common/util/storage/ImageProcessor.java:127-138.
Choose the square-only policy: update ImageResizeSpec’s constructor to require
width == height and revise its documentation to state that only square
dimensions are supported; ImageProcessor requires no direct change because the
constructor validation prevents unsupported rectangular specifications.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: eac92740-1607-463e-9422-b9413f70a646
📒 Files selected for processing (8)
momogo-api/src/main/resources/application.yamlmomogo-core/src/main/java/com/momogo/core/common/storage/LocalStorageService.javamomogo-core/src/main/java/com/momogo/core/common/storage/S3StorageService.javamomogo-core/src/main/java/com/momogo/core/common/storage/StorageService.javamomogo-core/src/main/java/com/momogo/core/common/util/storage/ImageProcessor.javamomogo-core/src/main/java/com/momogo/core/common/util/storage/ImageResizeSpec.javamomogo-core/src/main/java/com/momogo/core/common/util/storage/StorageDirectoryValidator.javamomogo-core/src/main/java/com/momogo/core/domain/user/service/UserServiceImpl.java
🚧 Files skipped from review as they are similar to previous changes (1)
- momogo-api/src/main/resources/application.yaml
작업 내용
🛠️ 주요 변경 사항
ImageProcessor컴포넌트 도입 (기존ImageFileValidator대체)outputQuality(0.85))을 적용하여 파일 저장 용량 절감 및 로딩 성능 최적화readWithLimit으로 파일 용량 상한 초과 시 스트림 읽기 즉시 중단StorageDirectoryValidator를 신설하여 로컬 저장소 저장 시 Path Traversal 방지 및 디렉토리 자동 생성LocalStorageService및S3StorageService가ImageProcessor를 주입받아 리사이징/압축된 결과 스트림을 저장하도록 통합변경 사항
체크리스트
참고 사항
관련 이슈
Summary by CodeRabbit
새로운 기능
버그 수정
max-file-size로 정리했습니다.