feat: [ALT-258] 업장 대표이미지 관리 기능 추가 (최대 5개)#91
Conversation
대표이미지(최대 5개) 관리를 위한 기반 구조 추가. 순서 관리가 필요해 File과 별도로 WorkspaceImage(라이브 업장), WorkspaceRequestImage(신청 단계) 조인 엔티티를 도입. FileTargetType에 WORKSPACE_REPRESENTATIVE_IMAGE, ErrorCode에 FILE_LIMIT_EXCEEDED 추가.
신청 시 대표이미지 파일을 첨부하고 순서를 보관(requestId 기준). 승인 시 생성된 업장(workspaceId)으로 파일을 재첨부하고 WorkspaceImage로 순서를 그대로 옮김.
GET /manager/workspaces/{id}/images 목록 조회,
PUT /manager/workspaces/{id}/images 전체 교체(추가/삭제/순서변경 원자 처리).
전달 목록 순서가 노출 순서, 최대 5개 제한.
매니저 업장 상세 조회 시 대표이미지를 노출 순서대로 반환.
📝 WalkthroughWalkthrough업장 대표이미지 기능을 전 계층에 걸쳐 추가한다. Changes업장 대표이미지 기능 전체
Sequence Diagram(s)sequenceDiagram
participant Client
participant ManagerWorkspaceImageController
participant ManagerUpdateWorkspaceImages
participant WorkspaceImageQueryRepository
participant AttachFilesUseCase
participant FileDeleteService
participant WorkspaceImageRepository
Client->>ManagerWorkspaceImageController: PUT /manager/workspaces/{workspaceId}/images
ManagerWorkspaceImageController->>ManagerUpdateWorkspaceImages: execute(actor, workspaceId, request)
ManagerUpdateWorkspaceImages->>WorkspaceImageQueryRepository: findAllByWorkspaceId(workspaceId)
ManagerUpdateWorkspaceImages->>AttachFilesUseCase: execute(신규 fileIds, WORKSPACE_REPRESENTATIVE_IMAGE)
ManagerUpdateWorkspaceImages->>WorkspaceImageRepository: saveAll(신규/갱신 이미지)
ManagerUpdateWorkspaceImages->>FileDeleteService: delete(제거 대상 파일)
ManagerUpdateWorkspaceImages->>WorkspaceImageRepository: deleteAll(제거 대상 이미지)
ManagerUpdateWorkspaceImages-->>ManagerWorkspaceImageController: void
ManagerWorkspaceImageController-->>Client: 200 OK (empty)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 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: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java (1)
24-27: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winApplication 계층 유스케이스에
@Slf4j추가 필요코딩 가이드라인에 따르면
src/main/java/com/dreamteam/alter/application/**경로의 유스케이스는 로깅을 위해@Slf4j를 사용해야 합니다. 대표이미지 관련 주요 비즈니스 작업(생성, 승인 시 마이그레이션, 조회, 수정)에 로깅을 추가하면 운영 환경에서의 추적성과 문제 해결에 도움이 됩니다.
src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java#L24-L27: 클래스 선언부에@Slf4j추가 및 대표이미지 첨부 시점에log.info()권장src/main/java/com/dreamteam/alter/application/workspace/usecase/ApproveWorkspaceRequest.java#L36-L39: 클래스 선언부에@Slf4j추가 및 파일 누락 시log.warn()권장src/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerGetWorkspaceImages.java#L25-L28: 클래스 선언부에@Slf4j추가 및 파일 필터링 시log.debug()권장src/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerUpdateWorkspaceImages.java#L32-L35: 클래스 선언부에@Slf4j추가 및 삭제/추가 작업 시log.info()권장🤖 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 `@src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java` around lines 24 - 27, Add `@Slf4j` annotation to the class declarations in all four workspace usecase files to enable logging according to coding guidelines. In src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java (anchor site, lines 24-27), add `@Slf4j` above the class declaration and insert log.info() calls when attaching representative images. In src/main/java/com/dreamteam/alter/application/workspace/usecase/ApproveWorkspaceRequest.java (sibling site, lines 36-39), add `@Slf4j` to the class declaration and add log.warn() when files are missing during approval. In src/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerGetWorkspaceImages.java (sibling site, lines 25-28), add `@Slf4j` to the class declaration and add log.debug() during file filtering operations. In src/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerUpdateWorkspaceImages.java (sibling site, lines 32-35), add `@Slf4j` to the class declaration and add log.info() when performing delete and add operations on images.Source: Coding guidelines
src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceImage.java (1)
1-72:⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift도메인 계층에 인프라 의존성이 존재합니다.
도메인 엔티티가 JPA 어노테이션(
@Entity,@Table,@ManyToOne,@Column등)과 Spring Data 어노테이션(@CreatedDate,@LastModifiedDate,AuditingEntityListener)을 사용하고 있습니다.코딩 가이드라인에 따르면 도메인 계층은 "ZERO infrastructure dependencies (no Spring, no JPA annotations, no external libs)"를 준수해야 합니다. 헥사고날 아키텍처에서는 도메인 엔티티가 순수 POJO여야 하며, 영속성 관심사는 어댑터 계층에 속합니다.
As per coding guidelines: "
src/main/java/com/dreamteam/alter/domain/**: ZERO infrastructure dependencies (no Spring, no JPA annotations, no external libs)."🤖 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 `@src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceImage.java` around lines 1 - 72, The WorkspaceImage class in the domain layer contains infrastructure dependencies through JPA annotations (`@Entity`, `@Table`, `@ManyToOne`, `@Column`, `@Id`, `@GeneratedValue`, `@JoinColumn`) and Spring Data annotations (`@CreatedDate`, `@LastModifiedDate`, `@EntityListeners`), which violates the requirement for ZERO infrastructure dependencies. Refactor by removing all JPA and Spring annotations from WorkspaceImage, converting it to a pure POJO domain entity with only the core properties (id, workspace, fileId, sortOrder, createdAt, updatedAt) and business methods (create factory method and updateSortOrder). Create a separate JPA persistence entity in the infrastructure layer that handles all database mapping concerns including the `@Entity` annotation, all column configurations, unique constraints, and auditing listeners, then use a mapper to convert between the domain entity and the JPA persistence entity.Source: Coding guidelines
🤖 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
`@src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/CreateWorkspaceRequestDto.java`:
- Around line 71-73: The representativeImageFileIds list validation in both DTOs
is insufficient. In
src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/CreateWorkspaceRequestDto.java
(lines 71-73), add element-level validation by changing the List declaration to
List<`@NotBlank` String> and add a constraint to prevent duplicate IDs (either via
validation annotation or use case-level validation). In
src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/UpdateWorkspaceImagesRequestDto.java
(lines 18-21), apply identical validation: change the representativeImageFileIds
field to List<`@NotBlank` String> and add the duplicate ID prevention constraint
to match the anchor site. This ensures consistent input contracts across both
DTOs and prevents conflicts during delete/add/reorder operations when the image
list is modified.
In
`@src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceImageController.java`:
- Around line 27-33: The ManagerWorkspaceImageController class is missing the
`@Getter` annotation, which violates the team's coding guidelines that require
controllers to use both `@Getter` and `@RequiredArgsConstructor`. Add the `@Getter`
annotation to the class-level annotations alongside the existing
`@RequiredArgsConstructor` annotation to ensure consistency with team standards.
- Around line 34-38: The code mixes `@RequiredArgsConstructor` constructor
injection with `@Resource` field injection, which causes bean name resolution to
fail because `@Resource` annotations are not processed by the constructor
generated by `@RequiredArgsConstructor`. In the ManagerWorkspaceImageController
class, replace the `@Resource` annotations on the managerGetWorkspaceImages and
managerUpdateWorkspaceImages fields with `@Autowired` annotations, and add
`@Qualifier` annotations with the corresponding bean names
(managerGetWorkspaceImages and managerUpdateWorkspaceImages respectively) to
ensure consistent field-based injection. This same pattern should be applied
across all adapter layer controller classes where this mixed injection approach
is currently used.
In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/ApproveWorkspaceRequest.java`:
- Around line 86-111: The attachRepresentativeImages method in the
ApproveWorkspaceRequest class silently skips missing files when they are not
found in the fileMap, which can hide data integrity issues if files are deleted
between request submission and approval. Add `@Slf4j` annotation to the
ApproveWorkspaceRequest class, then add a warning log statement in the
null-check condition (the if block that currently just continues when file is
null) to log which file ID is missing from the workspace request ID, so
operations teams can detect when not all requested images are migrated during
workspace approval.
In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerUpdateWorkspaceImages.java`:
- Around line 58-60: The authorization validation logic in the
ManagerUpdateWorkspaceImages class (the Objects.equals check comparing workspace
manager IDs) should be extracted into a separate, dedicated method to improve
code clarity and intent. Create a new private method (e.g.,
validateWorkspaceOwnership or validateManagerAuthorization) that contains the
authorization check at lines 58-60, then call this new method from the
appropriate location in the use case logic. This makes it explicit that the code
is performing an authorization check rather than simply verifying workspace
existence.
In
`@src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceImage.java`:
- Line 1: The WorkspaceImage and WorkspaceRequestImage classes in the domain
layer currently violate hexagonal architecture principles by including JPA
annotations (`@Entity`, `@Table`, `@ManyToOne`, `@Column`) and Spring Data annotations
(`@CreatedDate`, `@LastModifiedDate`, AuditingEntityListener). Remove all
infrastructure-specific annotations from these domain entity classes to make
them pure POJOs with zero external dependencies. Create corresponding JPA entity
classes in the adapter/infrastructure layer instead, and implement a mapping
layer to convert between domain models and JPA entities for database
persistence.
- Around line 68-70: The updateSortOrder method in the WorkspaceImage class is
missing validation to ensure the sortOrder parameter is not negative. Add a
validation check at the beginning of the updateSortOrder method to verify that
the sortOrder parameter is greater than or equal to 0. If a negative value is
provided, throw an appropriate exception (such as IllegalArgumentException) with
a descriptive message explaining that sortOrder must be non-negative.
In
`@src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequestImage.java`:
- Around line 1-67: The `WorkspaceRequestImage` class contains JPA annotations
(`@Entity`, `@Table`, `@ManyToOne`, `@Column`) and Spring Data annotations
(`@CreatedDate`, `@LastModifiedDate`, `AuditingEntityListener`) in the domain
layer, violating the requirement for ZERO infrastructure dependencies. Remove
all JPA and Spring annotations from the `WorkspaceRequestImage` class and
convert it to a plain POJO containing only the core business logic and data
fields. Create a corresponding JPA entity in the persistence/infrastructure
layer (typically in a `persistence` or `infrastructure` package) that includes
all the annotations and handles the database mapping, keeping the domain entity
purely focused on business rules without any framework dependencies.
In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/ManagerGetWorkspaceImagesUseCase.java`:
- Around line 5-9: The ManagerGetWorkspaceImagesUseCase interface violates
layering by directly importing and using WorkspaceImageResponseDto from the
adapter.inbound package. Domain ports must not depend on adapter DTOs. Create a
domain or application layer response model (such as a WorkspaceImageResult or
similar query result class) in an appropriate package within the domain or
application layer, remove the import of WorkspaceImageResponseDto from the
adapter package, and update the return type of the execute method to use this
new domain-level model instead. The adapter layer will then map from this domain
model to WorkspaceImageResponseDto when needed.
---
Outside diff comments:
In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java`:
- Around line 24-27: Add `@Slf4j` annotation to the class declarations in all four
workspace usecase files to enable logging according to coding guidelines. In
src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java
(anchor site, lines 24-27), add `@Slf4j` above the class declaration and insert
log.info() calls when attaching representative images. In
src/main/java/com/dreamteam/alter/application/workspace/usecase/ApproveWorkspaceRequest.java
(sibling site, lines 36-39), add `@Slf4j` to the class declaration and add
log.warn() when files are missing during approval. In
src/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerGetWorkspaceImages.java
(sibling site, lines 25-28), add `@Slf4j` to the class declaration and add
log.debug() during file filtering operations. In
src/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerUpdateWorkspaceImages.java
(sibling site, lines 32-35), add `@Slf4j` to the class declaration and add
log.info() when performing delete and add operations on images.
In
`@src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceImage.java`:
- Around line 1-72: The WorkspaceImage class in the domain layer contains
infrastructure dependencies through JPA annotations (`@Entity`, `@Table`,
`@ManyToOne`, `@Column`, `@Id`, `@GeneratedValue`, `@JoinColumn`) and Spring Data
annotations (`@CreatedDate`, `@LastModifiedDate`, `@EntityListeners`), which violates
the requirement for ZERO infrastructure dependencies. Refactor by removing all
JPA and Spring annotations from WorkspaceImage, converting it to a pure POJO
domain entity with only the core properties (id, workspace, fileId, sortOrder,
createdAt, updatedAt) and business methods (create factory method and
updateSortOrder). Create a separate JPA persistence entity in the infrastructure
layer that handles all database mapping concerns including the `@Entity`
annotation, all column configurations, unique constraints, and auditing
listeners, then use a mapper to convert between the domain entity and the JPA
persistence entity.
🪄 Autofix (Beta)
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
Run ID: f0595dc9-c986-4c16-af2b-adfa57b7defa
📒 Files selected for processing (27)
src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/CreateWorkspaceRequestDto.javasrc/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceImageController.javasrc/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceImageControllerSpec.javasrc/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/ManagerWorkspaceResponseDto.javasrc/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/UpdateWorkspaceImagesRequestDto.javasrc/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/WorkspaceImageResponseDto.javasrc/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceImageJpaRepository.javasrc/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceImageQueryRepositoryImpl.javasrc/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceImageRepositoryImpl.javasrc/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestImageJpaRepository.javasrc/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestImageQueryRepositoryImpl.javasrc/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestImageRepositoryImpl.javasrc/main/java/com/dreamteam/alter/application/workspace/usecase/ApproveWorkspaceRequest.javasrc/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.javasrc/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerGetWorkspace.javasrc/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerGetWorkspaceImages.javasrc/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerUpdateWorkspaceImages.javasrc/main/java/com/dreamteam/alter/common/exception/ErrorCode.javasrc/main/java/com/dreamteam/alter/domain/file/type/FileTargetType.javasrc/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceImage.javasrc/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequestImage.javasrc/main/java/com/dreamteam/alter/domain/workspace/port/inbound/ManagerGetWorkspaceImagesUseCase.javasrc/main/java/com/dreamteam/alter/domain/workspace/port/inbound/ManagerUpdateWorkspaceImagesUseCase.javasrc/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceImageQueryRepository.javasrc/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceImageRepository.javasrc/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceRequestImageQueryRepository.javasrc/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceRequestImageRepository.java
동일 fileId 중복 전달 시 WorkspaceImage 중복 생성으로 uk_workspace_images_workspace_file 제약 위반 발생. distinct()로 선제거.
File 누락분을 건너뛸 때 sortOrder에 빈 구간이 생기던 문제 수정. 조회/승인 시 노출 순서를 0부터 연속 재계산.
List<@notblank String>로 빈/공백 fileId 유입 차단.
호출처 없는 데드코드 제거 (port/impl/jpa).
코드 리뷰 반영. 매니저 수정 플로우와 동일하게 distinct 처리.
코드 리뷰 반영. sortOrder는 0 이상이어야 하는 불변식 보장.
코드 리뷰 반영. 신청~승인 사이 파일 삭제로 일부만 마이그레이션되는 상황을 운영팀이 인지하도록 log.warn 추가.
엔티티 sortOrder 검증, 매니저 조회/수정(전체교체), 신청 시 중복제거, 승인 시 마이그레이션 케이스 커버.
|
흠... |
- S3 물리 삭제는 롤백 불가하므로 신규 파일 attach/검증 성공 이후 마지막 단계로 이동 - 신규 ErrorCode(FILE_LIMIT_EXCEEDED) 제거 후 기존 ILLEGAL_ARGUMENT 재활용
- List<String> → Set<WorkspaceImageRequestDto>로 변경, fileId 기준 중복 자동 제거 - 노출 순서를 목록 인덱스 대신 sortOrder 필드로 명시 (미지정 시 후순위) - 수정 시 S3 물리 삭제를 attach/검증 성공 이후 마지막 단계로 이동 (트랜잭션 정합성) - 신규 ErrorCode(FILE_LIMIT_EXCEEDED) 제거 후 기존 ILLEGAL_ARGUMENT 재활용
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequestImage.java (1)
56-61:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
create()에서sortOrder불변식 검증이 빠져 있습니다.
WorkspaceImage는 Line 59-76에서 음수 정렬값을 차단하지만, 여기서는sortOrder가 그대로 저장됩니다. 도메인 엔티티 간 불변식이 불일치하면 이후 정렬/조회 계약이 깨질 수 있습니다.
As per coding guidelines, "src/main/java/com/dreamteam/alter/domain/**: Entities encapsulate business rules and invariants."🔧 제안 수정안
public static WorkspaceRequestImage create(WorkspaceRequest workspaceRequest, String fileId, int sortOrder) { + validateSortOrder(sortOrder); return WorkspaceRequestImage.builder() .workspaceRequest(workspaceRequest) .fileId(fileId) .sortOrder(sortOrder) .build(); } + +private static void validateSortOrder(int sortOrder) { + if (sortOrder < 0) { + throw new CustomException(ErrorCode.ILLEGAL_ARGUMENT, "노출 순서는 0 이상이어야 합니다."); + } +}🤖 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 `@src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequestImage.java` around lines 56 - 61, The create() method in the WorkspaceRequestImage class is missing validation for the sortOrder parameter to ensure it is not negative, which creates an inconsistency with the WorkspaceImage entity that enforces this invariant. Add validation logic in the create() method to check that sortOrder is non-negative before building the WorkspaceRequestImage object, ensuring all domain entities maintain consistent business rule enforcement as per the guideline that entities should encapsulate business rules and invariants.Source: Coding guidelines
src/main/java/com/dreamteam/alter/application/workspace/usecase/ApproveWorkspaceRequest.java (1)
89-100:⚠️ Potential issue | 🟡 Minor포트 인터페이스에 정렬 계약을 명시하세요.
현재 코드는 정렬된 결과를 보장합니다: 어댑터의 JPA 리포지토리 메서드
findByWorkspaceRequestIdOrderBySortOrderAsc()가 명시적으로 오름차순 정렬을 수행합니다.하지만 포트 인터페이스
WorkspaceRequestImageQueryRepository.findAllByWorkspaceRequestId()는 정렬을 보장하는 메서드명을 사용하지 않습니다. 다른 개발자가 이 포트를 구현할 때 정렬 요구사항을 놓칠 수 있습니다.attachRepresentativeImages메서드는 이 정렬 순서에 직접 의존하므로, 포트 계약이 더 명확해야 합니다.수정 제안:
- 포트 메서드명을
findAllByWorkspaceRequestIdOrderBySortOrderAsc()로 변경하거나- 포트 인터페이스의 메서드에 JavaDoc을 추가하여 정렬 순서를 명시 (
@return sort_order 오름차순으로 정렬된 이미지 목록)🤖 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 `@src/main/java/com/dreamteam/alter/application/workspace/usecase/ApproveWorkspaceRequest.java` around lines 89 - 100, The port interface WorkspaceRequestImageQueryRepository.findAllByWorkspaceRequestId() does not explicitly specify that results are sorted by sort_order in ascending order, even though the attachRepresentativeImages method depends on this ordering. Make the sorting contract explicit in the port interface either by renaming the method to findAllByWorkspaceRequestIdOrderBySortOrderAsc() to match the implementation, or by adding a JavaDoc comment to the existing method that clearly documents that the returned list is sorted in ascending order by sort_order. This ensures other developers implementing this port will understand the sorting requirement.
🤖 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
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java`:
- Around line 59-61: The CreateWorkspaceRequest use case is missing validation
to enforce the maximum 5-image limit for representative images. After extracting
representativeImageFileIds using
WorkspaceImageRequestDto.toOrderedFileIds(request.getRepresentativeImages()),
add a check to validate that the list size does not exceed 5 images, and throw
an appropriate validation exception if the limit is exceeded, consistent with
how this validation is handled in the admin replacement use case.
In
`@src/test/java/com/dreamteam/alter/application/workspace/usecase/ApproveWorkspaceRequestTest.java`:
- Line 39: The test class ApproveWorkspaceRequestTest does not follow the
project's naming convention which requires test classes to use the plural form
[ClassName]Tests.java. Rename the class from ApproveWorkspaceRequestTest to
ApproveWorkspaceRequestTests and update the file name accordingly from
ApproveWorkspaceRequestTest.java to ApproveWorkspaceRequestTests.java to comply
with the coding guidelines for test classes in src/test/**.
In
`@src/test/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequestTest.java`:
- Line 34: The test class CreateWorkspaceRequestTest does not follow the
project's naming convention which requires test classes to use the plural
"Tests" suffix. Rename the class from CreateWorkspaceRequestTest to
CreateWorkspaceRequestTests and update the file name from
CreateWorkspaceRequestTest.java to CreateWorkspaceRequestTests.java to comply
with the coding guidelines.
In
`@src/test/java/com/dreamteam/alter/application/workspace/usecase/ManagerGetWorkspaceImagesTest.java`:
- Line 31: The test class and file name do not follow the required naming
convention for test classes. Rename both the file from
`ManagerGetWorkspaceImagesTest.java` to `ManagerGetWorkspaceImagesTests.java`
(note the plural "Tests") and update the class name from
`ManagerGetWorkspaceImagesTest` to `ManagerGetWorkspaceImagesTests` to comply
with the coding guideline that test classes in `src/test/**` should follow the
pattern `[ClassName]Tests.java` with a plural "Tests" suffix.
In
`@src/test/java/com/dreamteam/alter/application/workspace/usecase/ManagerUpdateWorkspaceImagesTest.java`:
- Line 44: The test class name violates the team's naming convention which
requires test classes to use the pattern [ClassName]Tests.java with a plural
"Tests" suffix. Rename the class ManagerUpdateWorkspaceImagesTest to
ManagerUpdateWorkspaceImagesTests and rename the corresponding file from
ManagerUpdateWorkspaceImagesTest.java to ManagerUpdateWorkspaceImagesTests.java
to comply with the coding guidelines.
In
`@src/test/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceImageTest.java`:
- Around line 13-56: Rename the test class from WorkspaceImageTest to
WorkspaceImageTests (plural form) to align with team conventions. Then update
all four test methods to follow the action_condition_expectedResult naming
pattern: rename create_정상 to create_validSortOrder_createsSuccessfully,
create_음수sortOrder_예외 to
create_negativeSortOrder_throwsIllegalArgumentException, updateSortOrder_정상 to
updateSortOrder_validValue_updatesSuccessfully, and updateSortOrder_음수_예외 to
updateSortOrder_negativeValue_throwsIllegalArgumentException. Finally, replace
the informal when/then comment style with explicit section comments: add a given
comment above the setup code, change when to when, and ensure then appears
before assertions, making the Given-When-Then pattern clearly visible throughout
all test methods.
---
Outside diff comments:
In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/ApproveWorkspaceRequest.java`:
- Around line 89-100: The port interface
WorkspaceRequestImageQueryRepository.findAllByWorkspaceRequestId() does not
explicitly specify that results are sorted by sort_order in ascending order,
even though the attachRepresentativeImages method depends on this ordering. Make
the sorting contract explicit in the port interface either by renaming the
method to findAllByWorkspaceRequestIdOrderBySortOrderAsc() to match the
implementation, or by adding a JavaDoc comment to the existing method that
clearly documents that the returned list is sorted in ascending order by
sort_order. This ensures other developers implementing this port will understand
the sorting requirement.
In
`@src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequestImage.java`:
- Around line 56-61: The create() method in the WorkspaceRequestImage class is
missing validation for the sortOrder parameter to ensure it is not negative,
which creates an inconsistency with the WorkspaceImage entity that enforces this
invariant. Add validation logic in the create() method to check that sortOrder
is non-negative before building the WorkspaceRequestImage object, ensuring all
domain entities maintain consistent business rule enforcement as per the
guideline that entities should encapsulate business rules and invariants.
🪄 Autofix (Beta)
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
Run ID: 0acc0242-f98a-4ea8-b0ec-a7c640c5006b
📒 Files selected for processing (18)
src/main/java/com/dreamteam/alter/adapter/inbound/common/dto/WorkspaceImageRequestDto.javasrc/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/CreateWorkspaceRequestDto.javasrc/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceImageControllerSpec.javasrc/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/UpdateWorkspaceImagesRequestDto.javasrc/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceImageJpaRepository.javasrc/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceImageQueryRepositoryImpl.javasrc/main/java/com/dreamteam/alter/application/workspace/usecase/ApproveWorkspaceRequest.javasrc/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.javasrc/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerGetWorkspaceImages.javasrc/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerUpdateWorkspaceImages.javasrc/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceImage.javasrc/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequestImage.javasrc/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceImageQueryRepository.javasrc/test/java/com/dreamteam/alter/application/workspace/usecase/ApproveWorkspaceRequestTest.javasrc/test/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequestTest.javasrc/test/java/com/dreamteam/alter/application/workspace/usecase/ManagerGetWorkspaceImagesTest.javasrc/test/java/com/dreamteam/alter/application/workspace/usecase/ManagerUpdateWorkspaceImagesTest.javasrc/test/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceImageTest.java
💤 Files with no reviewable changes (3)
- src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceImageJpaRepository.java
- src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceImageQueryRepositoryImpl.java
- src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceImageQueryRepository.java
| List<String> representativeImageFileIds = | ||
| WorkspaceImageRequestDto.toOrderedFileIds(request.getRepresentativeImages()); | ||
| if (!representativeImageFileIds.isEmpty()) { |
There was a problem hiding this comment.
신청 단계에서도 대표이미지 5개 상한을 강제해주세요.
현재 신청 생성 흐름에는 최대 5개 제한이 없어, 컨트롤러 검증을 우회한 호출에서 비즈니스 규칙이 깨질 수 있습니다. 관리자 교체 유스케이스와 동일하게 여기서도 상한을 검사하는 게 안전합니다.
제안 수정안
+import com.dreamteam.alter.common.exception.CustomException;
+import com.dreamteam.alter.common.exception.ErrorCode;
@@
List<String> representativeImageFileIds =
WorkspaceImageRequestDto.toOrderedFileIds(request.getRepresentativeImages());
+ if (representativeImageFileIds.size() > 5) {
+ throw new CustomException(ErrorCode.ILLEGAL_ARGUMENT, "대표이미지는 최대 5개까지 등록할 수 있습니다.");
+ }
if (!representativeImageFileIds.isEmpty()) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| List<String> representativeImageFileIds = | |
| WorkspaceImageRequestDto.toOrderedFileIds(request.getRepresentativeImages()); | |
| if (!representativeImageFileIds.isEmpty()) { | |
| import com.dreamteam.alter.common.exception.CustomException; | |
| import com.dreamteam.alter.common.exception.ErrorCode; | |
| // ... existing code ... | |
| List<String> representativeImageFileIds = | |
| WorkspaceImageRequestDto.toOrderedFileIds(request.getRepresentativeImages()); | |
| if (representativeImageFileIds.size() > 5) { | |
| throw new CustomException(ErrorCode.ILLEGAL_ARGUMENT, "대표이미지는 최대 5개까지 등록할 수 있습니다."); | |
| } | |
| if (!representativeImageFileIds.isEmpty()) { |
🤖 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
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java`
around lines 59 - 61, The CreateWorkspaceRequest use case is missing validation
to enforce the maximum 5-image limit for representative images. After extracting
representativeImageFileIds using
WorkspaceImageRequestDto.toOrderedFileIds(request.getRepresentativeImages()),
add a check to validate that the list size does not exceed 5 images, and throw
an appropriate validation exception if the limit is exceeded, consistent with
how this validation is handled in the admin replacement use case.
|
|
||
| @ExtendWith(MockitoExtension.class) | ||
| @DisplayName("ApproveWorkspaceRequest 테스트") | ||
| class ApproveWorkspaceRequestTest { |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
테스트 클래스/파일명을 ...Tests 형태로 변경해주세요.
ApproveWorkspaceRequestTest는 현재 테스트 네이밍 규칙과 맞지 않습니다. 클래스/파일명을 ApproveWorkspaceRequestTests로 맞춰주세요.
As per coding guidelines, src/test/**에서는 Test classes follow [ClassName]Tests.java naming (plural "Tests")를 따라야 합니다.
🤖 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
`@src/test/java/com/dreamteam/alter/application/workspace/usecase/ApproveWorkspaceRequestTest.java`
at line 39, The test class ApproveWorkspaceRequestTest does not follow the
project's naming convention which requires test classes to use the plural form
[ClassName]Tests.java. Rename the class from ApproveWorkspaceRequestTest to
ApproveWorkspaceRequestTests and update the file name accordingly from
ApproveWorkspaceRequestTest.java to ApproveWorkspaceRequestTests.java to comply
with the coding guidelines for test classes in src/test/**.
Source: Coding guidelines
|
|
||
| @ExtendWith(MockitoExtension.class) | ||
| @DisplayName("CreateWorkspaceRequest 테스트") | ||
| class CreateWorkspaceRequestTest { |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
테스트 클래스/파일명을 ...Tests 규칙으로 맞춰주세요.
현재 CreateWorkspaceRequestTest는 테스트 네이밍 컨벤션과 불일치합니다. 클래스명과 파일명을 CreateWorkspaceRequestTests로 통일해 주세요.
As per coding guidelines, src/test/**에서는 Test classes follow [ClassName]Tests.java naming (plural "Tests")를 따라야 합니다.
🤖 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
`@src/test/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequestTest.java`
at line 34, The test class CreateWorkspaceRequestTest does not follow the
project's naming convention which requires test classes to use the plural
"Tests" suffix. Rename the class from CreateWorkspaceRequestTest to
CreateWorkspaceRequestTests and update the file name from
CreateWorkspaceRequestTest.java to CreateWorkspaceRequestTests.java to comply
with the coding guidelines.
Source: Coding guidelines
|
|
||
| @ExtendWith(MockitoExtension.class) | ||
| @DisplayName("ManagerGetWorkspaceImages 테스트") | ||
| class ManagerGetWorkspaceImagesTest { |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
테스트 클래스/파일명을 ...Tests로 정렬해주세요.
ManagerGetWorkspaceImagesTest는 테스트 명명 규칙과 다릅니다. ManagerGetWorkspaceImagesTests로 클래스/파일명을 맞춰주세요.
As per coding guidelines, src/test/**에서는 Test classes follow [ClassName]Tests.java naming (plural "Tests")를 따라야 합니다.
🤖 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
`@src/test/java/com/dreamteam/alter/application/workspace/usecase/ManagerGetWorkspaceImagesTest.java`
at line 31, The test class and file name do not follow the required naming
convention for test classes. Rename both the file from
`ManagerGetWorkspaceImagesTest.java` to `ManagerGetWorkspaceImagesTests.java`
(note the plural "Tests") and update the class name from
`ManagerGetWorkspaceImagesTest` to `ManagerGetWorkspaceImagesTests` to comply
with the coding guideline that test classes in `src/test/**` should follow the
pattern `[ClassName]Tests.java` with a plural "Tests" suffix.
Source: Coding guidelines
|
|
||
| @ExtendWith(MockitoExtension.class) | ||
| @DisplayName("ManagerUpdateWorkspaceImages 테스트") | ||
| class ManagerUpdateWorkspaceImagesTest { |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
테스트 클래스/파일명을 ...Tests 규칙으로 변경해주세요.
ManagerUpdateWorkspaceImagesTest는 팀 테스트 네이밍 규칙과 불일치합니다. ManagerUpdateWorkspaceImagesTests로 맞춰주세요.
As per coding guidelines, src/test/**에서는 Test classes follow [ClassName]Tests.java naming (plural "Tests")를 따라야 합니다.
🤖 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
`@src/test/java/com/dreamteam/alter/application/workspace/usecase/ManagerUpdateWorkspaceImagesTest.java`
at line 44, The test class name violates the team's naming convention which
requires test classes to use the pattern [ClassName]Tests.java with a plural
"Tests" suffix. Rename the class ManagerUpdateWorkspaceImagesTest to
ManagerUpdateWorkspaceImagesTests and rename the corresponding file from
ManagerUpdateWorkspaceImagesTest.java to ManagerUpdateWorkspaceImagesTests.java
to comply with the coding guidelines.
Source: Coding guidelines
| class WorkspaceImageTest { | ||
|
|
||
| @Test | ||
| @DisplayName("정상 sortOrder로 생성된다") | ||
| void create_정상() { | ||
| // when | ||
| WorkspaceImage image = WorkspaceImage.create(null, "file-1", 0); | ||
|
|
||
| // then | ||
| assertThat(image.getFileId()).isEqualTo("file-1"); | ||
| assertThat(image.getSortOrder()).isZero(); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("음수 sortOrder로 생성하면 ILLEGAL_ARGUMENT 예외가 발생한다") | ||
| void create_음수sortOrder_예외() { | ||
| // when & then | ||
| assertThatThrownBy(() -> WorkspaceImage.create(null, "file-1", -1)) | ||
| .isInstanceOf(CustomException.class) | ||
| .satisfies(ex -> assertThat(((CustomException) ex).getErrorCode()).isEqualTo(ErrorCode.ILLEGAL_ARGUMENT)); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("updateSortOrder는 0 이상 값을 허용한다") | ||
| void updateSortOrder_정상() { | ||
| // given | ||
| WorkspaceImage image = WorkspaceImage.create(null, "file-1", 0); | ||
|
|
||
| // when & then | ||
| assertThatCode(() -> image.updateSortOrder(3)).doesNotThrowAnyException(); | ||
| assertThat(image.getSortOrder()).isEqualTo(3); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("updateSortOrder에 음수를 주면 ILLEGAL_ARGUMENT 예외가 발생한다") | ||
| void updateSortOrder_음수_예외() { | ||
| // given | ||
| WorkspaceImage image = WorkspaceImage.create(null, "file-1", 0); | ||
|
|
||
| // when & then | ||
| assertThatThrownBy(() -> image.updateSortOrder(-1)) | ||
| .isInstanceOf(CustomException.class) | ||
| .satisfies(ex -> assertThat(((CustomException) ex).getErrorCode()).isEqualTo(ErrorCode.ILLEGAL_ARGUMENT)); | ||
| } |
There was a problem hiding this comment.
테스트 네이밍/구조가 팀 테스트 규약과 다릅니다.
현재 클래스/메서드 네이밍(예: WorkspaceImageTest, create_정상)과 when & then 결합 스타일은 팀 규약(*Tests, action_condition_expectedResult, 명시적 Given-When-Then)과 불일치합니다. Line 13, Line 17, Line 28, Line 37, Line 48 기준으로 규약에 맞춰 정리해 주세요.
As per coding guidelines, "src/test/**: Test classes follow [ClassName]Tests.java naming, test methods use action_condition_expectedResult, Given-When-Then pattern with explicit comments."
🤖 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
`@src/test/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceImageTest.java`
around lines 13 - 56, Rename the test class from WorkspaceImageTest to
WorkspaceImageTests (plural form) to align with team conventions. Then update
all four test methods to follow the action_condition_expectedResult naming
pattern: rename create_정상 to create_validSortOrder_createsSuccessfully,
create_음수sortOrder_예외 to
create_negativeSortOrder_throwsIllegalArgumentException, updateSortOrder_정상 to
updateSortOrder_validValue_updatesSuccessfully, and updateSortOrder_음수_예외 to
updateSortOrder_negativeValue_throwsIllegalArgumentException. Finally, replace
the informal when/then comment style with explicit section comments: add a given
comment above the setup code, change when to when, and ensure then appears
before assertions, making the Given-When-Then pattern clearly visible throughout
all test methods.
Source: Coding guidelines
ysw789
left a comment
There was a problem hiding this comment.
ManagerGetWorkspace.java 에서 중복 소유 검증 하는 부분만 체크해보고, 통합 테스트 후 문제 없으면 병합하면 될 것 같습니다
관련 문서
https://app.notion.com/p/BE-5-38086553162880baab73d11e16837e09?source=copy_link
개요
업장 등록 시 대표이미지(구직자 노출용)를 등록·관리하는 기능 추가. 업장당 최대 5개, 노출 순서 관리 지원.
설계 요약
순서 관리가 필요해 polymorphic
File만으로는 부족(sortOrder 없음).File은 S3 객체 보관/생명주기 그대로 재사용하고, 순서·업장연결을 담당하는 전용 조인 엔티티를 도입.
WorkspaceImage— 라이브 업장용, 순서 authorityWorkspaceRequestImage— 신청 단계 순서 보관 (승인 시점엔 workspaceId가 없어 별도 보관)변경 사항
기반
FileTargetType.WORKSPACE_REPRESENTATIVE_IMAGE,ErrorCode.FILE_LIMIT_EXCEEDED(B026) 추가WorkspaceImage,WorkspaceRequestImage엔티티 + Repository/QueryRepository신청/승인 플로우
CreateWorkspaceRequestDto.representativeImageFileIds(최대 5) 첨부 + 순서 보관(requestId 기준)WorkspaceImage로 순서 이관매니저 관리 API
GET /manager/workspaces/{id}/images— 노출 순서대로 목록 조회PUT /manager/workspaces/{id}/images— 전체 교체(추가/삭제/순서변경 원자 처리), 최대 5개상세 조회
representativeImages노출DB 마이그레이션
workspace_images(workspace_id FK, file_id, sort_order, created_at, updated_at, UNIQUE(workspace_id, file_id))workspace_request_images(workspace_request_id FK, file_id, sort_order, created_at, updated_at, UNIQUE(workspace_request_id,file_id))
미포함 (후속)
PostingDetailWorkspaceResponseDto미변경테스트
./gradlew compileJava통과Summary by CodeRabbit
릴리스 노트