-
Notifications
You must be signed in to change notification settings - Fork 0
feat: [alt-267] 업종 키워드 관련 기능 고도화 및 지원조건 버그 수정 #96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
1e4586a
feat: [alt-267] 업종 마스터 관리자 CRUD 및 초기 시드 추가
ysw789 a92b001
feat: [alt-267] 공고 등록·수정 시 직접입력 업종 지원
ysw789 75387b3
feat: [alt-267] 알바생 공고 목록 업종 필터 추가
ysw789 edd90ae
feat: [alt-267] 공고 응답에 직접입력 업종 노출 및 키워드 null 가드
ysw789 828cf09
fix: [alt-267] 공고 지원 조건 반전 수정
ysw789 32b2ef7
refactor: [alt-267] 업종 키워드 생성 응답을 영속 엔티티 기반으로 변경
ysw789 cdca4df
fix: [alt-267] 공고 업종 필터 직접입력 라벨 LIKE 와일드카드 이스케이프
ysw789 172b058
refactor: [alt-267] 공고 키워드 조회·검증 로직 공용 리졸버로 추출
ysw789 a5715a4
refactor: [alt-267] 공고 직접입력 업종 저장 시 방어적 복사 적용
ysw789 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
84 changes: 84 additions & 0 deletions
84
...eamteam/alter/adapter/inbound/admin/posting/controller/AdminPostingKeywordController.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| package com.dreamteam.alter.adapter.inbound.admin.posting.controller; | ||
|
|
||
| import com.dreamteam.alter.adapter.inbound.admin.posting.dto.AdminPostingKeywordRequestDto; | ||
| import com.dreamteam.alter.adapter.inbound.admin.posting.dto.AdminPostingKeywordResponseDto; | ||
| import com.dreamteam.alter.adapter.inbound.common.dto.CommonApiResponse; | ||
| import com.dreamteam.alter.domain.posting.command.AdminCreatePostingKeywordCommand; | ||
| import com.dreamteam.alter.domain.posting.command.AdminUpdatePostingKeywordCommand; | ||
| import com.dreamteam.alter.domain.posting.entity.PostingKeyword; | ||
| import com.dreamteam.alter.domain.posting.port.inbound.AdminCreatePostingKeywordUseCase; | ||
| import com.dreamteam.alter.domain.posting.port.inbound.AdminDeletePostingKeywordUseCase; | ||
| import com.dreamteam.alter.domain.posting.port.inbound.AdminGetPostingKeywordListUseCase; | ||
| import com.dreamteam.alter.domain.posting.port.inbound.AdminUpdatePostingKeywordUseCase; | ||
| import jakarta.annotation.Resource; | ||
| import jakarta.validation.Valid; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.security.access.prepost.PreAuthorize; | ||
| import org.springframework.validation.annotation.Validated; | ||
| import org.springframework.web.bind.annotation.*; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/admin/posting-keywords") | ||
| @PreAuthorize("hasAnyRole('ADMIN')") | ||
| @RequiredArgsConstructor | ||
| @Validated | ||
| public class AdminPostingKeywordController implements AdminPostingKeywordControllerSpec { | ||
|
|
||
| @Resource(name = "adminGetPostingKeywordList") | ||
| private final AdminGetPostingKeywordListUseCase adminGetPostingKeywordList; | ||
|
|
||
| @Resource(name = "adminCreatePostingKeyword") | ||
| private final AdminCreatePostingKeywordUseCase adminCreatePostingKeyword; | ||
|
|
||
| @Resource(name = "adminUpdatePostingKeyword") | ||
| private final AdminUpdatePostingKeywordUseCase adminUpdatePostingKeyword; | ||
|
|
||
| @Resource(name = "adminDeletePostingKeyword") | ||
| private final AdminDeletePostingKeywordUseCase adminDeletePostingKeyword; | ||
|
|
||
| @Override | ||
| @GetMapping | ||
| public ResponseEntity<CommonApiResponse<List<AdminPostingKeywordResponseDto>>> getPostingKeywordList() { | ||
| List<AdminPostingKeywordResponseDto> result = adminGetPostingKeywordList.execute().stream() | ||
| .map(AdminPostingKeywordResponseDto::from) | ||
| .toList(); | ||
| return ResponseEntity.ok(CommonApiResponse.of(result)); | ||
| } | ||
|
|
||
| @Override | ||
| @PostMapping | ||
| public ResponseEntity<CommonApiResponse<AdminPostingKeywordResponseDto>> createPostingKeyword( | ||
| @Valid @RequestBody AdminPostingKeywordRequestDto request | ||
| ) { | ||
| PostingKeyword created = adminCreatePostingKeyword.execute( | ||
| new AdminCreatePostingKeywordCommand(request.getName(), request.getDescription()) | ||
| ); | ||
| return ResponseEntity.status(HttpStatus.CREATED) | ||
| .body(CommonApiResponse.of(AdminPostingKeywordResponseDto.from(created))); | ||
| } | ||
|
|
||
| @Override | ||
| @PutMapping("/{id}") | ||
| public ResponseEntity<CommonApiResponse<Void>> updatePostingKeyword( | ||
| @PathVariable Long id, | ||
| @Valid @RequestBody AdminPostingKeywordRequestDto request | ||
| ) { | ||
| adminUpdatePostingKeyword.execute( | ||
| id, new AdminUpdatePostingKeywordCommand(request.getName(), request.getDescription()) | ||
| ); | ||
| return ResponseEntity.ok(CommonApiResponse.empty()); | ||
| } | ||
|
|
||
| @Override | ||
| @DeleteMapping("/{id}") | ||
| public ResponseEntity<CommonApiResponse<Void>> deletePostingKeyword( | ||
| @PathVariable Long id | ||
| ) { | ||
| adminDeletePostingKeyword.execute(id); | ||
| return ResponseEntity.ok(CommonApiResponse.empty()); | ||
| } | ||
| } | ||
53 changes: 53 additions & 0 deletions
53
...eam/alter/adapter/inbound/admin/posting/controller/AdminPostingKeywordControllerSpec.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| package com.dreamteam.alter.adapter.inbound.admin.posting.controller; | ||
|
|
||
| import com.dreamteam.alter.adapter.inbound.admin.posting.dto.AdminPostingKeywordRequestDto; | ||
| import com.dreamteam.alter.adapter.inbound.admin.posting.dto.AdminPostingKeywordResponseDto; | ||
| import com.dreamteam.alter.adapter.inbound.common.dto.CommonApiResponse; | ||
| import io.swagger.v3.oas.annotations.Operation; | ||
| import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
| import io.swagger.v3.oas.annotations.responses.ApiResponses; | ||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||
| import jakarta.validation.Valid; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.PathVariable; | ||
| import org.springframework.web.bind.annotation.RequestBody; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @Tag(name = "ADMIN - 업종(키워드) 관리 API") | ||
| public interface AdminPostingKeywordControllerSpec { | ||
|
|
||
| @Operation(summary = "업종 목록 조회", description = "관리자가 등록된 업종(키워드) 전체 목록을 조회합니다.") | ||
| @ApiResponses(value = { | ||
| @ApiResponse(responseCode = "200", description = "업종 목록 조회 성공") | ||
| }) | ||
| ResponseEntity<CommonApiResponse<List<AdminPostingKeywordResponseDto>>> getPostingKeywordList(); | ||
|
|
||
| @Operation(summary = "업종 생성", description = "관리자가 새 업종(키워드)을 등록합니다. 이름은 중복될 수 없습니다.") | ||
| @ApiResponses(value = { | ||
| @ApiResponse(responseCode = "201", description = "업종 생성 성공"), | ||
| @ApiResponse(responseCode = "400", description = "이름 중복 또는 유효성 검증 실패") | ||
| }) | ||
| ResponseEntity<CommonApiResponse<AdminPostingKeywordResponseDto>> createPostingKeyword( | ||
| @Valid @RequestBody AdminPostingKeywordRequestDto request | ||
| ); | ||
|
|
||
| @Operation(summary = "업종 수정", description = "관리자가 업종(키워드)의 이름/설명을 수정합니다.") | ||
| @ApiResponses(value = { | ||
| @ApiResponse(responseCode = "200", description = "업종 수정 성공"), | ||
| @ApiResponse(responseCode = "400", description = "이름 중복 또는 존재하지 않는 업종") | ||
| }) | ||
| ResponseEntity<CommonApiResponse<Void>> updatePostingKeyword( | ||
| @PathVariable Long id, | ||
| @Valid @RequestBody AdminPostingKeywordRequestDto request | ||
| ); | ||
|
|
||
| @Operation(summary = "업종 삭제", description = "관리자가 업종(키워드)을 삭제합니다. 공고에서 사용 중인 업종은 삭제할 수 없습니다.") | ||
| @ApiResponses(value = { | ||
| @ApiResponse(responseCode = "200", description = "업종 삭제 성공"), | ||
| @ApiResponse(responseCode = "409", description = "공고에서 사용 중인 업종") | ||
| }) | ||
| ResponseEntity<CommonApiResponse<Void>> deletePostingKeyword( | ||
| @PathVariable Long id | ||
| ); | ||
| } |
24 changes: 24 additions & 0 deletions
24
.../com/dreamteam/alter/adapter/inbound/admin/posting/dto/AdminPostingKeywordRequestDto.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package com.dreamteam.alter.adapter.inbound.admin.posting.dto; | ||
|
|
||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import jakarta.validation.constraints.NotBlank; | ||
| import jakarta.validation.constraints.Size; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
|
|
||
| @Getter | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| @Schema(description = "업종(키워드) 생성/수정 요청 DTO") | ||
| public class AdminPostingKeywordRequestDto { | ||
|
|
||
| @NotBlank | ||
| @Size(max = 128) | ||
| @Schema(description = "업종명", example = "카페") | ||
| private String name; | ||
|
|
||
| @Size(max = 255) | ||
| @Schema(description = "업종 설명", example = "카페/디저트 매장") | ||
| private String description; | ||
| } |
34 changes: 34 additions & 0 deletions
34
...com/dreamteam/alter/adapter/inbound/admin/posting/dto/AdminPostingKeywordResponseDto.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package com.dreamteam.alter.adapter.inbound.admin.posting.dto; | ||
|
|
||
| import com.dreamteam.alter.domain.posting.entity.PostingKeyword; | ||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import lombok.AccessLevel; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Builder; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
|
|
||
| @Getter | ||
| @NoArgsConstructor(access = AccessLevel.PRIVATE) | ||
| @AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
| @Builder(access = AccessLevel.PRIVATE) | ||
| @Schema(description = "업종(키워드) 응답 DTO") | ||
| public class AdminPostingKeywordResponseDto { | ||
|
|
||
| @Schema(description = "업종 ID", example = "1") | ||
| private Long id; | ||
|
|
||
| @Schema(description = "업종명", example = "카페") | ||
| private String name; | ||
|
|
||
| @Schema(description = "업종 설명", example = "카페/디저트 매장") | ||
| private String description; | ||
|
|
||
| public static AdminPostingKeywordResponseDto from(PostingKeyword keyword) { | ||
| return AdminPostingKeywordResponseDto.builder() | ||
| .id(keyword.getId()) | ||
| .name(keyword.getName()) | ||
| .description(keyword.getDescription()) | ||
| .build(); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
@Resource와@RequiredArgsConstructor중복은 불필요합니다.@RequiredArgsConstructor로 생성자 주입이 이미 처리되며, 파라미터명이 빈 이름과 일치하므로@Resource(name = "...")는 중복입니다. 제거를 고려해 보세요.🤖 Prompt for AI Agents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
확인 결과, 이 패턴은 프로젝트 전역 컨벤션이라 유지합니다.
@Resource(name = "...")+@RequiredArgsConstructor병용은 현재 inbound 어댑터 컨트롤러 48개 파일에서 동일하게 사용 중입니다(예:UserSelfController,ManagerPostingController,AdminUserController등). UseCase 빈이@Service("...")로 명시적 이름을 갖는 구조와 짝을 이뤄 주입 대상을 빈 이름으로 고정하려는 의도적 관례입니다.이 파일만 제거하면 코드베이스 일관성이 깨지므로 반영하지 않습니다. 패턴 자체의 재검토가 필요하다면 별도의 전역 리팩토링으로 다루는 것이 적절합니다.