[REFACTOR] 폴더 구조 정리 및 쿼리/뮤테이션 훅 네이밍 컨벤션 적용 - #219
Conversation
- api/common, types/, hooks/ 루트에 흩어져 있던 스키마·타입·훅을 도메인별 폴더로 이동했습니다 - 폴더 이동으로 깨진 import 경로를 전체 수정했습니다 - 쿼리/뮤테이션 훅 11개의 파일명·함수명을 -query/-mutation, ~Query/~Mutation 컨벤션으로 통일했습니다
- naming.md에 TanStack Query 훅의 파일명·함수명 컨벤션을 추가했습니다 - timo-api-integration 스킬의 _queries 훅 작성 가이드와 예시를 새 컨벤션에 맞게 갱신했습니다
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (58)
Walkthrough도메인별 Zod 스키마와 타입을 추가하고, TanStack Query 훅의 명명·경로를 정리했습니다. 관련 화면과 타이머 연동 코드를 새 엔트리포인트로 전환했으며, 오늘 Todo 카드와 OverlayProvider를 추가했습니다. Changes스키마 및 Query 훅 구조 정리
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Timo Performance ReportBundle Size — timo-web
Lighthouse — timo-web
Image Optimization — timo-web
측정 커밋: |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts (1)
29-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
useCreateTodoSubmit훅의 로직 중복 및 검증 일관성 문제깔끔하게 생성 로직을 잘 작성해 주셨네요! ✨
살펴보니 두 파일에 동일한 역할을 수행하는 비즈니스 훅이 나뉘어 존재하고 있습니다. 특히 전역 훅에는 응답을 검증하는
safeParse로직이 있지만, 오늘(Today) 화면용 훅에는 해당 로직이 누락되어 있어 동작에 일관성이 부족한 상황입니다.
로직 파편화를 방지하고 유지보수성을 높이기 위해, 하나의 훅으로 깔끔하게 통합하고 외부에서 무효화(invalidate)할 쿼리 키를 주입받는 구조로 개선하는 것을 추천합니다. React 공식 문서 - Hook 추출하기
apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts#L29-L60: 메인 훅으로서 매개변수를 통해queryKeysToInvalidate를 주입받을 수 있도록 수정해 보세요.apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.ts#L28-L52: 해당 중복 훅을 제거하고, 위에서 수정된 전역 훅에 필요한 쿼리 키를 넘겨 재사용하도록 교체하세요.💡 리팩터링 아이디어 (참고용)
import type { QueryKey } from "`@tanstack/react-query`"; export const useCreateTodoSubmit = (queryKeysToInvalidate: QueryKey[]) => { // ... (동일한 초기화 및 빌드 로직) const handleSubmit = (data: CreateTodoRequest) => { createTodo( { data: buildCreateTodoRequestBody(data) }, { onSuccess: (response) => { const parsed = todoCreateResponseSchema.safeParse(response.data); if (!parsed.success) { setIsErrorToastOpen(true); return; } queryKeysToInvalidate.forEach((key) => queryClient.invalidateQueries({ queryKey: key }) ); }, onError: () => { setIsErrorToastOpen(true); }, } ); }; // ... };🤖 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 `@apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts` around lines 29 - 60, The duplicated create-submit hooks lack a shared, consistent response-validation flow. In apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts:29-60, update useCreateTodoSubmit to accept queryKeysToInvalidate: QueryKey[] and invalidate each supplied key after successful todoCreateResponseSchema validation; preserve the existing error-toast behavior. In apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.ts:28-52, remove the duplicate hook implementation and reuse the global useCreateTodoSubmit, passing the Today screen’s required query keys.apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.ts (1)
120-130: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win에러 발생 시 낙관적 업데이트를 롤백하는 로직이 누락되었습니다.
투두 완료 상태를 변경하는
changeTodoStatusAPI 호출이 실패할 경우, UI에만 완료 처리된 상태로 남아있게 됩니다. 데이터 일관성을 위해onError시 이전 상태로 되돌리는 롤백 처리를 추가해 주세요. 😉🛠️ 롤백 처리를 포함한 수정 제안
updateTodo(todoId, (todo) => ({ ...todo, completed: true })); changeTodoStatus( { todoId, data: { isCompleted: true, date: dateKey } }, { onSuccess: () => { invalidateTodayView(); invalidateTodoDetail(todoId, dateKey); }, + onError: () => { + updateTodo(todoId, (todo) => ({ ...todo, completed: false })); + }, }, );🤖 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 `@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.ts around lines 120 - 130, In the todo completion flow around updateTodo and changeTodoStatus, preserve the todo’s previous state before the optimistic completed update, then add an onError handler to restore that state when the API call fails. Keep the existing onSuccess invalidation behavior unchanged.
🤖 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
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/today/_components/TodayTodoCard.tsx:
- Around line 85-99: Update TodayTodoCard’s handleCardKeyDown and card
interaction structure so the clickable area is a separate native button rather
than a container with role="button", keeping checkbox, playback, and toolbar
controls outside that button. Render the toolbar as non-interactive presentation
where appropriate, and ensure keyboard activation only occurs when e.target ===
e.currentTarget so Enter/Space from nested controls cannot trigger onCardClick.
- Around line 181-195: Update TodayTodoCardToolbar and its call site in
TodayTodoCard so all user-facing labels currently hardcoded in Korean—tagLabel,
detailHeading, and repeat option labels—are supplied through a locale-aware
props contract from the parent container. Keep _components/ locale-agnostic by
removing direct translation or locale handling there, and ensure each [locale]
renders the injected translations.
In `@apps/timo-web/schemas/auth/user-profile-schema.ts`:
- Around line 3-12: Strengthen userProfileSchema validation by requiring id to
be an integer with Zod’s integer constraint and validating email with Zod’s
email-format validator. Leave the remaining profile fields and their nullish
behavior unchanged.
In `@apps/timo-web/schemas/settings/terms-schema.ts`:
- Around line 13-14: Rename TermsType to TermsTypes and convert TermsDetail to
an interface in terms-schema.ts; update all related imports and parameter or
prop annotations in use-terms-query.ts and SettingsTermsContainer.tsx, including
SettingsTermsContainerProps, while keeping Props declarations as interfaces and
reserving type aliases for unions, tuples, and literals.
In `@apps/timo-web/schemas/timebox/timebox-schema.ts`:
- Line 30: Replace the inferred object type aliases with interface declarations:
update TimeBox in apps/timo-web/schemas/timebox/timebox-schema.ts at lines 30-30
and ActiveTimer in apps/timo-web/schemas/timer/timer-schema.ts at lines 18-18 to
extend their respective Zod inference types, preserving the existing
schema-derived shapes.
In `@apps/timo-web/schemas/todo/todo-schema.ts`:
- Around line 20-28: Move the existing dayOfWeekSchema declaration above
todoRepeatWeekdaySchema and reuse it for the repeat-weekday schema instead of
defining the identical weekday enum twice. Remove the later duplicate
dayOfWeekSchema declaration while preserving the current weekday values and
exported schema behavior.
---
Outside diff comments:
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.ts:
- Around line 120-130: In the todo completion flow around updateTodo and
changeTodoStatus, preserve the todo’s previous state before the optimistic
completed update, then add an onError handler to restore that state when the API
call fails. Keep the existing onSuccess invalidation behavior unchanged.
In `@apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts`:
- Around line 29-60: The duplicated create-submit hooks lack a shared,
consistent response-validation flow. In
apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts:29-60, update
useCreateTodoSubmit to accept queryKeysToInvalidate: QueryKey[] and invalidate
each supplied key after successful todoCreateResponseSchema validation; preserve
the existing error-toast behavior. In
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.ts:28-52,
remove the duplicate hook implementation and reuse the global
useCreateTodoSubmit, passing the Today screen’s required query keys.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: 1a23d551-18b0-471b-9eb4-339e7e8a03c1
📒 Files selected for processing (58)
.agents/skills/api/timo-api-integration/SKILL.mdapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_queries/use-home-view-query.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/todo-type.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_components/TodayTodoCard.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoCardContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_queries/use-today-query.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_types/today-type.tsapps/timo-web/app/[locale]/(main)/focus/_hooks/use-focus-session.tsapps/timo-web/app/[locale]/(main)/focus/_queries/use-focus-todo-query.tsapps/timo-web/app/[locale]/(main)/settings/_containers/terms/SettingsTermsContainer.tsxapps/timo-web/app/[locale]/(main)/settings/_containers/withdrawal/SettingsWithdrawalContainer.tsxapps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-profile.tsapps/timo-web/app/[locale]/(main)/settings/_queries/account/use-logout-mutation.tsapps/timo-web/app/[locale]/(main)/settings/_queries/withdrawal/use-withdraw-mutation.tsapps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsCalendarContainer.tsxapps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsContainer.tsxapps/timo-web/app/[locale]/(main)/statistics/_queries/use-statistics-query.tsapps/timo-web/app/[locale]/layout.tsxapps/timo-web/app/[locale]/policy/_containers/PolicyContainer.tsxapps/timo-web/app/[locale]/policy/page.tsxapps/timo-web/components/layout/sidebar/time/TimeboxPanel.tsxapps/timo-web/components/layout/sidebar/time/TimerPanel.tsxapps/timo-web/components/todo-modal/create/CreateTodoModalContent.tsxapps/timo-web/containers/todo-modal/create/CreateTodoModalContainer.tsxapps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsxapps/timo-web/hooks/timer/use-active-timer.tsapps/timo-web/hooks/timer/use-timer-actions.tsapps/timo-web/hooks/timer/use-timer-overtime.tsapps/timo-web/hooks/timer/use-timer-query-invalidation.tsapps/timo-web/hooks/todo-modal/common/use-tag-field.tsxapps/timo-web/hooks/todo-modal/create/use-create-todo-submit.tsapps/timo-web/hooks/todo-modal/create/use-icon-field.tsapps/timo-web/hooks/todo-modal/create/use-repeat-field.tsapps/timo-web/hooks/todo-modal/create/use-subtask-field.tsapps/timo-web/hooks/todo-modal/create/use-time-field.tsapps/timo-web/hooks/todo-modal/create/use-title-field.tsapps/timo-web/hooks/todo-modal/detail/use-detail-subtask-field.tsapps/timo-web/providers/locale/LanguageSyncProvider.tsxapps/timo-web/providers/overlay/OverlayProvider.tsxapps/timo-web/queries/auth/use-my-profile-query.tsapps/timo-web/queries/settings/use-terms-query.tsapps/timo-web/queries/tag/use-create-tag-mutation.tsapps/timo-web/queries/tag/use-delete-tag-mutation.tsapps/timo-web/queries/tag/use-tags-query.tsapps/timo-web/queries/time-box/use-time-boxes-query.tsapps/timo-web/schemas/auth/user-profile-schema.tsapps/timo-web/schemas/settings/terms-schema.tsapps/timo-web/schemas/tag/tag-schema.tsapps/timo-web/schemas/timebox/timebox-schema.tsapps/timo-web/schemas/timer/timer-schema.tsapps/timo-web/schemas/todo/todo-schema.tsdocs/conventions/naming.md
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts (1)
29-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
useCreateTodoSubmit훅의 로직 중복 및 검증 일관성 문제깔끔하게 생성 로직을 잘 작성해 주셨네요! ✨
살펴보니 두 파일에 동일한 역할을 수행하는 비즈니스 훅이 나뉘어 존재하고 있습니다. 특히 전역 훅에는 응답을 검증하는
safeParse로직이 있지만, 오늘(Today) 화면용 훅에는 해당 로직이 누락되어 있어 동작에 일관성이 부족한 상황입니다.
로직 파편화를 방지하고 유지보수성을 높이기 위해, 하나의 훅으로 깔끔하게 통합하고 외부에서 무효화(invalidate)할 쿼리 키를 주입받는 구조로 개선하는 것을 추천합니다. React 공식 문서 - Hook 추출하기
apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts#L29-L60: 메인 훅으로서 매개변수를 통해queryKeysToInvalidate를 주입받을 수 있도록 수정해 보세요.apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.ts#L28-L52: 해당 중복 훅을 제거하고, 위에서 수정된 전역 훅에 필요한 쿼리 키를 넘겨 재사용하도록 교체하세요.💡 리팩터링 아이디어 (참고용)
import type { QueryKey } from "`@tanstack/react-query`"; export const useCreateTodoSubmit = (queryKeysToInvalidate: QueryKey[]) => { // ... (동일한 초기화 및 빌드 로직) const handleSubmit = (data: CreateTodoRequest) => { createTodo( { data: buildCreateTodoRequestBody(data) }, { onSuccess: (response) => { const parsed = todoCreateResponseSchema.safeParse(response.data); if (!parsed.success) { setIsErrorToastOpen(true); return; } queryKeysToInvalidate.forEach((key) => queryClient.invalidateQueries({ queryKey: key }) ); }, onError: () => { setIsErrorToastOpen(true); }, } ); }; // ... };🤖 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 `@apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts` around lines 29 - 60, The duplicated create-submit hooks lack a shared, consistent response-validation flow. In apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts:29-60, update useCreateTodoSubmit to accept queryKeysToInvalidate: QueryKey[] and invalidate each supplied key after successful todoCreateResponseSchema validation; preserve the existing error-toast behavior. In apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.ts:28-52, remove the duplicate hook implementation and reuse the global useCreateTodoSubmit, passing the Today screen’s required query keys.apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.ts (1)
120-130: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win에러 발생 시 낙관적 업데이트를 롤백하는 로직이 누락되었습니다.
투두 완료 상태를 변경하는
changeTodoStatusAPI 호출이 실패할 경우, UI에만 완료 처리된 상태로 남아있게 됩니다. 데이터 일관성을 위해onError시 이전 상태로 되돌리는 롤백 처리를 추가해 주세요. 😉🛠️ 롤백 처리를 포함한 수정 제안
updateTodo(todoId, (todo) => ({ ...todo, completed: true })); changeTodoStatus( { todoId, data: { isCompleted: true, date: dateKey } }, { onSuccess: () => { invalidateTodayView(); invalidateTodoDetail(todoId, dateKey); }, + onError: () => { + updateTodo(todoId, (todo) => ({ ...todo, completed: false })); + }, }, );🤖 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 `@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.ts around lines 120 - 130, In the todo completion flow around updateTodo and changeTodoStatus, preserve the todo’s previous state before the optimistic completed update, then add an onError handler to restore that state when the API call fails. Keep the existing onSuccess invalidation behavior unchanged.
🤖 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
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/today/_components/TodayTodoCard.tsx:
- Around line 85-99: Update TodayTodoCard’s handleCardKeyDown and card
interaction structure so the clickable area is a separate native button rather
than a container with role="button", keeping checkbox, playback, and toolbar
controls outside that button. Render the toolbar as non-interactive presentation
where appropriate, and ensure keyboard activation only occurs when e.target ===
e.currentTarget so Enter/Space from nested controls cannot trigger onCardClick.
- Around line 181-195: Update TodayTodoCardToolbar and its call site in
TodayTodoCard so all user-facing labels currently hardcoded in Korean—tagLabel,
detailHeading, and repeat option labels—are supplied through a locale-aware
props contract from the parent container. Keep _components/ locale-agnostic by
removing direct translation or locale handling there, and ensure each [locale]
renders the injected translations.
In `@apps/timo-web/schemas/auth/user-profile-schema.ts`:
- Around line 3-12: Strengthen userProfileSchema validation by requiring id to
be an integer with Zod’s integer constraint and validating email with Zod’s
email-format validator. Leave the remaining profile fields and their nullish
behavior unchanged.
In `@apps/timo-web/schemas/settings/terms-schema.ts`:
- Around line 13-14: Rename TermsType to TermsTypes and convert TermsDetail to
an interface in terms-schema.ts; update all related imports and parameter or
prop annotations in use-terms-query.ts and SettingsTermsContainer.tsx, including
SettingsTermsContainerProps, while keeping Props declarations as interfaces and
reserving type aliases for unions, tuples, and literals.
In `@apps/timo-web/schemas/timebox/timebox-schema.ts`:
- Line 30: Replace the inferred object type aliases with interface declarations:
update TimeBox in apps/timo-web/schemas/timebox/timebox-schema.ts at lines 30-30
and ActiveTimer in apps/timo-web/schemas/timer/timer-schema.ts at lines 18-18 to
extend their respective Zod inference types, preserving the existing
schema-derived shapes.
In `@apps/timo-web/schemas/todo/todo-schema.ts`:
- Around line 20-28: Move the existing dayOfWeekSchema declaration above
todoRepeatWeekdaySchema and reuse it for the repeat-weekday schema instead of
defining the identical weekday enum twice. Remove the later duplicate
dayOfWeekSchema declaration while preserving the current weekday values and
exported schema behavior.
---
Outside diff comments:
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.ts:
- Around line 120-130: In the todo completion flow around updateTodo and
changeTodoStatus, preserve the todo’s previous state before the optimistic
completed update, then add an onError handler to restore that state when the API
call fails. Keep the existing onSuccess invalidation behavior unchanged.
In `@apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts`:
- Around line 29-60: The duplicated create-submit hooks lack a shared,
consistent response-validation flow. In
apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts:29-60, update
useCreateTodoSubmit to accept queryKeysToInvalidate: QueryKey[] and invalidate
each supplied key after successful todoCreateResponseSchema validation; preserve
the existing error-toast behavior. In
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.ts:28-52,
remove the duplicate hook implementation and reuse the global
useCreateTodoSubmit, passing the Today screen’s required query keys.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: 1a23d551-18b0-471b-9eb4-339e7e8a03c1
📒 Files selected for processing (58)
.agents/skills/api/timo-api-integration/SKILL.mdapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_queries/use-home-view-query.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/todo-type.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_components/TodayTodoCard.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoCardContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_queries/use-today-query.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_types/today-type.tsapps/timo-web/app/[locale]/(main)/focus/_hooks/use-focus-session.tsapps/timo-web/app/[locale]/(main)/focus/_queries/use-focus-todo-query.tsapps/timo-web/app/[locale]/(main)/settings/_containers/terms/SettingsTermsContainer.tsxapps/timo-web/app/[locale]/(main)/settings/_containers/withdrawal/SettingsWithdrawalContainer.tsxapps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-profile.tsapps/timo-web/app/[locale]/(main)/settings/_queries/account/use-logout-mutation.tsapps/timo-web/app/[locale]/(main)/settings/_queries/withdrawal/use-withdraw-mutation.tsapps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsCalendarContainer.tsxapps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsContainer.tsxapps/timo-web/app/[locale]/(main)/statistics/_queries/use-statistics-query.tsapps/timo-web/app/[locale]/layout.tsxapps/timo-web/app/[locale]/policy/_containers/PolicyContainer.tsxapps/timo-web/app/[locale]/policy/page.tsxapps/timo-web/components/layout/sidebar/time/TimeboxPanel.tsxapps/timo-web/components/layout/sidebar/time/TimerPanel.tsxapps/timo-web/components/todo-modal/create/CreateTodoModalContent.tsxapps/timo-web/containers/todo-modal/create/CreateTodoModalContainer.tsxapps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsxapps/timo-web/hooks/timer/use-active-timer.tsapps/timo-web/hooks/timer/use-timer-actions.tsapps/timo-web/hooks/timer/use-timer-overtime.tsapps/timo-web/hooks/timer/use-timer-query-invalidation.tsapps/timo-web/hooks/todo-modal/common/use-tag-field.tsxapps/timo-web/hooks/todo-modal/create/use-create-todo-submit.tsapps/timo-web/hooks/todo-modal/create/use-icon-field.tsapps/timo-web/hooks/todo-modal/create/use-repeat-field.tsapps/timo-web/hooks/todo-modal/create/use-subtask-field.tsapps/timo-web/hooks/todo-modal/create/use-time-field.tsapps/timo-web/hooks/todo-modal/create/use-title-field.tsapps/timo-web/hooks/todo-modal/detail/use-detail-subtask-field.tsapps/timo-web/providers/locale/LanguageSyncProvider.tsxapps/timo-web/providers/overlay/OverlayProvider.tsxapps/timo-web/queries/auth/use-my-profile-query.tsapps/timo-web/queries/settings/use-terms-query.tsapps/timo-web/queries/tag/use-create-tag-mutation.tsapps/timo-web/queries/tag/use-delete-tag-mutation.tsapps/timo-web/queries/tag/use-tags-query.tsapps/timo-web/queries/time-box/use-time-boxes-query.tsapps/timo-web/schemas/auth/user-profile-schema.tsapps/timo-web/schemas/settings/terms-schema.tsapps/timo-web/schemas/tag/tag-schema.tsapps/timo-web/schemas/timebox/timebox-schema.tsapps/timo-web/schemas/timer/timer-schema.tsapps/timo-web/schemas/todo/todo-schema.tsdocs/conventions/naming.md
🛑 Comments failed to post (6)
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_components/TodayTodoCard.tsx (2)
85-99: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
카드 전체를
button으로 모델링하지 말고 내부 컨트롤과 분리해 주세요.
role="button"내부에 체크박스·재생 버튼·툴바 컨트롤이 중첩되어 접근성 트리가 불안정합니다. 특히pointer-events-none은 키보드 포커스를 막지 않으므로, 툴바에서 Enter/Space를 누르면 이벤트가 Line 85의 핸들러로 전파되어 카드 클릭까지 실행됩니다.카드의 클릭 영역을 별도 네이티브 버튼으로 분리하고, 툴바는 비대화형 표시 컴포넌트로 렌더링하세요. 임시 방어로는
e.target === e.currentTarget일 때만 카드 키보드 동작을 실행해야 합니다.참고: MDN ARIA button role, MDN pointer-events
Also applies to: 108-157, 172-198
🤖 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 `@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/today/_components/TodayTodoCard.tsx around lines 85 - 99, Update TodayTodoCard’s handleCardKeyDown and card interaction structure so the clickable area is a separate native button rather than a container with role="button", keeping checkbox, playback, and toolbar controls outside that button. Render the toolbar as non-interactive presentation where appropriate, and ensure keyboard activation only occurs when e.target === e.currentTarget so Enter/Space from nested controls cannot trigger onCardClick.
181-195: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
로케일별 문구를 props로 전달해 주세요.
태그,상세 설정, 반복 옵션 등의 한국어 문자열이 고정되어 다른[locale]에서도 한국어로 노출됩니다. 번역된 라벨을 컨테이너에서 주입하도록TodayTodoCardToolbar계약에 추가해 주세요.참고: Next.js Internationalization
As per path instructions, "
_components/: props만 받는 순수 UI" 규칙에 따라 로케일 처리는 상위 계층에 두어야 합니다.🤖 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 `@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/today/_components/TodayTodoCard.tsx around lines 181 - 195, Update TodayTodoCardToolbar and its call site in TodayTodoCard so all user-facing labels currently hardcoded in Korean—tagLabel, detailHeading, and repeat option labels—are supplied through a locale-aware props contract from the parent container. Keep _components/ locale-agnostic by removing direct translation or locale handling there, and ensure each [locale] renders the injected translations.Source: Path instructions
apps/timo-web/schemas/auth/user-profile-schema.ts (1)
3-12: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
스키마 검증 강도를 높여보는 것은 어떨까요?
Zod의 향상된 기능을 활용하여
id와 이메일 필드를 더 안전하게 정의할 수 있습니다.id에는.int()를 추가하여 소수점이 포함되지 않은 정수만 허용하도록 하고, 이메일 필드에는 이메일 형식을 엄격하게 검증하도록 수정하는 것을 제안합니다. 이렇게 하면 데이터 무결성을 높이고 예기치 않은 데이터 오류를 사전에 방지할 수 있습니다.💡 향상된 스키마 제안
export const userProfileSchema = z.object({ - id: z.number(), + id: z.number().int(), name: z.string(), - email: z.string(), + email: z.string().email(), profileImageUrl: z.string().nullish(), language: z.string(), zoneId: z.string(), calendarConnected: z.boolean(), - calendarEmail: z.string().nullish(), + calendarEmail: z.string().email().nullish(), });📝 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.export const userProfileSchema = z.object({ id: z.number().int(), name: z.string(), email: z.string().email(), profileImageUrl: z.string().nullish(), language: z.string(), zoneId: z.string(), calendarConnected: z.boolean(), calendarEmail: z.string().email().nullish(), });🤖 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 `@apps/timo-web/schemas/auth/user-profile-schema.ts` around lines 3 - 12, Strengthen userProfileSchema validation by requiring id to be an integer with Zod’s integer constraint and validating email with Zod’s email-format validator. Leave the remaining profile fields and their nullish behavior unchanged.apps/timo-web/schemas/settings/terms-schema.ts (1)
13-14: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
타입 네이밍 가이드라인 준수를 위한 일괄 수정 제안
타입 안전성 가이드라인에 따라 객체 타입은
interface로 선언하고,typealias에는Types접미사를 사용해야 합니다. 이에 맞춰 타입 선언과 관련된 참조를 모두 업데이트해 주세요. 구조화된 네이밍은 유지보수에 큰 도움이 됩니다! 😊
apps/timo-web/schemas/settings/terms-schema.ts#L13-L14:TermsDetail을interface로 선언하고,TermsType을TermsTypes로 수정합니다.apps/timo-web/queries/settings/use-terms-query.ts#L10-L20: import 구문과 매개변수 타입을TermsTypes로 변경합니다.apps/timo-web/app/[locale]/(main)/settings/_containers/terms/SettingsTermsContainer.tsx#L5-L18: import 구문을TermsTypes로 변경하고, 연관된SettingsTermsContainerProps의 타입(11번 줄)도 함께 업데이트해야 합니다.As per path instructions:
Props 타입은 interface로 선언,type alias는 유니언·튜플·리터럴에만 사용, 접미사 Types💡 Proposed fixes for the schema file
-export type TermsType = z.infer<typeof termsTypeSchema>; -export type TermsDetail = z.infer<typeof termsDetailSchema>; +export type TermsTypes = z.infer<typeof termsTypeSchema>; + +export interface TermsDetail extends z.infer<typeof termsDetailSchema> {}📍 Affects 3 files
apps/timo-web/schemas/settings/terms-schema.ts#L13-L14(this comment)apps/timo-web/queries/settings/use-terms-query.ts#L10-L20apps/timo-web/app/[locale]/(main)/settings/_containers/terms/SettingsTermsContainer.tsx#L5-L18🤖 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 `@apps/timo-web/schemas/settings/terms-schema.ts` around lines 13 - 14, Rename TermsType to TermsTypes and convert TermsDetail to an interface in terms-schema.ts; update all related imports and parameter or prop annotations in use-terms-query.ts and SettingsTermsContainer.tsx, including SettingsTermsContainerProps, while keeping Props declarations as interfaces and reserving type aliases for unions, tuples, and literals.Source: Path instructions
apps/timo-web/schemas/timebox/timebox-schema.ts (1)
30-30: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
객체 타입 선언 시
interface를 사용해 주세요.경로 규칙(Path Instructions)에 따르면
type별칭은 유니언·튜플·리터럴에만 사용해야 하며, 일반 객체 타입은interface를 사용해야 합니다. Zod 객체 스키마의 추론 타입에도interface확장을 사용하여 코드베이스의 일관성을 높여주세요! 🚀
apps/timo-web/schemas/timebox/timebox-schema.ts#L30-L30:export interface TimeBox extends z.infer<typeof timeBoxSchema> {}로 변경하세요.apps/timo-web/schemas/timer/timer-schema.ts#L18-L18:export interface ActiveTimer extends z.infer<typeof activeTimerSchema> {}로 변경하세요.📍 Affects 2 files
apps/timo-web/schemas/timebox/timebox-schema.ts#L30-L30(this comment)apps/timo-web/schemas/timer/timer-schema.ts#L18-L18🤖 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 `@apps/timo-web/schemas/timebox/timebox-schema.ts` at line 30, Replace the inferred object type aliases with interface declarations: update TimeBox in apps/timo-web/schemas/timebox/timebox-schema.ts at lines 30-30 and ActiveTimer in apps/timo-web/schemas/timer/timer-schema.ts at lines 18-18 to extend their respective Zod inference types, preserving the existing schema-derived shapes.Source: Path instructions
apps/timo-web/schemas/todo/todo-schema.ts (1)
20-28: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
dayOfWeekSchema재사용을 통한 중복 제거훌륭하게 스키마를 구성해 주셨네요! 👏
하나 제안을 드리자면, 현재
todoRepeatWeekdaySchema와 74번째 라인의dayOfWeekSchema가 완전히 동일한 요일 리스트를 가지고 있습니다. Zod의 중복 선언을 줄이기 위해dayOfWeekSchema를 위로 올려서 선언하고, 이를 재사용하는 건 어떨까요?
Zod 공식 문서에서도 DRY 원칙을 권장하고 있습니다. 유지보수하기 한결 편해질 거예요!💡 개선 제안
-export const todoRepeatWeekdaySchema = z.enum([ +export const dayOfWeekSchema = z.enum([ "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN", ]); + +export const todoRepeatWeekdaySchema = dayOfWeekSchema;(수정 후, 기존 74~82 라인에 있던
dayOfWeekSchema선언은 삭제해 주시면 완벽합니다!)🤖 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 `@apps/timo-web/schemas/todo/todo-schema.ts` around lines 20 - 28, Move the existing dayOfWeekSchema declaration above todoRepeatWeekdaySchema and reuse it for the repeat-weekday schema instead of defining the identical weekday enum twice. Remove the later duplicate dayOfWeekSchema declaration while preserving the current weekday values and exported schema behavior.
yumin-kim2
left a comment
There was a problem hiding this comment.
굿굿입니다 파일이 점점 많아질수록 역할이 헷갈릴 수 있는데, 이렇게 역할별로 분리해두니 관리하기 훨씬 편할 것 같네요 짱짱맨
ISSUE 🔗
close #217
What is this PR? 🔍
api/common/,types/,hooks/루트에 흩어져 있던 스키마·타입·훅 파일을 도메인별 폴더로 재정리하고, 그 과정에서 깨진 import 경로를 전부 수정했습니다. 동시에 TanStack Query 훅의 파일명·함수명을-query/-mutation,~Query/~Mutation컨벤션으로 통일하고, 이 컨벤션을 문서에 명문화했습니다.배경
api/common/)·타입(types/)·타이머 훅(hooks/)·오버레이 프로바이더가 도메인 구분 없이 루트에 흩어져 있었고, 쿼리/뮤테이션 훅은 파일명·함수명 규칙이 통일되어 있지 않았습니다 (useTerms,useWithdrawAction,useLogoutAction등 제각각).~Query/-query.ts, 뮤테이션 훅은~Mutation/-mutation.ts로 통일하고, 이 규칙을docs/conventions/naming.md와timo-api-integration스킬에 반영해 앞으로도 동일하게 적용되도록 했습니다.폴더 구조 재정리
api/common/의 zod 스키마,types/의 도메인 타입,hooks/의 타이머 훅,providers/의OverlayProvider를 각각schemas/{domain}/,hooks/timer/,providers/overlay/로 이동했습니다.tsc --noEmit으로 전수 검증하며 하나씩 수정했습니다 —TimeboxPanel.tsx의@/queries/use-time-boxes,TodayTodoCardContainer.tsx의today/_components/TodayTodoCard등 도메인 라우트 그룹((with-time-sidebar)) 이동 과정에서 누락된 경로도 함께 잡았습니다.쿼리/뮤테이션 훅 네이밍
useMyProfile,useTerms,useTags,useTimeBoxes,useCreateTag,useDeleteTag,useToday,useFocusTodo,useHomeView,useWithdrawAction,useLogoutAction11개 훅의 파일명·함수명을~Query/~Mutation접미사로 통일했습니다 (예:useWithdrawAction→useWithdrawMutation,use-terms.ts→use-terms-query.ts).useSuspenseQuery/useQuery를 감싸는 훅은~Query,useMutation을 감싸는 훅은~Mutation으로 이름을 바꾸고 파일명도 동일한 접미사(-query.ts/-mutation.ts)로 맞췄습니다. 이 훅들을 사용하는 10개 소비 파일의 import 경로와 호출부도 함께 갱신했습니다.hooks/timer/use-active-timer.ts처럼 react-query 조회 결과에 타이머 tick 같은 추가 상태·로직을 합성한 훅은 순수 조회/변경 래퍼가 아니므로 이번 컨벤션 대상에서 제외했습니다.statistics/_queries/statistics-queries.ts는 파일 분리 대신 함수명이 이미~Query로 끝나는 점을 살려 파일명만use-statistics-query.ts로 맞추고 훅 3개는 한 파일에 유지했습니다 — 도메인당 조회 훅이 늘어날 때마다 파일을 잘게 쪼개는 대신, 이미 응집도 높게 묶여 있던 단위는 그대로 두는 쪽을 선택했습니다.컨벤션 문서화
docs/conventions/naming.md에 TanStack Query 훅의 파일명·함수명 규칙 섹션을 추가하고,timo-api-integration스킬의_queries/훅 작성 가이드 예시 코드와 자가 검토 체크리스트를 새 컨벤션에 맞게 갱신했습니다.timo-api-integration스킬에는 조회 훅(useHomeViewQuery)과 변경 훅(useWithdrawMutation) 예시 코드를 각각 추가했습니다.To Reviewers
폴더 이동은 대부분
git mv기반이라 파일 내용 diff는 거의 없고, import 경로 갱신이 diff의 대부분을 차지합니다.git log상 리네임으로 잡힌 파일들은 내용을 다시 볼 필요 없이 새 경로만 확인해 주시면 됩니다.hooks/timer/use-active-timer.ts등 합성 훅을 이번 네이밍 컨벤션 대상에서 제외한 판단이 맞는지 한번 봐주세요 — react-query 결과에 로컬 상태(타이머 tick)를 얹은 훅이라~Query접미사를 붙이면 오히려 오해의 소지가 있다고 판단했습니다.statistics/_queries/use-statistics-query.ts는 조회 훅 3개를 한 파일에 유지했습니다. 파일당 훅 1개 원칙과는 다르지만, 이미 응집도 높게 묶여 있던 단위라 분리보다 유지가 낫다고 판단했습니다 — 이견 있으시면 알려주세요.Screenshot 📷
Test Checklist ✔
pnpm check-types통과pnpm lint(--max-warnings 0) 통과pnpm build프로덕션 빌드 성공 (22개 라우트 정상 생성)