diff --git a/src/main/java/com/indayvidual/server/domain/todo/controller/TodoCategoryController.java b/src/main/java/com/indayvidual/server/domain/todo/controller/TodoCategoryController.java index e10d659..a708575 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/controller/TodoCategoryController.java +++ b/src/main/java/com/indayvidual/server/domain/todo/controller/TodoCategoryController.java @@ -45,4 +45,17 @@ public ApiResponse> getCategories() { SuccessStatus.GET_CATEGORIES_SUCCESS.getCode(), SuccessStatus.GET_CATEGORIES_SUCCESS.getMessage()); } + + @Operation(summary = "카테고리 삭제", description = """ + 카테고리를 삭제합니다.\n + **카테고리 내 할 일도 모두 삭제됩니다.**""") + @DeleteMapping("/{categoryId}") + public ApiResponse deleteCategory(@PathVariable Long categoryId) { + Long userId = Utils.getUserId(); + categoryCommandService.delete(userId, categoryId); + return ApiResponse.onSuccess( + null, + SuccessStatus.DELETE_CATEGORY_SUCCESS.getCode(), + SuccessStatus.DELETE_CATEGORY_SUCCESS.getMessage()); + } } diff --git a/src/main/java/com/indayvidual/server/domain/todo/controller/TodoTaskController.java b/src/main/java/com/indayvidual/server/domain/todo/controller/TodoTaskController.java index ad70f4c..177db3c 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/controller/TodoTaskController.java +++ b/src/main/java/com/indayvidual/server/domain/todo/controller/TodoTaskController.java @@ -2,6 +2,7 @@ import com.indayvidual.server.domain.todo.dto.request.*; import com.indayvidual.server.domain.todo.dto.response.TaskCheckUpdateResponseDTO; +import com.indayvidual.server.domain.todo.dto.response.TaskOrderCategoryUpdateResponseDTO; import com.indayvidual.server.domain.todo.dto.response.TaskResponseDTO; import com.indayvidual.server.domain.todo.dto.response.TaskUpdateResponseDTO; import com.indayvidual.server.domain.todo.service.task.TaskCommandService; @@ -110,22 +111,18 @@ public ApiResponse updateTaskStatus(@PathVariable Lo SuccessStatus.UPDATE_TASK_CHECK_SUCCESS.getMessage()); } - @Operation(summary = "할 일 순서 변경", + @Operation(summary = "할 일 순서 및 카테고리 변경", description = """ - 카테고리 내 할 일의 순서를 변경합니다.\n - **해당 카테고리 내 모든 Task ID**를 정렬 순서대로 request body로 전달해야 합니다.\n - 해당 순서를 기준으로 `position` 필드를 재정렬합니다. + 할 일의 순서 또는 카테고리를 변경합니다.\n + 순서/카테고리가 변경되는 모든 `task`의 정보를 포함해야 합니다. """) - @PatchMapping("/categories/{categoryId}/tasks/order") - public ApiResponse updateTaskOrder( - @PathVariable Long categoryId, - @RequestBody @Valid TaskOrderUpdateRequestDTO request) { + @PatchMapping("/tasks/order") + public ApiResponse updateTaskOrder( + @RequestBody @Valid TaskOrderCategoryUpdateBulkRequestDTO request) { - //TODO : 카테고리 변경도 추가하기 Long userId = Utils.getUserId(); - taskCommandService.updateTaskOrder(userId, categoryId, request); return ApiResponse.onSuccess( - null, + taskCommandService.updateTaskOrders(userId, request), SuccessStatus.UPDATE_TASK_ORDER_SUCCESS.getCode(), SuccessStatus.UPDATE_TASK_ORDER_SUCCESS.getMessage()); } diff --git a/src/main/java/com/indayvidual/server/domain/todo/dto/request/TaskOrderCategoryUpdateBulkRequestDTO.java b/src/main/java/com/indayvidual/server/domain/todo/dto/request/TaskOrderCategoryUpdateBulkRequestDTO.java new file mode 100644 index 0000000..ce04d24 --- /dev/null +++ b/src/main/java/com/indayvidual/server/domain/todo/dto/request/TaskOrderCategoryUpdateBulkRequestDTO.java @@ -0,0 +1,13 @@ +package com.indayvidual.server.domain.todo.dto.request; + +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +import java.util.List; + +@Data +public class TaskOrderCategoryUpdateBulkRequestDTO { + + @NotEmpty(message = "tasks 리스트는 비어 있을 수 없습니다.") + private List tasks; +} diff --git a/src/main/java/com/indayvidual/server/domain/todo/dto/request/TaskOrderCategoryUpdateRequestDTO.java b/src/main/java/com/indayvidual/server/domain/todo/dto/request/TaskOrderCategoryUpdateRequestDTO.java new file mode 100644 index 0000000..571c309 --- /dev/null +++ b/src/main/java/com/indayvidual/server/domain/todo/dto/request/TaskOrderCategoryUpdateRequestDTO.java @@ -0,0 +1,19 @@ +package com.indayvidual.server.domain.todo.dto.request; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class TaskOrderCategoryUpdateRequestDTO { + + @NotNull(message = "taskId는 필수입니다.") + private Long taskId; + + @NotNull(message = "categoryId는 필수입니다.") + private Long categoryId; + + @NotNull(message = "order는 필수입니다.") + @Min(value = 0, message = "order는 0 이상이어야 합니다.") + private Integer order; +} \ No newline at end of file diff --git a/src/main/java/com/indayvidual/server/domain/todo/dto/request/TaskOrderUpdateRequestDTO.java b/src/main/java/com/indayvidual/server/domain/todo/dto/request/TaskOrderUpdateRequestDTO.java deleted file mode 100644 index f825409..0000000 --- a/src/main/java/com/indayvidual/server/domain/todo/dto/request/TaskOrderUpdateRequestDTO.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.indayvidual.server.domain.todo.dto.request; - -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; - -import java.util.List; - -@Data -public class TaskOrderUpdateRequestDTO { - - @NotEmpty(message = "taskOrder 리스트는 비어 있을 수 없습니다.") - private List taskOrder; -} diff --git a/src/main/java/com/indayvidual/server/domain/todo/dto/response/TaskOrderCategoryUpdateResponseDTO.java b/src/main/java/com/indayvidual/server/domain/todo/dto/response/TaskOrderCategoryUpdateResponseDTO.java new file mode 100644 index 0000000..e30e2aa --- /dev/null +++ b/src/main/java/com/indayvidual/server/domain/todo/dto/response/TaskOrderCategoryUpdateResponseDTO.java @@ -0,0 +1,19 @@ +package com.indayvidual.server.domain.todo.dto.response; + +import lombok.Builder; +import lombok.Getter; + +import java.util.List; + +@Getter +@Builder +public class TaskOrderCategoryUpdateResponseDTO { + + private Integer updatedCount; + private List affectedCategories; + + public TaskOrderCategoryUpdateResponseDTO(int updatedCount, List affectedCategories) { + this.updatedCount = updatedCount; + this.affectedCategories = affectedCategories; + } +} diff --git a/src/main/java/com/indayvidual/server/domain/todo/entity/Task.java b/src/main/java/com/indayvidual/server/domain/todo/entity/Task.java index f359a38..86fbdef 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/entity/Task.java +++ b/src/main/java/com/indayvidual/server/domain/todo/entity/Task.java @@ -74,6 +74,11 @@ public void updatePosition(int position) { this.position = position; } + public void updateCategory(Category category) { + log.debug("[TASK] 카테고리 변경 - before: {}, after: {}", this.category, category); + this.category = category; + } + public static Task create(User user, Category category, String title, LocalDate dueDate, int position) { return Task.builder() .user(user) diff --git a/src/main/java/com/indayvidual/server/domain/todo/repository/CategoryRepository.java b/src/main/java/com/indayvidual/server/domain/todo/repository/CategoryRepository.java index 2ae9889..0ed93d4 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/repository/CategoryRepository.java +++ b/src/main/java/com/indayvidual/server/domain/todo/repository/CategoryRepository.java @@ -4,8 +4,13 @@ import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; +import java.util.Optional; public interface CategoryRepository extends JpaRepository { List findAllByUserIdOrderByCreatedAtDesc(Long userId); + + Optional findByIdAndUserId(Long userId, Long categoryId); + + boolean existsByIdAndUserId(Long categoryId, Long userId); } diff --git a/src/main/java/com/indayvidual/server/domain/todo/repository/TaskRepository.java b/src/main/java/com/indayvidual/server/domain/todo/repository/TaskRepository.java index c14c0b1..7989cb4 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/repository/TaskRepository.java +++ b/src/main/java/com/indayvidual/server/domain/todo/repository/TaskRepository.java @@ -29,4 +29,8 @@ public interface TaskRepository extends JpaRepository { */ @Query("SELECT MAX(t.position) FROM Task t WHERE t.category.id = :categoryId") Integer findMaxPositionByCategoryId(@Param("categoryId") Long categoryId); + + List findAllByUserIdAndCategoryId(Long userId, Long categoryId); + + List findAllByCategoryId(Long categoryId); } diff --git a/src/main/java/com/indayvidual/server/domain/todo/service/category/CategoryCommandService.java b/src/main/java/com/indayvidual/server/domain/todo/service/category/CategoryCommandService.java index 1e0aaab..a7195b2 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/service/category/CategoryCommandService.java +++ b/src/main/java/com/indayvidual/server/domain/todo/service/category/CategoryCommandService.java @@ -4,20 +4,27 @@ import com.indayvidual.server.domain.todo.dto.request.CategoryCreateRequestDTO; import com.indayvidual.server.domain.todo.dto.response.CategoryResponseDTO; import com.indayvidual.server.domain.todo.entity.Category; +import com.indayvidual.server.domain.todo.entity.Task; import com.indayvidual.server.domain.todo.repository.CategoryRepository; +import com.indayvidual.server.domain.todo.repository.TaskRepository; import com.indayvidual.server.domain.user.entity.User; import com.indayvidual.server.domain.user.repository.UserRepository; import com.indayvidual.server.global.api.code.status.ErrorStatus; import com.indayvidual.server.global.exception.GeneralException; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + @Service +@Slf4j @RequiredArgsConstructor public class CategoryCommandService { private final CategoryRepository categoryRepository; + private final TaskRepository taskRepository; private final CategoryConverter categoryConverter; private final UserRepository userRepository; @@ -31,4 +38,18 @@ public CategoryResponseDTO create(CategoryCreateRequestDTO request, Long userId) Category saved = categoryRepository.save(entity); return categoryConverter.toResponse(saved); } + + @Transactional + public void delete(Long userId, Long categoryId) { + Category category = categoryRepository.findByIdAndUserId(categoryId, userId) + .orElseThrow(() -> new GeneralException(ErrorStatus.TASK_CATEGORY_NOT_FOUND)); + + // 연관된 task 먼저 삭제 + List tasks = taskRepository.findAllByCategoryId(categoryId); + taskRepository.deleteAll(tasks); + + categoryRepository.delete(category); + + log.debug("[CATEGORY] 삭제 완료 - categoryId={}", categoryId); + } } \ No newline at end of file diff --git a/src/main/java/com/indayvidual/server/domain/todo/service/task/TaskCommandService.java b/src/main/java/com/indayvidual/server/domain/todo/service/task/TaskCommandService.java index b5e24c5..6e0fdc7 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/service/task/TaskCommandService.java +++ b/src/main/java/com/indayvidual/server/domain/todo/service/task/TaskCommandService.java @@ -2,9 +2,10 @@ import com.indayvidual.server.domain.todo.dto.request.TaskCreateRequestDTO; import com.indayvidual.server.domain.todo.dto.request.TaskDueDateUpdateRequestDTO; -import com.indayvidual.server.domain.todo.dto.request.TaskOrderUpdateRequestDTO; +import com.indayvidual.server.domain.todo.dto.request.TaskOrderCategoryUpdateBulkRequestDTO; import com.indayvidual.server.domain.todo.dto.request.TaskTitleUpdateRequestDTO; import com.indayvidual.server.domain.todo.dto.response.TaskCheckUpdateResponseDTO; +import com.indayvidual.server.domain.todo.dto.response.TaskOrderCategoryUpdateResponseDTO; import com.indayvidual.server.domain.todo.dto.response.TaskResponseDTO; import com.indayvidual.server.domain.todo.dto.response.TaskUpdateResponseDTO; @@ -44,10 +45,9 @@ public interface TaskCommandService { * 특정 카테고리 내 할 일의 순서를 일괄 변경합니다. * * @param userId - * @param categoryId * @param request 요청 DTO */ - void updateTaskOrder(Long userId, Long categoryId, TaskOrderUpdateRequestDTO request); + TaskOrderCategoryUpdateResponseDTO updateTaskOrders(Long userId, TaskOrderCategoryUpdateBulkRequestDTO request); /** * 할 일의 체크 상태를 토글합니다. diff --git a/src/main/java/com/indayvidual/server/domain/todo/service/task/TaskCommandServiceImpl.java b/src/main/java/com/indayvidual/server/domain/todo/service/task/TaskCommandServiceImpl.java index af2606b..f197ac4 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/service/task/TaskCommandServiceImpl.java +++ b/src/main/java/com/indayvidual/server/domain/todo/service/task/TaskCommandServiceImpl.java @@ -1,11 +1,9 @@ package com.indayvidual.server.domain.todo.service.task; import com.indayvidual.server.domain.todo.converter.TaskConverter; -import com.indayvidual.server.domain.todo.dto.request.TaskCreateRequestDTO; -import com.indayvidual.server.domain.todo.dto.request.TaskDueDateUpdateRequestDTO; -import com.indayvidual.server.domain.todo.dto.request.TaskOrderUpdateRequestDTO; -import com.indayvidual.server.domain.todo.dto.request.TaskTitleUpdateRequestDTO; +import com.indayvidual.server.domain.todo.dto.request.*; import com.indayvidual.server.domain.todo.dto.response.TaskCheckUpdateResponseDTO; +import com.indayvidual.server.domain.todo.dto.response.TaskOrderCategoryUpdateResponseDTO; import com.indayvidual.server.domain.todo.dto.response.TaskResponseDTO; import com.indayvidual.server.domain.todo.dto.response.TaskUpdateResponseDTO; import com.indayvidual.server.domain.todo.entity.Category; @@ -21,8 +19,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; @Service @@ -127,67 +124,159 @@ public TaskCheckUpdateResponseDTO toggleCheck(Long userId, Long taskId) { * 카테고리 내 할 일 순서를 변경합니다. */ @Transactional - public void updateTaskOrder(Long userId, Long categoryId, TaskOrderUpdateRequestDTO request) { - List taskIds = validateTaskOrderRequest(request); - List tasks = findAndValidateTasks(userId, categoryId, taskIds); - applyTaskPositionChanges(tasks, taskIds); + public TaskOrderCategoryUpdateResponseDTO updateTaskOrders(Long userId, TaskOrderCategoryUpdateBulkRequestDTO request) { + // 요청 유효성 검사 + List taskRequests = validateTaskOrdersRequest(request); - log.debug("[TASK] 순서 변경 완료 - categoryId={}, userId={}, taskCount={}", - categoryId, userId, taskIds.size()); + // 유효성 검사 + Map taskMap = loadAndValidateTasks(userId, taskRequests); + + // 카테고리 별 재정렬 + Set affectedCategories = applyCategoryWiseReordering(userId, taskRequests, taskMap); + + log.debug("[TASK] 순서 변경 완료 - affectedCategories={}, userId={}, taskCount={}", + affectedCategories, userId, taskRequests.size()); + + // DTO 생성 + return buildReorderResponse(taskRequests.size(), affectedCategories); } /** - * Task 순서 변경 요청의 유효성을 검증합니다. + * 응답 DTO를 생성합니다. + * + * @param size + * @param affectedCategories + * @return */ - private List validateTaskOrderRequest(TaskOrderUpdateRequestDTO request) { - List taskIds = request.getTaskOrder(); - if (taskIds == null || taskIds.isEmpty()) { - log.warn("[TASK] 빈 taskOrder 요청"); - throw new GeneralException(ErrorStatus.TASK_INVALID_ORDER); + private TaskOrderCategoryUpdateResponseDTO buildReorderResponse(int size, Set affectedCategories) { + return new TaskOrderCategoryUpdateResponseDTO(size, new ArrayList<>(affectedCategories)); + } + + /** + * 할 일의 순서 변경 또는 카테고리를 변경합니다. + * + * @param userId + * @param requestList + * @param taskMap + * @return + */ + private Set applyCategoryWiseReordering( + Long userId, + List requestList, + Map taskMap + ) { + Set affectedCategories = new HashSet<>(); + + // 1. 요청을 카테고리별로 groupBy + Map> groupedRequests = + requestList.stream().collect(Collectors.groupingBy(TaskOrderCategoryUpdateRequestDTO::getCategoryId)); + + for (Map.Entry> entry : groupedRequests.entrySet()) { + Long categoryId = entry.getKey(); + List requestTasks = entry.getValue(); + + Category category = categoryRepository.findById(categoryId) + .orElseThrow(() -> new GeneralException(ErrorStatus.TASK_CATEGORY_NOT_FOUND)); + + log.debug("[TASK][REORDER] categoryId={} - 요청된 task 수: {}", categoryId, requestTasks.size()); + + // 2. 해당 카테고리의 전체 task 조회 + List allTasksInCategory = taskRepository.findAllByUserIdAndCategoryId(userId, categoryId); + log.debug("[TASK][REORDER] categoryId={} - DB 내 전체 task 수: {}", categoryId, allTasksInCategory.size()); + + // 3. 요청된 task 정렬용 Map + Map requestedOrderMap = requestTasks.stream() + .collect(Collectors.toMap(TaskOrderCategoryUpdateRequestDTO::getTaskId, TaskOrderCategoryUpdateRequestDTO::getOrder)); + + // 4. 요청된 task 정렬 + List requestedTasks = requestTasks.stream() + .map(dto -> taskMap.get(dto.getTaskId())) + .sorted(Comparator.comparingInt(task -> requestedOrderMap.get(task.getId()))) + .toList(); + + log.debug("[TASK][REORDER] 요청된 task 순서:"); + for (int i = 0; i < requestedTasks.size(); i++) { + Task t = requestedTasks.get(i); + log.debug(" - [{}] taskId={}, 요청 order={}", i, t.getId(), requestedOrderMap.get(t.getId())); + } + + // 5. 요청되지 않은 task + Set requestedIds = new HashSet<>(requestedOrderMap.keySet()); + List untouchedTasks = allTasksInCategory.stream() + .filter(task -> !requestedIds.contains(task.getId())) + .toList(); + + log.debug("[TASK][REORDER] 포함되지 않은 task 수: {}", untouchedTasks.size()); + + // 6. 최종 정렬 리스트 구성 + List finalSortedTasks = new ArrayList<>(); + finalSortedTasks.addAll(requestedTasks); + finalSortedTasks.addAll(untouchedTasks); + + log.debug("[TASK][REORDER] 최종 정렬 후 position 재할당:"); + + for (int i = 0; i < finalSortedTasks.size(); i++) { + Task task = finalSortedTasks.get(i); + + // 카테고리 변경 필요 시 + if (!task.getCategory().getId().equals(categoryId)) { + log.debug(" - taskId={} 카테고리 변경: {} → {}", task.getId(), task.getCategory().getId(), categoryId); + task.updateCategory(category); + } + + // position 재할당 + log.debug(" - taskId={}, 기존 position={}, 신규 position={}", task.getId(), task.getPosition(), i); + task.updatePosition(i); + } + + affectedCategories.add(categoryId); } - return taskIds; + + log.debug("[TASK][REORDER] 전체 변경 완료 - userId={}, 변경된 카테고리 수: {}", userId, affectedCategories.size()); + return affectedCategories; } /** - * Task를 조회, 검증합니다. + * Task가 유효한지 확인합니다. * * @param userId - * @param categoryId - * @param taskIds - * @return Task list + * @param taskRequests + * @return */ - private List findAndValidateTasks(Long userId, Long categoryId, List taskIds) { + private Map loadAndValidateTasks( + Long userId, + List taskRequests + ) { + // task id 추출 + List taskIds = taskRequests.stream().map(TaskOrderCategoryUpdateRequestDTO::getTaskId).toList(); + List tasks = taskRepository.findAllById(taskIds); + + // 요청 taskId 개수와 조회한 결과 개수가 다른 경우 예외 처리 if (tasks.size() != taskIds.size()) { - log.warn("[TASK] 일부 taskId 존재하지 않음"); throw new GeneralException(ErrorStatus.TASK_NOT_FOUND); } for (Task task : tasks) { - if (!task.getCategory().getId().equals(categoryId) || !task.getUser().getId().equals(userId)) { - log.warn("[TASK] 잘못된 소속의 task 존재 - taskId={}", task.getId()); + // task.userId와 요청한 userId가 다른 경우 예외 처리 + if (!task.getUser().getId().equals(userId)) { throw new GeneralException(ErrorStatus.TASK_FORBIDDEN); } } - return tasks; + return tasks.stream().collect(Collectors.toMap(Task::getId, t -> t)); } /** - * Task에 순서를 적용합니다. - * - * @param tasks - * @param orderedIds + * Task 순서 변경 요청의 유효성을 검증합니다. */ - private void applyTaskPositionChanges(List tasks, List orderedIds) { - Map taskMap = tasks.stream() - .collect(Collectors.toMap(Task::getId, t -> t)); - - for (int i = 0; i < orderedIds.size(); i++) { - Long taskId = orderedIds.get(i); - Task task = taskMap.get(taskId); - task.updatePosition(i); + private List validateTaskOrdersRequest(TaskOrderCategoryUpdateBulkRequestDTO request) { + List tasks = request.getTasks(); + if (tasks == null || tasks.isEmpty()) { + log.warn("[TASK] 빈 taskOrder 요청"); + throw new GeneralException(ErrorStatus.TASK_INVALID_ORDER); } + return tasks; } private Task findTaskByIdAndUserId(Long taskId, Long userId) { diff --git a/src/main/java/com/indayvidual/server/domain/todo/service/task/TaskQueryServiceImpl.java b/src/main/java/com/indayvidual/server/domain/todo/service/task/TaskQueryServiceImpl.java index 8527f7c..6a6f42b 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/service/task/TaskQueryServiceImpl.java +++ b/src/main/java/com/indayvidual/server/domain/todo/service/task/TaskQueryServiceImpl.java @@ -3,7 +3,10 @@ import com.indayvidual.server.domain.todo.converter.TaskConverter; import com.indayvidual.server.domain.todo.dto.response.TaskResponseDTO; import com.indayvidual.server.domain.todo.entity.Task; +import com.indayvidual.server.domain.todo.repository.CategoryRepository; import com.indayvidual.server.domain.todo.repository.TaskRepository; +import com.indayvidual.server.global.api.code.status.ErrorStatus; +import com.indayvidual.server.global.exception.GeneralException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -18,6 +21,7 @@ public class TaskQueryServiceImpl implements TaskQueryService { private final TaskRepository taskRepository; + private final CategoryRepository categoryRepository; private final TaskConverter taskConverter; @Override @@ -25,6 +29,12 @@ public class TaskQueryServiceImpl implements TaskQueryService { public List findTasksByCategoryAndDate(Long userId, Long categoryId, LocalDate dueDate) { log.debug("[TASK-QUERY] 할 일 조회 요청 - userId={}, categoryId={}, date={}", userId, categoryId, dueDate); + boolean categoryExists = categoryRepository.existsByIdAndUserId(categoryId, userId); + if (!categoryExists) { + log.warn("[TASK-QUERY] 존재하지 않는 카테고리 - categoryId={}, userId={}", categoryId, userId); + throw new GeneralException(ErrorStatus.TASK_CATEGORY_NOT_FOUND); + } + List tasks = taskRepository.findByUserIdAndCategoryIdAndDueDate(userId, categoryId, dueDate); log.debug("[TASK-QUERY] 조회된 할 일 수: {}", tasks.size()); diff --git a/src/main/java/com/indayvidual/server/global/api/code/status/SuccessStatus.java b/src/main/java/com/indayvidual/server/global/api/code/status/SuccessStatus.java index 6f69e8b..40c3e70 100644 --- a/src/main/java/com/indayvidual/server/global/api/code/status/SuccessStatus.java +++ b/src/main/java/com/indayvidual/server/global/api/code/status/SuccessStatus.java @@ -32,13 +32,14 @@ public enum SuccessStatus implements BaseCode { // 할 일 관련 응답 CREATE_CATEGORY_SUCCESS(HttpStatus.CREATED, "CREATE_CATEGORY_SUCCESS", "카테고리 등록 성공"), GET_CATEGORIES_SUCCESS(HttpStatus.OK, "GET_CATEGORIES_SUCCESS", "카테고리 목록 조회 성공"), + DELETE_CATEGORY_SUCCESS(HttpStatus.OK, "DELETE_CATEGORY_SUCCESS", "카테고리 삭제 성공"), CREATE_TASK_SUCCESS(HttpStatus.CREATED, "CREATE_TASK_SUCCESS", "할일 등록 성공"), GET_TASKS_SUCCESS(HttpStatus.OK, "GET_TASKS_SUCCESS", "할일 목록 조회 성공"), UPDATE_TASK_TITLE_SUCCESS(HttpStatus.OK, "UPDATE_TASK_TITLE_SUCCESS", "할일 제목 수정 성공"), UPDATE_TASK_DUE_DATE_SUCCESS(HttpStatus.OK, "UPDATE_TASK_DUEDATE_SUCCESS", "할일 날짜 수정 성공"), DELETE_TASK_SUCCESS(HttpStatus.OK, "DELETE_TASK_SUCCESS", "할일 삭제 성공"), UPDATE_TASK_CHECK_SUCCESS(HttpStatus.OK, "UPDATE_TASK_CHECK_SUCCESS", "할일 체크 상태 변경 성공"), - UPDATE_TASK_ORDER_SUCCESS(HttpStatus.OK, "UPDATE_TASK_ORDER_SUCCESS", "할일 순서 변경 성공"), + UPDATE_TASK_ORDER_SUCCESS(HttpStatus.OK, "UPDATE_TASK_ORDER_SUCCESS", "할일 순서 및 카테고리 이동 성공"), // 색상 관련 응답 GET_COLORS_SUCCESS(HttpStatus.OK, "GET_COLORS_SUCCESS", "색상 목록 조회 성공")