feat(configuration): 파일 도메인 모델 및 규칙 정의 #26 - #56
Hidden character warning
Conversation
- FileExtension: 확장자↔MIME 매핑, jpeg 별칭 허용 - FileCategory: 용도별 object_key prefix, 허용 확장자, 최대 용량 - FileDocument: files 테이블 대응 도메인 모델 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
명세의 에러 코드에 1:1 대응하는 예외를 추가한다. INVALID_FILE_FORMAT, FILE_TOO_LARGE, FILE_NOT_FOUND, STORAGE_UPLOAD_FAILED, PRESIGN_FAILED 및 키 조작 방어용 예외. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- port/in: UploadFileUseCase, IssueDownloadUrlUseCase, ReadFileUseCase - port/out: StoragePort(S3), FileDocumentRepository(files) - DownloadUrl, StoredObject 값 객체와 커맨드 추가 바이너리는 커맨드가 아니라 InputStream 파라미터로 분리해 커맨드의 값 의미를 유지한다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
명세 응답 예시(application_1001.pdf, photo_5f3c9a2b.jpg 등)에 맞는 파일명 생성 규칙을 도메인에 둔다. 경로 구분자, 상위 경로 참조, 허용 외 문자를 걸러 object_key 조작을 막는다. 지원자 목록 excel 다운로드는 fileName이 그대로 키에 붙으므로 requireSafeFileName으로 거부한다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
확장자 인식, 카테고리별 허용 형식/용량, 명세 예시와 동일한 파일명 생성, 경로 조작 거부를 검증한다. 기존 test 타깃이 :main에 의존하지 않아 도메인 클래스를 참조하는 테스트가 컴파일되지 않던 문제를 함께 수정한다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are limited based on label configuration. 🏷️ Required labels (at least one) (1)
🚫 Excluded labels (none allowed) (2)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 Walkthrough사용자는 파일 업로드와 다운로드 기능에 필요한 순수 Kotlin 도메인 모델과 규칙을 사용할 수 있습니다. Spring, AWS, JPA 의존성은 추가하지 않았습니다. 아키텍처 변경
위험 영역
마이그레이션 및 호환성
검증 체크리스트
롤아웃 노트
Walkthrough문서 도메인에 파일 모델, 확장자·크기·파일명 검증 규칙, 업로드·조회·다운로드 URL 발급 포트가 추가되었습니다. 관련 예외와 도메인 테스트 및 Bazel 테스트 타깃도 추가되었습니다. Changes문서 도메인 기능
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 9 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (9 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: 3
🤖 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
`@systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileCategory.kt`:
- Line 24: Update FileCategory.objectKeyOf to validate fileName through
FileNaming.requireSafeFileName before constructing the prefixed object key,
preserving the existing key format for valid names. Add a DocumentDomainTest
case asserting that objectKeyOf("../../etc/passwd") throws the expected
validation exception.
In
`@systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileExtension.kt`:
- Around line 18-22: Rename the non-const properties in FileExtension.kt at
lines 18-22 from DOCUMENT_FORMATS, IMAGE_FORMATS, and ATTACHMENT_FORMATS to
documentFormats, imageFormats, and attachmentFormats, updating all references.
Apply the same lowerCamelCase convention in FileNaming.kt lines 8-10 by renaming
the properties to safeIdentifier, unsafeCharacters, and applicantListDate and
updating their references.
In
`@systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileNaming.kt`:
- Line 11: Update TOKEN_LENGTH and the corresponding token-generation logic in
FileNaming to use a full UUID or another identifier with at least 128 bits,
rather than an 8-character hexadecimal token. Adjust related tests expecting
[0-9a-f]{8} to validate the new identifier length and format.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: 03ae35d1-1383-4683-97a6-fb305604d6ae
📒 Files selected for processing (21)
systems/configuration/configuration-domain/BUILD.bazelsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/DownloadUrl.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileCategory.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileDocument.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileExtension.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileNaming.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/StoredObject.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/IssueDownloadUrlCommand.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/UploadFileCommand.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileDocumentNotFoundException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileTooLargeException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileFormatException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileNameException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/PresignFailedException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/StorageUploadFailedException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/IssueDownloadUrlUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/ReadFileUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/UploadFileUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/FileDocumentRepository.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/StoragePort.ktsystems/configuration/configuration-domain/src/test/kotlin/hs/kr/entrydsm/configuration/domain/document/DocumentDomainTest.kt
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{kt,go}
📄 CodeRabbit inference engine (Custom checks)
If production logic is changed in Kotlin or Go files, require corresponding test updates in the same subsystem unless the PR description explicitly justifies why tests are unnecessary
Files:
systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileDocumentNotFoundException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/PresignFailedException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/IssueDownloadUrlUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/DownloadUrl.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileTooLargeException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileFormatException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/ReadFileUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileNameException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/StoragePort.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/UploadFileUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/UploadFileCommand.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileDocument.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/StorageUploadFailedException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileCategory.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/FileDocumentRepository.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/StoredObject.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileNaming.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileExtension.ktsystems/configuration/configuration-domain/src/test/kotlin/hs/kr/entrydsm/configuration/domain/document/DocumentDomainTest.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/IssueDownloadUrlCommand.kt
**/*-domain/**/*.{java,kt,scala,groovy}
📄 CodeRabbit inference engine (Custom checks)
For files under *-domain modules, fail if imports reference adapter or bootstrap packages
Files:
systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileDocumentNotFoundException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/PresignFailedException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/IssueDownloadUrlUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/DownloadUrl.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileTooLargeException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileFormatException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/ReadFileUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileNameException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/StoragePort.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/UploadFileUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/UploadFileCommand.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileDocument.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/StorageUploadFailedException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileCategory.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/FileDocumentRepository.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/StoredObject.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileNaming.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileExtension.ktsystems/configuration/configuration-domain/src/test/kotlin/hs/kr/entrydsm/configuration/domain/document/DocumentDomainTest.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/IssueDownloadUrlCommand.kt
**/*.{java,kt,scala,groovy,go,js,ts,tsx,jsx,py,rb,rs,cpp,c,h,hpp,cs}
📄 CodeRabbit inference engine (Custom checks)
Flag TODO/FIXME comments introduced by this PR that do not include an issue reference in the form
#123or a full tracker key like PROJ-123
Files:
systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileDocumentNotFoundException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/PresignFailedException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/IssueDownloadUrlUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/DownloadUrl.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileTooLargeException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileFormatException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/ReadFileUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileNameException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/StoragePort.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/UploadFileUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/UploadFileCommand.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileDocument.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/StorageUploadFailedException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileCategory.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/FileDocumentRepository.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/StoredObject.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileNaming.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileExtension.ktsystems/configuration/configuration-domain/src/test/kotlin/hs/kr/entrydsm/configuration/domain/document/DocumentDomainTest.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/IssueDownloadUrlCommand.kt
**/*.kt
⚙️ CodeRabbit configuration file
**/*.kt: Apply Kotlin Official Coding Conventions.Formatting and structure:
- Use 4 spaces for indentation; no tabs.
- Keep files focused and readable; avoid horizontal alignment for spacing.
- Place related declarations together and keep overloads adjacent.
- Keep implementation member order stable and logical for readability.
Naming:
- Package names are lowercase and do not use underscores.
- Class/object names use UpperCamelCase.
- Functions/properties/local variables use lowerCamelCase.
- Constants use UPPER_SNAKE_CASE only for true constants.
API and null-safety:
- Avoid platform type leakage in public APIs.
- Use explicit types in public APIs when inference obscures meaning.
- Prefer immutable values (
val) over mutable values (var) unless mutation is required.- Flag nullable flows that can be replaced with safer modeling.
Imports and idioms:
- Avoid wildcard imports unless justified by language/tooling conventions.
- Prefer expression bodies for short, clear functions.
- Prefer standard library idioms over custom utility wrappers when equivalent.
Architecture and tests:
- Respect module boundaries (domain/application/adapter/bootstrap layering).
- Highlight behavior-changing code that lacks corresponding unit/integration tests.
- Ask for deterministic tests and meaningful assertions, not only happy-path checks.
Files:
systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileDocumentNotFoundException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/PresignFailedException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/IssueDownloadUrlUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/DownloadUrl.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileTooLargeException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileFormatException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/ReadFileUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileNameException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/StoragePort.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/UploadFileUseCase.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/UploadFileCommand.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileDocument.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/StorageUploadFailedException.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileCategory.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/FileDocumentRepository.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/StoredObject.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileNaming.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileExtension.ktsystems/configuration/configuration-domain/src/test/kotlin/hs/kr/entrydsm/configuration/domain/document/DocumentDomainTest.ktsystems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/IssueDownloadUrlCommand.kt
**/{BUILD.bazel,*.bzl}
📄 CodeRabbit inference engine (Custom checks)
In BUILD.bazel and .bzl files, require buildifier-compatible formatting and stable target naming
Files:
systems/configuration/configuration-domain/BUILD.bazel
**/BUILD.bazel
⚙️ CodeRabbit configuration file
**/BUILD.bazel: Apply Bazel BUILD style guidance.Core rules:
- BUILD formatting must match buildifier output.
- Prefer DAMP BUILD files over over-abstracted DRY patterns.
- Keep top-level layout clear: load() first, then package/default visibility, then targets.
Target definitions:
- Keep deps explicit and close to each target's real direct dependencies.
- Avoid recursive globs unless there is a clear, documented reason.
- Avoid top-level list comprehensions for generating many targets.
- Prefer literal labels and stable naming for readability and tooling compatibility.
- Use boolean values (True/False), not numeric stand-ins.
Maintenance:
- Flag duplicated target logic that should be moved into a macro.
- Flag macro usage that hides important dependency or visibility decisions.
Files:
systems/configuration/configuration-domain/BUILD.bazel
🔇 Additional comments (12)
systems/configuration/configuration-domain/BUILD.bazel (1)
25-25: 📐 Maintainability & Code Quality | ⚡ Quick win
document_test에는 명시적인 테스트 소스를 사용하십시오.새 타깃은 모든 테스트 소스를 재귀
glob으로 다시 포함합니다.document_test는DocumentDomainTest만 실행하므로 해당 파일만srcs에 지정하십시오. 이 변경은 타깃 입력과 컴파일 범위를 안정화합니다.[ suggest_recommended_refactor]
As per path instructions, "Avoid recursive globs unless there is a clear, documented reason."
Source: Path instructions
systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileTooLargeException.kt (1)
1-4: LGTM!systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/InvalidFileNameException.kt (1)
1-4: LGTM!systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/IssueDownloadUrlCommand.kt (1)
5-8: 🔒 Security & Privacy두 명령의 파일명 입력이 동일한 object key 안전성 경계를 공유합니다.
FileNaming.requireSafeFileName을 통과한 값만FileCategory.objectKeyOf에 전달되도록 두 유스케이스의 호출 순서를 확인하세요.
systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/IssueDownloadUrlCommand.kt#L5-L8:fileName을 검증한 후 object key 조회와 URL 발급을 수행하세요.systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/UploadFileCommand.kt#L5-L10: nullablefileName이 생성 규칙을 우회하지 않도록 안전한 값 객체를 사용하거나 검증 후 object key를 생성하세요.systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/command/UploadFileCommand.kt (2)
7-9: 🔒 Security & Privacy선택적
fileName으로 파일명 생성 규칙을 우회하지 못하게 하세요.호출자가
fileName을 직접 지정할 수 있습니다. 이 값이FileCategory.objectKeyOf에 전달되기 전에FileNaming.requireSafeFileName을 통과하지 않으면 경로 구분자와..가 포함된 object key가 생성될 수 있습니다. 안전한 값 객체를 사용하거나, 업로드 유스케이스에서 항상 검증 후 object key를 생성하는지 확인하세요.
8-8: 🗄️ Data Integrity & Integration음수
sizeBytes입력을 명시적으로 거부하세요.
systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/FileCategory.ktLine 7-25의exceedsMaxSize는sizeBytes > maxSizeBytes만 확인합니다. 별도 하한 검사가 없으면 음수 크기가StoragePort.upload와FileDocument.sizeBytes로 전달될 수 있습니다.sizeBytes >= 0검증과-1,0, 최대값, 최대값 초과 경계값 테스트를 확인하세요.systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/IssueDownloadUrlUseCase.kt (1)
6-9: LGTM!systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/ReadFileUseCase.kt (1)
6-10: LGTM!systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/in/UploadFileUseCase.kt (1)
7-9: LGTM!systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/FileDocumentRepository.kt (1)
5-11: LGTM!systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/port/out/StoragePort.kt (1)
6-19: LGTM!systems/configuration/configuration-domain/src/main/kotlin/hs/kr/entrydsm/configuration/domain/document/exception/FileDocumentNotFoundException.kt (1)
3-4: 🎯 Functional CorrectnessID 기반 조회의 예외 메시지를 구분하세요.
FileDocumentNotFoundException의 생성자로 전달된 값은 현재 실제 객체 키로만 쓰입니다. 나중에findById(id: Long)가 이 예외를 던지면 메시지에도 ID가 표시되어 조회 기준을 오해할 수 있으므로, ID 조회와 object key 조회는 서로 다른 예외로 구분하세요. 현재는 해당 throw site가 없습니다.
FileCategory.objectKeyOf 가 파일명을 검증 없이 prefix 에 이어붙여 경로 구분자나 상위 경로 참조를 그대로 키에 넣을 수 있었다. FileNaming.requireSafeFileName 을 통과한 값만 사용하도록 바꾸고, 128비트로 확장된 랜덤 토큰 길이에 맞춰 깨져 있던 테스트 기대값도 수정했다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
const 가 아닌 프로퍼티에 UPPER_SNAKE_CASE 를 쓰고 있어 코딩 컨벤션과 어긋났다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Summary
deps.bzl은 비어 있는 상태 유지).Related Issue
Scope
configuration-domain의hs.kr.entrydsm.configuration.domain.document패키지Implementation
API 11종은 허용 확장자·용량 한도·
object_key명명 규칙이 API마다 다릅니다. 이 규칙이 컨트롤러나 어댑터에 흩어지면 원서 슬롯에 이미지가 올라가는 식의 사고를 막을 수 없어 도메인에 모았습니다.FileExtension— 확장자↔MIME 매핑.jpeg를jpg별칭으로 처리FileCategory— 용도별object_keyprefix, 허용 확장자 집합, 최대 용량. 전역 화이트리스트 하나로 두면 카테고리별 제한이 불가능해 카테고리가 자기 허용 집합을 갖습니다FileNaming— 명세 응답 예시와 동일한 파일명 생성(application_1001.pdf,photo_5f3c9a2b.jpg등) + 경로 조작 방어INVALID_FILE_FORMAT,FILE_TOO_LARGE,FILE_NOT_FOUND,STORAGE_UPLOAD_FAILED,PRESIGN_FAILED)port/in3종,port/out2종. 참조 구현(EnvironmentVariable)과 동일하게-application이 아니라-domain에 둡니다#7 지원자 목록 excel 다운은fileName이 그대로 S3 키에 붙으므로requireSafeFileName으로 경로 구분자·상위 경로 참조를 거부합니다.Testing
Deployment Notes
Checklist
리뷰 시 봐주셨으면 하는 것
.hwpMIME — 표준이 없어application/x-hwp로 고정했습니다.BUILD.bazel수정 포함 — 기존test타깃이:main에 의존하지 않아 도메인 클래스를 참조하는 테스트가 컴파일되지 않았습니다. 함께 고쳤습니다.kt_jvm_test는test_class를 하나만 받아document_test타깃을 별도로 추가했습니다.