Skip to content

[hotfix] #191 - 반복 투두의 하위 태스크 완료·메모를 날짜별로 분리#193

Merged
laura-jung merged 8 commits into
developfrom
hotfix/#191--repeatSubtask
Jul 16, 2026
Merged

[hotfix] #191 - 반복 투두의 하위 태스크 완료·메모를 날짜별로 분리#193
laura-jung merged 8 commits into
developfrom
hotfix/#191--repeatSubtask

Conversation

@laura-jung

@laura-jung laura-jung commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

관련 이슈 🛠

작업 내용 요약 ✏️

반복 투두는 여러 날짜가 같은 todoId(규칙)를 공유하는데, 하위 태스크 완료 여부와 메모가
규칙 레벨에 저장되어 모든 날짜가 상태를 공유하는 문제가 있었습니다.
상위 투두 완료는 이미 날짜별(TodoInstance)로 분리되어 있어 하위와 불일치가 발생했습니다.

주요 변경 사항 🛠️

  • SubtaskCompletion 엔티티 신규 (todo_instance, subtask, completed) + unique(todo_instance_id, subtask_id)
  • 내용(content/sortOrder)은 Subtask(규칙)에서 공유, 완료 여부만 인스턴스별 저장
  • 상태 변경 API에 date 추가 → 해당 날짜 인스턴스의 완료만 upsert
  • 규칙 레벨 Subtask.completed 및 관련 필드/DTO 제거

테스트 결과 📄

매일 투두 생성하여 일정 투두만 하위태스크 완료 여부 변경진행하였습니다.

스크린샷 📷

스크린샷 2026-07-16 오후 5 59 05

리뷰 요구사항 📢

바쁘니까 머지할게요

Summary by CodeRabbit

  • 새로운 기능

    • 날짜별 할 일 메모를 조회하고 수정할 수 있습니다.
    • 날짜별 서브태스크 완료 상태가 저장되고 표시됩니다.
    • 서브태스크 상태 변경 시 날짜를 지정할 수 있습니다.
  • 개선

    • 할 일 상세 화면과 홈 화면에서 날짜별 메모 및 서브태스크 완료 상태가 정확히 반영됩니다.
    • 서브태스크 수정과 할 일 삭제 시 완료 정보가 안정적으로 관리됩니다.

@laura-jung laura-jung linked an issue Jul 16, 2026 that may be closed by this pull request
1 task
@laura-jung laura-jung self-assigned this Jul 16, 2026
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@laura-jung, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 51 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 22542027-8db5-4eed-8d4d-a2adae3fe3b1

📥 Commits

Reviewing files that changed from the base of the PR and between 8fe1009 and be43b14.

📒 Files selected for processing (1)
  • src/main/java/com/Timo/Timo/domain/todo/repository/SubtaskCompletionRepository.java

Walkthrough

반복 Todo의 서브태스크 완료 상태를 날짜별 SubtaskCompletion으로 관리하고, 홈·상세·포커스 응답에 TodoInstance별 완료 상태와 메모를 반영한다. 상태 변경 및 날짜별 메모 수정 API와 관련 마이그레이션도 추가한다.

Changes

TodoInstance 기반 상태 관리

Layer / File(s) Summary
완료 상태 모델과 계약
db/migration/..., src/main/java/com/Timo/Timo/domain/todo/entity/*, src/main/java/com/Timo/Timo/domain/todo/dto/request/*
Subtask.completed를 제거하고 SubtaskCompletion 엔티티·저장소를 추가했으며, Todo 및 요청 DTO에서 완료 상태 필드를 분리했다.
날짜별 인스턴스 메모
src/main/java/com/Timo/Timo/domain/todo/entity/TodoInstance.java, src/main/java/com/Timo/Timo/domain/todo/dto/request/TodoMemoUpdateRequest.java
TodoInstance 메모 저장·갱신·폴백 해석과 날짜별 메모 요청 DTO를 추가했다.
완료 상태와 메모 변경 흐름
src/main/java/com/Timo/Timo/domain/todo/controller/TodoController.java, src/main/java/com/Timo/Timo/domain/todo/service/TodoService.java
서브태스크 상태 변경에 날짜를 추가하고 날짜별 메모 수정 API를 도입했으며, 완료 레코드 생성·갱신·삭제를 서비스에 연결했다.
날짜별 완료 상태 응답
src/main/java/com/Timo/Timo/domain/home/..., src/main/java/com/Timo/Timo/domain/todo/dto/response/*
홈과 상세 응답이 TodoInstance별 완료 서브태스크 ID를 사용해 완료 상태를 매핑하도록 변경했다.
포커스 날짜별 메모 해석
src/main/java/com/Timo/Timo/domain/focus/service/FocusService.java
포커스 및 활성 타이머 응답에서 해당 날짜의 TodoInstance 메모를 우선 사용하도록 변경했다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant TodoController
  participant TodoService
  participant SubtaskCompletionRepository
  Client->>TodoController: 날짜와 서브태스크 상태 전송
  TodoController->>TodoService: 날짜 포함 상태 변경 호출
  TodoService->>SubtaskCompletionRepository: 완료 레코드 조회 또는 저장
  TodoService->>SubtaskCompletionRepository: 완료 상태 갱신
  TodoService-->>TodoController: 상태 변경 응답
  TodoController-->>Client: 응답 반환
Loading

Possibly related PRs

Suggested labels: slack-approval-notified

Suggested reviewers: aneykrap, jy000n

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 반복 투두의 하위 태스크 완료와 메모를 날짜별로 분리하는 핵심 변경을 정확히 요약합니다.
Linked Issues check ✅ Passed 반복 todo의 하위태스크 완료 상태를 TodoInstance/SubtaskCompletion 기준으로 분리해 요구사항을 충족합니다.
Out of Scope Changes check ✅ Passed 서브태스크 완료 분리, 메모 날짜별 저장, 관련 API/DTO/마이그레이션만 보여 별도 범위 변경은 없습니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hotfix/#191--repeatSubtask

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
db/migration/2026-07-16__drop_subtasks_completed.sql (1)

5-7: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

무중단 배포(Zero-downtime deployment)를 위한 운영 환경 고려 사항

컬럼을 삭제하는 DDL 구문은 현재 이 테이블과 컬럼을 참조하고 있는 구버전 애플리케이션 인스턴스에서 SQL 오류를 발생시킬 수 있습니다. 시스템이 무중단 배포 환경으로 운영 중이거나 향후 이를 계획하고 있다면, 애플리케이션 코드에서 해당 컬럼에 대한 참조를 완전히 제거한 버전을 성공적으로 배포한 후, 다음 배포 주기나 별도의 마이그레이션 단계에서 컬럼을 안전하게 삭제하는 것을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@db/migration/2026-07-16__drop_subtasks_completed.sql` around lines 5 - 7,
Defer the DROP COLUMN operation in migration
2026-07-16__drop_subtasks_completed.sql until after all application instances no
longer reference subtasks.completed. Remove or postpone the ALTER TABLE
statement so zero-downtime deployments retain compatibility with older
application versions, then perform the column deletion in a subsequent migration
or deployment phase.
src/main/java/com/Timo/Timo/domain/home/service/HomeTodoReader.java (1)

89-102: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

데이터베이스 레벨에서 완료된 하위 태스크만 필터링하도록 조회 성능 개선

현재 findByTodoInstance_IdIn을 통해 모든 SubtaskCompletion 레코드를 데이터베이스에서 조회한 후, Java의 Stream.filter를 사용해 메모리 상에서 completed == true인 항목을 걸러내고 있습니다. 데이터가 늘어날 경우 완료되지 않은 불필요한 레코드까지 메모리에 로드하게 되어 메모리와 네트워크 I/O 성능 저하가 발생할 수 있습니다.

Repository에 completed == true 조건이 포함된 쿼리 메서드를 추가하여 데이터베이스 레벨에서 즉시 필터링하도록 개선하는 것을 권장합니다. (이 방식을 적용할 경우 동일하게 필터링 로직을 수행 중인 TodoService.resolveCompletedSubtaskIds 등의 다른 로직에도 함께 적용할 수 있습니다.)

As per path instructions, 쿼리 성능과 N+1 문제가 없는지 확인해야 합니다.

♻️ 수정 제안

SubtaskCompletionRepository에 새로운 쿼리 메서드를 추가합니다:

List<SubtaskCompletion> findByTodoInstance_IdInAndCompletedTrue(Collection<Long> todoInstanceIds);

이후 HomeTodoReader의 로직을 다음과 같이 수정합니다:

-		return subtaskCompletionRepository.findByTodoInstance_IdIn(instanceIds).stream()
-				.filter(SubtaskCompletion::isCompleted)
+		return subtaskCompletionRepository.findByTodoInstance_IdInAndCompletedTrue(instanceIds).stream()
				.collect(Collectors.groupingBy(
						completion -> completion.getTodoInstance().getId(),
						Collectors.mapping(completion -> completion.getSubtask().getId(), Collectors.toSet())
				));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/Timo/Timo/domain/home/service/HomeTodoReader.java` around
lines 89 - 102, Update SubtaskCompletionRepository with a
findByTodoInstance_IdInAndCompletedTrue(Collection<Long> todoInstanceIds) query
method, then change HomeTodoReader.loadCompletedSubtaskIds to use it and remove
the in-memory SubtaskCompletion::isCompleted filter. Preserve the existing
empty-input handling and grouping behavior, and verify the repository query
fetches the required associations without introducing N+1 queries.

Source: Path instructions

src/main/java/com/Timo/Timo/domain/todo/service/TodoService.java (1)

159-169: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

불필요한 데이터베이스 UPDATE 쿼리를 방지하도록 초기화 로직을 개선해 주세요.

현재 로직은 완료 레코드가 존재하지 않을 때 항상 false로 데이터베이스에 저장(INSERT)한 직후 updateCompleted를 호출하여 상태를 덮어씁니다. 이로 인해 트랜잭션 종료 시 의도치 않은 UPDATE 쿼리가 추가로 발생할 수 있습니다.

요청받은 상태(request.isCompleted())로 엔티티를 바로 초기화하고, 마지막에 한 번만 save를 호출하여 영속성 컨텍스트를 효율적으로 활용하도록 리팩토링하는 것을 권장합니다.

♻️ 제안하는 수정안
 		requireOccurrence(todo, date);
 
 		TodoInstance instance = todoInstanceReorderer.materializeInstance(userId, todo, date);
 		SubtaskCompletion completion = subtaskCompletionRepository
 				.findByTodoInstance_IdAndSubtask_Id(instance.getId(), subtaskId)
-				.orElseGet(() -> subtaskCompletionRepository.save(
-						SubtaskCompletion.of(instance, subtask, false)));
+				.orElseGet(() -> SubtaskCompletion.of(instance, subtask, request.isCompleted()));
+
 		completion.updateCompleted(request.isCompleted());
+		subtaskCompletionRepository.save(completion);
 
 		return new SubtaskStatusChangeResponse(subtaskId, request.isCompleted());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/Timo/Timo/domain/todo/service/TodoService.java` around
lines 159 - 169, Update the completion initialization in the subtask status
change method around subtaskCompletionRepository and SubtaskCompletion.of so new
records are created with request.isCompleted() instead of false. Remove the
unconditional completion.updateCompleted call, then invoke
subtaskCompletionRepository.save exactly once after resolving or creating the
completion, preserving the existing response behavior.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/com/Timo/Timo/domain/todo/repository/SubtaskCompletionRepository.java`:
- Around line 20-22: Update the deleteByTodoId bulk JPQL query to avoid the
implicit association traversal through sc.todoInstance.todo.id. Use a subquery
that explicitly selects matching TodoInstance IDs for the given todoId, then
delete SubtaskCompletion records whose todoInstance ID is in that result.

---

Nitpick comments:
In `@db/migration/2026-07-16__drop_subtasks_completed.sql`:
- Around line 5-7: Defer the DROP COLUMN operation in migration
2026-07-16__drop_subtasks_completed.sql until after all application instances no
longer reference subtasks.completed. Remove or postpone the ALTER TABLE
statement so zero-downtime deployments retain compatibility with older
application versions, then perform the column deletion in a subsequent migration
or deployment phase.

In `@src/main/java/com/Timo/Timo/domain/home/service/HomeTodoReader.java`:
- Around line 89-102: Update SubtaskCompletionRepository with a
findByTodoInstance_IdInAndCompletedTrue(Collection<Long> todoInstanceIds) query
method, then change HomeTodoReader.loadCompletedSubtaskIds to use it and remove
the in-memory SubtaskCompletion::isCompleted filter. Preserve the existing
empty-input handling and grouping behavior, and verify the repository query
fetches the required associations without introducing N+1 queries.

In `@src/main/java/com/Timo/Timo/domain/todo/service/TodoService.java`:
- Around line 159-169: Update the completion initialization in the subtask
status change method around subtaskCompletionRepository and SubtaskCompletion.of
so new records are created with request.isCompleted() instead of false. Remove
the unconditional completion.updateCompleted call, then invoke
subtaskCompletionRepository.save exactly once after resolving or creating the
completion, preserving the existing response behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e16e2498-0b28-40c0-bdb4-43a802fd817f

📥 Commits

Reviewing files that changed from the base of the PR and between 5f7fee4 and 8fe1009.

⛔ Files ignored due to path filters (2)
  • src/main/java/com/Timo/Timo/domain/timer/docs/TimerStartControllerDocs.java is excluded by !**/docs/**
  • src/main/java/com/Timo/Timo/domain/todo/docs/TodoControllerDocs.java is excluded by !**/docs/**
📒 Files selected for processing (17)
  • db/migration/2026-07-16__drop_subtasks_completed.sql
  • src/main/java/com/Timo/Timo/domain/focus/service/FocusService.java
  • src/main/java/com/Timo/Timo/domain/home/dto/response/HomeResponse.java
  • src/main/java/com/Timo/Timo/domain/home/mapper/HomeTodoMapper.java
  • src/main/java/com/Timo/Timo/domain/home/service/HomeTodoReader.java
  • src/main/java/com/Timo/Timo/domain/todo/controller/TodoController.java
  • src/main/java/com/Timo/Timo/domain/todo/dto/request/TodoMemoUpdateRequest.java
  • src/main/java/com/Timo/Timo/domain/todo/dto/request/TodoSubtaskUpdateRequest.java
  • src/main/java/com/Timo/Timo/domain/todo/dto/request/TodoUpdateRequest.java
  • src/main/java/com/Timo/Timo/domain/todo/dto/response/SubtaskStatusChangeResponse.java
  • src/main/java/com/Timo/Timo/domain/todo/dto/response/TodoDetailResponse.java
  • src/main/java/com/Timo/Timo/domain/todo/entity/Subtask.java
  • src/main/java/com/Timo/Timo/domain/todo/entity/SubtaskCompletion.java
  • src/main/java/com/Timo/Timo/domain/todo/entity/Todo.java
  • src/main/java/com/Timo/Timo/domain/todo/entity/TodoInstance.java
  • src/main/java/com/Timo/Timo/domain/todo/repository/SubtaskCompletionRepository.java
  • src/main/java/com/Timo/Timo/domain/todo/service/TodoService.java
💤 Files with no reviewable changes (2)
  • src/main/java/com/Timo/Timo/domain/todo/dto/response/SubtaskStatusChangeResponse.java
  • src/main/java/com/Timo/Timo/domain/todo/dto/request/TodoUpdateRequest.java

@laura-jung laura-jung merged commit 4ab83e4 into develop Jul 16, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[hotfix] 반복 하위태스크 완료 여부 수정

1 participant