Skip to content

찌르기 쿨타임 처리 수정#171

Merged
chanho0908 merged 16 commits into
developfrom
fix/#170-photolog-poke-cooldown
Jul 7, 2026
Merged

찌르기 쿨타임 처리 수정#171
chanho0908 merged 16 commits into
developfrom
fix/#170-photolog-poke-cooldown

Conversation

@chanho0908

@chanho0908 chanho0908 commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

이슈 번호

#170

작업내용

  • 찌르기 쿨타임 중 인증샷 상세 화면에서 토스트가 표시되지 않는 문제, 시간 경과 후 자동으로 해제되도록 수정
  • 찌르기 쿨타임 저장 기준을 goalId 단독에서 goalId + targetDate 복합키로 변경해, 같은 목표라도 날짜별로 독립적인 쿨타임을 갖도록 수정
  • Room poke_history 스키마 변경에 따라 DB version을 2로 올리고 MIGRATION_1_2를 추가
    • 기존 poke_history는 날짜 정보가 없는 로컬 쿨타임 캐시라 drop/recreate 처리
  • 홈 화면과 인증샷 상세 화면의 찌르기 호출부에서 각각 선택 날짜/상세 날짜를 전달하도록 수정

결과물

123.mp4

리뷰어에게 추가로 요구하는 사항 (선택)

@coderabbitai

coderabbitai Bot commented Jun 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.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 659d839f-3d37-4c31-8573-9d7c30ddae01

📥 Commits

Reviewing files that changed from the base of the PR and between cfc3b1a and ea312ca.

📒 Files selected for processing (2)
  • feature/photolog/detail/src/main/java/com/twix/photolog/detail/PhotologDetailViewModel.kt
  • feature/photolog/detail/src/main/java/com/twix/photolog/detail/component/PhotologCardContent.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • feature/photolog/detail/src/main/java/com/twix/photolog/detail/PhotologDetailViewModel.kt

📝 Walkthrough

Walkthrough

포크(찌르기) 쿨다운을 목표(goalId) 단독 기준에서 목표와 날짜(targetDate) 조합 기준으로 변경했습니다. Room 데이터베이스 버전을 2로 올리고 poke_history 테이블을 복합 기본키(goalId, targetDate)로 마이그레이션했습니다. Repository, UseCase, DAO 시그니처 전반에 targetDate 파라미터를 추가했고, PhotologDetailViewModel의 쿨다운 해제를 Job 기반 지연 스케줄링으로 재구성했습니다. UI 컴포넌트에서 isPokeDisabled 파라미터를 제거하고 uiState 필드를 사용하도록 정리했으며, 관련 테스트를 갱신·추가했습니다. PR 템플릿도 일부 수정되었습니다.

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

변경 사항

구성요소 변경 내용
데이터베이스 Room 버전 1→2, MIGRATION_1_2 추가, PokeHistoryEntity 복합 기본키 전환, DAO 조회 메서드 시그니처 변경
데이터/도메인 PokeRepository, DefaultPokeRepository, PokeGoalUseCasesavePokeHistory/findPokeHistory/invoke/remainingCooldowntargetDate 파라미터 추가
ViewModel PhotologDetailViewModel 쿨다운 처리를 Job 기반 지연 해제 로직으로 재구성, HomeViewModel에서 선택 날짜 전달
UI PhotologCardContentisPokeDisabled 파라미터 제거 및 uiState 기반으로 전환
테스트 FakePokeRepositoryPokeGoalUseCaseTest를 복합 키 기반으로 갱신, 날짜별 독립 쿨다운 검증 테스트 추가
문서 PR 템플릿 항목 구성 변경

Sequence Diagram(s)

sequenceDiagram
  participant PhotologDetailViewModel
  participant PokeGoalUseCase
  participant PokeRepository
  participant PokeHistoryDao

  PhotologDetailViewModel->>PokeGoalUseCase: invoke(goalId, targetDate)
  PokeGoalUseCase->>PokeRepository: findPokeHistory(goalId, targetDate)
  PokeRepository->>PokeHistoryDao: findPokeHistoryEntity(goalId, targetDate)
  PokeHistoryDao-->>PokeRepository: PokeHistoryEntity? / pokedAt
  PokeRepository-->>PokeGoalUseCase: pokedAt or null
  alt 쿨다운 중
    PokeGoalUseCase-->>PhotologDetailViewModel: OnCooldown(remainingMs)
    PhotologDetailViewModel->>PhotologDetailViewModel: startPokeCooldown(remainingMs)
  else 쿨다운 없음
    PokeGoalUseCase->>PokeRepository: savePokeHistory(goalId, targetDate, now)
    PokeGoalUseCase-->>PhotologDetailViewModel: Success
    PhotologDetailViewModel->>PhotologDetailViewModel: startPokeCooldown(COOLDOWN_MS)
  end
Loading

주요 이슈: 명시적으로 연결된 이슈 없음
관련 PR: 없음
제안 라벨: database-migration, refactor, cooldown-logic
제안 리뷰어: 없음 (저장소 정보 부족으로 특정 불가)

시:

토끼가 콕콕 찌르던 그 시절엔
goalId 하나로 온종일 기다렸는데
이젠 날짜마다 새 마음으로
쿨다운도 하루하루 다시 시작해요
poke_history 테이블도 새 단장 마치고
콩콩 뛰는 마음으로 머지를 기다려요 🐰
🚥 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
Title check ✅ Passed 제목이 찌르기 쿨타임 처리 수정이라는 मुख्य 변경점을 간결하게 잘 요약합니다.
Description check ✅ Passed 설명이 이슈 번호와 변경 내용, 결과물까지 PR 변경사항과 일치하게 잘 작성되었습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 fix/#170-photolog-poke-cooldown

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.

@chanho0908 chanho0908 self-assigned this Jun 7, 2026
@chanho0908 chanho0908 added the Refactor Good for newcomers label Jun 7, 2026
@chanho0908 chanho0908 changed the title 인증샷 상세 찌르기 쿨타임 처리 수정 찌르기 쿨타임 처리 수정 Jun 7, 2026

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
domain/src/main/java/com/twix/domain/usecase/PokeGoalUseCase.kt (1)

31-35: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

시스템 시간 변경 시 쿨타임이 설정값(3시간)을 초과할 수 있습니다.

현재는 pokedAtcurrentTime보다 미래면 elapsedMs가 음수가 되어 remainingMsCOOLDOWN_MS보다 커질 수 있습니다. 사용자 입장에서는 쿨타임이 비정상적으로 길어집니다. remainingMs0..COOLDOWN_MS 범위로 고정해 주세요.

수정 예시
-        val elapsedMs = currentTime - pokedAt
-        val remainingMs = COOLDOWN_MS - elapsedMs
-
-        return remainingMs.coerceAtLeast(0L)
+        val elapsedMs = (currentTime - pokedAt).coerceAtLeast(0L)
+        val remainingMs = COOLDOWN_MS - elapsedMs
+
+        return remainingMs.coerceIn(0L, COOLDOWN_MS)
🤖 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 `@domain/src/main/java/com/twix/domain/usecase/PokeGoalUseCase.kt` around lines
31 - 35, The current remainingMs calculation can exceed COOLDOWN_MS if pokedAt
is in the future; modify the return in PokeGoalUseCase (where currentTime,
elapsedMs and remainingMs are computed) to clamp remainingMs into the
0..COOLDOWN_MS range—e.g. replace remainingMs.coerceAtLeast(0L) with
remainingMs.coerceIn(0L, COOLDOWN_MS) so the returned cooldown is never negative
or greater than the configured COOLDOWN_MS.
🧹 Nitpick comments (1)
feature/photolog/detail/src/test/java/com/twix/photolog/detail/PhotologDetailViewModelTest.kt (1)

67-88: ⚡ Quick win

Sad Path 테스트가 빠져 있어 회귀를 놓칠 수 있습니다.

현재 케이스는 쿨타임 정상 흐름 검증은 좋지만, pokeGoalResult = AppResult.Error(...) 상황에서 isPoking 복구와 실패 후 상태를 검증하지 않아 회귀 여지가 남습니다.
에러 경로 테스트 1건을 추가해 dispatch(PhotologDetailIntent.Poke) 이후 isPoking == false 및 쿨타임 상태/사이드이펙트 기대값을 함께 확인해보실까요?

As per coding guidelines, "Happy / Sad Path가 모두 커버되는가?" 항목에 따라 실패 경로 검증을 포함하는 것이 좋습니다.

🤖 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
`@feature/photolog/detail/src/test/java/com/twix/photolog/detail/PhotologDetailViewModelTest.kt`
around lines 67 - 88, Add a sad-path unit test that mirrors the existing
cooldown test but configures FakePokeRepository to return AppResult.Error for
the poke call, then dispatch PhotologDetailIntent.Poke and advance the test
dispatcher (runCurrent/runTest); assert that viewModel.uiState.value.isPoking is
false after the failure, verify pokeCooldownRemaining and isPokeDisabled reflect
the expected post-error state, and check pokeRepository.pokeGoalCallCount (and
any error-handling side-effects) to ensure the failure path is covered; use the
same helpers (createViewModel, FakePokeRepository,
runTest/StandardTestDispatcher, PhotologDetailIntent.Poke) so the new test
parallels the happy-path case.

Source: Coding guidelines

🤖 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
`@feature/photolog/detail/src/main/java/com/twix/photolog/detail/PhotologDetailViewModel.kt`:
- Around line 175-179: The pokeToPartner() coroutine sets isPoking = true then
calls pokeGoalUseCase.invoke(...) but if that call throws the ViewModel can
remain stuck; wrap the invoke + handlePokeResult call in a try/catch inside
pokeToPartner(), on exception call handlePokeError(exception) and ensure
isPoking is cleared (reduce { copy(isPoking = false) }) in both success and
error paths; rethrow CancellationException (if exception is
CancellationException) so cancellations propagate normally.

---

Outside diff comments:
In `@domain/src/main/java/com/twix/domain/usecase/PokeGoalUseCase.kt`:
- Around line 31-35: The current remainingMs calculation can exceed COOLDOWN_MS
if pokedAt is in the future; modify the return in PokeGoalUseCase (where
currentTime, elapsedMs and remainingMs are computed) to clamp remainingMs into
the 0..COOLDOWN_MS range—e.g. replace remainingMs.coerceAtLeast(0L) with
remainingMs.coerceIn(0L, COOLDOWN_MS) so the returned cooldown is never negative
or greater than the configured COOLDOWN_MS.

---

Nitpick comments:
In
`@feature/photolog/detail/src/test/java/com/twix/photolog/detail/PhotologDetailViewModelTest.kt`:
- Around line 67-88: Add a sad-path unit test that mirrors the existing cooldown
test but configures FakePokeRepository to return AppResult.Error for the poke
call, then dispatch PhotologDetailIntent.Poke and advance the test dispatcher
(runCurrent/runTest); assert that viewModel.uiState.value.isPoking is false
after the failure, verify pokeCooldownRemaining and isPokeDisabled reflect the
expected post-error state, and check pokeRepository.pokeGoalCallCount (and any
error-handling side-effects) to ensure the failure path is covered; use the same
helpers (createViewModel, FakePokeRepository, runTest/StandardTestDispatcher,
PhotologDetailIntent.Poke) so the new test parallels the happy-path case.
🪄 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.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 668257ad-95ce-406a-a7cd-339c9c5f44fa

📥 Commits

Reviewing files that changed from the base of the PR and between dbbd63a and cfc3b1a.

📒 Files selected for processing (15)
  • .github/PULL_REQUEST_TEMPLATE.md
  • core/database/src/main/java/com/twix/database/TwixDatabase.kt
  • core/database/src/main/java/com/twix/database/di/DatabaseModule.kt
  • core/database/src/main/java/com/twix/database/poke/PokeHistoryDao.kt
  • core/database/src/main/java/com/twix/database/poke/PokeHistoryEntity.kt
  • data/src/main/java/com/twix/data/repository/DefaultPokeRepository.kt
  • domain/src/main/java/com/twix/domain/repository/PokeRepository.kt
  • domain/src/main/java/com/twix/domain/usecase/PokeGoalUseCase.kt
  • domain/src/test/java/com/twix/domain/fake/FakePokeRepository.kt
  • domain/src/test/java/com/twix/domain/usecase/PokeGoalUseCaseTest.kt
  • feature/main/src/main/java/com/twix/home/HomeViewModel.kt
  • feature/photolog/detail/src/main/java/com/twix/photolog/detail/PhotologDetailScreen.kt
  • feature/photolog/detail/src/main/java/com/twix/photolog/detail/PhotologDetailViewModel.kt
  • feature/photolog/detail/src/main/java/com/twix/photolog/detail/component/PhotologCardContent.kt
  • feature/photolog/detail/src/test/java/com/twix/photolog/detail/PhotologDetailViewModelTest.kt
💤 Files with no reviewable changes (2)
  • .github/PULL_REQUEST_TEMPLATE.md
  • feature/photolog/detail/src/main/java/com/twix/photolog/detail/PhotologDetailScreen.kt

@chanho0908 chanho0908 requested a review from dogmania June 7, 2026 00:59

@dogmania dogmania left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

고생하셨습니다!

onClickUpload
} else {
{ if (!isPokeDisabled) onPoke() }
{ if (!uiState.isPoking) onPoke() }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PhotologDetailUiState에 선언되어 있는 isPokeDisabled를 사용하는 건 어떨까요? 지금 isPoking만 바라보고 있으면 쿨다운 상황에서도 클릭 이벤트 자체는 발생할 것 같습니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

리뷰 반영 커밋 : ea312ca

Comment on lines 175 to +178
private fun pokeToPartner() {
viewModelScope.launch {
startPokeLoading()
handlePokeResult(pokeGoalUseCase.invoke(argGoalId))
reduce { copy(isPoking = true) }
handlePokeResult(pokeGoalUseCase.invoke(argGoalId, argTargetDate.toString()))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

메서드 초반에 isPoking이나 isPokeDisabled 활용해서 가드 로직을 추가하면 좋을 거 같아요

@chanho0908 chanho0908 merged commit 5a4acad into develop Jul 7, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Refactor Good for newcomers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants