feat: 인증 및 api 클라이언트 구현 #50#61
Conversation
WalkthroughAPI 클라이언트 설정을 위한 대규모 코드 추가가 이루어졌습니다. ky 기반의 HTTP 클라이언트, 커스텀 예외 클래스, 인증 및 세션 관리, 미들웨어, 인증 관련 API 및 쿼리 훅, 상수와 타입 정의 등 다양한 모듈이 신규로 도입되었습니다. package.json에 iron-session과 ky가 의존성으로 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant NextAPI as Next.js API Route
participant Backend
participant Session
Client->>NextAPI: POST /api/auth/login (code)
NextAPI->>Backend: postLogin(code, origin)
Backend-->>NextAPI: {token, user info}
NextAPI->>Session: 세션 갱신 (accessToken, refreshToken 등)
Session-->>NextAPI: 세션 저장 완료
NextAPI-->>Client: 로그인 성공, user info 반환
Client->>NextAPI: POST /api/auth/reissue
NextAPI->>Session: 세션 조회 (refreshToken)
Session-->>NextAPI: refreshToken
NextAPI->>Backend: postReissue(refreshToken)
Backend-->>NextAPI: {accessToken, refreshToken}
NextAPI->>Session: 세션 갱신
Session-->>NextAPI: 세션 저장 완료
NextAPI-->>Client: 갱신된 세션 반환
sequenceDiagram
participant Client
participant Middleware
participant Session
participant Backend
Client->>Middleware: 요청 (protected route)
Middleware->>Session: 세션 조회
alt 로그인 안됨
Middleware-->>Client: /login으로 리다이렉트
else 로그인됨
Middleware->>Session: accessToken 만료 체크
alt 만료 임박
Middleware->>Backend: 토큰 재발급 요청
Backend-->>Middleware: 새 access/refreshToken
Middleware->>Session: 세션 갱신
Session-->>Middleware: 저장 완료
Middleware-->>Client: 요청 통과
else
Middleware-->>Client: 요청 통과
end
end
Assessment against linked issues
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
src/app/(auth)/login/callback/page.tsxOops! Something went wrong! :( ESLint: 9.27.0 ESLint couldn't find the plugin "eslint-plugin-react-hooks". (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following: The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/eslint-config-next@15.3.2_eslint@9.27.0_jiti@2.4.2__typescript@5.8.3/node_modules/eslint-config-next/index.js". If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting. src/app/(auth)/_api/auth/auth.queries.tsOops! Something went wrong! :( ESLint: 9.27.0 ESLint couldn't find the plugin "eslint-plugin-react-hooks". (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following: The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/eslint-config-next@15.3.2_eslint@9.27.0_jiti@2.4.2__typescript@5.8.3/node_modules/eslint-config-next/index.js". If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting. src/app/(auth)/_api/auth/auth.api.tsOops! Something went wrong! :( ESLint: 9.27.0 ESLint couldn't find the plugin "eslint-plugin-react-hooks". (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following: The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/eslint-config-next@15.3.2_eslint@9.27.0_jiti@2.4.2__typescript@5.8.3/node_modules/eslint-config-next/index.js". If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting.
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
🎨 Storybook Preview: https://685a32a1c0bbd269fdb67af4-bbsahtnfli.chromatic.com/ |
|
This pull request (commit
|
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (7)
src/lib/session/serverSession.ts (1)
1-4: 동적 import의 필요성을 검토해보세요.현재 구현에서 동적 import를 사용하고 있지만, 이 경우 정적 import가 더 적절할 수 있습니다. 동적 import는 주로 코드 분할이나 조건부 로딩에 사용되는데, 여기서는 단순한 래퍼 함수 역할만 하고 있습니다.
다음과 같이 정적 import로 변경하는 것을 고려해보세요:
+import { getSession } from "./session"; + -export const getSessionFromServer = async () => { - const { getSession } = await import("./session"); - return await getSession(); -}; +export const getSessionFromServer = async () => { + return await getSession(); +};src/lib/api/type.ts (1)
1-23: 파일명 컨벤션과 타입 정의 개선 권장
- 파일명을
type.ts에서types.ts로 변경하는 것이 더 관례적입니다.ApiResponse<T>타입의 유니언 구조가 성공/실패를 명확히 구분하기 어렵습니다.더 명확한 타입 정의를 위해 다음과 같이 개선할 수 있습니다:
-export type ApiResponse<T> = T | ApiError; +export type ApiResponse<T> = + | { success: true; data: T } + | { success: false; error: ApiError };또는 discriminated union을 사용하여:
-export type ApiResponse<T> = T | ApiError; +export type ApiSuccessResponse<T> = T; +export type ApiErrorResponse = ApiError; +export type ApiResponse<T> = ApiSuccessResponse<T> | ApiErrorResponse;src/app/login/callback/page.tsx (1)
42-46: 로딩 상태와 에러 상태 UI 개선현재 구현에서는 에러 상태와 로딩 상태가 분리되어 있지만, 더 나은 사용자 경험을 위해 개선할 수 있습니다.
+const { mutate: login, isError, isPending, error } = useLoginMutation(); if (isError) { - return <div>로그인 처리 중 오류가 발생했습니다.</div>; + return ( + <div> + <h2>로그인 오류</h2> + <p>로그인 처리 중 오류가 발생했습니다.</p> + <button onClick={() => router.back()}>이전 페이지로</button> + </div> + ); } -return <div>로그인 중입니다...</div>; +return ( + <div> + <h2>로그인 중...</h2> + <p>잠시만 기다려주세요.</p> + </div> +);src/lib/session/clientSession.ts (1)
24-39: 캐시 로직이 올바르게 구현되었습니다.캐시 만료 시간 확인 로직과 API 호출을 통한 세션 갱신 로직이 적절하게 구현되어 있습니다.
향후 고려사항:
getSession()API 호출 시 발생할 수 있는 네트워크 에러나 인증 실패에 대한 에러 핸들링을 추가하는 것을 고려해보세요.src/middleware.ts (2)
8-13: PUBLIC_PATHS를 별도 상수 파일로 분리하는 것을 고려하세요.유지보수성을 위해 공개 경로 목록을
@/constants폴더의 별도 파일로 관리하는 것이 좋습니다.-// 인증이 필요 없는 경로 -const PUBLIC_PATHS = ["/login", "/signup", "/public", "/login/callback"]; +import { PUBLIC_PATHS } from "@/constants/auth.constants";
55-57: 프로덕션 환경을 위한 적절한 로깅 시스템을 사용하세요.
console.info와console.error는 개발 환경에서만 사용하고, 프로덕션에서는 구조화된 로깅을 사용하는 것이 좋습니다.src/app/_api/auth/auth.api.ts (1)
44-44: 타입 정의를 간소화하세요.복잡한 타입 조작 대신 직접적인 타입 정의를 사용하는 것이 더 명확합니다.
-type Information = Omit<LoginResponse, "token">["information"]; +type Information = LoginResponse["information"];
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (25)
package.json(1 hunks)src/app/_api/auth/auth.api.ts(1 hunks)src/app/_api/auth/auth.queries.ts(1 hunks)src/app/_api/auth/auth.types.ts(1 hunks)src/app/_api/session/session.api.ts(1 hunks)src/app/_api/session/session.queries.ts(1 hunks)src/app/_api/session/session.types.ts(1 hunks)src/app/api/auth/login/route.ts(1 hunks)src/app/api/auth/reissue/route.ts(1 hunks)src/app/api/session/route.ts(1 hunks)src/app/login/callback/page.tsx(1 hunks)src/constants/index.ts(1 hunks)src/constants/time.constants.ts(1 hunks)src/lib/api/client.ts(1 hunks)src/lib/api/index.ts(1 hunks)src/lib/api/type.ts(1 hunks)src/lib/exceptions/exceptions.ts(1 hunks)src/lib/exceptions/index.ts(1 hunks)src/lib/session/clientSession.ts(1 hunks)src/lib/session/index.ts(1 hunks)src/lib/session/serverSession.ts(1 hunks)src/lib/session/session.ts(1 hunks)src/lib/session/type.ts(1 hunks)src/lib/utils/environment.ts(1 hunks)src/middleware.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
`{src/lib/utils/*.{ts,tsx},src/lib/api/*.{ts,tsx},src/app/**/_utils/*.{ts,tsx},s...
{src/lib/utils/*.{ts,tsx},src/lib/api/*.{ts,tsx},src/app/**/_utils/*.{ts,tsx},src/app/**/_api/*.{ts,tsx}}: 유틸리티 및 API 파일은 camelCase로 네이밍해야 한다 (예:domainUtils.ts,domain.api.ts).
📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)
List of files the instruction was applied to:
src/lib/api/index.tssrc/lib/utils/environment.tssrc/lib/api/type.tssrc/lib/api/client.ts
`src/lib/api/*.{ts,tsx}`: 전역 API 클라이언트 및 타입은 `lib/api/` 폴더에 위치해야 한다.
src/lib/api/*.{ts,tsx}: 전역 API 클라이언트 및 타입은lib/api/폴더에 위치해야 한다.
📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)
List of files the instruction was applied to:
src/lib/api/index.tssrc/lib/api/type.tssrc/lib/api/client.ts
`{src/constants/*.{ts,tsx},src/app/**/_constants/*.{ts,tsx}}`: 상수 파일은 camelCase로 네이밍해야 한다 (예: `domain.constants.ts`).
{src/constants/*.{ts,tsx},src/app/**/_constants/*.{ts,tsx}}: 상수 파일은 camelCase로 네이밍해야 한다 (예:domain.constants.ts).
📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)
List of files the instruction was applied to:
src/constants/time.constants.tssrc/constants/index.ts
`src/constants/*.{ts,tsx}`: 전역 상수 정의는 `constants/` 폴더에 위치해야 한다.
src/constants/*.{ts,tsx}: 전역 상수 정의는constants/폴더에 위치해야 한다.
📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)
List of files the instruction was applied to:
src/constants/time.constants.tssrc/constants/index.ts
`src/lib/utils/*.{ts,tsx}`: 전역 공통 유틸리티는 `lib/utils/` 폴더에 기능별로 분리해 위치해야 한다.
src/lib/utils/*.{ts,tsx}: 전역 공통 유틸리티는lib/utils/폴더에 기능별로 분리해 위치해야 한다.
📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)
List of files the instruction was applied to:
src/lib/utils/environment.ts
🧠 Learnings (10)
src/lib/api/index.ts (2)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/lib/api/*.{ts,tsx} : 전역 API 클라이언트 및 타입은 `lib/api/` 폴더에 위치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/app/**/_api/*.{api,queries}.ts : API 호출 관련 코드는 `_api` 폴더에 `.api.ts` (ky 사용) 및 `.queries.ts` (TanStack Query) 파일로 분리해야 한다.
src/app/_api/session/session.types.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/types/*.{ts,tsx} : 전역 타입 정의는 `types/` 폴더에 위치해야 한다.
src/app/api/session/route.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to middleware.ts : Next.js 미들웨어는 프로젝트 루트의 `middleware.ts`로 관리해야 한다.
src/lib/api/type.ts (3)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/lib/api/*.{ts,tsx} : 전역 API 클라이언트 및 타입은 `lib/api/` 폴더에 위치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/app/**/_api/*.{api,queries}.ts : API 호출 관련 코드는 `_api` 폴더에 `.api.ts` (ky 사용) 및 `.queries.ts` (TanStack Query) 파일로 분리해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/types/*.{ts,tsx} : 전역 타입 정의는 `types/` 폴더에 위치해야 한다.
src/middleware.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to middleware.ts : Next.js 미들웨어는 프로젝트 루트의 `middleware.ts`로 관리해야 한다.
src/app/_api/auth/auth.queries.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/app/**/_api/*.{api,queries}.ts : API 호출 관련 코드는 `_api` 폴더에 `.api.ts` (ky 사용) 및 `.queries.ts` (TanStack Query) 파일로 분리해야 한다.
src/lib/api/client.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/lib/api/*.{ts,tsx} : 전역 API 클라이언트 및 타입은 `lib/api/` 폴더에 위치해야 한다.
src/lib/exceptions/index.ts (4)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/lib/api/*.{ts,tsx} : 전역 API 클라이언트 및 타입은 `lib/api/` 폴더에 위치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/lib/utils/*.{ts,tsx} : 전역 공통 유틸리티는 `lib/utils/` 폴더에 기능별로 분리해 위치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/constants/*.{ts,tsx} : 전역 상수 정의는 `constants/` 폴더에 위치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/types/*.{ts,tsx} : 전역 타입 정의는 `types/` 폴더에 위치해야 한다.
src/constants/index.ts (3)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/constants/*.{ts,tsx} : 전역 상수 정의는 `constants/` 폴더에 위치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/app/**/_constants/*.{ts,tsx} : 도메인별 상수 정의는 `_constants` 폴더에 위치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to {src/constants/*.{ts,tsx},src/app/**/_constants/*.{ts,tsx}} : 상수 파일은 camelCase로 네이밍해야 한다 (예: `domain.constants.ts`).
src/app/_api/auth/auth.api.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/lib/api/*.{ts,tsx} : 전역 API 클라이언트 및 타입은 `lib/api/` 폴더에 위치해야 한다.
🧬 Code Graph Analysis (10)
src/lib/session/serverSession.ts (2)
src/lib/session/index.ts (2)
getSessionFromServer(2-2)getSession(3-3)src/lib/session/session.ts (1)
getSession(28-36)
src/lib/session/clientSession.ts (3)
src/lib/session/type.ts (1)
SessionData(1-7)src/constants/time.constants.ts (1)
TOKEN_TIMES(17-29)src/lib/session/session.ts (1)
getSession(28-36)
src/app/_api/session/session.queries.ts (1)
src/app/_api/session/session.api.ts (1)
getSession(10-12)
src/middleware.ts (2)
src/constants/time.constants.ts (1)
TOKEN_TIMES(17-29)src/app/_api/auth/auth.api.ts (1)
postReissue(28-32)
src/app/_api/auth/auth.queries.ts (1)
src/app/_api/auth/auth.api.ts (3)
postClientLogin(52-56)postClientReissue(63-65)deleteClientSession(72-74)
src/app/_api/auth/auth.api.ts (2)
src/app/_api/auth/auth.types.ts (4)
LoginRequest(1-3)LoginResponse(5-14)ReissueRequest(16-18)ReissueResponse(20-23)src/lib/api/client.ts (2)
http(55-60)nextHttp(128-130)
src/app/_api/session/session.api.ts (2)
src/lib/api/client.ts (1)
nextHttp(128-130)src/app/_api/session/session.types.ts (1)
SessionData(1-1)
src/app/login/callback/page.tsx (1)
src/app/_api/auth/auth.queries.ts (1)
useLoginMutation(9-13)
src/app/api/auth/reissue/route.ts (3)
src/app/api/auth/login/route.ts (1)
POST(13-46)src/lib/api/type.ts (1)
ApiError(5-16)src/app/_api/auth/auth.api.ts (1)
postReissue(28-32)
src/app/api/auth/login/route.ts (4)
src/app/api/auth/reissue/route.ts (1)
POST(7-35)src/lib/api/type.ts (1)
ApiError(5-16)src/app/_api/auth/auth.api.ts (1)
postLogin(16-20)src/constants/time.constants.ts (1)
TOKEN_TIMES(17-29)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: deploy
- GitHub Check: test
🔇 Additional comments (24)
package.json (1)
24-25:ky및iron-session모두 최신 버전 사용 중
- ky@1.8.1 (최종 수정: 2025-04-14)
- iron-session@8.0.4 (최종 수정: 2024-11-12)
따라서 별도의 버전 업그레이드는 필요하지 않습니다.
다만 보안 취약점 점검을 위해 lockfile 생성 후npm audit실행을 권장드립니다:npm i --package-lock-only npm audit --omit=devLikely an incorrect or invalid review comment.
src/lib/exceptions/index.ts (1)
1-1: 배럴 파일 추가 👍공통 예외 클래스를 한곳에서 재-export 하도록 정리한 점이 좋습니다. 이후 import 경로가 간결해집니다.
src/lib/api/index.ts (1)
1-1: API 클라이언트 배포 포인트 일원화 👍
./client를 루트 배럴에 노출하여 사용성이 향상되었습니다. 폴더 구조 가이드라인도 충족합니다.src/constants/index.ts (1)
1-1: 전역 상수 통합 배럴 👍
time.constants를 index에 묶어 일관된 경로로 노출했습니다. 네이밍 및 구조 모두 가이드라인과 일치합니다.src/lib/session/type.ts (1)
1-7: 타입 정의가 잘 구성되어 있습니다.세션 데이터에 필요한 모든 필드가 적절히 정의되어 있고, 선택적 속성을 사용하여 유연한 세션 상태 관리가 가능합니다. 타입 선택도 각 용도에 맞게 적절합니다.
src/app/_api/session/session.api.ts (1)
5-12: 잘 구현된 API 함수입니다.JSDoc 문서화가 한국어로 잘 작성되어 있고, 타입 안전성을 보장하며, 깔끔한 async/await 패턴을 사용하고 있습니다. HTTP 클라이언트 사용법도 적절합니다.
src/lib/utils/environment.ts (1)
1-4: 표준적인 환경 감지 구현입니다.Next.js에서 클라이언트/서버 환경을 구분하는 표준 패턴을 올바르게 구현했습니다.
window와document객체의 존재 여부로 브라우저 환경을 감지하는 방식이 적절하고, 코딩 가이드라인도 잘 준수하고 있습니다.src/lib/session/index.ts (1)
1-3: 세션 모듈 구조가 잘 정리되어 있습니다클라이언트, 서버, 기본 세션 기능들을 명확하게 분리하여 내보내기하고 있어 모듈화가 잘 되어 있습니다. 중앙 집중식 내보내기로 사용자가 필요한 기능을 쉽게 찾을 수 있습니다.
src/app/_api/session/session.queries.ts (1)
1-14: TanStack Query 설정이 잘 구성되어 있습니다쿼리 키 구조가 명확하고,
queryOptions를 사용하여 타입 안전성을 보장하고 있습니다. 파일 위치와 명명 규칙도 가이드라인에 맞게 작성되어 있습니다.src/app/_api/auth/auth.queries.ts (1)
1-26: React Query 훅 구현이 올바르게 되어 있습니다.학습된 규칙에 따라 API 호출 관련 코드가
_api폴더의.queries.ts파일에 적절히 분리되어 있습니다. 각 뮤테이션 훅이 명확하게 정의되어 있어 좋습니다.향후 고려사항: 에러 핸들링이나 성공/실패 콜백 등 추가 옵션을 필요에 따라 구성할 수 있습니다.
src/lib/session/clientSession.ts (1)
5-8: 캐시 구조가 적절하게 설계되었습니다.Map을 사용한 세션 캐시 구조가 올바르게 정의되어 있습니다. 세션과 만료 시간을 함께 저장하는 구조가 명확합니다.
src/app/api/auth/login/route.ts (2)
13-21: 인가 코드 검증 로직이 적절합니다.요청에서 인가 코드를 확인하고 누락 시 적절한 에러 응답을 반환하는 로직이 올바르게 구현되어 있습니다.
27-34: 세션 업데이트 로직을 확인해주세요.세션에 로그인 정보를 저장하는 로직이 올바르게 구현되어 있습니다. 다만 TODO 주석에서 언급하신 대로 토큰 만료 시간을 백엔드에서 받아오는 것을 고려해보세요.
현재는 클라이언트에서
ACCESS_TOKEN_LIFESPAN상수를 사용해 만료 시간을 계산하고 있는데, 이는 서버와 클라이언트의 시간 동기화 문제나 토큰 정책 변경 시 불일치가 발생할 수 있습니다.src/lib/session/session.ts (1)
28-36: React cache를 활용한 세션 가져오기 함수가 잘 구현되었습니다.React의 cache 함수를 사용하여 렌더링 사이클 내에서 세션 요청을 최적화하는 접근법이 적절합니다. Next.js의 cookies API 사용법도 올바릅니다.
src/constants/time.constants.ts (1)
1-30: 시간 상수 정의가 올바르게 구현되었습니다.파일명이
time.constants.ts로 코딩 가이드라인의 camelCase 네이밍 규칙을 준수하고 있으며,src/constants/폴더에 올바르게 위치하고 있습니다.시간 단위 계산과 토큰 관련 상수들이 명확하게 정의되어 있고, 주석으로 각 상수의 용도가 잘 설명되어 있습니다. 밀리초 단위로 일관되게 정의된 점도 좋습니다.
src/app/_api/auth/auth.types.ts (1)
1-23: 타입 정의가 적절합니다!인증 API를 위한 타입 정의가 명확하고 구조적으로 잘 작성되었습니다.
src/middleware.ts (1)
69-73: 미들웨어 설정이 적절합니다!PWA 관련 파일들과 정적 자원들이 올바르게 제외되어 있습니다.
src/lib/api/client.ts (3)
21-51: 에러 핸들러가 잘 구현되었습니다!상태 코드별로 적절한 예외를 던지고 에러 메시지를 안전하게 추출하는 로직이 훌륭합니다.
66-74: 인증 헤더 설정이 적절합니다!서버/클라이언트 환경을 올바르게 구분하고 세션 상태를 안전하게 확인합니다.
112-126: 인증 HTTP 클라이언트 설정이 적절합니다!401 에러에 대해서만 한 번 재시도하는 보수적인 설정이 토큰 갱신 시나리오에 적합합니다.
src/app/_api/auth/auth.api.ts (2)
16-32: 백엔드 API 호출 함수들이 잘 구현되었습니다!타입 안전성과 문서화가 훌륭합니다.
52-74: 클라이언트 API 함수들이 잘 구현되었습니다!Next.js API 라우트를 통한 클라이언트 측 호출이 적절히 구현되었습니다.
src/lib/exceptions/exceptions.ts (2)
1-38: 상태 코드 enum과 기본 예외 클래스가 훌륭하게 설계되었습니다!HTTP 상태 코드가 명확히 정의되고 기본 예외 클래스가 필요한 모든 속성을 포함하고 있습니다.
40-116: 예외 클래스 계층 구조가 잘 구성되었습니다!각 예외 클래스가 적절한 기본 상태 코드를 가지고 있으며 일관된 패턴을 따릅니다.
|
This pull request (commit
|
|
This pull request (commit
|
wkdtnqls0506
left a comment
There was a problem hiding this comment.
준환님 로그인 처리 너무나도 고생이 많으셨습니다..👍🏻✨
Iron Session 사용하는 것과 서버, 클라이언트 분기 처리하는 방식 많이 배워갑니다..🙇🏻♀️
다이어그램 정리까지 감사해요~!!!
현재 구조가 _api / auth 순으로 되어 있는 것 같은데, 저희 컨벤션에 따르면 auth 하위에 _api가 있어야 할 거 같아요!
├── app/ # Next.js App Router
│ ├── (domain)/ # Route Group 예시 (비즈니스 도메인명으로 변경)
│ │ ├── _types/ # 해당 도메인 그룹 전용 타입
│ │ │ ├── domain.types.ts
│ │ │ └── index.ts
│ │ ├── _schemas/ # 해당 도메인 그룹 전용 Zod 스키마
│ │ │ ├── form.schema.ts
│ │ │ └── index.ts
│ │ ├── _utils/ # 해당 도메인 그룹 전용 유틸
│ │ │ ├── domainUtils.ts
│ │ │ └── index.ts
│ │ ├── _constants/ # 해당 도메인 그룹 전용 상수
│ │ │ ├── domain.constants.ts
│ │ │ └── index.ts
│ │ ├── _api/ # 해당 도메인 그룹 전용 API/TanStack Query
│ │ │ ├── domain.api.ts
│ │ │ ├── domain.queries.ts
│ │ │ └── index.ts
|
This pull request (commit
|
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/app/api/auth/login/route.ts (1)
50-57: 에러 처리 세분화를 고려해보세요.현재 모든 에러를 "로그인에 실패했습니다"로 처리하고 있습니다. 에러 유형별로 다른 메시지를 반환하는 것이 사용자 경험 개선에 도움이 될 것입니다.
예를 들어:
- 네트워크 오류
- 잘못된 인가 코드
- 서버 내부 오류
- 토큰 발급 실패
🧹 Nitpick comments (3)
src/app/api/auth/login/route.ts (3)
14-16: 입력값 검증을 강화하는 것을 고려해보세요.코드 파라미터에 대한 기본적인 형식 검증을 추가하면 보안성을 높일 수 있습니다.
export const POST = async (req: NextRequest) => { const { code } = await req.json(); const origin = req.headers.get("origin"); + if (typeof code !== 'string' || code.trim().length === 0) { + return NextResponse.json<ApiError>( + { errorMessage: "유효하지 않은 인가 코드입니다." }, + { status: 400 } + ); + }
42-42: userId 타입 변환의 필요성을 확인해보세요.
data.information.id를 문자열로 변환하고 있는데, 세션 타입과 API 응답 타입을 확인하여 변환이 필요한지 검토해보세요.
43-45: TODO 항목 해결을 위한 계획을 수립해보세요.백엔드에서 토큰 만료 시간을 받아오는 구현이 완료되면 하드코딩된 값을 대체할 수 있도록 준비해보세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/app/_api/auth/auth.api.ts(1 hunks)src/app/_api/auth/auth.types.ts(1 hunks)src/app/api/auth/login/route.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/app/_api/auth/auth.types.ts
- src/app/_api/auth/auth.api.ts
🧰 Additional context used
🧠 Learnings (1)
src/app/api/auth/login/route.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/app/**/_api/*.{api,queries}.ts : API 호출 관련 코드는 `_api` 폴더에 `.api.ts` (ky 사용) 및 `.queries.ts` (TanStack Query) 파일로 분리해야 한다.
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: test
🔇 Additional comments (3)
src/app/api/auth/login/route.ts (3)
1-7: 임포트 구조가 잘 정리되어 있습니다.모든 필요한 모듈들이 적절히 임포트되었고, 타입 임포트와 일반 임포트가 올바르게 분리되어 있습니다.
18-30: 입력값 검증 로직이 적절합니다.필수 파라미터들에 대한 검증이 올바르게 구현되었고, 적절한 HTTP 상태 코드와 사용자 친화적인 에러 메시지를 사용하고 있습니다.
32-49: 로그인 로직이 잘 구현되어 있습니다.인증 플로우가 올바르게 구현되었고 세션 관리도 적절합니다.
|
This pull request (commit
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/app/(auth)/login/callback/page.tsx (2)
17-40: 사용자 경험 개선을 위한 리팩토링을 고려해보세요.현재 구현은 기능적으로 올바르지만, 다음과 같은 개선점이 있습니다:
alert()사용은 모던 웹 앱에서 권장되지 않습니다- 로딩 상태 관리가 부족합니다
- 에러 처리를 더 세밀하게 할 수 있습니다
다음과 같이 개선할 수 있습니다:
+ import { useState } from "react"; + import { toast } from "react-hot-toast"; // 또는 다른 토스트 라이브러리 export default function AuthCallbackPage() { const router = useRouter(); const searchParams = useSearchParams(); const code = searchParams.get("code"); const next = searchParams.get("next"); + const [isLoading, setIsLoading] = useState(false); - const { mutate: login } = useLoginMutation(); + const { mutate: login, isPending } = useLoginMutation(); useEffect(() => { if (code) { + setIsLoading(true); login( { code }, { onSuccess: () => { clearClientSessionCache(); const redirectUrl = next || "/"; router.replace(redirectUrl); }, onError: error => { console.error("로그인에 실패했습니다:", error); - alert("로그인에 실패했습니다. 다시 시도해주세요."); + toast.error("로그인에 실패했습니다. 다시 시도해주세요."); router.replace("/login"); + }, + onSettled: () => { + setIsLoading(false); }, } ); } else { - alert("비정상적인 접근입니다."); + toast.error("비정상적인 접근입니다."); router.replace("/"); } }, [code, login, router, next]);
42-43: 로딩 상태 표시를 개선해보세요.현재 단순한 텍스트만 표시하고 있습니다. 더 나은 사용자 경험을 위해 로딩 스피너나 스켈레톤 UI를 고려해보세요.
- return <div>로그인 중입니다...</div>; + return ( + <div className="flex items-center justify-center min-h-screen"> + <div className="text-center"> + <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div> + <p className="text-gray-600">로그인 중입니다...</p> + </div> + </div> + );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
src/app/(auth)/_api/auth/auth.api.ts(1 hunks)src/app/(auth)/_api/auth/auth.queries.ts(1 hunks)src/app/(auth)/_api/auth/auth.types.ts(1 hunks)src/app/(auth)/_api/session/session.api.ts(1 hunks)src/app/(auth)/_api/session/session.queries.ts(1 hunks)src/app/(auth)/_api/session/session.types.ts(1 hunks)src/app/(auth)/login/callback/page.tsx(1 hunks)src/app/api/auth/login/route.ts(1 hunks)src/app/api/auth/reissue/route.ts(1 hunks)src/lib/api/client.ts(1 hunks)src/lib/session/clientSession.ts(1 hunks)src/middleware.ts(1 hunks)
✅ Files skipped from review due to trivial changes (5)
- src/app/(auth)/_api/session/session.types.ts
- src/app/(auth)/_api/session/session.queries.ts
- src/app/(auth)/_api/auth/auth.queries.ts
- src/app/(auth)/_api/session/session.api.ts
- src/app/(auth)/_api/auth/auth.types.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- src/app/api/auth/login/route.ts
- src/lib/session/clientSession.ts
- src/app/api/auth/reissue/route.ts
- src/middleware.ts
- src/lib/api/client.ts
🧰 Additional context used
🧠 Learnings (1)
src/app/(auth)/_api/auth/auth.api.ts (2)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/app/**/_api/*.{api,queries}.ts : API 호출 관련 코드는 `_api` 폴더에 `.api.ts` (ky 사용) 및 `.queries.ts` (TanStack Query) 파일로 분리해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/lib/api/*.{ts,tsx} : 전역 API 클라이언트 및 타입은 `lib/api/` 폴더에 위치해야 한다.
🧬 Code Graph Analysis (2)
src/app/(auth)/login/callback/page.tsx (2)
src/app/(auth)/_api/auth/auth.queries.ts (1)
useLoginMutation(9-13)src/lib/session/clientSession.ts (1)
clearClientSessionCache(16-18)
src/app/(auth)/_api/auth/auth.api.ts (2)
src/app/(auth)/_api/auth/auth.types.ts (4)
LoginRequest(1-4)LoginResponse(6-15)ReissueRequest(17-19)ReissueResponse(21-24)src/lib/api/client.ts (2)
http(55-60)nextHttp(128-130)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: test
🔇 Additional comments (8)
src/app/(auth)/login/callback/page.tsx (1)
1-8: 임포트 및 초기 설정이 올바르게 구성되었습니다.클라이언트 컴포넌트 지시문과 필요한 훅들이 적절히 임포트되었습니다. 인증 관련 API와 세션 관리 유틸리티도 올바르게 가져왔습니다.
src/app/(auth)/_api/auth/auth.api.ts (7)
1-8: 임포트 구조가 올바르게 구성되었습니다.HTTP 클라이언트와 타입 정의가 적절히 임포트되었습니다. 검색된 학습 내용에 따르면
_api폴더에.api.ts파일을 배치하는 것이 올바른 구조입니다.
16-20: 백엔드 로그인 API 호출이 올바르게 구현되었습니다.HTTP 클라이언트를 사용하여 적절한 타입 안정성을 제공하고 있습니다.
28-32: 토큰 재발급 API 호출이 올바르게 구현되었습니다.백엔드 재발급 엔드포인트와의 통신이 적절히 구현되었습니다.
46-46: 타입 정의가 깔끔하게 구현되었습니다.
Information타입을 인라인으로 정의한 것이 적절합니다. 복잡한 타입 조작을 통해 재사용성을 높였습니다.
54-58: 클라이언트 로그인 API 호출이 올바르게 구현되었습니다.Next.js API 라우트를 통한 로그인 처리가 적절히 구현되었습니다.
origin파라미터를 제외한 타입 정의도 올바릅니다.
65-67: 클라이언트 토큰 재발급 API 호출이 올바르게 구현되었습니다.Next.js API 라우트를 통한 토큰 재발급 처리가 적절히 구현되었습니다.
74-76: 세션 삭제 API 호출이 올바르게 구현되었습니다.로그아웃 처리를 위한 API 호출이 적절히 구현되었습니다.
리뷰처럼 변경했습니다! 한번 확인 부탁드려요! |
오 준환님 확인했습니다!! 머지하셔도 될 거 같아요 ✨ 수고하셨습니다 ~ . ~ |
✅ 이슈 번호
close #50
🪄 작업 내용 (변경 사항)
📸 스크린샷
💡 설명
아래는 다이어그램이옵니다!
sequenceDiagram actor 브라우저 participant Next.js 서버 participant 백엔드 API Note over 브라우저, 백엔드 API: 1. 로그인 브라우저->>Next.js 서버: GET /login/callback (Auth Code 전달) Next.js 서버->>백엔드 API: POST /login (Auth Code로 토큰 요청) 백엔드 API-->>Next.js 서버: accessToken, refreshToken 응답 Note over Next.js 서버: Iron Session에 토큰 저장 Next.js 서버-->>브라우저: 로그인 성공 Note over 브라우저, 백엔드 API: 2. 클라이언트 API 요청 (토큰 유효) 브라우저->>Next.js 서버: GET /api/session (accessToken 요청) Next.js 서버-->>브라우저: accessToken 응답 브라우저->>백엔드 API: GET /data (with accessToken) 백엔드 API-->>브라우저: 데이터 응답 Note over 브라우저, 백엔드 API: 3. 서버 컴포넌트 요청 (토큰 유효) 브라우저->>Next.js 서버: GET /protected-page Note over Next.js 서버: Middleware: 토큰 유효성 검사 Note over Next.js 서버: Server Component: 세션에서 토큰 사용 Next.js 서버->>백엔드 API: GET /data (with accessToken) 백엔드 API-->>Next.js 서버: 데이터 응답 Next.js 서버-->>브라우저: 페이지 렌더링 Note over 브라우저, 백엔드 API: 4. 클라이언트 토큰 갱신 브라우저->>백엔드 API: GET /data (만료된 accessToken) 백엔드 API-->>브라우저: 401 Unauthorized 브라우저->>Next.js 서버: POST /api/auth/reissue Next.js 서버->>백엔드 API: POST /reissue (refreshToken 사용) 백엔드 API-->>Next.js 서버: 새 토큰 발급 Note over Next.js 서버: 새 토큰으로 세션 업데이트 Next.js 서버-->>브라우저: 갱신 성공 Note over 브라우저: 새로운 토큰으로 API 재요청 Note over 브라우저, 백엔드 API: 5. 서버(미들웨어) 토큰 갱신 브라우저->>Next.js 서버: GET /protected-page Note over Next.js 서버: Middleware: 토큰 만료 감지 Next.js 서버->>백엔드 API: POST /reissue (refreshToken 사용) 백엔드 API-->>Next.js 서버: 새 토큰 발급 Note over Next.js 서버: 새 토큰으로 세션 업데이트 Note over Next.js 서버: 갱신된 토큰으로 API 요청 Next.js 서버-->>브라우저: 페이지 렌더링🗣️ 리뷰어에게 전달 사항
📍 트러블 슈팅
Summary by CodeRabbit
신규 기능
기타