Skip to content

[feat] #37 - 온보딩 - #39

Merged
Jy000n merged 15 commits into
developfrom
feat/#37-onboarding
Jul 7, 2026
Merged

Jy000n merged 15 commits into
developfrom
feat/#37-onboarding

Conversation

@Jy000n

@Jy000n Jy000n commented Jul 7, 2026

Copy link
Copy Markdown
Member

관련 이슈 🛠

작업 내용 요약 ✏️

온보딩(언어, 작업 시간 예측 정확도, 기상/취침 시간)에서 수집한 값을 한 번에 저장하고, 온보딩 완료 상태(onboarding_completed = true)로 전환하는 API를 구현했습니다.

주요 변경 사항 🛠️

  • [OnboardingController]: POST /api/v1/users/onboarding 온보딩 완료 API 엔드포인트
  • [OnboardingService]: 온보딩 값 검증 및 저장, 완료 처리 로직
  • [OnboardingRequest]: language, predictionAccuracy, wakeUpTime, bedTime 필드 및 유효성 검증
  • [OnboardingResponse]: onboardingCompleted 필드 반환 DTO
  • [OnboardingResponseFactory]: AuthResponseFactory 패턴에 맞춰 응답 조립 책임 분리
  • [OnboardingControllerDocs]: Swagger 문서화를 위한 인터페이스
  • [User]: completeOnboarding() 메서드에 파라미터 추가하여 온보딩 데이터 반영하도록 수정
  • [UserSuccessCode]: ONBOARDING_COMPLETED 성공 코드
  • [UserErrorCode]: USER_400_INVALID_TIME 에러 코드 (취침 시간이 기상 시간보다 빠른 경우)

트러블 슈팅 ⚽️

테스트 결과 📄

  • 정상 케이스: 온보딩 값 저장 및 onboardingCompleted: true 반환 확인
  • 취침 시간 < 기상 시간인 경우 400 에러 반환 확인
  • 필수 필드 누락 시 400 에러 반환 확인
  • 시간 형식이 잘못된 경우(25:00 등) 400 에러 반환 확인
  • predictionAccuracy 범위(1~4) 밖 값 요청 시 400 에러 반환 확인
  • 존재하지 않는 유저인 경우 404 에러 반환 확인

스크린샷 📷 (추가 예정)

정상 케이스: 온보딩 값 저장 및 onboardingCompleted: true 반환 확인
image
취침 시간 < 기상 시간인 경우 400 에러 반환 확인
image
필수 필드 누락 시 400 에러 반환 확인
image
시간 형식이 잘못된 경우(25:00 등) 400 에러 반환 확인
image
predictionAccuracy 범위(1~4) 밖 값 요청 시 400 에러 반환 확인
image

리뷰 요구사항 📢

📎 참고 자료 (선택)

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • 인증된 사용자를 위한 온보딩 완료 API(POST /api/v1/users/onboarding)가 추가되었습니다.
    • 온보딩 입력(언어, 예측 정확도, 기상/취침 시간)과 완료 여부 응답을 제공합니다(입력 값 검증 포함).
  • Bug Fixes
    • 취침 시간은 기상 시간 이후여야 하도록 검증해 잘못된 입력을 방지합니다.
    • 온보딩 완료 시 사용자 설정이 함께 반영됩니다.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 66be4739-d45c-4ee7-bd1f-c45f8002b7d2

📥 Commits

Reviewing files that changed from the base of the PR and between 1288370 and 559fa53.

⛔ Files ignored due to path filters (1)
  • src/main/java/com/Timo/Timo/global/auth/docs/AuthControllerDocs.java is excluded by !**/docs/**
📒 Files selected for processing (7)
  • src/main/java/com/Timo/Timo/domain/user/controller/OnboardingController.java
  • src/main/java/com/Timo/Timo/domain/user/dto/response/OnboardingResponse.java
  • src/main/java/com/Timo/Timo/domain/user/entity/User.java
  • src/main/java/com/Timo/Timo/domain/user/exception/UserErrorCode.java
  • src/main/java/com/Timo/Timo/domain/user/exception/UserSuccessCode.java
  • src/main/java/com/Timo/Timo/domain/user/factory/OnboardingResponseFactory.java
  • src/main/java/com/Timo/Timo/global/auth/controller/AuthController.java
💤 Files with no reviewable changes (1)
  • src/main/java/com/Timo/Timo/domain/user/exception/UserErrorCode.java
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/com/Timo/Timo/global/auth/controller/AuthController.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/main/java/com/Timo/Timo/domain/user/exception/UserSuccessCode.java
  • src/main/java/com/Timo/Timo/domain/user/entity/User.java
  • src/main/java/com/Timo/Timo/domain/user/dto/response/OnboardingResponse.java

Walkthrough

온보딩 완료 API가 추가되었습니다. 요청/응답 DTO, 서비스 검증 로직, 사용자 엔티티 갱신, 성공·오류 코드, 컨트롤러 엔드포인트가 함께 변경되었습니다.

Changes

온보딩 완료 처리

Layer / File(s) Summary
요청/응답 DTO와 코드
src/main/java/com/Timo/Timo/domain/user/dto/request/OnboardingRequest.java, src/main/java/com/Timo/Timo/domain/user/dto/response/OnboardingResponse.java, src/main/java/com/Timo/Timo/domain/user/exception/UserErrorCode.java, src/main/java/com/Timo/Timo/domain/user/exception/UserSuccessCode.java, src/main/java/com/Timo/Timo/domain/user/factory/OnboardingResponseFactory.java
OnboardingRequestOnboardingResponse가 추가되고, 온보딩 완료용 성공/오류 코드와 응답 래핑 팩토리가 정의됩니다.
User 온보딩 완료 메서드
src/main/java/com/Timo/Timo/domain/user/entity/User.java
completeOnboarding이 언어, 예측정확도, 기상시간, 취침시간을 받아 사용자 필드를 갱신하도록 변경됩니다.
온보딩 완료 서비스 처리
src/main/java/com/Timo/Timo/domain/user/service/OnboardingService.java
사용자 조회, 시간 파싱, 취침/기상 시간 검증 후 사용자 상태를 업데이트하고 완료 응답을 생성합니다.
온보딩 완료 엔드포인트
src/main/java/com/Timo/Timo/domain/user/controller/OnboardingController.java
인증된 사용자 ID와 요청 본문을 받아 온보딩 완료 서비스를 호출하고 BaseResponse로 반환합니다.

Estimated code review effort: 2 (Simple) | ~12 minutes

Possibly related PRs

  • Team-Timo/Timo-Server#14: 동일한 User.completeOnboarding() 확장 흐름과 온보딩 완료 상태 처리를 다룹니다.

Suggested labels: 🌵 예나, slack-approval-notified

Suggested reviewers: laura-jung

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 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 요구사항과 무관한 변경은 보이지 않으며, 남은 수정은 import 정리 수준입니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#37-onboarding

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.

🧹 Nitpick comments (5)
src/main/java/com/Timo/Timo/domain/user/dto/request/OnboardingRequest.java (2)

19-25: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

시간 정규식 중복

wakeUpTimebedTime에 동일한 HH:MM 정규식이 중복 정의되어 있습니다. 상수로 추출하면 유지보수성이 개선됩니다.

♻️ 제안
private static final String TIME_PATTERN = "^([01]\\d|2[0-3]):[0-5]\\d$";
🤖 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/user/dto/request/OnboardingRequest.java`
around lines 19 - 25, The HH:MM regex is duplicated on wakeUpTime and bedTime in
OnboardingRequest, so extract it into a shared constant and reuse it in both
`@Pattern` annotations. Add a single TIME_PATTERN field in the same DTO and update
the wakeUpTime and bedTime validation annotations to reference that constant for
easier maintenance.

1-27: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

시간 값을 String으로 받아 수동 파싱하는 대신 LocalTime + @JsonFormat 사용 검토

wakeUpTime/bedTimeString으로 받아 정규식으로 형식을 검증하고, 서비스에서 다시 LocalTime.parse하는 방식입니다. LocalTime 타입에 @JsonFormat(pattern = "HH:mm")을 적용하면 형식 오류를 Jackson 역직렬화 단계에서 처리할 수 있어 중복 검증/파싱 로직을 줄일 수 있습니다. (단, Jackson 파싱 오류를 GlobalExceptionHandler가 일관되게 처리하는지 별도 확인 필요)

🤖 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/user/dto/request/OnboardingRequest.java`
around lines 1 - 27, OnboardingRequest의 wakeUpTime/bedTime을 String 정규식 검증으로 받고
나중에 다시 파싱하는 중복을 줄이기 위해 LocalTime으로 변경하고 `@JsonFormat`(pattern = "HH:mm")를 적용하세요.
OnboardingRequest 레코드의 wakeUpTime/bedTime 필드를 LocalTime으로 바꾸고, 서비스에서
LocalTime.parse를 제거한 뒤 Jackson 역직렬화 단계에서 형식 검증이 되도록 맞추세요. 또한
GlobalExceptionHandler가 Jackson 파싱 예외를 일관되게 처리하는지 확인해 같은 응답 형식을 유지하세요.
src/main/java/com/Timo/Timo/domain/user/controller/OnboardingController.java (1)

37-39: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

하드코딩된 ResponseEntity.ok()는 successCode의 HTTP 상태와 별개로 동작

현재 UserSuccessCode.ONBOARDING_COMPLETEDHttpStatus.OK이므로 문제가 되지 않지만, ResponseEntity.ok(...)를 하드코딩하면 향후 성공 코드의 상태값이 변경되더라도 실제 HTTP 응답 코드는 반영되지 않는 구조적 위험이 있습니다. BaseResponse.onSuccess가 반환하는 successCode.getHttpStatus()ResponseEntity에도 그대로 사용하는 것이 일관성 있습니다.

♻️ 제안
-    return ResponseEntity.ok(
-        BaseResponse.onSuccess(UserSuccessCode.ONBOARDING_COMPLETED, response)
-    );
+    return ResponseEntity.status(UserSuccessCode.ONBOARDING_COMPLETED.getHttpStatus())
+        .body(BaseResponse.onSuccess(UserSuccessCode.ONBOARDING_COMPLETED, response));
🤖 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/user/controller/OnboardingController.java`
around lines 37 - 39, `OnboardingController` in the onboarding response path is
hardcoding `ResponseEntity.ok(...)`, which can diverge from
`UserSuccessCode.ONBOARDING_COMPLETED` if its HTTP status changes. Update the
controller to use the HTTP status from the success code returned by
`BaseResponse.onSuccess(...)` instead of always using `ok`, so the
`ResponseEntity` status stays aligned with the code’s `getHttpStatus()`
behavior.
src/main/java/com/Timo/Timo/domain/user/service/OnboardingService.java (1)

40-42: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

응답 값을 하드코딩하는 대신 엔티티 상태 참조 권장

onboardingCompleted(true)를 하드코딩하고 있는데, user.completeOnboarding(...) 호출 이후 실제 엔티티 상태(user.isOnboardingCompleted())를 참조하면 향후 로직 변경 시에도 응답이 실제 상태와 항상 일치함을 보장할 수 있습니다.

🤖 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/user/service/OnboardingService.java`
around lines 40 - 42, In OnboardingService, the OnboardingResponse is still
hardcoded with onboardingCompleted(true) after user.completeOnboarding(...);
update the response builder to read the actual state from the user entity via
user.isOnboardingCompleted() so the returned value always matches the domain
state. Use the existing completeOnboarding method and the
OnboardingResponse.builder() call as the main points to locate and adjust the
logic.
src/main/java/com/Timo/Timo/domain/user/entity/User.java (1)

79-90: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

도메인 불변식이 엔티티가 아닌 서비스에만 존재

completeOnboarding은 파라미터를 그대로 필드에 대입할 뿐, 취침시간이 기상시간보다 이후여야 한다는 규칙을 검증하지 않습니다. 현재는 OnboardingService에서만 이 규칙을 검증하는데, 이 메서드가 다른 경로로 호출될 경우 잘못된 상태가 저장될 수 있습니다. 도메인 규칙을 엔티티 메서드 내부로 옮겨 캡슐화하는 것을 권장합니다.

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

🤖 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/user/entity/User.java` around lines 79 -
90, Move the onboarding validation into User.completeOnboarding so the entity
enforces its own domain invariant, not just OnboardingService. In
User.completeOnboarding, check that bedTime is after wakeUpTime before assigning
fields, and reject invalid input consistently from any caller. Use the existing
completeOnboarding method and the wakeUpTime/bedTime fields as the main place to
encapsulate this rule.
🤖 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.

Nitpick comments:
In
`@src/main/java/com/Timo/Timo/domain/user/controller/OnboardingController.java`:
- Around line 37-39: `OnboardingController` in the onboarding response path is
hardcoding `ResponseEntity.ok(...)`, which can diverge from
`UserSuccessCode.ONBOARDING_COMPLETED` if its HTTP status changes. Update the
controller to use the HTTP status from the success code returned by
`BaseResponse.onSuccess(...)` instead of always using `ok`, so the
`ResponseEntity` status stays aligned with the code’s `getHttpStatus()`
behavior.

In `@src/main/java/com/Timo/Timo/domain/user/dto/request/OnboardingRequest.java`:
- Around line 19-25: The HH:MM regex is duplicated on wakeUpTime and bedTime in
OnboardingRequest, so extract it into a shared constant and reuse it in both
`@Pattern` annotations. Add a single TIME_PATTERN field in the same DTO and update
the wakeUpTime and bedTime validation annotations to reference that constant for
easier maintenance.
- Around line 1-27: OnboardingRequest의 wakeUpTime/bedTime을 String 정규식 검증으로 받고
나중에 다시 파싱하는 중복을 줄이기 위해 LocalTime으로 변경하고 `@JsonFormat`(pattern = "HH:mm")를 적용하세요.
OnboardingRequest 레코드의 wakeUpTime/bedTime 필드를 LocalTime으로 바꾸고, 서비스에서
LocalTime.parse를 제거한 뒤 Jackson 역직렬화 단계에서 형식 검증이 되도록 맞추세요. 또한
GlobalExceptionHandler가 Jackson 파싱 예외를 일관되게 처리하는지 확인해 같은 응답 형식을 유지하세요.

In `@src/main/java/com/Timo/Timo/domain/user/entity/User.java`:
- Around line 79-90: Move the onboarding validation into User.completeOnboarding
so the entity enforces its own domain invariant, not just OnboardingService. In
User.completeOnboarding, check that bedTime is after wakeUpTime before assigning
fields, and reject invalid input consistently from any caller. Use the existing
completeOnboarding method and the wakeUpTime/bedTime fields as the main place to
encapsulate this rule.

In `@src/main/java/com/Timo/Timo/domain/user/service/OnboardingService.java`:
- Around line 40-42: In OnboardingService, the OnboardingResponse is still
hardcoded with onboardingCompleted(true) after user.completeOnboarding(...);
update the response builder to read the actual state from the user entity via
user.isOnboardingCompleted() so the returned value always matches the domain
state. Use the existing completeOnboarding method and the
OnboardingResponse.builder() call as the main points to locate and adjust the
logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b0321237-0cdc-4095-8f96-f3c4fce2c73f

📥 Commits

Reviewing files that changed from the base of the PR and between fa2e464 and 1288370.

⛔ Files ignored due to path filters (1)
  • src/main/java/com/Timo/Timo/domain/user/docs/OnboardingControllerDocs.java is excluded by !**/docs/**
📒 Files selected for processing (7)
  • src/main/java/com/Timo/Timo/domain/user/controller/OnboardingController.java
  • src/main/java/com/Timo/Timo/domain/user/dto/request/OnboardingRequest.java
  • src/main/java/com/Timo/Timo/domain/user/dto/response/OnboardingResponse.java
  • src/main/java/com/Timo/Timo/domain/user/entity/User.java
  • src/main/java/com/Timo/Timo/domain/user/exception/UserErrorCode.java
  • src/main/java/com/Timo/Timo/domain/user/exception/UserSuccessCode.java
  • src/main/java/com/Timo/Timo/domain/user/service/OnboardingService.java

Jy000n added 2 commits July 8, 2026 02:44
…to feat/#37-onboarding

# Conflicts:
#	src/main/java/com/Timo/Timo/domain/user/exception/UserSuccessCode.java
laura-jung
laura-jung previously approved these changes Jul 7, 2026

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

아주 깔끔하고 굳입니다. 불필요한 여백만 없애주시면 될 것 같아용
어푸드립니다아ㅏ

public record OnboardingResponse(
boolean onboardingCompleted
) {

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.

p4) 별도로 들어가는 값이 없다면 빈칸 없애도 될 것 같아요

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.

넵 반영 완료했습니다-! 감사합니다아

public enum UserErrorCode implements BaseErrorCode {

USER_400_INVALID_TIME(HttpStatus.BAD_REQUEST, "USER_400", "취침 시간은 기상 시간보다 이후여야 합니다."),

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) 여기도 여백 삭제해주세요

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.

넵넵 수정했습니당

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

넹 여백제거 좋습니당

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

pr 내용에 맞게 구현된 거 확인했습니다!!
취침시간 기상시간이 24시 이내로 기획된 내용이면 같은 날짜로 비교해서 진행해도 될것 같습니다
고생 많았어용

@github-actions github-actions Bot added the slack-approval-notified Slack 승인 완료 알림 중복 방지용 라벨 label Jul 7, 2026
@Jy000n
Jy000n merged commit 77fee04 into develop Jul 7, 2026
7 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