Skip to content

feat: [alt-267] 업장 업종 관리 시스템 재설계 - #97

Merged
ysw789 merged 23 commits into
devfrom
feat/alt-267
Jul 24, 2026
Merged

feat: [alt-267] 업장 업종 관리 시스템 재설계#97
ysw789 merged 23 commits into
devfrom
feat/alt-267

Conversation

@ysw789

@ysw789 ysw789 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

변경사항

[BE] 업장 업종 관리 시스템 재설계

업종(業種)은 업장(Workspace) 등록 시 확정되는 속성인데, 기존에는 free-text로 저장되고 사실상 PostingKeyword(공고 키워드)가 그 역할을 대행하고 있었습니다. 업종을 업장의 마스터 FK로 재설계하고 PostingKeyword를 폐기합니다.

  • 업종(BusinessType) 마스터 테이블·엔티티 신설 및 기본 시드 추가 (Flyway V4)
  • 업장/업장 신청의 업종을 free-text에서 마스터 FK + 상세입력(businessTypeDetail)으로 전환, 기존 데이터 백필 (Flyway V5)
  • '기타' 업종 선택 시에만 상세 입력을 요구·저장 (관리자가 마스터 확충 필요성을 인지하도록)
  • 업장 등록 폼용 업종 목록 조회 API 추가 (app / manager)
  • 관리자 업종 관리 CRUD API 추가 (/admin/business-types, '기타'·사용중 업종 삭제 방지)
  • PostingKeyword 폐기 — 관련 코드 및 테이블(posting_keywords, posting_keyword_map) 제거 (Flyway V6)
  • 공고 응답에 업장 업종 노출 + 업종 기반 목록 필터(businessTypeIds) 및 filter-options facet 추가
  • fix: 공고 지원 조건 반전 버그 수정 (모집중(OPEN) 공고 지원이 차단되던 문제)

Breaking (프론트 협의 필요)

  • 업장 등록 요청 typebusinessTypeId + businessTypeDetail
  • 공고 등록/수정 요청 및 모든 공고 응답에서 keywords 제거
  • GET /manager/postings/available-keywords 제거

Summary by CodeRabbit

  • 새 기능
    • 관리자용 업종 관리 API(목록/생성/수정/삭제) 및 요청 화면 업종 목록 조회를 추가했습니다.
    • 공고 목록 필터에 업종 선택(다중 선택)을 추가했습니다.
  • 변경 사항
    • 업장·공고 응답에 업종과 ‘기타’ 상세 정보가 표시되도록 변경했습니다.
    • 공고 관련 키워드(응답/조회/관리) 기능이 제거되었습니다(키워드 포함 엔드포인트/필드 포함).
  • 개선
    • 모집 상태에 따른 지원 가능 여부 검증을 강화했습니다.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

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

BusinessType 엔터티와 관리자 CRUD API를 추가하고, workspace 업종을 FK 기반으로 전환했다. 공고 조회에 업종 필터를 추가했으며, 기존 posting 키워드 저장·조회·응답 기능을 제거하고 관련 응답 모델과 테스트를 갱신했다.

Changes

업종 도메인과 저장소

Layer / File(s) Summary
BusinessType 모델 및 영속성
src/main/java/.../domain/workspace/*, src/main/java/.../adapter/outbound/workspace/persistence/*, src/main/resources/db/migration/V4__create_business_types.sql
BusinessType 엔터티, 이름 중복 검사 저장소, 정렬된 전체 조회 및 참조 여부 조회를 추가했다.
Workspace 업종 이관
src/main/java/.../domain/workspace/entity/*, src/main/java/.../application/workspace/usecase/*, src/main/resources/db/migration/V5__migrate_workspace_business_type.sql
workspace와 workspace request가 BusinessType 연관과 businessTypeDetail을 사용하도록 변경하고 기존 문자열 데이터를 이관했다.

관리자 API와 응답

Layer / File(s) Summary
관리자 업종 CRUD
src/main/java/.../adapter/inbound/admin/workspace/*, src/main/java/.../application/workspace/usecase/Admin*BusinessType.java
ADMIN 전용 목록·생성·수정·삭제 API와 요청 검증, 중복·참조·삭제 제한 로직을 추가했다.
업종 목록 및 workspace 응답
src/main/java/.../adapter/inbound/general/workspace/*, src/main/java/.../adapter/inbound/manager/workspace/*, src/main/java/.../adapter/inbound/common/dto/BusinessTypeResponseDto.java
사용자와 매니저 workspace request 화면에서 업종 목록을 조회하며, workspace 응답에 업종 상세 값을 포함한다.

공고 기능 변경

Layer / File(s) Summary
업종 필터와 키워드 제거
src/main/java/.../adapter/inbound/general/posting/dto/*, src/main/java/.../adapter/outbound/posting/persistence/*, src/main/java/.../application/posting/usecase/*, src/main/java/.../domain/posting/entity/Posting.java
공고 필터에 businessTypeIds를 추가하고 BusinessType fetch join을 적용했다. posting 생성·수정·조회 응답에서 키워드 처리를 제거했다.
마이그레이션 및 테스트 갱신
src/main/resources/db/migration/V6__drop_posting_keyword_tables.sql, src/test/java/...
posting 키워드 테이블 제거 마이그레이션과 BusinessType, workspace 생성·승인·필터 관련 테스트를 추가·수정했다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant WorkspaceRequestController
  participant GetBusinessTypeList
  participant BusinessTypeQueryRepositoryImpl
  Client->>WorkspaceRequestController: GET /business-types
  WorkspaceRequestController->>GetBusinessTypeList: execute()
  GetBusinessTypeList->>BusinessTypeQueryRepositoryImpl: findAll()
  BusinessTypeQueryRepositoryImpl-->>GetBusinessTypeList: 정렬된 BusinessType 목록
  GetBusinessTypeList-->>WorkspaceRequestController: BusinessType 목록
  WorkspaceRequestController-->>Client: BusinessTypeResponseDto 목록
Loading

Suggested labels: FEAT

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.70% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 업장 업종 관리 시스템의 마스터 FK 전환, CRUD, 필터, 키워드 제거를 포괄하는 제목으로 변경 내용을 잘 요약합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/alt-267

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminCreateBusinessType.java`:
- Around line 22-30: Update AdminCreateBusinessType.execute to catch the
DataIntegrityViolationException raised by saving a duplicate BusinessType and
translate it to CustomException with ErrorCode.CONFLICT, preserving the existing
pre-check while ensuring concurrent duplicate inserts return 409 instead of 500.

In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java`:
- Around line 40-51: Move the “기타” 업종의 상세 입력 필수 검증 from the application-layer
resolveBusinessTypeDetail helper into the BusinessType domain model, preferably
through a method such as resolveDetail. Update CreateWorkspaceRequest.execute
and any related WorkspaceRequest.create flow to use the domain behavior,
preserving the existing exception behavior for missing required details and
allowing reuse by other use cases.

In `@src/main/java/com/dreamteam/alter/domain/workspace/entity/BusinessType.java`:
- Around line 13-34: BusinessType retains JPA and Spring infrastructure
annotations, violating the domain layer’s dependency boundary. Keep this PR
unchanged for this existing cross-cutting pattern; track separation of
BusinessType into a pure domain model and dedicated persistence entity as a
broader refactor rather than modifying this class now.

In
`@src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequest.java`:
- Around line 60-65: WorkspaceRequest.create(...) 내부에서도 BusinessType이 “기타”인 경우
businessTypeDetail이 필수라는 도메인 불변식을 검증하도록 수정하세요. CreateWorkspaceRequest에만 의존하지 말고,
BusinessType의 “기타” 판별과 상세값 검증을 팩토리 메서드에 포함해 다른 생성 경로에서도 동일한 규칙이 적용되게 하며, 기존의 유효한
생성 흐름은 유지하세요.

In `@src/main/resources/db/migration/V5__migrate_workspace_business_type.sql`:
- Around line 35-47: 분리 마이그레이션을 적용해 workspace_requests와 workspaces의 FK를 먼저 NOT
VALID로 추가하고, 별도 단계에서 VALIDATE CONSTRAINT 및 데이터 정합성 확인 후 NOT NULL을 설정하세요. 기존
business_type 컬럼 삭제는 구버전 애플리케이션이 참조하지 않도록 배포가 완료된 뒤 별도 contract 마이그레이션으로 이동하고,
현재 마이그레이션에서는 DROP COLUMN을 제거하세요.

In
`@src/test/java/com/dreamteam/alter/application/workspace/usecase/AdminDeleteBusinessTypeTests.java`:
- Around line 25-115: Organize the tests in AdminDeleteBusinessTypeTests into
`@Nested` classes with `@DisplayName`, separating the four exception scenarios from
the successful deletion scenario. Keep each existing test’s setup, assertions,
and behavior unchanged while placing failure cases under one clearly named group
and execute_성공 under a success group.

In
`@src/test/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequestTests.java`:
- Around line 166-241: Group the four BusinessType-related
tests—execute_존재하지않는업종_예외, execute_기타_상세없음_예외, execute_기타_상세있음_저장, and
execute_비기타_상세무시—inside a dedicated `@Nested` test class with a descriptive
`@DisplayName`. Preserve each test’s existing setup, assertions, and behavior.
🪄 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: ecd7bbce-b337-4283-95ec-a31840b0de94

📥 Commits

Reviewing files that changed from the base of the PR and between 333c799 and d070d70.

📒 Files selected for processing (81)
  • src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/controller/AdminBusinessTypeController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/controller/AdminBusinessTypeControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/dto/AdminBusinessTypeRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/dto/AdminBusinessTypeResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/dto/AdminWorkspaceRequestResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/common/dto/BusinessTypeResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/CreatePostingRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/ManagerPostingListWorkspaceResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingDetailResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingFilterOptionsResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingKeywordListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingListFilterDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingListWorkspaceResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingMapListResponseDto.java
  • 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/CreateWorkspaceRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/PostingDetailWorkspaceResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/WorkspaceRequestResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/controller/ManagerPostingController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/controller/ManagerPostingControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/dto/ManagerPostingDetailResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/dto/ManagerPostingListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/dto/UpdatePostingRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceRequestController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceRequestControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/ManagerWorkspaceListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/ManagerWorkspaceResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/PostingKeywordQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/PostingQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/readonly/ManagerPostingDetailResponse.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/readonly/ManagerPostingListResponse.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/readonly/PostingDetailResponse.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/readonly/PostingListResponse.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/BusinessTypeJpaRepository.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/BusinessTypeQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/BusinessTypeRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/readonly/ManagerWorkspaceListResponse.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/readonly/ManagerWorkspaceResponse.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/readonly/WorkspaceRequestResponse.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/CreatePosting.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/CreatePostingApplication.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/GetPostingFilterOptions.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/GetPostingKeywordList.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/ManagerUpdatePosting.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminCreateBusinessType.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminDeleteBusinessType.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminGetBusinessTypeList.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminUpdateBusinessType.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/GetBusinessTypeList.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/UpdateWorkspaceRequestStatus.java
  • src/main/java/com/dreamteam/alter/domain/posting/entity/Posting.java
  • src/main/java/com/dreamteam/alter/domain/posting/entity/PostingKeywordMap.java
  • src/main/java/com/dreamteam/alter/domain/posting/port/inbound/GetPostingKeywordListUseCase.java
  • src/main/java/com/dreamteam/alter/domain/posting/port/outbound/PostingKeywordQueryRepository.java
  • src/main/java/com/dreamteam/alter/domain/workspace/command/AdminCreateBusinessTypeCommand.java
  • src/main/java/com/dreamteam/alter/domain/workspace/command/AdminUpdateBusinessTypeCommand.java
  • src/main/java/com/dreamteam/alter/domain/workspace/entity/BusinessType.java
  • src/main/java/com/dreamteam/alter/domain/workspace/entity/Workspace.java
  • src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequest.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/AdminCreateBusinessTypeUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/AdminDeleteBusinessTypeUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/AdminGetBusinessTypeListUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/AdminUpdateBusinessTypeUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetBusinessTypeListUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/BusinessTypeQueryRepository.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/BusinessTypeRepository.java
  • src/main/resources/db/migration/V4__create_business_types.sql
  • src/main/resources/db/migration/V5__migrate_workspace_business_type.sql
  • src/main/resources/db/migration/V6__drop_posting_keyword_tables.sql
  • src/test/java/com/dreamteam/alter/application/posting/usecase/GetPostingFilterOptionsTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/AdminCreateBusinessTypeTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/AdminDeleteBusinessTypeTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/AdminUpdateBusinessTypeTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequestTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/UpdateWorkspaceRequestStatusTests.java
  • src/test/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequestTests.java
💤 Files with no reviewable changes (17)
  • src/main/java/com/dreamteam/alter/domain/posting/port/inbound/GetPostingKeywordListUseCase.java
  • src/main/java/com/dreamteam/alter/domain/posting/entity/PostingKeywordMap.java
  • src/main/java/com/dreamteam/alter/domain/posting/port/outbound/PostingKeywordQueryRepository.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/PostingKeywordQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingKeywordListResponseDto.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/GetPostingKeywordList.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/controller/ManagerPostingController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingDetailResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/dto/ManagerPostingListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/controller/ManagerPostingControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/CreatePostingRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/readonly/PostingDetailResponse.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingMapListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/dto/ManagerPostingDetailResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/dto/UpdatePostingRequestDto.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/ManagerUpdatePosting.java

Comment on lines +13 to +34
@Table(name = "business_types")
@Builder(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@EntityListeners(AuditingEntityListener.class)
public class PostingKeyword {
public class BusinessType {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;

@Column(name = "name", length = 128, nullable = false, unique = true)
@Column(name = "name", length = 64, nullable = false, unique = true)
private String name;

@Column(name = "description", length = 255, nullable = true)
private String description;

// '기타' 등 상세 입력을 요구하는 업종 식별 플래그. 시드로만 생성되며 관리자 CRUD로는 항상 false.
@Column(name = "requires_detail", nullable = false)
private boolean requiresDetail;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

도메인 엔티티에 JPA/Spring 어노테이션이 그대로 포함됨

@Entity, @Table, @Column, @GeneratedValue, @EntityListeners(AuditingEntityListener.class) 등은 인프라 의존성으로, 도메인 계층은 "ZERO infrastructure dependencies (no Spring, no JPA annotations, no external libs)"를 요구합니다. 다만 이는 이 PR에서 새로 도입된 문제가 아니라 기존 PostingKeyword 및 다른 도메인 엔티티들에서 이미 사용되던 패턴을 그대로 이전한 것으로 보입니다. 별도 영속성 엔티티(JPA)와 순수 도메인 모델을 분리하는 것은 코드베이스 전체에 걸친 대규모 리팩터가 필요해 이번 PR 범위에서 다루기는 어려워 보이나, 참고 차원에서 기록합니다.

As per path instructions, domain layer should have "ZERO infrastructure dependencies (no Spring, no JPA annotations, no external libs)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/dreamteam/alter/domain/workspace/entity/BusinessType.java`
around lines 13 - 34, BusinessType retains JPA and Spring infrastructure
annotations, violating the domain layer’s dependency boundary. Keep this PR
unchanged for this existing cross-cutting pattern; track separation of
BusinessType into a pure domain model and dedicated persistence entity as a
broader refactor rather than modifying this class now.

Source: Path instructions

Comment on lines +35 to +47
ALTER TABLE workspace_requests
ALTER COLUMN business_type_id SET NOT NULL,
ADD CONSTRAINT fk_workspace_requests_business_type
FOREIGN KEY (business_type_id) REFERENCES business_types (id);

ALTER TABLE workspaces
ALTER COLUMN business_type_id SET NOT NULL,
ADD CONSTRAINT fk_workspaces_business_type
FOREIGN KEY (business_type_id) REFERENCES business_types (id);

-- 구 free-text 컬럼 제거 (미일치분은 '기타' 상세로 보존됨)
ALTER TABLE workspace_requests DROP COLUMN business_type;
ALTER TABLE workspaces DROP COLUMN business_type;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔵 Trivial | 🏗️ Heavy lift

단일 마이그레이션에서 NOT NULL/FK/DROP COLUMN을 한꺼번에 수행 — 운영 환경 락 위험

Squawk 정적분석 결과 기준으로, SET NOT NULL(36/41행)과 FK 제약 추가(37-38/42-43행)는 각각 테이블 풀스캔과 SHARE ROW EXCLUSIVE 락을 유발하고, DROP COLUMN(46-47행)은 무중단 배포 중 구버전 앱 인스턴스가 여전히 business_type 컬럼을 참조할 경우 장애를 유발할 수 있습니다. 테이블 크기가 크다면 이 모든 작업이 하나의 마이그레이션에서 실행되어 서비스 다운타임으로 이어질 수 있습니다.

Postgres는 ADD COLUMN, SET NOT NULL, DROP COLUMN 모두 ACCESS EXCLUSIVE 락을 획득하며, FK/제약 추가는 기본적으로 테이블 스캔을 동반합니다. 안전한 expand/contract 패턴으로 분리하는 것을 권장합니다:

  • FK는 NOT VALID로 추가 후 별도 트랜잭션에서 VALIDATE CONSTRAINT 실행
  • DROP COLUMN은 애플리케이션이 새 컬럼만 사용하도록 배포를 완전히 마친 이후의 별도 마이그레이션으로 분리
🛡️ 제안: FK를 NOT VALID로 분리
 ALTER TABLE workspace_requests
     ALTER COLUMN business_type_id SET NOT NULL,
-    ADD CONSTRAINT fk_workspace_requests_business_type
-        FOREIGN KEY (business_type_id) REFERENCES business_types (id);
+    ADD CONSTRAINT fk_workspace_requests_business_type
+        FOREIGN KEY (business_type_id) REFERENCES business_types (id) NOT VALID;

+ALTER TABLE workspace_requests VALIDATE CONSTRAINT fk_workspace_requests_business_type;

테이블 규모와 트래픽 패턴에 따라 리스크 수준이 달라지므로, 실제 운영 배포 전 테이블 크기와 배포 방식(무중단 여부)을 재확인해보시길 권장합니다.

🧰 Tools
🪛 Squawk (2.59.0)

[warning] 36-36: Setting a column NOT NULL blocks reads while the table is scanned. Make the field nullable and use a CHECK constraint instead.

(adding-not-nullable-field)


[warning] 37-38: By default new constraints require a table scan and block writes to the table while that scan occurs. Use NOT VALID with a later VALIDATE CONSTRAINT call.

(constraint-missing-not-valid)


[warning] 37-38: Adding a foreign key constraint requires a table scan and a SHARE ROW EXCLUSIVE lock on both tables, which blocks writes to each table. Add NOT VALID to the constraint in one transaction and then VALIDATE the constraint in a separate transaction.

(adding-foreign-key-constraint)


[warning] 41-41: Setting a column NOT NULL blocks reads while the table is scanned. Make the field nullable and use a CHECK constraint instead.

(adding-not-nullable-field)


[warning] 42-43: By default new constraints require a table scan and block writes to the table while that scan occurs. Use NOT VALID with a later VALIDATE CONSTRAINT call.

(constraint-missing-not-valid)


[warning] 42-43: Adding a foreign key constraint requires a table scan and a SHARE ROW EXCLUSIVE lock on both tables, which blocks writes to each table. Add NOT VALID to the constraint in one transaction and then VALIDATE the constraint in a separate transaction.

(adding-foreign-key-constraint)


[warning] 46-46: Dropping a column may break existing clients.

(ban-drop-column)


[warning] 47-47: Dropping a column may break existing clients.

(ban-drop-column)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/db/migration/V5__migrate_workspace_business_type.sql`
around lines 35 - 47, 분리 마이그레이션을 적용해 workspace_requests와 workspaces의 FK를 먼저 NOT
VALID로 추가하고, 별도 단계에서 VALIDATE CONSTRAINT 및 데이터 정합성 확인 후 NOT NULL을 설정하세요. 기존
business_type 컬럼 삭제는 구버전 애플리케이션이 참조하지 않도록 배포가 완료된 뒤 별도 contract 마이그레이션으로 이동하고,
현재 마이그레이션에서는 DROP COLUMN을 제거하세요.

Source: Linters/SAST tools

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
src/test/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequestTests.java (1)

174-248: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

업종(BusinessType) 검증 테스트를 별도 @Nested 그룹으로 세분화하는 것을 권장합니다.

execute_존재하지않는업종_예외, execute_기타_상세없음_예외, execute_기타_상세있음_저장, execute_비기타_상세무시 4개는 모두 "업종 검증"이라는 공통 관심사를 다루지만 현재 ExecuteTests 최상위에 대표이미지 테스트들과 함께 나열되어 있습니다. 과거 리뷰에서 제안된 하위 @Nested 그룹화가 이번 커밋에서도 반영되지 않았습니다. As per path instructions, "@Nested classes group related tests with @DisplayName."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequestTests.java`
around lines 174 - 248, Create a dedicated `@Nested` class with an appropriate
`@DisplayName` inside ExecuteTests for BusinessType validation scenarios. Move
execute_존재하지않는업종_예외, execute_기타_상세없음_예외, execute_기타_상세있음_저장, and
execute_비기타_상세무시 into that group, keeping their setup and assertions unchanged.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In
`@src/test/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequestTests.java`:
- Around line 174-248: Create a dedicated `@Nested` class with an appropriate
`@DisplayName` inside ExecuteTests for BusinessType validation scenarios. Move
execute_존재하지않는업종_예외, execute_기타_상세없음_예외, execute_기타_상세있음_저장, and
execute_비기타_상세무시 into that group, keeping their setup and assertions unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e289cfbb-b2d6-47af-81fd-287a57039dc1

📥 Commits

Reviewing files that changed from the base of the PR and between d070d70 and c532c78.

📒 Files selected for processing (8)
  • .coderabbit.yaml
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java
  • src/main/java/com/dreamteam/alter/domain/workspace/entity/BusinessType.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/AdminCreateBusinessTypeTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/AdminDeleteBusinessTypeTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/AdminUpdateBusinessTypeTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequestTests.java
  • src/test/java/com/dreamteam/alter/domain/workspace/entity/BusinessTypeTests.java

@hodoon hodoon left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

자동 코드리뷰 (high effort, workflow) 결과입니다. 검증 통과 7건을 코드라인별로 남깁니다. 심각도: 🔴 correctness 1 · 🟡 조건부 1 · 🧹 cleanup 5.

return PostingDetailWorkspaceResponseDto.builder()
.id(workspace.getId())
.name(workspace.getBusinessName())
.businessType(workspace.getBusinessType().getName())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔴 N+1 / LazyInitializationException 위험 (correctness)

Workspace.businessType가 String 컬럼 → LAZY @ManyToOne으로 바뀌었는데, '내 지원내역' 읽기 경로만 fetch-join이 누락됐습니다.

  • PostingApplicationQueryRepositoryImpl.getUserPostingApplicationListWithCursorqPosting.workspace만 fetch-join하고 workspace.businessType는 안 함 (다른 PostingQueryRepositoryImpl 경로들은 .leftJoin(qWorkspace.businessType, ...).fetchJoin() 추가됨).
  • 여기서 getBusinessType().getName()이 lazy proxy를 건드려 row당 SELECT 1개 (N+1). 페이지 N개면 추가 쿼리 N개.
  • DTO가 Hibernate 세션 밖에서 매핑되면 LazyInitializationException → 500. 예전 plain 컬럼일 땐 불가능했던 케이스.

Fix: 이 조회 경로에도 businessType fetch-join 추가.

WHERE business_type_id IS NULL;

-- NOT NULL 제약 및 FK 설정
ALTER TABLE workspace_requests

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟡 Flyway 마이그레이션 중단 위험 (correctness, 조건부)

'기타' fallback backfill이 SELECT id FROM business_types WHERE requires_detail LIMIT 1 서브쿼리를 씁니다.

  • V4가 ON CONFLICT (name) DO NOTHING이라, 기존에 requires_detail=false인 '기타' 행이 이미 있으면 시드가 스킵됨.
  • 그 경우 이 서브쿼리가 NULL → 매칭 안 되는 free-text workspace의 business_type_id가 NULL로 남음 → 뒤의 ALTER COLUMN business_type_id SET NOT NULL이 abort → 앱 부팅 실패.

Fix: '기타' 행 존재 및 requires_detail=true 보장하거나 backfill을 방어적으로.


@Override
@DeleteMapping("/{id}")
public ResponseEntity<CommonApiResponse<Void>> deleteBusinessType(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🧹 Controller가 request 필드 추출 (cleanup)

request.getName()/getDescription()을 꺼내 Command를 조립합니다 (updateBusinessType, of()도 동일). CLAUDE.md 'Controller → UseCase 인자 전달 규칙' 위반 — @RequestBody DTO는 값 추출 없이 그대로 전달해야 합니다.

요청 필드 추가 시 UseCase만 고치면 되도록 DTO 통째로 넘기세요.


private final BusinessTypeQueryRepository businessTypeQueryRepository;

@Override

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🧹 UseCase 중복 (cleanup)

GetBusinessTypeList와 완전 동일합니다 (의존성 · body return businessTypeQueryRepository.findAll() · @Transactional(readOnly=true)). 목록 정렬/필터가 바뀌면(예: '기타' 숨김) 두 곳을 고쳐야 하고 admin/general 응답이 조용히 drift할 수 있음.


public static AdminBusinessTypeResponseDto from(BusinessType businessType) {
return AdminBusinessTypeResponseDto.builder()
.id(businessType.getId())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🧹 DTO 중복 (cleanup)

공통 BusinessTypeResponseDto와 동일 (id/name/description/requiresDetail + from(BusinessType)). 공통 DTO 재사용 가능. 지금 구조면 필드 추가/리네임 시 두 DTO를 같이 고쳐야 함.

void resolveDetail_비기타_null반환() {
// given
BusinessType businessType = businessType(false);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🧹 테스트 헬퍼 복붙 (cleanup)

businessType(boolean requiresDetail) reflection 헬퍼가 CreateWorkspaceRequestTests에도 그대로 복붙돼 있습니다. '기타' BusinessType 생성 방식이 바뀌면 두 헬퍼를 lock-step으로 고쳐야 함.

private final BusinessTypeQueryRepository businessTypeQueryRepository;

@Override
public void execute(Long id) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🧹 존재 쿼리 2회 (cleanup)

existsWorkspaceUsingBusinessType + existsWorkspaceRequestUsingBusinessType로 DB 왕복 2회. 'referenced-anywhere' 단일 쿼리로 합치면 이 경로 쿼리 수 절반.

ysw789 added 16 commits July 21, 2026 18:59
모집중(OPEN) 공고 지원이 오히려 차단되던 조건 반전 버그 수정. if (OPEN) throw -> if (!OPEN) throw.
# Conflicts:
#	src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingListWorkspaceResponseDto.java
'ZERO infrastructure dependencies (no JPA annotations)' 규칙이 실제 컨벤션과
불일치하여 매 PR마다 오탐을 생성했다. 도메인 엔티티 40개 전부가 JPA 매핑을
사용하고, CLAUDE.md 역시 Getter + private Builder + 정적 팩토리 패턴을 명시한다.

규칙을 실제 컨벤션(JPA 매핑 허용, Setter 금지, 불변식 캡슐화)으로 교체한다.
AdminCreate/Update/DeleteBusinessTypeTests 3종의 테스트를 execute 그룹으로 묶어
같은 폴더의 다른 유스케이스 테스트(CancelWorkspaceRequestTests 등)와 구조를 통일한다.

Mock/InjectMocks/ExtendWith는 외부 클래스에 유지하고 테스트 본문은 변경하지 않는다.
셋 다 flat 이었으므로 Delete 만 그룹화하면 오히려 일관성이 깨져 3종을 함께 처리한다.
'기타 업종이면 상세 입력 필수' 규칙은 requiresDetail 플래그를 소유한 BusinessType 의
불변식이므로, CreateWorkspaceRequest 의 private 헬퍼에서 BusinessType.resolveDetail()
로 옮긴다. 호출부가 1곳뿐이고 승인 시 copy 경로는 검증된 값을 그대로 전달하므로
동작은 동일하다.

테스트가 BusinessType 을 mock 으로 생성해 검증 규칙이 스텁아웃되던 문제도 함께
해소한다. businessType() 헬퍼를 실제 엔티티 생성으로 전환하여 업종 관련 테스트 4개가
유스케이스를 통해 실제 규칙을 검증하게 되고, 이미지 테스트 3개의 불필요한 스텁도
사라진다. BusinessTypeTests 도메인 단위테스트를 신설한다.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/com/dreamteam/alter/domain/workspace/entity/Workspace.java (1)

91-108: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

업종 상세 필수 입력 불변식을 도메인 엔티티 팩토리에도 캡슐화하여 일관되게 적용하세요.

WorkspaceRequest.create에서는 businessType.resolveDetail(...)을 통해 '기타' 업종에 대한 상세 입력 불변식을 캡슐화하여 잘 검증하고 있습니다. 하지만 Workspace.create에서는 인자로 받은 값을 검증 없이 그대로 빌더에 넘기고 있습니다. As per path instructions, 도메인 계층 엔티티는 비즈니스 규칙과 불변식을 스스로 캡슐화해야 합니다. 현재 구조상 검증된 요청 데이터가 유입되더라도, 엔티티 자신이 불변식을 보호하도록 팩토리 메서드 내부에서 resolveDetail을 사용해 방어하는 것이 안전합니다.

🛡️ 제안: 팩토리 메서드에 도메인 불변식 적용
     public static Workspace create(
         ManagerUser managerUser,
         String businessRegistrationNo,
         String businessName,
         BusinessType businessType,
-        String businessTypeDetail,
+        String rawBusinessTypeDetail,
         String contact,
         String description,
         WorkspaceStatus status,
         String fullAddress,
         String province,
         String district,
         String town,
         BigDecimal latitude,
         BigDecimal longitude
     ) {
         return Workspace.builder()
             .managerUser(managerUser)
             .businessRegistrationNo(businessRegistrationNo)
             .businessName(businessName)
             .businessType(businessType)
-            .businessTypeDetail(businessTypeDetail)
+            .businessTypeDetail(businessType.resolveDetail(rawBusinessTypeDetail))
             .contact(contact)
             .description(description)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/dreamteam/alter/domain/workspace/entity/Workspace.java`
around lines 91 - 108, Update the Workspace.create factory to apply
businessType.resolveDetail(...) to the incoming businessTypeDetail before
passing it to Workspace.builder(). Preserve the remaining builder mappings while
ensuring the entity factory itself enforces the required detail invariant,
including the “other” business type case.

Source: Path instructions

♻️ Duplicate comments (2)
src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminCreateBusinessType.java (1)

23-30: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

경쟁 조건(Race condition)으로 인한 중복 저장 예외 처리

이전 리뷰에서 지적된 바와 같이, existsByName() 확인 후 save()를 수행하는 구조는 동시 요청 시 TOCTOU(time-of-check to time-of-use) 경쟁 조건이 발생합니다. 두 요청이 동시에 검사를 통과하면 한 요청은 DB의 고유 제약 조건 위반으로 인해 500 에러를 발생시킬 수 있습니다.

이 클래스에서 DataIntegrityViolationException과 같은 스프링 프레임워크 예외를 직접 잡게 되면 아키텍처 원칙을 위반하게 됩니다. 대신 영속성 어댑터(BusinessTypeRepositoryImpl)에서 해당 예외를 잡아 도메인 예외(CustomException)로 변환하거나, GlobalExceptionHandler에서 DB 예외를 409(CONFLICT)로 매핑하는 방식으로 개선하는 것을 권장합니다.

As per path instructions: "No direct infrastructure dependencies (no Spring Data, no HTTP clients)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminCreateBusinessType.java`
around lines 23 - 30, Update the persistence boundary used by
AdminCreateBusinessType.execute so unique-name constraint violations are
translated into the existing CustomException with ErrorCode.CONFLICT, or map
them centrally in GlobalExceptionHandler to HTTP 409. Keep Spring Data
exceptions out of AdminCreateBusinessType and preserve the existing
duplicate-name behavior for both pre-check and concurrent-save cases.

Source: Path instructions

src/main/resources/db/migration/V5__migrate_workspace_business_type.sql (1)

37-49: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

대규모 테이블 마이그레이션 시 락(Lock) 및 다운타임 방지를 위해 마이그레이션을 분리하세요.

단일 마이그레이션 단계에서 SET NOT NULL, FOREIGN KEY 제약 조건 추가, DROP COLUMN을 동시에 수행하면 운영 환경의 테이블 크기와 트래픽에 따라 심각한 테이블 락(ACCESS EXCLUSIVE 및 SHARE ROW EXCLUSIVE)과 함께 긴 다운타임이 발생할 수 있습니다. 무중단 배포(Zero-downtime deployment)를 보장하기 위해 다음과 같이 단계적으로 분리하는 것이 안전합니다.

  • FK 제약 조건: NOT VALID 옵션으로 추가하여 락을 최소화하고, 별도의 마이그레이션(또는 배포 이후)에서 VALIDATE CONSTRAINT를 수행하세요.
  • DROP COLUMN: 구버전 애플리케이션의 배포 사이클이 모두 끝나고 완전히 새 버전으로 트래픽이 넘어간 다음 단계의 배포 주기 마이그레이션으로 분리하세요.
  • NOT NULL 제약: 데이터가 방대하다면 테이블 풀스캔이 발생하므로 주의가 필요하며, 필요한 경우 CHECK 제약 조건을 우선적으로 활용할 수 있습니다.
🛡️ 제안: 무중단 배포를 위한 마이그레이션 스크립트 분리
-ALTER TABLE workspace_requests
-    ALTER COLUMN business_type_id SET NOT NULL,
-    ADD CONSTRAINT fk_workspace_requests_business_type
-        FOREIGN KEY (business_type_id) REFERENCES business_types (id);
-
-ALTER TABLE workspaces
-    ALTER COLUMN business_type_id SET NOT NULL,
-    ADD CONSTRAINT fk_workspaces_business_type
-        FOREIGN KEY (business_type_id) REFERENCES business_types (id);
-
--- 구 free-text 컬럼 제거 (미일치분은 '기타' 상세로 보존됨)
-ALTER TABLE workspace_requests DROP COLUMN business_type;
-ALTER TABLE workspaces DROP COLUMN business_type;
+ALTER TABLE workspace_requests
+    ADD CONSTRAINT fk_workspace_requests_business_type
+        FOREIGN KEY (business_type_id) REFERENCES business_types (id) NOT VALID;
+
+ALTER TABLE workspaces
+    ADD CONSTRAINT fk_workspaces_business_type
+        FOREIGN KEY (business_type_id) REFERENCES business_types (id) NOT VALID;
+
+-- 이후 별도 마이그레이션 스크립트(V6 등)에서 진행할 항목 (배포 안전성 확보 후)
+-- ALTER TABLE workspace_requests VALIDATE CONSTRAINT fk_workspace_requests_business_type;
+-- ALTER TABLE workspaces VALIDATE CONSTRAINT fk_workspaces_business_type;
+-- ALTER TABLE workspace_requests ALTER COLUMN business_type_id SET NOT NULL;
+-- ALTER TABLE workspaces ALTER COLUMN business_type_id SET NOT NULL;
+-- ALTER TABLE workspace_requests DROP COLUMN business_type;
+-- ALTER TABLE workspaces DROP COLUMN business_type;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/db/migration/V5__migrate_workspace_business_type.sql`
around lines 37 - 49, Split the workspace_requests and workspaces constraint
changes from the legacy business_type column removal: add each foreign key as
NOT VALID, defer validation to a later migration with VALIDATE CONSTRAINT, and
avoid setting business_type_id NOT NULL in this large-table migration unless
implemented through the staged CHECK-then-NOT-NULL approach. Move both DROP
COLUMN business_type statements to a later migration after all older application
versions are retired.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/controller/AdminBusinessTypeController.java`:
- Around line 40-50: Update the final use-case fields in
AdminBusinessTypeController to remove the ignored `@Resource` annotations or
replace them with `@Qualifier` using the specified bean names when explicit bean
selection is required; preserve constructor injection through
`@RequiredArgsConstructor` and ensure each dependency resolves by the intended
type or qualifier.

In `@src/main/java/com/dreamteam/alter/domain/workspace/entity/BusinessType.java`:
- Around line 64-68: Update the validation and normalization logic in
BusinessType to remove the org.apache.commons.lang3.StringUtils dependency.
Replace StringUtils.isBlank with standard Java checks that handle null, empty,
and whitespace-only values, and replace StringUtils.trim with the equivalent
Java string operation while preserving the existing exception and returned-value
behavior.

In `@src/main/java/com/dreamteam/alter/domain/workspace/entity/Workspace.java`:
- Around line 39-44: 도메인 엔티티의 JPA 의존성을 제거하고 순수 Java 객체로 유지하세요.
src/main/java/com/dreamteam/alter/domain/workspace/entity/Workspace.java#L39-L44와
src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequest.java#L60-L65의
연관관계 및 컬럼 매핑을 어댑터 계층의 별도 JPA Entity로 이동하고, 두 계층 간 변환을 연결해 기존 영속화 동작을 보존하세요.

In
`@src/test/java/com/dreamteam/alter/application/posting/usecase/GetPostingFilterOptionsTests.java`:
- Around line 33-35: Rename the test method execute_업종포함 in
GetPostingFilterOptionsTests to follow the action_condition_expectedResult
convention, explicitly including the relevant condition and expected result
while preserving the test’s behavior.

---

Outside diff comments:
In `@src/main/java/com/dreamteam/alter/domain/workspace/entity/Workspace.java`:
- Around line 91-108: Update the Workspace.create factory to apply
businessType.resolveDetail(...) to the incoming businessTypeDetail before
passing it to Workspace.builder(). Preserve the remaining builder mappings while
ensuring the entity factory itself enforces the required detail invariant,
including the “other” business type case.

---

Duplicate comments:
In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminCreateBusinessType.java`:
- Around line 23-30: Update the persistence boundary used by
AdminCreateBusinessType.execute so unique-name constraint violations are
translated into the existing CustomException with ErrorCode.CONFLICT, or map
them centrally in GlobalExceptionHandler to HTTP 409. Keep Spring Data
exceptions out of AdminCreateBusinessType and preserve the existing
duplicate-name behavior for both pre-check and concurrent-save cases.

In `@src/main/resources/db/migration/V5__migrate_workspace_business_type.sql`:
- Around line 37-49: Split the workspace_requests and workspaces constraint
changes from the legacy business_type column removal: add each foreign key as
NOT VALID, defer validation to a later migration with VALIDATE CONSTRAINT, and
avoid setting business_type_id NOT NULL in this large-table migration unless
implemented through the staged CHECK-then-NOT-NULL approach. Move both DROP
COLUMN business_type statements to a later migration after all older application
versions are retired.
🪄 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: b51f7091-e701-434d-8c96-484af749e7bc

📥 Commits

Reviewing files that changed from the base of the PR and between e2a5516 and c66cd86.

📒 Files selected for processing (83)
  • .coderabbit.yaml
  • src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/controller/AdminBusinessTypeController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/controller/AdminBusinessTypeControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/dto/AdminBusinessTypeRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/admin/workspace/dto/AdminWorkspaceRequestResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/common/dto/BusinessTypeResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/CreatePostingRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/ManagerPostingListWorkspaceResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingDetailResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingFilterOptionsResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingKeywordListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingListFilterDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingListWorkspaceResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingMapListResponseDto.java
  • 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/CreateWorkspaceRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/PostingDetailWorkspaceResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/workspace/dto/WorkspaceRequestResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/controller/ManagerPostingController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/controller/ManagerPostingControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/dto/ManagerPostingDetailResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/dto/ManagerPostingListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/dto/UpdatePostingRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceRequestController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/controller/ManagerWorkspaceRequestControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/ManagerWorkspaceListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/workspace/dto/ManagerWorkspaceResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/PostingApplicationQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/PostingKeywordQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/PostingQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/readonly/ManagerPostingDetailResponse.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/readonly/ManagerPostingListResponse.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/readonly/PostingDetailResponse.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/readonly/PostingListResponse.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/BusinessTypeJpaRepository.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/BusinessTypeQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/BusinessTypeRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceRequestQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/readonly/ManagerWorkspaceListResponse.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/readonly/ManagerWorkspaceResponse.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/readonly/WorkspaceRequestResponse.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/CreatePosting.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/CreatePostingApplication.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/GetPostingFilterOptions.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/GetPostingKeywordList.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/ManagerUpdatePosting.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminCreateBusinessType.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminDeleteBusinessType.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminUpdateBusinessType.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequest.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/GetBusinessTypeList.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/UpdateWorkspaceRequestStatus.java
  • src/main/java/com/dreamteam/alter/domain/posting/entity/Posting.java
  • src/main/java/com/dreamteam/alter/domain/posting/entity/PostingKeyword.java
  • src/main/java/com/dreamteam/alter/domain/posting/entity/PostingKeywordMap.java
  • src/main/java/com/dreamteam/alter/domain/posting/port/inbound/GetPostingKeywordListUseCase.java
  • src/main/java/com/dreamteam/alter/domain/posting/port/outbound/PostingKeywordQueryRepository.java
  • src/main/java/com/dreamteam/alter/domain/workspace/command/AdminCreateBusinessTypeCommand.java
  • src/main/java/com/dreamteam/alter/domain/workspace/command/AdminUpdateBusinessTypeCommand.java
  • src/main/java/com/dreamteam/alter/domain/workspace/entity/BusinessType.java
  • src/main/java/com/dreamteam/alter/domain/workspace/entity/Workspace.java
  • src/main/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequest.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/AdminCreateBusinessTypeUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/AdminDeleteBusinessTypeUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/AdminUpdateBusinessTypeUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetBusinessTypeListUseCase.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/BusinessTypeQueryRepository.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/BusinessTypeRepository.java
  • src/main/resources/db/migration/V4__create_business_types.sql
  • src/main/resources/db/migration/V5__migrate_workspace_business_type.sql
  • src/main/resources/db/migration/V6__drop_posting_keyword_tables.sql
  • src/test/java/com/dreamteam/alter/application/posting/usecase/GetPostingFilterOptionsTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/AdminCreateBusinessTypeTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/AdminDeleteBusinessTypeTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/AdminUpdateBusinessTypeTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/CreateWorkspaceRequestTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/UpdateWorkspaceRequestStatusTests.java
  • src/test/java/com/dreamteam/alter/domain/workspace/entity/BusinessTypeFixture.java
  • src/test/java/com/dreamteam/alter/domain/workspace/entity/BusinessTypeTests.java
  • src/test/java/com/dreamteam/alter/domain/workspace/entity/WorkspaceRequestTests.java
💤 Files with no reviewable changes (18)
  • src/main/java/com/dreamteam/alter/domain/posting/port/outbound/PostingKeywordQueryRepository.java
  • src/main/java/com/dreamteam/alter/domain/posting/port/inbound/GetPostingKeywordListUseCase.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/GetPostingKeywordList.java
  • src/main/java/com/dreamteam/alter/domain/posting/entity/PostingKeyword.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/CreatePostingRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingListResponseDto.java
  • src/main/java/com/dreamteam/alter/domain/posting/entity/PostingKeywordMap.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingKeywordListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/PostingKeywordQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/controller/ManagerPostingController.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/controller/ManagerPostingControllerSpec.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingDetailResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/dto/UpdatePostingRequestDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/dto/ManagerPostingListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingMapListResponseDto.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/readonly/PostingDetailResponse.java
  • src/main/java/com/dreamteam/alter/adapter/inbound/manager/posting/dto/ManagerPostingDetailResponseDto.java
  • src/main/java/com/dreamteam/alter/application/posting/usecase/ManagerUpdatePosting.java

@hodoon hodoon left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

재검토 추가 코멘트 4건입니다. 이전 7건 중 6건은 잘 반영됐고, 아래는 남은 컨벤션 위반 1건 + 새로 발견한 경미 항목 3건입니다.

@Valid @RequestBody AdminBusinessTypeRequestDto request
) {
BusinessType created = adminCreateBusinessType.execute(
new AdminCreateBusinessTypeCommand(request.getName(), request.getDescription())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🧹 Controller가 request 필드 추출 (cleanup, 이전 리뷰 미반영)

request.getName()/getDescription()을 꺼내 Command를 조립하고 있습니다. CLAUDE.md 'Controller → UseCase 인자 전달 규칙' 위반 — @RequestBody DTO는 값 추출 없이 그대로 전달해야 합니다.

요청 필드가 추가돼도 UseCase만 고치면 되도록 DTO(또는 DTO→Command 매핑을 UseCase 안)로 넘겨주세요. 아래 updateBusinessType(L80)도 동일합니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

현재 new AdminCreateBusinessTypeCommand(request.getName(), request.getDescription()) 방식은 CLAUDE.md의 Command/Result 규칙(UseCase 경계에 *RequestDto를 넘기지 않고 도메인 Command만 전달)을 준수하는 형태입니다. AdminTermsController, ManagerSelfController 등 다수 컨트롤러도 동일하게 컨트롤러에서 inline으로 Command를 조립하고 있습니다.

DTO를 그대로 UseCase에 넘기면 오히려 이 규칙(어댑터 DTO의 UseCase 경계 유입 금지)을 위반하게 됩니다. 별도 정적 CommandMapper.toCommand() 패턴도 코드베이스에 2건뿐인 소수 패턴이라 이 엔드포인트엔 과하다고 판단해, 현행 inline Command 조립을 유지하겠습니다. updateBusinessType도 동일합니다.

@Valid @RequestBody AdminBusinessTypeRequestDto request
) {
adminUpdateBusinessType.execute(
id, new AdminUpdateBusinessTypeCommand(request.getName(), request.getDescription())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🧹 위 createBusinessType(L67)과 동일 — request 필드 추출 없이 DTO 그대로 전달하도록 정리 필요.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

createBusinessType 회신과 동일한 이유로, CLAUDE.md Command/Result 규칙 준수 및 기존 컨트롤러 컨벤션(AdminTermsController 등)에 맞춰 현행 inline Command 조립을 유지하겠습니다.

}

BusinessType businessType = BusinessType.create(command.name(), command.description());
return businessTypeRepository.save(businessType);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟡 동시 중복 생성 시 500 (correctness, 조건부)

existsByName 사전 체크 → save 구조인데, name에 UNIQUE 제약(V4)이 있어 사전 체크를 동시에 통과한 요청 2건이면 두 번째 saveDataIntegrityViolationException을 던져 409가 아닌 500이 됩니다.

관리자 전용 API라 실제 발생 확률은 낮지만, 엄밀히 하려면 save를 try-catch로 감싸 ErrorCode.CONFLICT로 변환하면 사전 체크와 경합 케이스가 일관되게 409를 반환합니다.

throw new CustomException(ErrorCode.CONFLICT, "이미 존재하는 업종입니다.");
}

businessType.update(command.name(), command.description());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟡 '기타' 업종 이름 변경 무방비 (design)

AdminDeleteBusinessTypeisRequiresDetail() 플래그로 '기타' 삭제를 막는데, update에는 가드가 없어 '기타'의 이름·설명을 자유롭게 바꿀 수 있습니다.

resolveDetail이 flag 기반이라 기능이 깨지진 않지만, 특수 업종인 '기타' 라벨 자체가 바뀌면 사용자 노출/운영에서 혼란이 생길 수 있습니다. 의도된 허용이 아니라면 delete와 동일하게 requiresDetail 업종의 이름 변경을 막는 가드를 두는 편이 안전합니다.

return town != null ? qWorkspace.town.eq(town) : null;
}

private BooleanExpression businessTypeIn(QWorkspace qWorkspace, java.util.List<Long> businessTypeIds) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🧹 인라인 FQN (trivial)

java.util.List<Long>을 import 없이 풀네임으로 사용하고 있습니다. 파일 내 다른 타입들은 import 방식이라 컨벤션 불일치 — import java.util.List;List<Long>로 정리하면 됩니다.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminCreateBusinessType.java`:
- Line 33: Update the DataIntegrityViolationException handling in
AdminCreateBusinessType to preserve the caught exception as the cause when
throwing CustomException. Use the existing cause-aware CustomException
constructor, or add one if unavailable, while keeping the current conflict error
code and message unchanged.
- Around line 30-34: Update AdminCreateBusinessType and the
BusinessTypeRepository port/adapter to flush immediately after saving, using
saveAndFlush or an explicit flush so unique-name violations are caught by the
existing DataIntegrityViolationException handler and converted to CONFLICT. Add
an integration test covering concurrent creation of the same business type name
and asserting the duplicate request returns 409.
- Line 3: Remove the Spring DAO dependency and direct
DataIntegrityViolationException handling from AdminCreateBusinessType. Translate
persistence constraint violations in the outbound adapter, such as
BusinessTypeRepositoryImpl, into the repository port’s dedicated exception, and
handle only that contract in the use case. Ensure the adapter flushes at the
appropriate point so commit-time violations are translated, and preserve the
original cause when constructing CustomException.
🪄 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: e0aa33d3-4ff9-442e-a341-6a1768593d17

📥 Commits

Reviewing files that changed from the base of the PR and between c66cd86 and 862e06c.

📒 Files selected for processing (12)
  • src/main/java/com/dreamteam/alter/adapter/outbound/posting/persistence/PostingQueryRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/BusinessTypeJpaRepository.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/BusinessTypeRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminCreateBusinessType.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminUpdateBusinessType.java
  • src/main/java/com/dreamteam/alter/domain/workspace/entity/BusinessType.java
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/BusinessTypeRepository.java
  • src/test/java/com/dreamteam/alter/adapter/inbound/general/posting/dto/PostingListWorkspaceResponseDtoTests.java
  • src/test/java/com/dreamteam/alter/application/posting/usecase/GetPostingFilterOptionsTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/AdminCreateBusinessTypeTests.java
  • src/test/java/com/dreamteam/alter/application/workspace/usecase/AdminUpdateBusinessTypeTests.java
  • src/test/java/com/dreamteam/alter/domain/workspace/entity/BusinessTypeTests.java
💤 Files with no reviewable changes (4)
  • src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/BusinessTypeRepository.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/BusinessTypeJpaRepository.java
  • src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/BusinessTypeRepositoryImpl.java
  • src/main/java/com/dreamteam/alter/application/workspace/usecase/AdminUpdateBusinessType.java

@ysw789
ysw789 merged commit a39f208 into dev Jul 24, 2026
3 checks passed
ysw789 added a commit that referenced this pull request Aug 3, 2026
V4·V5·V6가 업종(#97)과 채팅(#95)에서 각각 중복돼 Flyway가 기동 단계에서
실패했다. 채팅 계열을 V11~V14로 옮긴다. 네 파일은 스키마 생성 → 백필 → 인덱스
순서로 서로 의존하므로 상대 순서를 유지한 채 함께 이동한다.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants