# 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 (
    <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
- [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 교체
