Conversation
📝 WalkthroughWalkthrough방 관련 API/타입/훅/UI와 전역 CSS 추가, ApiError/axios 에러 파싱 변경 및 관련 훅들의 에러 타입 정비가 적용되었습니다. 일부 버튼에 cursor 스타일이 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as CreateRoomTest
participant Hook as useCreateRoom
participant Query as ReactQuery
participant API as axiosInstance
participant Server
User->>UI: 폼 제출 (title, password?, tags?)
UI->>Hook: mutate(payload)
Hook->>Query: mutation 실행
Query->>API: POST /api/v1/rooms (payload)
API->>Server: 요청 전달
Server-->>API: 응답 (Location 헤더 포함 or 에러 body)
alt 성공 (Location 헤더 존재)
API-->>Query: 정상 응답, Location -> slug
Query->>Hook: 성공 결과 반환
Hook->>Query: invalidateQueries(["rooms"])
Hook-->>UI: result (slug)
UI->>User: 라우팅/성공 표시
else 실패 / 백엔드 에러
API-->>Query: 에러 응답
API->>Hook: ApiError({status, message, code?})
Hook-->>UI: 에러 상태
UI->>User: 에러 표시
end
sequenceDiagram
participant Browser
participant Page as test/page
participant Hook as useRoomsQuery
participant Query as ReactQuery
participant API as axiosInstance
participant Server
Browser->>Page: 페이지 렌더링
Page->>Hook: useRoomsQuery() 호출
Hook->>Query: useQuery(["rooms"], fetchRooms)
Query->>API: GET /api/v1/rooms
API->>Server: 요청 전달
Server-->>API: rooms 데이터 응답
API-->>Query: 응답 파싱 -> RoomsResponse
Query-->>Hook: data 반환
Hook-->>Page: RoomsResponse 전달
Page->>Browser: 방 목록 렌더링
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used📓 Path-based instructions (2)**/*⚙️ CodeRabbit configuration file
Files:
src/app/**/*.ts*⚙️ CodeRabbit configuration file
Files:
🔇 Additional comments (2)
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 |
There was a problem hiding this comment.
Actionable comments posted: 6
♻️ Duplicate comments (1)
src/entities/room/api/fetchTags.ts (1)
4-4: 공통 타입 중복 정의 (createRoom.ts와 동일)
ApiResponse<T>타입이createRoom.ts와 중복 정의되어 있습니다.src/entities/room/api/createRoom.ts에 남긴 리뷰 코멘트를 참고하여 공통 타입으로 추출하세요.
🧹 Nitpick comments (14)
src/features/auth/login-with-google/ui/googleLoginButton.tsx (1)
7-10: 불필요한 익명 함수 제거 권장
onClick={() => redirectToGoogleLogin()}는 매 렌더마다 새로운 함수 참조를 생성합니다. 현재는 로컬 onClick이므로 성능 영향은 미미하지만,onClick={redirectToGoogleLogin}형태로 직접 전달하는 것이 더 간결하고 일관된 패턴입니다.🔎 제안하는 개선안
<button className="border cursor-pointer mx-2" - onClick={() => redirectToGoogleLogin()} + onClick={redirectToGoogleLogin} >src/features/auth/logout/ui/logoutButton.tsx (1)
9-13: 불필요한 익명 함수 제거 권장
onClick={() => logout()}는 매 렌더마다 새로운 함수 참조를 생성합니다.onClick={logout}형태로 직접 전달하는 것이 더 간결합니다.🔎 제안하는 개선안
<button className="border cursor-pointer" - onClick={() => logout()} + onClick={logout} disabled={isPending} >src/features/room/create/model/useCreateRoom.ts (1)
13-14: 불필요한 async 제거 권장
qc.invalidateQueries는 이미 Promise를 반환하므로onSuccess를async로 선언하고await할 필요가 없습니다. React Query가 자동으로 처리합니다.🔎 제안하는 개선안
- onSuccess: async () => { - await qc.invalidateQueries({ queryKey: ["rooms"] }); + onSuccess: () => { + qc.invalidateQueries({ queryKey: ["rooms"] }); // TODO: room으로 이동 },src/entities/room/api/types.ts (1)
1-5: 타입 정의 적절함
CreateRoomPayload타입 정의는 명확하고 적절합니다.다만, 코딩 가이드라인("API 모듈은 DTO 타입 + 네트워크 호출 + toDomain 매핑까지 책임")에 따라 향후 API 응답 타입(예:
CreateRoomResponse,Room)도 이 파일 또는 별도의 domain model 파일(src/entities/room/model/types.ts)에 정의하는 것을 권장합니다.src/entities/room/api/fetchRooms.ts (1)
6-11: API 응답을 도메인 모델로 변환하는 매핑 레이어 추가 고려코딩 가이드라인에 따르면 "API 모듈은 DTO 타입 + 네트워크 호출 + toDomain 매핑까지 책임지는 구조를 우선 권장"합니다. 현재는 API 응답을 그대로 반환하고 있는데, 만약 서버 응답 형식(예: 날짜 문자열 → Date 객체 변환, 필드명 변경 등)과 클라이언트 도메인 모델 간 차이가 있다면 이 계층에서 변환을 처리하는 것이 좋습니다.
현재 구조가 간단하다면 문제없지만, 향후 API 스펙 변경 시 UI 레이어까지 영향을 최소화하려면 매핑 함수를 고려해보세요.
Based on coding guidelines: "API 모듈은 DTO 타입 + 네트워크 호출 + toDomain 매핑까지 책임"
src/app/test/page.tsx (1)
20-23: 병렬 데이터 페칭 최적화 가능 (선택 사항)각 컴포넌트(
IsLogin,RoomTags,CreateRoomTest,RoomsListTest)가 독립적으로 데이터를 페칭하므로, React Query가 자동으로 병렬 처리하겠지만 초기 마운트 시 약간의 waterfall이 발생할 수 있습니다.테스트 페이지이므로 현재 구조로 충분하지만, 프로덕션 페이지에서는 다음을 고려할 수 있습니다:
- Next.js App Router의 서버 컴포넌트에서 데이터를 병렬로 prefetch
- 또는 React Query의
prefetchQuery를 활용한 초기 데이터 로딩src/entities/user/ui/IsLogin.tsx (1)
7-7: className에 불필요한 공백이 있습니다.
className=" text-black"에서 앞쪽 공백을 제거하세요.🔎 수정 제안
- <div className=" text-black"> + <div className="text-black">src/entities/room/model/types.ts (1)
1-18: DTO와 Domain 타입의 분리를 고려하세요.현재
model/types.ts에 정의된 타입들이 실제로는 API 응답 DTO 구조를 그대로 반영하고 있습니다 (예: 날짜를 string으로 표현). 코딩 가이드라인에 따르면, API 모듈은 DTO 타입 + 네트워크 호출 + Domain으로의 매핑까지 책임져야 합니다.다음과 같은 구조를 권장합니다:
api/types.ts: DTO 타입 정의 (서버 응답 구조)model/types.ts: Domain 타입 정의 (앱 내부에서 사용하는 정규화된 타입, 예: Date 객체)api/*.ts:toDomain매핑 함수로 DTO → Domain 변환현재는 소규모이므로 당장 분리가 필수는 아니지만, 향후 비즈니스 로직이 복잡해질 경우 DTO와 Domain의 명확한 분리가 유지보수성을 높입니다.
src/entities/room/api/createRoom.ts (1)
6-12: API 함수가 raw DTO를 반환하지 않도록 개선을 고려하세요.코딩 가이드라인에 따르면, API 모듈은 DTO → Domain 매핑까지 책임져야 하며, UI에서 raw DTO를 직접 다루지 않도록 Domain 타입을 반환해야 합니다.
현재는
boolean을 반환하고 있어 생성된 방의 정보(id, slug 등)를 즉시 활용할 수 없습니다. PR 설명에서 언급하신 것처럼, 향후 서버가 생성된 방 정보를 반환하도록 변경되면 다음과 같이 개선하세요:export async function createRoom(payload: CreateRoomPayload): Promise<Room> { const res = await axiosInstance.post<ApiResponse<RoomDTO>>("/api/v1/rooms", payload); return toDomainRoom(res.data.result); // DTO → Domain 변환 }당장은 서버 스펙 제약으로 boolean 반환이 불가피하지만, 추후 개선 시점에 참고하세요.
src/entities/room/ui/RoomTags.tsx (1)
11-11: 디버깅용 console.log를 제거하세요.프로덕션 코드에 디버깅용 console.log가 남아있습니다. 개발 중 확인이 필요하다면 개발 환경에서만 동작하도록 조건부로 처리하거나, 확인 후 제거하세요.
🔎 수정 제안
const tags = data ?? []; - console.log("roomTags data:", data); - return (src/entities/user/hooks/useMe.ts (1)
6-6:import type사용 권장
ApiError는 타입 위치에서만 사용되므로import type을 사용하면 번들 크기 최적화에 도움이 됩니다.🔎 제안된 수정
-import { ApiError } from "@/src/shared/api/api-error"; +import type { ApiError } from "@/src/shared/api/api-error";src/shared/api/parse-api-error.ts (1)
4-10:BackendErrorBody타입을 공유 타입으로 분리 고려
axiosInstance.ts에서도 동일한 백엔드 에러 구조(err.response.data.error)를 파싱하고 있습니다. 타입 정의를 한 곳에서 관리하면 일관성을 유지하기 쉽습니다.src/shared/api/axiosInstance.ts (1)
14-40: 에러 파싱 로직 통합 제안
parse-api-error.ts의toApiError함수와 거의 동일한 로직이 인터셉터에 직접 구현되어 있습니다. 유지보수성을 위해 한 곳에서 관리하는 것이 좋습니다.🔎 제안된 수정
import axios from "axios"; import { API_BASE_URL } from "./config"; -import { ApiError } from "./api-error"; +import { toApiError } from "./parse-api-error"; export const axiosInstance = axios.create({ baseURL: API_BASE_URL, withCredentials: true, headers: { Accept: "application/json" }, xsrfCookieName: "XSRF-TOKEN", xsrfHeaderName: "X-XSRF-TOKEN", withXSRFToken: true, }); axiosInstance.interceptors.response.use( (res) => res, - (err) => { - const status = err?.response?.status ?? 0; - - const backendError = err?.response?.data?.error; - const backendStatus = backendError?.statusCode; - const backendCode = backendError?.code; - const backendMessage = backendError?.message; - - const message = - backendMessage ?? - err?.response?.data?.message ?? - err?.response?.data ?? - err?.message ?? - "Unknown error"; - - const finalStatus = backendStatus ?? status; - - return Promise.reject( - new ApiError({ - status: finalStatus, - message: String(message), - code: backendCode, - }) - ); - } + (err) => Promise.reject(toApiError(err)) );src/features/room/create/ui/CreateRoomTest.tsx (1)
44-50: 비밀번호 입력 필드에type="password"누락비밀번호 필드가 일반 텍스트로 표시됩니다. 테스트 UI라도
type="password"를 사용하면 더 실제 사용 환경과 유사합니다.🔎 제안된 수정
<input + type="password" className="border px-2 py-1 w-full" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="1234" disabled={isPending} />
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (23)
src/app/layout.tsxsrc/app/test/page.tsxsrc/entities/room/api/createRoom.tssrc/entities/room/api/fetchRooms.tssrc/entities/room/api/fetchTags.tssrc/entities/room/api/types.tssrc/entities/room/hooks/useFetchRooms.tssrc/entities/room/hooks/useRoomTags.tssrc/entities/room/model/types.tssrc/entities/room/ui/RoomListTest.tsxsrc/entities/room/ui/RoomTags.tsxsrc/entities/user/hooks/useMe.tssrc/entities/user/ui/IsLogin.tsxsrc/features/auth/login-with-google/ui/googleLoginButton.tsxsrc/features/auth/logout/ui/logoutButton.tsxsrc/features/room/.gitkeepsrc/features/room/create/model/useCreateRoom.tssrc/features/room/create/ui/CreateRoomTest.tsxsrc/features/user-profile/hooks/useUpdateMe.tssrc/features/user-profile/ui/NicknameEditForm.tsxsrc/shared/api/api-error.tssrc/shared/api/axiosInstance.tssrc/shared/api/parse-api-error.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*
⚙️ CodeRabbit configuration file
**/*: - 리뷰는 한국어로 작성.
- 유지보수/확장성 관점에서 모듈 경계(의존성 방향, 책임 분리)가 적절한지 최우선으로 확인.
- 파일/함수 책임이 과도하면 응집도/결합도 기준으로 분리/통합 개선안을 제시.
- TypeScript에서 any/과도한 as 캐스팅을 지양하고, 도메인 타입(예: ProfileId 같은 ID 타입)으로 의미를 드러내는지 확인.
- React에서 상태 위치 미스, 불필요한 리렌더링, derived state 남발, useEffect 남용을 지적하고 개선안을 제시.
Files:
src/entities/room/model/types.tssrc/features/auth/login-with-google/ui/googleLoginButton.tsxsrc/shared/api/parse-api-error.tssrc/entities/room/api/createRoom.tssrc/features/user-profile/ui/NicknameEditForm.tsxsrc/entities/room/ui/RoomTags.tsxsrc/entities/room/api/fetchRooms.tssrc/entities/room/hooks/useRoomTags.tssrc/entities/user/ui/IsLogin.tsxsrc/entities/user/hooks/useMe.tssrc/app/test/page.tsxsrc/features/room/create/ui/CreateRoomTest.tsxsrc/entities/room/hooks/useFetchRooms.tssrc/entities/room/ui/RoomListTest.tsxsrc/entities/room/api/types.tssrc/features/auth/logout/ui/logoutButton.tsxsrc/features/user-profile/hooks/useUpdateMe.tssrc/app/layout.tsxsrc/shared/api/axiosInstance.tssrc/features/room/create/model/useCreateRoom.tssrc/entities/room/api/fetchTags.tssrc/shared/api/api-error.ts
**/ui/**/*.tsx
⚙️ CodeRabbit configuration file
**/ui/**/*.tsx: - 상태 위치가 적절한지(상/하위 이동 필요성) 지적하고 개선안 제시.
- 파생 값은 state로 두지 말고 계산(useMemo는 필요할 때만).
- 리스트 key 안정성, 불필요한 re-render 유발 props(익명 함수/객체) 지적.
Files:
src/features/auth/login-with-google/ui/googleLoginButton.tsxsrc/features/user-profile/ui/NicknameEditForm.tsxsrc/entities/room/ui/RoomTags.tsxsrc/entities/user/ui/IsLogin.tsxsrc/features/room/create/ui/CreateRoomTest.tsxsrc/entities/room/ui/RoomListTest.tsxsrc/features/auth/logout/ui/logoutButton.tsx
**/api/**/*.ts*
⚙️ CodeRabbit configuration file
**/api/**/*.ts*: - API 모듈은 DTO 타입 + 네트워크 호출 + toDomain 매핑까지 책임지는 구조를 우선 권장.
- UI에서 raw DTO(res.json())를 직접 다루지 않도록, 반환 타입은 Domain(User 등)으로 정규화.
- fetch 옵션(credentials, headers 등) 규약이 일관적인지 확인.
Files:
src/shared/api/parse-api-error.tssrc/entities/room/api/createRoom.tssrc/entities/room/api/fetchRooms.tssrc/entities/room/api/types.tssrc/shared/api/axiosInstance.tssrc/entities/room/api/fetchTags.tssrc/shared/api/api-error.ts
src/app/**/*.ts*
⚙️ CodeRabbit configuration file
src/app/**/*.ts*: - Next.js App Router 규칙 준수: server/client 컴포넌트 경계가 적절한지 확인.
- 가능하면 데이터 패칭은 async 서버 컴포넌트/route handler에서 처리하고, 클라에서 불필요한 fetch/useEffect를 줄일 것.
- "use client"는 꼭 필요한 곳에만.
Files:
src/app/test/page.tsxsrc/app/layout.tsx
🧬 Code graph analysis (16)
src/features/auth/login-with-google/ui/googleLoginButton.tsx (1)
src/features/auth/login-with-google/api/login.ts (1)
redirectToGoogleLogin(3-18)
src/shared/api/parse-api-error.ts (1)
src/shared/api/api-error.ts (1)
ApiError(1-11)
src/entities/room/api/createRoom.ts (2)
src/entities/room/api/types.ts (1)
CreateRoomPayload(1-5)src/shared/api/axiosInstance.ts (1)
axiosInstance(5-12)
src/entities/room/ui/RoomTags.tsx (1)
src/entities/room/hooks/useRoomTags.ts (1)
useRoomTags(4-11)
src/entities/room/api/fetchRooms.ts (2)
src/entities/room/model/types.ts (1)
RoomsResponse(15-18)src/shared/api/axiosInstance.ts (1)
axiosInstance(5-12)
src/entities/room/hooks/useRoomTags.ts (1)
src/entities/room/api/fetchTags.ts (1)
fetchRoomTags(6-12)
src/entities/user/ui/IsLogin.tsx (1)
src/entities/user/hooks/useMe.ts (1)
useMe(8-15)
src/entities/user/hooks/useMe.ts (2)
src/entities/user/model/types.ts (1)
User(1-5)src/shared/api/api-error.ts (1)
ApiError(1-11)
src/app/test/page.tsx (3)
src/entities/user/ui/IsLogin.tsx (1)
IsLogin(3-21)src/entities/room/ui/RoomTags.tsx (1)
RoomTags(3-22)src/features/room/create/ui/CreateRoomTest.tsx (1)
CreateRoomTest(6-85)
src/features/room/create/ui/CreateRoomTest.tsx (1)
src/features/room/create/model/useCreateRoom.ts (1)
useCreateRoom(8-18)
src/entities/room/hooks/useFetchRooms.ts (3)
src/entities/room/model/types.ts (1)
RoomsResponse(15-18)src/shared/api/api-error.ts (1)
ApiError(1-11)src/entities/room/api/fetchRooms.ts (1)
fetchRooms(6-11)
src/entities/room/ui/RoomListTest.tsx (1)
src/entities/room/hooks/useFetchRooms.ts (1)
useRoomsQuery(8-14)
src/features/user-profile/hooks/useUpdateMe.ts (4)
src/entities/user/model/types.ts (1)
User(1-5)src/shared/api/api-error.ts (1)
ApiError(1-11)src/features/user-profile/model/types.ts (1)
UpdateMePayload(1-4)src/features/user-profile/api/updateMe.ts (1)
updateMe(7-13)
src/shared/api/axiosInstance.ts (1)
src/shared/api/api-error.ts (1)
ApiError(1-11)
src/features/room/create/model/useCreateRoom.ts (3)
src/shared/api/api-error.ts (1)
ApiError(1-11)src/entities/room/api/types.ts (1)
CreateRoomPayload(1-5)src/entities/room/api/createRoom.ts (1)
createRoom(6-12)
src/entities/room/api/fetchTags.ts (2)
src/entities/room/model/types.ts (1)
RoomTag(1-4)src/shared/api/axiosInstance.ts (1)
axiosInstance(5-12)
🔇 Additional comments (9)
src/app/layout.tsx (1)
3-3: 전역 스타일 임포트 적절함루트 레이아웃에서
globals.css를 임포트하는 것은 Next.js의 표준 패턴입니다. 앱 전체에 전역 스타일을 적용하기에 적절한 위치입니다.src/entities/room/hooks/useRoomTags.ts (1)
4-11: LGTM - React Query 설정 적절함React Query 훅 구현이 깔끔합니다.
staleTime: 5분,retry: false설정은 태그 데이터가 자주 변경되지 않는다는 가정 하에 적절해 보입니다.다만 향후 참고사항:
- 태그 데이터가 실시간으로 변경되어야 한다면
staleTime을 줄이거나 invalidation 전략을 검토해주세요.retry: false로 설정한 이유가 명확하다면(예: 태그 로딩 실패 시 즉시 에러 표시) 현재 설정이 적합합니다.src/entities/room/ui/RoomListTest.tsx (1)
5-53: LGTM - 깔끔한 컴포넌트 구현방 목록 렌더링 컴포넌트가 잘 구현되었습니다:
✅ 로딩/에러/빈 목록 상태를 모두 처리
✅room.id를 key로 사용하여 안정적인 렌더링
✅ Optional chaining(data?.rooms,room.tags?.length)으로 안전한 접근
✅ 조건부 렌더링이 명확함src/features/user-profile/ui/NicknameEditForm.tsx (1)
39-43: 타입 검증 완료 - 에러 표시 방식이 정확합니다
useUpdateMe훅이useMutation<User, ApiError, UpdateMePayload>를 반환하며,ApiError클래스에status속성(number)이 명시적으로 정의되어 있고message는 Error 클래스에서 상속됩니다. 따라서 lines 39-43의error.status와error.message참조는 타입 안전하며 추가 개선이 필요하지 않습니다.src/entities/user/hooks/useMe.ts (1)
8-14: LGTM!
useQuery에ApiError타입을 명시하여 에러 핸들링 일관성이 개선되었습니다.staleTime: 0과retry: false설정도 사용자 인증 정보에 적합합니다.src/features/user-profile/hooks/useUpdateMe.ts (1)
9-17: LGTM!
useMutation에 제네릭 타입(User,ApiError,UpdateMePayload)이 명시되어 타입 안전성이 향상되었습니다.invalidateQueries를 통한 캐시 무효화 로직도 적절합니다.src/entities/room/hooks/useFetchRooms.ts (1)
8-14: LGTM!React Query 훅 패턴이 다른 훅들과 일관성있게 구현되었습니다.
RoomsResponse에hasNext필드가 있으므로, 향후 페이지네이션 구현 시queryKey에 파라미터를 추가하고fetchRooms에 인자를 전달하는 형태로 확장하면 됩니다.src/features/room/create/ui/CreateRoomTest.tsx (1)
6-84: 테스트 UI 구현 LGTM테스트 목적의 컴포넌트로서 적절하게 구현되었습니다.
isPending상태를 활용한 UI 피드백과 에러 표시 로직이 잘 작성되어 있습니다.src/shared/api/api-error.ts (1)
1-11: LGTM!객체 파라미터 패턴을 사용하여 확장성이 좋고,
name속성을 명시적으로 설정하여 에러 식별이 용이합니다. 백엔드 에러 코드(code)를 선택적으로 포함할 수 있어 디버깅에 유용합니다.
| slug: string; | ||
| title: string; | ||
| isPrivate: boolean; | ||
| createAt: string; |
There was a problem hiding this comment.
필드명 오타를 수정하세요.
createAt은 createdAt의 오타로 보입니다. 서버 API 응답 스펙을 확인하고 올바른 필드명으로 수정하세요.
🔎 수정 제안
- createAt: string;
+ createdAt: string;📝 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.
| createAt: string; | |
| createdAt: string; |
🤖 Prompt for AI Agents
In src/entities/room/model/types.ts around line 11, the property name createAt
is a typo and should be renamed to createdAt to match the server API spec;
update the TypeScript type/interface to use createdAt, update any usages/imports
in the module to the new name, and run type checks to ensure no remaining
references to createAt remain.
| import { UpdateMePayload } from "../model/types"; | ||
| import type { UpdateMePayload } from "../model/types"; | ||
| import type { ApiError } from "@/src/shared/api/api-error"; | ||
| import type { User } from "@/src/entities/user/model/types"; // 너 프로젝트 User 타입 경로에 맞게 |
There was a problem hiding this comment.
불필요한 주석 제거 필요
개발 중 작성된 메모("너 프로젝트 User 타입 경로에 맞게")가 남아있습니다. 코드 정리 시 제거해주세요.
🔎 제안된 수정
-import type { User } from "@/src/entities/user/model/types"; // 너 프로젝트 User 타입 경로에 맞게
+import type { User } from "@/src/entities/user/model/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.
| import type { User } from "@/src/entities/user/model/types"; // 너 프로젝트 User 타입 경로에 맞게 | |
| import type { User } from "@/src/entities/user/model/types"; |
🤖 Prompt for AI Agents
In src/features/user-profile/hooks/useUpdateMe.ts around line 7, remove the
leftover inline comment "너 프로젝트 User 타입 경로에 맞게" from the import line so the
import reads cleanly; ensure only the necessary import remains (import type {
User } from "@/src/entities/user/model/types") with no trailing developer note
or comment, and run a quick lint/format to confirm no trailing whitespace.
| export function toApiError(err: unknown): ApiError { | ||
| // axios 에러인 경우 (백엔드 응답 파싱) | ||
| if (axios.isAxiosError(err)) { | ||
| const status = err.response?.status ?? 0; | ||
| const data = err.response?.data as BackendErrorBody | undefined; | ||
|
|
||
| const backend = data?.error; | ||
|
|
||
| // 백엔드 포맷이 있는 경우 | ||
| if (backend?.statusCode && backend?.message) { | ||
| return new ApiError({ | ||
| status: backend.statusCode, | ||
| code: backend.code, | ||
| message: backend.message, | ||
| }); | ||
| } | ||
|
|
||
| // 백엔드 포맷이 없을 때 (nginx, html, 네트워크 등) | ||
| return new ApiError({ | ||
| status, | ||
| message: err.message || "요청 중 오류가 발생했어요.", | ||
| }); | ||
| } | ||
|
|
||
| // 그 외 알 수 없는 에러 | ||
| return new ApiError({ | ||
| status: 0, | ||
| message: "알 수 없는 오류가 발생했어요.", | ||
| }); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n "toApiError" --type tsRepository: Queuing-org/front-end
Length of output: 154
🏁 Script executed:
fd -name "axiosInstance.ts" -o -name "axios*.ts" | head -20Repository: Queuing-org/front-end
Length of output: 295
🏁 Script executed:
rg -n "response interceptor|\.interceptors\.response" --type ts -A 10 | head -100Repository: Queuing-org/front-end
Length of output: 787
🏁 Script executed:
wc -l src/shared/api/axiosInstance.tsRepository: Queuing-org/front-end
Length of output: 99
🏁 Script executed:
cat -n src/shared/api/axiosInstance.tsRepository: Queuing-org/front-end
Length of output: 1377
🏁 Script executed:
rg -n "parse-api-error" --type tsRepository: Queuing-org/front-end
Length of output: 47
toApiError 함수는 사용되지 않는 데드 코드입니다. 제거하세요.
전체 코드베이스에서 toApiError 함수는 어디서도 import되거나 호출되지 않습니다. axiosInstance.ts의 response interceptor (14-41줄)가 이미 모든 axios 에러를 ApiError로 변환하여 처리하고 있으므로, 이 함수는 제거해도 문제없습니다.
🤖 Prompt for AI Agents
In src/shared/api/parse-api-error.ts around lines 12 to 41, the toApiError
function is dead code and should be removed; delete the entire function (and its
export) and then remove any now-unused imports or type references in this file,
run a repo-wide search to confirm there are no remaining references, and run
tests/build to ensure nothing else depends on it.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/features/room/join/JoinRoomButton.tsx (1)
1-20: LGTM! 단순하고 명확한 구현입니다.컴포넌트의 책임이 명확하고(방 입장 네비게이션),
features/room/join경로에 위치하여 도메인 구조도 적절합니다."use client"는useRouter와onClick핸들러 사용으로 인해 필요합니다.선택적 개선: 접근성 및 국제화 고려사항
향후 확장 시 다음 사항을 고려할 수 있습니다:
- 접근성 개선: 스크린 리더 사용자를 위한 aria-label 추가
- 국제화: 하드코딩된 "방 입장하기" 텍스트를 i18n 시스템으로 관리
export default function JoinRoomButton({ slug }: Props) { const router = useRouter(); return ( <button className="border cursor-pointer" onClick={() => router.push(`/room/${slug}`)} + aria-label={`${slug} 방 입장하기`} > 방 입장하기 </button> ); }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
src/app/room/[slug]/page.tsxsrc/entities/room/api/createRoom.tssrc/entities/room/api/fetchRooms.tssrc/entities/room/api/fetchTags.tssrc/entities/room/api/types.tssrc/entities/room/model/types.tssrc/entities/room/ui/RoomListTest.tsxsrc/entities/user/api/me.tssrc/entities/user/api/onboarding.tssrc/features/room/create/model/useCreateRoom.tssrc/features/room/join/JoinRoomButton.tsxsrc/features/user-profile/api/updateMe.tssrc/shared/api/types.ts
🚧 Files skipped from review as they are similar to previous changes (6)
- src/entities/room/api/fetchTags.ts
- src/entities/room/api/fetchRooms.ts
- src/entities/room/ui/RoomListTest.tsx
- src/entities/room/api/types.ts
- src/entities/room/api/createRoom.ts
- src/entities/room/model/types.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*
⚙️ CodeRabbit configuration file
**/*: - 리뷰는 한국어로 작성.
- 유지보수/확장성 관점에서 모듈 경계(의존성 방향, 책임 분리)가 적절한지 최우선으로 확인.
- 파일/함수 책임이 과도하면 응집도/결합도 기준으로 분리/통합 개선안을 제시.
- TypeScript에서 any/과도한 as 캐스팅을 지양하고, 도메인 타입(예: ProfileId 같은 ID 타입)으로 의미를 드러내는지 확인.
- React에서 상태 위치 미스, 불필요한 리렌더링, derived state 남발, useEffect 남용을 지적하고 개선안을 제시.
Files:
src/features/room/create/model/useCreateRoom.tssrc/app/room/[slug]/page.tsxsrc/shared/api/types.tssrc/features/user-profile/api/updateMe.tssrc/features/room/join/JoinRoomButton.tsxsrc/entities/user/api/onboarding.tssrc/entities/user/api/me.ts
src/app/**/*.ts*
⚙️ CodeRabbit configuration file
src/app/**/*.ts*: - Next.js App Router 규칙 준수: server/client 컴포넌트 경계가 적절한지 확인.
- 가능하면 데이터 패칭은 async 서버 컴포넌트/route handler에서 처리하고, 클라에서 불필요한 fetch/useEffect를 줄일 것.
- "use client"는 꼭 필요한 곳에만.
Files:
src/app/room/[slug]/page.tsx
**/api/**/*.ts*
⚙️ CodeRabbit configuration file
**/api/**/*.ts*: - API 모듈은 DTO 타입 + 네트워크 호출 + toDomain 매핑까지 책임지는 구조를 우선 권장.
- UI에서 raw DTO(res.json())를 직접 다루지 않도록, 반환 타입은 Domain(User 등)으로 정규화.
- fetch 옵션(credentials, headers 등) 규약이 일관적인지 확인.
Files:
src/shared/api/types.tssrc/features/user-profile/api/updateMe.tssrc/entities/user/api/onboarding.tssrc/entities/user/api/me.ts
🧬 Code graph analysis (1)
src/features/room/create/model/useCreateRoom.ts (3)
src/entities/room/api/types.ts (2)
CreateRoomResult(7-9)CreateRoomPayload(1-5)src/shared/api/api-error.ts (1)
ApiError(1-11)src/entities/room/api/createRoom.ts (1)
createRoom(6-24)
🔇 Additional comments (6)
src/shared/api/types.ts (1)
1-1: 타입 중앙화 LGTM!
ApiResponse<T>타입을 공유 모듈로 추출하여 여러 API 모듈에서 중복 정의를 제거한 것은 좋은 리팩토링입니다. 타입의 일관성을 유지하고 유지보수성을 높였습니다.src/entities/user/api/onboarding.ts (1)
3-3: 공유 타입 사용 LGTM!로컬 타입 정의를 제거하고 중앙 집중식
ApiResponse타입을 사용하도록 변경한 것은 적절합니다.src/entities/user/api/me.ts (1)
4-4: 공유 타입 사용 LGTM!중앙 집중식
ApiResponse타입을 사용하도록 변경한 것은 적절하며, 도메인 타입(User)을 반환하여 가이드라인을 준수하고 있습니다.src/features/room/create/model/useCreateRoom.ts (2)
16-22: 도메인 타입 반환 개선 확인됨!이전 리뷰에서 지적된
boolean반환 타입 문제가 해결되었습니다. 이제CreateRoomResult도메인 타입을 반환하고slug를 사용하여 생성된 방으로 정상적으로 라우팅합니다. 코딩 가이드라인의 "반환 타입은 Domain으로 정규화" 요구사항을 충족합니다.
20-20: 라우팅 경로는 올바르게 구현되어 있습니다프로젝트의 Next.js App Router 구조에서
src/app/room/[slug]/page.tsx가 존재하므로, 현재 코드의/room/${result.slug}경로는 적절합니다. 추가 수정이 필요하지 않습니다.Likely an incorrect or invalid review comment.
src/features/user-profile/api/updateMe.ts (1)
4-4: 공유 타입 사용 LGTM!중앙 집중식
ApiResponse타입을 사용하도록 변경한 것은 적절하며, 도메인 타입(User)을 반환하여 API 모듈 가이드라인을 준수하고 있습니다.
| "use client"; | ||
|
|
||
| import { useParams } from "next/navigation"; | ||
|
|
||
| export default function RoomPage() { | ||
| const params = useParams<{ slug: string }>(); | ||
|
|
||
| return <div>room: {params.slug}</div>; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
불필요한 클라이언트 컴포넌트 - 서버 컴포넌트로 전환 필요
이 페이지는 클라이언트 인터랙션(상태, 이벤트 핸들러 등)이 없으므로 "use client"가 불필요합니다. Next.js 15+ (현재 16.1.1 사용 중)에서는 페이지 컴포넌트가 params를 프로미스 prop으로 직접 받으며, 서버 컴포넌트로 구현하는 것이 권장됩니다.
코딩 가이드라인에 따르면:
- "use client는 꼭 필요한 곳에만"
- "가능하면 데이터 패칭은 async 서버 컴포넌트/route handler에서 처리"
향후 이 페이지에서 방 데이터를 패칭할 경우, 서버 컴포넌트에서 직접 처리하면 초기 로딩 성능과 SEO에 유리합니다.
🔎 Next.js 15+ 서버 컴포넌트 패턴으로 리팩토링
Next.js 15+ 문서 및 라이브러리 정보 기반 제안:
-"use client";
-
-import { useParams } from "next/navigation";
-
-export default function RoomPage() {
- const params = useParams<{ slug: string }>();
+type Props = {
+ params: Promise<{ slug: string }>;
+};
+
+export default async function RoomPage({ params }: Props) {
+ const { slug } = await params;
- return <div>room: {params.slug}</div>;
+ return <div>room: {slug}</div>;
}장점:
- 서버에서 렌더링되어 초기 로딩 속도 향상
- 향후 서버 측 데이터 패칭 추가 시 별도의 API 요청 불필요
- SEO 최적화에 유리
- Next.js App Router 권장 패턴 준수
🤖 Prompt for AI Agents
In src/app/room/[slug]/page.tsx lines 1-9: this file is marked "use client" but
has no client-side state or handlers, so remove the "use client" directive and
convert the component to a server component that accepts params from Next.js.
Replace useParams usage by defining an async (or sync) page function that
receives { params } prop, extract params.slug, and return the same JSX; also
remove the import of useParams. Keep the component as a default export and
ensure it uses the server-component signature so future server-side data
fetching can be added.
Title
feat(room): 방 생성/조회/태그 조회 API 및 React Query 훅 추가
Summary
방 생성(createRoom), 방 목록 조회(fetchRooms), 태그 목록 조회(fetchRoomTags) API 함수 추가
React Query 기반 useCreateRoom/useRoomsQuery/useRoomTagsQuery 훅 구현 및 캐시 무효화(invalidate) 적용
기능 확인을 위한 테스트 UI(태그 렌더링, 방 목록 렌더링, 방 생성 폼) 추가
Notes
createRoom 응답이 boolean(result: true/false) 기준으로 구현되어 있어, 추후 방 id/slug 반환으로 바뀌면 생성 성공 후 room으로 이동 로직 추가 예정
태그 목록이 현재 서버에서 빈 배열로 내려오는 중
Summary by CodeRabbit
새로운 기능
버그 수정
스타일
✏️ Tip: You can customize this high-level summary in your review settings.