Skip to content

[feat] #72 - 타임박스 조회 #86

Merged
aneykrap merged 5 commits into
developfrom
feat/#72-time-boxes
Jul 9, 2026
Merged

[feat] #72 - 타임박스 조회 #86
aneykrap merged 5 commits into
developfrom
feat/#72-time-boxes

Conversation

@aneykrap

@aneykrap aneykrap commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

관련 이슈 🛠

작업 내용 요약 ✏️

지정한 날짜의 타임라인에 표시할 타임박스 조회 API를 구현했습니다.
사용자의 저장된 타임존 기준으로 조회 날짜를 계산하고 타이머 세션 기록을 기반으로 시작/정지/재개/완료 시점을 타임박스 응답에 포함하도록 구성했습니다.

주요 변경 사항 🛠️

  • GET /api/v1/time-boxes?date={date} 타임박스 조회 API 추가
  • 사용자 타임존 기준으로 조회 날짜의 시작/끝 범위를 UTC로 변환해 타이머 세션 조회
  • 타이머 세션 기준으로 START, PAUSE, RESUME, COMPLETE 액션 응답 구성
  • 자정을 넘는 세션은 조회 날짜 범위에 맞게 시작/종료 시간을 잘라서 반환
  • 진행 중인 타임박스는 endedAt, endActionnull로 응답
  • 완료된 타임박스는 실제 수행 시간인 actualMinutes를 응답

트러블 슈팅 ⚽️

없음

테스트 결과 📄

스크린샷 📷

<img width="976" height="658" alt="스크린샷 2026-07-09 오후 11 29 06" src="https://github.com/user-attachments/assets/1
스크린샷 2026-07-09 오후 11 59 09
2b8a078-9419-4f16-831f-bfd86473fdd9" />

타이머 시작, 재개, 종료시 화면입니다.

리뷰 요구사항 📢

없음

📎 참고 자료 (선택)

없음

Summary by CodeRabbit

  • New Features

    • 타이머를 연장, 완료, 종료할 수 있는 기능이 추가되었습니다.
    • 완료된 타이머에 대해 AI 피드백을 함께 확인할 수 있습니다.
    • 날짜별 타임박스 조회 기능이 새로 제공됩니다.
  • Bug Fixes

    • 타임박스와 AI 관련 조회가 사용자 시간대 기준으로 더 정확하게 처리되도록 개선되었습니다.
    • 날짜 입력 검증이 강화되어 잘못된 형식의 날짜를 더 명확하게 처리합니다.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 38 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: 5858f59f-b4ef-4f90-865b-fb7b5fa1afce

📥 Commits

Reviewing files that changed from the base of the PR and between 5ee70b3 and 657b1b6.

⛔ Files ignored due to path filters (1)
  • src/main/java/com/Timo/Timo/domain/timebox/docs/TimeBoxControllerDocs.java is excluded by !**/docs/**
📒 Files selected for processing (8)
  • src/main/java/com/Timo/Timo/domain/timebox/controller/TimeBoxController.java
  • src/main/java/com/Timo/Timo/domain/timebox/dto/response/TimeBoxResponse.java
  • src/main/java/com/Timo/Timo/domain/timebox/enums/TimeBoxAction.java
  • src/main/java/com/Timo/Timo/domain/timebox/exception/TimeBoxErrorCode.java
  • src/main/java/com/Timo/Timo/domain/timebox/exception/TimeBoxSuccessCode.java
  • src/main/java/com/Timo/Timo/domain/timebox/service/TimeBoxService.java
  • src/main/java/com/Timo/Timo/domain/timebox/support/TimeBoxDateParser.java
  • src/main/java/com/Timo/Timo/domain/timer/repository/TimerSessionRepository.java

Walkthrough

타임박스 조회 API(컨트롤러, 서비스, DTO, 날짜 파서, 세션 조회 쿼리)가 신규 추가됨. 타이머 연장/완료/중지 엔드포인트와 관련 도메인 로직, AI 피드백 생성 흐름(프롬프트 빌더, DTO, 파싱/검증)이 추가됨. AI 히스토리 조회가 LocalDate에서 사용자 타임존 기반 LocalDateTime 경계로 변경되고, AiTodoController 라우팅 경로가 수정됨.

Changes

타임박스 조회 API

Layer / File(s) Summary
DTO/열거형/에러코드
domain/timebox/dto/response/TimeBoxResponse.java, domain/timebox/enums/TimeBoxAction.java, domain/timebox/exception/TimeBox*Code.java
TimeBoxResponse 레코드, TimeBoxAction 열거형, 에러/성공 코드 enum이 신규 정의됨.
날짜 파서
domain/timebox/support/TimeBoxDateParser.java
날짜 문자열 필수/형식/유효성 검증 후 LocalDate로 파싱.
세션 조회 쿼리
domain/timer/repository/TimerSessionRepository.java
사용자/시간 구간 기준 fetch join 조회 메서드 findTimeBoxSessions 추가.
서비스 로직
domain/timebox/service/TimeBoxService.java
사용자 타임존 기준 일자 경계 계산, 세션→응답 매핑, 시작/종료 액션 판정, 실제 수행 분 계산.
조회 엔드포인트
domain/timebox/controller/TimeBoxController.java
/api/v1/time-boxes GET 엔드포인트로 타임박스 목록 반환.

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

타이머 연장/완료/중지 및 AI 피드백 연동

Layer / File(s) Summary
TimerRecord 도메인 확장
domain/timer/entity/TimerRecord.java, domain/timer/exception/TimerErrorCode.java, domain/timer/exception/TimerSuccessCode.java
finish, updateAiFeedback, extend 메서드 추가, 관련 에러/성공 코드 상수 추가.
연장/종료 DTO
domain/timer/dto/request/TimerExtendRequest.java, domain/timer/dto/response/TimerExtendResponse.java, domain/timer/dto/response/TimerFinishResponse.java
요청/응답 레코드와 TimerRecord 기반 정적 팩토리 메서드 추가.
서비스 흐름
domain/timer/service/TimerService.java
extendTimer, completeTimer, stopTimer, finishTimer, generateAiFeedback 추가 및 AiTodoService 연동.
엔드포인트
domain/timer/controller/TimerController.java
extendTimer/completeTimer/stopTimer PATCH 엔드포인트 및 docs 인터페이스 구현 확장.
AI 피드백 소스/프롬프트
domain/ai/dto/TodoFeedbackSource.java, domain/ai/dto/response/GeminiTodoFeedback.java, domain/ai/prompt/TodoFeedbackPromptBuilder.java
피드백 소스/응답 레코드 신규 정의 및 히스토리 기반 한국어 프롬프트 생성 로직 추가.
AI 히스토리 조회 타임존화
domain/ai/repository/AiTodoQueryRepository.java, domain/ai/service/AiTodoHistoryService.java
히스토리 조회가 LocalDate 기준에서 LocalDateTime/ZoneId 기준 경계로 변경, findFeedbackSource 추가.
AiTodoService 피드백 생성 및 라우팅
domain/ai/service/AiTodoService.java, domain/ai/controller/AiTodoController.java
createFeedback/parseFeedback/validateFeedback 추가, recommendDuration 경계 계산 변경, 컨트롤러 라우팅 경로 수정.

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

Possibly related PRs

Suggested labels: 🌸 자윤

Suggested reviewers: Jy000n, laura-jung

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 타임박스 조회와 무관한 AI 타이머 연장/완료/피드백 및 AI todo 관련 변경이 함께 포함되어 있습니다. 타임박스 조회 API에 필요한 파일만 남기고, AI todo 및 timer 확장/피드백 관련 변경은 별도 PR로 분리하세요.
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 (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 타임박스 조회 API 추가라는 핵심 변경을 간결하게 잘 요약합니다.
Linked Issues check ✅ Passed 직접 연결된 #72의 타임박스 조회 API 구현 요구를 새 TimeBox 조회 컨트롤러/서비스가 충족합니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#72-time-boxes

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: 5

🧹 Nitpick comments (1)
src/main/java/com/Timo/Timo/domain/timer/repository/TimerSessionRepository.java (1)

16-31: 🚀 Performance & Scalability | 🔵 Trivial

쿼리 성능을 위한 인덱스 확인 권장

tr.user.id = :userIdts.startedAt < :toExclusive 조건으로 결과 집합이 좁혀지지만, 대량 데이터 환경에서는 다음 인덱스 확인이 필요합니다:

  • TimerSession.startedAt — 상한 조건( < :toExclusive)에 사용
  • TimerRecord.user_id (FK 인덱스) — 사용자 필터링에 사용
  • coalesce(ts.pausedAt, :nowUtc)는 함수 호출로 인해 pausedAt 인덱스를 활용할 수 없으나, 앞선 조건들로 충분히 필터링될 것으로 예상됩니다.

fetch join으로 N+1 문제를 잘 방지하고 있습니다. As per path instructions, 필요한 경우 인덱스 고려가 되어 있는지 확인해 주세요.

🤖 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/timer/repository/TimerSessionRepository.java`
around lines 16 - 31, `TimerSessionRepository.findTimeBoxSessions`의 조회
조건(`tr.user.id`, `ts.startedAt`, `ts.pausedAt`)에 맞는 인덱스가 대량 데이터에서 성능을 좌우하므로,
`TimerSession`과 `TimerRecord`의 매핑을 기준으로 실제 DB 스키마에 `startedAt`과 `user_id` 인덱스가
있는지 확인하고 필요하면 추가하세요. 특히 `coalesce(ts.pausedAt, :nowUtc)`는 인덱스를 타기 어렵다는 점을 감안해,
`pausedAt` 인덱스는 보조적으로 검토하되 우선적으로 `findTimeBoxSessions`의 필터링 경로가 효율적인지 점검해 주세요.

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/ai/repository/AiTodoQueryRepository.java`:
- Around line 158-176: The Timestamp handling in AiTodoQueryRepository is using
the JVM default timezone via toLocalDateTime(), which can shift the date on
non-UTC servers. Update the Timestamp branch in toUserLocalDate(Object, ZoneId)
to convert from timestamp.toInstant() directly into the userZoneId and derive
the LocalDate there, while keeping the LocalDateTime overload consistent with
the same user timezone conversion logic.

In
`@src/main/java/com/Timo/Timo/domain/timer/dto/request/TimerExtendRequest.java`:
- Around line 1-12: `TimerExtendRequest`의 `extendMinutes`에 하한만 있고 상한이 없어
`extendMinutes * 60` 계산에서 `int` 오버플로우가 날 수 있으므로, 이 record 필드에 합리적인 `@Max` 제약을
추가해 입력 범위를 제한하세요. `TimerExtendRequest`의 `extendMinutes`와 이를 사용하는 서비스의 시간 변환 로직을
함께 확인해, 오버플로우가 발생하지 않는 최대 분 단위를 기준으로 검증 메시지도 함께 맞춰 주세요.

In `@src/main/java/com/Timo/Timo/domain/timer/entity/TimerRecord.java`:
- Around line 98-105: `TimerRecord.finish()` currently accepts any
`targetStatus` and only checks `isFinished()`, unlike `pause()` and `resume()`
which enforce state transitions. Update `finish(TimerStatus targetStatus,
LocalDateTime endedAt, int actualSeconds)` to validate that `targetStatus` is
only one of the allowed terminal statuses (`COMPLETED` or `STOPPED`) and throw
the appropriate domain exception for invalid values. Keep the rule encapsulated
inside `TimerRecord` alongside the other status transition methods.
- Around line 111-116: `TimerRecord.extend()` only checks `isFinished()` and
allows non-positive values, so add a defensive domain validation before updating
`extendedSeconds`. Update the `extend(int extendedSeconds)` method to reject
zero or negative input by throwing an appropriate `CustomException`/timer error,
keeping the rule enforced even when called outside the DTO path. Use the
`extend` method and `isFinished` as the main points to locate and adjust this
state change logic.

In `@src/main/java/com/Timo/Timo/domain/timer/service/TimerService.java`:
- Around line 196-197: `finishTimer`에서 `generateAiFeedback`를 같은 트랜잭션 안에서 바로 호출해
외부 AI 요청이 DB 커넥션을 오래 점유하고 있습니다. `TimerService.finishTimer`와
`generateAiFeedback`의 결합을 끊고, 타이머 저장/종료는 트랜잭션에서만 완료한 뒤 AI 피드백 생성은 커밋 이후로 분리하세요.
`@TransactionalEventListener` 같은 이벤트 기반 방식으로 `timerRecordRepository.flush()` 이후에
비동기/후처리로 실행되도록 옮기고, 관련 도메인 로직은 `TimerService`에서 외부 호출과 데이터 저장 책임이 섞이지 않게 정리하세요.

---

Nitpick comments:
In
`@src/main/java/com/Timo/Timo/domain/timer/repository/TimerSessionRepository.java`:
- Around line 16-31: `TimerSessionRepository.findTimeBoxSessions`의 조회
조건(`tr.user.id`, `ts.startedAt`, `ts.pausedAt`)에 맞는 인덱스가 대량 데이터에서 성능을 좌우하므로,
`TimerSession`과 `TimerRecord`의 매핑을 기준으로 실제 DB 스키마에 `startedAt`과 `user_id` 인덱스가
있는지 확인하고 필요하면 추가하세요. 특히 `coalesce(ts.pausedAt, :nowUtc)`는 인덱스를 타기 어렵다는 점을 감안해,
`pausedAt` 인덱스는 보조적으로 검토하되 우선적으로 `findTimeBoxSessions`의 필터링 경로가 효율적인지 점검해 주세요.
🪄 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: 83273829-a51a-4861-a15e-e9c653c5f65f

📥 Commits

Reviewing files that changed from the base of the PR and between 4688ca6 and 5ee70b3.

⛔ Files ignored due to path filters (5)
  • src/main/java/com/Timo/Timo/domain/ai/docs/AiTodoDocs.java is excluded by !**/docs/**
  • src/main/java/com/Timo/Timo/domain/timebox/docs/TimeBoxControllerDocs.java is excluded by !**/docs/**
  • src/main/java/com/Timo/Timo/domain/timer/docs/TimerCompleteControllerDocs.java is excluded by !**/docs/**
  • src/main/java/com/Timo/Timo/domain/timer/docs/TimerExtendControllerDocs.java is excluded by !**/docs/**
  • src/main/java/com/Timo/Timo/domain/timer/docs/TimerStopControllerDocs.java is excluded by !**/docs/**
📒 Files selected for processing (33)
  • src/main/java/com/Timo/Timo/domain/ai/controller/AiTodoController.java
  • src/main/java/com/Timo/Timo/domain/ai/dto/TodoDurationHistory.java
  • src/main/java/com/Timo/Timo/domain/ai/dto/TodoFeedbackSource.java
  • src/main/java/com/Timo/Timo/domain/ai/dto/request/RecommendDurationRequest.java
  • src/main/java/com/Timo/Timo/domain/ai/dto/response/GeminiTodoFeedback.java
  • src/main/java/com/Timo/Timo/domain/ai/exception/AiErrorCode.java
  • src/main/java/com/Timo/Timo/domain/ai/prompt/TodoDurationPromptBuilder.java
  • src/main/java/com/Timo/Timo/domain/ai/prompt/TodoFeedbackPromptBuilder.java
  • src/main/java/com/Timo/Timo/domain/ai/repository/AiTodoQueryRepository.java
  • src/main/java/com/Timo/Timo/domain/ai/service/AiRequestRateLimiter.java
  • src/main/java/com/Timo/Timo/domain/ai/service/AiTodoHistories.java
  • src/main/java/com/Timo/Timo/domain/ai/service/AiTodoHistoryService.java
  • src/main/java/com/Timo/Timo/domain/ai/service/AiTodoService.java
  • src/main/java/com/Timo/Timo/domain/ai/service/GeminiService.java
  • src/main/java/com/Timo/Timo/domain/tag/entity/Tag.java
  • src/main/java/com/Timo/Timo/domain/timebox/controller/TimeBoxController.java
  • src/main/java/com/Timo/Timo/domain/timebox/dto/response/TimeBoxResponse.java
  • src/main/java/com/Timo/Timo/domain/timebox/enums/TimeBoxAction.java
  • src/main/java/com/Timo/Timo/domain/timebox/exception/TimeBoxErrorCode.java
  • src/main/java/com/Timo/Timo/domain/timebox/exception/TimeBoxSuccessCode.java
  • src/main/java/com/Timo/Timo/domain/timebox/service/TimeBoxService.java
  • src/main/java/com/Timo/Timo/domain/timebox/support/TimeBoxDateParser.java
  • src/main/java/com/Timo/Timo/domain/timer/controller/TimerController.java
  • src/main/java/com/Timo/Timo/domain/timer/dto/request/TimerExtendRequest.java
  • src/main/java/com/Timo/Timo/domain/timer/dto/response/TimerExtendResponse.java
  • src/main/java/com/Timo/Timo/domain/timer/dto/response/TimerFinishResponse.java
  • src/main/java/com/Timo/Timo/domain/timer/entity/TimerRecord.java
  • src/main/java/com/Timo/Timo/domain/timer/exception/TimerErrorCode.java
  • src/main/java/com/Timo/Timo/domain/timer/exception/TimerSuccessCode.java
  • src/main/java/com/Timo/Timo/domain/timer/repository/TimerRecordRepository.java
  • src/main/java/com/Timo/Timo/domain/timer/repository/TimerSessionRepository.java
  • src/main/java/com/Timo/Timo/domain/timer/service/TimerService.java
  • src/main/java/com/Timo/Timo/domain/todo/exception/TodoErrorCode.java
💤 Files with no reviewable changes (1)
  • src/main/java/com/Timo/Timo/domain/timer/repository/TimerRecordRepository.java

Comment thread src/main/java/com/Timo/Timo/domain/ai/repository/AiTodoQueryRepository.java Outdated
Comment on lines +98 to +105
public void finish(TimerStatus targetStatus, LocalDateTime endedAt, int actualSeconds) {
if (isFinished()) {
throw new CustomException(TimerErrorCode.TIMER_ALREADY_FINISHED);
}
this.status = targetStatus;
this.endedAt = endedAt;
this.actualSeconds = actualSeconds;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

finish() 메서드가 targetStatus를 검증하지 않습니다.

기존 pause()resume()은 상태 전환을 검증하는 패턴을 따르지만, finish()targetStatusCOMPLETED 또는 STOPPED인지 확인하지 않고 어떤 상태든 허용합니다. 도메인 규칙 캡슐화를 위해 targetStatus 검증을 추가하세요.

🛡️ 제안 수정
 public void finish(TimerStatus targetStatus, LocalDateTime endedAt, int actualSeconds) {
   if (isFinished()) {
     throw new CustomException(TimerErrorCode.TIMER_ALREADY_FINISHED);
   }
+  if (targetStatus != TimerStatus.COMPLETED && targetStatus != TimerStatus.STOPPED) {
+    throw new CustomException(TimerErrorCode.TIMER_INVALID_STATUS_TRANSITION);
+  }
   this.status = targetStatus;
   this.endedAt = endedAt;
   this.actualSeconds = actualSeconds;
 }

As per path instructions, "Entity에 필요한 도메인 규칙과 상태 변경 메서드가 적절히 캡슐화되어 있는지 확인해 주세요."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void finish(TimerStatus targetStatus, LocalDateTime endedAt, int actualSeconds) {
if (isFinished()) {
throw new CustomException(TimerErrorCode.TIMER_ALREADY_FINISHED);
}
this.status = targetStatus;
this.endedAt = endedAt;
this.actualSeconds = actualSeconds;
}
public void finish(TimerStatus targetStatus, LocalDateTime endedAt, int actualSeconds) {
if (isFinished()) {
throw new CustomException(TimerErrorCode.TIMER_ALREADY_FINISHED);
}
if (targetStatus != TimerStatus.COMPLETED && targetStatus != TimerStatus.STOPPED) {
throw new CustomException(TimerErrorCode.TIMER_INVALID_STATUS_TRANSITION);
}
this.status = targetStatus;
this.endedAt = endedAt;
this.actualSeconds = actualSeconds;
}
🤖 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/timer/entity/TimerRecord.java` around
lines 98 - 105, `TimerRecord.finish()` currently accepts any `targetStatus` and
only checks `isFinished()`, unlike `pause()` and `resume()` which enforce state
transitions. Update `finish(TimerStatus targetStatus, LocalDateTime endedAt, int
actualSeconds)` to validate that `targetStatus` is only one of the allowed
terminal statuses (`COMPLETED` or `STOPPED`) and throw the appropriate domain
exception for invalid values. Keep the rule encapsulated inside `TimerRecord`
alongside the other status transition methods.

Source: Path instructions

Comment on lines +111 to +116
public void extend(int extendedSeconds){
if (isFinished()){
throw new CustomException(TimerErrorCode.TIMER_ALREADY_FINISHED);
}
this.extendedSeconds += extendedSeconds;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

extend() 메서드가 양수 입력을 검증하지 않습니다.

DTO에 @Min(1) 검증이 있으나, 도메인 메서드 자체도 방어적으로 검증해야 합니다. 다른 서비스 코드에서 직접 호출 시 음수가 전달되면 extendedSeconds가 감소하는 문제가 발생할 수 있습니다.

🛡️ 제안 수정
-public void extend(int extendedSeconds){
+public void extend(int extendedSeconds) {
+  if (extendedSeconds <= 0) {
+    throw new CustomException(TimerErrorCode.TIMER_INVALID_STATUS_TRANSITION);
+  }
   if (isFinished()){
     throw new CustomException(TimerErrorCode.TIMER_ALREADY_FINISHED);
   }
   this.extendedSeconds += extendedSeconds;
 }

As per path instructions, "Entity에 필요한 도메인 규칙과 상태 변경 메서드가 적절히 캡슐화되어 있는지 확인해 주세요."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void extend(int extendedSeconds){
if (isFinished()){
throw new CustomException(TimerErrorCode.TIMER_ALREADY_FINISHED);
}
this.extendedSeconds += extendedSeconds;
}
public void extend(int extendedSeconds) {
if (extendedSeconds <= 0) {
throw new CustomException(TimerErrorCode.TIMER_INVALID_STATUS_TRANSITION);
}
if (isFinished()) {
throw new CustomException(TimerErrorCode.TIMER_ALREADY_FINISHED);
}
this.extendedSeconds += extendedSeconds;
}
🤖 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/timer/entity/TimerRecord.java` around
lines 111 - 116, `TimerRecord.extend()` only checks `isFinished()` and allows
non-positive values, so add a defensive domain validation before updating
`extendedSeconds`. Update the `extend(int extendedSeconds)` method to reject
zero or negative input by throwing an appropriate `CustomException`/timer error,
keeping the rule enforced even when called outside the DTO path. Use the
`extend` method and `isFinished` as the main points to locate and adjust this
state change logic.

Source: Path instructions

Comment thread src/main/java/com/Timo/Timo/domain/timer/service/TimerService.java Outdated

@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.

아주 굳입니다아 머지합시다아ㅏ

@Jy000n Jy000n 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.

저도 아주 굳입니다~~

@aneykrap aneykrap force-pushed the feat/#72-time-boxes branch from 5ee70b3 to 657b1b6 Compare July 9, 2026 18:21
@github-actions github-actions Bot added ✨ feat 🌵 예나 slack-approval-notified Slack 승인 완료 알림 중복 방지용 라벨 and removed 🌵 예나 ✨ feat labels Jul 9, 2026
@aneykrap aneykrap merged commit 9490365 into develop Jul 9, 2026
3 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] 타임박스 조회 api

3 participants