Skip to content

[FEAT] 태그 API 연동 및 설정 확인 모달·폴더 구조 개선 - #178

Merged
kimminna merged 18 commits into
developfrom
feat/web/177-tag-api-integration
Jul 14, 2026
Merged

[FEAT] 태그 API 연동 및 설정 확인 모달·폴더 구조 개선#178
kimminna merged 18 commits into
developfrom
feat/web/177-tag-api-integration

Conversation

@kimminna

@kimminna kimminna commented Jul 13, 2026

Copy link
Copy Markdown
Member

ISSUE 🔗

close #177



What is this PR? 🔍

홈 모달과 설정 페이지에서 태그 관련 mock 데이터를 실제 태그 API(목록 조회·생성·삭제)로 교체하고, 설정 페이지에 확인 모달을 추가하면서 탭 단위로 폴더 구조를 재정리했습니다.

배경

  • 기존 구조: 홈 모달은 고정 프리셋 5종 + 로컬 state로 태그를 흉내냈고, 설정 페이지는 mock 배열을 react-hook-form에 담아 "저장하기"를 눌러야 반영되는 구조였습니다.
  • 발생 문제: 두 화면 모두 실제 서버 태그와 무관하게 동작해 새로고침하면 사라지고, 두 화면끼리 데이터가 공유되지 않았습니다. 또한 설정 페이지에서 언어 변경에만 확인 모달이 있고 태그 삭제·로그아웃은 클릭 즉시 실행돼 실수로 되돌릴 수 없는 액션이 아무 확인 없이 발생할 수 있었습니다.
  • 해결 방향: getTags/createTag/deleteTag API를 실제로 연동하고, 두 도메인이 공유해야 하는 스키마·쿼리 훅·생성 모달을 앱 공유 위치(api/tag, queries/tag, components/tag)로 추출했습니다. 이어서 태그 삭제·로그아웃에도 언어 변경과 동일한 패턴의 확인 모달을 추가하고, 탭(계정/약관/탈퇴)이 늘어나며 평평하게 섞여 있던 설정 폴더를 탭 단위로 재구조화했습니다.

공유 인프라 (api/tag, queries/tag, components/tag)

  • 변경 요약: 태그 응답 zod 스키마, getTags/createTag/deleteTag를 감싸는 React Query 훅, 태그 생성 모달을 앱 공유 위치에 추가했습니다.
  • 이유: 홈 모달과 설정 페이지가 동일한 태그 CRUD 로직을 필요로 하는데, 기존 CreateTagModalContainer와 관련 스키마는 홈 도메인 폴더(home/_containers, home/_types) 안에 있어 설정 페이지에서 그대로 import할 수 없었습니다.
  • 구현 방식: useCreateTag/useDeleteTag는 각각 useMutation 내부에서 성공 시 getGetTagsQueryKey()로 캐시를 무효화하도록 했습니다. 소비하는 쪽(홈/설정)은 mutate(variables, { onSuccess, onError })로 각자 필요한 UI 반응(토스트, 모달 닫기, 필드 선택)만 처리합니다. useTags는 생성된 useGetTags를 그대로 감싸고 select에서 로컬 zod 스키마로 .parse()해 백엔드 계약 변경을 조기에 감지하도록 했습니다.
  • 경계 · 제약: 홈 도메인 전용이던 CreateTagModalContainer는 삭제하고 components/tag/로 이동했습니다(내용 변경 없음).

홈 모달 태그 필드

  • 변경 요약: use-tag-field.tsx의 고정 프리셋(TAG_NAMES/TAG_ID_BY_NAME)과 로컬 customTags state를 제거하고 실제 useTags()/useCreateTag()로 교체했습니다.
  • 이유: 프리셋 mock은 서버의 실제 태그 목록·ID와 무관해 새로고침 시 커스텀 태그가 사라지고, 다른 화면과 태그 목록이 어긋났습니다.
  • 구현 방식: useTags() 결과를 { id: tagId, label: name }으로 매핑해 드롭다운을 채웁니다. 태그 생성 시 createTag({ name: label })을 호출하고, 성공하면 응답을 tagCreateDataSchema.safeParse로 검증한 뒤 반환된 tagId를 바로 폼 필드에 선택 상태로 반영하고 모달을 닫습니다. 실패하면 토스트(Toast.tagCreateFailed)를 띄웁니다.
  • 경계 · 제약: 태그 드롭다운에 삭제(x) 인터랙션이 없어 deleteTag 연동은 이번 PR 범위에서 제외했습니다.

설정 페이지 태그 관리

  • 변경 요약: useSettingsProfile의 태그 mock 배열·react-hook-form 스테이징 로직을 제거하고, 실제 목록 조회·생성·삭제 API로 교체했습니다.
  • 이유: 실제 삭제 API에는 "저장 시 일괄 반영" 개념이 없어, 기존처럼 폼에 스테이징했다가 "변경사항 저장" 버튼을 눌러야 반영되는 구조를 유지할 수 없었습니다. "태그 추가" 버튼도 window.prompt 임시 구현이었습니다.
  • 구현 방식: 태그 add/remove는 이제 즉시 서버에 반영됩니다. getTags 응답에는 isDefault 필드가 없어(/v3/api-docs 실제 확인) 기본 태그 5종(Common.tag.*)의 번역된 이름과 매칭해 삭제 가능 여부를 판별합니다 — 백엔드가 기본 태그와 같은 이름의 태그 생성을 막아주므로 이름 매칭으로도 안전합니다. "태그 추가"는 홈 모달과 동일한 CreateTagModalContainer를 재사용합니다.
  • 경계 · 제약: 이름/이메일/구글 캘린더 연동 등 이번 요청과 무관한 나머지 mock은 그대로 두었습니다.

설정 확인 모달 (언어 변경 · 태그 삭제 · 로그아웃)

  • 변경 요약: 언어 변경, 태그 삭제, 로그아웃 세 액션 모두 즉시 실행되지 않고 동일한 패턴의 확인 모달을 거치도록 통일했습니다.
  • 이유: 언어 변경에만 확인 모달이 있었고, 태그 삭제·로그아웃은 클릭 즉시 실행돼 되돌릴 수 없는 액션이 확인 없이 발생할 수 있었습니다.
  • 구현 방식: 각 액션의 컨테이너(SettingsLanguageSectionContainer, SettingsTagsSectionContainer, SettingsLogoutModalContainer)가 숨김 처리된 Modal.Trigger 버튼의 ref를 코드에서 직접 클릭해 모달을 열고, 모달의 확인 버튼에서만 실제 액션을 실행합니다. 모달 UI는 기존 타이머 종료/중단 모달과 동일하게 Modal.Icon(타이모 로고) + Title + Description + Footer 조합을 그대로 재사용합니다.
  • 경계 · 제약: 로그아웃은 별도 View 파일 없이 ref·상태·모달 JSX를 컨테이너 하나로 캡슐화했습니다(섹션 콘텐츠 없이 모달만 있는 케이스라 View 분리 실익이 없었습니다).

설정 페이지 폴더 구조 (탭 단위)

  • 변경 요약: SettingsProfileFormSettingsProfileView로 이름을 바꾸고(폼 제출 로직이 없어 Form이라는 이름이 더 이상 맞지 않았습니다), 계정/약관/탈퇴 각 탭의 컴포넌트·컨테이너·훅·타입을 account/, terms/, withdrawal/ 하위 폴더로 재구조화했습니다.
  • 이유: 탭이 늘어나면서 _components/_containers/_hooks/_types 안에 서로 다른 탭의 파일이 평평하게 섞여 있어 어디에 무엇이 속하는지 파악하기 어려웠습니다.
  • 구현 방식: 기존 home/today 폴더에서 쓰이던 "타입 폴더(_components/_containers/_hooks) 안에 기능별 하위 폴더를 두는" 컨벤션을 그대로 따랐습니다(예: _containers/account/, _containers/withdrawal/). 여러 탭이 공유하는 useClearSession(로그아웃·탈퇴 두 곳에서만 사용)은 전역 hooks/가 아닌 settings/_hooks/로 옮겨 탭 공용 위치에 두었습니다.
  • 경계 · 제약: develop에는 이미 settings/account/, settings/withdrawal/를 실제 라우트 폴더로 스캐폴딩(page.tsx + 빈 _components/_containers)해 두는 다른 방향의 구조가 있었습니다. 이 브랜치는 이미 그 스캐폴딩을 걷어내고 쿼리 파라미터 탭 방식으로 되돌린 상태였고, 이번 PR도 그 기존 방향(타입 폴더 우선 + 쿼리 파라미터 탭)을 유지하는 쪽을 택했습니다. develop을 머지하며 들어온 실제 로그아웃/탈퇴 API(useLogoutAction, useWithdrawAction)는 이 구조에 맞게 재배치해 통합했습니다.

언어 변경 안정성 개선

  • 변경 요약: 언어 변경 성공 시 setQueryData로 프로필 캐시를 직접 병합하던 로직을 invalidateQueries로 교체하고, 실패 시 window.alert 대신 토스트를 띄우도록 했습니다.
  • 이유: 업데이트 응답의 language 필드를 그대로 캐시에 병합하는 방식은 응답 형태가 프로필 조회 응답과 다르면 캐시가 실제 서버 상태와 어긋날 위험이 있었고, window.alert는 다른 실패 케이스들과 달리 앱의 토스트 UI 컨벤션을 따르지 않고 있었습니다.
  • 구현 방식: updateLanguage 성공 후 getGetMyProfileQueryKey()invalidateQueries를 호출해 프로필을 서버에서 다시 받아오도록 했습니다. 실패 시에는 다른 액션들과 동일하게 isLanguageErrorToastOpen 상태 + AnimatedToast(Toast.languageChangeFailed)로 처리합니다.



To Reviewers

isDefault 판별을 이름 매칭으로 처리한 부분(DEFAULT_TAG_NAME_KEYS)이 다소 우회적인 방식이라 한번 봐주세요 — 백엔드 TagResponseisDefault 필드가 없어서 나온 임시방편이며, 추후 백엔드 스펙에 필드가 추가되면 정리가 필요합니다.
설정 폴더를 develop의 라우트 우선 스캐폴딩과 다른 방향(타입 폴더 우선)으로 유지하기로 한 판단이 맞는지 확인 부탁드립니다 — 두 구조가 계속 공존하면 이후 병합 때마다 이번처럼 충돌이 반복될 수 있어서, 팀 차원의 방향 정리가 필요해 보입니다.
홈 모달의 태그 삭제는 UI가 없어 이번 범위에서 의도적으로 제외했습니다.



Screenshot 📷

실제 화면(설정 페이지 태그 추가 모달, 확인 모달, 삭제 버튼 동작)은 이번 세션에서 브라우저로 캡처하지 않아 스크린샷은 첨부하지 못했습니다.



Test Checklist ✔

  • pnpm check-types 통과
  • pnpm lint 통과
  • pnpm build:web 통과 (번들 크기 경고 없음)
  • 브라우저에서 홈 모달 태그 생성/선택 동작 확인 — 미실행
  • 브라우저에서 설정 페이지 태그 추가/삭제/로그아웃 확인 모달 동작 확인 — 미실행

kimminna added 3 commits July 13, 2026 22:02
- 태그 목록/생성 응답 zod 스키마를 api/tag/tag-schema.ts에 추가했습니다
- getTags/createTag/deleteTag를 감싸는 공유 React Query 훅을 queries/tag/에 추가했습니다
- 홈 도메인에만 있던 태그 생성 모달을 components/tag/로 이동해 설정 페이지와 공유하도록 했습니다
- 홈 모달의 태그 선택 필드에서 고정 프리셋 mock 대신 실제 태그 목록 조회 API를 사용하도록 했습니다
- 태그 생성 시 실제 생성 API를 호출하고 응답으로 받은 tagId를 바로 선택하도록 했습니다
- 태그 생성 실패 시 안내할 토스트 메시지를 ko/en에 추가했습니다
- 설정 페이지의 태그 관리 목록을 mock 배열 대신 실제 태그 목록 조회 API로 교체했습니다
- 태그 이름은 응답에 isDefault가 없어 기본 태그 5종 이름과 매칭해 삭제 가능 여부를 판단하도록 했습니다
- "태그 추가" 버튼을 임시 window.prompt에서 실제 생성 모달로 교체했습니다
- TagChip의 삭제 버튼에 실제 태그 삭제 API를 연동했습니다
- 태그 add/remove가 즉시 반영되도록 해 저장 버튼은 언어 변경에만 적용되도록 했습니다
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
timo Ready Ready Preview, Comment Jul 14, 2026 6:59am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 32 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: ASSERTIVE

Plan: Pro Plus

Run ID: adef44d8-990d-4f16-8cc4-1d69e2196084

📥 Commits

Reviewing files that changed from the base of the PR and between 883df20 and 41f9598.

📒 Files selected for processing (16)
  • apps/timo-web/api/common/tag-schema.ts
  • apps/timo-web/api/common/todo-schema.ts
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/todo-modal/use-create-todo-submit.ts
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-profile.ts
  • apps/timo-web/components/todo-modal/create/CreateTodoModalContainer.tsx
  • apps/timo-web/components/todo-modal/create/CreateTodoModalContent.tsx
  • apps/timo-web/hooks/todo-modal/use-create-todo-submit.ts
  • apps/timo-web/hooks/todo-modal/use-icon-field.ts
  • apps/timo-web/hooks/todo-modal/use-repeat-field.ts
  • apps/timo-web/hooks/todo-modal/use-subtask-field.ts
  • apps/timo-web/hooks/todo-modal/use-tag-field.tsx
  • apps/timo-web/hooks/todo-modal/use-time-field.ts
  • apps/timo-web/hooks/todo-modal/use-title-field.ts
  • apps/timo-web/messages/en.json
  • apps/timo-web/messages/ko.json
  • apps/timo-web/queries/tag/use-tags.ts

Walkthrough

태그 API 스키마와 React Query 훅을 추가하고 홈 모달과 설정 화면에서 태그 생성·삭제를 서버 API로 처리하도록 변경했다. 설정 화면에는 언어·태그·로그아웃 확인 모달, 약관 컨테이너, 세션 정리 및 관련 라우팅 구조가 추가됐다.

Changes

태그 API 및 홈 모달

Layer / File(s) Summary
태그 계약과 쿼리 훅
apps/timo-web/api/tag/tag-schema.ts, apps/timo-web/queries/tag/*
태그 응답·생성 스키마와 추론 타입을 추가하고 태그 조회·생성·삭제 훅을 구현했다. 성공 시 태그 목록 캐시를 무효화한다.
공유 태그 생성 모달
apps/timo-web/components/tag/CreateTagModalContainer.tsx
태그 이름의 trim, 중복, 공백, 길이를 검증하고 유효한 라벨을 생성 콜백에 전달한다.
홈 모달 태그 생성
apps/timo-web/hooks/todo-modal/use-tag-field.tsx, apps/timo-web/components/todo-modal/CreateTodoModalContent.tsx
로컬 태그 생성 로직을 API 호출로 교체하고 생성 응답을 검증하며 실패 토스트를 표시한다.

설정 화면 연동

Layer / File(s) Summary
설정 상호작용 컨테이너
apps/timo-web/app/[locale]/(main)/settings/_containers/account/*, apps/timo-web/app/[locale]/(main)/settings/_types/account/profile-type.ts, apps/timo-web/messages/*.json
언어 변경, 태그 삭제, 로그아웃 확인 모달과 관련 타입·영어/한국어 문구를 추가했다.
설정 프로필 오케스트레이션
apps/timo-web/app/[locale]/(main)/settings/_hooks/account/*, apps/timo-web/app/[locale]/(main)/settings/_containers/account/SettingsProfileContainer.tsx, apps/timo-web/app/[locale]/(main)/settings/_components/account/SettingsProfileView.tsx
프로필 훅이 태그 API, 언어 변경, 로그아웃, 캘린더 액션과 오류 토스트를 연결하고 뷰가 세부 컨테이너를 렌더링하도록 변경했다.
설정 탐색과 지원 흐름
apps/timo-web/app/[locale]/(main)/settings/_containers/*, apps/timo-web/app/[locale]/(main)/settings/_hooks/*, apps/timo-web/app/[locale]/(main)/settings/_queries/*
설정 탭·약관·인출 import 경로를 재구성하고 언어 탭, 세션 정리 훅 및 관련 로그아웃·인출 연결을 추가했다.

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

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SettingsProfileContainer
  participant useSettingsProfile
  participant useCreateTag
  participant useDeleteTag
  participant TagAPI
  User->>SettingsProfileContainer: 태그 추가 또는 삭제 선택
  SettingsProfileContainer->>useSettingsProfile: 생성·삭제 액션 전달
  useSettingsProfile->>useCreateTag: 태그 생성 요청
  useSettingsProfile->>useDeleteTag: tagId 삭제 요청
  useCreateTag->>TagAPI: 생성 API 호출
  useDeleteTag->>TagAPI: 삭제 API 호출
  TagAPI-->>useSettingsProfile: 작업 결과 반환
  useSettingsProfile-->>SettingsProfileContainer: 성공 또는 오류 콜백
Loading

Possibly related PRs

  • Team-Timo/Timo-client#127: 설정 화면 구조와 라우팅, 언어 선택 관련 코드 경로가 연결되어 있다.
  • Team-Timo/Timo-client#164: 태그 라벨 타입가드 유틸리티를 통해 태그 라벨 처리 흐름이 연결되어 있다.
  • Team-Timo/Timo-client#173: 프로필 조회와 언어 변경 API 연동을 포함해 동일한 설정 프로필 코드 경로를 다룬다.

Suggested labels: ♠️ 정민

Suggested reviewers: yumin-kim2, jjangminii

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed 태그 API 연동과 설정 확인 모달·구조 재정리를 함께 담아 변경의 핵심을 잘 요약했습니다.
Description check ✅ Passed 설명이 태그 API 교체, 공유 훅/컴포넌트 추출, 설정 모달 추가를 정확히 반영합니다.
Linked Issues check ✅ Passed 이슈 #177의 태그 mock 교체, 공유 추출, 생성·삭제 토스트와 모달 교체 요구를 충족합니다.
Out of Scope Changes check ✅ Passed 폴더 재구성과 언어·로그아웃·탈퇴 관련 정리는 PR 목적의 설정 화면 개선 범위 안에 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/web/177-tag-api-integration

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

🤖 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)/home/_hooks/todo-modal/use-tag-field.tsx:
- Around line 58-76: Use the useCreateTag mutation’s isPending state in
CreateTagModalContainer and pass it to CreateButton so submission is disabled
while tag creation is in progress, preventing duplicate requests. Keep the
existing onSuccess and onError handling unchanged.

In `@apps/timo-web/app/`[locale]/(main)/settings/_hooks/useSettingsProfile.tsx:
- Around line 65-96: Update handleAddTag to guard before opening
CreateTagModalContainer: when tagItems.length is at least 8, show the existing
tagLimit toast/message and return immediately. Reuse the established translation
or toast mechanism from useTagField, while preserving the current modal and
creation flow below the guard for fewer than 8 tags.
- Around line 17-46: Update useSettingsProfile so default-tag detection compares
each tag’s stable name key (or the API’s stable isDefault field) instead of
translated values from tCommon. Reuse the same key-based criterion as
HomeTodoContainer, and keep translation limited to rendering labels so locale
changes never make default tags appear deletable.

In `@apps/timo-web/components/tag/CreateTagModalContainer.tsx`:
- Around line 38-43: Update handleCreate and the onCreate contract so creation
returns a Promise indicating success; await that result and call setName("")
only after a successful API response. Preserve the trimmed input when creation
fails, including the existing validation behavior.
- Around line 27-28: Update CreateTagModalContainer’s translation usage to
depend on a shared Tag namespace instead of Home, including changing the
relevant key references from Home.createTagModal.* to Tag.createTagModal.*. Move
the corresponding createTagModal entries from the Home namespace to the Tag
namespace in both en.json and ko.json, while preserving the existing Common
translations.
🪄 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: 5d75d67f-3c9a-4783-bcbe-96f8d0bb4182

📥 Commits

Reviewing files that changed from the base of the PR and between 317052f and c0c4d00.

📒 Files selected for processing (14)
  • apps/timo-web/api/tag/tag-schema.ts
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/todo-modal/CreateTodoModalContent.tsx
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-tag-field.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_components/SettingsProfileForm.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/SettingsProfileContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsProfile.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_mocks/profile-mock.ts
  • apps/timo-web/app/[locale]/(main)/settings/_types/profile-type.ts
  • apps/timo-web/components/tag/CreateTagModalContainer.tsx
  • apps/timo-web/messages/en.json
  • apps/timo-web/messages/ko.json
  • apps/timo-web/queries/tag/use-create-tag.ts
  • apps/timo-web/queries/tag/use-delete-tag.ts
  • apps/timo-web/queries/tag/use-tags.ts
💤 Files with no reviewable changes (1)
  • apps/timo-web/app/[locale]/(main)/settings/_mocks/profile-mock.ts

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

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

🤖 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)/home/_hooks/todo-modal/use-tag-field.tsx:
- Around line 58-76: Use the useCreateTag mutation’s isPending state in
CreateTagModalContainer and pass it to CreateButton so submission is disabled
while tag creation is in progress, preventing duplicate requests. Keep the
existing onSuccess and onError handling unchanged.

In `@apps/timo-web/app/`[locale]/(main)/settings/_hooks/useSettingsProfile.tsx:
- Around line 65-96: Update handleAddTag to guard before opening
CreateTagModalContainer: when tagItems.length is at least 8, show the existing
tagLimit toast/message and return immediately. Reuse the established translation
or toast mechanism from useTagField, while preserving the current modal and
creation flow below the guard for fewer than 8 tags.
- Around line 17-46: Update useSettingsProfile so default-tag detection compares
each tag’s stable name key (or the API’s stable isDefault field) instead of
translated values from tCommon. Reuse the same key-based criterion as
HomeTodoContainer, and keep translation limited to rendering labels so locale
changes never make default tags appear deletable.

In `@apps/timo-web/components/tag/CreateTagModalContainer.tsx`:
- Around line 38-43: Update handleCreate and the onCreate contract so creation
returns a Promise indicating success; await that result and call setName("")
only after a successful API response. Preserve the trimmed input when creation
fails, including the existing validation behavior.
- Around line 27-28: Update CreateTagModalContainer’s translation usage to
depend on a shared Tag namespace instead of Home, including changing the
relevant key references from Home.createTagModal.* to Tag.createTagModal.*. Move
the corresponding createTagModal entries from the Home namespace to the Tag
namespace in both en.json and ko.json, while preserving the existing Common
translations.
🪄 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: 5d75d67f-3c9a-4783-bcbe-96f8d0bb4182

📥 Commits

Reviewing files that changed from the base of the PR and between 317052f and c0c4d00.

📒 Files selected for processing (14)
  • apps/timo-web/api/tag/tag-schema.ts
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/todo-modal/CreateTodoModalContent.tsx
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-tag-field.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_components/SettingsProfileForm.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/SettingsProfileContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsProfile.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_mocks/profile-mock.ts
  • apps/timo-web/app/[locale]/(main)/settings/_types/profile-type.ts
  • apps/timo-web/components/tag/CreateTagModalContainer.tsx
  • apps/timo-web/messages/en.json
  • apps/timo-web/messages/ko.json
  • apps/timo-web/queries/tag/use-create-tag.ts
  • apps/timo-web/queries/tag/use-delete-tag.ts
  • apps/timo-web/queries/tag/use-tags.ts
💤 Files with no reviewable changes (1)
  • apps/timo-web/app/[locale]/(main)/settings/_mocks/profile-mock.ts
🛑 Comments failed to post (5)
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-tag-field.tsx (1)

58-76: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# CreateTagModalContainer의 onCreate prop 타입과 로딩 상태 처리 확인
ast-grep outline apps/timo-web/components/tag/CreateTagModalContainer.tsx --items all --type function,interface --match 'onCreate|loading|disabled|isLoading'

# onCreate prop 타입 정의 확인
rg -n -C3 'onCreate' apps/timo-web/components/tag/CreateTagModalContainer.tsx

Repository: Team-Timo/Timo-client

Length of output: 737


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== CreateTagModalContainer outline ==\n'
ast-grep outline apps/timo-web/components/tag/CreateTagModalContainer.tsx --view expanded

printf '\n== CreateTagModalContainer relevant lines ==\n'
cat -n apps/timo-web/components/tag/CreateTagModalContainer.tsx | sed -n '1,220p'

printf '\n== use-tag-field wiring ==\n'
cat -n apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-tag-field.tsx | sed -n '1,220p'

Repository: Team-Timo/Timo-client

Length of output: 3765


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== use-tag-field.tsx ==\n'
cat -n 'apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-tag-field.tsx' | sed -n '1,260p'

printf '\n== createTag usages and definition ==\n'
rg -n -C3 'createTag|isPending|isLoading|mutate\(' 'apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home' 'apps/timo-web/components/tag' 'apps/timo-web/app' | sed -n '1,260p'

Repository: Team-Timo/Timo-client

Length of output: 18647


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== useCreateTag hook ==\n'
cat -n 'apps/timo-web/queries/tag/use-create-tag.ts' | sed -n '1,220p'

printf '\n== settings hook wiring ==\n'
cat -n 'apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsProfile.tsx' | sed -n '1,220p'

printf '\n== CreateTagModalContainer usages ==\n'
rg -n -C2 'CreateTagModalContainer' apps/timo-web | sed -n '1,240p'

Repository: Team-Timo/Timo-client

Length of output: 10330


생성 중 제출 차단 추가

CreateTagModalContainer 쪽에 생성 중 상태가 없어서 onCreate가 실행된 뒤에도 버튼이 계속 눌릴 수 있습니다. useCreateTagisPending을 내려 CreateButton을 비활성화하거나, 필요하면 mutateAsync로 바꿔 중복 태그 생성 요청을 막아주세요.
참고: https://tanstack.com/query/latest/docs/react/reference/useMutation

🤖 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)/home/_hooks/todo-modal/use-tag-field.tsx
around lines 58 - 76, Use the useCreateTag mutation’s isPending state in
CreateTagModalContainer and pass it to CreateButton so submission is disabled
while tag creation is in progress, preventing duplicate requests. Keep the
existing onSuccess and onError handling unchanged.
apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsProfile.tsx (2)

17-46: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

git ls-files 'apps/timo-web/app/[locale]/(main)/settings/**' 'apps/timo-web/queries/tag/**' 'apps/timo-web/**/tag*' 'packages/**/tag*' | sed -n '1,200p'

echo '--- useSettingsProfile ---'
sed -n '1,240p' 'apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsProfile.tsx'

echo '--- tag-related files ---'
rg -n "tagSchema|useTags|useCreateTag|useDeleteTag|tagId|isDefault|dailyLife|work|exercise|assignment|additional|tagLimit|Common" \
  'apps/timo-web' 'packages' \
  -g '!**/node_modules/**' \
  -g '!**/.next/**' \
  -g '!**/dist/**' \
  -g '!**/build/**'

Repository: Team-Timo/Timo-client

Length of output: 19373


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- api/tag/tag-schema.ts ---'
cat -n 'apps/timo-web/api/tag/tag-schema.ts'

echo '--- queries/tag/use-tags.ts ---'
cat -n 'apps/timo-web/queries/tag/use-tags.ts'

echo '--- queries/tag/use-create-tag.ts ---'
cat -n 'apps/timo-web/queries/tag/use-create-tag.ts'

echo '--- queries/tag/use-delete-tag.ts ---'
cat -n 'apps/timo-web/queries/tag/use-delete-tag.ts'

echo '--- generated tag response models ---'
cat -n 'apps/timo-web/api/generated/models/tagResponse.ts'
echo
cat -n 'apps/timo-web/api/generated/models/tagListResponse.ts'
echo
cat -n 'apps/timo-web/api/generated/models/tagCreateResponse.ts'

echo '--- use of isDefault elsewhere ---'
rg -n "isDefault" 'apps/timo-web/app' 'apps/timo-web/components' 'apps/timo-web/queries' -g '!**/node_modules/**' -g '!**/.next/**'

Repository: Team-Timo/Timo-client

Length of output: 3925


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- home container tag usage ---'
sed -n '90,130p' 'apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx'

echo '--- tag field usage ---'
sed -n '20,90p' 'apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-tag-field.tsx'

echo '--- tag mocks and sample names ---'
sed -n '1,120p' 'apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_mocks/todo-mock.ts'
echo
sed -n '1,120p' 'apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_mocks/today-todo-mock.ts'

echo '--- tag display components in settings ---'
sed -n '110,150p' 'apps/timo-web/app/[locale]/(main)/settings/_components/SettingsProfileForm.tsx'

Repository: Team-Timo/Timo-client

Length of output: 9535


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "function isTagLabelKey|const isTagLabelKey|export .*isTagLabelKey|isTagLabelKey\\(" 'apps/timo-web' -g '!**/node_modules/**' -g '!**/.next/**'

echo '--- possible helper file(s) ---'
fd -a 'tag' 'apps/timo-web' | sed -n '1,120p'

Repository: Team-Timo/Timo-client

Length of output: 1854


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- HomeTodoContainer top section ---'
sed -n '1,50p' 'apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx'

echo '--- settings profile type ---'
cat -n 'apps/timo-web/app/[locale]/(main)/settings/_types/profile-type.ts'

Repository: Team-Timo/Timo-client

Length of output: 2948


기본 태그 판별 기준을 tag.name 번역값이 아니라 안정적인 키로 맞춰주세요.
useSettingsProfile에서는 tCommon(\tag.${key}`)로 만든 번역 라벨과 tag.name을 비교하고 있는데, 이 코드베이스의 다른 태그 표시 로직은 tag.name"work" | "dailyLife" ...같은 키로 보고 화면에서만 번역합니다. 지금 방식이면 로케일이 바뀌면 기본 태그가 커스텀 태그처럼 보여 삭제 가능 상태로 풀릴 수 있어요.HomeTodoContainer와 같은 기준으로 키 비교를 재사용하거나, API의 isDefault` 같은 안정적인 필드를 쓰는 쪽이 맞습니다.
next-intl 문서와 태그 도메인 스키마를 같이 맞춰두면 덜 미끄러집니다.

🤖 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)/settings/_hooks/useSettingsProfile.tsx
around lines 17 - 46, Update useSettingsProfile so default-tag detection
compares each tag’s stable name key (or the API’s stable isDefault field)
instead of translated values from tCommon. Reuse the same key-based criterion as
HomeTodoContainer, and keep translation limited to rendering labels so locale
changes never make default tags appear deletable.

65-96: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect the target file and nearby context
sed -n '1,220p' apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsProfile.tsx

# 2) Find tag limit / error message definitions and related usages
rg -n "tagLimit|tagActionFailed|isTagLimitToastOpen|isTagErrorToastOpen|최대 8개|8개" apps/timo-web -S

# 3) Inspect the tag creation flow and error handling around createTag
rg -n "createTag\\(|onError: \\(\\) =>|onSuccess: \\(response\\)|CreateTagModalContainer|existingLabels" apps/timo-web/app apps/timo-web/queries -S

Repository: Team-Timo/Timo-client

Length of output: 212


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Target file
sed -n '1,220p' 'apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsProfile.tsx'

# Related message/error strings and toast states
rg -n "tagLimit|tagActionFailed|isTagLimitToastOpen|isTagErrorToastOpen|최대 8개|8개" apps/timo-web -S

# Tag creation flow usage
rg -n "createTag\\(|CreateTagModalContainer|existingLabels|onError: \\(\\) =>|onSuccess: \\(response\\)" 'apps/timo-web/app' 'apps/timo-web/queries' -S

Repository: Team-Timo/Timo-client

Length of output: 9328


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the tag-field flow that already uses a limit toast
sed -n '1,220p' 'apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-tag-field.tsx'

# Inspect the limit toast container
sed -n '1,200p' 'apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/toast/TagLimitToastContainer.tsx'

# Inspect settings container toast wiring
sed -n '1,180p' 'apps/timo-web/app/[locale]/(main)/settings/_containers/SettingsProfileContainer.tsx'

# Inspect create-tag API/query and schema for error/response shape
sed -n '1,220p' 'apps/timo-web/queries/tag/use-create-tag.ts'
sed -n '1,220p' 'apps/timo-web/api/tag/tag-schema.ts'

Repository: Team-Timo/Timo-client

Length of output: 6121


태그 한도 초과는 별도 안내로 분기해 주세요.

apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsProfile.tsx에는 8개 제한 가드가 없어서, 이미 한도에 도달한 상태에서도 생성 모달이 열리고 실패 시 tagActionFailed만 노출됩니다. homeuseTagField처럼 tagItems.length >= 8이면 먼저 tagLimit 토스트를 띄우거나, 서버 에러를 구분해 같은 문구를 재사용하면 사용자 안내가 더 정확해집니다.
참고: https://next-intl.dev/docs/usage/translations

🤖 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)/settings/_hooks/useSettingsProfile.tsx
around lines 65 - 96, Update handleAddTag to guard before opening
CreateTagModalContainer: when tagItems.length is at least 8, show the existing
tagLimit toast/message and return immediately. Reuse the established translation
or toast mechanism from useTagField, while preserving the current modal and
creation flow below the guard for fewer than 8 tags.
apps/timo-web/components/tag/CreateTagModalContainer.tsx (2)

27-28: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

공유 컴포넌트에서 useTranslations("Home") 사용은 도메인 결합을 유발합니다.

components/tag/는 앱 전역 공유 위치이지만, useTranslations("Home")을 사용해 Home 도메인의 번역 키(Home.createTagModal.*)에 의존하고 있습니다. 설정 페이지 등 다른 도메인에서 이 모달을 사용할 때도 Home 번역이 필요하므로 결합도가 높아집니다.

Tag 또는 Common 등 공유 번역 네임스페이스로 분리하는 것을 권장합니다.

♻️ 제안: 번역 네임스페이스 분리
-  const t = useTranslations("Home");
+  const t = useTranslations("Tag");

그리고 messages/en.jsonmessages/ko.json에서 createTagModal 키를 Home에서 Tag 네임스페이스로 이동합니다.

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

  const t = useTranslations("Tag");
  const tCommon = useTranslations("Common");
🤖 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/components/tag/CreateTagModalContainer.tsx` around lines 27 -
28, Update CreateTagModalContainer’s translation usage to depend on a shared Tag
namespace instead of Home, including changing the relevant key references from
Home.createTagModal.* to Tag.createTagModal.*. Move the corresponding
createTagModal entries from the Home namespace to the Tag namespace in both
en.json and ko.json, while preserving the existing Common translations.

38-43: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

API 실패 시 입력값이 미리 초기화되어 사용자가 다시 입력해야 합니다.

handleCreate에서 onCreate(trimmedName) 호출 직후 setName("")을 실행하므로, API 호출이 실패해도 입력값이 이미 비워집니다. 에러 토스트는 표시되지만 사용자가 원래 입력값을 다시 타이핑해야 하는 UX 저하가 발생합니다.

onCreate가 Promise를 반환하도록 변경하여 성공 시에만 입력값을 초기화하는 방안을 고려해 보세요.

♻️ 제안: onCreate 반환값 기반 초기화
-  const handleCreate = () => {
-    if (!isValid) return;
-
-    onCreate(trimmedName);
-    setName("");
-  };
+  const handleCreate = async () => {
+    if (!isValid) return;
+
+    const result = await onCreate(trimmedName);
+    if (result) setName("");
+  };

이를 위해 onCreate 시그니처를 (label: string) => Promise<boolean> 등으로 변경하고, 호출자에서 API 성공 여부를 반환하도록 합니다.

🤖 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/components/tag/CreateTagModalContainer.tsx` around lines 38 -
43, Update handleCreate and the onCreate contract so creation returns a Promise
indicating success; await that result and call setName("") only after a
successful API response. Preserve the trimmed input when creation fails,
including the existing validation behavior.

kimminna added 2 commits July 13, 2026 22:19
- 기본 태그 이름을 프론트에서 추정해 매칭하던 방식이 실제 백엔드 기본 태그 구성과 달라 삭제 버튼이 잘못 노출됐습니다
- GET /api/v1/tags 응답에 실제로 내려오는 isDefault 필드를 로컬 zod 스키마에 추가해 그대로 사용하도록 했습니다
…pi-integration

# Conflicts:
#	apps/timo-web/messages/en.json
#	apps/timo-web/messages/ko.json
@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown

Timo Performance Report

Bundle Size — timo-web
라우트 크기 First Load JS
/[locale]/home 207.39 kB 🔴 413.25 kB
/[locale]/today 189.62 kB 🔴 395.48 kB
/[locale]/focus 159.59 kB 🔴 365.45 kB
/[locale]/settings 168.44 kB 🔴 374.30 kB
/[locale]/statistics 156.13 kB 🔴 361.99 kB
/[locale]/[...rest] 0 B 🟡 205.86 kB
/[locale]/login 215.67 kB 🔴 421.53 kB
/[locale]/oauth/callback 122.31 kB 🟡 328.17 kB
/[locale]/onboarding 235.15 kB 🔴 441.01 kB
/[locale] 121.69 kB 🟡 327.55 kB
/[locale]/policy 127.80 kB 🟡 333.66 kB

공유 번들: 205.86 kB
🟢 < 200kB  |  🟡 < 350kB  |  🔴 ≥ 350kB (First Load JS · gzip)

Lighthouse — timo-web
URL Perf A11y LCP CLS TBT
/en/home 🔴 63 🟢 95 🔴 15.7s 🟢 0.000 🟡 457ms
/en/today 🔴 60 🟢 95 🔴 15.5s 🟢 0.000 🟡 567ms
/en/focus 🔴 61 🟢 95 🔴 15.2s 🟢 0.000 🟡 533ms
/en/statistics 🔴 66 🟢 95 🔴 14.7s 🟢 0.000 🟡 385ms

Perf ≥ 70 / A11y ≥ 85 목표
LCP 🟢 < 2.5s 🟡 < 4s 🔴 ≥ 4s  |  CLS 🟢 < 0.1 🟡 < 0.25 🔴 ≥ 0.25  |  TBT 🟢 < 200ms 🟡 < 600ms 🔴 ≥ 600ms

Image Optimization — timo-web
파일 크기 포맷 상태
images/google-calendar.png 36.20 kB PNG ⚠️ 🟢
images/google-logo.png 26.79 kB PNG ⚠️ 🟢

총 2개 · 63.00 kB  |  🟢 < 200KB  |  🟡 < 500KB  |  🔴 ≥ 500KB
⚠️ 2개 파일 WebP/AVIF 변환 권장

측정 커밋: da3715a

@kimminna kimminna self-assigned this Jul 13, 2026
@kimminna kimminna added ✨ Feature 새로운 기능(기능성) 구현 ♦️ 민아 민아상 labels Jul 13, 2026
kimminna added 2 commits July 13, 2026 22:40
- 빈 페이지만 있던 설정 계정 탭 라우트를 제거했습니다
- policy/, withdrawal/ 기능 도메인 폴더를 다른 설정 탭과 동일하게 settings/_components, _containers, _types 평탄한 구조로 통일했습니다
- 이동에 따라 SettingsTabsContainer의 import 경로를 갱신했습니다
…to feat/web/177-tag-api-integration

# Conflicts:
#	apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/tag-modal/CreateTagModalContainer.tsx
#	apps/timo-web/app/[locale]/(main)/settings/_containers/SettingsPolicyContainer.tsx
#	apps/timo-web/app/[locale]/(main)/settings/_containers/SettingsTabsContainer.tsx
#	apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsProfile.tsx
#	apps/timo-web/app/[locale]/(main)/settings/_mocks/profile-mock.ts
#	apps/timo-web/app/[locale]/(main)/settings/_types/profile-type.ts
#	apps/timo-web/components/tag-modal/CreateTagModalContainer.tsx
#	apps/timo-web/components/tag/CreateTagModalContainer.tsx
#	apps/timo-web/hooks/todo-modal/use-tag-field.tsx

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

굿굿 홈 연동 확인 ~~👍🏻‼️

- 언어 변경 확인 모달에 다른 모달들과 동일하게 타이모 로고 아이콘을 추가했습니다
- 태그 삭제, 로그아웃 클릭 시에도 동일한 패턴의 확인 모달이 뜨도록 추가했습니다
- SettingsProfileForm을 SettingsProfileView로 리네임하고 언어/태그/로그아웃 섹션의 ref·상태·모달 로직을 각각의 컨테이너로 분리했습니다
- 설정 폴더를 account/terms/withdrawal 탭 단위 하위 폴더로 재구조화했습니다

@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: 3

🤖 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/api/tag/tag-schema.ts`:
- Around line 4-6: Strengthen the tagId validation in the tag schema by
requiring it to be an integer greater than zero, while leaving the existing name
and isDefault validations unchanged.

In
`@apps/timo-web/app/`[locale]/(main)/settings/_containers/account/SettingsLogoutModalContainer.tsx:
- Around line 29-34: Replace the hidden-trigger and imperative click flow in
SettingsLogoutModalContainer.tsx at lines 29-34 with a declarative Modal.Trigger
using asChild around the existing PillButton, if supported, and ensure the modal
closes after the action completes. In SettingsTagsSectionContainer.tsx at lines
65-70, use controlled isOpen/onClose state for dynamically selected chips and
explicitly close the modal after a successful delete action.

In
`@apps/timo-web/app/`[locale]/(main)/settings/_hooks/account/useSettingsProfile.tsx:
- Around line 126-138: In the successful language-update flow of the settings
profile hook, replace the direct cache mutation via queryClient.setQueryData
with queryClient.invalidateQueries for the getGetMyProfileQueryKey query. Keep
commitLanguage(next) and ensure the profile is refetched from the server so the
cached language uses the backend’s canonical format.
🪄 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: 4e2f036c-39ae-4ab2-b378-850b31c510fc

📥 Commits

Reviewing files that changed from the base of the PR and between c0c4d00 and 669c158.

📒 Files selected for processing (27)
  • apps/timo-web/api/tag/tag-schema.ts
  • apps/timo-web/app/[locale]/(main)/settings/_components/.gitkeep
  • apps/timo-web/app/[locale]/(main)/settings/_components/account/SettingsProfileView.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_components/withdrawal/SettingsWithdrawalView.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/SettingsTabsContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/account/SettingsLanguageSectionContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/account/SettingsLogoutModalContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/account/SettingsProfileContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/account/SettingsTagsSectionContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/terms/SettingsTermsContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/withdrawal/SettingsWithdrawalContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/account/useSettingsLanguageParam.ts
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/account/useSettingsProfile.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/account/useSettingsProfileLabels.ts
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsLanguageParam.ts
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsProfileLabels.ts
  • apps/timo-web/app/[locale]/(main)/settings/_types/account/profile-type.ts
  • apps/timo-web/app/[locale]/(main)/settings/_types/withdrawal/withdrawal-type.ts
  • apps/timo-web/app/[locale]/(main)/settings/account/_components/.gitkeep
  • apps/timo-web/app/[locale]/(main)/settings/account/_containers/.gitkeep
  • apps/timo-web/app/[locale]/(main)/settings/account/_queries/.gitkeep
  • apps/timo-web/app/[locale]/(main)/settings/account/page.tsx
  • apps/timo-web/app/[locale]/(main)/settings/withdrawal/_queries/.gitkeep
  • apps/timo-web/components/todo-modal/CreateTodoModalContent.tsx
  • apps/timo-web/hooks/todo-modal/use-tag-field.tsx
  • apps/timo-web/messages/en.json
  • apps/timo-web/messages/ko.json
💤 Files with no reviewable changes (3)
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsLanguageParam.ts
  • apps/timo-web/app/[locale]/(main)/settings/account/page.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsProfileLabels.ts

Comment thread apps/timo-web/api/common/tag-schema.ts
Comment on lines +29 to +34
<Modal.Trigger
ref={modalTriggerRef}
className="hidden"
aria-hidden="true"
tabIndex={-1}
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

숨김 버튼을 활용한 모달 트리거 제어 개선 제안

현재 두 곳 모두 useRef로 숨겨진 Modal.Trigger 컴포넌트를 참조하여 강제로 .click() 이벤트를 발생시켜 모달을 열고 있습니다. 이러한 구조는 리액트의 선언적 패러다임과 맞지 않아 아쉽습니다. 😅 또한 사용자가 '확인' 버튼을 클릭하여 API 작업이 완료된 후, 모달이 스스로 닫히지 않고 열려 있을 가능성도 존재합니다.

가능하다면 다음과 같이 선언적인 방식을 적용해 보시는 건 어떨까요? (만약 디자인 시스템 제약으로 불가피한 구조라면 편하게 무시해 주셔도 됩니다!)

  • apps/timo-web/app/[locale]/(main)/settings/_containers/account/SettingsLogoutModalContainer.tsx#L29-L34: Modal.TriggerasChild 속성이 있다면 숨김 버튼 없이 기존 PillButton을 직접 감싸도록 수정하고, 동작 후 모달이 닫히는지 확인해 주세요.
  • apps/timo-web/app/[locale]/(main)/settings/_containers/account/SettingsTagsSectionContainer.tsx#L65-L70: 여러 칩 요소에서 동적으로 모달을 열어야 하므로, 상태(isOpen, onClose) 기반의 제어(controlled) 컴포넌트 방식을 고려해 보고 삭제 액션 성공 시 명시적으로 모달을 닫아주는 로직을 확인해 주세요.
📍 Affects 2 files
  • apps/timo-web/app/[locale]/(main)/settings/_containers/account/SettingsLogoutModalContainer.tsx#L29-L34 (this comment)
  • apps/timo-web/app/[locale]/(main)/settings/_containers/account/SettingsTagsSectionContainer.tsx#L65-L70
🤖 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)/settings/_containers/account/SettingsLogoutModalContainer.tsx
around lines 29 - 34, Replace the hidden-trigger and imperative click flow in
SettingsLogoutModalContainer.tsx at lines 29-34 with a declarative Modal.Trigger
using asChild around the existing PillButton, if supported, and ensure the modal
closes after the action completes. In SettingsTagsSectionContainer.tsx at lines
65-70, use controlled isOpen/onClose state for dynamically selected chips and
explicitly close the modal after a successful delete action.

Comment thread apps/timo-web/app/[locale]/(main)/settings/_hooks/account/useSettingsProfile.tsx Outdated
kimminna added 2 commits July 14, 2026 14:30
…pi-integration

# Conflicts:
#	apps/timo-web/app/[locale]/(main)/settings/_containers/withdrawal/SettingsWithdrawalContainer.tsx
#	apps/timo-web/app/[locale]/(main)/settings/_hooks/useSettingsProfile.ts
- 로그아웃과 탈퇴 두 곳에서만 쓰이는 훅이라 전역 hooks가 아닌 settings/_hooks로 옮겼습니다
- use-logout.ts, use-withdraw.ts의 import 경로를 갱신했습니다
- setQueryData로 응답 값을 캐시에 직접 병합하던 로직을 제거했습니다
- updateLanguage 성공 후 getMyProfile 쿼리를 invalidate해 서버의 최신 상태를 다시 받아오도록 했습니다
- Toast.languageChangeFailed 메시지 키를 추가했습니다
- useSettingsProfile의 window.alert를 제거하고 토스트 상태로 교체했습니다
- SettingsProfileContainer에 언어 변경 실패 토스트를 렌더링했습니다
@kimminna kimminna changed the title [FEAT] 태그 API 연동 (홈 모달 + 설정 페이지) [FEAT] 태그 API 연동 및 설정 확인 모달·폴더 구조 개선 Jul 14, 2026
kimminna added 2 commits July 14, 2026 15:28
- useSettingsLanguageParam.ts, useSettingsProfileLabels.ts, useClearSession.ts, useSettingsTab.ts를 kebab-case로 리네임했습니다
- 컴포넌트 파일을 제외한 파일은 kebab-case를 쓰는 프로젝트 컨벤션에 맞췄습니다
- 태그 생성 모달(overlay.open + CreateTagModalContainer)을 SettingsProfileContainer로 옮겼습니다
- 캘린더 연결 여부, 태그/언어 에러 토스트 등 UI state를 컨테이너가 소유하도록 했습니다
- 훅은 각 액션에 { onSuccess, onError } 핸들러를 받아 데이터/뮤테이션 로직만 담당하도록 정리했습니다
- JSX가 사라져 useSettingsProfile.tsx를 use-settings-profile.ts로 리네임했습니다
- 홈 모달, 설정 페이지 등 여러 도메인이 공유하는 스키마임을 명확히 하기 위해 api/tag, api/todo에서 api/common으로 옮겼습니다
- 소비하는 11개 파일의 import 경로를 갱신했습니다

@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: 3

🤖 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)/settings/_containers/account/SettingsProfileContainer.tsx:
- Around line 19-21: Remove the local isCalendarConnected useState in
SettingsProfileContainer and use profileState.calendarConnected as the single
source of truth. Update any calendar connection toggle or rendering logic to
read from that React Query-backed value; use an optimistic update only if
immediate UI feedback is required.

In `@apps/timo-web/app/`[locale]/(main)/settings/_hooks/use-settings-tab.ts:
- Line 5: Rename the union type alias SettingsTab to SettingsTabTypes, then
update the import and all related return-type references in
SettingsNavContainer.tsx to use the new name.
- Around line 14-18: Wrap SettingsTabsContainer with a React Suspense boundary
in page.tsx or layout.tsx, positioned above where useSettingsTab is invoked; do
not rely on the inner AsyncBoundary. Preserve the existing useSettingsTab
behavior and provide a suitable Suspense fallback to avoid static-rendering
bailout/build failures from useSearchParams.
🪄 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: 929303e0-4e6e-4491-8081-9f022ef7f76c

📥 Commits

Reviewing files that changed from the base of the PR and between 669c158 and 883df20.

📒 Files selected for processing (14)
  • apps/timo-web/app/[locale]/(main)/settings/_containers/SettingsNavContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/SettingsTabsContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/account/SettingsProfileContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/withdrawal/SettingsWithdrawalContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-language-param.ts
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-profile-labels.ts
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-profile.ts
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/use-clear-session.ts
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/use-settings-tab.ts
  • apps/timo-web/app/[locale]/(main)/settings/_queries/.gitkeep
  • apps/timo-web/app/[locale]/(main)/settings/_queries/account/use-logout.ts
  • apps/timo-web/app/[locale]/(main)/settings/_queries/withdrawal/use-withdraw.ts
  • apps/timo-web/messages/en.json
  • apps/timo-web/messages/ko.json

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

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

🤖 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)/settings/_containers/account/SettingsProfileContainer.tsx:
- Around line 19-21: Remove the local isCalendarConnected useState in
SettingsProfileContainer and use profileState.calendarConnected as the single
source of truth. Update any calendar connection toggle or rendering logic to
read from that React Query-backed value; use an optimistic update only if
immediate UI feedback is required.

In `@apps/timo-web/app/`[locale]/(main)/settings/_hooks/use-settings-tab.ts:
- Line 5: Rename the union type alias SettingsTab to SettingsTabTypes, then
update the import and all related return-type references in
SettingsNavContainer.tsx to use the new name.
- Around line 14-18: Wrap SettingsTabsContainer with a React Suspense boundary
in page.tsx or layout.tsx, positioned above where useSettingsTab is invoked; do
not rely on the inner AsyncBoundary. Preserve the existing useSettingsTab
behavior and provide a suitable Suspense fallback to avoid static-rendering
bailout/build failures from useSearchParams.
🪄 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: 929303e0-4e6e-4491-8081-9f022ef7f76c

📥 Commits

Reviewing files that changed from the base of the PR and between 669c158 and 883df20.

📒 Files selected for processing (14)
  • apps/timo-web/app/[locale]/(main)/settings/_containers/SettingsNavContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/SettingsTabsContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/account/SettingsProfileContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_containers/withdrawal/SettingsWithdrawalContainer.tsx
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-language-param.ts
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-profile-labels.ts
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/account/use-settings-profile.ts
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/use-clear-session.ts
  • apps/timo-web/app/[locale]/(main)/settings/_hooks/use-settings-tab.ts
  • apps/timo-web/app/[locale]/(main)/settings/_queries/.gitkeep
  • apps/timo-web/app/[locale]/(main)/settings/_queries/account/use-logout.ts
  • apps/timo-web/app/[locale]/(main)/settings/_queries/withdrawal/use-withdraw.ts
  • apps/timo-web/messages/en.json
  • apps/timo-web/messages/ko.json
🛑 Comments failed to post (3)
apps/timo-web/app/[locale]/(main)/settings/_containers/account/SettingsProfileContainer.tsx (1)

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

서버 상태와 로컬 상태의 중복 관리 방지

현재 isCalendarConnecteduseState로 관리하여 서버 상태(profileState.calendarConnected)를 복사해서 사용하고 계시네요.

현재는 API가 모킹되어 있어 즉각적인 UI 반영을 위해 임시로 추가하신 것으로 보입니다만, 향후 실제 캘린더 연동 API를 구현하실 때는 아키텍처 가이드라인에 맞춰 로컬 상태 복제를 피하고 React Query를 단일 출처(Single Source of Truth)로 유지하는 것을 추천해 드려요! 클릭 시 즉각적인 반응이 필요하다면 React Query의 낙관적 업데이트(Optimistic Updates) 패턴을 활용하시면 좋습니다. 😊

🤖 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)/settings/_containers/account/SettingsProfileContainer.tsx
around lines 19 - 21, Remove the local isCalendarConnected useState in
SettingsProfileContainer and use profileState.calendarConnected as the single
source of truth. Update any calendar connection toggle or rendering logic to
read from that React Query-backed value; use an optimistic update only if
immediate UI feedback is required.

Source: Path instructions

apps/timo-web/app/[locale]/(main)/settings/_hooks/use-settings-tab.ts (2)

5-5: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

union 타입 alias 이름을 Types 접미사 규칙에 맞춰 주세요.

새로 추가된 SettingsTab은 union용 type alias인데, 경로 지침은 이런 alias에 Types 접미사를 요구합니다. SettingsTabTypes로 변경하고 SettingsNavContainer.tsx의 import 및 관련 반환 타입도 함께 갱신해 주세요.

제안
-export type SettingsTab = "account" | "policy" | "privacy" | "withdrawal";
+export type SettingsTabTypes =
+  | "account"
+  | "policy"
+  | "privacy"
+  | "withdrawal";

경로 지침의 “type alias는 유니언·튜플·리터럴에만 사용, 접미사 Types” 규칙을 적용해야 합니다.

📝 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 type SettingsTabTypes =
  | "account"
  | "policy"
  | "privacy"
  | "withdrawal";
🤖 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)/settings/_hooks/use-settings-tab.ts at
line 5, Rename the union type alias SettingsTab to SettingsTabTypes, then update
the import and all related return-type references in SettingsNavContainer.tsx to
use the new name.

Source: Path instructions


14-18: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

rg -n -C 5 'useSettingsTab|SettingsTabsContainer|<Suspense|dynamic' \
  apps/timo-web/app

Repository: Team-Timo/Timo-client

Length of output: 6402


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

cat -n .agents/skills/quality/timo-review/SKILL.md

Repository: Team-Timo/Timo-client

Length of output: 2559


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '\n== page.tsx ==\n'
cat -n apps/timo-web/app/[locale]/(main)/settings/page.tsx

printf '\n== SettingsTabsContainer.tsx ==\n'
cat -n apps/timo-web/app/[locale]/(main)/settings/_containers/SettingsTabsContainer.tsx

printf '\n== layout files around settings ==\n'
find apps/timo-web/app/[locale]/(main) -maxdepth 3 \( -name 'layout.tsx' -o -name 'page.tsx' \) | sort

Repository: Team-Timo/Timo-client

Length of output: 228


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '\n== page.tsx ==\n'
cat -n "apps/timo-web/app/[locale]/(main)/settings/page.tsx"

printf '\n== SettingsTabsContainer.tsx ==\n'
cat -n "apps/timo-web/app/[locale]/(main)/settings/_containers/SettingsTabsContainer.tsx"

printf '\n== layout/page files under settings ==\n'
find "apps/timo-web/app/[locale]/(main)/settings" -maxdepth 3 \( -name 'layout.tsx' -o -name 'page.tsx' \) | sort | xargs -r -I{} sh -c 'printf "\n-- %s --\n" "$1"; cat -n "$1"' _ {}

Repository: Team-Timo/Timo-client

Length of output: 2729


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '\n== search for Suspense / dynamic in settings route tree ==\n'
rg -n -C 3 'Suspense|dynamic\s*=|useSearchParams|SettingsTabsContainer' "apps/timo-web/app/[locale]/(main)/settings" "apps/timo-web/app/[locale]/(main)"

Repository: Team-Timo/Timo-client

Length of output: 10176


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '\n== AsyncBoundary definition ==\n'
rg -n -C 4 'export .*AsyncBoundary|function AsyncBoundary|const AsyncBoundary' "apps/timo-web" "components" "packages"

printf '\n== file candidates ==\n'
fd -a 'AsyncBoundary*' "apps/timo-web" "components" "packages"

Repository: Team-Timo/Timo-client

Length of output: 924


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

FILE="$(fd -a 'AsyncBoundary*' apps/timo-web components packages | head -n 1 || true)"
if [ -n "$FILE" ]; then
  printf '== %s ==\n' "$FILE"
  cat -n "$FILE"
fi

Repository: Team-Timo/Timo-client

Length of output: 1074


useSearchParams()SettingsTabsContainer보다 상위에서 Suspense로 감싸세요.
AsyncBoundary가 있더라도 useSettingsTab() 호출은 그보다 먼저 실행됩니다. page.tsx(또는 layout.tsx)에서 <Suspense>SettingsTabsContainer를 감싸야 정적 렌더링에서의 bailout/build 이슈를 피할 수 있습니다. Next.js useSearchParams 문서의 Suspense 요구사항도 같이 참고해 주세요.

🤖 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)/settings/_hooks/use-settings-tab.ts around
lines 14 - 18, Wrap SettingsTabsContainer with a React Suspense boundary in
page.tsx or layout.tsx, positioned above where useSettingsTab is invoked; do not
rely on the inner AsyncBoundary. Preserve the existing useSettingsTab behavior
and provide a suitable Suspense fallback to avoid static-rendering bailout/build
failures from useSearchParams.

…pi-integration

# Conflicts:
#	apps/timo-web/components/todo-modal/create/CreateTodoModalContent.tsx
@kimminna
kimminna merged commit 9616cf9 into develop Jul 14, 2026
9 of 10 checks passed
@kimminna
kimminna deleted the feat/web/177-tag-api-integration branch July 14, 2026 06:59
@kimminna kimminna mentioned this pull request Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 새로운 기능(기능성) 구현 ⏰ Timo-web Timo 웹 서비스 ♦️ 민아 민아상

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 태그 API 연동 (홈 모달 + 설정 페이지)

2 participants