Skip to content

[feat] #34 - 타이머 완료/종료 - #68

Merged
Jy000n merged 15 commits into
developfrom
feat/#34-timer-stop-complete
Jul 9, 2026
Merged

Jy000n merged 15 commits into
developfrom
feat/#34-timer-stop-complete

Conversation

@Jy000n

@Jy000n Jy000n commented Jul 9, 2026 •

Copy link
Copy Markdown
Member

관련 이슈 🛠

작업 내용 요약 ✏️

투두 타이머의 완료(자동 종료)/종료(수동 종료) API 구현

예상 시간이 모두 경과하여 자동으로 완료되는 경우와, 사용자가 직접 종료하는 경우를 각각 다루며, 두 API 모두 실제 수행 시간을 계산하고 날짜별 TodoInstance의 완료 상태를 갱신합니다.

주요 변경 사항 🛠️

  • [Timer] TimerErrorCode, TimerSuccessCode에 완료/종료 관련 코드 추가
  • [Timer] TimerRecord에 finish() 도메인 메서드 추가
    • status/endedAt/actualSeconds/aiFeedback을 한 번에 갱신, 이미 종료된 타이머면 예외 발생
  • [Timer] PATCH /timers/{timerId}/complete, PATCH /timers/{timerId}/stop API 구현
    • 종료 시각 기록, 실제 수행 시간(actualSeconds) 계산 (elapsedSeconds 계산 로직 재사용)
    • 본인 소유가 아닌 타이머 403, 존재하지 않는 타이머 404, 이미 종료된 타이머 409 처리
    • 완료/종료 공통 로직을 finishTimer private 메서드로 묶어 중복 제거
  • [Timer] TimerFinishResponse 공통 응답 DTO 추가 (완료/종료 응답 필드가 동일하여 통합)
  • [Timer] 완료/종료 시 날짜별 TodoInstance의 timerStatus, completed 상태 동기화
    • 해당 타이머가 시작된 날짜의 TodoInstance를 조회하고, 없으면 생성 후 stopTimer() + markCompleted() 호출
  • [Timer] TimerCompleteControllerDocs, TimerStopControllerDocs 추가하여 Swagger 문서화

트러블 슈팅 ⚽️

테스트 결과 📄

  • PATCH /timers/{timerId}/complete 성공 시 200 응답, status=COMPLETED, actualSeconds 정상 계산 확인
  • PATCH /timers/{timerId}/stop 성공 시 200 응답, status=STOPPED, actualSeconds 정상 계산 확인
  • 완료/종료 후 해당 날짜 TodoInstance의 completed=true, timerStatus=STOPPED 확인 (DB 직접 조회)
  • 이미 종료된 타이머에 재요청 시 409 확인
  • 존재하지 않는 timerId로 요청 시 404 확인

스크린샷 📷

PATCH /timers/{timerId}/complete 성공 시 200 응답, status=COMPLETED, actualSeconds 정상 계산 확인
image
PATCH /timers/{timerId}/stop 성공 시 200 응답, status=STOPPED, actualSeconds 정상 계산 확인
image
완료/종료 후 해당 날짜 TodoInstance의 completed=true, timerStatus=STOPPED 확인 (DB 직접 조회)
image
image
image
존재하지 않는 timerId로 요청 시 404 확인
image
image
이미 종료된 타이머에 재요청 시 409 확인
image
image

리뷰 요구사항 📢

aiFeedback을 현재 null로 반환하고 있으니 참고해주시면 감사하겠습니다 :)

📎 참고 자료 (선택)

Summary by CodeRabbit

  • New Features

    • 타이머를 완료하거나 중지하는 기능이 추가되었습니다.
    • 타이머 종료 시 실제 경과 시간과 피드백을 포함한 결과를 확인할 수 있습니다.
  • Bug Fixes

    • 이미 종료된 타이머를 다시 종료하려 할 때 적절한 오류가 표시되도록 개선되었습니다.
    • 종료 처리 시 진행 중이던 세션 시간이 정확히 반영되도록 수정되었습니다.
  • Chores

    • 타이머 완료/중지에 대한 응답 및 상태 코드가 확장되었습니다.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 41 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: 6d7f2d38-ad4f-4829-b7b3-91f1b0e567a5

📥 Commits

Reviewing files that changed from the base of the PR and between 5bf983c and e5a7594.

📒 Files selected for processing (3)
  • src/main/java/com/Timo/Timo/domain/timer/controller/TimerController.java
  • src/main/java/com/Timo/Timo/domain/timer/exception/TimerSuccessCode.java
  • src/main/java/com/Timo/Timo/domain/timer/service/TimerService.java

Walkthrough

타이머 완료/종료 기능을 위해 TimerFinishResponse DTO, TimerRecord.finish 상태 전이 메서드, TIMER_ALREADY_FINISHED 에러 코드, TIMER_COMPLETED/TIMER_STOPPED 성공 코드가 추가됐다. TimerService에 completeTimer/stopTimer 및 공통 finishTimer 로직(경과 시간 계산, TodoInstance 처리)이 구현됐고, TimerController에 PATCH /timers/{timerId}/complete, /stop 엔드포인트가 추가됐다.

Changes

타이머 완료/종료 기능

Layer / File(s) Summary
종료 응답과 상태/에러 코드
.../dto/response/TimerFinishResponse.java, .../entity/TimerRecord.java, .../exception/TimerErrorCode.java, .../exception/TimerSuccessCode.java
TimerFinishResponse record와 TimerRecord.finish(상태/종료시각/경과초/AI피드백 갱신, 중복 종료 시 TIMER_ALREADY_FINISHED 예외) 메서드가 추가되고, TIMER_COMPLETED/TIMER_STOPPED 성공 코드가 정의된다.
완료/종료 서비스 로직과 저장소 조회
.../service/TimerService.java, .../repository/TimerRecordRepository.java
completeTimer/stopTimer 및 공통 finishTimer가 추가되어 잠금 조회, 소유자 검증, 세션 pause 반영, calculateElapsedSeconds로 실제 경과 초 계산, TodoInstance 조회/생성 후 stopTimer/markCompleted 적용까지 수행하며, findByIdForUpdate 선언 위치가 재정렬된다.
컨트롤러 엔드포인트와 응답 구성
.../controller/TimerController.java
TimerController가 TimerCompleteControllerDocs/TimerStopControllerDocs를 구현하며, PATCH /timers/{timerId}/complete, /stop 엔드포인트가 추가되어 TimerService 호출 결과를 BaseResponse로 감싸 반환한다.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant TimerController
  participant TimerService
  participant TimerRecord
  participant TodoInstance

  Client->>TimerController: PATCH /timers/{timerId}/complete or /stop
  TimerController->>TimerService: completeTimer/stopTimer(userId, timerId)
  TimerService->>TimerService: finishTimer(targetStatus)
  TimerService->>TimerRecord: finish(status, now, actualSeconds, aiFeedback)
  TimerService->>TodoInstance: stopTimer() / markCompleted()
  TimerService-->>TimerController: TimerFinishResponse
  TimerController-->>Client: BaseResponse(TIMER_COMPLETED/TIMER_STOPPED)
Loading

Possibly related PRs

  • Team-Timo/Timo-Server#46: 타이머 시작 흐름과 TimerRecord/TimerStatus/세션 모델 위에 완료/종료 API 및 로직이 직접 이어진다.
  • Team-Timo/Timo-Server#49: TodoInstance의 stopTimer/timerStatus 전이 메서드가 completeTimer/stopTimer 종료 흐름과 코드 레벨로 맞물린다.
  • Team-Timo/Timo-Server#67: TimerRecordRepository의 existsByTodo_IdAndStatusIn 및 활성 타이머 확인 로직이 동일한 타이머 상태 처리 흐름과 연결된다.

Suggested labels: 🌸 자윤, slack-approval-notified

Suggested reviewers: laura-jung, aneykrap

🚥 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 자동 완료/수동 종료 API, 실제 시간 계산, 투두 완료 처리와 종료 응답이 구현되어 직접 이슈 요구사항을 충족합니다.
Out of Scope Changes check ✅ Passed 변경은 타이머 완료/종료 기능과 관련된 도메인, 서비스, DTO, 응답 코드에 국한되어 있습니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#34-timer-stop-complete

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.

@aneykrap aneykrap left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

타이머 굿뜨 고생했어용!


@Transactional
public TimerFinishResponse completeTimer(Long userId, Long timerId) {
return finishTimer(userId, timerId, TimerStatus.COMPLETED);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

완료와 수동 종료의 공통 로직을 finishTimer()로 묶고 최종 상태만 전달하도록 구성 조은것 같아용

LocalDateTime now = LocalDateTime.now();
int actualSeconds = calculateElapsedSeconds(timerId, now);

timerRecord.finish(targetStatus, now, actualSeconds, null);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

P3) RUNNING 상태의 타이머를 완료하거나 종료할 때 활성 TimerSession의 pausedAt은 갱신되지 않는 것 같아용
그러면 TimerRecord는 종료 상태인데 세션은 여전히 활성 상태(pausedAt=null)로 남고 이후 활성 세션 조회나 경과 시간 재계산 시 종료 이후 시간까지 포함될 수 있지 않을까 싶습니당
그래서 타이머 종료 시 활성 세션도 now로 닫아주면 좋을 것 같습니다!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

말씀주신대로 actualSeconds 계산 직후, 활성 세션이 있으면 종료 시각(now)으로 pausedAt을 채우도록 수정했습니다!! PAUSED 상태에서 종료하는 경우는 이미 활성 세션이 없는 상태라 별도 처리 없이 자연스럽게 넘어가게 하였습니다!!

감사합니다아:)

@Jy000n
Jy000n requested a review from aneykrap July 9, 2026 08:11

@laura-jung laura-jung left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

아주 굳입니다. 응답 코드만 수정하고 머지합니다.


boolean existsByTodo_IdAndStatusIn(Long todoId, List<TimerStatus> statuses);

@Lock(LockModeType.PESSIMISTIC_WRITE)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

락 좋습니다아

Comment on lines +15 to +16
TIMER_COMPLETED(HttpStatus.OK, "TIMER_200_3", "타이머가 완료되었습니다."),
TIMER_STOPPED(HttpStatus.OK, "TIMER_200_4", "타이머가 종료되었습니다.");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

p3) 저희 에러코드에는 넘버링 안하기로 해서 뒤에 _3, _4 없애도 될 것 같습니다

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

넵 반영했습니다-!

@aneykrap aneykrap left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

리뷰 반영된 부분 확인했습니다

@laura-jung laura-jung left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

머지를 드갑시다

@github-actions github-actions Bot added the slack-approval-notified Slack 승인 완료 알림 중복 방지용 라벨 label Jul 9, 2026
@Jy000n
Jy000n merged commit ad7b337 into develop Jul 9, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ feat slack-approval-notified Slack 승인 완료 알림 중복 방지용 라벨 🌸 자윤

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 타이머 완료/종료

3 participants