Skip to content

Refactor: expense/category mutation 정책을 queries 레이어로 일원화 - #203

Merged
hyun907 merged 4 commits into
developfrom
refactor/#113/expense-mutation
May 20, 2026
Merged

Refactor: expense/category mutation 정책을 queries 레이어로 일원화#203
hyun907 merged 4 commits into
developfrom
refactor/#113/expense-mutation

Conversation

@hyun907

@hyun907 hyun907 commented Apr 28, 2026

Copy link
Copy Markdown
Member

📝 PR 유형

  • 🔨 리팩토링

    🔔 관련된 이슈 넘버

    ✅ 작업 목록

    1. expense mutation을 queries 레이어로 이동

    • ExpenseEditBottomSheet/ExpenseRecordFunnel에 흩어져 있던 useMutation 선언과 invalidateQueries 로직을
      expenseQueries로 일원화
    • recordMutation/updateMutation/deleteMutation 모두 QueryClient를 받아 entityExpenseQueries.all +
      expenseReportQueries.all을 공통 헬퍼(invalidateExpenseCaches)로 무효화
    • UI 레이어는 mutate(vars, { onSuccess, onError }) 콜백으로 화면별
      부수효과(토스트·네비게이션·onConfirm/onDelete 등)만 담당

    2. category mutation의 중복 invalidateQueries 제거

    • AddCategory/AddCategoryStep에서 useMutation({ ...categoryQueries.xxx(qc), onSuccess }) 형태로
      override하면서 queries 레이어의 onSuccess를 가리고, UI가 직접 invalidateQueries를 다시 호출하던 중복
      패턴을 제거
    • expense와 동일하게 useMutation(categoryQueries.xxx(qc)) + per-call mutate 콜백 구조로 정리

    3. 미사용 api 배럴 정리

    • features/expense/api/index.ts(updateExpense/deleteExpense/getCategoryList 재내보내기)는 리팩토링 후
      어디서도 직접 import하지 않아 파일 자체를 삭제
    • 이를 트레일링하던 model/index.ts의 export * from '../api' 한 줄도 제거

    🍰 논의사항

    컨벤션 결정 사항

    • 토스트 위치: UI 레이어 유지. 위치별 메시지("저장됐어요"/"수정됐어요"/"삭제됐어요"/"추가됐어요"/...)가
      다르고 카테고리 패턴과 일관됨.
    • mutation 콜백 합성: queries 레이어 옵션을 spread + override하는 대신, useMutation(queries.xxx(qc))로
      그대로 받고 화면별 부수효과는 .mutate(vars, { onSuccess, onError })로 주입. 이렇게 하면 queries 레이어의
      invalidate가 항상 먼저 실행되고 UI 콜백이 뒤따릅니다 (override 시에는 queries 레이어 onSuccess가 가려져서
      실행되지 않음).

    동작 변화 (의도된 trade-off)

    • AddCategory create 플로우의 await invalidate → navigate 순서가 fire-and-forget으로 변경됨.
      setSubmitSuccess(true)는 동기적으로 navigate 전에 적용되므로 duplicate-name 플래시 방지는 그대로
      동작합니다. navigate 후 페이지가 카테고리 list freshness에 의존하지 않아 UX 영향 없음.
    • mutate-level 콜백은 v5에서 컴포넌트 언마운트 시 실행되지 않습니다(mutation observer 콜백은 실행됨). 캐시
      무효화는 queries 레이어에 있으므로 항상 실행되며, submit 중 isPending으로 버튼이 disabled되어 정상
      플로우에서 언마운트 트리거 가능성은 낮습니다.

    후속 cleanup 후보 (이번 PR 범위 외)

    • queries 레이어에 default onError 부재 → 미래 호출자가 onError를 빠뜨리면 silent 실패. 현재 모든 호출
      site는 전달하므로 문제 없음. 안전망 필요 시 fallback 추가 검토.
    • expenseQueries.recordMutation vs categoryQueries.createMutation 네이밍 차이. 도메인 어휘(기록 vs 생성)
      차이로 의도된 부분.

    📷 ETC

    기대 효과:

    • UI 컴포넌트 경량화 (mutation 정의·캐시 정책·중복 invalidate 제거)
    • 서버 상태 관리 정책 일관성 확보
    • 캐시 전략 변경 시 수정 범위가 queries 레이어로 한정됨

Summary by CodeRabbit

릴리스 노트

  • Refactor
    • 뮤테이션 캐시 무효화 로직을 쿼리 정의에서 일괄 관리하도록 개선했습니다.
    • 비용 및 카테고리 뮤테이션 구성을 표준화하여 일관된 동작을 제공합니다.

hyun907 and others added 3 commits April 28, 2026 14:03
ExpenseEditBottomSheet/ExpenseRecordFunnel의 inline useMutation 선언과
중복 invalidateQueries 호출을 제거하고, expenseQueries 레이어에서
record/update/delete mutation과 캐시 무효화 정책을 일원화. UI는
mutate(vars, { onSuccess, onError }) 콜백으로 토스트/네비게이션 등
화면별 부수효과만 담당.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AddCategory/AddCategoryStep의 useMutation onSuccess override가 queries
레이어의 onSuccess를 가리면서 UI가 invalidateQueries를 다시 호출하던
중복 패턴을 제거. expense와 동일하게 useMutation(categoryQueries.xxx(qc))
형태로 단순화하고, 토스트·네비게이션·setSubmitSuccess 등 화면별 부수효과는
mutate(vars, { onSuccess, onError }) 콜백으로 이동.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
리팩토링 후 updateExpense/deleteExpense/getCategoryList는 expenseQueries
와 categoryQueries에서만 직접 경로로 import해 사용. api/index.ts와 이를
재내보내던 model/index.ts의 한 줄을 정리.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyun907
hyun907 requested a review from ssilver01 April 28, 2026 05:37
@hyun907 hyun907 self-assigned this Apr 28, 2026
@hyun907 hyun907 added the 🔨 Refactor 코드 리팩토링 label Apr 28, 2026
@hyun907 hyun907 linked an issue Apr 28, 2026 that may be closed by this pull request
11 tasks
@vercel

vercel Bot commented Apr 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nitrogen-front-web Ready Ready Preview, Comment Apr 28, 2026 6:02am

@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@hyun907 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 36 minutes and 0 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8966a59f-3756-44d6-b521-2678b4cd0f6f

📥 Commits

Reviewing files that changed from the base of the PR and between b1135e5 and 4d2c483.

📒 Files selected for processing (2)
  • apps/web/src/features/expense/ui/ExpenseEditBottomSheet.tsx
  • apps/web/src/shared/ui/alertDialog/AlertDialog.tsx

Walkthrough

Expense 관련 mutation 로직과 캐시 무효화 처리를 expenseQueries 모델 레이어로 통합하는 리팩토링입니다. UI 컴포넌트에서 분산된 mutation 설정과 캐시 관리 책임을 중앙화하여 관심사를 분리합니다.

Changes

Cohort / File(s) Summary
Expense Query 레이어
apps/web/src/features/expense/model/expenseQueries.ts
QueryClient를 받는 recordMutation, updateMutation, deleteMutation 팩토리 함수 추가. 모든 mutation에 공통 invalidateExpenseCaches 핸들러를 onSuccess로 등록하여 expense/expenseReport 캐시 일괄 무효화.
Expense API 내보내기 정리
apps/web/src/features/expense/api/index.ts, apps/web/src/features/expense/model/index.ts
getCategoryList, updateExpense, deleteExpense 재내보내기 제거. barrel export 경로 정리로 명시적 import 강제.
Expense 수정 UI
apps/web/src/features/expense/ui/ExpenseEditBottomSheet.tsx
로컬 mutation 설정 제거. expenseQueries.updateMutation(queryClient), expenseQueries.deleteMutation(queryClient) 사용. per-call onSuccess/onError 콜백으로 토스트/콜백 처리 이동.
Expense 기록 UI
apps/web/src/features/expense/ui/steps/AddCategoryStep/AddCategoryStep.tsx, apps/web/src/widgets/expenseRecordFunnel/ui/ExpenseRecordFunnel.tsx
Hook 레벨 onSuccess/onError 제거. expenseQueries.recordMutation(queryClient) 사용. 캐시 무효화는 query 레이어로 이관, UI는 형식 초기화와 토스트 표시만 담당.
카테고리 생성 UI
apps/web/src/widgets/addCategory/ui/AddCategory.tsx
mutation side-effect를 useMutation 설정에서 mutate 호출 옵션으로 이동. onSuccess/onError 콜백을 per-call로 전달하여 UI 이벤트 처리와 캐시 무효화 책임 분리.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • ssilver01

Poem

🐰 캐시 무효화 한 곳에 모아,
Mutation 정책 명확하게 정리,
UI는 가볍게, Query는 든든하게,
관심사 분리의 우아함이 피어난다! ✨

🚥 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 제목은 PR의 주요 변경 사항을 명확하게 요약합니다. 'expense/category mutation 정책을 queries 레이어로 일원화'는 변경의 핵심 목표와 영향 범위를 정확하게 설명합니다.
Linked Issues check ✅ Passed PR은 #113의 모든 주요 목표를 달성합니다. expenseQueries에 updateMutation/deleteMutation/recordMutation을 정의하고 invalidateExpenseCaches 공통 헬퍼를 추가하였으며, UI 컴포넌트에서 mutate 호출 시 per-call 콜백으로 부수효과를 처리하고 중복 캐시 무효화를 제거했습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #113의 범위 내입니다. 사용되지 않는 API 배럴 제거, expenseQueries 레이어 통합, UI 컴포넌트 리팩토링이 모두 명시된 목표에 부합합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/#113/expense-mutation

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 and usage tips.

@hyun907 hyun907 changed the title Refactor/#113/expense mutation Refactor: expense/category mutation 정책을 queries 레이어로 일원화 Apr 28, 2026
@github-actions

github-actions Bot commented Apr 28, 2026

Copy link
Copy Markdown

🎨 Storybook 배포 완료

📚 Storybook: https://6960ec095e9394ddeaa0f9f3-safpodriho.chromatic.com/
🔍 Chromatic 빌드: https://www.chromatic.com/build?appId=6960ec095e9394ddeaa0f9f3&number=203

UI 변경사항을 확인해주세요!

@github-actions

Copy link
Copy Markdown

🎉 구현한 기능 Preview: https://nitrogen-front-609n2i14l-ssilver01s-projects.vercel.app

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/src/features/expense/ui/ExpenseEditBottomSheet.tsx`:
- Around line 167-183: The delete dialog is closed immediately after calling
deleteMutation.mutate which hides the UI even if deletion fails; move the
setIsDeleteDialogOpen(false) call into the mutate onSuccess callback (inside
deleteMutation.mutate's onSuccess) so the dialog only closes when delete
succeeds, and ensure it is not called in onError (keep current handleApiError
behavior to leave the dialog open on failure); reference deleteMutation.mutate,
its onSuccess/onError callbacks, and setIsDeleteDialogOpen when making this
change.
🪄 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

Run ID: 6b2d3521-2550-495e-b11e-ba28b7b552e6

📥 Commits

Reviewing files that changed from the base of the PR and between 7e21281 and b1135e5.

📒 Files selected for processing (7)
  • apps/web/src/features/expense/api/index.ts
  • apps/web/src/features/expense/model/expenseQueries.ts
  • apps/web/src/features/expense/model/index.ts
  • apps/web/src/features/expense/ui/ExpenseEditBottomSheet.tsx
  • apps/web/src/features/expense/ui/steps/AddCategoryStep/AddCategoryStep.tsx
  • apps/web/src/widgets/addCategory/ui/AddCategory.tsx
  • apps/web/src/widgets/expenseRecordFunnel/ui/ExpenseRecordFunnel.tsx
💤 Files with no reviewable changes (2)
  • apps/web/src/features/expense/api/index.ts
  • apps/web/src/features/expense/model/index.ts

Comment thread apps/web/src/features/expense/ui/ExpenseEditBottomSheet.tsx Outdated
@github-actions

Copy link
Copy Markdown

🎉 구현한 기능 Preview: https://nitrogen-front-oronclsln-ssilver01s-projects.vercel.app

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

수고하셨어요 ~! 전체적으로 구조 개선 방향이 좋습니다 !!
mutation/invalidate를 queries 레이어로 일원화 + mutate 콜백으로 UI 사이드이팩트 분리 패턴 👍👍 덕분에 서버 상태 관리 책임이 명확해졌고, UI도 많이 가벼워졌네요 👍

invalidate 범위가 현재는 조금 넓어서 추후 최적화 여지 있어 보이고
onError 기본 처리만 하나 있으면 더 안전할 것 같습니다~!!

@hyun907
hyun907 merged commit 0012735 into develop May 20, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔨 Refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ Refactor ] Expense mutation 및 캐시 무효화 로직 expenseQueries로 이동

2 participants