Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
Expand All @@ -30,13 +32,11 @@ public Member makeProfile(CreateProfileDTO request,Member member) {
Job job = jobService.findJobById(request.job());

Member profileMember = findMemberByMemberId(member.getId());
//회원 프로필 작성
//회원 프로필 작성하기
profileMember.createProfile(request, job);
profileMember.completeProfile();

//비어있는 플래너 생성
CreatePlannerDTO createPlannerDTO = CreatePlannerDTO.builder().build();
plannerService.savePlanner(profileMember,createPlannerDTO);
plannerService.savePlanner(profileMember);

return profileMember;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/UMC/career_mate/domain/planner/Planner.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class Planner extends BaseEntity {
@Column(name = "other_plans")
private String otherPlans;

@OneToOne
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package UMC.career_mate.domain.planner.controller;

import UMC.career_mate.domain.member.Member;
import UMC.career_mate.domain.planner.dto.request.CreatePlannerDTO;
import UMC.career_mate.domain.planner.dto.response.PlannerResponseDTO;
import UMC.career_mate.domain.planner.dto.request.CreatePlannerListDTO;
import UMC.career_mate.domain.planner.dto.response.PlannerListResponseDTO;
import UMC.career_mate.domain.planner.service.PlannerCommandService;
import UMC.career_mate.domain.planner.service.PlannerQueryService;
import UMC.career_mate.global.annotation.LoginMember;
Expand All @@ -19,35 +19,6 @@ public class PlannerController {
private final PlannerCommandService plannerCommandService;
private final PlannerQueryService plannerQueryService;

@Deprecated
@PostMapping
@Operation(
summary = "[관리자용 API] 플래너 생성",
description = """
[관리자용 API입니다]
새로운 플래너를 생성합니다.
값이 비어있어도 상관 없습니다.
### Example JSON:
```json
{
"activityName": "React.js로 커리어 메이트 00파트 개발",
"startTime": "2025-12-23T09:00:00",
"endTime": "2025-12-23T18:00:00",
"specifics": "React.js를 활용한 프로젝트 5개 기능 구현",
"measurable": "개인 프로젝트를 GitHub에 배포 + 최소 5개 기능 구현",
"achievable": "하루에 최소 3시간 이상 투자하기",
"relevant": "프로젝트 경험을 통한 기술 및 협업 역량 향상 기대",
"timeBound": "2025년 2월 10일 - 12/23~1/10: 00부분까지 완료, 1/12~1/26: API 연결",
"otherPlans": "매주 토요일 강남역 대면 미팅 참석"
}
```
""")

public ApiResponse<String> savePlanner(@LoginMember Member member, @RequestBody CreatePlannerDTO createPlannerDTO) {
plannerCommandService.savePlanner(member, createPlannerDTO);
return ApiResponse.onSuccess("플래너 추가 완료");
}

@PatchMapping
@Operation(
summary = "플래너 수정",
Expand All @@ -57,22 +28,35 @@ public ApiResponse<String> savePlanner(@LoginMember Member member, @RequestBody
값이 비어있어도 상관 없습니다.
### Example JSON:
```json
{
"activityName": "React.js로 커리어 메이트 00파트 개발",
"startTime": "2025-12-23T09:00:00",
"endTime": "2025-12-23T18:00:00",
"specifics": "React.js를 활용한 프로젝트 5개 기능 구현",
"measurable": "개인 프로젝트를 GitHub에 배포 + 최소 5개 기능 구현",
"achievable": "하루에 최소 3시간 이상 투자하기",
"relevant": "프로젝트 경험을 통한 기술 및 협업 역량 향상 기대",
"timeBound": "2025년 2월 10일 - 12/23~1/10: 00부분까지 완료, 1/12~1/26: API 연결",
"otherPlans": "매주 토요일 강남역 대면 미팅 참석"
}
planners : [
{
"activityName": "React.js로 커리어 메이트 00파트 개발",
"startTime": "2025-12-23T09:00:00",
"endTime": "2025-12-23T18:00:00",
"specifics": "React.js를 활용한 프로젝트 5개 기능 구현",
"measurable": "개인 프로젝트를 GitHub에 배포 + 최소 5개 기능 구현",
"achievable": "하루에 최소 3시간 이상 투자하기",
"relevant": "프로젝트 경험을 통한 기술 및 협업 역량 향상 기대",
"timeBound": "2025년 2월 10일 - 12/23~1/10: 00부분까지 완료, 1/12~1/26: API 연결",
"otherPlans": "매주 토요일 강남역 대면 미팅 참석"
},
{
"activityName": "React.js로 커리어 메이트 00파트 개발",
"startTime": "2025-12-23T09:00:00",
"endTime": "2025-12-23T18:00:00",
"specifics": "React.js를 활용한 프로젝트 5개 기능 구현",
"measurable": "개인 프로젝트를 GitHub에 배포 + 최소 5개 기능 구현",
"achievable": "하루에 최소 3시간 이상 투자하기",
"relevant": "프로젝트 경험을 통한 기술 및 협업 역량 향상 기대",
"timeBound": "2025년 2월 10일 - 12/23~1/10: 00부분까지 완료, 1/12~1/26: API 연결",
"otherPlans": "매주 토요일 강남역 대면 미팅 참석"
}
]
```
""")

public ApiResponse<String> editPlanner(@LoginMember Member member, @RequestBody CreatePlannerDTO createPlannerDTO) {
plannerCommandService.editPlanner(member, createPlannerDTO);
public ApiResponse<String> editPlanner(@LoginMember Member member, @RequestBody CreatePlannerListDTO createPlannerListDTO) {
plannerCommandService.editPlanner(member, createPlannerListDTO);
return ApiResponse.onSuccess("플래너 수정 완료");
}

Expand All @@ -95,20 +79,31 @@ public ApiResponse<String> deletePlanner(@LoginMember Member member){
없는 값은 null을 리턴합니다.
### Example JSON:
```json
{
"activityName": "React.js로 커리어 메이트 00파트 개발",
"startTime": "2025-12-23T09:00:00",
"endTime": "2025-12-23T18:00:00",
"specifics": "React.js를 활용한 프로젝트 5개 기능 구현",
"measurable": "개인 프로젝트를 GitHub에 배포 + 최소 5개 기능 구현",
"achievable": "하루에 최소 3시간 이상 투자하기",
"relevant": "프로젝트 경험을 통한 기술 및 협업 역량 향상 기대",
"timeBound": "2025년 2월 10일 - 12/23~1/10: 00부분까지 완료, 1/12~1/26: API 연결",
"otherPlans": "매주 토요일 강남역 대면 미팅 참석"
}
planners : [
{
"activityName": "React.js로 커리어 메이트 00파트 개발",
"startTime": "2025-12-23T09:00:00",
"endTime": "2025-12-23T18:00:00",
"specifics": "React.js를 활용한 프로젝트 5개 기능 구현",
"measurable": "개인 프로젝트를 GitHub에 배포 + 최소 5개 기능 구현",
"achievable": "하루에 최소 3시간 이상 투자하기",
"relevant": "프로젝트 경험을 통한 기술 및 협업 역량 향상 기대",
"timeBound": "2025년 2월 10일 - 12/23~1/10: 00부분까지 완료, 1/12~1/26: API 연결",
"otherPlans": "매주 토요일 강남역 대면 미팅 참석"
},{
"activityName": "React.js로 커리어 메이트 00파트 개발",
"startTime": "2025-12-23T09:00:00",
"endTime": "2025-12-23T18:00:00",
"specifics": "React.js를 활용한 프로젝트 5개 기능 구현",
"measurable": "개인 프로젝트를 GitHub에 배포 + 최소 5개 기능 구현",
"achievable": "하루에 최소 3시간 이상 투자하기",
"relevant": "프로젝트 경험을 통한 기술 및 협업 역량 향상 기대",
"timeBound": "2025년 2월 10일 - 12/23~1/10: 00부분까지 완료, 1/12~1/26: API 연결",
"otherPlans": "매주 토요일 강남역 대면 미팅 참석"
}]
```
""")
public ApiResponse<PlannerResponseDTO> getPlanner(@LoginMember Member member){
public ApiResponse<PlannerListResponseDTO> getPlanner(@LoginMember Member member){
return ApiResponse.onSuccess(plannerQueryService.getPlannerByMember(member));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
import UMC.career_mate.domain.member.Member;
import UMC.career_mate.domain.planner.Planner;
import UMC.career_mate.domain.planner.dto.request.CreatePlannerDTO;
import UMC.career_mate.domain.planner.dto.response.PlannerListResponseDTO;
import UMC.career_mate.domain.planner.dto.response.PlannerResponseDTO;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class PlannerConverter {

public static Planner toPlanner(Member member, CreatePlannerDTO createPlannerDTO){
Expand All @@ -23,6 +28,10 @@ public static Planner toPlanner(Member member, CreatePlannerDTO createPlannerDTO
.build();
}

public static List<Planner> toPlannerList(Member member, List<CreatePlannerDTO> createPlannerDTOList){
return createPlannerDTOList.stream().map(createPlannerDTO -> PlannerConverter.toPlanner(member, createPlannerDTO)).toList();
}

public static PlannerResponseDTO toPlannerResponseDTO(Planner planner){
return PlannerResponseDTO.builder()
.activityName(planner.getActivityName())
Expand All @@ -36,4 +45,14 @@ public static PlannerResponseDTO toPlannerResponseDTO(Planner planner){
.otherPlans(planner.getOtherPlans())
.build();
}

public static PlannerListResponseDTO toPlannerListResponseDTO(List<Planner> plannerList){
List<PlannerResponseDTO> plannerResponseDTOList = plannerList.stream()
.map(PlannerConverter::toPlannerResponseDTO)
.toList();
return PlannerListResponseDTO.builder()
.planners(plannerResponseDTOList)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package UMC.career_mate.domain.planner.dto.request;

import UMC.career_mate.global.response.exception.GeneralException;
import UMC.career_mate.global.response.exception.code.CommonErrorCode;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;

import java.util.List;

@Builder
public record CreatePlannerListDTO(

@NotNull(message = "플래너 목록은 필수입니다.")
@Valid
List<CreatePlannerDTO> planners
) {
public CreatePlannerListDTO {

if (planners == null || planners.size() != 2) {
throw new GeneralException(CommonErrorCode.INVALID_PLANNER_COUNT);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package UMC.career_mate.domain.planner.dto.response;

import UMC.career_mate.domain.planner.Planner;
import lombok.Builder;

import java.util.List;

@Builder
public record PlannerListResponseDTO(
List<PlannerResponseDTO> planners
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import UMC.career_mate.domain.planner.Planner;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;

public interface PlannerRepository extends JpaRepository<Planner,Long> {

Boolean existsByMember(Member member);
Optional<Planner> findPlannerByMember(Member member);
List<Planner> findByMember(Member member);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import UMC.career_mate.domain.planner.Planner;
import UMC.career_mate.domain.planner.converter.PlannerConverter;
import UMC.career_mate.domain.planner.dto.request.CreatePlannerDTO;
import UMC.career_mate.domain.planner.dto.request.CreatePlannerListDTO;
import UMC.career_mate.domain.planner.repository.PlannerRepository;
import UMC.career_mate.global.response.exception.GeneralException;
import UMC.career_mate.global.response.exception.code.CommonErrorCode;
Expand All @@ -12,6 +13,9 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Iterator;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
Expand All @@ -20,25 +24,35 @@ public class PlannerCommandService {

private final PlannerRepository plannerRepository;

public void savePlanner(Member member, CreatePlannerDTO createPlannerDTO){
public void savePlanner(Member member){

Comment on lines +27 to +28
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

메서드 시그니처 명칭과 실제 동작 간의 괴리
savePlanner 메서드 이름과 달리 내부적으로 2개의 Planner를 자동으로 생성하고 있습니다. 처음 사용자가 보기에 혼동이 생길 수 있으니, 메서드 명을 initializePlanners 등으로 좀 더 명시적으로 수정하는 방안을 고려해 보세요.

- public void savePlanner(Member member){
+ public void initializePlanners(Member member){
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void savePlanner(Member member){
public void initializePlanners(Member member){

if(plannerRepository.existsByMember(member)){
throw new GeneralException(CommonErrorCode.PLANNER_EXISTS);
}
Planner planner = PlannerConverter.toPlanner(member, createPlannerDTO);
plannerRepository.save(planner);

List<CreatePlannerDTO> createPlannerDTOList = List.of(
CreatePlannerDTO.builder().build(),
CreatePlannerDTO.builder().build()
);

plannerRepository.saveAll(PlannerConverter.toPlannerList(member, createPlannerDTOList));
}

public void editPlanner(Member member, CreatePlannerDTO createPlannerDTO){
Planner planner = plannerRepository.findPlannerByMember(member).orElseThrow(
()->new GeneralException(CommonErrorCode.PLANNER_NOT_EXISTS));
public void editPlanner(Member member, CreatePlannerListDTO createPlannerListDTO){

List<Planner> planners = plannerRepository.findByMember(member);
List<CreatePlannerDTO> plannerDTOs = createPlannerListDTO.planners();

Iterator<CreatePlannerDTO> dtoIterator = plannerDTOs.iterator();
planners.forEach(planner -> planner.update(dtoIterator.next()));
Comment on lines +41 to +47
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

플래너 개수와 DTO 목록 개수 불일치 시 예외 처리 필요
plannersplannerDTOs의 크기가 다를 경우 dtoIterator.next() 호출 시 예외가 발생할 수 있습니다. 두 리스트 길이가 동일한지를 확인하는 로직을 추가하거나, 안전하게 처리하는 방법을 고민해 보세요.

List<CreatePlannerDTO> plannerDTOs = createPlannerListDTO.planners();
if (planners.size() != plannerDTOs.size()) {
+   throw new GeneralException(CommonErrorCode.INVALID_REQUEST, "DTO 개수와 플래너 개수가 일치하지 않습니다.");
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void editPlanner(Member member, CreatePlannerListDTO createPlannerListDTO){
List<Planner> planners = plannerRepository.findByMember(member);
List<CreatePlannerDTO> plannerDTOs = createPlannerListDTO.planners();
Iterator<CreatePlannerDTO> dtoIterator = plannerDTOs.iterator();
planners.forEach(planner -> planner.update(dtoIterator.next()));
public void editPlanner(Member member, CreatePlannerListDTO createPlannerListDTO){
List<Planner> planners = plannerRepository.findByMember(member);
List<CreatePlannerDTO> plannerDTOs = createPlannerListDTO.planners();
if (planners.size() != plannerDTOs.size()) {
throw new GeneralException(CommonErrorCode.INVALID_REQUEST, "DTO 개수와 플래너 개수가 일치하지 않습니다.");
}
Iterator<CreatePlannerDTO> dtoIterator = plannerDTOs.iterator();
planners.forEach(planner -> planner.update(dtoIterator.next()));


planner.update(createPlannerDTO);
}

public void deletePlanner(Member member){
Planner planner = plannerRepository.findPlannerByMember(member).orElseThrow(
()->new GeneralException(CommonErrorCode.PLANNER_NOT_EXISTS));
plannerRepository.delete(planner);

List<Planner> planners = plannerRepository.findByMember(member);
plannerRepository.deleteAll(planners);

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import UMC.career_mate.domain.member.Member;
import UMC.career_mate.domain.planner.Planner;
import UMC.career_mate.domain.planner.converter.PlannerConverter;
import UMC.career_mate.domain.planner.dto.response.PlannerListResponseDTO;
import UMC.career_mate.domain.planner.dto.response.PlannerResponseDTO;
import UMC.career_mate.domain.planner.repository.PlannerRepository;
import UMC.career_mate.global.response.exception.GeneralException;
Expand All @@ -12,6 +13,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
Expand All @@ -20,11 +23,8 @@ public class PlannerQueryService {

private final PlannerRepository plannerRepository;

public PlannerResponseDTO getPlannerByMember(Member member) {
Planner planner = plannerRepository.findPlannerByMember(member).orElseThrow(
()-> new GeneralException(CommonErrorCode.PLANNER_NOT_EXISTS)
);

return PlannerConverter.toPlannerResponseDTO(planner);
public PlannerListResponseDTO getPlannerByMember(Member member) {
List<Planner> planners = plannerRepository.findByMember(member);
return PlannerConverter.toPlannerListResponseDTO(planners);
Comment on lines +26 to +28
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

빈 리스트 처리 로직이 필요합니다.

현재 구현에서는 플래너가 없는 경우에 대한 명시적인 처리가 없습니다. 다음과 같이 개선하면 좋을 것 같습니다:

 public PlannerListResponseDTO getPlannerByMember(Member member) {
     List<Planner> planners = plannerRepository.findByMember(member);
+    if (planners.isEmpty()) {
+        throw new GeneralException(CommonErrorCode.PLANNER_NOT_EXISTS);
+    }
     return PlannerConverter.toPlannerListResponseDTO(planners);
 }

Committable suggestion skipped: line range outside the PR's diff.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public enum CommonErrorCode implements ErrorCode {
//Planner 도메인
PLANNER_NOT_EXISTS(400, "EPL001","유저의 플래너가 존재하지 않습니다. 먼저 POST로 생성해주세요."),
PLANNER_EXISTS(400, "EPL002","유저의 플래너가 존재합니다. 프로필 작성 완료시 플래너가 자동 생성되기 때문에,PATCH API를 사용해주시면 되겠습니다"),
INVALID_PLANNER_COUNT(400, "EPL003", "플래너는 2개씩 전송해야 합니다."),

// Recruit 도메인
NOT_FOUND_RECRUIT(400, "ERE000", "해당 채용 공고를 찾을 수 없습니다."),
Expand Down