fromis_9/frontend/src/App.jsx
caadiq e852f215a3 feat: 보안 강화 및 인증 개선 (Phase 2)
- 로그인 Rate Limit 추가 (5회/분, 마지막 시도 기준 리셋)
- Multipart JSON 파싱 에러 처리 추가
- 로그아웃 시 무한 리다이렉트 버그 수정
- 인증 라우트 가드(RequireAuth) 추가로 비로그인 접근 차단
- Zustand hydration 대기로 페이지 깜빡임 해결
- admin/public 라우트 조건부 렌더링으로 경로 매칭 경고 해결

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 20:47:05 +09:00

67 lines
1.5 KiB
JavaScript

import { useEffect } from 'react';
import { BrowserRouter, useLocation } from 'react-router-dom';
import { BrowserView, MobileView } from 'react-device-detect';
// 공통 컴포넌트
import { ScrollToTop } from '@/components/common';
// 라우트
import { PCPublicRoutes, PCAdminRoutes, MobileRoutes } from '@/routes';
// 스토어
import { useAuthStore } from '@/stores';
/**
* PC 환경에서 body에 클래스 추가하는 래퍼
*/
function PCWrapper({ children }) {
useEffect(() => {
document.body.classList.add('is-pc');
return () => document.body.classList.remove('is-pc');
}, []);
return children;
}
/**
* PC 라우트 - admin 경로일 때만 AdminRoutes 렌더링
*/
function PCRoutes() {
const location = useLocation();
const isAdminPath = location.pathname.startsWith('/admin');
const { _hasHydrated } = useAuthStore();
// admin 경로에서 hydration 완료 전까지 빈 화면
if (isAdminPath && !_hasHydrated) {
return null;
}
return (
<PCWrapper>
{isAdminPath ? <PCAdminRoutes /> : <PCPublicRoutes />}
</PCWrapper>
);
}
/**
* 프로미스나인 팬사이트 메인 앱
* react-device-detect를 사용한 PC/Mobile 분리
*/
function App() {
return (
<BrowserRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
<ScrollToTop />
{/* PC 뷰 */}
<BrowserView>
<PCRoutes />
</BrowserView>
{/* Mobile 뷰 */}
<MobileView>
<MobileRoutes />
</MobileView>
</BrowserRouter>
);
}
export default App;