Skip to content

feat: 업장 등록 신청 및 승인/반려 사유 댓글 구현#70

Open
juny0955 wants to merge 41 commits intodevfrom
feat/ALT-148
Open

feat: 업장 등록 신청 및 승인/반려 사유 댓글 구현#70
juny0955 wants to merge 41 commits intodevfrom
feat/ALT-148

Conversation

@juny0955
Copy link
Copy Markdown
Contributor

@juny0955 juny0955 commented Mar 21, 2026

관련 문서

https://www.notion.so/BE-317865531628803b9e67c82adb3f67c3?v=2b186553162880979f62000c6c946512&source=copy_link

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 파일 업로드, 임시 접근 URL 조회 및 삭제 기능 추가
    • 업장 등록 신청 기능 추가
    • 업장 등록 신청 사유에 대한 댓글 작성 및 조회 기능 추가
  • 개선 사항

    • 파일 관리 및 업장 등록 프로세스 강화

@juny0955 juny0955 requested review from hodoon and ysw789 March 21, 2026 06:51
@juny0955 juny0955 self-assigned this Mar 21, 2026
@juny0955 juny0955 added the FEAT label Mar 21, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 21, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

파일 업로드, 프리사인된 URL 조회, 삭제 기능을 제공하는 REST 컨트롤러와 워크스페이스 등록 신청서 작성, 조회, 반려 이유 댓글 관리 기능을 추가합니다. 관련 도메인 엔터티, 리포지토리, 유스케이스, DTO를 함께 구현합니다.

Changes

코호트 / 파일(s) 요약
파일 관리 REST 컨트롤러
src/main/java/com/dreamteam/alter/adapter/inbound/general/file/controller/AppFileController.java, src/main/java/com/dreamteam/alter/adapter/inbound/general/file/controller/AppFileControllerSpec.java
파일 업로드(POST), 프리사인된 URL 조회(GET), 삭제(DELETE) 엔드포인트를 정의하는 컨트롤러 및 스펙 인터페이스 추가. OpenAPI 문서 및 권한 검증 포함.
파일 관리 유스케이스 구현
src/main/java/com/dreamteam/alter/application/file/usecase/AppUploadFile.java, src/main/java/com/dreamteam/alter/application/file/usecase/AppGetPresignedUrl.java, src/main/java/com/dreamteam/alter/application/file/usecase/AppDeleteFile.java
파일 업로드, 프리사인된 URL 생성, 파일 삭제 비즈니스 로직. 사용자 권한 확인 및 파일 조회 포함.
파일 관리 도메인 포트
src/main/java/com/dreamteam/alter/domain/file/port/inbound/AppUploadFileUseCase.java, src/main/java/com/dreamteam/alter/domain/file/port/inbound/AppGetPresignedUrlUseCase.java, src/main/java/com/dreamteam/alter/domain/file/port/inbound/AppDeleteFileUseCase.java
파일 관리 기능의 인바운드 포트 인터페이스 정의.
파일 관리 DTO 및 열거형
src/main/java/com/dreamteam/alter/adapter/inbound/general/file/dto/AppUploadFileResponseDto.java, src/main/java/com/dreamteam/alter/domain/file/type/FileTargetType.java
파일 업로드 응답 DTO 및 FileTargetType 열거형에 워크스페이스 관련 타입 추가.
AttachFiles 유스케이스 확장
src/main/java/com/dreamteam/alter/application/file/usecase/AttachFiles.java, src/main/java/com/dreamteam/alter/domain/file/port/inbound/AttachFilesUseCase.java
파일 타겟 타입 맵 기반 다중 파일 첨부 메서드 executeMap 추가. 워크스페이스 등록 시 복수 파일 타입 처리용.
워크스페이스 등록 REST 컨트롤러
src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceRequestController.java, src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceRequestControllerSpec.java
워크스페이스 신청서 작성(POST), 목록 조회(GET), 상세 조회(GET) 엔드포인트 정의.
워크스페이스 반려 이유 댓글 컨트롤러
src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceReasonCommentController.java, src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceReasonCommentControllerSpec.java
반려 이유 댓글 작성(POST) 및 조회(GET) 엔드포인트.
워크스페이스 등록 유스케이스
src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java, src/main/java/com/dreamteam/alter/application/workspace/usecase/GetWorkspaceRequestList.java, src/main/java/com/dreamteam/alter/application/workspace/usecase/GetWorkspaceRequest.java
신청서 생성, 사용자 목록 조회, 상세 조회 비즈니스 로직. 파일 첨부 및 조회 포함.
워크스페이스 댓글 유스케이스
src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceReasonComment.java, src/main/java/com/dreamteam/alter/application/workspace/usecase/GetWorkspaceReasonComments.java
댓글 생성 및 조회 비즈니스 로직. 권한 검증 및 데이터 존재 확인 포함.
워크스페이스 도메인 엔터티
src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequest.java, src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceReason.java, src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceReasonComment.java
JPA 엔터티: 신청서, 반려 이유, 댓글. 사용자 연관성, 감사 필드, 팩토리 메서드 포함.
워크스페이스 도메인 포트
src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/Create*.java, src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetWorkspace*.java, src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceRequest*.java, src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceReason*.java
워크스페이스 관리 인바운드/아웃바운드 포트 인터페이스 정의.
워크스페이스 도메인 열거형
src/main/java/com/dreamteam/alter/domain/workspace/type/WorkspaceRequestStatus.java, src/main/java/com/dreamteam/alter/domain/workspace/type/WorkspaceReasonStatus.java
신청서 상태(PENDING, ACTIVATED, REVOKED) 및 반려 이유 상태(APPROVE, REJECT) 열거형. 상태 설명 메서드 포함.
워크스페이스 요청 DTO
src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/CreateWorkspaceRequestDto.java, src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/WorkspaceRequestResponseDto.java, src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/WorkspaceRequestListResponseDto.java
신청서 생성 요청, 상세 응답, 목록 응답 DTO. 유효성 검증 및 OpenAPI 문서 포함.
워크스페이스 댓글 DTO
src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/CreateWorkspaceReasonCommentRequestDto.java, src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/WorkspaceReasonCommentResponseDto.java
댓글 생성 요청, 응답 DTO. 문자 길이 제약 및 팩토리 메서드 포함.
워크스페이스 리포지토리 인터페이스
src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/Workspace*.java
워크스페이스, 신청서, 반려 이유, 댓글 관련 리포지토리 포트 인터페이스.
워크스페이스 JPA 리포지토리
src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestJpaRepository.java, src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceReasonJpaRepository.java, src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceReasonCommentJpaRepository.java
Spring Data JPA 리포지토리 인터페이스.
워크스페이스 리포지토리 구현
src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestRepositoryImpl.java, src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestQueryRepositoryImpl.java, src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceReasonQueryRepositoryImpl.java, src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceReasonCommentRepositoryImpl.java, src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceReasonCommentQueryRepositoryImpl.java
JPA 및 QueryDSL 기반 리포지토리 구현. 저장, 조회, 조건부 쿼리 포함.
워크스페이스 읽기 전용 응답 모델
src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/readonly/WorkspaceRequestListResponse.java, src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/readonly/WorkspaceRequestResponse.java
쿼리 결과 매핑용 읽기 전용 DTO.
사용자 관리 리포지토리
src/main/java/com/dreamteam/alter/adapter/outbound/user/persistence/ManagerUserJpaRepository.java, src/main/java/com/dreamteam/alter/adapter/outbound/user/persistence/ManagerUserRepositoryImpl.java, src/main/java/com/dreamteam/alter/domain/user/port/outbound/ManagerUserRepository.java
매니저 사용자 저장소 인터페이스 및 구현.
관리자 워크스페이스 컨트롤러
src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/controller/AdminWorkspaceController.java
관리자용 워크스페이스 컨트롤러 기본 구조 (엔드포인트 미정의).

Sequence Diagram(s)

sequenceDiagram
    participant User as 사용자
    participant Controller as AppFileController
    participant UseCase as AppUploadFile
    participant Service as FileUploadService
    participant Repository as FileRepository
    participant DB as 데이터베이스

    User->>Controller: POST /app/files (파일, targetType, bucketType)
    Controller->>Controller: AppActionContext에서 Actor 조회
    Controller->>UseCase: execute(actor, file, targetType, bucketType)
    UseCase->>Service: upload(userId, file, targetType, bucketType)
    Service->>Repository: save(file)
    Repository->>DB: INSERT file 레코드
    DB-->>Repository: fileId 반환
    Repository-->>Service: 저장된 File
    Service-->>UseCase: fileId
    UseCase-->>Controller: AppUploadFileResponseDto(fileId)
    Controller-->>User: 200 OK {fileId}
Loading
sequenceDiagram
    participant User as 사용자
    participant Controller as UserWorkspaceRequestController
    participant UseCase as CreateWorkspaceRequest
    participant WSRepository as WorkspaceRequestRepository
    participant FileUseCase as AttachFiles
    participant FileRepository as FileRepository
    participant DB as 데이터베이스

    User->>Controller: POST /app/workspace-requests (CreateWorkspaceRequestDto)
    Controller->>Controller: AppActionContext에서 Actor 조회
    Controller->>UseCase: execute(actor, request)
    UseCase->>WSRepository: save(workspaceRequest)
    WSRepository->>DB: INSERT workspace_requests 레코드
    DB-->>WSRepository: workspaceRequestId
    WSRepository-->>UseCase: 저장된 WorkspaceRequest
    UseCase->>FileUseCase: executeMap(fileIdsMap, wsRequestId, userId)
    FileUseCase->>FileRepository: 파일 목록 조회 (fileIds)
    FileRepository->>DB: SELECT files WHERE id IN (fileIds)
    DB-->>FileRepository: File 목록
    FileRepository-->>FileUseCase: 파일 엔터티 목록
    FileUseCase->>DB: UPDATE files SET targetId, status
    DB-->>FileUseCase: 업데이트 완료
    FileUseCase-->>UseCase: 완료
    UseCase-->>Controller: void
    Controller-->>User: 200 OK (empty response)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #69: 이 PR의 파일 관리 기능(AppFileController, AppUploadFile, AppGetPresignedUrl, AppDeleteFile)이 S3 파일 관리 PR과 동일한 유스케이스 구현, DTO, 도메인 타입을 다룸.

Suggested reviewers

  • hodoon
  • ysw789
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 pull request의 주요 변경 사항을 명확하게 요약하고 있습니다. '업장 등록 신청 및 승인/반려 사유 댓글 구현'은 workspace 등록 신청 기능과 approval/rejection 사유 댓글 기능이라는 핵심 변경 사항을 직접적으로 설명합니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ALT-148

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 17

♻️ Duplicate comments (1)
src/main/java/com/dreamteam/alter/adapter/inbound/general/file/controller/AppFileController.java (1)

33-40: ⚠️ Potential issue | 🟠 Major

@Resourcefinal 필드 조합 문제가 반복됩니다.

UserWorkspaceController와 동일한 문제입니다. @Resource는 필드/세터 주입용이며 final 필드와 @RequiredArgsConstructor와 함께 사용할 수 없습니다.

♻️ 수정 제안
-    `@Resource`(name = "appUploadFile")
-    private final AppUploadFileUseCase appUploadFile;
+    private final AppUploadFileUseCase appUploadFile;

-    `@Resource`(name = "appGetPresignedUrl")
-    private final AppGetPresignedUrlUseCase appGetPresignedUrl;
+    private final AppGetPresignedUrlUseCase appGetPresignedUrl;

-    `@Resource`(name = "appDeleteFile")
-    private final AppDeleteFileUseCase appDeleteFile;
+    private final AppDeleteFileUseCase appDeleteFile;

생성자에서 @Qualifier 사용이 필요한 경우:

public AppFileController(
    `@Qualifier`("appUploadFile") AppUploadFileUseCase appUploadFile,
    `@Qualifier`("appGetPresignedUrl") AppGetPresignedUrlUseCase appGetPresignedUrl,
    `@Qualifier`("appDeleteFile") AppDeleteFileUseCase appDeleteFile
) {
    this.appUploadFile = appUploadFile;
    this.appGetPresignedUrl = appGetPresignedUrl;
    this.appDeleteFile = appDeleteFile;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/dreamteam/alter/adapter/inbound/general/file/controller/AppFileController.java`
around lines 33 - 40, The fields appUploadFile, appGetPresignedUrl, and
appDeleteFile in AppFileController are annotated with `@Resource` while declared
final, which conflicts with constructor-based injection; remove the `@Resource`
annotations from those fields and add a constructor for AppFileController that
accepts the three use-case parameters and assigns them to the final fields,
applying `@Qualifier`("appUploadFile"), `@Qualifier`("appGetPresignedUrl"), and
`@Qualifier`("appDeleteFile") to the corresponding constructor parameters to
preserve bean selection.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceController.java`:
- Around line 26-27: The field injection on UserWorkspaceController uses
`@Resource` on a final field createWorkspace which prevents Spring from injecting
the dependency; change to constructor injection by adding a constructor that
takes CreateWorkspaceUseCase (or annotate the constructor parameter with
`@Qualifier`("createWorkspace")) and assign it to the createWorkspace field, or
remove final and use a non-final setter with `@Resource`—prefer constructor
injection for the CreateWorkspaceUseCase dependency to ensure proper wiring.

In
`@src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceReasonCommentController.java`:
- Around line 34-38: In ManagerWorkspaceReasonCommentController, remove the
field-level `@Resource` annotations on the final fields
createWorkspaceReasonComment and getWorkspaceReasonComments because
`@RequiredArgsConstructor` already generates constructor injection; if you need to
bind specific bean names, replace `@Resource` with `@Qualifier` qualifiers on those
dependencies (either annotate the fields with `@Qualifier`("beanName") or annotate
the constructor parameters), keeping the fields final and relying on Lombok's
`@RequiredArgsConstructor` for constructor injection.

In
`@src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceReasonCommentControllerSpec.java`:
- Around line 26-30: 메서드 이름 createWorkspaceReason이 실제로는 "사유 코멘트"를 생성하므로
인터페이스/컨트롤러 및 관련 구현 및 테스트에서 메서드명을 createWorkspaceReasonComment로 변경하세요; 구체적으로
ManagerWorkspaceReasonCommentControllerSpec 및 해당 인터페이스의 메서드 선언
ResponseEntity<CommonApiResponse<Void>> createWorkspaceReason(...) 를 찾아 이름을
createWorkspaceReasonComment(...)로 바꾸고, 이 메서드를 호출하거나 오버라이드하는 모든 구현체, 단위/통합 테스트,
라우팅/리플렉션 참조들도 동일한 새 이름으로 업데이트하여 컴파일 오류가 없도록 하십시오.

In
`@src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/CreateWorkspaceReasonCommentRequestDto.java`:
- Around line 15-17: The comment field in CreateWorkspaceReasonCommentRequestDto
currently only has `@NotBlank` and needs a maximum-length validation to prevent
oversized input; add a `@Size`(max = N) annotation on the private String comment
field (choose N to match the domain/DB column limit) and ensure the
corresponding import for javax.validation.constraints.Size (or
jakarta.validation.constraints.Size) is present so validation triggers before
persistence.

In
`@src/main/java/com/dreamteam/alter/application/file/usecase/AppGetPresignedUrl.java`:
- Line 6: AppGetPresignedUrl currently imports the adapter DTO
FilePresignedUrlResponseDto from adapter.inbound.common.dto; change the use case
to return the domain record PresignedUrlResult instead of the adapter DTO by
removing the adapter DTO import and updating the AppGetPresignedUrl method
signature and return value to PresignedUrlResult (adjust any internal variables
like build/construct logic to produce PresignedUrlResult), and move mapping to
FilePresignedUrlResponseDto into the controller layer so controllers convert
PresignedUrlResult -> FilePresignedUrlResponseDto.

In
`@src/main/java/com/dreamteam/alter/application/file/usecase/AppUploadFile.java`:
- Around line 21-22: The field injection annotation `@Resource` on the final
FileUploadService fileUploadService conflicts with constructor injection
provided by Lombok's `@RequiredArgsConstructor`; remove the `@Resource` annotation
so Spring uses the generated constructor to inject FileUploadService (also
remove any unused import for `@Resource` if present) and keep the field final to
preserve constructor injection semantics in AppUploadFile.

In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspace.java`:
- Line 9: The application use-case CreateWorkspace currently imports and depends
on the adapter DTO CreateWorkspaceRequestDto; remove that dependency by
introducing a domain-level command interface (e.g., CreateWorkspaceCommand with
getters like getBrn(), getBizName(), getType(), etc.) in the domain workspace
port and change CreateWorkspace to accept that command instead of
CreateWorkspaceRequestDto; update the controller/adapters so their
CreateWorkspaceRequestDto implements the new CreateWorkspaceCommand, remove the
import of CreateWorkspaceRequestDto from CreateWorkspace.java, and wire the
command through the existing inbound port/handler to preserve behavior without
referencing adapter-layer DTOs.

In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceReasonComment.java`:
- Line 6: The CreateWorkspaceReasonComment use case currently depends on the
inbound adapter DTO CreateWorkspaceReasonCommentRequestDto, breaking layer
boundaries; replace that dependency by defining an application-layer command
(e.g., CreateWorkspaceReasonCommentCommand) in the application/usecase or
application/port package and change the CreateWorkspaceReasonComment class and
its method signature to accept that command instead of
CreateWorkspaceReasonCommentRequestDto; then update the inbound controller to
map CreateWorkspaceReasonCommentRequestDto ->
CreateWorkspaceReasonCommentCommand before calling the use case and remove the
import of CreateWorkspaceReasonCommentRequestDto from the application layer.

In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/GetWorkspaceReasonComments.java`:
- Line 8: The use case GetWorkspaceReasonComments currently imports and returns
the adapter DTO WorkspaceReasonCommentResponseDto which violates the hexagonal
boundary; change GetWorkspaceReasonComments to return domain entities or domain
DTOs (e.g., List<WorkspaceReasonComment> or a domain-specific DTO) instead of
WorkspaceReasonCommentResponseDto, remove the import of
com.dreamteam.alter.adapter.inbound.manager.workspace.dto.WorkspaceReasonCommentResponseDto
from GetWorkspaceReasonComments, and move the mapping to
WorkspaceReasonCommentResponseDto::from into the controller layer so the
controller maps the domain list to the adapter response DTO before returning the
HTTP response.

In
`@src/main/java/com/dreamteam/alter/domain/file/port/inbound/AppGetPresignedUrlUseCase.java`:
- Around line 3-7: The domain interface AppGetPresignedUrlUseCase currently
returns the adapter DTO FilePresignedUrlResponseDto which inverts hexagonal
dependencies; create a domain-level result type (e.g., PresignedUrlResult record
in domain.file.port.inbound) and change AppGetPresignedUrlUseCase.execute
signature to return PresignedUrlResult instead of FilePresignedUrlResponseDto,
then update the adapter/controller layer to map PresignedUrlResult ->
FilePresignedUrlResponseDto when exposing the API.

In
`@src/main/java/com/dreamteam/alter/domain/file/port/inbound/AppUploadFileUseCase.java`:
- Around line 3-11: The AppUploadFileUseCase interface currently depends on
infrastructure and adapter types
(org.springframework.web.multipart.MultipartFile and AppUploadFileResponseDto);
remove those imports from the domain contract and replace the method signature
to use pure-domain DTOs (e.g., introduce domain.port.inbound.FileUploadCommand
holding InputStream, originalFilename, contentType, size and FileUploadResult
holding fileId or metadata). Update AppUploadFileUseCase.execute to accept
FileUploadCommand and return FileUploadResult, then delegate conversion between
MultipartFile <-> FileUploadCommand and FileUploadResult <->
AppUploadFileResponseDto in the controller/adapter layer.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceReason.java`:
- Around line 61-66: The factory method create(...) currently builds a
WorkspaceReason without validating invariants; update
WorkspaceReason.create(Workspace workspace, WorkspaceReasonStatus status, String
reason) to validate inputs (e.g., Objects.requireNonNull(workspace,
"workspace"), Objects.requireNonNull(status, "status") and ensure reason is
non-null/non-blank or trimmed) and throw a clear
RuntimeException/IllegalArgumentException when invalid, before calling
WorkspaceReason.builder().workspace(...).status(...).reason(...).build(); this
ensures the entity invariants are enforced at creation time.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceReasonComment.java`:
- Around line 5-23: The WorkspaceReasonComment domain class currently contains
Spring/JPA/Lombok infrastructure (annotations like `@Entity`, `@Table`, `@Id`,
`@GeneratedValue`, `@ManyToOne`, `@JoinColumn`, `@CreatedDate`, `@LastModifiedDate`,
`@EntityListeners` and Lombok annotations) and must be converted into a pure
domain model: remove all JPA/Spring/Lombok annotations and infrastructure
imports from WorkspaceReasonComment and keep only plain fields and business
logic; then create a separate persistence-side entity (e.g.,
WorkspaceReasonCommentEntity) in the infra/persistence layer that contains the
removed JPA annotations and mapping to related entities, and add mapping methods
(e.g., toEntity()/fromEntity() or a mapper class) to translate between
WorkspaceReasonComment and WorkspaceReasonCommentEntity so repositories use the
persistence entity while the domain layer remains framework-free.
- Around line 53-57: Validate invariants in WorkspaceReasonComment.create:
ensure the workspaceReason parameter is not null and the comment is not
null/blank (no only-whitespace) before building; if validation fails throw an
appropriate runtime exception (e.g., IllegalArgumentException or
NullPointerException) with a clear message. Update the create factory method in
class WorkspaceReasonComment to perform these checks (refer to method
WorkspaceReasonComment.create and fields workspaceReason and comment) and only
call the builder when inputs pass validation.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceReasonCommentUseCase.java`:
- Around line 3-7: The inbound port CreateWorkspaceReasonCommentUseCase
currently depends on the adapter DTO CreateWorkspaceReasonCommentRequestDto
which breaks layer boundaries; change the method signature of
CreateWorkspaceReasonCommentUseCase.execute(ManagerActor actor, Long
workspaceId, Long reasonId, CreateWorkspaceReasonCommentRequestDto request) to
accept a domain-level input model (e.g., CreateWorkspaceReasonCommentCommand or
CreateWorkspaceReasonCommentRequest in the domain package) instead of the
adapter DTO, keep ManagerActor/workspaceId/reasonId as needed, and move the
mapping from CreateWorkspaceReasonCommentRequestDto→domain model into the
inbound adapter so the domain package has zero infrastructure/adapter
dependencies. Ensure all callers and implementations (use case handler) are
updated to the new domain model.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceUseCase.java`:
- Line 3: The domain interface CreateWorkspaceUseCase currently imports and
depends on adapter DTO CreateWorkspaceRequestDto; remove this adapter-layer
dependency by introducing a domain-side command (e.g., CreateWorkspaceCommand)
or by changing the CreateWorkspaceUseCase method signature to accept explicit
primitive/domain types instead of CreateWorkspaceRequestDto; update
CreateWorkspaceUseCase (and any implementations) to use the new
CreateWorkspaceCommand (or parameter list) and move mapping from DTO→command
into the adapter layer so the domain package no longer references
CreateWorkspaceRequestDto.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetWorkspaceReasonCommentsUseCase.java`:
- Around line 5-9: GetWorkspaceReasonCommentsUseCase currently returns an
adapter DTO (WorkspaceReasonCommentResponseDto) which introduces an
infrastructure dependency into the domain port; change the port's execute
signature to return a domain/application model (e.g., a new or existing domain
type like WorkspaceReasonComment or WorkspaceReasonCommentModel) instead of
WorkspaceReasonCommentResponseDto, remove the import of
com.dreamteam.alter.adapter.inbound.manager.workspace.dto.WorkspaceReasonCommentResponseDto,
and keep the ManagerActor and execute(ManagerActor actor, Long workspaceId, Long
reasonId) parameters unchanged; then update the inbound adapter/controller that
implements this port to map from the domain model to
WorkspaceReasonCommentResponseDto before returning to the client.

---

Duplicate comments:
In
`@src/main/java/com/dreamteam/alter/adapter/inbound/general/file/controller/AppFileController.java`:
- Around line 33-40: The fields appUploadFile, appGetPresignedUrl, and
appDeleteFile in AppFileController are annotated with `@Resource` while declared
final, which conflicts with constructor-based injection; remove the `@Resource`
annotations from those fields and add a constructor for AppFileController that
accepts the three use-case parameters and assigns them to the final fields,
applying `@Qualifier`("appUploadFile"), `@Qualifier`("appGetPresignedUrl"), and
`@Qualifier`("appDeleteFile") to the corresponding constructor parameters to
preserve bean selection.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bdcdf009-7e1d-4e80-bcec-a830be5c9e35

📥 Commits

Reviewing files that changed from the base of the PR and between b61b237 and 8f7270f.

📒 Files selected for processing (41)
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/file/controller/AppFileController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/file/controller/AppFileControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/file/dto/AppUploadFileResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/CreateWorkspaceRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceReasonCommentController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceReasonCommentControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/CreateWorkspaceReasonCommentRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/WorkspaceReasonCommentResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/user/persistence/ManagerUserJpaRepository.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/user/persistence/ManagerUserRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceReasonCommentJpaRepository.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceReasonCommentQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceReasonCommentRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceReasonJpaRepository.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceReasonQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/application/file/usecase/AppDeleteFile.java
  • src/main/java/com/dreamteam/alter/application/file/usecase/AppGetPresignedUrl.java
  • src/main/java/com/dreamteam/alter/application/file/usecase/AppUploadFile.java
  • src/main/java/com/dreamteam/alter/application/file/usecase/AttachFiles.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspace.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceReasonComment.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/GetWorkspaceReasonComments.java
  • src/main/java/com/dreamteam/alter/domain/file/port/inbound/AppDeleteFileUseCase.java
  • src/main/java/com/dreamteam/alter/domain/file/port/inbound/AppGetPresignedUrlUseCase.java
  • src/main/java/com/dreamteam/alter/domain/file/port/inbound/AppUploadFileUseCase.java
  • src/main/java/com/dreamteam/alter/domain/file/port/inbound/AttachFilesUseCase.java
  • src/main/java/com/dreamteam/alter/domain/file/type/FileTargetType.java
  • src/main/java/com/dreamteam/alter/domain/user/port/outbound/ManagerUserRepository.java
  • src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceReason.java
  • src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceReasonComment.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceReasonCommentUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetWorkspaceReasonCommentsUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceReasonCommentQueryRepository.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceReasonCommentRepository.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceReasonQueryRepository.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceRepository.java
  • src/main/java/com/dreamteam/alter/domain/workspace/type/WorkspaceReasonStatus.java

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceReasonCommentController.java (1)

34-38: ⚠️ Potential issue | 🟠 Major

@Resource 필드 주입과 final + @RequiredArgsConstructor`` 혼용을 제거하세요.

현재 주입 방식이 혼재되어 의도와 동작이 불명확합니다. 생성자 주입으로 통일하는 편이 안전합니다.

🔧 권장 수정안
-import jakarta.annotation.Resource;
+import org.springframework.beans.factory.annotation.Qualifier;
@@
-	`@Resource`(name = "createWorkspaceReasonComment")
+	`@Qualifier`("createWorkspaceReasonComment")
 	private final CreateWorkspaceReasonCommentUseCase createWorkspaceReasonComment;
@@
-	`@Resource`(name = "getWorkspaceReasonComments")
+	`@Qualifier`("getWorkspaceReasonComments")
 	private final GetWorkspaceReasonCommentsUseCase getWorkspaceReasonComments;
#!/bin/bash
# 목적: final 필드에 `@Resource를` 적용한 혼용 패턴 탐지 및 현재 컨트롤러 상태 확인
rg -n -U --type java '@Resource\(name\s*=\s*"[^"]+"\)\s*\n\s*private final'
rg -n --type java 'class ManagerWorkspaceReasonCommentController|@RequiredArgsConstructor|@Resource|@Qualifier' -A4 -B4 src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceReasonCommentController.java
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceReasonCommentController.java`
around lines 34 - 38, ManagerWorkspaceReasonCommentController mixes field
`@Resource` injection with final fields and constructor-based
`@RequiredArgsConstructor`; unify to constructor injection: remove the
`@Resource`(name = "...") annotations from the final fields
CreateWorkspaceReasonCommentUseCase createWorkspaceReasonComment and
GetWorkspaceReasonCommentsUseCase getWorkspaceReasonComments, keep them as final
fields, ensure the class is annotated with Lombok's `@RequiredArgsConstructor` (or
add it if missing) so Spring will use constructor injection, and if you need
specific bean names keep the bean selection via `@Qualifier` on the constructor
parameters rather than `@Resource` on fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceReasonCommentController.java`:
- Around line 34-38: ManagerWorkspaceReasonCommentController mixes field
`@Resource` injection with final fields and constructor-based
`@RequiredArgsConstructor`; unify to constructor injection: remove the
`@Resource`(name = "...") annotations from the final fields
CreateWorkspaceReasonCommentUseCase createWorkspaceReasonComment and
GetWorkspaceReasonCommentsUseCase getWorkspaceReasonComments, keep them as final
fields, ensure the class is annotated with Lombok's `@RequiredArgsConstructor` (or
add it if missing) so Spring will use constructor injection, and if you need
specific bean names keep the bean selection via `@Qualifier` on the constructor
parameters rather than `@Resource` on fields.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a3831959-4a95-499e-bfa1-717c73fc7dd1

📥 Commits

Reviewing files that changed from the base of the PR and between 8f7270f and 0467a46.

📒 Files selected for processing (2)
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceReasonCommentController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceReasonCommentControllerSpec.java

Copy link
Copy Markdown
Contributor

@ysw789 ysw789 left a comment

Choose a reason for hiding this comment

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

  • 현재 댓글 작성/조회 API가 매니저 전용(/manager/..., ManagerActor)으로만 구현되어 있는데, 일반 사용자도 자기 신청 건에 대해 댓글을 작성/조회할 수 있어야 합니다. 일반 사용자용 API도 파주세요~ 만약 같은 UseCase를 참조해도 되는 경우면 전에 얘기했듯이 헥사고날 아키텍처 구체화해서 command dto로 인자 주고받도록 구성해도 괜찮을 듯 해요
  • 관리자(ADMIN)이 신청 상태를 바꾸고 댓글을 작성/조회하는 API도 필요할 것 같습니다. 등록 신청 최종 승인자는 ADMIN입니다
  • 업장 등록 신청이 승인 될 경우 User.role을 ROLE_MANAGER로 변경해야 하는데, 만일 사용자가 이미 ROLE_MANAGER인 경우에 대한 조건 처리도 포함해주세요 (다른 업장을 이미 등록한 상태라면 매니저임)

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/CreateWorkspaceReasonCommentRequestDto.java`:
- Around line 14-20: CreateWorkspaceReasonCommentRequestDto is leaking into the
domain port CreateWorkspaceReasonCommentUseCase; define a separate
application-level command/port model (e.g., CreateWorkspaceReasonCommentCommand)
in the application/usecase package, change the use case signature to accept that
command, and update the controller/adapter to map from
CreateWorkspaceReasonCommentRequestDto -> CreateWorkspaceReasonCommentCommand
before calling CreateWorkspaceReasonCommentUseCase; keep adapter DTOs only in
the adapter layer and ensure no adapter types are referenced by
domain/application interfaces.

In
`@src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/WorkspaceReasonCommentResponseDto.java`:
- Around line 30-35: The static factory method
WorkspaceReasonCommentResponseDto.from(WorkspaceReasonComment entity) creates a
direct dependency on the domain entity; change it to accept raw values or a
port-specific response model (e.g., id, comment, createdAt or a
WorkspaceReasonCommentPortResponse) instead of WorkspaceReasonComment, update
the method signature and its callers to map the entity -> DTO at the adapter
boundary (where the domain is visible) by extracting entity.getId(),
entity.getComment(), entity.getCreatedAt() there, and then pass those
primitives/port model into WorkspaceReasonCommentResponseDto's
factory/constructor to remove the domain-entity reference from the DTO class.
🪄 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: 4517d15d-4df1-42b6-a2bb-80a286a9f57f

📥 Commits

Reviewing files that changed from the base of the PR and between 0467a46 and fe16fab.

📒 Files selected for processing (2)
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/CreateWorkspaceReasonCommentRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/WorkspaceReasonCommentResponseDto.java

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 14

♻️ Duplicate comments (6)
src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/WorkspaceReasonCommentResponseDto.java (1)

30-36: 🛠️ Refactor suggestion | 🟠 Major

어댑터 DTO가 도메인 엔티티에 직접 의존하고 있습니다.

from(WorkspaceReasonComment entity) 팩토리 메서드는 DTO가 도메인 엔티티 구조를 직접 알게 만들어 계층 결합을 증가시킵니다. DTO 팩토리는 원시 값만 받도록 변경하고, 엔티티 → DTO 매핑은 어댑터 경계(컨트롤러 또는 유스케이스 구현체)에서 수행하는 것이 좋습니다.

♻️ 권장 수정안
-import com.dreamteam.alter.domain.workspace.entity.WorkspaceReasonComment;
-
-public static WorkspaceReasonCommentResponseDto from(WorkspaceReasonComment entity) {
-	return new WorkspaceReasonCommentResponseDto(
-		entity.getId(),
-		entity.getComment(),
-		entity.getCreatedAt()
-	);
-}
+public static WorkspaceReasonCommentResponseDto of(Long id, String comment, LocalDateTime createdAt) {
+	return new WorkspaceReasonCommentResponseDto(id, comment, createdAt);
+}

As per coding guidelines, src/main/java/com/dreamteam/alter/adapter/**: "DTOs are properly separated from domain entities."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/WorkspaceReasonCommentResponseDto.java`
around lines 30 - 36, The from(WorkspaceReasonComment entity) factory in
WorkspaceReasonCommentResponseDto creates a direct dependency on the domain
entity; change the factory signature to accept raw values (e.g., id, comment,
createdAt) instead of WorkspaceReasonComment, update
WorkspaceReasonCommentResponseDto.create/from to use those primitives, and
remove any import/usage of WorkspaceReasonComment from the DTO class; then
update adapter boundary code (controller or use-case implementations) to perform
the entity→DTO mapping there by extracting entity.getId(), entity.getComment(),
entity.getCreatedAt() and passing them into WorkspaceReasonCommentResponseDto's
new factory/constructor.
src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceReasonCommentUseCase.java (1)

3-7: ⚠️ Potential issue | 🟠 Major

도메인 인바운드 포트가 어댑터 DTO에 의존하고 있습니다.

CreateWorkspaceReasonCommentUseCase가 어댑터 DTO(CreateWorkspaceReasonCommentRequestDto)를 직접 받으면 계층 경계가 깨집니다. 포트 입력 모델은 도메인(또는 애플리케이션) 계층 타입으로 분리하세요.

♻️ 권장 수정안
 package com.dreamteam.alter.domain.workspace.port.inbound;
 
-import com.dreamteam.alter.adapter.inbound.manager.workspace.dto.CreateWorkspaceReasonCommentRequestDto;
+import com.dreamteam.alter.domain.workspace.command.CreateWorkspaceReasonCommentCommand;
 import com.dreamteam.alter.domain.user.context.AppActor;
 
 public interface CreateWorkspaceReasonCommentUseCase {
-    void execute(AppActor actor, Long workspaceRequestId, Long reasonId, CreateWorkspaceReasonCommentRequestDto request);
+    void execute(AppActor actor, Long workspaceRequestId, Long reasonId, CreateWorkspaceReasonCommentCommand command);
 }

As per coding guidelines, src/main/java/com/dreamteam/alter/domain/**: "ZERO infrastructure dependencies" and "Port interfaces (inbound/outbound) are clean contracts with no implementation details."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceReasonCommentUseCase.java`
around lines 3 - 7, The inbound port CreateWorkspaceReasonCommentUseCase
currently depends on an adapter DTO (CreateWorkspaceReasonCommentRequestDto)
which breaks the domain layer boundary; change the execute signature to accept a
domain-level input model (e.g., CreateWorkspaceReasonCommentCommand or
CreateWorkspaceReasonCommentInput) instead of the adapter DTO while keeping
AppActor, workspaceRequestId and reasonId parameters; create that domain model
in the domain package with the necessary fields, update any service/handler
implementations of CreateWorkspaceReasonCommentUseCase to consume the new domain
model, and update the adapter/controller layer to map from
CreateWorkspaceReasonCommentRequestDto to the new domain model before calling
CreateWorkspaceReasonCommentUseCase.execute.
src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceRequestUseCase.java (1)

3-7: ⚠️ Potential issue | 🟠 Major

도메인 레이어에서 어댑터 DTO를 참조하고 있습니다.

CreateWorkspaceRequestDto는 어댑터 레이어(adapter.inbound.general.workspace.dto)에 위치한 DTO입니다. 도메인 포트 인터페이스는 어댑터 레이어에 의존하면 안 됩니다.

도메인 레이어에 커맨드 객체(예: CreateWorkspaceRequestCommand)를 정의하고, 어댑터에서 DTO → 커맨드 변환을 수행하세요.

♻️ 권장 수정안
 package com.dreamteam.alter.domain.workspace.port.inbound;
 
-import com.dreamteam.alter.adapter.inbound.general.workspace.dto.CreateWorkspaceRequestDto;
+import com.dreamteam.alter.domain.workspace.command.CreateWorkspaceRequestCommand;
 import com.dreamteam.alter.domain.user.context.AppActor;
 
 public interface CreateWorkspaceRequestUseCase {
-	void execute(AppActor actor, CreateWorkspaceRequestDto request);
+	void execute(AppActor actor, CreateWorkspaceRequestCommand command);
 }

As per coding guidelines, src/main/java/com/dreamteam/alter/domain/**: "ZERO infrastructure dependencies" and "Port interfaces (inbound/outbound) are clean contracts with no implementation details."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceRequestUseCase.java`
around lines 3 - 7, The domain port CreateWorkspaceRequestUseCase currently
depends on the adapter DTO CreateWorkspaceRequestDto; remove that dependency by
defining a domain-level command (e.g., CreateWorkspaceRequestCommand) in the
domain model and change the interface signature of
CreateWorkspaceRequestUseCase.execute to accept (AppActor actor,
CreateWorkspaceRequestCommand request) instead of the DTO; then update the
inbound adapter to perform DTO → CreateWorkspaceRequestCommand mapping before
calling CreateWorkspaceRequestUseCase.execute so the domain layer has zero
adapter dependencies.
src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetWorkspaceReasonCommentsUseCase.java (1)

5-9: ⚠️ Potential issue | 🟠 Major

도메인 인바운드 포트의 반환 타입이 어댑터 DTO입니다.

GetWorkspaceReasonCommentsUseCase가 어댑터 DTO(WorkspaceReasonCommentResponseDto)를 반환하면 도메인 계층이 어댑터 계층에 종속됩니다. 포트 반환 타입은 도메인/애플리케이션 계층 타입으로 분리하고, DTO 매핑은 컨트롤러(어댑터)에서 수행하세요.

♻️ 권장 수정안
 package com.dreamteam.alter.domain.workspace.port.inbound;
 
 import java.util.List;
 
-import com.dreamteam.alter.adapter.inbound.general.workspace.dto.WorkspaceReasonCommentResponseDto;
+import com.dreamteam.alter.domain.workspace.port.inbound.result.WorkspaceReasonCommentResult;
 import com.dreamteam.alter.domain.user.context.AppActor;
 
 public interface GetWorkspaceReasonCommentsUseCase {
-	List<WorkspaceReasonCommentResponseDto> execute(AppActor actor, Long workspaceRequestId, Long reasonId);
+	List<WorkspaceReasonCommentResult> execute(AppActor actor, Long workspaceRequestId, Long reasonId);
 }

As per coding guidelines, src/main/java/com/dreamteam/alter/domain/**: "ZERO infrastructure dependencies" and "Port interfaces (inbound/outbound) are clean contracts with no implementation details."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetWorkspaceReasonCommentsUseCase.java`
around lines 5 - 9, GetWorkspaceReasonCommentsUseCase currently returns an
adapter DTO (WorkspaceReasonCommentResponseDto) which couples the domain port to
the adapter layer; change the port signature of the execute(AppActor actor, Long
workspaceRequestId, Long reasonId) method to return a domain/application-level
type (e.g., a new domain DTO or domain model like WorkspaceReasonComment or
WorkspaceReasonCommentDto placed under the domain package) instead of
WorkspaceReasonCommentResponseDto, update all inbound adapters/controllers to
map that domain type to WorkspaceReasonCommentResponseDto at the
controller/adapter boundary, and adjust implementing classes to return the new
domain type.
src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java (1)

9-28: ⚠️ Potential issue | 🟠 Major

애플리케이션 레이어가 어댑터 DTO에 직접 의존하고 있습니다.

CreateWorkspaceRequestDto를 유스케이스 시그니처에서 직접 받으면 application 계층이 adapter 계층에 결합됩니다. 포트 커맨드(도메인/애플리케이션 모델)로 추상화하고, DTO 구현/매핑은 인바운드 어댑터에서 처리하세요.

As per coding guidelines "src/main/java/com/dreamteam/alter/application/**: Verify that No direct infrastructure dependencies".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java`
around lines 9 - 28, The CreateWorkspaceRequest application class currently
depends on the adapter DTO CreateWorkspaceRequestDto; change the use-case API to
accept an application/domain command (e.g., CreateWorkspaceRequestCommand or
WorkspaceRequestModel) instead of CreateWorkspaceRequestDto by updating the
CreateWorkspaceRequestUseCase signature and the
CreateWorkspaceRequest.execute(AppActor, ...) method to use that command; move
the mapping from CreateWorkspaceRequestDto -> domain/command into the inbound
adapter (controller/mapper) so the application layer only uses the new command
and domain types, leaving WorkspaceRequestRepository and attachFiles usage
unchanged inside the use case.
src/main/java/com/dreamteam/alter/application/workspace/usecase/GetWorkspaceRequestList.java (1)

8-26: ⚠️ Potential issue | 🟠 Major

유스케이스가 인바운드 DTO에 직접 의존하고 있습니다.

GetWorkspaceRequestListWorkspaceRequestListResponseDto를 직접 반환/매핑하면서 application 계층이 adapter 계층에 의존합니다. 유스케이스는 도메인/애플리케이션 모델을 반환하고, DTO 변환은 컨트롤러(인바운드 어댑터)로 이동해야 합니다.

As per coding guidelines "src/main/java/com/dreamteam/alter/application/**: Verify that No direct infrastructure dependencies".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/GetWorkspaceRequestList.java`
around lines 8 - 26, GetWorkspaceRequestList currently returns/constructs the
inbound adapter DTO WorkspaceRequestListResponseDto inside execute, creating an
application->adapter dependency; change execute in GetWorkspaceRequestList (and
the GetWorkspaceRequestListUseCase signature) to return an
application/domain-safe type (e.g., domain model or an application-layer DTO)
instead of WorkspaceRequestListResponseDto, keep using
workspaceRequestQueryRepository.getWorkspaceRequestList(actor.getUserId()) to
fetch domain objects, and remove the .map(WorkspaceRequestListResponseDto::of)
call; then move the mapping from domain/application objects to
WorkspaceRequestListResponseDto into the inbound adapter/controller that calls
the use case so only the controller depends on WorkspaceRequestListResponseDto.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/controller/AdminWorkspaceController.java`:
- Around line 8-12: Add the missing security and Swagger contract to the
AdminWorkspaceController: annotate the AdminWorkspaceController class with
`@PreAuthorize`("hasAnyRole('ADMIN')") and have it implement the ControllerSpec
interface so Swagger docs are generated; ensure necessary imports for
org.springframework.security.access.prepost.PreAuthorize and the ControllerSpec
interface are added and update the class declaration to "public class
AdminWorkspaceController implements ControllerSpec" with the annotation above
the class.

In
`@src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceReasonCommentControllerSpec.java`:
- Around line 26-30: The `@PathVariable` names are inconsistent between the spec
and the controller (createWorkspaceReasonComment uses workspaceId in the spec
but the controller/URL use workspaceRequestId), causing Swagger and runtime
binding errors; update the spec method signatures (createWorkspaceReasonComment
and the other method around lines 38-41) so their `@PathVariable` names exactly
match the controller URL template and parameter names (either rename workspaceId
-> workspaceRequestId in the spec or change the controller/URL to workspaceId)
so both the annotation value, parameter name, and URL template are identical for
each affected method.

In
`@src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceRequestRequestController.java`:
- Line 29: Rename the class UserWorkspaceRequestRequestController to
UserWorkspaceRequestController: update the class declaration (public class
UserWorkspaceRequestController implements UserWorkspaceRequestControllerSpec),
rename the Java file accordingly, and update all references/usages (dependency
injection, component scanning, imports, tests, and any beans) to the new class
name so compilation and wiring continue to work; ensure any constructors, logger
names or annotations that embed the old class name are adjusted to match the new
identifier.
- Around line 47-51: The getWorkspaces() method in
UserWorkspaceRequestRequestController implements the
UserWorkspaceRequestControllerSpec interface but is missing the `@Override`
annotation; add `@Override` above the public
ResponseEntity<CommonApiResponse<List<WorkspaceRequestListResponseDto>>>
getWorkspaces() method in the UserWorkspaceRequestRequestController class to
explicitly mark the implementation of the interface method (keep method
signature and behavior unchanged).
- Around line 31-35: The class UserWorkspaceRequestRequestController currently
mixes `@Resource` on final fields (CreateWorkspaceRequestUseCase,
GetWorkspaceRequestListUseCase) while using `@RequiredArgsConstructor`, which
conflicts; remove the field-level `@Resource` annotations and switch to
constructor injection with qualifiers by annotating the constructor parameters
(or the fields) using `@Qualifier`("createWorkspaceRequest") and
`@Qualifier`("getWorkspaceRequestList") so the generated `@RequiredArgsConstructor`
will receive the correct beans for CreateWorkspaceRequestUseCase and
GetWorkspaceRequestListUseCase.

In
`@src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/WorkspaceRequestListResponseDto.java`:
- Around line 25-43: Remove the request-validation annotations from the response
DTO and use OpenAPI schema required flags: in WorkspaceRequestListResponseDto,
replace `@NotNull/`@NotBlank on fields id, businessName, fullAddress, createdAt,
and status with `@Schema`(requiredMode = RequiredMode.REQUIRED) (or add
requiredMode to the existing `@Schema` on each field) so the OpenAPI docs mark
them required while keeping validation annotations out of response DTOs.

In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java`:
- Around line 45-51: The code silently overwrites duplicate file IDs when
populating fileMap before calling attachFiles.executeMap; update the
CreateWorkspaceRequest logic to detect duplicate IDs among
request.getWorkspaceCertFileId(), request.getWorkspaceOwnIdentityFileId(), and
request.getWorkspaceWarrantFileId() before calling attachFiles.executeMap, e.g.,
collect non-null IDs into a Set and if the Set size differs from the number of
non-null IDs throw/return a validation error (or reject the request) referencing
the offending fields, then only build fileMap and call
attachFiles.executeMap(savedWorkspaceRequestId.toString(), actor.getUserId())
when duplicates are absent.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequest.java`:
- Around line 90-116: The WorkspaceRequest.create factory does not validate
required fields or coordinate ranges, allowing invalid entities; update
WorkspaceRequest.create (and/or the WorkspaceRequest.builder() validation path)
to validate non-null/non-blank values for user, brn, bizName, contact, address
and ensure latitude is between -90 and 90 and longitude between -180 and 180,
throwing an IllegalArgumentException (or a domain-specific exception) when
invariants fail, and preserve setting status to WorkspaceRequestStatus.PENDING
only after validation passes.
- Around line 6-24: The WorkspaceRequest class is coupled to Spring/JPA via
imports and annotations (remove org.springframework.data.*,
jakarta.persistence.* imports and the `@Entity`, `@Table`, `@EntityListeners`,
`@CreatedDate`, `@LastModifiedDate` annotations) — convert WorkspaceRequest into a
pure domain model keeping only business fields and logic (e.g., id, status,
requester User reference as a domain type) and move all persistence concerns
into a new persistence adapter/entity (e.g., WorkspaceRequestEntity) in the
persistence layer that contains the JPA annotations and mapping to
WorkspaceRequest fields; implement explicit mapping functions or a mapper (e.g.,
WorkspaceRequest <-> WorkspaceRequestEntity) in the adapter so
creation/modification timestamps and enum mapping (WorkspaceRequestStatus) are
handled by the persistence entity/auditor rather than the domain class.
- Line 33: WorkspaceRequest currently contains JPA infrastructure and conflicts
with Workspace by mapping to the same "workspaces" table; remove all JPA
annotations (`@Entity`, `@Table`, `@Column`, `@JoinColumn`, `@ManyToOne`, `@CreatedDate`,
`@LastModifiedDate`, `@EntityListeners`, `@Id/`@GeneratedValue) from the
WorkspaceRequest domain class and move persistence-specific mappings into a new
persistence-mapped class (e.g., WorkspaceRequestEntity) in the persistence layer
that maps to table "workspace_requests"; ensure WorkspaceRequest remains a pure
domain DTO/value object and create a mapper between WorkspaceRequest and
WorkspaceRequestEntity, and in the new entity use its own id generation
strategy, correct FK column (e.g., user_id or manager_id as appropriate) and the
correct enum type (WorkspaceRequestStatus) to avoid collisions with Workspace.
- Around line 64-65: Remove all JPA and Spring infrastructure annotations from
the domain class WorkspaceRequest (e.g., remove `@Entity`, `@Column`, `@ManyToOne`,
`@CreatedDate`, `@LastModifiedDate`, `@EntityListeners`) so it becomes a pure POJO;
create a separate persistence mapping (e.g., WorkspaceRequestEntity or JPA
mapper) in the infra layer that reintroduces the JPA annotations and handles
relationships and auditing. For the fullAddress field, remove the length =
Integer.MAX_VALUE usage from the domain and instead define appropriate column
length or a CLOB/text mapping in the persistence class. Ensure
constructors/getters/setters remain on WorkspaceRequest and map between domain
and persistence representations in the infra mapping layer.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetWorkspaceRequestListUseCase.java`:
- Around line 5-9: The port GetWorkspaceRequestListUseCase currently returns the
adapter DTO WorkspaceRequestListResponseDto which couples the domain port to the
adapter layer; change the port signature of execute(AppActor actor) to return a
domain/application-level type (e.g., WorkspaceRequestList or
WorkspaceRequestListModel) defined in the domain package instead of
WorkspaceRequestListResponseDto, update all implementations of
GetWorkspaceRequestListUseCase to produce that domain type, and move the mapping
from the domain type to WorkspaceRequestListResponseDto into the
controller/adapter layer where the response is constructed.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceRequestQueryRepository.java`:
- Around line 5-10: The interface WorkspaceRequestQueryRepository must not
reference the adapter read-model WorkspaceRequestListResponse; change the
signature of getWorkspaceRequestList(Long userId) to return a domain-level type
(e.g., create or use a domain DTO such as WorkspaceRequestSummary or a domain
model in the domain package) and remove the import of
com.dreamteam.alter.adapter...WorkspaceRequestListResponse; then update the
outbound adapter to perform mapping from its WorkspaceRequestListResponse to the
new domain DTO when implementing
WorkspaceRequestQueryRepository.existsByIdAndUserId and getWorkspaceRequestList
so the domain port depends only on domain types.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/type/WorkspaceRequestStatus.java`:
- Around line 12-17: The describe() method currently recreates the mapping on
every call; change this by defining a private static final
Map<WorkspaceRequestStatus, String> (e.g., DESCRIPTIONS) initialized once with
WorkspaceRequestStatus.PENDING, REVOKED, ACTIVATED mappings, and update
describe() to simply return that constant (or an unmodifiable view) so the enum
no longer allocates a new Map on each invocation.

---

Duplicate comments:
In
`@src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/WorkspaceReasonCommentResponseDto.java`:
- Around line 30-36: The from(WorkspaceReasonComment entity) factory in
WorkspaceReasonCommentResponseDto creates a direct dependency on the domain
entity; change the factory signature to accept raw values (e.g., id, comment,
createdAt) instead of WorkspaceReasonComment, update
WorkspaceReasonCommentResponseDto.create/from to use those primitives, and
remove any import/usage of WorkspaceReasonComment from the DTO class; then
update adapter boundary code (controller or use-case implementations) to perform
the entity→DTO mapping there by extracting entity.getId(), entity.getComment(),
entity.getCreatedAt() and passing them into WorkspaceReasonCommentResponseDto's
new factory/constructor.

In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java`:
- Around line 9-28: The CreateWorkspaceRequest application class currently
depends on the adapter DTO CreateWorkspaceRequestDto; change the use-case API to
accept an application/domain command (e.g., CreateWorkspaceRequestCommand or
WorkspaceRequestModel) instead of CreateWorkspaceRequestDto by updating the
CreateWorkspaceRequestUseCase signature and the
CreateWorkspaceRequest.execute(AppActor, ...) method to use that command; move
the mapping from CreateWorkspaceRequestDto -> domain/command into the inbound
adapter (controller/mapper) so the application layer only uses the new command
and domain types, leaving WorkspaceRequestRepository and attachFiles usage
unchanged inside the use case.

In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/GetWorkspaceRequestList.java`:
- Around line 8-26: GetWorkspaceRequestList currently returns/constructs the
inbound adapter DTO WorkspaceRequestListResponseDto inside execute, creating an
application->adapter dependency; change execute in GetWorkspaceRequestList (and
the GetWorkspaceRequestListUseCase signature) to return an
application/domain-safe type (e.g., domain model or an application-layer DTO)
instead of WorkspaceRequestListResponseDto, keep using
workspaceRequestQueryRepository.getWorkspaceRequestList(actor.getUserId()) to
fetch domain objects, and remove the .map(WorkspaceRequestListResponseDto::of)
call; then move the mapping from domain/application objects to
WorkspaceRequestListResponseDto into the inbound adapter/controller that calls
the use case so only the controller depends on WorkspaceRequestListResponseDto.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceReasonCommentUseCase.java`:
- Around line 3-7: The inbound port CreateWorkspaceReasonCommentUseCase
currently depends on an adapter DTO (CreateWorkspaceReasonCommentRequestDto)
which breaks the domain layer boundary; change the execute signature to accept a
domain-level input model (e.g., CreateWorkspaceReasonCommentCommand or
CreateWorkspaceReasonCommentInput) instead of the adapter DTO while keeping
AppActor, workspaceRequestId and reasonId parameters; create that domain model
in the domain package with the necessary fields, update any service/handler
implementations of CreateWorkspaceReasonCommentUseCase to consume the new domain
model, and update the adapter/controller layer to map from
CreateWorkspaceReasonCommentRequestDto to the new domain model before calling
CreateWorkspaceReasonCommentUseCase.execute.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceRequestUseCase.java`:
- Around line 3-7: The domain port CreateWorkspaceRequestUseCase currently
depends on the adapter DTO CreateWorkspaceRequestDto; remove that dependency by
defining a domain-level command (e.g., CreateWorkspaceRequestCommand) in the
domain model and change the interface signature of
CreateWorkspaceRequestUseCase.execute to accept (AppActor actor,
CreateWorkspaceRequestCommand request) instead of the DTO; then update the
inbound adapter to perform DTO → CreateWorkspaceRequestCommand mapping before
calling CreateWorkspaceRequestUseCase.execute so the domain layer has zero
adapter dependencies.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetWorkspaceReasonCommentsUseCase.java`:
- Around line 5-9: GetWorkspaceReasonCommentsUseCase currently returns an
adapter DTO (WorkspaceReasonCommentResponseDto) which couples the domain port to
the adapter layer; change the port signature of the execute(AppActor actor, Long
workspaceRequestId, Long reasonId) method to return a domain/application-level
type (e.g., a new domain DTO or domain model like WorkspaceReasonComment or
WorkspaceReasonCommentDto placed under the domain package) instead of
WorkspaceReasonCommentResponseDto, update all inbound adapters/controllers to
map that domain type to WorkspaceReasonCommentResponseDto at the
controller/adapter boundary, and adjust implementing classes to return the new
domain type.
🪄 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: 506def3e-8c6f-4097-b058-04ab4f1ca969

📥 Commits

Reviewing files that changed from the base of the PR and between fe16fab and fed2dce.

📒 Files selected for processing (26)
  • src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/controller/AdminWorkspaceController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceReasonCommentController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceReasonCommentControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceRequestControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceRequestRequestController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/WorkspaceReasonCommentResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/WorkspaceRequestListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceReasonQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestJpaRepository.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/readonly/WorkspaceRequestListResponse.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceReasonComment.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/GetWorkspaceReasonComments.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/GetWorkspaceRequestList.java
  • src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceReason.java
  • src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequest.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceReasonCommentUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceRequestUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetWorkspaceReasonCommentsUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetWorkspaceRequestListUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceReasonQueryRepository.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceRequestQueryRepository.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceRequestRepository.java
  • src/main/java/com/dreamteam/alter/domain/workspace/type/WorkspaceRequestStatus.java

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceRequestController.java (1)

30-41: ⚠️ Potential issue | 🟡 Minor

빈 이름 지정 의도가 현재 생성자 주입에 보장되지 않습니다.

@RequiredArgsConstructor가 실제 주입 경로를 만들기 때문에, 필드의 @Resource(name = "...")는 생성자 파라미터 선택을 보장하지 않습니다. 지금은 구현체가 1개라 통과할 수 있어도 같은 인터페이스 빈이 추가되면 이름 기반 주입 의도와 다르게 동작할 수 있습니다. 빈 이름을 고정하려면 명시적 생성자 + @Qualifier로 옮기거나, 최소한 Lombok이 qualifier를 생성자 파라미터로 복사하도록 설정돼 있는지 확인해 주세요.

아래 스크립트로 (1) 각 UseCase 구현체 개수, (2) lombok.configcopyableAnnotations 설정, (3) 현재 컨트롤러 주입 선언을 확인해 주세요. 예상 결과는 구현체가 2개 이상이거나 qualifier 복사 설정이 없으면 현재 이름 기반 주입 의도가 보장되지 않는 것입니다.

#!/bin/bash
set -euo pipefail

echo "== UseCase implementations =="
for symbol in CreateWorkspaceRequestUseCase GetWorkspaceRequestListUseCase GetWorkspaceRequestUseCase; do
  echo "--- ${symbol} ---"
  rg -n --type=java "implements\\s+${symbol}\\b" src/main/java || true
  echo
done

echo "== lombok.config =="
fd -a '^lombok\.config$' . -x sh -c 'echo "--- {} ---"; cat "{}"; echo' || true

echo "== UserWorkspaceRequestController injection fields =="
sed -n '28,42p' src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceRequestController.java

As per coding guidelines "src/main/java/com/dreamteam/alter/adapter/**: Controllers use @Getter, @RequiredArgsConstructor (no @Setter)."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceRequestController.java`
around lines 30 - 41, The controller currently relies on Lombok's
`@RequiredArgsConstructor` while annotating fields with `@Resource`(name=...), which
does not guarantee the name-based injection is preserved; update
UserWorkspaceRequestController to use an explicit constructor with parameters
for CreateWorkspaceRequestUseCase, GetWorkspaceRequestListUseCase, and
GetWorkspaceRequestUseCase and annotate those constructor parameters with
`@Qualifier` (or `@Resource`) to bind the bean names (or alternatively ensure
lombok.config includes copyableAnnotations with javax.annotation.Resource so
Lombok copies the annotations to constructor parameters); change the field
declarations to final without `@Resource` and remove reliance on
`@RequiredArgsConstructor` if you add the explicit constructor, or if you keep
Lombok, confirm copyableAnnotations contains Resource so the qualifier is
actually applied to the generated constructor.
src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceRequestQueryRepository.java (1)

5-13: ⚠️ Potential issue | 🟠 Major

도메인 포트에서 adapter read-model을 직접 노출하지 마세요.

WorkspaceRequestQueryRepositoryWorkspaceRequestListResponse, WorkspaceRequestResponse를 그대로 반환해서 도메인 계층이 persistence adapter 구현에 결합됩니다. 포트 반환형은 domain/application 내부 조회 모델로 바꾸고, WorkspaceRequestQueryRepositoryImpl에서 adapter DTO를 그 타입으로 매핑하는 구조로 정리하는 편이 맞습니다. 지금 결합이 GetWorkspaceRequestWorkspaceRequestResponseDto까지 전파되고 있습니다.

As per coding guidelines "src/main/java/com/dreamteam/alter/domain/**: Verify that ZERO infrastructure dependencies (no Spring, no JPA annotations, no external libs). Port interfaces (inbound/outbound) are clean contracts with no implementation details."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceRequestQueryRepository.java`
around lines 5 - 13, The port WorkspaceRequestQueryRepository currently returns
adapter DTOs (WorkspaceRequestListResponse, WorkspaceRequestResponse) which
leaks persistence details into the domain; change the port method return types
of existsByIdAndUserId, getWorkspaceRequestList, and getWorkspaceRequest to
domain/application-level read models (create e.g. WorkspaceRequestSummary and
WorkspaceRequestDetail in the domain or application DTO package), remove imports
of the adapter DTOs from the port, and update callers (e.g. GetWorkspaceRequest
and WorkspaceRequestResponseDto uses) to consume the new domain read models;
implement mapping from adapter DTOs to the new domain read models inside
WorkspaceRequestQueryRepositoryImpl (map WorkspaceRequestListResponse ->
WorkspaceRequestSummary and WorkspaceRequestResponse -> WorkspaceRequestDetail)
so the domain layer has zero infrastructure dependencies.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestQueryRepositoryImpl.java`:
- Around line 57-78: The getWorkspaceRequest method is missing the
workspaceRequestId filter so it may return the wrong record; update the query in
WorkspaceRequestQueryRepositoryImpl (method getWorkspaceRequest, using
QWorkspaceRequest.workspaceRequest) to include a condition for
qWorkspaceRequest.id.eq(workspaceRequestId) combined with the existing
qWorkspaceRequest.user.id.eq(userId) (e.g., using
.where(qWorkspaceRequest.user.id.eq(userId).and(qWorkspaceRequest.id.eq(workspaceRequestId))))
so the result is filtered by both user and request ID.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetWorkspaceRequestUseCase.java`:
- Around line 3-7: GetWorkspaceRequestUseCase currently returns the API DTO
WorkspaceRequestResponseDto which leaks web-layer types into the
domain/application port; change the port signature in GetWorkspaceRequestUseCase
to return a pure domain/application result (e.g., a domain model or an
application-level DTO in the domain package such as WorkspaceRequest or
WorkspaceRequestResult) and remove the dependency on WorkspaceRequestResponseDto
and its import; then update the inbound adapter (e.g.,
UserWorkspaceRequestController) to map that domain result to
WorkspaceRequestResponseDto for the HTTP response, keeping AppActor as the input
parameter and ensuring only the controller knows about the API DTO conversion.

---

Duplicate comments:
In
`@src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceRequestController.java`:
- Around line 30-41: The controller currently relies on Lombok's
`@RequiredArgsConstructor` while annotating fields with `@Resource`(name=...), which
does not guarantee the name-based injection is preserved; update
UserWorkspaceRequestController to use an explicit constructor with parameters
for CreateWorkspaceRequestUseCase, GetWorkspaceRequestListUseCase, and
GetWorkspaceRequestUseCase and annotate those constructor parameters with
`@Qualifier` (or `@Resource`) to bind the bean names (or alternatively ensure
lombok.config includes copyableAnnotations with javax.annotation.Resource so
Lombok copies the annotations to constructor parameters); change the field
declarations to final without `@Resource` and remove reliance on
`@RequiredArgsConstructor` if you add the explicit constructor, or if you keep
Lombok, confirm copyableAnnotations contains Resource so the qualifier is
actually applied to the generated constructor.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceRequestQueryRepository.java`:
- Around line 5-13: The port WorkspaceRequestQueryRepository currently returns
adapter DTOs (WorkspaceRequestListResponse, WorkspaceRequestResponse) which
leaks persistence details into the domain; change the port method return types
of existsByIdAndUserId, getWorkspaceRequestList, and getWorkspaceRequest to
domain/application-level read models (create e.g. WorkspaceRequestSummary and
WorkspaceRequestDetail in the domain or application DTO package), remove imports
of the adapter DTOs from the port, and update callers (e.g. GetWorkspaceRequest
and WorkspaceRequestResponseDto uses) to consume the new domain read models;
implement mapping from adapter DTOs to the new domain read models inside
WorkspaceRequestQueryRepositoryImpl (map WorkspaceRequestListResponse ->
WorkspaceRequestSummary and WorkspaceRequestResponse -> WorkspaceRequestDetail)
so the domain layer has zero infrastructure dependencies.
🪄 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: 996e821a-91db-4896-b6de-47e7c19eba46

📥 Commits

Reviewing files that changed from the base of the PR and between fed2dce and ce19e8b.

📒 Files selected for processing (8)
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceRequestController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceRequestControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/WorkspaceRequestResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/readonly/WorkspaceRequestResponse.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/GetWorkspaceRequest.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetWorkspaceRequestUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceRequestQueryRepository.java

@juny0955 juny0955 marked this pull request as draft April 1, 2026 08:45
@juny0955 juny0955 marked this pull request as ready for review April 3, 2026 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants