Skip to content

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

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

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

Conversation

@juny0955
Copy link
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

coderabbitai bot commented Mar 21, 2026

Warning

Rate limit exceeded

@juny0955 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 23 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3fa3a75a-aae5-4571-8aa4-39a6e35b7fbc

📥 Commits

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

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

Walkthrough

앱 파일 업로드/사전서명 URL 조회/삭제, 워크스페이스 생성, 매니저용 워크스페이스 사유 댓글 CRUD 흐름이 추가되었습니다. 관련 DTO, 엔티티, 리포지토리, 인바운드/아웃바운드 포트 및 서비스(유스케이스)가 구현되었습니다.

Changes

Cohort / File(s) Summary
파일 관리 API 컨트롤러
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), presigned URL 조회(GET), 삭제(DELETE) 엔드포인트 및 Swagger 인터페이스 추가. Inbound use-case 의존성 주입.
파일 응답 DTO
src/main/java/com/dreamteam/alter/adapter/inbound/general/file/dto/AppUploadFileResponseDto.java
업로드 응답으로 fileId 반환하는 DTO 추가.
파일 유스케이스(앱)
src/main/java/com/dreamteam/alter/application/file/usecase/AppUploadFile.java, .../AppGetPresignedUrl.java, .../AppDeleteFile.java
업로드, presigned URL 생성, 삭제 서비스 구현(권한/존재 검증, 트랜잭션 설정).
AttachFiles 변경
src/main/java/com/dreamteam/alter/application/file/usecase/AttachFiles.java, src/main/java/com/dreamteam/alter/domain/file/port/inbound/AttachFilesUseCase.java
파일 검증 헬퍼 분리 및 Map 기반 다중 첨부 executeMap 추가(인터페이스와 구현).
파일 포트(인바운드)
src/main/java/com/dreamteam/alter/domain/file/port/inbound/AppUploadFileUseCase.java, AppGetPresignedUrlUseCase.java, AppDeleteFileUseCase.java
앱 스코프 파일 관련 인바운드 포트 추가.
파일 타입 확장
src/main/java/com/dreamteam/alter/domain/file/type/FileTargetType.java
워크스페이스 관련 파일 타깃: WORKSPACE_CERTIFICATE, WORKSPACE_OWN_IDENTITY, WORKSPACE_WARRANT 추가.
워크스페이스 생성 API
src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/controller/UserWorkspaceController.java, .../UserWorkspaceControllerSpec.java
앱 사용자를 위한 워크스페이스 생성 POST 엔드포인트 및 Swagger 인터페이스 추가.
워크스페이스 생성 DTO
src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/CreateWorkspaceRequestDto.java
사업자명·BRN·주소·좌표·타입·연락처·파일 ID 등 필드와 검증 어노테이션 포함한 요청 DTO 추가.
워크스페이스 유스케이스(앱)
src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspace.java
ManagerUser 및 Workspace 생성, 파일 첨부를 위한 흐름 구현. attachFiles.executeMap 호출로 파일 연결.
워크스페이스 관련 도메인 포트
src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceUseCase.java
워크스페이스 생성 인바운드 포트 추가.
매니저용 댓글 컨트롤러
src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceReasonCommentController.java, .../ManagerWorkspaceReasonCommentControllerSpec.java
매니저 권한 보호 하에 워크스페이스 사유 댓글 생성(POST) 및 조회(GET) 엔드포인트와 Swagger 인터페이스 추가.
댓글 DTO
src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/CreateWorkspaceReasonCommentRequestDto.java, .../WorkspaceReasonCommentResponseDto.java
댓글 생성 요청 DTO 및 엔티티 → 응답 DTO 변환 메서드 추가.
댓글 유스케이스
src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceReasonComment.java, .../GetWorkspaceReasonComments.java
워크스페이스 접근 검증, 이유(Reason) 존재 검증 후 댓글 생성 및 조회 로직 구현.
댓글 관련 도메인 포트
src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/CreateWorkspaceReasonCommentUseCase.java, .../GetWorkspaceReasonCommentsUseCase.java, src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceReasonCommentRepository.java, .../WorkspaceReasonCommentQueryRepository.java, .../WorkspaceReasonQueryRepository.java
댓글/이유 조회 및 저장을 위한 인바운드·아웃바운드 포트 추가.
워크스페이스 엔티티
src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceReason.java, .../WorkspaceReasonComment.java
워크스페이스 이유 및 댓글 JPA 엔티티 추가(감사 필드 포함, 팩토리 메서드 제공).
워크스페이스 리포지토리 구현
src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/...
JPA 리포지토리 및 QueryDSL 기반 쿼리 리포지토리 구현 추가(Reason, Comment 관련).
매니저 유저 저장소
src/main/java/com/dreamteam/alter/domain/user/port/outbound/ManagerUserRepository.java, src/main/java/com/dreamteam/alter/adapter/outbound/user/persistence/ManagerUserJpaRepository.java, .../ManagerUserRepositoryImpl.java
ManagerUser 저장을 위한 포트 및 JPA 구현 추가.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AppFileController
    participant AppUploadFile
    participant FileUploadService
    participant FileRepository
    Client->>AppFileController: POST /app/files (file, targetType, bucketType)
    AppFileController->>AppFileController: AppActionContext.getActor()
    AppFileController->>AppUploadFile: execute(actor, file, targetType, bucketType)
    AppUploadFile->>FileUploadService: upload(userId, targetType, bucketType, file)
    FileUploadService->>FileRepository: save metadata
    FileRepository-->>FileUploadService: fileId
    FileUploadService-->>AppUploadFile: fileId
    AppUploadFile-->>AppFileController: AppUploadFileResponseDto(fileId)
    AppFileController-->>Client: 200 OK (fileId)
Loading
sequenceDiagram
    participant Client
    participant UserWorkspaceController
    participant CreateWorkspace
    participant ManagerUserRepository
    participant WorkspaceRepository
    participant AttachFiles
    Client->>UserWorkspaceController: POST /app/workspaces (CreateWorkspaceRequestDto)
    UserWorkspaceController->>UserWorkspaceController: AppActionContext.getActor()
    UserWorkspaceController->>CreateWorkspace: execute(actor, request)
    CreateWorkspace->>ManagerUserRepository: save(managerUser)
    ManagerUserRepository-->>CreateWorkspace: saved ManagerUser
    CreateWorkspace->>WorkspaceRepository: save(workspace)
    WorkspaceRepository-->>CreateWorkspace: workspaceId
    CreateWorkspace->>AttachFiles: executeMap(fileIdsMap, workspaceId, userId)
    AttachFiles-->>CreateWorkspace: void
    CreateWorkspace-->>UserWorkspaceController: void
    UserWorkspaceController-->>Client: 200 OK
Loading
sequenceDiagram
    participant Client
    participant ManagerController
    participant CreateWorkspaceReasonComment
    participant WorkspaceQueryRepository
    participant WorkspaceReasonQueryRepository
    participant CommentRepository
    Client->>ManagerController: POST /manager/workspaces/{wId}/reasons/{rId}/comments (request)
    ManagerController->>ManagerController: ManagerActionContext.getActor()
    ManagerController->>CreateWorkspaceReasonComment: execute(actor, wId, rId, request)
    CreateWorkspaceReasonComment->>WorkspaceQueryRepository: existsByIdAndManagerUser(wId, managerUserId)
    WorkspaceQueryRepository-->>CreateWorkspaceReasonComment: boolean
    CreateWorkspaceReasonComment->>WorkspaceReasonQueryRepository: findByIdAndWorkspaceId(rId, wId)
    WorkspaceReasonQueryRepository-->>CreateWorkspaceReasonComment: WorkspaceReason?
    CreateWorkspaceReasonComment->>CommentRepository: save(comment)
    CommentRepository-->>CreateWorkspaceReasonComment: void
    CreateWorkspaceReasonComment-->>ManagerController: void
    ManagerController-->>Client: 200 OK
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

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 제목은 주요 변경사항을 정확하게 반영합니다. 업장 등록 신청 기능과 승인/반려 사유 댓글 구현이라는 두 가지 핵심 기능이 명확하게 요약되어 있습니다.

✏️ 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.

Tip

You can customize the tone of the review comments and chat replies.

Configure the tone_instructions setting to customize the tone of the review comments and chat replies. For example, you can set the tone to Act like a strict teacher, Act like a pirate and more.

Copy link

@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

@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
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인 경우에 대한 조건 처리도 포함해주세요 (다른 업장을 이미 등록한 상태라면 매니저임)

Comment on lines +20 to +22
private Long id;
private String comment;
private LocalDateTime createdAt;
Copy link
Contributor

Choose a reason for hiding this comment

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

필드별로도 api 스펙 명시해주세영

public class CreateWorkspaceReasonCommentRequestDto {

@Schema(description = "댓글 내용", example = "왜 반려죠")
@Max(255)
Copy link
Contributor

Choose a reason for hiding this comment

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

Max 는 정수값 제한에 사용되는 어노테이션이라 문자열 길이 제한하려면 Size 어노테이션으로 바꿔주세요

request.getTown(),
request.getLatitude(),
request.getLongitude()
);
Copy link
Contributor

Choose a reason for hiding this comment

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

업장 등록 신청 생성 시점에 ManagerUser, Worksapce를 생성하는 것 보단, ADMIN에 의한 최종 승인 시 ManagerUser로 전환하고 Workspace를 만드는 게 어떨까요?

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