상태 관리
Lumie는 하나의 전역 스토어를 쓰지 않고 상태 계층에 따라 서로 다른 도구를 사용합니다.
상태 계층
| 상태 유형 | 주요 도구 | 현재 사용 방식 |
|---|---|---|
| 서버 상태 | TanStack Query | 세션, 목록, 상세 뷰, 대부분의 CRUD 기반 화면 |
| 폼 상태 | React Hook Form | 로그인, 회원가입, 온보딩, 설정, CRUD 다이얼로그, 다단계 폼 |
| 공유 클라이언트 UI 상태 | Zustand | 공유 인증 모달 상태 |
| 라우트 상태 | Next.js search params | 목록 필터, 정렬, 페이지네이션, 모달 진입 파라미터 |
| 로컬 일시 UI 상태 | React 컴포넌트 상태 | 초안 입력값, 다이얼로그 상태, 대기 중 액션, 뷰 토글 |
소스 경로
| 상태 경계 | 소스 경로 |
|---|---|
| Query 기본값과 서버/브라우저 client 분리 | lumie-frontend/src/shared/lib/query-client.ts |
| 루트 Query provider | lumie-frontend/src/shared/providers/QueryProvider.tsx |
| Orval fetch 브리지 | lumie-frontend/src/shared/api/orval-mutator.ts |
| 공유 API 요청과 refresh 재시도 | lumie-frontend/src/shared/api/base.ts |
| 서버 인증 상태 | lumie-frontend/src/entities/session/api/getServerUser.ts |
| 클라이언트 인증 모달 스토어 | lumie-frontend/src/shared/providers/AuthModalProvider.tsx |
| URL 기반 목록 상태 | lumie-frontend/src/entities/student/model/search-params.ts, lumie-frontend/src/shared/lib/useUrlPageParam.ts |
TanStack Query를 이용한 서버 상태
QueryProvider는 루트에서 QueryClientProvider를 한 번만 마운트합니다. getQueryClient()는 다음을 사용합니다.
- 서버 요청마다 새로운 query client
- 브라우저에서는 안정적인 singleton query client
기본 query 동작은 src/shared/lib/query-client.ts에서 중앙 정의됩니다.
- 서버
staleTime은 한 번의 SSR 패스에서 중복 fetch를 피하기 위해Infinity - 브라우저
staleTime은 5분 - query cache garbage collection은 10분 동안 warm 상태 유지
- window-focus refetch는 기본 비활성화
대부분의 API 읽기와 쓰기는 src/shared/api/orval-mutator.ts로 위임하는 Orval 생성 hook에서 옵니다. 이 mutator는 다시 공유 apiRequest()와 apiUpload() 헬퍼를 사용합니다. 생성된 클라이언트만으로 충분하지 않은 경우 수동 hook도 존재하지만, 같은 공유 fetch 기본 요소를 사용합니다.
세션 및 인증 상태
인증된 사용자 상태는 커스텀 전역 스토어에 저장하지 않습니다.
- 서버 레이아웃은 접근 제어를 위해
getServerUser()를 호출합니다. - 클라이언트 컴포넌트는
useMe()또는useMeQuery()를 사용합니다. apiRequest()는tryRefreshToken()으로 401 재시도를 처리합니다.sessionAccessor와sessionCache는shared에서 엔티티 코드를 import하지 않고도 공유 API 코드가 tenant slug를 읽고 세션 상태를 지우게 해줍니다.
이렇게 하면 인증 관심사를 여러 스토어에 중복시키지 않고 query 레이어 가까이에 둘 수 있습니다.
Zustand를 이용한 공유 클라이언트 UI 상태
Zustand는 현재 src/shared/providers/AuthModalProvider.tsx의 인증 모달에 사용됩니다. 이 스토어는 다음을 유지합니다.
- 로그인용 또는 회원가입용으로 모달이 열려 있는지
- 정제된
callbackUrl - 열기, 초기화, URL 기반 초기화를 위한 액션
스토어 범위는 의도적으로 좁습니다. 대부분의 페이지 수준 UI 상태는 여전히 해당 컴포넌트 로컬에 둡니다.