# Express → Fastify 마이그레이션 ## 개요 `backend-backup/` (Express) → `backend/` (Fastify)로 마이그레이션 완료 ## 완료된 작업 ### 서버 기반 - [x] Fastify 앱 구조 (`src/app.js`, `src/server.js`) - [x] 플러그인 시스템 (`src/plugins/`) - db.js (MariaDB) - redis.js - auth.js (JWT) - meilisearch.js - scheduler.js (봇 스케줄러) ### API 라우트 (`src/routes/`) - [x] 인증 (`/api/auth`) - POST /login - 로그인 - GET /verify - 토큰 검증 - [x] 멤버 (`/api/members`) - GET / - 목록 조회 - GET /:name - 상세 조회 - PUT /:name - 수정 (이미지 업로드 포함) - [x] 앨범 (`/api/albums`) - GET / - 목록 조회 - GET /:id - ID로 조회 - GET /by-name/:name - 이름으로 조회 - GET /by-name/:albumName/track/:trackTitle - 트랙 조회 - POST / - 생성 - PUT /:id - 수정 - DELETE /:id - 삭제 - 사진 관리 (`/api/albums/:id/photos`) - GET / - 목록 - POST / - 업로드 - PUT /:photoId - 수정 - DELETE /:photoId - 삭제 - 티저 관리 (`/api/albums/:id/teasers`) - GET / - 목록 - POST / - 업로드 - DELETE /:teaserId - 삭제 - [x] 일정 (`/api/schedules`) - GET / - 월별 조회 (생일 포함) - GET /?search= - Meilisearch 검색 - GET /:id - 상세 조회 - DELETE /:id - 삭제 - POST /sync-search - Meilisearch 동기화 - [x] 추천 검색어 (`/api/schedules/suggestions`) - GET / - 추천 검색어 조회 - GET /popular - 인기 검색어 조회 - POST /save - 검색어 저장 - GET /dict - 사용자 사전 조회 (관리자) - PUT /dict - 사용자 사전 저장 (관리자) - [x] 통계 (`/api/stats`) - GET / - 대시보드 통계 ### 관리자 API (`src/routes/admin/`) - [x] 봇 관리 (`/api/admin/bots`) - GET / - 봇 목록 - POST /:id/start - 봇 시작 - POST /:id/stop - 봇 정지 - POST /:id/sync-all - 전체 동기화 - GET /quota-warning - 할당량 경고 조회 - DELETE /quota-warning - 할당량 경고 해제 - [x] YouTube 관리 (`/api/admin/youtube`) - GET /video-info - 영상 정보 조회 - POST /schedule - 일정 저장 - PUT /schedule/:id - 일정 수정 - [x] X 관리 (`/api/admin/x`) - GET /post-info - 게시글 정보 조회 - POST /schedule - 일정 저장 ### 서비스 (`src/services/`) - [x] YouTube 봇 (`services/youtube/`) - 영상 자동 수집 - 채널별 필터링 (제목 필터, 멤버 추출) - [x] X(Twitter) 봇 (`services/x/`) - Nitter 스크래핑 - 이미지 URL 추출 - [x] Meilisearch 검색 (`services/meilisearch/`) - 일정 검색 - 전체 동기화 - [x] 추천 검색어 (`services/suggestions/`) - 형태소 분석 (kiwi-nlp) - bi-gram 빈도 - 초성 검색 - 사용자 사전 관리 - [x] 이미지 업로드 (`services/image.js`) - 앨범 커버 - 멤버 이미지 - 앨범 사진/티저 ## 남은 작업 (미구현) ### 일반 일정 CRUD - [ ] POST /api/schedules - 일정 생성 (일반) - [ ] PUT /api/schedules/:id - 일정 수정 (일반) ※ 현재는 YouTube/X 전용 일정 생성 API만 구현됨 ### 카테고리 관리 - [ ] POST /api/schedule-categories - 생성 - [ ] PUT /api/schedule-categories/:id - 수정 - [ ] DELETE /api/schedule-categories/:id - 삭제 - [ ] PUT /api/schedule-categories-order - 순서 변경 ※ GET은 구현됨 (목록 조회) ### 기타 - [ ] GET /api/kakao/places - 카카오 장소 검색 프록시 ## 파일 비교표 | Express (backend-backup) | Fastify (backend) | 상태 | |--------------------------|-------------------|------| | routes/admin.js (로그인) | routes/auth.js | 완료 | | routes/admin.js (앨범 CRUD) | routes/albums/index.js | 완료 | | routes/admin.js (사진/티저) | routes/albums/photos.js, teasers.js | 완료 | | routes/admin.js (멤버 수정) | routes/members/index.js | 완료 | | routes/admin.js (일정 삭제) | routes/schedules/index.js | 완료 | | routes/admin.js (일정 생성/수정) | - | 미완료 | | routes/admin.js (카테고리 CUD) | - | 미완료 | | routes/admin.js (봇 관리) | routes/admin/bots.js | 완료 | | routes/admin.js (할당량) | routes/admin/bots.js | 완료 | | routes/admin.js (카카오) | - | 미완료 | | - | routes/admin/youtube.js | 신규 | | - | routes/admin/x.js | 신규 | | routes/albums.js | routes/albums/index.js | 완료 | | routes/members.js | routes/members/index.js | 완료 | | routes/schedules.js | routes/schedules/index.js | 완료 | | routes/stats.js | routes/stats/index.js | 완료 | | services/youtube-bot.js | services/youtube/ | 완료 | | services/youtube-scheduler.js | plugins/scheduler.js | 완료 | | services/x-bot.js | services/x/ | 완료 | | services/meilisearch.js | services/meilisearch/ | 완료 | | services/meilisearch-bot.js | services/meilisearch/ | 완료 | | services/suggestions.js | services/suggestions/ | 완료 | ## 참고 사항 - 기존 Express 코드는 `backend-backup/` 폴더에 보존 - 마이그레이션 시 기존 코드 참조하여 동일 기능 구현 - DB 스키마 변경 사항: - `tracks` → `album_tracks` (이름 변경) - `venues` → `concert_venues` (이름 변경) --- # 프론트엔드 마이그레이션 (Strangler Fig) ## 개요 `frontend/` (레거시) → `frontend-temp/` (신규)로 점진적 마이그레이션 ## 설계 원칙 1. **react-device-detect 사용** - App.jsx에서 `BrowserView`/`MobileView`로 PC/Mobile 완전 분리 - User Agent 기반 디바이스 감지 2. **기능별 폴더 + pc/mobile 하위 폴더** - 각 페이지 폴더 내에 `pc/`, `mobile/` 서브폴더 - 비즈니스 로직(api, hooks, stores)은 최상위에서 공유 3. **React Query 사용** - `useQuery`로 데이터 패칭 및 캐싱 4. **관리자 페이지는 PC 전용** - mobile 폴더 없이 단일 구조 ## App.jsx 라우팅 구조 ```jsx import { BrowserView, MobileView } from 'react-device-detect'; function App() { return ( {/* Admin routes */} } /> } /> {/* Public routes with PC Layout */} }> } /> } /> } /> } /> ... }> } /> } /> ... ); } ``` ## 전체 마이그레이션 체크리스트 ### API 계층 #### 공개 API - [x] client.js (fetchApi, fetchAuthApi) - [x] albums.js - [x] members.js - [x] schedules.js - [x] auth.js #### 관리자 API (`api/admin/`) - [ ] albums.js - [ ] members.js - [ ] schedules.js - [ ] categories.js - [ ] stats.js - [ ] bots.js - [ ] suggestions.js ### 훅 (hooks/) - [x] useAlbumData.js - [x] useMemberData.js - [x] useScheduleData.js - [x] useScheduleSearch.js - [x] useCalendar.js - [x] useAdminAuth.js - [ ] useToast.js ### 스토어 (stores/) - [x] useScheduleStore.js - [x] useAuthStore.js ### 유틸리티 (utils/) - [x] date.js - [x] format.js ### 공통 컴포넌트 (components/common/) - [x] Loading.jsx - [x] ErrorBoundary.jsx - [x] Toast.jsx - [x] Lightbox.jsx - [ ] LightboxIndicator.jsx - [ ] Tooltip.jsx - [ ] ScrollToTop.jsx ### PC 레이아웃 컴포넌트 (components/pc/) - [ ] Layout.jsx (Outlet 사용) - [ ] Header.jsx - [ ] Footer.jsx ### Mobile 레이아웃 컴포넌트 (components/mobile/) - [ ] Layout.jsx (Outlet 사용) - [ ] MobileNav.jsx ### 관리자 컴포넌트 (components/admin/) - [ ] AdminLayout.jsx - [ ] AdminHeader.jsx - [ ] ConfirmDialog.jsx - [ ] CustomDatePicker.jsx - [ ] CustomTimePicker.jsx - [ ] NumberPicker.jsx ### 페이지 - Home (pages/home/) - [ ] pc/Home.jsx - [ ] mobile/Home.jsx ### 페이지 - Members (pages/members/) - [ ] pc/Members.jsx - [ ] mobile/Members.jsx ### 페이지 - Album (pages/album/) - [ ] pc/Album.jsx - [ ] pc/AlbumDetail.jsx - [ ] pc/AlbumGallery.jsx - [ ] pc/TrackDetail.jsx - [ ] mobile/Album.jsx - [ ] mobile/AlbumDetail.jsx - [ ] mobile/AlbumGallery.jsx - [ ] mobile/TrackDetail.jsx ### 페이지 - Schedule (pages/schedule/) - [ ] sections/DefaultSection.jsx - [ ] sections/XSection.jsx - [ ] sections/YoutubeSection.jsx - [ ] pc/Schedule.jsx - [ ] pc/ScheduleDetail.jsx - [ ] pc/Birthday.jsx - [ ] mobile/Schedule.jsx - [ ] mobile/ScheduleDetail.jsx ### 페이지 - Common (pages/common/) - [ ] pc/NotFound.jsx - [ ] mobile/NotFound.jsx ### 페이지 - Admin (pages/admin/) - PC 전용 - [ ] Login.jsx - [ ] Dashboard.jsx - [ ] members/List.jsx - [ ] members/Edit.jsx - [ ] albums/List.jsx - [ ] albums/Form.jsx - [ ] albums/Photos.jsx - [ ] schedules/List.jsx - [ ] schedules/Form.jsx - [ ] schedules/YouTubeForm.jsx - [ ] schedules/XForm.jsx - [ ] schedules/YouTubeEditForm.jsx - [ ] categories/List.jsx - [ ] bots/Manager.jsx - [ ] dict/Manager.jsx ### 기타 - [ ] App.jsx (BrowserView/MobileView 라우팅) - [ ] main.jsx ### CSS 파일 - [x] index.css - [ ] mobile.css (모바일 전용 스타일, 달력 등) - [ ] pc.css (PC 전용 스타일) ### 기타 파일 - [ ] data/dummy.js (개발용 더미 데이터) - [ ] .env (VITE_KAKAO_JS_KEY - 콘서트 장소 검색용, 미구현) - [ ] public/favicon.ico ## 사용 라이브러리 (package.json) | 라이브러리 | 용도 | 사용 위치 | |-----------|------|----------| | react-device-detect | PC/Mobile 분기 | App.jsx | | @tanstack/react-query | 데이터 패칭 | 모든 페이지 | | @tanstack/react-virtual | 가상화 리스트 | 관리자 일정 목록 | | react-calendar | 캘린더 | 일정 페이지 | | react-colorful | 색상 선택 | 카테고리 관리 | | react-photo-album | 앨범 갤러리 | 앨범 갤러리 | | react-infinite-scroll-component | 무한 스크롤 | 일정 검색 | | react-intersection-observer | 뷰포트 감지 | 애니메이션 | | react-ios-time-picker | 시간 선택 | 일정 폼 | | react-linkify | URL 자동 링크 | 일정 상세 | | react-window | 가상화 리스트 | 긴 목록 | | swiper | 슬라이더 | 앨범 상세 | | canvas-confetti | 축하 효과 | 생일 페이지 | | framer-motion | 애니메이션 | 전체 | | dayjs | 날짜 처리 | 전체 | | zustand | 상태 관리 | 전체 | ## 특수 패턴 및 주의사항 ### React Query 고급 사용 - `useInfiniteQuery` - 일정 검색 무한 스크롤 (mobile/Schedule) - `useQuery` - 일반 데이터 패칭 ### Swiper 사용 시 ```jsx import { Swiper, SwiperSlide } from 'swiper/react'; import { Virtual } from 'swiper/modules'; import 'swiper/css'; ``` - 사용 위치: mobile/Members, mobile/AlbumDetail, mobile/AlbumGallery ### 가상화 리스트 - `useVirtualizer` from `@tanstack/react-virtual` - 사용 위치: mobile/Schedule, admin/AdminSchedule ### 교차 관찰자 - `useInView` from `react-intersection-observer` - 사용 위치: mobile/Schedule (무한 스크롤 트리거) ### 축하 효과 - `canvas-confetti` - 생일 페이지 폭죽 효과 - 사용 위치: pc/Birthday, mobile/Schedule (생일 일정) ### 색상 선택기 - `HexColorPicker` from `react-colorful` - 사용 위치: admin/AdminScheduleCategory ### 앨범 갤러리 - `RowsPhotoAlbum` from `react-photo-album` - 사용 위치: pc/AlbumGallery, mobile/AlbumGallery ### Kakao API (미구현) - 콘서트 장소 검색: `/api/admin/kakao/places` - 환경변수: `VITE_KAKAO_JS_KEY` - 사용 예정: 콘서트 일정 추가 시 장소 검색 ## 마이그레이션 진행 상황 ### 완료된 작업 (재검토 필요) - [x] Phase 1: 프로젝트 셋업 - [x] Phase 2: 유틸리티 및 상수 - [x] Phase 3: Zustand 스토어 - [x] Phase 4: API 계층 (공개 API만) - [x] Phase 5: 커스텀 훅 (일부) - [x] Phase 6: 공통 컴포넌트 (일부) ### 구조 리팩토링 필요 - [ ] 기존 코드를 새 폴더 구조로 재배치 - [ ] App.jsx를 BrowserView/MobileView 구조로 변경 - [ ] 레이아웃 컴포넌트 분리 (components/pc, components/mobile) ### 미완료 작업 - [ ] 관리자 API 전체 - [ ] 관리자 컴포넌트 전체 - [ ] 관리자 페이지 전체 - [ ] 누락된 공통 컴포넌트 (LightboxIndicator, Tooltip, ScrollToTop) - [ ] 누락된 페이지 (AlbumDetail, AlbumGallery, TrackDetail, ScheduleDetail, Birthday) - [ ] 누락된 훅 (useToast) - [ ] PC/Mobile 페이지 분리 ### 최종 검증 - [ ] 모든 라우트 동작 확인 - [ ] PC/Mobile 전환 테스트 - [ ] 관리자 기능 테스트 - [ ] frontend-temp → frontend 교체