From 83ffdca3ed266a38ec35be95a48dd2f8162cb4f2 Mon Sep 17 00:00:00 2001 From: KSH0326 Date: Mon, 22 Sep 2025 17:39:55 +0900 Subject: [PATCH 1/7] =?UTF-8?q?refect:=20=EB=94=94=EB=A0=89=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=20=EA=B5=AC=EC=A1=B0=20=EB=B0=8F=20plan=EC=9D=98=20?= =?UTF-8?q?=EA=B8=B0=EC=B4=88=20=EA=B5=AC=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Conflicts: # src/main/java/com/back/domain/studyroom/entity/Room.java --- .../plan/controller/StudyPlanController.java | 11 +++++++++++ .../domain/study/{ => plan}/entity/Color.java | 2 +- .../study/{ => plan}/entity/DayOfWeek.java | 2 +- .../study/{ => plan}/entity/Frequency.java | 2 +- .../study/{ => plan}/entity/RepeatRule.java | 2 +- .../study/{ => plan}/entity/RepeatType.java | 3 ++- .../study/{ => plan}/entity/StudyPlan.java | 5 +---- .../study/{ => plan}/entity/StudyStatus.java | 2 +- .../plan/repository/StudyPlanRepository.java | 8 ++++++++ .../study/plan/service/StudyPlanService.java | 16 ++++++++++++++++ .../study/{ => record}/entity/StudyRecord.java | 3 ++- .../domain/study/{ => todo}/entity/Todo.java | 3 ++- .../java/com/back/domain/user/entity/User.java | 4 ++-- 13 files changed, 49 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/back/domain/study/plan/controller/StudyPlanController.java rename src/main/java/com/back/domain/study/{ => plan}/entity/Color.java (62%) rename src/main/java/com/back/domain/study/{ => plan}/entity/DayOfWeek.java (60%) rename src/main/java/com/back/domain/study/{ => plan}/entity/Frequency.java (55%) rename src/main/java/com/back/domain/study/{ => plan}/entity/RepeatRule.java (92%) rename src/main/java/com/back/domain/study/{ => plan}/entity/RepeatType.java (50%) rename src/main/java/com/back/domain/study/{ => plan}/entity/StudyPlan.java (86%) rename src/main/java/com/back/domain/study/{ => plan}/entity/StudyStatus.java (50%) create mode 100644 src/main/java/com/back/domain/study/plan/repository/StudyPlanRepository.java create mode 100644 src/main/java/com/back/domain/study/plan/service/StudyPlanService.java rename src/main/java/com/back/domain/study/{ => record}/entity/StudyRecord.java (88%) rename src/main/java/com/back/domain/study/{ => todo}/entity/Todo.java (86%) diff --git a/src/main/java/com/back/domain/study/plan/controller/StudyPlanController.java b/src/main/java/com/back/domain/study/plan/controller/StudyPlanController.java new file mode 100644 index 00000000..38d16a88 --- /dev/null +++ b/src/main/java/com/back/domain/study/plan/controller/StudyPlanController.java @@ -0,0 +1,11 @@ +package com.back.domain.study.plan.controller; + +import com.back.domain.study.plan.service.StudyPlanService; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/plans") +public class StudyPlanController { + private final StudyPlanService studyPlanService; +} diff --git a/src/main/java/com/back/domain/study/entity/Color.java b/src/main/java/com/back/domain/study/plan/entity/Color.java similarity index 62% rename from src/main/java/com/back/domain/study/entity/Color.java rename to src/main/java/com/back/domain/study/plan/entity/Color.java index b265ca5f..c074e71e 100644 --- a/src/main/java/com/back/domain/study/entity/Color.java +++ b/src/main/java/com/back/domain/study/plan/entity/Color.java @@ -1,4 +1,4 @@ -package com.back.domain.study.entity; +package com.back.domain.study.plan.entity; public enum Color { RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, PINK diff --git a/src/main/java/com/back/domain/study/entity/DayOfWeek.java b/src/main/java/com/back/domain/study/plan/entity/DayOfWeek.java similarity index 60% rename from src/main/java/com/back/domain/study/entity/DayOfWeek.java rename to src/main/java/com/back/domain/study/plan/entity/DayOfWeek.java index 244e1a87..8127acd2 100644 --- a/src/main/java/com/back/domain/study/entity/DayOfWeek.java +++ b/src/main/java/com/back/domain/study/plan/entity/DayOfWeek.java @@ -1,4 +1,4 @@ -package com.back.domain.study.entity; +package com.back.domain.study.plan.entity; public enum DayOfWeek { MON, TUE, WED, THU, FRI, SAT, SUN diff --git a/src/main/java/com/back/domain/study/entity/Frequency.java b/src/main/java/com/back/domain/study/plan/entity/Frequency.java similarity index 55% rename from src/main/java/com/back/domain/study/entity/Frequency.java rename to src/main/java/com/back/domain/study/plan/entity/Frequency.java index 820b1e8f..cec35ef4 100644 --- a/src/main/java/com/back/domain/study/entity/Frequency.java +++ b/src/main/java/com/back/domain/study/plan/entity/Frequency.java @@ -1,4 +1,4 @@ -package com.back.domain.study.entity; +package com.back.domain.study.plan.entity; public enum Frequency { DAILY, WEEKLY, MONTHLY diff --git a/src/main/java/com/back/domain/study/entity/RepeatRule.java b/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java similarity index 92% rename from src/main/java/com/back/domain/study/entity/RepeatRule.java rename to src/main/java/com/back/domain/study/plan/entity/RepeatRule.java index 06329667..6886c9ef 100644 --- a/src/main/java/com/back/domain/study/entity/RepeatRule.java +++ b/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java @@ -1,4 +1,4 @@ -package com.back.domain.study.entity; +package com.back.domain.study.plan.entity; import com.back.global.entity.BaseEntity; import jakarta.persistence.*; diff --git a/src/main/java/com/back/domain/study/entity/RepeatType.java b/src/main/java/com/back/domain/study/plan/entity/RepeatType.java similarity index 50% rename from src/main/java/com/back/domain/study/entity/RepeatType.java rename to src/main/java/com/back/domain/study/plan/entity/RepeatType.java index d12a2a63..ff7238ba 100644 --- a/src/main/java/com/back/domain/study/entity/RepeatType.java +++ b/src/main/java/com/back/domain/study/plan/entity/RepeatType.java @@ -1,5 +1,6 @@ -package com.back.domain.study.entity; +package com.back.domain.study.plan.entity; +//삭제 예정 public enum RepeatType { NONE, DAILY, WEEKLY, MONTHLY } diff --git a/src/main/java/com/back/domain/study/entity/StudyPlan.java b/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java similarity index 86% rename from src/main/java/com/back/domain/study/entity/StudyPlan.java rename to src/main/java/com/back/domain/study/plan/entity/StudyPlan.java index 427db28d..5679e763 100644 --- a/src/main/java/com/back/domain/study/entity/StudyPlan.java +++ b/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java @@ -1,4 +1,4 @@ -package com.back.domain.study.entity; +package com.back.domain.study.plan.entity; import com.back.domain.user.entity.User; import com.back.global.entity.BaseEntity; @@ -28,9 +28,6 @@ public class StudyPlan extends BaseEntity { @Enumerated(EnumType.STRING) private Color color; - @Enumerated(EnumType.STRING) - private RepeatType repeatType; - @OneToOne(mappedBy = "studyPlan") private RepeatRule repeatRule; } diff --git a/src/main/java/com/back/domain/study/entity/StudyStatus.java b/src/main/java/com/back/domain/study/plan/entity/StudyStatus.java similarity index 50% rename from src/main/java/com/back/domain/study/entity/StudyStatus.java rename to src/main/java/com/back/domain/study/plan/entity/StudyStatus.java index eb953649..f50ddd08 100644 --- a/src/main/java/com/back/domain/study/entity/StudyStatus.java +++ b/src/main/java/com/back/domain/study/plan/entity/StudyStatus.java @@ -1,4 +1,4 @@ -package com.back.domain.study.entity; +package com.back.domain.study.plan.entity; public enum StudyStatus { TODO, DONE diff --git a/src/main/java/com/back/domain/study/plan/repository/StudyPlanRepository.java b/src/main/java/com/back/domain/study/plan/repository/StudyPlanRepository.java new file mode 100644 index 00000000..82f903f0 --- /dev/null +++ b/src/main/java/com/back/domain/study/plan/repository/StudyPlanRepository.java @@ -0,0 +1,8 @@ +package com.back.domain.study.plan.repository; + +import com.back.domain.study.plan.entity.StudyPlan; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface StudyPlanRepository extends JpaRepository { + +} diff --git a/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java b/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java new file mode 100644 index 00000000..790c7cd3 --- /dev/null +++ b/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java @@ -0,0 +1,16 @@ +package com.back.domain.study.plan.service; + +import com.back.domain.study.plan.repository.StudyPlanRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional +public class StudyPlanService{ + private final StudyPlanRepository studyPlanRepository; + + + +} diff --git a/src/main/java/com/back/domain/study/entity/StudyRecord.java b/src/main/java/com/back/domain/study/record/entity/StudyRecord.java similarity index 88% rename from src/main/java/com/back/domain/study/entity/StudyRecord.java rename to src/main/java/com/back/domain/study/record/entity/StudyRecord.java index ee892c52..8c48a417 100644 --- a/src/main/java/com/back/domain/study/entity/StudyRecord.java +++ b/src/main/java/com/back/domain/study/record/entity/StudyRecord.java @@ -1,5 +1,6 @@ -package com.back.domain.study.entity; +package com.back.domain.study.record.entity; +import com.back.domain.study.todo.entity.Todo; import com.back.domain.studyroom.entity.Room; import com.back.global.entity.BaseEntity; import jakarta.persistence.Entity; diff --git a/src/main/java/com/back/domain/study/entity/Todo.java b/src/main/java/com/back/domain/study/todo/entity/Todo.java similarity index 86% rename from src/main/java/com/back/domain/study/entity/Todo.java rename to src/main/java/com/back/domain/study/todo/entity/Todo.java index efafdc08..32223b0b 100644 --- a/src/main/java/com/back/domain/study/entity/Todo.java +++ b/src/main/java/com/back/domain/study/todo/entity/Todo.java @@ -1,5 +1,6 @@ -package com.back.domain.study.entity; +package com.back.domain.study.todo.entity; +import com.back.domain.study.record.entity.StudyRecord; import com.back.domain.user.entity.User; import com.back.global.entity.BaseEntity; import jakarta.persistence.*; diff --git a/src/main/java/com/back/domain/user/entity/User.java b/src/main/java/com/back/domain/user/entity/User.java index a08fb0b3..554aa564 100644 --- a/src/main/java/com/back/domain/user/entity/User.java +++ b/src/main/java/com/back/domain/user/entity/User.java @@ -2,8 +2,8 @@ import com.back.domain.board.entity.*; import com.back.domain.file.entity.FileAttachment; -import com.back.domain.study.entity.StudyPlan; -import com.back.domain.study.entity.Todo; +import com.back.domain.study.plan.entity.StudyPlan; +import com.back.domain.study.todo.entity.Todo; import com.back.domain.studyroom.entity.RoomChatMessage; import com.back.domain.studyroom.entity.RoomMember; import com.back.domain.studyroom.entity.RoomParticipantHistory; From e3e975bf00a1e86a88e691b5807fc0a3f5c09ee0 Mon Sep 17 00:00:00 2001 From: KSH0326 Date: Tue, 23 Sep 2025 10:08:19 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refect:=EC=97=94=ED=8B=B0=ED=8B=B0=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plan/controller/StudyPlanController.java | 4 ++++ .../domain/study/plan/entity/RepeatRule.java | 10 +++++++-- .../domain/study/plan/entity/StudyPlan.java | 21 ++++++++++++++++--- .../plan/repository/StudyPlanRepository.java | 2 ++ 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/back/domain/study/plan/controller/StudyPlanController.java b/src/main/java/com/back/domain/study/plan/controller/StudyPlanController.java index 38d16a88..3c87277b 100644 --- a/src/main/java/com/back/domain/study/plan/controller/StudyPlanController.java +++ b/src/main/java/com/back/domain/study/plan/controller/StudyPlanController.java @@ -1,11 +1,15 @@ package com.back.domain.study.plan.controller; import com.back.domain.study.plan.service.StudyPlanService; +import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController +@RequiredArgsConstructor @RequestMapping("/api/plans") public class StudyPlanController { private final StudyPlanService studyPlanService; + + } diff --git a/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java b/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java index 6886c9ef..053ffbfd 100644 --- a/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java +++ b/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java @@ -2,24 +2,30 @@ import com.back.global.entity.BaseEntity; import jakarta.persistence.*; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; import java.time.LocalDateTime; @Entity -@NoArgsConstructor @Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor public class RepeatRule extends BaseEntity { @OneToOne - @JoinColumn(name = "study_plan_id") + @JoinColumn(name = "study_plan_id", nullable = false) private StudyPlan studyPlan; @Enumerated(EnumType.STRING) private Frequency frequency; + @Column(name = "interval_value", nullable = false) private int RepeatInterval; + //필요 시 요일 지정 @Enumerated(EnumType.STRING) private DayOfWeek byDay; diff --git a/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java b/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java index 5679e763..b52f92c3 100644 --- a/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java +++ b/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java @@ -7,27 +7,42 @@ import lombok.NoArgsConstructor; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; @Entity @NoArgsConstructor @Getter public class StudyPlan extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id") + @JoinColumn(name = "user_id", nullable = false) private User user; + @Column(nullable = false, length = 100) private String subject; @Enumerated(EnumType.STRING) private StudyStatus status; - private LocalDateTime studyDate; + @Column(name = "start_date", nullable = false) + private LocalDateTime startDate; + @Column(name = "end_date", nullable = false) private LocalDateTime endDate; @Enumerated(EnumType.STRING) private Color color; - @OneToOne(mappedBy = "studyPlan") + // 부모 계획과의 연관관계 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_plan_id", + foreignKey = @ForeignKey(name = "fk_study_plan_parent")) + private StudyPlan parentPlan; + + // 자식 계획들과 연관관계 + @OneToMany(mappedBy = "parentPlan", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private List childPlans = new ArrayList<>(); + + @OneToOne(mappedBy = "studyPlan",cascade = CascadeType.ALL, fetch = FetchType.LAZY) private RepeatRule repeatRule; } diff --git a/src/main/java/com/back/domain/study/plan/repository/StudyPlanRepository.java b/src/main/java/com/back/domain/study/plan/repository/StudyPlanRepository.java index 82f903f0..53c35c4c 100644 --- a/src/main/java/com/back/domain/study/plan/repository/StudyPlanRepository.java +++ b/src/main/java/com/back/domain/study/plan/repository/StudyPlanRepository.java @@ -2,7 +2,9 @@ import com.back.domain.study.plan.entity.StudyPlan; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +@Repository public interface StudyPlanRepository extends JpaRepository { } From 347c5f80eb19f20b7e5ae16d76834edc7952c423 Mon Sep 17 00:00:00 2001 From: KSH0326 Date: Wed, 24 Sep 2025 09:18:54 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=EA=B8=B0=EC=B4=88=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=9D=BC=EB=B6=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plan/controller/StudyPlanController.java | 26 +++++- .../plan/dto/StudyPlanCreateRequest.java | 43 ++++++++++ .../study/plan/dto/StudyPlanResponse.java | 86 +++++++++++++++++++ .../domain/study/plan/entity/RepeatRule.java | 4 +- .../domain/study/plan/entity/StudyPlan.java | 4 +- .../domain/study/plan/entity/StudyStatus.java | 5 -- .../study/plan/service/StudyPlanService.java | 51 ++++++++++- 7 files changed, 207 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/back/domain/study/plan/dto/StudyPlanCreateRequest.java create mode 100644 src/main/java/com/back/domain/study/plan/dto/StudyPlanResponse.java delete mode 100644 src/main/java/com/back/domain/study/plan/entity/StudyStatus.java diff --git a/src/main/java/com/back/domain/study/plan/controller/StudyPlanController.java b/src/main/java/com/back/domain/study/plan/controller/StudyPlanController.java index 3c87277b..1745ccd0 100644 --- a/src/main/java/com/back/domain/study/plan/controller/StudyPlanController.java +++ b/src/main/java/com/back/domain/study/plan/controller/StudyPlanController.java @@ -1,9 +1,13 @@ package com.back.domain.study.plan.controller; +import com.back.domain.study.plan.dto.StudyPlanCreateRequest; +import com.back.domain.study.plan.dto.StudyPlanResponse; import com.back.domain.study.plan.service.StudyPlanService; +import com.back.global.common.dto.RsData; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor @@ -11,5 +15,23 @@ public class StudyPlanController { private final StudyPlanService studyPlanService; + @PostMapping + public ResponseEntity> createStudyPlan( + // 로그인 유저 정보 받기 @AuthenticationPrincipal CustomUserDetails user, + @RequestBody StudyPlanCreateRequest request) { + //커스텀 디테일 구현 시 사용 int userId = user.getId(); + Long userId = 1L; // 임시로 userId를 1로 설정 + StudyPlanResponse response = studyPlanService.createStudyPlan(userId, request); + return ResponseEntity.ok(RsData.success("학습 계획이 성공적으로 생성되었습니다.", response)); + } + + @DeleteMapping("/{planId}") + public ResponseEntity> deleteStudyPlan(@PathVariable Long planId) { + //studyPlanService.deleteStudyPlan(planId); + return ResponseEntity.ok(RsData.success("학습 계획이 성공적으로 삭제되었습니다.", null)); + } + + + } diff --git a/src/main/java/com/back/domain/study/plan/dto/StudyPlanCreateRequest.java b/src/main/java/com/back/domain/study/plan/dto/StudyPlanCreateRequest.java new file mode 100644 index 00000000..5b5bfbcd --- /dev/null +++ b/src/main/java/com/back/domain/study/plan/dto/StudyPlanCreateRequest.java @@ -0,0 +1,43 @@ +package com.back.domain.study.plan.dto; + +import com.back.domain.study.plan.entity.Color; +import com.back.domain.study.plan.entity.Frequency; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class StudyPlanCreateRequest { + private String subject; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime startDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime endDate; + + private Color color; + + // RepeatRule 중첩 객체 + private RepeatRuleRequest repeatRule; + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class RepeatRuleRequest { + private Frequency frequency; + private Integer intervalValue; + private String byDay; // "MON" 형태의 문자열 + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private String untilDate; // "2025-12-31" 형태 + } +} diff --git a/src/main/java/com/back/domain/study/plan/dto/StudyPlanResponse.java b/src/main/java/com/back/domain/study/plan/dto/StudyPlanResponse.java new file mode 100644 index 00000000..1daa5390 --- /dev/null +++ b/src/main/java/com/back/domain/study/plan/dto/StudyPlanResponse.java @@ -0,0 +1,86 @@ +package com.back.domain.study.plan.dto; + +import com.back.domain.study.plan.entity.Color; +import com.back.domain.study.plan.entity.Frequency; +import com.back.domain.study.plan.entity.StudyPlan; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class StudyPlanResponse { + private Long id; + private String subject; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime startDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime endDate; + + private Color color; + + private Long parentPlanId; + private List childPlans; + + // RepeatRule 정보 + private RepeatRuleResponse repeatRule; + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class RepeatRuleResponse { + private Frequency frequency; + private Integer repeatInterval; + private String byDay; // "MON" 형태의 문자열 + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime until; + + public RepeatRuleResponse(com.back.domain.study.plan.entity.RepeatRule repeatRule) { + if (repeatRule != null) { + this.frequency = repeatRule.getFrequency(); + this.repeatInterval = repeatRule.getRepeatInterval(); + this.byDay = repeatRule.getByDay(); + this.until = repeatRule.getUntilDate(); + } + } + } + //엔티티를 DTO로 변환하는 생성자 + public StudyPlanResponse(StudyPlan studyPlan) { + if (studyPlan != null) { + this.id = studyPlan.getId(); + this.subject = studyPlan.getSubject(); + this.startDate = studyPlan.getStartDate(); + this.endDate = studyPlan.getEndDate(); + this.color = studyPlan.getColor(); + + // 부모 계획 ID 설정 + if (studyPlan.getParentPlan() != null) { + this.parentPlanId = studyPlan.getParentPlan().getId(); + } + + // 자식 계획들 변환 + if (studyPlan.getChildPlans() != null && !studyPlan.getChildPlans().isEmpty()) { + this.childPlans = studyPlan.getChildPlans().stream() + .map(StudyPlanResponse::new) + .collect(Collectors.toList()); + } + + // RepeatRule 변환 + if (studyPlan.getRepeatRule() != null) { + this.repeatRule = new RepeatRuleResponse(studyPlan.getRepeatRule()); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java b/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java index 053ffbfd..2345240e 100644 --- a/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java +++ b/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java @@ -27,7 +27,7 @@ public class RepeatRule extends BaseEntity { //필요 시 요일 지정 @Enumerated(EnumType.STRING) - private DayOfWeek byDay; + private String byDay; - private LocalDateTime until; + private LocalDateTime untilDate; } diff --git a/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java b/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java index b52f92c3..afdbde64 100644 --- a/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java +++ b/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java @@ -5,6 +5,7 @@ import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; import java.time.LocalDateTime; import java.util.ArrayList; @@ -13,6 +14,7 @@ @Entity @NoArgsConstructor @Getter +@Setter public class StudyPlan extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", nullable = false) @@ -21,8 +23,6 @@ public class StudyPlan extends BaseEntity { @Column(nullable = false, length = 100) private String subject; - @Enumerated(EnumType.STRING) - private StudyStatus status; @Column(name = "start_date", nullable = false) private LocalDateTime startDate; diff --git a/src/main/java/com/back/domain/study/plan/entity/StudyStatus.java b/src/main/java/com/back/domain/study/plan/entity/StudyStatus.java deleted file mode 100644 index f50ddd08..00000000 --- a/src/main/java/com/back/domain/study/plan/entity/StudyStatus.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.back.domain.study.plan.entity; - -public enum StudyStatus { - TODO, DONE -} diff --git a/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java b/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java index 790c7cd3..8f8d51f3 100644 --- a/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java +++ b/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java @@ -1,16 +1,65 @@ package com.back.domain.study.plan.service; +import com.back.domain.study.plan.dto.StudyPlanCreateRequest; +import com.back.domain.study.plan.dto.StudyPlanResponse; +import com.back.domain.study.plan.entity.RepeatRule; +import com.back.domain.study.plan.entity.StudyPlan; +import com.back.domain.study.plan.entity.StudyStatus; import com.back.domain.study.plan.repository.StudyPlanRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; + @Service @RequiredArgsConstructor -@Transactional +@Transactional(readOnly = true) public class StudyPlanService{ private final StudyPlanRepository studyPlanRepository; + @Transactional + public StudyPlanResponse createStudyPlan(Long userId, StudyPlanCreateRequest request) { + + StudyPlan studyPlan = new StudyPlan(); + //studyPlan.setUser(user); + studyPlan.setSubject(request.getSubject()); + studyPlan.setStatus(StudyStatus.TODO); + studyPlan.setStartDate(request.getStartDate()); + studyPlan.setEndDate(request.getEndDate()); + studyPlan.setColor(request.getColor()); + studyPlan.setParentPlan(null); + + // 반복 규칙 설정 + if (request.getRepeatRule() != null) { + StudyPlanCreateRequest.RepeatRuleRequest repeatRuleRequest = request.getRepeatRule(); + RepeatRule repeatRule = new RepeatRule(); + repeatRule.setStudyPlan(studyPlan); + repeatRule.setFrequency(repeatRuleRequest.getFrequency()); + repeatRule.setRepeatInterval(repeatRuleRequest.getIntervalValue() != null ? repeatRuleRequest.getIntervalValue() : 1); + + // byDay 문자열 그대로 저장 + if (repeatRuleRequest.getByDay() != null && !repeatRuleRequest.getByDay().isEmpty()) { + repeatRule.setByDay(repeatRuleRequest.getByDay()); + } + + // untilDate 문자열을 LocalDateTime으로 변환 + if (repeatRuleRequest.getUntilDate() != null && !repeatRuleRequest.getUntilDate().isEmpty()) { + try { + LocalDateTime untilDateTime = LocalDateTime.parse(repeatRuleRequest.getUntilDate() + "T23:59:59"); + repeatRule.setUntilDate(untilDateTime); + } catch (Exception e) { + // 날짜 파싱 실패 시 무시하거나 예외 처리 + } + } + + studyPlan.setRepeatRule(repeatRule); + } + + StudyPlan savedStudyPlan = studyPlanRepository.save(studyPlan); + return convertToResponse(savedStudyPlan); + } + } From 62c43d73b48ddaaeed205a243f863422e9488318 Mon Sep 17 00:00:00 2001 From: KSH0326 Date: Wed, 24 Sep 2025 09:38:22 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=EC=98=88=EC=99=B8=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=9D=BC?= =?UTF-8?q?=EB=B6=80=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/study/plan/entity/StudyPlan.java | 7 +++ .../study/plan/entity/StudyPlanException.java | 63 +++++++++++++++++++ .../study/record/entity/StudyRecord.java | 5 +- .../back/domain/study/todo/entity/Todo.java | 2 - 4 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/back/domain/study/plan/entity/StudyPlanException.java diff --git a/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java b/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java index afdbde64..04250b4e 100644 --- a/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java +++ b/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java @@ -1,5 +1,6 @@ package com.back.domain.study.plan.entity; +import com.back.domain.study.record.entity.StudyRecord; import com.back.domain.user.entity.User; import com.back.global.entity.BaseEntity; import jakarta.persistence.*; @@ -45,4 +46,10 @@ public class StudyPlan extends BaseEntity { @OneToOne(mappedBy = "studyPlan",cascade = CascadeType.ALL, fetch = FetchType.LAZY) private RepeatRule repeatRule; + + @OneToMany(mappedBy = "todo", cascade = CascadeType.ALL, orphanRemoval = true) + private List studyRecords; + + @OneToMany(mappedBy = "studyPlan", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private List exceptions = new ArrayList<>(); } diff --git a/src/main/java/com/back/domain/study/plan/entity/StudyPlanException.java b/src/main/java/com/back/domain/study/plan/entity/StudyPlanException.java new file mode 100644 index 00000000..5c94a3c1 --- /dev/null +++ b/src/main/java/com/back/domain/study/plan/entity/StudyPlanException.java @@ -0,0 +1,63 @@ +package com.back.domain.study.plan.entity; + +import com.back.global.entity.BaseEntity; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "study_plan_exception") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +//이후 날짜 반복 계획 모두 삭제는 원본 엔티티의 untilDate를 수정해 구현 +//단일 삭제 또는 단일, 이후 모두 수정은 이 엔티티로 구현 +public class StudyPlanException extends BaseEntity { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "study_plan_id", nullable = false) + private StudyPlan studyPlan; + + // 예외가 발생한 날짜 + @Column(name = "exception_date", nullable = false) + private LocalDateTime exceptionDate; + + //예외 유형 (수정 / 삭제) + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private ExceptionType exceptionType; + + // 적용 범위 (이 날짜만 / 이후 모든 날짜) + @Enumerated(EnumType.STRING) + @Column(name = "apply_scope") + private ApplyScope applyScope; + + // 수정된 내용 (MODIFIED 타입인 경우) + @Column(name = "modified_subject") + private String modifiedSubject; + + @Column(name = "modified_start_date") + private LocalDateTime modifiedStartDate; + + @Column(name = "modified_end_date") + private LocalDateTime modifiedEndDate; + + @Enumerated(EnumType.STRING) + @Column(name = "modified_color") + private Color modifiedColor; + + public enum ExceptionType { + DELETED, // 해당 날짜 삭제 + MODIFIED // 해당 날짜 수정 + } + + public enum ApplyScope { + THIS_ONLY, // 이 날짜만 + FROM_THIS_DATE // 이 날짜부터 이후 모든 날짜 + } +} \ No newline at end of file diff --git a/src/main/java/com/back/domain/study/record/entity/StudyRecord.java b/src/main/java/com/back/domain/study/record/entity/StudyRecord.java index 8c48a417..fd800571 100644 --- a/src/main/java/com/back/domain/study/record/entity/StudyRecord.java +++ b/src/main/java/com/back/domain/study/record/entity/StudyRecord.java @@ -1,5 +1,6 @@ package com.back.domain.study.record.entity; +import com.back.domain.study.plan.entity.StudyPlan; import com.back.domain.study.todo.entity.Todo; import com.back.domain.studyroom.entity.Room; import com.back.global.entity.BaseEntity; @@ -17,8 +18,8 @@ @Getter public class StudyRecord extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "todo_id") - private Todo todo; + @JoinColumn(name = "plan_id") + private StudyPlan plan; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "room_id") diff --git a/src/main/java/com/back/domain/study/todo/entity/Todo.java b/src/main/java/com/back/domain/study/todo/entity/Todo.java index 32223b0b..73c606a2 100644 --- a/src/main/java/com/back/domain/study/todo/entity/Todo.java +++ b/src/main/java/com/back/domain/study/todo/entity/Todo.java @@ -24,6 +24,4 @@ public class Todo extends BaseEntity { private LocalDateTime date; - @OneToMany(mappedBy = "todo", cascade = CascadeType.ALL, orphanRemoval = true) - private List studyRecords; } From d2a7fea6426f14b8a983dc6476b7f94e5f433ee6 Mon Sep 17 00:00:00 2001 From: KSH0326 Date: Wed, 24 Sep 2025 09:46:50 +0900 Subject: [PATCH 5/7] =?UTF-8?q?fix:=20room=EC=97=90=EC=84=9C=20import=20re?= =?UTF-8?q?cord=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/back/domain/studyroom/entity/Room.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/back/domain/studyroom/entity/Room.java b/src/main/java/com/back/domain/studyroom/entity/Room.java index 706f2c90..e07fd5a6 100644 --- a/src/main/java/com/back/domain/studyroom/entity/Room.java +++ b/src/main/java/com/back/domain/studyroom/entity/Room.java @@ -1,6 +1,6 @@ package com.back.domain.studyroom.entity; -import com.back.domain.study.entity.StudyRecord; +import com.back.domain.study.record.entity.StudyRecord; import com.back.domain.user.entity.User; import com.back.global.entity.BaseEntity; import jakarta.persistence.*; From bf16898efb2248779aa24fe0ead5c07f9f240212 Mon Sep 17 00:00:00 2001 From: KSH0326 Date: Wed, 24 Sep 2025 09:55:08 +0900 Subject: [PATCH 6/7] fix: planService return error fix --- .../back/domain/study/plan/service/StudyPlanService.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java b/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java index 8f8d51f3..66cee51e 100644 --- a/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java +++ b/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java @@ -4,7 +4,6 @@ import com.back.domain.study.plan.dto.StudyPlanResponse; import com.back.domain.study.plan.entity.RepeatRule; import com.back.domain.study.plan.entity.StudyPlan; -import com.back.domain.study.plan.entity.StudyStatus; import com.back.domain.study.plan.repository.StudyPlanRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -24,7 +23,6 @@ public StudyPlanResponse createStudyPlan(Long userId, StudyPlanCreateRequest req StudyPlan studyPlan = new StudyPlan(); //studyPlan.setUser(user); studyPlan.setSubject(request.getSubject()); - studyPlan.setStatus(StudyStatus.TODO); studyPlan.setStartDate(request.getStartDate()); studyPlan.setEndDate(request.getEndDate()); studyPlan.setColor(request.getColor()); @@ -56,8 +54,8 @@ public StudyPlanResponse createStudyPlan(Long userId, StudyPlanCreateRequest req studyPlan.setRepeatRule(repeatRule); } - StudyPlan savedStudyPlan = studyPlanRepository.save(studyPlan); - return convertToResponse(savedStudyPlan); + StudyPlanResponse rs =new StudyPlanResponse(studyPlanRepository.save(studyPlan)); + return rs; } From 308c76394d01f4f4cf7ad6c3ed105f8aaa0adec1 Mon Sep 17 00:00:00 2001 From: KSH0326 Date: Wed, 24 Sep 2025 10:44:13 +0900 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20entity=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EC=A4=91=20=EC=97=90=EB=9F=AC=20=EB=B0=9C=EC=83=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/plan/dto/StudyPlanResponse.java | 24 ++++++++++--------- .../domain/study/plan/entity/RepeatRule.java | 7 +++--- .../domain/study/plan/entity/StudyPlan.java | 12 ++-------- .../study/plan/service/StudyPlanService.java | 2 +- .../study/record/entity/StudyRecord.java | 3 +-- 5 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/back/domain/study/plan/dto/StudyPlanResponse.java b/src/main/java/com/back/domain/study/plan/dto/StudyPlanResponse.java index 1daa5390..1f204e29 100644 --- a/src/main/java/com/back/domain/study/plan/dto/StudyPlanResponse.java +++ b/src/main/java/com/back/domain/study/plan/dto/StudyPlanResponse.java @@ -1,6 +1,7 @@ package com.back.domain.study.plan.dto; import com.back.domain.study.plan.entity.Color; +import com.back.domain.study.plan.entity.DayOfWeek; import com.back.domain.study.plan.entity.Frequency; import com.back.domain.study.plan.entity.StudyPlan; import com.fasterxml.jackson.annotation.JsonFormat; @@ -10,6 +11,7 @@ import lombok.Setter; import java.time.LocalDateTime; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -55,6 +57,17 @@ public RepeatRuleResponse(com.back.domain.study.plan.entity.RepeatRule repeatRul this.until = repeatRule.getUntilDate(); } } + + // 요일을 리스트로 접근 ("MON,TUE" -> [MON, TUE]) + public List getByDaysList() { + if (byDay == null || byDay.isEmpty()) { + return List.of(); + } + return Arrays.stream(byDay.split(",")) + .map(String::trim) + .map(com.back.domain.study.plan.entity.DayOfWeek::valueOf) + .collect(Collectors.toList()); + } } //엔티티를 DTO로 변환하는 생성자 public StudyPlanResponse(StudyPlan studyPlan) { @@ -65,17 +78,6 @@ public StudyPlanResponse(StudyPlan studyPlan) { this.endDate = studyPlan.getEndDate(); this.color = studyPlan.getColor(); - // 부모 계획 ID 설정 - if (studyPlan.getParentPlan() != null) { - this.parentPlanId = studyPlan.getParentPlan().getId(); - } - - // 자식 계획들 변환 - if (studyPlan.getChildPlans() != null && !studyPlan.getChildPlans().isEmpty()) { - this.childPlans = studyPlan.getChildPlans().stream() - .map(StudyPlanResponse::new) - .collect(Collectors.toList()); - } // RepeatRule 변환 if (studyPlan.getRepeatRule() != null) { diff --git a/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java b/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java index 2345240e..1d7c7120 100644 --- a/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java +++ b/src/main/java/com/back/domain/study/plan/entity/RepeatRule.java @@ -16,7 +16,7 @@ @AllArgsConstructor public class RepeatRule extends BaseEntity { @OneToOne - @JoinColumn(name = "study_plan_id", nullable = false) + @JoinColumn(name = "plan_id", nullable = false) private StudyPlan studyPlan; @Enumerated(EnumType.STRING) @@ -25,8 +25,9 @@ public class RepeatRule extends BaseEntity { @Column(name = "interval_value", nullable = false) private int RepeatInterval; - //필요 시 요일 지정 - @Enumerated(EnumType.STRING) + //필요 시 요일 지정. 여러 요일 지정 시 ,로 구분 + //현재는 요일 하나만 지정하는 형태로 구현 + @Column(name = "by_day") private String byDay; private LocalDateTime untilDate; diff --git a/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java b/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java index 04250b4e..f992b165 100644 --- a/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java +++ b/src/main/java/com/back/domain/study/plan/entity/StudyPlan.java @@ -34,22 +34,14 @@ public class StudyPlan extends BaseEntity { @Enumerated(EnumType.STRING) private Color color; - // 부모 계획과의 연관관계 - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "parent_plan_id", - foreignKey = @ForeignKey(name = "fk_study_plan_parent")) - private StudyPlan parentPlan; - - // 자식 계획들과 연관관계 - @OneToMany(mappedBy = "parentPlan", cascade = CascadeType.ALL, fetch = FetchType.LAZY) - private List childPlans = new ArrayList<>(); @OneToOne(mappedBy = "studyPlan",cascade = CascadeType.ALL, fetch = FetchType.LAZY) private RepeatRule repeatRule; - @OneToMany(mappedBy = "todo", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(mappedBy = "studyPlan", cascade = CascadeType.ALL, orphanRemoval = true) private List studyRecords; + //반복 주기 설정 시 예외 리스트 @OneToMany(mappedBy = "studyPlan", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private List exceptions = new ArrayList<>(); } diff --git a/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java b/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java index 66cee51e..306bf9d8 100644 --- a/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java +++ b/src/main/java/com/back/domain/study/plan/service/StudyPlanService.java @@ -26,7 +26,6 @@ public StudyPlanResponse createStudyPlan(Long userId, StudyPlanCreateRequest req studyPlan.setStartDate(request.getStartDate()); studyPlan.setEndDate(request.getEndDate()); studyPlan.setColor(request.getColor()); - studyPlan.setParentPlan(null); // 반복 규칙 설정 if (request.getRepeatRule() != null) { @@ -54,6 +53,7 @@ public StudyPlanResponse createStudyPlan(Long userId, StudyPlanCreateRequest req studyPlan.setRepeatRule(repeatRule); } + //추후 변수명이나 리턴 형식은 수정 예정 StudyPlanResponse rs =new StudyPlanResponse(studyPlanRepository.save(studyPlan)); return rs; } diff --git a/src/main/java/com/back/domain/study/record/entity/StudyRecord.java b/src/main/java/com/back/domain/study/record/entity/StudyRecord.java index fd800571..100a0110 100644 --- a/src/main/java/com/back/domain/study/record/entity/StudyRecord.java +++ b/src/main/java/com/back/domain/study/record/entity/StudyRecord.java @@ -1,7 +1,6 @@ package com.back.domain.study.record.entity; import com.back.domain.study.plan.entity.StudyPlan; -import com.back.domain.study.todo.entity.Todo; import com.back.domain.studyroom.entity.Room; import com.back.global.entity.BaseEntity; import jakarta.persistence.Entity; @@ -19,7 +18,7 @@ public class StudyRecord extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "plan_id") - private StudyPlan plan; + private StudyPlan studyPlan; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "room_id")