diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a87a31f..faef3d1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,11 @@ jobs: run: chmod +x gradlew - name: Build + run: ./gradlew build --info --stacktrace + + - name: SonarCloud Analysis + continue-on-error: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: ./gradlew build sonar --info --stacktrace + run: ./gradlew sonar --info --stacktrace diff --git a/.gitignore b/.gitignore index 1939075b..99c7c98f 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ application-local.yml application-dev.yml application-prod.yml /src/main/generated/ +.claude ### NetBeans ### /nbproject/private/ @@ -47,3 +48,6 @@ application-prod.yml ./src/main/resources/config /logs + +# AI Tool Configuration +CLAUDE.md diff --git a/build.gradle b/build.gradle index 4e48378d..e8556c1f 100644 --- a/build.gradle +++ b/build.gradle @@ -41,7 +41,7 @@ sonar { property "sonar.host.url", "https://sonarcloud.io" property "sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacoco/test/jacocoTestReport.xml" property "sonar.exclusions", "**/*Application*.java, **/*Config*.java, **/*GlobalExceptionHandler.java, **/Q*.java, **/DynamicQuery.java, " + - "**/*Exception.java, **/*Adapter.java, **/CustomOAuth2UserService.java, **/*Filter.java" + "**/*Exception.java, **/*Adapter.java, **/CustomOAuth2UserService.java, **/*Filter.java, **/*Converter.java" property "sonar.java.coveragePlugin", "jacoco" } } @@ -126,7 +126,8 @@ jacocoTestCoverageVerification { '*.*.CustomUserDetails', 'scouter.*', 'reactor.*', - '*.*RepositoryImpl' + '*.*RepositoryImpl', + '*.*Converter' ] } } @@ -214,4 +215,8 @@ dependencies { // 이미지 메타데이터 관련 라이브러리 implementation 'com.drewnoakes:metadata-extractor:2.19.0' implementation 'org.apache.commons:commons-imaging:1.0.0-alpha5' + + // Flyway + implementation 'org.flywaydb:flyway-core' + implementation 'org.flywaydb:flyway-mysql' } diff --git a/src/main/java/com/tnt/common/error/model/ErrorMessage.java b/src/main/java/com/tnt/common/error/model/ErrorMessage.java index a5d97c53..fe3b91bd 100644 --- a/src/main/java/com/tnt/common/error/model/ErrorMessage.java +++ b/src/main/java/com/tnt/common/error/model/ErrorMessage.java @@ -8,6 +8,7 @@ public enum ErrorMessage { SERVER_ERROR("서버 에러가 발생했습니다."), + FAILED_TO_CONVERT_JSON("JSON 직렬화에 실패했습니다."), FCM_FAILED("FCM 전송에 실패했습니다."), S3_UPLOAD_ERROR("S3로 이미지 업로드 중 오류가 발생했습니다."), S3_DELETE_ERROR("S3 이미지 삭제 중 오류가 발생했습니다."), @@ -48,7 +49,7 @@ public enum ErrorMessage { TRAINEE_INVALID_CAUTION_NOTE("주의사항이 올바르지 않습니다."), TRAINEE_NOT_FOUND("존재하지 않는 트레이니입니다."), - PT_GOAL_INVALID_CONTENT("목적 내용이 올바르지 않습니다."), + UNSUPPORTED_PT_GOAL("지원하지 않는 PT 목적입니다."), PT_TRAINER_TRAINEE_ALREADY_EXIST("이미 연결된 트레이너-트레이니입니다."), PT_TRAINEE_ALREADY_EXIST("이미 다른 트레이너와 연결되어 있습니다."), diff --git a/src/main/java/com/tnt/member/application/MemberService.java b/src/main/java/com/tnt/member/application/MemberService.java index 6ec73cd8..bbbf7ad6 100644 --- a/src/main/java/com/tnt/member/application/MemberService.java +++ b/src/main/java/com/tnt/member/application/MemberService.java @@ -7,11 +7,8 @@ import static com.tnt.member.domain.MemberType.TRAINER; import static com.tnt.member.dto.MemberProjection.MemberTypeDto; import static java.util.Objects.isNull; -import static java.util.stream.Collectors.toSet; -import java.util.HashSet; import java.util.List; -import java.util.Set; import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; @@ -28,9 +25,7 @@ import com.tnt.member.dto.response.MemberInfoResponse; import com.tnt.pt.application.PtService; import com.tnt.pt.domain.PtTrainerTrainee; -import com.tnt.trainee.application.PtGoalService; import com.tnt.trainee.application.TraineeService; -import com.tnt.trainee.application.repository.PtGoalRepository; import com.tnt.trainee.application.repository.TraineeRepository; import com.tnt.trainee.domain.PtGoal; import com.tnt.trainee.domain.Trainee; @@ -45,12 +40,10 @@ public class MemberService { private final TrainerService trainerService; private final TraineeService traineeService; - private final PtGoalService ptGoalService; private final PtService ptService; private final MemberRepository memberRepository; private final TraineeRepository traineeRepository; - private final PtGoalRepository ptGoalRepository; @Transactional(readOnly = true) public MemberInfoResponse getMemberInfo(Long memberId) { @@ -78,10 +71,7 @@ public MemberInfoResponse getMemberInfo(Long memberId) { if (member.getMemberType() == TRAINEE) { Trainee trainee = traineeService.getByMemberId(memberId); - List ptGoals = ptGoalService.getAllByTraineeId(trainee.getId()) - .stream() - .map(PtGoal::getContent) - .toList(); + List ptGoals = trainee.getPtGoals(); boolean isConnected = ptService.isPtTrainerTraineeExistWithTraineeId(trainee.getId()); MemberInfoResponse.TraineeInfo traineeInfo = new MemberInfoResponse.TraineeInfo(isConnected, @@ -154,8 +144,7 @@ public void updateMemberInfo(Long memberId, UpdateMemberInfoRequest request, Str Trainee trainee = traineeService.getByMemberId(memberId); member.updateBirthday(request.birthday()); - trainee.updateTraineeInfo(request.height(), request.weight(), request.cautionNote()); - updatePtGoals(trainee, new HashSet<>(request.goalContents())); + trainee.updateTraineeInfo(request.height(), request.weight(), request.cautionNote(), request.ptGoals()); traineeRepository.save(trainee); } @@ -175,32 +164,4 @@ public void validateMemberNotExists(String socialId, SocialType socialType) { public Member getByMemberId(Long memberId) { return memberRepository.findById(memberId); } - - private void updatePtGoals(Trainee trainee, HashSet newGoalContents) { - // 기존 PT 목표들 조회 - List currentPtGoals = ptGoalService.getAllByTraineeId(trainee.getId()); - - // 기존 목표 중 더 이상 필요없는 목표 삭제 - List goalsToDelete = currentPtGoals.stream() - .filter(goal -> !newGoalContents.contains(goal.getContent())) - .toList(); - - if (!goalsToDelete.isEmpty()) { - ptGoalRepository.deleteAll(goalsToDelete); - } - - // 새로운 목표 추가 (기존에 없는 것만) - Set existingContents = currentPtGoals.stream() - .map(PtGoal::getContent) - .collect(toSet()); - - List newPtGoals = newGoalContents.stream() - .filter(content -> !existingContents.contains(content)) - .map(content -> PtGoal.builder().traineeId(trainee.getId()).content(content).build()) - .toList(); - - if (!newPtGoals.isEmpty()) { - ptGoalRepository.saveAll(newPtGoals); - } - } } diff --git a/src/main/java/com/tnt/member/application/SignUpService.java b/src/main/java/com/tnt/member/application/SignUpService.java index 57d5b06e..6fc98211 100644 --- a/src/main/java/com/tnt/member/application/SignUpService.java +++ b/src/main/java/com/tnt/member/application/SignUpService.java @@ -17,7 +17,6 @@ import com.tnt.member.domain.MemberType; import com.tnt.member.dto.request.SignUpRequest; import com.tnt.member.dto.response.SignUpResponse; -import com.tnt.trainee.application.repository.PtGoalRepository; import com.tnt.trainee.application.repository.TraineeRepository; import com.tnt.trainee.domain.PtGoal; import com.tnt.trainee.domain.Trainee; @@ -32,11 +31,9 @@ public class SignUpService { private final SessionService sessionService; private final MemberService memberService; - private final MemberRepository memberRepository; private final TrainerRepository trainerRepository; private final TraineeRepository traineeRepository; - private final PtGoalRepository ptGoalRepository; @Transactional public Long signUp(SignUpRequest request) { @@ -76,16 +73,18 @@ private Long createTrainer(SignUpRequest request) { private Long createTrainee(SignUpRequest request) { Member member = createMember(request, TRAINEE_DEFAULT_IMAGE, TRAINEE); + + List ptGoals = request.ptGoals().stream().map(PtGoal::of).toList(); + Trainee trainee = Trainee.builder() .member(member) .height(request.height()) .weight(request.weight()) .cautionNote(request.cautionNote()) + .ptGoals(ptGoals) .build(); - trainee = traineeRepository.save(trainee); - - createPtGoals(trainee, request.goalContents()); + traineeRepository.save(trainee); return member.getId(); } @@ -107,15 +106,4 @@ private Member createMember(SignUpRequest request, String defaultImageUrl, Membe return memberRepository.save(member); } - - private void createPtGoals(Trainee trainee, List goalContents) { - List ptGoals = goalContents.stream() - .map(content -> PtGoal.builder() - .traineeId(trainee.getId()) - .content(content) - .build()) - .toList(); - - ptGoalRepository.saveAll(ptGoals); - } } diff --git a/src/main/java/com/tnt/member/application/WithdrawService.java b/src/main/java/com/tnt/member/application/WithdrawService.java index 097048be..fd98303f 100644 --- a/src/main/java/com/tnt/member/application/WithdrawService.java +++ b/src/main/java/com/tnt/member/application/WithdrawService.java @@ -19,13 +19,10 @@ import com.tnt.pt.domain.PtLesson; import com.tnt.pt.domain.PtTrainerTrainee; import com.tnt.trainee.application.DietService; -import com.tnt.trainee.application.PtGoalService; import com.tnt.trainee.application.TraineeService; import com.tnt.trainee.application.repository.DietRepository; -import com.tnt.trainee.application.repository.PtGoalRepository; import com.tnt.trainee.application.repository.TraineeRepository; import com.tnt.trainee.domain.Diet; -import com.tnt.trainee.domain.PtGoal; import com.tnt.trainee.domain.Trainee; import com.tnt.trainer.application.TrainerService; import com.tnt.trainer.application.repository.TrainerRepository; @@ -41,11 +38,8 @@ public class WithdrawService { private final MemberService memberService; private final TrainerService trainerService; private final TraineeService traineeService; - private final PtGoalService ptGoalService; private final DietService dietService; private final PtService ptService; - - private final PtGoalRepository ptGoalRepository; private final MemberRepository memberRepository; private final TrainerRepository trainerRepository; private final TraineeRepository traineeRepository; @@ -90,7 +84,6 @@ private void deleteMemberData(Member member) { if (member.getMemberType() == TRAINEE) { Trainee trainee = traineeService.getByMemberId(member.getId()); - List ptGoals = ptGoalService.getAllByTraineeId(trainee.getId()); List diets = dietService.getAllByTraineeId(trainee.getId()); if (ptService.isPtTrainerTraineeExistWithTraineeId(trainee.getId())) { @@ -108,8 +101,6 @@ private void deleteMemberData(Member member) { } } - ptGoalRepository.deleteAll(ptGoals); - diets.forEach(Diet::softDelete); dietRepository.saveAll(diets); diff --git a/src/main/java/com/tnt/member/dto/request/SignUpRequest.java b/src/main/java/com/tnt/member/dto/request/SignUpRequest.java index 23fbb33d..e0afa7cd 100644 --- a/src/main/java/com/tnt/member/dto/request/SignUpRequest.java +++ b/src/main/java/com/tnt/member/dto/request/SignUpRequest.java @@ -66,8 +66,8 @@ public record SignUpRequest( @Schema(description = "주의사항", example = "가냘퍼요", nullable = true) String cautionNote, - @Schema(description = "PT 목적들", example = "[\"체중 감량\", \"근력 향상\"]", nullable = false) - List goalContents + @Schema(description = "PT 목적", example = "[\"체중 감량\", \"근력 향상\"]", nullable = false) + List ptGoals ) { } diff --git a/src/main/java/com/tnt/member/dto/request/UpdateMemberInfoRequest.java b/src/main/java/com/tnt/member/dto/request/UpdateMemberInfoRequest.java index ee0f2a65..c1c268dd 100644 --- a/src/main/java/com/tnt/member/dto/request/UpdateMemberInfoRequest.java +++ b/src/main/java/com/tnt/member/dto/request/UpdateMemberInfoRequest.java @@ -4,6 +4,7 @@ import java.util.List; import com.tnt.member.domain.MemberType; +import com.tnt.trainee.domain.PtGoal; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Digits; @@ -39,8 +40,8 @@ public record UpdateMemberInfoRequest( @Schema(description = "주의사항", example = "가냘퍼요", nullable = true) String cautionNote, - @Schema(description = "PT 목적들", example = "[\"체중 감량\", \"근력 향상\"]", nullable = false) - List goalContents + @Schema(description = "PT 목적", example = "[\"WEIGHT_LOSS\", \"STRENGTH_ENHANCE\"]", nullable = false) + List ptGoals ) { } diff --git a/src/main/java/com/tnt/member/dto/response/MemberInfoResponse.java b/src/main/java/com/tnt/member/dto/response/MemberInfoResponse.java index 3c0bb179..fe913046 100644 --- a/src/main/java/com/tnt/member/dto/response/MemberInfoResponse.java +++ b/src/main/java/com/tnt/member/dto/response/MemberInfoResponse.java @@ -5,6 +5,7 @@ import com.tnt.member.domain.MemberType; import com.tnt.member.domain.SocialType; +import com.tnt.trainee.domain.PtGoal; import io.swagger.v3.oas.annotations.media.Schema; @@ -61,8 +62,8 @@ public record TraineeInfo( @Schema(description = "주의사항", example = "가냘퍼요", nullable = true) String cautionNote, - @Schema(description = "PT 목적들", example = "[\"체중 감량\", \"근력 향상\"]", nullable = false) - List ptGoals + @Schema(description = "PT 목적", example = "[\"WEIGHT_LOSS\", \"STRENGTH_ENHANCE\"]", nullable = false) + List ptGoals ) { } diff --git a/src/main/java/com/tnt/pt/application/PtService.java b/src/main/java/com/tnt/pt/application/PtService.java index de3b3860..87e57c05 100644 --- a/src/main/java/com/tnt/pt/application/PtService.java +++ b/src/main/java/com/tnt/pt/application/PtService.java @@ -30,7 +30,6 @@ import com.tnt.pt.domain.PtTrainerTrainee; import com.tnt.pt.dto.PtTrainerTraineeProjection; import com.tnt.trainee.application.DietService; -import com.tnt.trainee.application.PtGoalService; import com.tnt.trainee.application.TraineeService; import com.tnt.trainee.domain.Diet; import com.tnt.trainee.domain.PtGoal; @@ -60,7 +59,6 @@ public class PtService { private final TrainerService trainerService; private final TraineeService traineeService; - private final PtGoalService ptGoalService; private final DietService dietService; private final PtTrainerTraineeRepository ptTrainerTraineeRepository; @@ -100,13 +98,12 @@ public ConnectWithTraineeResponse getFirstTrainerTraineeConnect(Long memberId, L Member trainerMember = trainer.getMember(); // fetch join 으로 가져온 member Member traineeMember = trainee.getMember(); // fetch join 으로 가져온 member - List ptGoals = ptGoalService.getAllByTraineeId(traineeId); - String ptGoal = ptGoals.stream().map(PtGoal::getContent).collect(Collectors.joining(", ")); + List ptGoals = trainee.getPtGoals(); return new ConnectWithTraineeResponse( new ConnectTrainerInfo(trainerMember.getName(), trainerMember.getProfileImageUrl()), new ConnectTraineeInfo(traineeMember.getName(), traineeMember.getProfileImageUrl(), - traineeMember.getAge(), trainee.getHeight(), trainee.getWeight(), ptGoal, trainee.getCautionNote()) + traineeMember.getAge(), trainee.getHeight(), trainee.getWeight(), ptGoals, trainee.getCautionNote()) ); } @@ -158,10 +155,7 @@ public GetActiveTraineesResponse getActiveTrainees(Long memberId) { List activeTraineeInfo = trainees.stream().map(trainee -> { PtTrainerTrainee ptTrainerTrainee = ptTrainerTraineeRepository.findByTraineeId(trainee.getId()); - List ptGoals = ptGoalService.getAllByTraineeId(trainee.getId()) - .stream() - .map(PtGoal::getContent) - .toList(); + List ptGoals = ptTrainerTrainee.getTrainee().getPtGoals(); // Memo 추가 구현 필요 return new ActiveTraineeInfo(trainee.getId(), trainee.getMember().getName(), diff --git a/src/main/java/com/tnt/trainee/application/DietService.java b/src/main/java/com/tnt/trainee/application/DietService.java index 39e93320..93a8981e 100644 --- a/src/main/java/com/tnt/trainee/application/DietService.java +++ b/src/main/java/com/tnt/trainee/application/DietService.java @@ -21,7 +21,6 @@ public class DietService { private final TraineeService traineeService; - private final DietRepository dietRepository; @Transactional diff --git a/src/main/java/com/tnt/trainee/application/PtGoalService.java b/src/main/java/com/tnt/trainee/application/PtGoalService.java deleted file mode 100644 index 6034dc19..00000000 --- a/src/main/java/com/tnt/trainee/application/PtGoalService.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.tnt.trainee.application; - -import java.util.List; - -import org.springframework.stereotype.Service; - -import com.tnt.trainee.application.repository.PtGoalRepository; -import com.tnt.trainee.domain.PtGoal; - -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -public class PtGoalService { - - private final PtGoalRepository ptGoalRepository; - - public List getAllByTraineeId(Long traineeId) { - return ptGoalRepository.findAllByTraineeId(traineeId); - } -} diff --git a/src/main/java/com/tnt/trainee/application/repository/PtGoalRepository.java b/src/main/java/com/tnt/trainee/application/repository/PtGoalRepository.java deleted file mode 100644 index 6f34649e..00000000 --- a/src/main/java/com/tnt/trainee/application/repository/PtGoalRepository.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.tnt.trainee.application.repository; - -import java.util.List; - -import com.tnt.trainee.domain.PtGoal; - -public interface PtGoalRepository { - - List saveAll(List ptGoals); - - List findAllByTraineeId(Long traineeId); - - void deleteAll(List goalsToDelete); -} diff --git a/src/main/java/com/tnt/trainee/domain/PtGoal.java b/src/main/java/com/tnt/trainee/domain/PtGoal.java index 7f3ffd5a..1fef4d31 100644 --- a/src/main/java/com/tnt/trainee/domain/PtGoal.java +++ b/src/main/java/com/tnt/trainee/domain/PtGoal.java @@ -1,33 +1,40 @@ package com.tnt.trainee.domain; -import static com.tnt.common.error.model.ErrorMessage.PT_GOAL_INVALID_CONTENT; -import static io.micrometer.common.util.StringUtils.isBlank; -import static java.util.Objects.requireNonNull; +import static com.tnt.common.error.model.ErrorMessage.UNSUPPORTED_PT_GOAL; -import lombok.Builder; -import lombok.Getter; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.tnt.common.error.exception.TnTException; -@Getter -public class PtGoal { +public enum PtGoal { + WEIGHT_LOSS("체중 감량"), + STRENGTH_ENHANCE("근력 향상"), + HEALTH_MANAGE("건강 관리"), + FLEXIBILITY_ENHANCE("유연성향상"), + BODY_PROFILE("바디프로필"), + POSTURE_CORRECTION("자세 교정"); - public static final int CONTENT_LENGTH = 100; + private final String koreanName; - private final Long id; - private final Long traineeId; - private final String content; - - @Builder - public PtGoal(Long id, Long traineeId, String content) { - this.id = id; - this.traineeId = requireNonNull(traineeId); - this.content = validateContent(content); + PtGoal(String koreanName) { + this.koreanName = koreanName; } - private String validateContent(String content) { - if (isBlank(content) || content.length() > CONTENT_LENGTH) { - throw new IllegalArgumentException(PT_GOAL_INVALID_CONTENT.getMessage()); + @JsonCreator + public static PtGoal of(String value) { + // 1. 영어 enum 이름으로 시도 + for (PtGoal goal : PtGoal.values()) { + if (goal.name().equalsIgnoreCase(value)) { + return goal; + } + } + + // 2. 한글 이름으로 시도 + for (PtGoal goal : PtGoal.values()) { + if (goal.koreanName.equals(value)) { + return goal; + } } - return content; + throw new TnTException(UNSUPPORTED_PT_GOAL); } } diff --git a/src/main/java/com/tnt/trainee/domain/PtGoalListConverter.java b/src/main/java/com/tnt/trainee/domain/PtGoalListConverter.java new file mode 100644 index 00000000..c7fb41ba --- /dev/null +++ b/src/main/java/com/tnt/trainee/domain/PtGoalListConverter.java @@ -0,0 +1,46 @@ +package com.tnt.trainee.domain; + +import static com.tnt.common.error.model.ErrorMessage.FAILED_TO_CONVERT_JSON; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tnt.common.error.exception.TnTException; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; + +@Converter +public class PtGoalListConverter implements AttributeConverter, String> { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public String convertToDatabaseColumn(List attribute) { + if (attribute == null || attribute.isEmpty()) { + return "[]"; + } + + try { + return objectMapper.writeValueAsString(attribute); + } catch (JsonProcessingException e) { + throw new TnTException(FAILED_TO_CONVERT_JSON, e); + } + } + + @Override + public List convertToEntityAttribute(String dbData) { + if (dbData == null || dbData.trim().isEmpty()) { + return new ArrayList<>(); + } + + try { + return objectMapper.readValue(dbData, + objectMapper.getTypeFactory().constructCollectionType(List.class, PtGoal.class)); + } catch (JsonProcessingException e) { + throw new TnTException(FAILED_TO_CONVERT_JSON, e); + } + } +} diff --git a/src/main/java/com/tnt/trainee/domain/Trainee.java b/src/main/java/com/tnt/trainee/domain/Trainee.java index a3b3b5f5..3c36380e 100644 --- a/src/main/java/com/tnt/trainee/domain/Trainee.java +++ b/src/main/java/com/tnt/trainee/domain/Trainee.java @@ -4,6 +4,7 @@ import static java.util.Objects.isNull; import java.time.LocalDateTime; +import java.util.List; import com.tnt.member.domain.Member; @@ -20,22 +21,30 @@ public class Trainee { private Double height; private Double weight; private String cautionNote; + private List ptGoals; private LocalDateTime deletedAt; @Builder - public Trainee(Long id, Member member, Double height, Double weight, String cautionNote, LocalDateTime deletedAt) { + public Trainee(Long id, Member member, Double height, Double weight, String cautionNote, List ptGoals, + LocalDateTime deletedAt) { this.id = id; this.member = member; this.height = height; this.weight = weight; + this.ptGoals = ptGoals; this.deletedAt = deletedAt; validateAndSetCautionNote(cautionNote); } - public void updateTraineeInfo(Double height, Double weight, String cautionNote) { + public void updatePtGoals(List ptGoals) { + this.ptGoals = ptGoals; + } + + public void updateTraineeInfo(Double height, Double weight, String cautionNote, List ptGoals) { this.height = height; this.weight = weight; validateAndSetCautionNote(cautionNote); + this.ptGoals = ptGoals; } private void validateAndSetCautionNote(String cautionNote) { diff --git a/src/main/java/com/tnt/trainee/infrastructure/PtGoalJpaEntity.java b/src/main/java/com/tnt/trainee/infrastructure/PtGoalJpaEntity.java deleted file mode 100644 index c89ce0db..00000000 --- a/src/main/java/com/tnt/trainee/infrastructure/PtGoalJpaEntity.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.tnt.trainee.infrastructure; - -import com.tnt.common.jpa.BaseTimeEntity; -import com.tnt.trainee.domain.PtGoal; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Entity -@Getter -@Table(name = "pt_goal") -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class PtGoalJpaEntity extends BaseTimeEntity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id", nullable = false, unique = true) - private Long id; - - @Column(name = "trainee_id", nullable = false) - private Long traineeId; - - @Column(name = "content", nullable = false) - private String content; - - @Builder - public PtGoalJpaEntity(Long id, Long traineeId, String content) { - this.id = id; - this.traineeId = traineeId; - this.content = content; - } - - public static PtGoalJpaEntity from(PtGoal ptGoal) { - return PtGoalJpaEntity.builder() - .id(ptGoal.getId()) - .traineeId(ptGoal.getTraineeId()) - .content(ptGoal.getContent()) - .build(); - } - - public PtGoal toModel() { - return PtGoal.builder() - .id(id) - .traineeId(traineeId) - .content(content) - .build(); - } -} diff --git a/src/main/java/com/tnt/trainee/infrastructure/PtGoalJpaRepository.java b/src/main/java/com/tnt/trainee/infrastructure/PtGoalJpaRepository.java deleted file mode 100644 index 8e7598d4..00000000 --- a/src/main/java/com/tnt/trainee/infrastructure/PtGoalJpaRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.tnt.trainee.infrastructure; - -import java.util.List; - -import org.springframework.data.jpa.repository.JpaRepository; - -public interface PtGoalJpaRepository extends JpaRepository { - - List findAllByTraineeId(Long traineeId); -} diff --git a/src/main/java/com/tnt/trainee/infrastructure/PtGoalRepositoryImpl.java b/src/main/java/com/tnt/trainee/infrastructure/PtGoalRepositoryImpl.java deleted file mode 100644 index 398ca69d..00000000 --- a/src/main/java/com/tnt/trainee/infrastructure/PtGoalRepositoryImpl.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.tnt.trainee.infrastructure; - -import java.util.List; - -import org.springframework.stereotype.Repository; - -import com.tnt.trainee.application.repository.PtGoalRepository; -import com.tnt.trainee.domain.PtGoal; - -import lombok.RequiredArgsConstructor; - -@Repository -@RequiredArgsConstructor -public class PtGoalRepositoryImpl implements PtGoalRepository { - - private final PtGoalJpaRepository ptGoalJpaRepository; - - @Override - public List saveAll(List ptGoals) { - List ptGoalJpaEntities = ptGoals.stream() - .map(PtGoalJpaEntity::from) - .toList(); - - return ptGoalJpaRepository.saveAll(ptGoalJpaEntities).stream() - .map(PtGoalJpaEntity::toModel) - .toList(); - } - - @Override - public List findAllByTraineeId(Long traineeId) { - return ptGoalJpaRepository.findAllByTraineeId(traineeId).stream() - .map(PtGoalJpaEntity::toModel) - .toList(); - } - - @Override - public void deleteAll(List goalsToDelete) { - List ptGoalJpaEntities = goalsToDelete.stream() - .map(PtGoalJpaEntity::from) - .toList(); - - ptGoalJpaRepository.deleteAll(ptGoalJpaEntities); - } -} diff --git a/src/main/java/com/tnt/trainee/infrastructure/TraineeJpaEntity.java b/src/main/java/com/tnt/trainee/infrastructure/TraineeJpaEntity.java index 7d470c17..4607ffc5 100644 --- a/src/main/java/com/tnt/trainee/infrastructure/TraineeJpaEntity.java +++ b/src/main/java/com/tnt/trainee/infrastructure/TraineeJpaEntity.java @@ -4,13 +4,18 @@ import static java.util.Objects.requireNonNull; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import com.tnt.common.jpa.BaseTimeEntity; import com.tnt.member.infrastructure.MemberJpaEntity; +import com.tnt.trainee.domain.PtGoal; +import com.tnt.trainee.domain.PtGoalListConverter; import com.tnt.trainee.domain.Trainee; import io.hypersistence.utils.hibernate.id.Tsid; import jakarta.persistence.Column; +import jakarta.persistence.Convert; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.ForeignKey; @@ -50,14 +55,19 @@ public class TraineeJpaEntity extends BaseTimeEntity { @Column(name = "deleted_at", nullable = true) private LocalDateTime deletedAt; + @Convert(converter = PtGoalListConverter.class) + @Column(name = "pt_goals", columnDefinition = "TEXT", nullable = false) + private List ptGoals; + @Builder public TraineeJpaEntity(Long id, MemberJpaEntity member, Double height, Double weight, String cautionNote, - LocalDateTime deletedAt) { + List ptGoals, LocalDateTime deletedAt) { this.id = id; this.member = requireNonNull(member); this.height = height; this.weight = weight; this.cautionNote = cautionNote; + this.ptGoals = ptGoals != null ? new ArrayList<>(ptGoals) : new ArrayList<>(); this.deletedAt = deletedAt; } @@ -68,6 +78,7 @@ public static TraineeJpaEntity from(Trainee trainee) { .height(trainee.getHeight()) .weight(trainee.getWeight()) .cautionNote(trainee.getCautionNote()) + .ptGoals(trainee.getPtGoals()) .deletedAt(trainee.getDeletedAt()) .build(); } @@ -79,6 +90,7 @@ public Trainee toModel() { .height(height) .weight(weight) .cautionNote(cautionNote) + .ptGoals(ptGoals) .deletedAt(deletedAt) .build(); } diff --git a/src/main/java/com/tnt/trainer/dto/response/ConnectWithTraineeResponse.java b/src/main/java/com/tnt/trainer/dto/response/ConnectWithTraineeResponse.java index a9653692..449fd344 100644 --- a/src/main/java/com/tnt/trainer/dto/response/ConnectWithTraineeResponse.java +++ b/src/main/java/com/tnt/trainer/dto/response/ConnectWithTraineeResponse.java @@ -1,5 +1,9 @@ package com.tnt.trainer.dto.response; +import java.util.List; + +import com.tnt.trainee.domain.PtGoal; + import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "트레이니와 연결 응답 - 트레이너의 화면") @@ -37,8 +41,8 @@ public record ConnectTraineeInfo( @Schema(description = "트레이니 몸무게", example = "70.2kg", nullable = true) Double weight, - @Schema(description = "PT 목표", example = "체중 감량, 근력 향상, 건강 관리", nullable = false) - String ptGoal, + @Schema(description = "PT 목표", example = "[\"WEIGHT_LOSS\", \"STRENGTH_ENHANCE\"]", nullable = false) + List ptGoals, @Schema(description = "주의 사항", example = "왼쪽 발목 골절", nullable = true) String cautionNote diff --git a/src/main/java/com/tnt/trainer/dto/response/GetActiveTraineesResponse.java b/src/main/java/com/tnt/trainer/dto/response/GetActiveTraineesResponse.java index 7e4d3e7d..517c1bec 100644 --- a/src/main/java/com/tnt/trainer/dto/response/GetActiveTraineesResponse.java +++ b/src/main/java/com/tnt/trainer/dto/response/GetActiveTraineesResponse.java @@ -2,6 +2,8 @@ import java.util.List; +import com.tnt.trainee.domain.PtGoal; + import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "관리중인 트레이니 목록 응답") @@ -32,8 +34,8 @@ public record ActiveTraineeInfo( @Schema(description = "메모", example = "건강하지 않음", nullable = true) String memo, - @Schema(description = "PT 목적들", example = "[\"체중 감량\", \"근력 향상\"]", nullable = false) - List ptGoals + @Schema(description = "PT 목적", example = "[\"WEIGHT_LOSS\", \"STRENGTH_ENHANCE\"]", nullable = false) + List ptGoals ) { } diff --git a/src/main/resources/config b/src/main/resources/config index 095dc124..2a1ef66b 160000 --- a/src/main/resources/config +++ b/src/main/resources/config @@ -1 +1 @@ -Subproject commit 095dc1242730fd233ef34fae095d6125bfd8f3c8 +Subproject commit 2a1ef66b1afe41ea1acdbef9f0302cc35413c13d diff --git a/src/main/resources/db/migration/V1__add_pt_goals_column_to_trainee.sql b/src/main/resources/db/migration/V1__add_pt_goals_column_to_trainee.sql new file mode 100644 index 00000000..1f7e9a02 --- /dev/null +++ b/src/main/resources/db/migration/V1__add_pt_goals_column_to_trainee.sql @@ -0,0 +1,3 @@ +-- Add pt_goals column to trainee table +ALTER TABLE trainee +ADD COLUMN pt_goals TEXT NOT NULL DEFAULT '[]'; diff --git a/src/test/java/com/tnt/fixture/PtGoalsFixture.java b/src/test/java/com/tnt/fixture/PtGoalsFixture.java deleted file mode 100644 index 583aa56b..00000000 --- a/src/test/java/com/tnt/fixture/PtGoalsFixture.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.tnt.fixture; - -import java.util.List; - -import com.tnt.trainee.domain.PtGoal; - -public class PtGoalsFixture { - - public static List getPtGoals(Long traineeId) { - return List.of( - PtGoal.builder() - .traineeId(traineeId) - .content("체중 감량") - .build(), - PtGoal.builder() - .traineeId(traineeId) - .content("근력 향상") - .build() - ); - } -} diff --git a/src/test/java/com/tnt/fixture/TraineeFixture.java b/src/test/java/com/tnt/fixture/TraineeFixture.java index 6001bc55..d45f2e16 100644 --- a/src/test/java/com/tnt/fixture/TraineeFixture.java +++ b/src/test/java/com/tnt/fixture/TraineeFixture.java @@ -1,10 +1,19 @@ package com.tnt.fixture; +import static com.tnt.trainee.domain.PtGoal.STRENGTH_ENHANCE; +import static com.tnt.trainee.domain.PtGoal.WEIGHT_LOSS; + +import java.util.Arrays; +import java.util.List; + import com.tnt.member.domain.Member; +import com.tnt.trainee.domain.PtGoal; import com.tnt.trainee.domain.Trainee; public final class TraineeFixture { + static List ptGoals = Arrays.asList(WEIGHT_LOSS, STRENGTH_ENHANCE); + public static Trainee getTrainee1WithId(Member member) { Long traineeId = 1L; @@ -14,6 +23,7 @@ public static Trainee getTrainee1WithId(Member member) { .height(180.4) .weight(70.5) .cautionNote("주의사항00") + .ptGoals(ptGoals) .build(); } @@ -23,6 +33,7 @@ public static Trainee getTrainee1(Member member) { .height(170.5) .weight(60.5) .cautionNote("주의사항11") + .ptGoals(ptGoals) .build(); } @@ -32,6 +43,7 @@ public static Trainee getTrainee2(Member member) { .height(173.3) .weight(65.5) .cautionNote("주의사항22") + .ptGoals(ptGoals) .build(); } } diff --git a/src/test/java/com/tnt/member/application/SignUpServiceTest.java b/src/test/java/com/tnt/member/application/SignUpServiceTest.java index 9e5b6db9..beccb2d8 100644 --- a/src/test/java/com/tnt/member/application/SignUpServiceTest.java +++ b/src/test/java/com/tnt/member/application/SignUpServiceTest.java @@ -3,17 +3,18 @@ import static com.tnt.common.constant.ImageConstant.TRAINER_DEFAULT_IMAGE; import static com.tnt.common.error.model.ErrorMessage.MEMBER_CONFLICT; import static com.tnt.member.domain.MemberType.TRAINER; +import static com.tnt.trainee.domain.PtGoal.STRENGTH_ENHANCE; +import static com.tnt.trainee.domain.PtGoal.WEIGHT_LOSS; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; +import java.util.Arrays; import java.util.List; -import java.util.stream.Stream; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -29,7 +30,6 @@ import com.tnt.member.domain.Member; import com.tnt.member.dto.request.SignUpRequest; import com.tnt.member.dto.response.SignUpResponse; -import com.tnt.trainee.application.repository.PtGoalRepository; import com.tnt.trainee.application.repository.TraineeRepository; import com.tnt.trainee.domain.PtGoal; import com.tnt.trainee.domain.Trainee; @@ -57,9 +57,6 @@ class SignUpServiceTest { @Mock private TraineeRepository traineeRepository; - @Mock - private PtGoalRepository ptGoalRepository; - @Test @DisplayName("트레이너 회원가입 성공") void save_trainer_success() { @@ -90,19 +87,18 @@ void save_trainer_success() { void save_trainee_success() { // given Member traineeMember = MemberFixture.getTraineeMemberWithId1(); + List ptGoals = Arrays.asList(WEIGHT_LOSS, STRENGTH_ENHANCE); + List ptGoalStrings = Arrays.asList("체중 감량", "근력 향상"); given(memberRepository.save(any(Member.class))).willReturn(traineeMember); given(traineeRepository.save(any(Trainee.class))).willReturn( - Trainee.builder().id(1L).member(traineeMember).height(180.0).weight(75.0).build()); - given(ptGoalRepository.saveAll(anyList())).willReturn(Stream.of("목표1", "목표2") - .map(content -> PtGoal.builder().traineeId(traineeMember.getId()).content(content).build()) - .toList()); + Trainee.builder().id(1L).member(traineeMember).height(180.0).weight(75.0).ptGoals(ptGoals).build()); SignUpRequest request = new SignUpRequest(traineeMember.getFcmToken(), traineeMember.getMemberType(), traineeMember.getSocialType(), traineeMember.getSocialId(), traineeMember.getEmail(), traineeMember.getServiceAgreement(), traineeMember.getCollectionAgreement(), traineeMember.getAdvertisementAgreement(), traineeMember.getName(), traineeMember.getBirthday(), 180.0, - 75.0, "주의사항", List.of("목표1", "목표2")); + 75.0, "주의사항", ptGoalStrings); // when Long result = signUpService.signUp(request); @@ -111,7 +107,6 @@ void save_trainee_success() { assertThat(result).isNotNull().isEqualTo(traineeMember.getId()); verify(memberRepository).save(any(Member.class)); verify(traineeRepository).save(any(Trainee.class)); - verify(ptGoalRepository).saveAll(any()); } @Test diff --git a/src/test/java/com/tnt/member/application/WithdrawServiceTest.java b/src/test/java/com/tnt/member/application/WithdrawServiceTest.java index fa9aae20..f79e4ece 100644 --- a/src/test/java/com/tnt/member/application/WithdrawServiceTest.java +++ b/src/test/java/com/tnt/member/application/WithdrawServiceTest.java @@ -30,13 +30,10 @@ import com.tnt.pt.domain.PtLesson; import com.tnt.pt.domain.PtTrainerTrainee; import com.tnt.trainee.application.DietService; -import com.tnt.trainee.application.PtGoalService; import com.tnt.trainee.application.TraineeService; import com.tnt.trainee.application.repository.DietRepository; -import com.tnt.trainee.application.repository.PtGoalRepository; import com.tnt.trainee.application.repository.TraineeRepository; import com.tnt.trainee.domain.Diet; -import com.tnt.trainee.domain.PtGoal; import com.tnt.trainee.domain.Trainee; import com.tnt.trainer.application.TrainerService; import com.tnt.trainer.application.repository.TrainerRepository; @@ -57,9 +54,6 @@ class WithdrawServiceTest { @Mock private TraineeService traineeService; - @Mock - private PtGoalService ptGoalService; - @Mock private DietService dietService; @@ -81,9 +75,6 @@ class WithdrawServiceTest { @Mock private PtLessonRepository ptLessonRepository; - @Mock - private PtGoalRepository ptGoalRepository; - @Mock private DietRepository dietRepository; @@ -113,15 +104,10 @@ void withdraw_trainee_success() { // given Member traineeMember = MemberFixture.getTraineeMemberWithId1(); Trainee trainee = TraineeFixture.getTrainee1WithId(traineeMember); - - List ptGoals = List.of( - PtGoal.builder().id(1L).traineeId(trainee.getId()).content("test").build()); - List diets = List.of(DietFixture.getDiet1(trainee.getId()), - DietFixture.getDiet2(trainee.getId())); + List diets = List.of(DietFixture.getDiet1(trainee.getId()), DietFixture.getDiet2(trainee.getId())); given(memberService.getByMemberId(traineeMember.getId())).willReturn(traineeMember); given(traineeService.getByMemberId(traineeMember.getId())).willReturn(trainee); - given(ptGoalService.getAllByTraineeId(trainee.getId())).willReturn(ptGoals); given(dietService.getAllByTraineeId(trainee.getId())).willReturn(diets); given(dietRepository.saveAll(diets)).willReturn(diets); @@ -171,8 +157,6 @@ void withdraw_trainee_with_pt_success() { PtTrainerTrainee ptTrainerTrainee = PtTrainerTraineeFixture.getPtTrainerTrainee1(trainer, trainee); - List ptGoals = List.of( - PtGoal.builder().id(1L).traineeId(trainee.getId()).content("test").build()); List diets = List.of(DietFixture.getDiet1(trainee.getId()), DietFixture.getDiet2(trainee.getId())); @@ -181,7 +165,6 @@ void withdraw_trainee_with_pt_success() { given(memberService.getByMemberId(traineeMember.getId())).willReturn(traineeMember); given(traineeService.getByMemberId(traineeMember.getId())).willReturn(trainee); given(ptService.isPtTrainerTraineeExistWithTraineeId(trainee.getId())).willReturn(true); - given(ptGoalService.getAllByTraineeId(trainee.getId())).willReturn(ptGoals); given(dietService.getAllByTraineeId(trainee.getId())).willReturn(diets); given(ptService.getPtTrainerTraineeWithTraineeId(trainee.getId())).willReturn(ptTrainerTrainee); given(ptService.getPtLessonWithPtTrainerTrainee(ptTrainerTrainee)).willReturn(ptLessons); @@ -225,15 +208,12 @@ void withdraw_trainee_without_pt_success() { Trainee trainee = TraineeFixture.getTrainee1WithId(traineeMember); - List ptGoals = List.of( - PtGoal.builder().id(1L).traineeId(trainee.getId()).content("test").build()); List diets = List.of(DietFixture.getDiet1(trainee.getId()), DietFixture.getDiet2(trainee.getId())); given(memberService.getByMemberId(traineeMember.getId())).willReturn(traineeMember); given(traineeService.getByMemberId(traineeMember.getId())).willReturn(trainee); given(ptService.isPtTrainerTraineeExistWithTraineeId(trainee.getId())).willReturn(true); - given(ptGoalService.getAllByTraineeId(trainee.getId())).willReturn(ptGoals); given(dietService.getAllByTraineeId(trainee.getId())).willReturn(diets); given(ptService.getPtTrainerTraineeWithTraineeId(trainee.getId())).willThrow(NotFoundException.class); given(traineeRepository.save(trainee)).willReturn(trainee); diff --git a/src/test/java/com/tnt/member/presentation/MemberControllerTest.java b/src/test/java/com/tnt/member/presentation/MemberControllerTest.java index cbd2af41..100c58b4 100644 --- a/src/test/java/com/tnt/member/presentation/MemberControllerTest.java +++ b/src/test/java/com/tnt/member/presentation/MemberControllerTest.java @@ -5,6 +5,8 @@ import static com.tnt.member.domain.MemberType.TRAINEE; import static com.tnt.member.domain.MemberType.TRAINER; import static com.tnt.member.domain.SocialType.KAKAO; +import static com.tnt.trainee.domain.PtGoal.STRENGTH_ENHANCE; +import static com.tnt.trainee.domain.PtGoal.WEIGHT_LOSS; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.http.HttpMethod.PUT; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @@ -18,6 +20,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.time.LocalDate; +import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -46,7 +49,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.tnt.AbstractContainerBaseTest; import com.tnt.fixture.MemberFixture; -import com.tnt.fixture.PtGoalsFixture; import com.tnt.fixture.PtTrainerTraineeFixture; import com.tnt.fixture.TraineeFixture; import com.tnt.fixture.TrainerFixture; @@ -57,7 +59,6 @@ import com.tnt.member.dto.request.UpdateMemberInfoRequest; import com.tnt.pt.application.repository.PtTrainerTraineeRepository; import com.tnt.pt.domain.PtTrainerTrainee; -import com.tnt.trainee.application.repository.PtGoalRepository; import com.tnt.trainee.application.repository.TraineeRepository; import com.tnt.trainee.domain.PtGoal; import com.tnt.trainee.domain.Trainee; @@ -93,9 +94,6 @@ class MemberControllerTest extends AbstractContainerBaseTest { @Autowired private TraineeRepository traineeRepository; - @Autowired - private PtGoalRepository ptGoalRepository; - @Autowired private PtTrainerTraineeRepository ptTrainerTraineeRepository; @@ -104,7 +102,7 @@ class MemberControllerTest extends AbstractContainerBaseTest { void sign_up_trainer_success() throws Exception { // given SignUpRequest request = new SignUpRequest("fcm-token-test", TRAINER, KAKAO, "12345", "test@kakao.com", true, - true, true, "홍길동", LocalDate.of(1990, 1, 1), 175.0, 70.0, "테스트 주의사항", List.of("체중 감량", "근력 향상")); + true, true, "홍길동", LocalDate.of(1990, 1, 1), null, null, null, List.of()); // when var jsonRequest = new MockMultipartFile("request", "", APPLICATION_JSON_VALUE, @@ -126,8 +124,10 @@ void sign_up_trainer_success() throws Exception { @DisplayName("통합 테스트 - 트레이니 회원가입 성공") void sign_up_trainee_success() throws Exception { // given + List ptGoals = Arrays.asList("체중 감량", "근력 향상"); + SignUpRequest request = new SignUpRequest("fcm-token-test", TRAINEE, KAKAO, "12345", "test@kakao.com", true, - true, true, "홍길동", LocalDate.of(1990, 1, 1), 175.0, 70.0, "테스트 주의사항", List.of("체중 감량", "근력 향상")); + true, true, "홍길동", LocalDate.of(1990, 1, 1), 175.0, 70.0, "테스트 주의사항", ptGoals); // when var jsonRequest = new MockMultipartFile("request", "", APPLICATION_JSON_VALUE, @@ -149,8 +149,10 @@ void sign_up_trainee_success() throws Exception { @DisplayName("통합 테스트 - 필수 필드 누락으로 회원가입 실패") void sign_up_missing_required_field_fail() throws Exception { // given + List ptGoals = Arrays.asList("체중 감량", "근력 향상"); + SignUpRequest request = new SignUpRequest("", TRAINER, KAKAO, "12345", "test@kakao.com", true, - true, true, "홍길동", LocalDate.of(1990, 1, 1), 175.0, 70.0, "테스트 주의사항", List.of("체중 감량", "근력 향상")); + true, true, "홍길동", LocalDate.of(1990, 1, 1), 175.0, 70.0, "테스트 주의사항", ptGoals); // when var jsonRequest = new MockMultipartFile("request", "", APPLICATION_JSON_VALUE, @@ -248,10 +250,6 @@ void get_member_info_trainer_success() throws Exception { trainee2 = traineeRepository.save(trainee2); trainee3 = traineeRepository.save(trainee3); - List ptGoals = PtGoalsFixture.getPtGoals(trainee1.getId()); - - ptGoalRepository.saveAll(ptGoals); - PtTrainerTrainee ptTrainerTrainee = PtTrainerTraineeFixture.getPtTrainerTrainee1(trainer, trainee1); PtTrainerTrainee ptTrainerTrainee2 = PtTrainerTraineeFixture.getPtTrainerTrainee2(trainer, trainee2); PtTrainerTrainee ptTrainerTrainee3 = PtTrainerTraineeFixture.getPtTrainerTrainee2(trainer, trainee3); @@ -300,10 +298,6 @@ void get_member_info_trainee_success() throws Exception { trainer = trainerRepository.save(trainer); trainee = traineeRepository.save(trainee); - List ptGoals = PtGoalsFixture.getPtGoals(trainee.getId()); - - ptGoalRepository.saveAll(ptGoals); - PtTrainerTrainee ptTrainerTrainee = PtTrainerTraineeFixture.getPtTrainerTrainee1(trainer, trainee); ptTrainerTraineeRepository.save(ptTrainerTrainee); @@ -463,7 +457,7 @@ void update_member_info_trainer_success() throws Exception { trainerRepository.save(trainer); UpdateMemberInfoRequest request = new UpdateMemberInfoRequest(true, TRAINER, "홍길동", null, null, null, null, - null); + List.of()); // when & then var jsonRequest = new MockMultipartFile("request", "", APPLICATION_JSON_VALUE, @@ -501,12 +495,10 @@ void update_member_info_trainee_success() throws Exception { trainee = traineeRepository.save(trainee); - List ptGoals = PtGoalsFixture.getPtGoals(trainee.getId()); - - ptGoalRepository.saveAll(ptGoals); + List ptGoals = Arrays.asList(WEIGHT_LOSS, STRENGTH_ENHANCE); UpdateMemberInfoRequest request = new UpdateMemberInfoRequest(true, TRAINEE, "홍길동", LocalDate.of(1990, 1, 1), - 175.0, 70.0, "테스트 주의사항", List.of("체중 감량", "건강 관리")); + 175.0, 70.0, "테스트 주의사항", ptGoals); // when & then var jsonRequest = new MockMultipartFile("request", "", APPLICATION_JSON_VALUE, diff --git a/src/test/java/com/tnt/trainee/application/PtGoalServiceTest.java b/src/test/java/com/tnt/trainee/application/PtGoalServiceTest.java deleted file mode 100644 index c0f106ff..00000000 --- a/src/test/java/com/tnt/trainee/application/PtGoalServiceTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.tnt.trainee.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.verify; - -import java.util.List; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.tnt.trainee.application.repository.PtGoalRepository; -import com.tnt.trainee.domain.PtGoal; - -@ExtendWith(MockitoExtension.class) -class PtGoalServiceTest { - - @Mock - private PtGoalRepository ptGoalRepository; - - @InjectMocks - private PtGoalService ptGoalService; - - @Test - @DisplayName("traineeId로 PT 목표 목록 조회 성공") - void get_all_pt_goals_with_trainee_id_success() { - // given - Long traineeId = 1L; - List ptGoals = List.of( - PtGoal.builder() - .traineeId(traineeId) - .content("목표1") - .build(), - PtGoal.builder() - .traineeId(traineeId) - .content("목표2") - .build() - ); - - given(ptGoalRepository.findAllByTraineeId(traineeId)) - .willReturn(ptGoals); - - // when - List result = ptGoalService.getAllByTraineeId(traineeId); - - // then - assertThat(result).isNotNull().hasSize(2).isEqualTo(ptGoals); - verify(ptGoalRepository).findAllByTraineeId(traineeId); - } - - @Test - @DisplayName("PT 목표 목록 저장 성공") - void save_all_pt_goals_success() { - // given - List ptGoals = List.of( - PtGoal.builder() - .traineeId(1L) - .content("목표1") - .build(), - PtGoal.builder() - .traineeId(1L) - .content("목표2") - .build() - ); - - given(ptGoalRepository.saveAll(ptGoals)).willReturn(ptGoals); - - // when - List savedPtGoals = ptGoalRepository.saveAll(ptGoals); - - // then - assertThat(savedPtGoals).isNotNull().hasSize(2).isEqualTo(ptGoals); - verify(ptGoalRepository).saveAll(ptGoals); - } -} diff --git a/src/test/java/com/tnt/trainer/presentation/TrainerControllerTest.java b/src/test/java/com/tnt/trainer/presentation/TrainerControllerTest.java index 3874152e..dec74505 100644 --- a/src/test/java/com/tnt/trainer/presentation/TrainerControllerTest.java +++ b/src/test/java/com/tnt/trainer/presentation/TrainerControllerTest.java @@ -2,6 +2,8 @@ import static com.tnt.member.domain.MemberType.TRAINER; import static com.tnt.member.domain.SocialType.KAKAO; +import static com.tnt.trainee.domain.PtGoal.STRENGTH_ENHANCE; +import static com.tnt.trainee.domain.PtGoal.WEIGHT_LOSS; import static java.util.Comparator.comparing; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -13,6 +15,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; +import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -33,7 +36,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.tnt.annotation.WithMockCustomUser; import com.tnt.fixture.MemberFixture; -import com.tnt.fixture.PtGoalsFixture; import com.tnt.fixture.PtTrainerTraineeFixture; import com.tnt.fixture.TraineeFixture; import com.tnt.fixture.TrainerFixture; @@ -44,7 +46,6 @@ import com.tnt.pt.application.repository.PtTrainerTraineeRepository; import com.tnt.pt.domain.PtLesson; import com.tnt.pt.domain.PtTrainerTrainee; -import com.tnt.trainee.application.repository.PtGoalRepository; import com.tnt.trainee.application.repository.TraineeRepository; import com.tnt.trainee.domain.PtGoal; import com.tnt.trainee.domain.Trainee; @@ -78,9 +79,6 @@ class TrainerControllerTest { @Autowired private PtTrainerTraineeRepository ptTrainerTraineeRepository; - @Autowired - private PtGoalRepository ptGoalRepository; - @Autowired private PtLessonRepository ptLessonRepository; @@ -281,11 +279,14 @@ void get_first_connected_trainee_success() throws Exception { .member(trainerMember) .build(); + List ptGoals = Arrays.asList(WEIGHT_LOSS, STRENGTH_ENHANCE); + Trainee trainee = Trainee.builder() .member(traineeMember) .height(180.5) .weight(78.4) .cautionNote("주의사항") + .ptGoals(ptGoals) .build(); trainer = trainerRepository.save(trainer); @@ -295,18 +296,6 @@ void get_first_connected_trainee_success() throws Exception { ptTrainerTraineeRepository.save(ptTrainerTrainee); - PtGoal ptGoal1 = PtGoal.builder() - .traineeId(trainee.getId()) - .content("다이어트") - .build(); - - PtGoal ptGoal2 = PtGoal.builder() - .traineeId(trainee.getId()) - .content("체중 감량") - .build(); - - ptGoalRepository.saveAll(List.of(ptGoal1, ptGoal2)); - // when & then mockMvc.perform(get("/trainers/first-connected-trainee") .param("trainerId", trainer.getId().toString()) @@ -462,12 +451,6 @@ void get_active_trainees_success() throws Exception { trainee1 = traineeRepository.save(trainee1); trainee2 = traineeRepository.save(trainee2); - List ptGoals1 = PtGoalsFixture.getPtGoals(trainee1.getId()); - List ptGoals2 = PtGoalsFixture.getPtGoals(trainee2.getId()); - - ptGoalRepository.saveAll(ptGoals1); - ptGoalRepository.saveAll(ptGoals2); - PtTrainerTrainee ptTrainerTrainee1 = PtTrainerTraineeFixture.getPtTrainerTrainee1(trainer, trainee1); PtTrainerTrainee ptTrainerTrainee2 = PtTrainerTraineeFixture.getPtTrainerTrainee2(trainer, trainee2); @@ -516,11 +499,14 @@ void add_pt_lesson_success1() throws Exception { .member(trainerMember) .build(); + List ptGoals = Arrays.asList(WEIGHT_LOSS, STRENGTH_ENHANCE); + Trainee trainee = Trainee.builder() .member(traineeMember) .height(180.5) .weight(78.4) .cautionNote("주의사항") + .ptGoals(ptGoals) .build(); trainer = trainerRepository.save(trainer); @@ -529,18 +515,6 @@ void add_pt_lesson_success1() throws Exception { PtTrainerTrainee ptTrainerTrainee = PtTrainerTraineeFixture.getPtTrainerTrainee1(trainer, trainee); ptTrainerTraineeRepository.save(ptTrainerTrainee); - PtGoal ptGoal1 = PtGoal.builder() - .traineeId(trainee.getId()) - .content("다이어트") - .build(); - - PtGoal ptGoal2 = PtGoal.builder() - .traineeId(trainee.getId()) - .content("체중 감량") - .build(); - - ptGoalRepository.saveAll(List.of(ptGoal1, ptGoal2)); - LocalDateTime start = LocalDateTime.of(2025, 1, 1, 10, 0); LocalDateTime end = LocalDateTime.of(2025, 1, 1, 11, 0); String memo = "THIS IS MEMO"; @@ -588,18 +562,6 @@ void add_pt_lesson_success2() throws Exception { PtTrainerTrainee ptTrainerTrainee = PtTrainerTraineeFixture.getPtTrainerTrainee1(trainer, trainee); ptTrainerTrainee = ptTrainerTraineeRepository.save(ptTrainerTrainee); - PtGoal ptGoal1 = PtGoal.builder() - .traineeId(trainee.getId()) - .content("다이어트") - .build(); - - PtGoal ptGoal2 = PtGoal.builder() - .traineeId(trainee.getId()) - .content("체중 감량") - .build(); - - ptGoalRepository.saveAll(List.of(ptGoal1, ptGoal2)); - LocalDateTime startDate1 = LocalDateTime.parse("2025-02-01T11:30"); LocalDateTime endDate1 = LocalDateTime.parse("2025-02-01T13:00"); @@ -745,18 +707,6 @@ void add_pt_lesson_success4() throws Exception { PtTrainerTrainee ptTrainerTrainee = PtTrainerTraineeFixture.getPtTrainerTrainee1(trainer, trainee); ptTrainerTrainee = ptTrainerTraineeRepository.save(ptTrainerTrainee); - PtGoal ptGoal1 = PtGoal.builder() - .traineeId(trainee.getId()) - .content("다이어트") - .build(); - - PtGoal ptGoal2 = PtGoal.builder() - .traineeId(trainee.getId()) - .content("체중 감량") - .build(); - - ptGoalRepository.saveAll(List.of(ptGoal1, ptGoal2)); - LocalDateTime startDate1 = LocalDateTime.parse("2025-02-01T11:30"); LocalDateTime endDate1 = LocalDateTime.parse("2025-02-01T13:00"); @@ -897,18 +847,6 @@ void add_pt_lesson_fail1() throws Exception { PtTrainerTrainee ptTrainerTrainee = PtTrainerTraineeFixture.getPtTrainerTrainee1(trainer, trainee); ptTrainerTrainee = ptTrainerTraineeRepository.save(ptTrainerTrainee); - PtGoal ptGoal1 = PtGoal.builder() - .traineeId(trainee.getId()) - .content("다이어트") - .build(); - - PtGoal ptGoal2 = PtGoal.builder() - .traineeId(trainee.getId()) - .content("체중 감량") - .build(); - - ptGoalRepository.saveAll(List.of(ptGoal1, ptGoal2)); - LocalDateTime createdStart = LocalDateTime.of(2025, 1, 1, 10, 0); LocalDateTime createdEnd = LocalDateTime.of(2025, 1, 1, 11, 0);