Skip to content

[FEAT] axios 기반 공통 API 레이어 구축#8

Merged
BaeSeong-min merged 20 commits into
developfrom
feat/#7
Apr 30, 2026
Merged

[FEAT] axios 기반 공통 API 레이어 구축#8
BaeSeong-min merged 20 commits into
developfrom
feat/#7

Conversation

@BaeSeong-min

@BaeSeong-min BaeSeong-min commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

🔍 PR 요약

  • Swagger API 명세 기반으로 axios 공통 API 레이어를 구축하고, 기존 fetch 기반 코드를 교체합니다.

🧾 관련 이슈

🛠️ 주요 변경 사항

  • pnpm add axios, pnpm add react-hot-toast
  • src/apis/http.ts 생성 (axios 인스턴스, withCredentials: true, 응답 인터셉터)
  • src/apis/types.ts 생성 (PaginatedResponse, ApiError 타입)
  • src/apis/endpoints.ts 생성 (API 경로 상수)
  • src/apis/modules/ 모듈 생성 (auth, payments, companies, partners, matches, buyers, consultations, admin, analytics)
  • src/apis/index.ts 생성 (모듈 일괄 export)
  • src/stores/authStore.jsopenLoginModal, closeLoginModal 액션 추가
  • 기존 src/apis/*.js fetch 기반 파일 전체 제거 및 import 경로 교체
  • .env, .env.exampleVITE_API_BASE_URL 추가

🧠 의도 및 배경

  • fetch 기반 API 호출이 파일마다 분산되어 공통 처리(에러, 인증)가 불가능했던 문제 해결
  • 세션 쿠키 기반 인증이므로 withCredentials: true 설정
  • 401 → 로그인 모달 오픈, 403/500 → react-hot-toast 에러 메시지 표시
  • 결제 생성 시 Idempotency-Key 헤더 필수 처리 유지

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 세션 만료 시 자동으로 로그인 모달 표시
    • 오류 발생 시 토스트 알림으로 사용자 피드백 강화
  • 개선 사항

    • API 통신 기반 구조 현대화로 안정성 향상
    • 환경 변수 설정으로 API 엔드포인트 관리 개선

@BaeSeong-min BaeSeong-min self-assigned this Apr 30, 2026
@vercel

vercel Bot commented Apr 30, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
k-statra-frontend Ready Ready Preview, Comment Apr 30, 2026 3:16pm

@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@BaeSeong-min has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 51 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c7889391-d8f7-4d3a-9b5b-f1a234cdc1c6

📥 Commits

Reviewing files that changed from the base of the PR and between a9be36c and 4f67954.

📒 Files selected for processing (8)
  • src/App.jsx
  • src/apis/http.ts
  • src/apis/modules/consultations.ts
  • src/apis/modules/payments.ts
  • src/hooks/usePayments.js
  • src/pages/PartnerSearch.jsx
  • src/stores/authStore.js
  • src/vite-env.d.ts
📝 Walkthrough

Walkthrough

기존 분산된 fetch 기반 API 호출들을 axios 공통 인스턴스로 통일하고, 공통 헤더·에러 처리를 중앙화합니다. 응답 인터셉터로 401/403 에러를 처리하며, 기능별 타입화된 API 모듈들로 구조화했습니다.

Changes

Cohort / File(s) Summary
환경 및 의존성 설정
.env.example, package.json
환경 변수 VITE_API_BASE_URL 추가 및 axios, react-hot-toast 패키지 의존성 추가.
폐기된 API 모듈
src/apis/admin.js, src/apis/analytics.js, src/apis/buyers.js, src/apis/client.js, src/apis/companies.js, src/apis/consultants.js, src/apis/matches.js, src/apis/payments.js
기존 fetch 기반 API 모듈 제거. 해당 기능들은 새로운 모듈 구조로 마이그레이션됨.
공통 API 인프라
src/apis/http.ts, src/apis/types.ts, src/apis/endpoints.ts, src/apis/index.ts
axios 기반 공통 HTTP 클라이언트 (withCredentials, 응답 인터셉터), 페이지네이션/에러 타입, API 경로 상수, 배럴 export 모듈 추가.
기능별 API 모듈
src/apis/modules/auth.ts, src/apis/modules/payments.ts, src/apis/modules/companies.ts, src/apis/modules/partners.ts, src/apis/modules/matches.ts, src/apis/modules/buyers.ts, src/apis/modules/consultations.ts, src/apis/modules/admin.ts, src/apis/modules/analytics.ts
각 도메인별 DTO/타입 정의 및 HTTP 메서드 래핑. Idempotency-Key 헤더, 동적 경로 구성, blob 응답 처리 등 포함.
Hook 업데이트
src/hooks/useAnalytics.js, src/hooks/useBuyers.js, src/hooks/useCompanies.js, src/hooks/useConsultations.js, src/hooks/useMatches.js, src/hooks/usePayments.js
기존 직접 import 제거, *Api 네임스페이스 객체를 통한 메서드 호출로 변경.
페이지 컴포넌트 업데이트
src/pages/AdminMatches.jsx, src/pages/AdminPayments.jsx, src/pages/AdminStats.jsx, src/pages/BuyerForm.jsx, src/pages/ContactPage.jsx, src/pages/Matches.jsx, src/pages/PartnerSearch.jsx, src/pages/PaymentCheckout.jsx
분산된 API 함수 import를 *Api 객체로 통합하고 메서드 호출 경로 수정. 통합 import로 의존성 단순화.
Store 및 App 업데이트
src/stores/authStore.js, src/App.jsx
authStoreloginModalOpen 상태 및 openLoginModal/closeLoginModal 액션 추가. App.jsx에서 toast Toaster 통합 및 로그인 모달 동기화 효과 추가.

Sequence Diagram(s)

sequenceDiagram
    participant Client as React Component
    participant Interceptor as HTTP Interceptor
    participant Backend as Backend Server
    
    Client->>Interceptor: API 요청<br/>(axios.get/post/patch)
    Interceptor->>Backend: HTTP 요청 전송<br/>(withCredentials: true)
    
    alt 성공 (2xx)
        Backend-->>Interceptor: 응답 반환
        Interceptor-->>Client: 파싱된 데이터 반환
    else 401 Unauthorized
        Backend-->>Interceptor: 401 응답
        Interceptor->>Interceptor: openLoginModal 호출
        Interceptor->>Client: 토스트 메시지 표시<br/>(에러 rethrow)
    else 403 Forbidden
        Backend-->>Interceptor: 403 응답
        Interceptor->>Client: 로컬라이즈된 토스트<br/>에러 메시지 표시<br/>(에러 rethrow)
    else 5xx Server Error
        Backend-->>Interceptor: 5xx 응답
        Interceptor->>Client: 서버 에러 토스트<br/>메시지 표시<br/>(에러 rethrow)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 분

Possibly related PRs

  • [REFACTOR] 초기 리팩토링 #4: 이전 API 모듈 구조 (admin, analytics, buyers 등)를 새로운 타입화된 모듈 레이아웃과 중앙화된 axios 기반 http.ts로 대체하는 동일한 API 표면을 재구성하는 직접 관련 PR입니다.

Poem

🐰 axios 묶음으로 API를 정리하고,
인터셉터가 에러들을 거르지요.
세션 쿠키로 인증 안전하게,
모듈별로 깔끔하게 정렬되어,
토스트 팝업에 사용자 알려주고,
로그인 모달 열고 닫고~ ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 주요 변경사항(axios 기반 공통 API 레이어 구축)을 명확하게 요약하고 있으며, 변경사항과 완전히 관련이 있습니다.
Description check ✅ Passed PR 설명이 템플릿 구조를 따르고 있으며, 요약, 관련 이슈, 주요 변경사항, 의도 및 배경을 모두 포함하고 있습니다.
Linked Issues check ✅ Passed 모든 주요 요구사항이 충족되었습니다: axios 기반 공통 API 레이어 구축, 응답 인터셉터, 공유 타입 정의, 모듈화된 API 엔드포인트, Idempotency-Key 헤더 처리, 레거시 fetch 호출 제거, 환경 변수 추가, 로그인 모달 액션 추가 등.
Out of Scope Changes check ✅ Passed 모든 변경사항이 issue #7의 요구사항 범위 내에 있으며, 외부 범위의 변경은 없습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#7

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
Review rate limit: 0/1 reviews remaining, refill in 20 minutes and 51 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

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

Caution

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

⚠️ Outside diff range comments (2)
src/pages/AdminPayments.jsx (2)

75-83: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

listPayments 응답 언랩 누락으로 페이지네이션/리스트가 깨질 수 있습니다.

현재는 AxiosResponse를 바로 쓰고 있어 totalPages, page가 항상 기본값으로 떨어지거나, items가 배열이 아니게 될 수 있습니다.

🔧 제안 수정
-      const res = await adminApi.listPayments({
+      const res = await adminApi.listPayments({
         token,
         page: p,
         limit: 20,
         ...Object.fromEntries(Object.entries(filters).filter(([_, v]) => v)),
       });
-      setItems(res?.data || []);
-      setTotalPages(res?.totalPages || 1);
-      setPage(res?.page || p);
+      const body = res?.data ?? {};
+      setItems(Array.isArray(body?.data) ? body.data : []);
+      setTotalPages(body?.totalPages || 1);
+      setPage(body?.page || p);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/AdminPayments.jsx` around lines 75 - 83, The code is using the raw
Axios response (res) instead of unwrapping res.data, causing page/list values to
fall back to defaults or be invalid; update the adminApi.listPayments handling
to read the payload from res.data (e.g., const payload = res?.data || {}), then
setItems using a safe check (ensure payload.items is an array, otherwise []),
setTotalPages using a numeric fallback from payload.totalPages (default 1), and
setPage using a numeric fallback from payload.page (default p); refer to
adminApi.listPayments, res, setItems, setTotalPages, and setPage when making
these changes.

342-349: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

getPaymentStats도 AxiosResponse 언랩이 필요합니다.

setStats(s)로 저장하면 실제 통계 객체 대신 응답 래퍼가 들어가서 카드/테이블이 비정상 표시됩니다. s.data를 저장하도록 맞춰 주세요.

🔧 제안 수정
-              const s = await adminApi.getPaymentStats({
+              const s = await adminApi.getPaymentStats({
                 token,
                 from: filters.from,
                 to: filters.to,
                 buyerId: filters.buyerId,
                 companyId: filters.companyId,
               });
-              setStats(s);
+              setStats(s?.data ?? { since: "", byStatus: {}, byCurrency: {}, byCurrencyStatus: {} });

Also applies to: 388-395, 413-420, 438-445, 469-476

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/AdminPayments.jsx` around lines 342 - 349, The response wrapper
from Axios is being stored instead of the actual payload: change usages where
you call adminApi.getPaymentStats and immediately call setStats(s) to instead
setStats(s.data); apply the same unwrapping (.data) to the other adminApi.*
calls in this file so their corresponding setters (e.g., replace
setPayments(response) with setPayments(response.data),
setTopBuyers(...)->setTopBuyers(... .data),
setTopCompanies(...)->setTopCompanies(... .data), and any count/stat setters)
receive the raw data rather than the AxiosResponse object.
🧹 Nitpick comments (1)
src/apis/modules/consultations.ts (1)

35-36: ⚡ Quick win

하드코딩 경로를 ENDPOINTS로 통일해 주세요.

Line 35-36만 문자열 리터럴 경로를 직접 사용하고 있어, 이번 PR의 “경로 상수 중앙화” 목표와 어긋납니다.

수정 예시
   createRequest: (data: Record<string, unknown>) =>
-    http.post("/consultants/requests", data),
+    http.post(ENDPOINTS.consultations.requests, data),
 };
// src/apis/endpoints.ts (추가 예시)
consultations: {
  root: "/consultations",
  status: (id: string) => `/consultations/${id}/status`,
  requests: "/consultants/requests",
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/apis/modules/consultations.ts` around lines 35 - 36, The createRequest
function in src/apis/modules/consultations.ts currently uses a hardcoded path
string "/consultants/requests"; replace that literal with the centralized
endpoint constant (e.g., ENDPOINTS.consultations.requests) so the module uses
the project's endpoint constants; update the createRequest implementation to
call http.post(ENDPOINTS.consultations.requests, data) and ensure ENDPOINTS (or
the exported endpoints object) is imported at the top of the file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/apis/modules/payments.ts`:
- Around line 13-16: The create method in payments.ts accepts an idempotencyKey
but currently allows empty or whitespace-only strings; update the create
function to validate idempotencyKey (e.g., trim() and check length > 0) and
reject/throw an error immediately if it's empty or only whitespace before
calling http.post (reference the create function and the header
"Idempotency-Key"); ensure the header is only sent when the key is valid and
return a clear error message like "Idempotency key is required" so callers can
handle the failure.
- Around line 13-29: The payment API calls (create, getById, refresh,
getSummary, getRecent) expect the payload directly but the HTTP response
interceptor still returns the full AxiosResponse (res => res), causing consumers
to read undefined (they access res._id or res.payment._id); update the response
interceptor in the HTTP client module so it returns the response body (res.data)
instead of the entire AxiosResponse, and ensure the http.post/http.get generic
typings propagate the data type (or alternatively map http.post/get calls inside
the payments module to return response.data) so callers of
create/getById/refresh/getSummary/getRecent receive the actual payload.

In `@src/App.jsx`:
- Around line 126-127: buyersApi.list() returns a paginated AxiosResponse so
accessing res.data?.[0] is wrong and yields undefined; update the code that
assigns buyer (around the buyersApi.list call) to read the first item from the
paginated payload — i.e., use res.data?.data?.[0] (preserving optional chaining)
when setting buyer so the demo login can find the first buyer.

In `@src/hooks/usePayments.js`:
- Line 39: mutationFn 호출에서 idemKey가 비어 있으면 런타임에서 차단해야 합니다: usePayments.js의
mutationFn (현재: mutationFn: ({ payload, idemKey }) =>
paymentsApi.create(payload, idemKey)) 시작 부분에서 idemKey를 검사하고 비어있으면 예외를 던지거나 에러를
반환하도록 추가해 주세요(예: throw new Error 또는 반환된 Promise.reject). 이렇게 하면
paymentsApi.create가 빈 idemKey로 호출되는 것을 방지하고 호출자에게 명확한 실패 이유를 제공합니다.

In `@src/pages/BuyerForm.jsx`:
- Around line 53-54: The issue is that buyersApi.create returns an AxiosResponse
so res?._id is undefined; change the id extraction to read the response payload
(e.g., use res?.data?._id or destructure const { data } = res and use data._id)
in BuyerForm.jsx where you call buyersApi.create(payload) so id is set from the
actual response body, or alternatively update buyersApi.create to return
res.data directly and then keep id = res?._id.

In `@src/pages/ContactPage.jsx`:
- Around line 24-25: The payment ID lookup is using the raw Axios response shape
incorrectly (res?.payment?._id || res?._id) while earlier code uses res?.data;
update the logic to consistently read the payload from res.data (e.g. const
payload = res?.data || {}; then use payload.payment?._id || payload._id) so the
navigation to /payments/checkout/{id} receives the actual ID returned by
matchesApi.list / payment API; adjust any references to res?.payment or res?._id
to use payload.payment and payload._id instead.

In `@src/stores/authStore.js`:
- Around line 9-13: clearAuth currently only resets buyerId and buyerName which
can leave the login modal open; update the clearAuth setter to also set
loginModalOpen: false so the modal state is cleared when clearing auth. Locate
the clearAuth function in the auth store (clearAuth: () => set({...})) and
include loginModalOpen: false in the object returned by set; keep other helpers
(setAuth, openLoginModal, closeLoginModal) unchanged.

---

Outside diff comments:
In `@src/pages/AdminPayments.jsx`:
- Around line 75-83: The code is using the raw Axios response (res) instead of
unwrapping res.data, causing page/list values to fall back to defaults or be
invalid; update the adminApi.listPayments handling to read the payload from
res.data (e.g., const payload = res?.data || {}), then setItems using a safe
check (ensure payload.items is an array, otherwise []), setTotalPages using a
numeric fallback from payload.totalPages (default 1), and setPage using a
numeric fallback from payload.page (default p); refer to adminApi.listPayments,
res, setItems, setTotalPages, and setPage when making these changes.
- Around line 342-349: The response wrapper from Axios is being stored instead
of the actual payload: change usages where you call adminApi.getPaymentStats and
immediately call setStats(s) to instead setStats(s.data); apply the same
unwrapping (.data) to the other adminApi.* calls in this file so their
corresponding setters (e.g., replace setPayments(response) with
setPayments(response.data), setTopBuyers(...)->setTopBuyers(... .data),
setTopCompanies(...)->setTopCompanies(... .data), and any count/stat setters)
receive the raw data rather than the AxiosResponse object.

---

Nitpick comments:
In `@src/apis/modules/consultations.ts`:
- Around line 35-36: The createRequest function in
src/apis/modules/consultations.ts currently uses a hardcoded path string
"/consultants/requests"; replace that literal with the centralized endpoint
constant (e.g., ENDPOINTS.consultations.requests) so the module uses the
project's endpoint constants; update the createRequest implementation to call
http.post(ENDPOINTS.consultations.requests, data) and ensure ENDPOINTS (or the
exported endpoints object) is imported at the top of the file.
🪄 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: CHILL

Plan: Pro

Run ID: eb71f537-6fd1-4657-8e85-9eb3be0f42c8

📥 Commits

Reviewing files that changed from the base of the PR and between 9de9352 and a9be36c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (39)
  • .env.example
  • package.json
  • src/App.jsx
  • src/apis/admin.js
  • src/apis/analytics.js
  • src/apis/buyers.js
  • src/apis/client.js
  • src/apis/companies.js
  • src/apis/consultants.js
  • src/apis/endpoints.ts
  • src/apis/http.ts
  • src/apis/index.ts
  • src/apis/matches.js
  • src/apis/modules/admin.ts
  • src/apis/modules/analytics.ts
  • src/apis/modules/auth.ts
  • src/apis/modules/buyers.ts
  • src/apis/modules/companies.ts
  • src/apis/modules/consultations.ts
  • src/apis/modules/matches.ts
  • src/apis/modules/partners.ts
  • src/apis/modules/payments.ts
  • src/apis/payments.js
  • src/apis/types.ts
  • src/hooks/useAnalytics.js
  • src/hooks/useBuyers.js
  • src/hooks/useCompanies.js
  • src/hooks/useConsultations.js
  • src/hooks/useMatches.js
  • src/hooks/usePayments.js
  • src/pages/AdminMatches.jsx
  • src/pages/AdminPayments.jsx
  • src/pages/AdminStats.jsx
  • src/pages/BuyerForm.jsx
  • src/pages/ContactPage.jsx
  • src/pages/Matches.jsx
  • src/pages/PartnerSearch.jsx
  • src/pages/PaymentCheckout.jsx
  • src/stores/authStore.js
💤 Files with no reviewable changes (8)
  • src/apis/matches.js
  • src/apis/admin.js
  • src/apis/companies.js
  • src/apis/consultants.js
  • src/apis/payments.js
  • src/apis/analytics.js
  • src/apis/client.js
  • src/apis/buyers.js

Comment thread src/apis/modules/payments.ts Outdated
Comment thread src/apis/modules/payments.ts Outdated
Comment thread src/App.jsx Outdated
Comment on lines 126 to 127
const res = await buyersApi.list({ limit: 1 });
const buyer = res.data?.[0];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# buyersApi.list 반환 계약 확인 및 호출부 매칭 확인
fd -i "http.ts" src | xargs -r sed -n '1,220p'
fd -i "buyers.ts" src/apis/modules | xargs -r sed -n '1,220p'
rg -n -C2 'buyersApi\.list\(|res\.data\?\.\[0\]|payload\?\.data\?\.\[0\]' src

Repository: K-Statra/frontend

Length of output: 2170


🏁 Script executed:

# Find PaginatedResponse type definition
rg -n "type PaginatedResponse|interface PaginatedResponse" src

# Check the types file
fd -i "types.ts" src/apis | xargs -r cat

# Check how useBuyers hook handles the response
cat -n src/hooks/useBuyers.js

# Check other usages of buyersApi.list() response
rg -n -A5 "buyersApi\.list" src --type js --type jsx --type ts

Repository: K-Statra/frontend

Length of output: 680


Line 127의 응답 구조 접근이 잘못되어 demo 로그인이 항상 실패합니다.

buyersApi.list()AxiosResponse<PaginatedResponse<unknown>>을 반환하므로, res.data{ page, limit, total, totalPages, data: T[] } 구조입니다. 현재 res.data?.[0]은 객체의 첫 번째 요소를 접근하려는 것이므로 항상 undefined를 반환합니다. 올바른 접근은 res.data?.data?.[0]입니다.

수정 제안
      const res = await buyersApi.list({ limit: 1 });
-     const buyer = res.data?.[0];
+     const buyer = res.data?.data?.[0];
📝 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.

Suggested change
const res = await buyersApi.list({ limit: 1 });
const buyer = res.data?.[0];
const res = await buyersApi.list({ limit: 1 });
const buyer = res.data?.data?.[0];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/App.jsx` around lines 126 - 127, buyersApi.list() returns a paginated
AxiosResponse so accessing res.data?.[0] is wrong and yields undefined; update
the code that assigns buyer (around the buyersApi.list call) to read the first
item from the paginated payload — i.e., use res.data?.data?.[0] (preserving
optional chaining) when setting buyer so the demo login can find the first
buyer.

Comment thread src/hooks/usePayments.js Outdated
Comment thread src/pages/BuyerForm.jsx
Comment on lines +53 to 54
const res = await buyersApi.create(payload);
const id = res?._id;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# buyersApi.create 반환 shape 확인 (success interceptor 포함)
fd -i "http.ts" src | xargs -r sed -n '1,220p'
fd -i "buyers.ts" src/apis/modules | xargs -r sed -n '1,220p'
rg -n -C2 'buyersApi\.create\(|res\?\._id|res\.data\?\._id' src

Repository: K-Statra/frontend

Length of output: 3104


AxiosResponse에서 데이터를 언래핑하지 않으면 _id가 undefined가 되어 리다이렉트가 동작하지 않습니다.

buyersApi.createhttp.post를 반환하며, 응답 인터셉터가 전체 AxiosResponse 객체를 반환하므로 라인 54의 res?._id는 항상 undefined입니다. 실제 데이터는 res.data._id에 위치하기 때문에 id는 falsy 값이 되어 이후 리다이렉트 조건을 만족하지 못합니다.

수정 제안
      const res = await buyersApi.create(payload);
-     const id = res?._id;
+     const id = res?.data?._id;
📝 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.

Suggested change
const res = await buyersApi.create(payload);
const id = res?._id;
const res = await buyersApi.create(payload);
const id = res?.data?._id;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/BuyerForm.jsx` around lines 53 - 54, The issue is that
buyersApi.create returns an AxiosResponse so res?._id is undefined; change the
id extraction to read the response payload (e.g., use res?.data?._id or
destructure const { data } = res and use data._id) in BuyerForm.jsx where you
call buyersApi.create(payload) so id is set from the actual response body, or
alternatively update buyersApi.create to return res.data directly and then keep
id = res?._id.

Comment thread src/pages/ContactPage.jsx
Comment on lines +24 to 25
const res = await matchesApi.list(buyerId, 50);
let arr = res?.data || [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# matches/payments 모듈 및 interceptor의 반환 shape 확인
fd -i "http.ts" src | xargs -r sed -n '1,240p'
fd -i "matches.ts" src/apis/modules | xargs -r sed -n '1,220p'
fd -i "payments.ts" src/apis/modules | xargs -r sed -n '1,260p'
rg -n -C2 'matchesApi\.list\(|paymentsApi\.create\(|res\?\.data \|\| \[\]|res\?\.payment\?\._id' src/pages/ContactPage.jsx

Repository: K-Statra/frontend

Length of output: 2965


🏁 Script executed:

rg -n "payment\?\._id|\.payment|paymentPayload|CreatePaymentDto" src --type ts --type tsx -A2 -B2

Repository: K-Statra/frontend

Length of output: 89


🏁 Script executed:

fd -i "types" src/apis | head -5
rg "interface.*Payment|type.*Payment" src --type ts -A5 | head -50

Repository: K-Statra/frontend

Length of output: 400


🏁 Script executed:

cat src/apis/types.ts

Repository: K-Statra/frontend

Length of output: 282


🏁 Script executed:

rg -n "payment" src/pages/ContactPage.jsx -i -C3 | head -60

Repository: K-Statra/frontend

Length of output: 1143


🏁 Script executed:

rg "interface.*Payment|type.*Payment|export.*Payment" src/apis --type ts -A8

Repository: K-Statra/frontend

Length of output: 886


🏁 Script executed:

rg "res\.data\?\.payment|paymentPayload|Payment.*Response" src --type ts -C2

Repository: K-Statra/frontend

Length of output: 43


🏁 Script executed:

rg -n "\.checkout|nav\(|navigate\(" src/pages/ContactPage.jsx -C1

Repository: K-Statra/frontend

Length of output: 351


🏁 Script executed:

# Check if there are any other files handling payment responses to see the pattern
rg "paymentsApi\." src --type ts -A3 | head -40

Repository: K-Statra/frontend

Length of output: 43


결제 응답 파싱이 axios 계약을 위반하여 결제 흐름이 실패합니다.

Line 123에서 res?.payment?._id || res?._id로 접근하는데, http 인터셉터는 AxiosResponse를 그대로 반환하므로 실제 페이로드는 res.data 안에 있습니다. Line 25에서는 올바르게 res?.data로 접근하지만, Line 123은 일관성 없이 res.payment를 직접 접근하려 하므로 항상 undefined가 되어 결제 후 /payments/checkout/{id} 네비게이션이 실패합니다.

수정 제안
-                  const pid = res?.payment?._id || res?._id;
+                  const pid = res?.data?.payment?._id || res?.data?._id;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ContactPage.jsx` around lines 24 - 25, The payment ID lookup is
using the raw Axios response shape incorrectly (res?.payment?._id || res?._id)
while earlier code uses res?.data; update the logic to consistently read the
payload from res.data (e.g. const payload = res?.data || {}; then use
payload.payment?._id || payload._id) so the navigation to
/payments/checkout/{id} receives the actual ID returned by matchesApi.list /
payment API; adjust any references to res?.payment or res?._id to use
payload.payment and payload._id instead.

Comment thread src/stores/authStore.js
@BaeSeong-min BaeSeong-min merged commit 7503e12 into develop Apr 30, 2026
4 checks passed
@BaeSeong-min BaeSeong-min changed the title [Feat] axios 기반 공통 API 레이어 구축 [FEAT] axios 기반 공통 API 레이어 구축 Apr 30, 2026
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.

[Feat] axios 기반 공통 API 레이어 구축

1 participant