Skip to content

Feat: total user count api 연결 및 쿼리 무효화 로직 수정#195

Merged
seueooo merged 3 commits into
developfrom
feat/home-api/#194
Aug 22, 2025
Merged

Feat: total user count api 연결 및 쿼리 무효화 로직 수정#195
seueooo merged 3 commits into
developfrom
feat/home-api/#194

Conversation

@seueooo
Copy link
Copy Markdown
Contributor

@seueooo seueooo commented Aug 22, 2025

📌 Summary

해당 PR에 대한 작업 내용을 요약하여 작성해주세요.

📚 Tasks

  • total user count api 연결
  • 필요한 부분만 쿼리키 무효화되도록 로직 수정
  • staleTime 설정

Summary by CodeRabbit

  • New Features
    • 홈 캡션이 총 이용자 수를 실시간으로 표시하도록 개선되었습니다.
  • Refactor
    • 캡슐 관련 쿼리 캐시 무효화를 더욱 세분화·동시 처리하여 불필요한 새로고침을 줄이고 응답성을 향상했습니다.
  • Chores
    • 전체 이용자 수 조회 엔드포인트, 응답 타입, 장기 캐시 설정 및 해당 쿼리가 추가되었습니다.
  • Style
    • 사용되지 않는 임포트와 포맷을 정리해 코드 품질을 개선했습니다.

@seueooo seueooo requested a review from seung365 as a code owner August 22, 2025 12:45
@seueooo seueooo linked an issue Aug 22, 2025 that may be closed by this pull request
@vercel
Copy link
Copy Markdown

vercel Bot commented Aug 22, 2025

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

Project Deployment Preview Comments Updated (UTC)
time-capsule Ready Ready Preview Comment Aug 22, 2025 1:04pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 22, 2025

Walkthrough

홈 캡션 컴포넌트가 총 사용자 수를 prop으로 받아 렌더하도록 변경하고, 홈 페이지에서 React Query로 TOTAL_USER_COUNT를 조회해 전달합니다. 관련 엔드포인트·응답 타입·쿼리 옵션·CACHE_TIME 상수를 추가했고, 캡슐 관련 뮤테이션들의 캐시 무효화를 detail/my 단위로 세분화 및 동시 처리하도록 변경했습니다. 그 외 불필요한 임포트 제거와 포맷 정리가 포함됩니다.

Changes

Cohort / File(s) Change Summary
User count 통합 (엔드포인트·타입·쿼리·UI)
shared/constants/endpoints.ts, shared/types/api/user.ts, shared/constants/api.ts, shared/api/queries/user.ts, app/(main)/page.tsx, app/(main)/_components/home-caption-section/index.tsx
TOTAL_USER_COUNT 엔드포인트 및 TotalUserCountRes 타입 추가, CACHE_TIME 상수 도입, userQueryOptions.totalUserCount 쿼리 추가(staleTime: LONG), Home 페이지에서 totalUserCount 조회 후 HomeCaptionSection에 전달, 컴포넌트가 정적 문구에서 전달된 숫자 기반 동적 문구로 변경
캡슐 뮤테이션 캐시 무효화 정교화
shared/api/mutations/capsule.ts
create/leave 이후 무효화 대상을 전체에서 ["capsule","my"] 및 해당 detail(id)로 축소, like 토글은 id를 반환하도록 변경하고 onSuccess에서 detail(id)my()Promise.all로 동시 무효화
경미한 정리/포맷 수정
app/(sub)/capsule-detail/_components/write-modal/index.tsx, shared/api/queries/capsule.ts
불필요한 useEffect 임포트 제거, getSearchCapsuleLists 시그니처의 트레일링 콤마 제거(기능 변경 없음)

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor 사용자
  participant Home as Home (app/(main)/page.tsx)
  participant RQ as React Query
  participant API as ENDPOINTS.TOTAL_USER_COUNT
  participant Comp as HomeCaptionSection

  사용자->>Home: 페이지 접속
  Home->>RQ: totalUserCount 쿼리 요청 (staleTime: LONG)
  RQ->>API: GET /api/v1/users/total-count
  API-->>RQ: { result: { userTotalCount } }
  RQ-->>Home: data 전달
  Home->>Comp: totalUserCount={data?.result.userTotalCount ?? 0}
  Comp-->>사용자: "{n}명이 이야기를 주고 받는 중" 렌더
  Note right of RQ: 캐시 유효기간 = CACHE_TIME.LONG
Loading
sequenceDiagram
  autonumber
  actor 사용자
  participant UI as Like UI
  participant M as useLikeToggle
  participant API as Like API
  participant RQ as React Query Cache

  사용자->>UI: 좋아요 토글
  UI->>M: mutate(id)
  M->>API: 요청 (like/unlike)
  API-->>M: 성공 응답 (id 반환)
  M->>RQ: Promise.all([invalidate(detail(id)), invalidate(["capsule","my"])])
  RQ-->>UI: 관련 쿼리 재검증
  UI-->>사용자: 업데이트된 상태 표시
  Note over M,RQ: 이전: 전체 무효화 → 변경: detail/my 동시 무효화
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/home-api/#194

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Copy Markdown

This pull request (commit ca67b0b) has been deployed to Vercel ▲ - View GitHub Actions Workflow Logs

Name Link
🌐 Unique https://time-capsule-onh0cf920-hs-projects-b4a69d5f.vercel.app
🔍 Inspect https://vercel.com/hs-projects-b4a69d5f/time-capsule/56xP33H6uGyF6uAwPKEccSZ9ppC5

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Aug 22, 2025

🚀 Storybook 배포

📖 Storybook: https://683d91ab23651aa0b399e435-ujvknsbsva.chromatic.com/
🔗 Chromatic Build: https://www.chromatic.com/build?appId=683d91ab23651aa0b399e435&number=220
✅ Status: success

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
app/(sub)/capsule-detail/_components/write-modal/index.tsx (1)

93-104: 경고 모달 표시 시 즉시 reset/removeImage가 실행되어 작성 중 데이터가 소실됩니다

닫기 버튼 클릭만으로 폼이 초기화되고 이미지가 제거됩니다. 사용자가 경고 모달에서 “취소(계속 작성)”를 눌러도 복구가 불가합니다. 초기화는 실제 닫기 확정 시점(경고 모달의 close 핸들러)으로 이동하세요.

아래처럼 수정 제안:

-  const handleCloseWithWarning = () => {
-    setIsWarningOpen(true);
-    reset({
-      capsuleId: capsuleData.result.id.toString(),
-      content: "",
-      from: "",
-      objectKey: "",
-    });
-    if (uploadedImageUrl) {
-      removeImage();
-    }
-  };
+  const handleCloseWithWarning = () => {
+    setIsWarningOpen(true);
+  };
-        <PopupWarningLetter
-          isOpen={isWarningOpen}
-          close={() => {
-            setIsWarningOpen(false);
-            onClose();
-          }}
-          confirm={() => setIsWarningOpen(false)}
-        />
+        <PopupWarningLetter
+          isOpen={isWarningOpen}
+          close={() => {
+            // 실제 닫기 확정 시점에만 초기화
+            reset({
+              capsuleId: capsuleData.result.id.toString(),
+              content: "",
+              from: "",
+              objectKey: "",
+            });
+            if (uploadedImageUrl) {
+              removeImage();
+            }
+            setIsWarningOpen(false);
+            onClose();
+          }}
+          confirm={() => setIsWarningOpen(false)}
+        />

Also applies to: 232-239

🧹 Nitpick comments (10)
app/(sub)/capsule-detail/_components/write-modal/index.tsx (2)

118-125: 로딩 상태의 접근성 보완: aria-busy 등 추가 제안

스피너 표시는 좋습니다. 보조기기 인식을 위해 버튼에 aria-busy를 함께 지정하면 더 좋습니다.

-            <button 
+            <button 
               type="submit" 
               className={styles.title} 
-              disabled={(isPending || isUploading)}
+              disabled={isPending || isUploading}
+              aria-busy={isPending || isUploading}
+              aria-live="polite"
             >

149-156: 입력 컨트롤에 명시적 접근성 연결 추가 제안

  • textarea에 레이블이 없어 스크린리더 인식이 어렵습니다(placeholder는 대체 불가).
  • “보내는 사람” 텍스트와 input이 시각적으로만 연계되어 있습니다.

간단히 다음처럼 개선을 권장합니다.

           <textarea
             className={styles.textarea}
             placeholder="나누고 싶은 생각을 공유해보세요!"
+            aria-label="편지 내용"
             {...contentField}
             maxLength={1000}
           />
-                <p className={styles.senderTitle}>보내는 사람</p>
+                <p id="sender-title" className={styles.senderTitle}>보내는 사람</p>
...
-                  <input
+                  <input
                     id="sender-name"
                     type="text"
                     placeholder="꼭 입력하지 않아도 괜찮아요"
                     className={styles.senderInput}
                     {...fromField}
                     maxLength={20}
+                    aria-labelledby="sender-title"
                   />

Also applies to: 200-209

shared/constants/api.ts (1)

11-15: CACHE_TIME 프리셋 추가 LGTM + 의미 명확화 제안

staleTime 등 밀리초 단위 사용을 명시하는 주석을 추가하면 혼동을 줄일 수 있습니다(이름 변경까지는 비필수).

+/**
+ * 밀리초(ms) 단위의 캐시/신선도 프리셋. React Query staleTime 등에 사용.
+ */
 export const CACHE_TIME = {
   SHORT: 1000 * 60 * 3,
   MEDIUM: 1000 * 60 * 5,
   LONG: 1000 * 60 * 10,
 } as const;
shared/constants/endpoints.ts (1)

43-44: 파일 업로드 쿼리 파라미터도 인코딩 권장

fileName/extension에 공백·특수문자가 포함될 수 있다면 인코딩이 안전합니다. 기존 호출부 영향은 거의 없고 서버 파싱이 표준적이라면 그대로 동작합니다.

-  UPLOAD_FILE: (fileName: string, extension: string) =>
-    `api/v1/files/presigned-url?fileName=${fileName}&extension=${extension}`,
+  UPLOAD_FILE: (fileName: string, extension: string) =>
+    `api/v1/files/presigned-url?fileName=${encodeURIComponent(fileName)}&extension=${encodeURIComponent(extension)}`,
shared/api/queries/capsule.ts (1)

68-78: 검색 인피니트 쿼리: 공백/빈 키워드 시 요청 방지 제안

빈 문자열 또는 공백만 있을 때 네트워크 호출을 막아 불필요한 트래픽을 줄일 수 있습니다.

   searchCapsuleList: (keyword: string) =>
     infiniteQueryOptions({
       queryKey: capsuleQueryKeys.searchList(keyword),
       queryFn: ({ pageParam = 0 }) =>
         getSearchCapsuleLists(keyword, pageParam, 20),
+      enabled: keyword.trim().length > 0,
       getNextPageParam: (lastPage) => {
         const { pageNumber, totalPages } = lastPage.result;
         return pageNumber < totalPages - 1 ? pageNumber + 1 : undefined;
       },
       initialPageParam: 0,
     }),
shared/api/mutations/capsule.ts (2)

34-43: 좋은 방향: ID 기반 동시 무효화 + onSuccess의 반환값 활용

토글 결과로 id를 반환하고, detail(id)myPromise.all로 동시에 무효화하는 접근은 효율적입니다. 다만 위 코멘트처럼 my() 대신 접두 키를 사용해 다양한 정렬/필터 변형을 모두 커버하는 것이 안전합니다.

적용 제안(diff):

-        queryClient.invalidateQueries({ queryKey: capsuleQueryKeys.my() }),
+        queryClient.invalidateQueries({ queryKey: ["capsule", "my"] }),

11-22: 에러 처리 훅(onError) 연결 제안

생성/탈퇴/좋아요 토글에서 서버 에러 시 사용자 피드백(토스트/알럿)이나 로깅이 필요하다면 onError를 추가해 주세요. UX/관측성 측면 이점이 큽니다.

Also applies to: 47-57

app/(main)/page.tsx (1)

20-21: 초기값 처리는 null 병합 연산자(??)가 더 명확합니다

의도상 “정의되지 않은 경우만 0”이면 || 0보다 ?? 0이 안전하고 가독성도 좋습니다. JSX에서도 중복 초기값을 제거할 수 있습니다.

적용 제안(diff):

-  const totalUserCount = data?.result.userTotalCount;
+  const totalUserCount = data?.result.userTotalCount ?? 0;
@@
-        <HomeCaptionSection totalUserCount={totalUserCount || 0} />
+        <HomeCaptionSection totalUserCount={totalUserCount} />

Also applies to: 37-37

app/(main)/_components/home-caption-section/index.tsx (1)

11-13: 숫자 가독성 및 접근성 보강 제안(toLocaleString, aria-live)

큰 숫자는 천 단위 구분이 가독성을 높입니다. 또한 값이 비동기로 갱신되므로 보조공학 사용자에게는 aria-live="polite"가 유용합니다.

적용 제안(diff):

-      <p className={styles.caption}>
-        {totalUserCount}명이 이야기를 주고 받는 중
+      <p className={styles.caption} aria-live="polite">
+        {totalUserCount.toLocaleString()}명이 이야기를 주고 받는 중
       </p>
shared/api/queries/user.ts (1)

31-37: 캐시 보존 시간(gcTime)과 데이터 선택(select) 추가로 응답 봉인을 페이지에서 제거

  • LONG 기간 동안 재사용하려면 v5 기준 gcTime도 함께 설정하는 게 안전합니다(기본 5분 후 GC).
  • 페이지에서 result.userTotalCount를 꺼내는 보일러플레이트를 없애려면 select로 숫자만 노출하세요.

두 개선으로 페이지 단은 data를 곧바로 숫자로 다룰 수 있습니다.

적용 제안(diff):

     queryOptions({
       queryKey: userQueryKeys.totalUserCount(),
       queryFn: () => {
         return apiClient.get<TotalUserCountRes>(ENDPOINTS.TOTAL_USER_COUNT);
       },
       ...options,
-      staleTime: CACHE_TIME.LONG,
+      staleTime: CACHE_TIME.LONG,
+      gcTime: CACHE_TIME.LONG,
+      select: (data) => data.result.userTotalCount,
     }),

추가로, 이 변경을 적용하면 app/(main)/page.tsx에서

const { data: totalUserCount } = useQuery(userQueryOptions.totalUserCount());

처럼 바로 숫자를 받을 수 있습니다.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a4ca568 and ca67b0b.

📒 Files selected for processing (9)
  • app/(main)/_components/home-caption-section/index.tsx (1 hunks)
  • app/(main)/page.tsx (2 hunks)
  • app/(sub)/capsule-detail/_components/write-modal/index.tsx (1 hunks)
  • shared/api/mutations/capsule.ts (3 hunks)
  • shared/api/queries/capsule.ts (1 hunks)
  • shared/api/queries/user.ts (2 hunks)
  • shared/constants/api.ts (1 hunks)
  • shared/constants/endpoints.ts (2 hunks)
  • shared/types/api/user.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
shared/api/queries/capsule.ts (3)
shared/api/api-client.ts (1)
  • apiClient (50-65)
shared/types/api/capsule.ts (1)
  • CapsuleListsRes (45-53)
shared/constants/endpoints.ts (1)
  • ENDPOINTS (3-45)
app/(main)/page.tsx (1)
shared/api/queries/user.ts (1)
  • userQueryOptions (13-38)
shared/api/mutations/capsule.ts (1)
shared/api/queries/capsule.ts (1)
  • capsuleQueryKeys (14-34)
shared/api/queries/user.ts (4)
shared/api/api-client.ts (1)
  • apiClient (50-65)
shared/types/api/user.ts (1)
  • TotalUserCountRes (9-13)
shared/constants/endpoints.ts (1)
  • ENDPOINTS (3-45)
shared/constants/api.ts (1)
  • CACHE_TIME (11-15)
🔇 Additional comments (6)
app/(sub)/capsule-detail/_components/write-modal/index.tsx (1)

16-16: 불필요한 React import 정리 LGTM

useEffect 제거로 번들 미미하지만 긍정적인 정리입니다. 영향도 없음.

shared/types/api/user.ts (1)

9-13: TotalUserCountRes 타입 추가 LGTM

응답 스키마(result.userTotalCount) 명확하고 일관적입니다. 향후 확장을 염두에 두면 readonly 필드 지정까지는 선택 사항입니다.

shared/constants/endpoints.ts (2)

17-19: 검색 키워드 인코딩 적용 LGTM

encodeURIComponent 적용으로 공백/특수문자 검색 안정성이 좋아졌습니다.


33-34: TOTAL_USER_COUNT 엔드포인트 정의 LGTM

타입 및 쿼리 추가와 일관되며, 경로 네이밍도 명확합니다.

shared/api/queries/capsule.ts (1)

96-103: 포맷 정리(마지막 파라미터 콤마 제거) — 동작 영향 없음

의미 변화 없이 가독성만 개선되었습니다.

app/(main)/page.tsx (1)

16-19: queryOptions 기반 useQuery 사용 적절

userQueryOptions.totalUserCount()로 옵션을 캡슐화해 사용한 점 좋습니다. 이 패턴을 유지하면 API 응답 형태 변경 시 페이지 단의 수정 비용이 줄어듭니다.

Comment on lines 19 to 22
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: capsuleQueryKeys.all() });
queryClient.invalidateQueries({ queryKey: capsuleQueryKeys.my() });
},
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

my() 키 무효화: 부분 매칭 실패 가능성(undef 포함) → 접두 키로 변경 권장

capsuleQueryKeys.my()["capsule","my", sort, filter] 형태를 반환하는데, 인자를 생략하면 [...,"my", undefined, undefined]가 됩니다. React Query의 부분 매칭에서 undefined가 포함된 배열은 원하는 모든 my 변형(정렬/필터 값이 있는 키)과 매칭되지 않을 수 있어 실제로 캐시가 무효화되지 않는 위험이 있습니다. 접두 키 ["capsule","my"]로 무효화하는 것이 안전합니다.

아래 스크립트로 실제 capsuleQueryKeys.my( 사용 시 정렬/필터 인자를 넘기는지 점검해 주세요. 인자를 넘기는 사용이 있다면 지금의 무효화는 누락됩니다.

적용 제안(diff):

-      queryClient.invalidateQueries({ queryKey: capsuleQueryKeys.my() });
+      queryClient.invalidateQueries({ queryKey: ["capsule", "my"] });

🏁 Script executed:

#!/bin/bash
# my() 키 사용 패턴 확인
rg -nC2 -P 'capsuleQueryKeys\.my\s*\(' --type ts --type tsx

# React Query 버전 확인(선택)
fd -HI package.json -x jq -r '.dependencies["@tanstack/react-query"], .devDependencies["@tanstack/react-query"]?' {}

Length of output: 223


TSX 파일 검색 오류로 my() 호출 패턴이 제대로 확인되지 않았습니다. 아래 명령어로 .ts/.tsx 파일 전체를 재검색해 주세요. 결과를 공유해 주시면, 정렬·필터 인자 전달 여부를 검토해 드리겠습니다.


🏁 Script executed:

#!/bin/bash
# capsuleQueryKeys.my 호출 패턴 확인 (ts, tsx 전체 검색)
rg -nC2 'capsuleQueryKeys\.my\s*\(' --glob '*.ts' --glob '*.tsx'

Length of output: 1399


invalidateQueries: capsuleQueryKeys.my() 대신 ['capsule','my'] 접두 키 사용

capsuleQueryKeys.my()는 sort/filter 인자를 생략하면 마지막 요소에 undefined가 들어가 React Query의 부분 매칭에서 예상치 못한 누락이 발생할 수 있습니다. 모든 my 관련 쿼리를 안전하게 무효화하려면 접두 키만 전달하세요.

수정이 필요한 위치:

  • shared/api/mutations/capsule.ts:20 (onSuccess 첫 번째)
  • shared/api/mutations/capsule.ts:41 (onSuccess 두 번째)
  • shared/api/mutations/capsule.ts:54 (onSuccess 세 번째)

예시 diff:

-      queryClient.invalidateQueries({ queryKey: capsuleQueryKeys.my() });
+      queryClient.invalidateQueries({ queryKey: ["capsule", "my"] });
🤖 Prompt for AI Agents
shared/api/mutations/capsule.ts around lines 20, 41, and 54: the onSuccess
handlers call queryClient.invalidateQueries({ queryKey: capsuleQueryKeys.my() })
which can produce a trailing undefined element and break partial matching;
replace those calls to use the prefix array form queryClient.invalidateQueries({
queryKey: ['capsule','my'] }) (update the three onSuccess occurrences) so all
"my" related queries are safely invalidated.

Comment thread shared/api/mutations/capsule.ts Outdated
@github-actions
Copy link
Copy Markdown

This pull request (commit c7cb61b) has been deployed to Vercel ▲ - View GitHub Actions Workflow Logs

Name Link
🌐 Unique https://time-capsule-asc6c0d0k-hs-projects-b4a69d5f.vercel.app
🔍 Inspect https://vercel.com/hs-projects-b4a69d5f/time-capsule/CyxccL515EGV7mnM3aCR9wSNvXwN

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
shared/api/mutations/capsule.ts (1)

19-21: invalidateQueries 키: capsuleQueryKeys.my() 대신 접두 키 사용 필요

capsuleQueryKeys.my()(sort?, filter?)가 생략될 때 ["capsule","my", undefined, undefined]가 되어 부분 매칭에서 누락될 수 있습니다. 접두 키 ["capsule","my"]로 무효화하는 것이 안전합니다. 이전 코멘트와 동일한 이슈로, 여기 한 군데만 처리 남아 있습니다.

적용 diff:

-      queryClient.invalidateQueries({ queryKey: capsuleQueryKeys.my() });
+      queryClient.invalidateQueries({ queryKey: ["capsule", "my"] });

아래 스크립트로 레포 전반에 남아있는 invalidateQueries({ queryKey: capsuleQueryKeys.my() }) 사용을 점검해 주세요.

#!/bin/bash
# 남은 my() 무효화 호출 탐지
rg -nP -C2 --type ts --type tsx 'invalidateQueries\(\s*\{\s*queryKey:\s*capsuleQueryKeys\.my\(\s*\)\s*\}\s*\)'

# my() 호출 전반(정렬/필터 인자 전달 여부 확인용)
rg -nP -C1 --type ts --type tsx '\bcapsuleQueryKeys\.my\s*\('
🧹 Nitpick comments (1)
shared/api/mutations/capsule.ts (1)

38-41: (선택) detail 키 스키마에 세그먼트 추가 제안

현재 capsuleQueryKeys.detail(id)["capsule", id] 형태입니다(queries/capsule.ts 참조). 충돌 가능성은 낮지만, 키 충돌/접두 무효화 오작동 방지를 위해 ["capsule","detail", id]처럼 세그먼트를 명시하는 것을 권장합니다. 전역적으로 바꾸는 작업이므로 범위가 크다면 스코프를 분리해 진행해 주세요.

예시:

// shared/api/queries/capsule.ts
export const capsuleQueryKeys = {
  all: () => ["capsule"],
  detail: (id: string) => ["capsule", "detail", id],
  // ...
};

이 파일의 무효화 코드는 그대로 동작합니다(함수 호출부는 동일).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ca67b0b and c7cb61b.

📒 Files selected for processing (1)
  • shared/api/mutations/capsule.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
shared/api/mutations/capsule.ts (1)
shared/api/queries/capsule.ts (1)
  • capsuleQueryKeys (14-34)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: deploy
  • GitHub Check: test
🔇 Additional comments (3)
shared/api/mutations/capsule.ts (3)

34-35: 좋아요 토글 mutationFn이 id 반환: onSuccess 연동 명확

onSuccess에서 바로 id를 받을 수 있어 후속 무효화가 깔끔해졌습니다. 타입 추론도 자연스럽게 맞습니다.


36-42: detail(id) + ['capsule','my'] 병렬 무효화 적절

Promise.all로 동시 처리한 점 좋습니다. 필요한 범위만 갱신하여 불필요한 네트워크 요청을 줄입니다.


53-59: leave 성공 시 my + detail 동시 무효화: 이전 피드백 반영 완료

탈퇴 후 상세 화면과 내 목록의 상태 불일치가 해소됩니다. 병렬 처리로 성능 영향도 최소화되어 좋습니다.

@github-actions
Copy link
Copy Markdown

This pull request (commit 498afc5) has been deployed to Vercel ▲ - View GitHub Actions Workflow Logs

Name Link
🌐 Unique https://time-capsule-39khnh3hy-hs-projects-b4a69d5f.vercel.app
🔍 Inspect https://vercel.com/hs-projects-b4a69d5f/time-capsule/jHvMn4ippmihX1veBMpdrXPcGnjS

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
shared/api/mutations/capsule.ts (2)

34-42: 좋은 세분화 + 동시 무효화입니다. 추가로 onSettled 전환/낙관적 업데이트 고려해 보세요

  • 현재 구현은 detail(id)와 ["capsule","my"]를 함께 무효화해 일관성을 보장합니다. 동작상 문제 없습니다.
  • 선택 사항:
    • 실패/취소 케이스에서도 최신화를 보장하려면 onSuccess 대신 onSettled로 옮기면 안전합니다.
    • UX 향상을 위해 낙관적 업데이트(onMutate/onError 롤백)를 적용하면 토글 즉시 반영됩니다.

소폭 변경안(onSettled 전환):

-    onSuccess: async (id: string) => {
-      await Promise.all([
-        queryClient.invalidateQueries({
-          queryKey: capsuleQueryKeys.detail(id),
-        }),
-        queryClient.invalidateQueries({ queryKey: ["capsule", "my"] }),
-      ]);
-    },
+    onSettled: async (data) => {
+      const id = data as string | undefined;
+      if (!id) return;
+      await Promise.all([
+        queryClient.invalidateQueries({ queryKey: capsuleQueryKeys.detail(id) }),
+        queryClient.invalidateQueries({ queryKey: ["capsule", "my"] }),
+      ]);
+    },

추가 확인:

  • 캡슐 목록 화면(예: lists/searchList)이 “좋아요 수/상태”를 노출한다면 해당 키도 함께 무효화하거나, 목록에 대해서만 가벼운 낙관적 업데이트를 적용할지 검토해 주세요.

20-20: 매직 스트링 제거: 공통 접두 키 헬퍼로 일관성 강화

세 곳에서 ["capsule","my"] 리터럴이 반복됩니다. query key 정의부에 접두 키 헬퍼를 추가하면 오타/리팩터 시 안전합니다.

적용 제안:

  • shared/api/queries/capsule.ts에 헬퍼 추가
// 추가 제안
myPrefix: () => [...capsuleQueryKeys.all(), "my"],
  • 본 파일에서 사용처 교체
-      queryClient.invalidateQueries({ queryKey: ["capsule", "my"] });
+      queryClient.invalidateQueries({ queryKey: capsuleQueryKeys.myPrefix() });
-        queryClient.invalidateQueries({ queryKey: ["capsule", "my"] }),
+        queryClient.invalidateQueries({ queryKey: capsuleQueryKeys.myPrefix() }),
-        queryClient.invalidateQueries({ queryKey: ["capsule", "my"] }),
+        queryClient.invalidateQueries({ queryKey: capsuleQueryKeys.myPrefix() }),

Also applies to: 41-41, 55-55

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c7cb61b and 498afc5.

📒 Files selected for processing (1)
  • shared/api/mutations/capsule.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
shared/api/mutations/capsule.ts (1)
shared/api/queries/capsule.ts (1)
  • capsuleQueryKeys (14-34)
🔇 Additional comments (2)
shared/api/mutations/capsule.ts (2)

20-20: my 쿼리 접두 키로 세분화 무효화한 점 좋습니다

["capsule","my"] 접두 키로만 무효화해 불필요한 refetch를 줄인 결정이 유효합니다. 이전에 논의된 undefined 꼬리 요소 이슈도 회피됩니다.


53-59: leave 이후 detail + my 동시 무효화는 타당합니다. 목록/검색 화면 영향 범위 점검 권장

  • 현재 구현으로 상세/내 목록의 정합성은 보장됩니다.
  • 다만, “탈퇴”가 공개 목록(lists)이나 검색(searchList)의 참여자 수/상태 표시에 영향을 준다면 해당 접두 키도 함께 무효화가 필요할 수 있습니다. 영향 범위를 한번 짚어 주세요.

Copy link
Copy Markdown
Member

@seung365 seung365 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다~👍

@seueooo seueooo merged commit 43f93f1 into develop Aug 22, 2025
10 checks passed
@seueooo seueooo deleted the feat/home-api/#194 branch August 22, 2025 13:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: 홈 api 연결

2 participants