- PC/Mobile 404 페이지 구현 - App.jsx에 catch-all 라우트 추가 - pages/common/ 폴더 구조 생성 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
13 KiB
13 KiB
Express → Fastify 마이그레이션
개요
backend-backup/ (Express) → backend/ (Fastify)로 마이그레이션 완료
완료된 작업
서버 기반
- Fastify 앱 구조 (
src/app.js,src/server.js) - 플러그인 시스템 (
src/plugins/)- db.js (MariaDB)
- redis.js
- auth.js (JWT)
- meilisearch.js
- scheduler.js (봇 스케줄러)
API 라우트 (src/routes/)
- 인증 (
/api/auth)- POST /login - 로그인
- GET /verify - 토큰 검증
- 멤버 (
/api/members)- GET / - 목록 조회
- GET /:name - 상세 조회
- PUT /:name - 수정 (이미지 업로드 포함)
- 앨범 (
/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 - 삭제
- 일정 (
/api/schedules)- GET / - 월별 조회 (생일 포함)
- GET /?search= - Meilisearch 검색
- GET /:id - 상세 조회
- DELETE /:id - 삭제
- POST /sync-search - Meilisearch 동기화
- 추천 검색어 (
/api/schedules/suggestions)- GET / - 추천 검색어 조회
- GET /popular - 인기 검색어 조회
- POST /save - 검색어 저장
- GET /dict - 사용자 사전 조회 (관리자)
- PUT /dict - 사용자 사전 저장 (관리자)
- 통계 (
/api/stats)- GET / - 대시보드 통계
관리자 API (src/routes/admin/)
- 봇 관리 (
/api/admin/bots)- GET / - 봇 목록
- POST /:id/start - 봇 시작
- POST /:id/stop - 봇 정지
- POST /:id/sync-all - 전체 동기화
- GET /quota-warning - 할당량 경고 조회
- DELETE /quota-warning - 할당량 경고 해제
- YouTube 관리 (
/api/admin/youtube)- GET /video-info - 영상 정보 조회
- POST /schedule - 일정 저장
- PUT /schedule/:id - 일정 수정
- X 관리 (
/api/admin/x)- GET /post-info - 게시글 정보 조회
- POST /schedule - 일정 저장
서비스 (src/services/)
- YouTube 봇 (
services/youtube/)- 영상 자동 수집
- 채널별 필터링 (제목 필터, 멤버 추출)
- X(Twitter) 봇 (
services/x/)- Nitter 스크래핑
- 이미지 URL 추출
- Meilisearch 검색 (
services/meilisearch/)- 일정 검색
- 전체 동기화
- 추천 검색어 (
services/suggestions/)- 형태소 분석 (kiwi-nlp)
- bi-gram 빈도
- 초성 검색
- 사용자 사전 관리
- 이미지 업로드 (
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/ (신규)로 점진적 마이그레이션
설계 원칙
-
react-device-detect 사용
- App.jsx에서
BrowserView/MobileView로 PC/Mobile 완전 분리 - User Agent 기반 디바이스 감지
- App.jsx에서
-
기능별 폴더 + pc/mobile 하위 폴더
- 각 페이지 폴더 내에
pc/,mobile/서브폴더 - 비즈니스 로직(api, hooks, stores)은 최상위에서 공유
- 각 페이지 폴더 내에
-
React Query 사용
useQuery로 데이터 패칭 및 캐싱
-
관리자 페이지는 PC 전용
- mobile 폴더 없이 단일 구조
App.jsx 라우팅 구조
import { BrowserView, MobileView } from 'react-device-detect';
function App() {
return (
<BrowserRouter>
<BrowserView>
<Routes>
{/* Admin routes */}
<Route path="/admin" element={<AdminLogin />} />
<Route path="/admin/*" element={<AdminRoutes />} />
{/* Public routes with PC Layout */}
<Route element={<PCLayout />}>
<Route path="/" element={<PCHome />} />
<Route path="/members" element={<PCMembers />} />
<Route path="/album" element={<PCAlbum />} />
<Route path="/album/:name" element={<PCAlbumDetail />} />
...
</Route>
</Routes>
</BrowserView>
<MobileView>
<Routes>
<Route element={<MobileLayout />}>
<Route path="/" element={<MobileHome />} />
<Route path="/members" element={<MobileMembers />} />
...
</Route>
</Routes>
</MobileView>
</BrowserRouter>
);
}
전체 마이그레이션 체크리스트
API 계층
공개 API
- client.js (fetchApi, fetchAuthApi)
- albums.js
- members.js
- schedules.js
- auth.js
관리자 API (api/admin/)
- albums.js
- members.js
- schedules.js
- categories.js
- stats.js
- bots.js
- suggestions.js
훅 (hooks/)
- useAlbumData.js
- useMemberData.js
- useScheduleData.js
- useScheduleSearch.js
- useScheduleFiltering.js
- useCalendar.js
- useMediaQuery.js
- useAdminAuth.js
- useToast.js (Toast 컴포넌트는 있으나 훅은 미구현)
스토어 (stores/)
- useScheduleStore.js
- useAuthStore.js
- useUIStore.js
상수 (constants/)
- index.js (CATEGORY_ID, MIN_YEAR, SEARCH_LIMIT 등)
유틸리티 (utils/)
- index.js
- date.js
- format.js
- cn.js (className 유틸)
- schedule.js (일정 관련 유틸)
공통 컴포넌트 (components/common/)
- Loading.jsx
- ErrorBoundary.jsx
- Toast.jsx
- Lightbox.jsx
- LightboxIndicator.jsx
- Tooltip.jsx
- ScrollToTop.jsx
PC 컴포넌트 (components/pc/)
- Layout.jsx
- Header.jsx
- Footer.jsx
- Calendar.jsx
- ScheduleCard.jsx
- BirthdayCard.jsx
- CategoryFilter.jsx
Mobile 컴포넌트 (components/mobile/)
- Layout.jsx
- Calendar.jsx
- ScheduleCard.jsx
- ScheduleListCard.jsx
- ScheduleSearchCard.jsx
- BirthdayCard.jsx
공용 일정 컴포넌트 (components/schedule/)
- confetti.js (fireBirthdayConfetti)
- AdminScheduleCard.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
- sections/utils.js
- sections/index.js
- pc/Schedule.jsx
- pc/ScheduleDetail.jsx
- pc/Birthday.jsx
- mobile/Schedule.jsx
- mobile/ScheduleDetail.jsx
- mobile/Birthday.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 파일
- 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 사용 시
import { Swiper, SwiperSlide } from 'swiper/react';
import { Virtual } from 'swiper/modules';
import 'swiper/css';
- 사용 위치: mobile/Members, mobile/AlbumDetail, mobile/AlbumGallery
가상화 리스트
useVirtualizerfrom@tanstack/react-virtual- 사용 위치: mobile/Schedule, admin/AdminSchedule
교차 관찰자
useInViewfromreact-intersection-observer- 사용 위치: mobile/Schedule (무한 스크롤 트리거)
축하 효과
canvas-confetti- 생일 페이지 폭죽 효과- 사용 위치: pc/Birthday, mobile/Schedule (생일 일정)
색상 선택기
HexColorPickerfromreact-colorful- 사용 위치: admin/AdminScheduleCategory
앨범 갤러리
RowsPhotoAlbumfromreact-photo-album- 사용 위치: pc/AlbumGallery, mobile/AlbumGallery
Kakao API (미구현)
- 콘서트 장소 검색:
/api/admin/kakao/places - 환경변수:
VITE_KAKAO_JS_KEY - 사용 예정: 콘서트 일정 추가 시 장소 검색
마이그레이션 진행 상황
완료된 작업
- Phase 1: 프로젝트 셋업
- Phase 2: 유틸리티 및 상수
- Phase 3: Zustand 스토어
- Phase 4: API 계층 (공개 API)
- Phase 5: 커스텀 훅
- Phase 6: 공통 컴포넌트
- Phase 7: PC/Mobile 레이아웃 컴포넌트
- Phase 8: App.jsx (BrowserView/MobileView 라우팅)
- Phase 9: 공개 페이지 전체
- Home, Members, Album, AlbumDetail, AlbumGallery, TrackDetail
- Schedule, ScheduleDetail, Birthday
미완료 작업
공개 영역
- useToast 훅
관리자 영역 (별도 요청 시 진행)
- 관리자 API 전체 (api/admin/)
- 관리자 컴포넌트 전체 (components/admin/)
- 관리자 페이지 전체 (pages/admin/)
최종 검증
- 모든 라우트 동작 확인
- PC/Mobile 전환 테스트
- 관리자 기능 테스트
- frontend-temp → frontend 교체