Skip to content
wooryeolPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

WMS Web - 창고 관리 시스템 (Warehouse Management System)

📌 프로젝트 개요

wms_web은 창고관리 시스템용 프론트엔드 애플리케이션입니다. 탭 기반 작업 흐름과 인증/토큰 관리, Keep-Alive 캐싱, 안정적인 네트워크 계층을 중심으로 설계되었습니다. React + TypeScript + Vite 환경에서 동작하며, @tanstack/react-query와 Zustand를 중심으로 데이터/상태를 관리합니다.

주요 특징

  • 🔄 탭 기반 작업 흐름: 복수 페이지를 탭 단위로 관리하여 빠른 전환과 상태 보존을 지원
  • 🔐 인증/토큰 관리: Axios 인터셉터로 액세스 토큰 자동 주입 및 refresh token 재발급 처리
  • 💾 Keep-Alive 캐시: 탭 이동 시 컴포넌트 상태를 보존하여 사용자 경험 향상
  • ⛔ Dirty State 보호: 미저장 변경 시 브라우저 새로고침/탭 이동 경고
  • 🎯 타입 안전성: TypeScript 기반 설계로 안정적인 코드 유지
  • 🌐 데이터 계층 분리: API / query / mutation / 캐시 invalidation을 명확히 분리

🛠 기술 스택

프레임워크

  • React 19.2.4
  • TypeScript ~6.0.2
  • Vite 8.0.4

상태 및 데이터

  • Zustand 5.0.12
  • @tanstack/react-query 5.99.0

UI / 스타일

  • @mui/material 9.0.1
  • @mui/icons-material 9.0.1
  • Tailwind CSS 4.2.2
  • @emotion/react 11.14.0
  • @emotion/styled 11.14.1
  • react-hook-form 7.75.0

네트워크 / 라우팅

  • axios 1.15.1
  • react-router-dom 7.14.2
  • qs 6.15.1

개발 도구

  • ESLint + Prettier
  • Babel
  • PostCSS + Tailwind
  • @vitejs/plugin-react

🔧 핵심 구조

앱 진입점

  • src/main.tsx: 앱 시작점, 글로벌 Provider 등록
  • src/App.tsx: 라우터 기반 앱 구조

전역 Provider

  • src/app/providers/QueryClient.ts: React Query 전역 설정
  • src/app/providers/QueryProvider.tsx: QueryClientProvider 등록
  • src/app/providers/ThemeProvider.tsx: MUI + 테마 적용
  • src/app/providers/ToastProviders.tsx: 전역 toast 환경 구성
  • src/app/providers/RouterProvider.tsx: 라우터 최상위 Provider
  • src/app/providers/ErrorBoundaryProvider.tsx: 최상위 렌더링 레벨 에러 처리 Provider

상태 관리

  • src/app/store/authStore.ts: 인증 토큰, 권한, 로그인 상태
  • src/app/store/tabStore.ts: 탭 목록 및 활성 탭 관리
  • src/app/store/dirtyStore.ts: 폼/데이터 변경 감지
  • src/app/store/keepAliveStore.ts: 컴포넌트 Keep-Alive 캐시
  • src/app/store/uiStore.ts: 글로벌 로딩 상태

라우터 및 UI 안정성

  • src/app/router/KeepAliveCache.ts: 탭별 컴포넌트 캐싱
  • src/app/router/TabRouterSync.ts: URL-탭 상태 동기화
  • src/app/router/ProtectedRoute.tsx: 인증/권한 보호
  • src/app/router/TabErrorBoundary.tsx: 탭 단위 에러 격리
  • src/app/hooks/useBeforeUnload.ts: 페이지 나가기 차단
  • src/app/hooks/useRouterBlocker.ts: 라우터 전환 차단

API 레이어

  • src/shared/api/client/axiosClient.ts: 공통 API 인스턴스
  • src/shared/api/client/authClient.ts: 로그인/refresh 전용 인스턴스
  • src/shared/api/utils/fetcher.ts: API 응답 표준화
  • src/shared/api/error/ApiError.ts: 공통 API 예외
  • src/shared/api/error/errorCode.ts: 에러 코드 정의
  • src/shared/api/error/errorHandler.ts: 인증/세션 검사 유틸
  • src/shared/api/interceptor/requestInterceptor.ts: 요청 전처리
  • src/shared/api/interceptor/responseInterceptor.ts: 응답 후처리
  • src/shared/api/auth/refreshTokenService.ts: refresh token 로직
  • src/shared/api/auth/sessionService.ts: 세션 만료 처리

Query / Mutation 레이어

  • src/shared/lib/query/createQueryKeys.ts: query key factory
  • src/shared/lib/query/createListQueryOptions.ts: 리스트 query 옵션
  • src/shared/lib/query/createMutationOptions.ts: mutation 옵션 공통화
  • src/shared/lib/query/invalidation.ts: query invalidation helper
  • src/shared/lib/query/normalizeParams.ts: 파라미터 정규화
  • src/shared/lib/toast/toastHandler.ts: API 오류 toast 연결

📁 주요 폴더 구조

src/
├── App.tsx
├── index.css
├── main.tsx
├── app/
│   ├── hooks/
│   │   ├── useBeforeUnload.ts
│   │   └── useRouterBlocker.ts
│   ├── providers/
│   │   ├── ErrorBoundaryProvider.tsx
│   │   ├── QueryClient.ts
│   │   ├── QueryProvider.tsx
│   │   ├── RouterProvider.tsx
│   │   ├── ThemeProvider.tsx
│   │   └── ToastProviders.tsx
│   ├── router/
│   │   ├── index.tsx
│   │   ├── KeepAliveCache.ts
│   │   ├── ProtectedRoute.tsx
│   │   ├── routerConfig.ts
│   │   ├── routes.tsx
│   │   ├── TabErrorBoundary.tsx
│   │   └── TabRouterSync.tsx
│   ├── store/
│   │   ├── authStore.ts
│   │   ├── dirtyStore.ts
│   │   ├── index.ts
│   │   ├── keepAliveStore.ts
│   │   ├── tabStore.ts
│   │   └── uiStore.ts
│   └── theme/
│       ├── components.ts
│       ├── index.ts
│       ├── palette.ts
│       └── typography.ts
├── assets/
│   └── bg-login.png
├── components/
│   ├── common/
│   │   ├── button/
│   │   │   ├── BaseButton.tsx
│   │   │   ├── HeaderUserMenu.tsx
│   │   │   └── index.ts
│   │   ├── checkbox/
│   │   │   ├── BaseCheckbox.tsx
│   │   │   └── index.ts
│   │   ├── input/
│   │   │   ├── BaseInput.tsx
│   │   │   └── index.ts
│   │   └── modal/
│   │       ├── AlertModal.tsx
│   │       └── index.ts
│   ├── grid/
│   │   ├── BaseGrid.tsx
│   │   └── DataInfoGrid.tsx
│   ├── layout/
│   │   ├── DashboardLayout.tsx
│   │   ├── Header.tsx
│   │   ├── Layout.tsx
│   │   ├── Sidebar.tsx
│   │   ├── TabLayout.tsx
│   │   └── Tabs.tsx
│   └── pagination/
│       └── Basepagination.tsx
├── pages/
│   ├── Dashboard/
│   │   └── ui/
│   │       └── DashboardPage.tsx
│   ├── Inbound/
│   │   └── ui/
│   │       └── InboundPage.tsx
│   ├── Login/
│   │   ├── api/
│   │   │   └── loginApi.ts
│   │   ├── hooks/
│   │   │   └── useLogin.ts
│   │   ├── model/
│   │   │   ├── loginMutation.ts
│   │   │   ├── loginTypes.ts
│   │   │   ├── mutationKeys.ts
│   │   │   └── useLoginMutation.ts
│   │   └── ui/
│   │       └── LoginPage.tsx
│   ├── Outbound/
│   │   └── ui/
│   │       └── OutboundPage.tsx
│   └── Test/
│       ├── api/
│       │   └── testApi.tsx
│       ├── hooks/
│       │   └── useTest.ts
│       ├── model/
│       │   ├── mutationKeys.ts
│       │   ├── queryKeys.ts
│       │   ├── testMutations.ts
│       │   ├── testQueries.ts
│       │   ├── testTypes.ts
│       │   ├── useTestQuery.ts
│       │   └── useUpdateTestMutation.ts
│       └── ui/
│           └── TestPage.tsx
└── shared/
    ├── api/
    │   ├── auth/
    │   │   ├── refreshTokenService.ts
    │   │   ├── sessionService.ts
    │   │   └── sessionTimer.ts
    │   ├── client/
    │   │   ├── authClient.ts
    │   │   └── axiosClient.ts
    │   ├── error/
    │   │   ├── ApiError.ts
    │   │   ├── errorCode.ts
    │   │   └── errorHandler.ts
    │   ├── interceptor/
    │   │   ├── refreshQueue.ts
    │   │   ├── requestInterceptor.ts
    │   │   └── responseInterceptor.ts
    │   ├── types/
    │   │   └── responseTypes.ts
    │   └── utils/
    │       └── fetcher.ts
    ├── config/
    │   └── tab.ts
    ├── constants/
    │   ├── message.ts
    │   ├── roles.ts
    │   ├── routes.ts
    │   └── stogare.ts
    ├── hooks/
    │   ├── useActiveTab.ts
    │   └── useFormDirty.ts
    ├── lib/
    │   ├── query/
    │   │   ├── createListQueryOptions.ts
    │   │   ├── createMutationOptions.ts
    │   │   ├── createQueryKeys.ts
    │   │   ├── invalidation.ts
    │   │   ├── normalizeParams.ts
    │   │   └── paginationTypes.ts
    │   ├── toast/
    │   │   ├── toast.ts
    │   │   ├── toastHandler.ts
    │   │   └── toastMessage.ts
    │   └── ui/
    │       └── ErrorFallback.tsx
    ├── styles/
    │   └── globals.css
    └── utils/
        └── sha512.ts

🧠 Query Architecture

wms_web의 데이터 조회 계층은 @tanstack/react-query를 중심으로 설계되어 있습니다.

핵심 전략

  • 도메인별 query key factory로 일관된 쿼리 키 생성
  • 탭 ID를 포함하여 탭별 캐시 분리
  • 활성 탭 전용 요청, 비활성 탭에서는 쿼리 취소
  • QueryClient 기본 설정으로 캐시/재요청 정책 통제

주요 컴포넌트

  • QueryClient.ts
    • staleTime: 1분
    • gcTime: 5분
    • refetchOnWindowFocus: false
    • refetchOnReconnect: true
    • retry: 1
    • throwOnError: false
  • createQueryKeys.ts
    • 도메인별 list, listBy, detail, search 등의 key factory
  • createListQueryOptions.ts
    • 파라미터 정규화
    • queryKey에 tabId 병합
    • 리스트 조회 옵션 일관화
  • useTestQuery.ts
    • enabled 제어로 활성 탭에서만 fetch
    • 비활성 탭에서는 cancelQueries() 호출
    • 다시 활성화 시 query.isStale 기반 refetch()

작동 흐름

  1. 화면 훅에서 queryOptions 생성
  2. useQuery() 호출 및 캐시 확인
  3. 필요한 경우 API 호출 수행
  4. 결과는 react-query 캐시에 저장되어 재사용

🔄 Mutation Architecture

Mutation 계층은 API 변경 작업을 표준화하고 후처리를 공통화합니다.

핵심 전략

  • mutation은 model 레이어에서 정의하고, hook에서 useMutation으로 감싼다
  • 성공 시 관련 쿼리를 invalidation하여 최신 데이터 유지
  • 실패 시 공통 toast 에러 처리
  • CUD 작업은 재시도를 최소화

주요 컴포넌트

  • mutationKeys.ts: 도메인별 mutation key 생성
  • testMutations.ts, loginMutation.ts: mutation 정의
  • useUpdateTestMutation.ts, useLoginMutation.ts: mutation hook
  • createMutationOptions.ts
    • queryClient와 invalidateKeys 연결
    • successMessage 자동 toast
    • showApiError() 공통 에러 처리

예시

  • useUpdateTestMutation은 testKeys.list()를 invalidation하여 테스트 리스트를 갱신
  • useLoginMutation은 로그인 성공 시 authStore에 토큰/role 저장

🌐 API Layer

구조

  • 공통 API: axiosClient.ts
  • 인증 전용 API: authClient.ts
  • fetcher: fetcher.ts
  • 에러/로그인 관리: errorHandler.ts, ApiError.ts, errorCode.ts
  • 토큰 갱신: refreshTokenService.ts
  • 세션 만료: sessionService.ts

axiosClient 특징

  • 기본 URL: VITE_API_BASE_URL
  • timeout 360초
  • Content-Type: application/json
  • qs 기반 params serializer
  • request/response interceptor 등록

인증/토큰 처리

  • request interceptor
    • Authorization 헤더 자동 주입
    • 로딩 상태 증가/감소
    • multipart/form-data 제외 body wrapping
    • POST/PUT/PATCH 요청 body를 { data: ... } 형태로 래핑
  • response interceptor
    • 세션 만료 시 로그아웃 및 로그인 화면 이동
    • 액세스 토큰 만료 시 refresh token 흐름 실행
    • 동시 요청 시 refresh token 큐 처리

fetcher 및 에러

  • fetcher.ts는 API response code가 1000일 때만 데이터를 반환
  • 비즈니스 에러 시 ApiError throw
  • showApiError()는 ApiError 코드에 따라 toast 메시지 매핑

🧩 UI / Stability

탭 기반 UX

  • KeepAliveCache로 탭 간 컴포넌트 상태 유지
  • TabRouterSync로 URL과 탭 상태 동기화
  • TabErrorBoundary로 탭 단위 에러 격리

안정성/보호

  • useBeforeUnload와 useRouterBlocker로 미저장 변경 보호
  • dirtyStore로 변경 상태 중앙 관리
  • uiStore로 글로벌 로딩/로딩 카운트 관리
  • authStore로 인증 상태 동기화

UI 구성

  • MUI + Tailwind 기반 UI
  • ThemeProvider로 디자인 토큰 적용
  • ToastProviders로 전역 알림 구성
  • Header, Sidebar, TabLayout 등의 공통 레이아웃 컴포넌트

🚀 실행 방법

npm install
npm run dev

브라우저에서 http://localhost:5173로 접근하세요.

프로덕션 빌드

npm run build
npm run preview

⚙️ 환경 변수

  • VITE_API_BASE_URL: 백엔드 API 기본 URL

📌 주의 사항

  • 인증 요청과 refresh 요청을 분리한 authClient로 인터셉터 순환 문제 방지
  • react-query query key는 탭 ID를 포함해 탭별 캐시 분리
  • createMutationOptions로 success toast, invalidation, 공통 오류 처리를 일관되게 적용

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages