수강신청 연습 사이트 (SnuClear) 프론트엔드. React 19 + Vite + TypeScript, FSD(Feature-Sliced Design) 아키텍처.
- 빌드: Vite 7, TypeScript 5.9
- UI: React 19, React Router DOM 7, Recharts
- 상태관리: TanStack Query 5, Zustand 5
- 스타일: CSS Modules (컴포넌트별
.css파일) - HTTP: 네이티브 fetch 래퍼 (
src/shared/api/fetch.ts, Bearer 토큰, sessionStorage에 저장) - API 베이스:
https://snuclear-server.wafflestudio.com/(개발 시 vite proxy/api사용)
src/
├── app/ # 앱 진입점, 라우터, 프로바이더
├── pages/ # 페이지 컴포넌트 (라우트별)
├── widgets/ # 복합 UI 블록
├── features/ # 비즈니스 기능 단위
├── entities/ # 도메인 엔티티 (user 등)
└── shared/ # 공통 유틸, fetch API 래퍼 등
| 경로 | 설명 |
|---|---|
/practice-session/:sessionId |
연습 세션 상세 조회 |
/practice-results |
연습 세션 목록 |
/session-share?d=<base64> |
QR 공유 이미지 페이지 (인증 불필요) |
/mypage |
마이페이지 |
npm run dev # 개발 서버
npm run dev -- --host # 핸드폰 테스트용 (로컬 IP 노출)
npm run typecheck # 타입 체크
npm run build # 프로덕션 빌드핸드폰 테스트: 백엔드가 특정 IP만 허용하므로
snuclear.wafflestudio.com프로덕션에서 테스트. 롤백 필요 시 GitHub PR 페이지의 Revert 버튼 사용.
- JWT Bearer 토큰을
sessionStorage에 저장 (authToken키) src/shared/api/fetch.ts에서 요청 시 자동 첨부- 토큰은 탭/브라우저 세션 단위로 유지 (창 닫으면 만료)
src/features/auth/ui/ 의 컴포넌트로 라우트 레벨 보호. 비권한 시 /로 리다이렉트.
<RequireAuth>— 로그인 필요 (/cart,/registration,/enrollment-history,/mypage,/practice-results,/practice-session/:id)<RequireAdmin>— 어드민 권한 필요 (/admin)
어드민 유저도 일반 페이지 자유 접근 가능 (AuthProvider에서 강제 리다이렉트 제거됨).
src/pages/practice-session/index.tsx: 세션 데이터를 base64 인코딩 → QR 생성 (qrcode라이브러리)src/pages/session-share/index.tsx: URL 파라미터 디코딩 → Canvas API로 카드 이미지 생성 →<img>표시- 인증 불필요, 데이터가 URL에 포함되어 있음
- push/PR 시 반드시
user983740계정 사용 (gh auth status로 확인 후 진행) - 계정이 다르면:
gh auth switch --user user983740
- 컴포넌트: PascalCase, 파일명
index.tsx - CSS: 컴포넌트 옆에 동명
.css파일 - API 함수:
src/entities/{domain}/api/또는src/features/{feature}/api/ - 타입:
src/entities/{domain}/model/types.ts