swiperRef.current?.slideTo(i)}
- width={120}
-/>
-```
-
-### 2열 지그재그 Masonry 그리드
-
-```jsx
-// 1,3,5번 → 왼쪽 열 / 2,4,6번 → 오른쪽 열
-const distributePhotos = () => {
- const leftColumn = [];
- const rightColumn = [];
- photos.forEach((photo, index) => {
- if (index % 2 === 0) leftColumn.push({ ...photo, originalIndex: index });
- else rightColumn.push({ ...photo, originalIndex: index });
- });
- return { leftColumn, rightColumn };
-};
-```
-
-### 뒤로가기 처리 패턴
-
-```jsx
-// 모달/라이트박스 열 때 히스토리 추가
-const openLightbox = useCallback((images, index, options = {}) => {
- setLightbox({ open: true, images, index, ...options });
- window.history.pushState({ lightbox: true }, "");
-}, []);
-
-// popstate 이벤트로 닫기
-useEffect(() => {
- const handlePopState = () => {
- if (showModal) setShowModal(false);
- else if (lightbox.open) setLightbox((prev) => ({ ...prev, open: false }));
- };
- window.addEventListener("popstate", handlePopState);
- return () => window.removeEventListener("popstate", handlePopState);
-}, [showModal, lightbox.open]);
-
-// X 버튼도 history.back() 호출
-;
-```
-
-### 바텀시트 (정보 표시)
-
-```jsx
- {
- if (info.offset.y > 100 || info.velocity.y > 300) {
- window.history.back();
- }
- }}
- className="bg-zinc-900 rounded-t-3xl"
->
- {/* 드래그 핸들 */}
-
- {/* 내용 */}
-
-```
-
----
-
-## 14. Redis 기반 Bi-gram 추천 검색어 시스템
-
-### 아키텍처 개요
-
-```mermaid
-graph LR
- User[사용자 검색] --> API[/api/schedules/suggestions]
- API --> Redis[(Redis)]
- Redis --> |bi-gram 매칭| Results[추천 검색어]
-
- Admin[관리자 일정 CRUD] --> Extract[키워드 추출]
- Extract --> Redis
-```
-
-### 주요 파일
-
-| 파일 | 설명 |
-| ----------------------------------------------- | ---------------------------------------------- |
-| `backend/routes/schedules.js` | 추천 검색어 API (`/api/schedules/suggestions`) |
-| `backend/scripts/extract-keywords.js` | 기존 일정에서 키워드 일괄 추출 스크립트 |
-| `frontend/src/pages/pc/admin/Schedule.jsx` | 관리자 검색창 드롭다운 |
-| `frontend/src/pages/pc/public/Schedule.jsx` | PC 검색 추천 UI |
-| `frontend/src/pages/mobile/public/Schedule.jsx` | 모바일 유튜브 스타일 추천 리스트 |
-
-### Redis 데이터 구조
-
-```
-fromis9:search:suggestions (Sorted Set)
-├── "쇼케이스" → score: 15
-├── "팬미팅" → score: 12
-├── "라디오" → score: 8
-└── ...
-
-fromis9:search:bigrams (Hash)
-├── "쇼케" → "쇼케이스,쇼케이스투어"
-├── "케이" → "쇼케이스,케이팝"
-└── ...
-```
-
-### API 엔드포인트
-
-```javascript
-// GET /api/schedules/suggestions?q=쇼케
-// Response: ["쇼케이스", "쇼케이스 투어", ...]
-
-router.get("/suggestions", async (req, res) => {
- const query = req.query.q?.trim();
- if (!query || query.length < 2) return res.json([]);
-
- // bi-gram 매칭
- const bigram = query.slice(0, 2);
- const cached = await redis.hget("fromis9:search:bigrams", bigram);
-
- if (cached) {
- const keywords = cached
- .split(",")
- .filter((k) => k.toLowerCase().includes(query.toLowerCase()))
- .slice(0, 10);
- return res.json(keywords);
- }
-
- res.json([]);
-});
-```
-
-### 키워드 추출 로직 (일정 저장 시)
-
-```javascript
-// admin.js - 일정 저장 시 키워드 추출
-const extractKeywords = (title) => {
- // 특수문자 제거, 공백으로 분리
- const words = title.replace(/[^\w\s가-힣]/g, " ").split(/\s+/);
- return words.filter((w) => w.length >= 2);
-};
-
-// Redis에 저장
-for (const keyword of keywords) {
- await redis.zincrby("fromis9:search:suggestions", 1, keyword);
-
- // bi-gram 인덱스
- for (let i = 0; i < keyword.length - 1; i++) {
- const bigram = keyword.slice(i, i + 2);
- const existing = await redis.hget("fromis9:search:bigrams", bigram);
- const set = new Set(existing ? existing.split(",") : []);
- set.add(keyword);
- await redis.hset("fromis9:search:bigrams", bigram, [...set].join(","));
- }
-}
-```
-
-### 프론트엔드 UI
-
-#### PC 관리자/공개 페이지 - 드롭다운
-
-```jsx
-// 검색창 아래 드롭다운
-{
- suggestions.length > 0 && (
-
- {suggestions.map((s, i) => (
-
- ))}
-
- );
-}
-```
-
-#### 모바일 - 유튜브 스타일 리스트
-
-```jsx
-// 검색창 아래 전체 화면 리스트
-{
- showSuggestions && suggestions.length > 0 && (
-
- {suggestions.map((s, i) => (
-
- ))}
-
- );
-}
-```
-
-### 키워드 일괄 추출 스크립트
-
-```bash
-# 기존 일정에서 키워드 추출하여 Redis에 저장
-cd /docker/fromis_9/backend
-node scripts/extract-keywords.js
-```
-
----
-
-## 15. 모바일 앱 (`/app`)
-
-### 기술 스택
-
-| 계층 | 기술 |
-| -------------- | ------------------------------------------------------------------------ |
-| **프레임워크** | Expo (React Native) |
-| **언어** | TypeScript |
-| **네비게이션** | React Navigation (Tab + Stack) |
-| **UI 효과** | expo-blur, expo-linear-gradient, react-native-color-matrix-image-filters |
-| **미디어** | expo-file-system, expo-media-library, react-native-pager-view |
-
-### 디렉토리 구조
-
-```
-app/src/
-├── api/ # API 호출 함수
-│ ├── albums.ts # 앨범 API (AlbumPhoto에 width/height 포함)
-│ ├── members.ts # 멤버 API
-│ └── schedules.ts # 일정 API
-├── components/ # 공통 컴포넌트
-│ └── common/
-│ └── Header.tsx # 공통 헤더 (title, showBack, rightElement)
-├── constants/
-│ └── colors.ts # 테마 색상 (primary: #FF4D8D)
-├── navigation/
-│ └── AppNavigator.tsx # 탭 + 스택 네비게이션
-└── screens/
- ├── HomeScreen.tsx # 홈 (멤버, 앨범, 일정 요약)
- ├── MembersScreen.tsx # 멤버 목록 + 바텀시트 상세
- ├── AlbumScreen.tsx # 앨범 목록 (2열 그리드)
- ├── AlbumDetailScreen.tsx # 앨범 상세 (트랙, 티저, 포토)
- ├── AlbumGalleryScreen.tsx # 컨셉포토 갤러리 (라이트박스)
- └── ScheduleScreen.tsx # 일정 목록
-```
-
-### 네비게이션 구조
-
-```mermaid
-graph TB
- TabNav[TabNavigator 하단 탭]
- TabNav --> HomeTab[홈]
- TabNav --> MembersTab[멤버]
- TabNav --> AlbumTab[앨범]
- TabNav --> ScheduleTab[일정]
-
- AlbumTab --> AlbumStack[AlbumStackNavigator]
- AlbumStack --> AlbumList[AlbumScreen]
- AlbumStack --> AlbumDetail[AlbumDetailScreen]
- AlbumStack --> AlbumGallery[AlbumGalleryScreen]
-```
-
-### 주요 기능
-
-#### 탭 전환 시 앨범 스택 리셋
-
-```tsx
-// AppNavigator.tsx
- ({
- tabPress: (e) => {
- // 앨범 탭 클릭 시 스택을 루트(목록)으로 리셋
- navigation.navigate("AlbumTab", { screen: "AlbumList" });
- },
- })}
-/>
-```
-
-#### AlbumGalleryScreen (컨셉포토 라이트박스)
-
-- **PagerView**: 스와이프로 이미지 탐색
-- **페이지 인디케이터**: `n / total` 형식
-- **다운로드 기능**: `expo-file-system` + `expo-media-library`
-- 웹 버전과 1:1 동일한 UI
-
-#### MembersScreen (멤버 상세)
-
-- **바텀시트 모달**: PanResponder 드래그로 닫기
-- **전 멤버 흑백 처리**: `Grayscale` 필터
-- **글래스모피즘**: `BlurView` (intensity 30, dimezisBlurView)
-
-### 개발 명령어
-
-```bash
-# 개발 서버 실행
-cd /docker/fromis_9/app
-npx expo start --lan
-
-# Android APK 빌드
-npx expo run:android --variant release
-
-# 로컬 네이티브 빌드 (android/ 폴더에서)
-./gradlew assembleDebug
-```
-
-### 웹-앱 동기화 체크리스트
-
-| 화면 | 웹 경로 | 앱 파일 |
-| ----------- | -------------------------------- | ------------------------ |
-| 홈 | `mobile/public/Home.jsx` | `HomeScreen.tsx` |
-| 멤버 | `mobile/public/Members.jsx` | `MembersScreen.tsx` |
-| 앨범 목록 | `mobile/public/Album.jsx` | `AlbumScreen.tsx` |
-| 앨범 상세 | `mobile/public/AlbumDetail.jsx` | `AlbumDetailScreen.tsx` |
-| 앨범 갤러리 | `mobile/public/AlbumGallery.jsx` | `AlbumGalleryScreen.tsx` |
-| 일정 | `mobile/public/Schedule.jsx` | `ScheduleScreen.tsx` |
-
----
-
-## 16. 오늘 작업 요약 (2026-01-11 ~ 2026-01-12)
-
-### 최근 커밋 히스토리
-
-| 커밋 | 설명 |
-| --------- | ---------------------------------------------------------- |
-| `7e570d3` | 모바일 곡 상세: 뒤로가기 헤더 제거 |
-| `db6949d` | 모바일 곡 상세: YouTube 전체화면 시 자동 가로 회전 시도 |
-| `5f2c86b` | 모바일 곡 상세: 가사 더보기/접기 기능 추가, 하단 여백 조정 |
-| `e5d4036` | 모바일: 곡 상세 화면 구현 (TrackDetail 페이지) |
-| `67cd681` | PC 곡 상세: TITLE 배지를 노래 제목 옆으로 이동 |
-| `0232edc` | PC 곡 상세: 수록곡 섹션 디자인 개선 |
-| `4e52f79` | 백엔드: 트랙 상세 API 라우트 순서 수정 |
-| `b18183a` | 웹: PC 곡 상세 화면 구현 (TrackDetail 페이지) |
-| `dc65858` | 웹: AlbumDetail, AlbumGallery 페이지 useQuery로 리팩토링 |
-
-### 주요 변경 사항
-
-1. **곡 상세 화면 (PC/Mobile)**: 트랙 정보, 크레딧, 가사, 수록곡 목록, 뮤직비디오 임베드
-2. **트랙 상세 API**: `/api/albums/by-name/:albumName/track/:trackTitle` 엔드포인트 추가
-3. **useQuery 리팩토링**: AlbumDetail, AlbumGallery 페이지에 @tanstack/react-query 적용
-4. **모바일 UX 개선**: 가사 더보기/접기, YouTube 전체화면 시 자동 가로 회전
-
----
-
-## 17. 곡 상세 화면 (TrackDetail)
-
-### API 엔드포인트
-
-| 엔드포인트 | 메서드 | 설명 |
-| -------------------------------------------------- | ------ | --------------------- |
-| `/api/albums/by-name/:albumName/track/:trackTitle` | GET | 트랙 상세 + 앨범 정보 |
-
-### 반환 데이터
-
-```json
-{
- "id": 1,
- "title": "LIKE YOU BETTER",
- "track_number": 1,
- "is_title_track": 1,
- "duration": "3:05",
- "lyrics": "...",
- "lyricist": "Tomy, HANIHAS(XYXX), ...",
- "composer": "HONEY NOISE, ...",
- "arranger": "...",
- "music_video_url": "https://youtube.com/...",
- "album": {
- "id": 7,
- "title": "From Our 20's",
- "album_type": "미니 6집",
- "cover_medium_url": "..."
- },
- "otherTracks": [...]
-}
-```
-
-### 파일 구조
-
-| 플랫폼 | 파일 경로 | 주요 기능 |
-| ------ | -------------------------------------------------- | ------------------------------- |
-| PC | `frontend/src/pages/pc/public/TrackDetail.jsx` | 크레딧, 가사, 수록곡, MV 임베드 |
-| Mobile | `frontend/src/pages/mobile/public/TrackDetail.jsx` | 가사 더보기/접기, 자동 회전 |
-
-### 주요 기능
-
-- **뮤직비디오 임베드**: is_title_track인 경우 YouTube 영상 표시
-- **크레딧 줄바꿈**: 쉼표 기준으로 각 항목 분리
-- **가사 더보기 (모바일)**: 기본 일부만 표시, 버튼으로 전체 펼침
-- **수록곡 목록 (PC)**: 현재 곡 강조, 재생 시간 표시
-- **자동 가로 회전 (모바일)**: YouTube 전체화면 시 `screen.orientation.lock('landscape')`
diff --git a/docs/api.md b/docs/api.md
new file mode 100644
index 0000000..18a793a
--- /dev/null
+++ b/docs/api.md
@@ -0,0 +1,132 @@
+# API 명세
+
+Base URL: `/api`
+
+## 인증
+
+### POST /auth/login
+로그인 (JWT 토큰 발급)
+
+### GET /auth/me
+현재 사용자 정보 (인증 필요)
+
+---
+
+## 멤버
+
+### GET /members
+멤버 목록 조회
+
+### GET /members/:id
+멤버 상세 조회
+
+---
+
+## 앨범
+
+### GET /albums
+앨범 목록 조회
+
+### GET /albums/:id
+앨범 상세 조회
+
+---
+
+## 일정
+
+### GET /schedules
+일정 조회
+
+**Query Parameters:**
+- `year`, `month` - 월별 조회 (필수, search 없을 때)
+- `search` - 검색어 (Meilisearch 사용)
+- `offset`, `limit` - 페이징
+
+**월별 조회 응답:**
+```json
+{
+ "2026-01-18": {
+ "categories": [
+ { "id": 2, "name": "유튜브", "color": "#ff0033", "count": 3 }
+ ],
+ "schedules": [
+ {
+ "id": 123,
+ "title": "...",
+ "time": "19:00:00",
+ "category": { "id": 2, "name": "유튜브", "color": "#ff0033" },
+ "source_name": "fromis_9"
+ }
+ ]
+ }
+}
+```
+
+**검색 응답:**
+```json
+{
+ "schedules": [
+ {
+ "id": 123,
+ "title": "...",
+ "datetime": "2026-01-18T19:00:00",
+ "category": { "id": 2, "name": "유튜브", "color": "#ff0033" },
+ "source_name": "fromis_9",
+ "members": ["송하영"],
+ "_rankingScore": 0.95
+ }
+ ],
+ "total": 100,
+ "offset": 0,
+ "limit": 20,
+ "hasMore": true
+}
+```
+
+### GET /schedules/:id
+일정 상세 조회
+
+### POST /schedules/sync-search
+Meilisearch 전체 동기화 (인증 필요)
+
+---
+
+## 추천 검색어
+
+### GET /schedules/suggestions
+추천 검색어 조회
+
+**Query Parameters:**
+- `q` - 검색어 (2자 이상)
+- `limit` - 결과 개수 (기본 10)
+
+**응답:**
+```json
+{
+ "suggestions": ["송하영", "송하영 직캠", "하영"]
+}
+```
+
+---
+
+## 봇 상태
+
+### GET /bots
+봇 상태 조회
+
+---
+
+## 헬스 체크
+
+### GET /health
+서버 상태 확인
+
+---
+
+## API 문서
+
+### GET /docs
+Scalar API Reference UI
+
+### GET /docs/json
+OpenAPI JSON 스펙
diff --git a/docs/architecture.md b/docs/architecture.md
new file mode 100644
index 0000000..94a83b6
--- /dev/null
+++ b/docs/architecture.md
@@ -0,0 +1,100 @@
+# 프로젝트 구조
+
+## 디렉토리 구조
+
+```
+fromis_9/
+├── backend/ # Fastify 백엔드 (현재 사용)
+│ ├── src/
+│ │ ├── config/
+│ │ │ ├── index.js # 환경변수 통합 관리
+│ │ │ └── bots.js # 봇 설정 (YouTube, X)
+│ │ ├── plugins/ # Fastify 플러그인
+│ │ │ ├── db.js # MariaDB 연결
+│ │ │ ├── redis.js # Redis 연결
+│ │ │ ├── auth.js # JWT 인증
+│ │ │ ├── meilisearch.js # 검색 엔진
+│ │ │ └── scheduler.js # 봇 스케줄러
+│ │ ├── routes/ # API 라우트
+│ │ │ ├── auth/
+│ │ │ ├── members/
+│ │ │ ├── albums/
+│ │ │ ├── schedules/
+│ │ │ │ ├── index.js # 일정 조회/검색
+│ │ │ │ └── suggestions.js
+│ │ │ └── index.js # 라우트 등록
+│ │ ├── services/ # 비즈니스 로직
+│ │ │ ├── youtube/ # YouTube 봇
+│ │ │ ├── x/ # X(Twitter) 봇
+│ │ │ ├── meilisearch/ # 검색 서비스
+│ │ │ └── suggestions/ # 추천 검색어
+│ │ ├── app.js # Fastify 앱 설정
+│ │ └── server.js # 진입점
+│ └── package.json
+│
+├── backend-backup/ # Express 백엔드 (참조용, 마이그레이션 원본)
+│
+├── frontend/ # React 프론트엔드
+│ ├── src/
+│ │ ├── api/ # API 클라이언트
+│ │ │ ├── index.js # fetchApi 유틸
+│ │ │ ├── public/ # 공개 API
+│ │ │ └── admin/ # 어드민 API
+│ │ ├── components/ # 공통 컴포넌트
+│ │ ├── pages/
+│ │ │ ├── pc/ # PC 페이지
+│ │ │ └── mobile/ # 모바일 페이지
+│ │ ├── stores/ # Zustand 스토어
+│ │ └── App.jsx
+│ ├── vite.config.js
+│ └── package.json
+│
+├── Dockerfile # 개발/배포 통합 (주석 전환)
+├── docker-compose.yml
+└── .env
+```
+
+## 서비스 구성
+
+```
+┌─────────────────────────────────────────────────────────┐
+│ Caddy │
+│ (리버스 프록시) │
+└─────────────────────┬───────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────┐
+│ fromis9-frontend (Docker) │
+│ ┌─────────────────┐ ┌─────────────────────────────┐ │
+│ │ Vite (:80) │───▶│ Fastify (:3000) │ │
+│ │ 프론트엔드 │ │ 백엔드 API │ │
+│ └─────────────────┘ └──────────┬──────────────────┘ │
+└─────────────────────────────────────┼───────────────────┘
+ │
+ ┌────────────────────────────┼────────────────────────────┐
+ │ │ │
+ ▼ ▼ ▼
+┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
+│ MariaDB │ │ Meilisearch │ │ Redis │
+│ (외부 DB망) │ │ (검색 엔진) │ │ (캐시) │
+└─────────────────┘ └─────────────────┘ └─────────────────┘
+```
+
+## 데이터베이스
+
+### 주요 테이블
+- `members` - 멤버 정보
+- `member_nicknames` - 멤버 별명 (검색용)
+- `albums` - 앨범 정보
+- `schedules` - 일정
+- `schedule_categories` - 일정 카테고리
+- `schedule_youtube` - YouTube 영상 정보
+- `schedule_x` - X(Twitter) 게시물 정보
+- `schedule_members` - 일정-멤버 연결
+- `images` - 이미지 메타데이터
+
+### 검색 인덱스 (Meilisearch)
+- `schedules` - 일정 검색용 인덱스
+ - 검색 필드: title, member_names, description, source_name, category_name
+ - 필터: category_id, date
+ - 정렬: date, time
diff --git a/docs/development.md b/docs/development.md
new file mode 100644
index 0000000..48ececf
--- /dev/null
+++ b/docs/development.md
@@ -0,0 +1,124 @@
+# 개발/배포 가이드
+
+## 개발 모드
+
+### 실행
+```bash
+cd /docker/fromis_9
+docker compose up -d --build
+```
+
+### 구성
+- **Vite** (포트 80): 프론트엔드 개발 서버, HMR 지원
+- **Fastify** (포트 3000): 백엔드 API, --watch 모드
+- Vite가 `/api`, `/docs` 요청을 localhost:3000으로 프록시
+
+### 로그 확인
+```bash
+docker compose logs -f fromis9-frontend
+```
+
+### 코드 수정
+- `frontend/`, `backend/` 폴더가 볼륨 마운트됨
+- 코드 수정 시 자동 반영 (HMR, watch)
+
+---
+
+## 배포 모드 전환
+
+### 1. Dockerfile 수정
+```dockerfile
+# 개발 모드 주석처리
+# FROM node:20-alpine
+# WORKDIR /app
+# ...
+
+# 배포 모드 주석해제
+FROM node:20-alpine AS frontend-builder
+...
+```
+
+### 2. docker-compose.yml 수정
+```yaml
+# volumes 주석처리
+# volumes:
+# - ./backend:/app/backend
+# - ./frontend:/app/frontend
+# - backend_modules:/app/backend/node_modules
+# - frontend_modules:/app/frontend/node_modules
+```
+
+### 3. 빌드 및 실행
+```bash
+docker compose up -d --build
+```
+
+---
+
+## 환경 변수 (.env)
+
+```env
+# 서버
+PORT=80
+
+# 데이터베이스
+DB_HOST=mariadb
+DB_PORT=3306
+DB_USER=...
+DB_PASSWORD=...
+DB_NAME=fromis9
+
+# Redis
+REDIS_HOST=fromis9-redis
+REDIS_PORT=6379
+
+# Meilisearch
+MEILI_HOST=http://fromis9-meilisearch:7700
+MEILI_MASTER_KEY=...
+
+# JWT
+JWT_SECRET=...
+
+# AWS S3
+AWS_ACCESS_KEY_ID=...
+AWS_SECRET_ACCESS_KEY=...
+AWS_REGION=...
+S3_BUCKET=...
+
+# YouTube API
+YOUTUBE_API_KEY=...
+```
+
+---
+
+## Caddy 설정
+
+`/docker/caddy/Caddyfile`:
+```caddyfile
+fromis9.caadiq.co.kr {
+ import custom_errors
+ request_body {
+ max_size 500MB
+ }
+ reverse_proxy fromis9-frontend:80
+}
+```
+
+---
+
+## 유용한 명령어
+
+```bash
+# 컨테이너 재시작
+docker compose restart fromis9-frontend
+
+# 볼륨 포함 완전 재시작
+docker compose down -v && docker compose up -d --build
+
+# Meilisearch 동기화
+curl -X POST https://fromis9.caadiq.co.kr/api/schedules/sync-search \
+ -H "Authorization: Bearer "
+
+# Redis 확인
+docker exec fromis9-redis redis-cli KEYS "*"
+```
diff --git a/docs/handover.md b/docs/handover.md
deleted file mode 100644
index 9ec101a..0000000
--- a/docs/handover.md
+++ /dev/null
@@ -1,163 +0,0 @@
-# fromis_9 프로젝트 인수인계서
-
-## 프로젝트 개요
-
-fromis_9 K-pop 아이돌 팬사이트 - 웹 프론트엔드, 백엔드 API, 모바일 앱으로 구성
-
----
-
-## 1. 디렉토리 구조
-
-```
-/docker/fromis_9/
-├── frontend/ # React 웹 프론트엔드 (Vite)
-├── backend/ # Express.js 백엔드 API
-├── app/ # React Native 모바일 앱 (Expo)
-└── .env # 환경변수 (DB 접속정보 등)
-```
-
----
-
-## 2. 웹 프론트엔드 (`/frontend`)
-
-### 기술 스택
-
-- React + Vite
-- TailwindCSS
-- framer-motion (애니메이션)
-
-### 주요 경로
-
-- `src/pages/` - 페이지 컴포넌트
- - `pc/public/` - PC 공개 페이지 (Home, Members, Album, AlbumDetail, TrackDetail 등)
- - `mobile/public/` - 모바일 전용 페이지
- - `pc/admin/` - 관리자 페이지
-- `src/api/` - API 호출 함수
-- `src/components/` - 재사용 컴포넌트
-
----
-
-## 3. 백엔드 (`/backend`)
-
-### 기술 스택
-
-- Express.js
-- MariaDB (mysql2)
-- RustFS (파일 스토리지)
-
-### 주요 경로
-
-- `routes/` - API 라우트
- - `public/` - 공개 API
- - `admin/` - 관리자 API
-- `lib/` - 유틸리티 (DB, 파일 업로드 등)
-
----
-
-## 4. 모바일 앱 (`/app`)
-
-### 기술 스택
-
-- **Expo** (React Native)
-- **TypeScript**
-- React Navigation (탭 + 스택 네비게이션)
-- expo-blur, expo-linear-gradient (UI 효과)
-
-### 주요 경로
-
-```
-app/src/
-├── api/ # API 호출 함수
-│ ├── albums.ts # 앨범 API
-│ ├── members.ts # 멤버 API
-│ └── schedules.ts # 일정 API
-├── components/ # 공통 컴포넌트
-│ └── common/
-│ └── Header.tsx # 공통 헤더 (뒤로가기, 타이틀, rightElement)
-├── navigation/ # 네비게이션 설정
-│ └── AppNavigator.tsx
-├── screens/ # 화면 컴포넌트
-│ ├── HomeScreen.tsx
-│ ├── MembersScreen.tsx
-│ ├── AlbumScreen.tsx
-│ ├── AlbumDetailScreen.tsx
-│ ├── AlbumGalleryScreen.tsx # 컨셉포토 갤러리 (라이트박스)
-│ └── ScheduleScreen.tsx
-└── constants/ # 상수 (colors 등)
-```
-
-### 네비게이션 구조
-
-```
-TabNavigator (하단 탭)
-├── HomeTab → HomeScreen
-├── MembersTab → MembersScreen
-├── AlbumTab → AlbumStackNavigator
-│ ├── AlbumList → AlbumScreen
-│ ├── AlbumDetail → AlbumDetailScreen
-│ └── AlbumGallery → AlbumGalleryScreen
-└── ScheduleTab → ScheduleScreen
-```
-
-### 주요 기능
-
-- **탭 전환 시 앨범 스택 리셋**: 다른 탭 갔다가 앨범 탭 클릭 시 목록으로 돌아감
-- **AlbumGalleryScreen**: 웹과 1:1 동일한 컨셉포토 갤러리 (PagerView 라이트박스, 다운로드)
-- **MembersScreen**: 바텀시트 모달, 전 멤버 흑백 처리
-
-### 개발 서버 실행
-
-```bash
-cd /docker/fromis_9/app
-npx expo start --lan
-```
-
-### APK 빌드
-
-```bash
-npx expo run:android --variant release
-# 또는 로컬 빌드
-./gradlew assembleDebug # android/ 폴더에서
-```
-
----
-
-## 5. 분석 절차
-
-### 5.1 코드 전수 조사
-
-```bash
-# 프로젝트 구조 확인
-find /docker/fromis_9 -type f -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" | head -50
-```
-
-### 5.2 DB 구조 파악
-
-```bash
-# .env에서 DB 정보 확인
-cat /docker/fromis_9/.env
-
-# MariaDB 접속 (컨테이너명: mariadb)
-docker exec -it mariadb mysql -u [USER] -p[PASSWORD] fromis9
-
-# 테이블 목록
-SHOW TABLES;
-
-# 테이블 스키마
-DESCRIBE [table_name];
-```
-
-### 5.3 Caddy 설정 확인
-
-```bash
-cat /docker/caddy/Caddyfile | grep -A 20 "fromis9"
-```
-
----
-
-## 6. 주의사항
-
-- **앱 HMR**: Vite처럼 자동 반영, 빌드 불필요
-- **앱 테스트**: 흔들어서 → Reload로 확인
-- **DB 접속**: `.env` 파일의 실제 자격증명 사용
-- **웹/앱 1:1 동기화**: 기능 추가 시 웹과 앱 모두 구현 필요
diff --git a/docs/migration.md b/docs/migration.md
new file mode 100644
index 0000000..03b68c3
--- /dev/null
+++ b/docs/migration.md
@@ -0,0 +1,54 @@
+# 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`)
+- [x] 멤버 (`/api/members`)
+- [x] 앨범 (`/api/albums`)
+- [x] 일정 (`/api/schedules`)
+ - 월별 조회 (생일 일정 포함)
+ - Meilisearch 검색
+ - 별명 → 멤버이름 변환
+ - 영문자판 → 한글 변환
+- [x] 추천 검색어 (`/api/schedules/suggestions`)
+ - kiwi-nlp 형태소 분석
+ - bi-gram 자동완성
+
+### 서비스 (`src/services/`)
+- [x] YouTube 봇 - 영상 자동 수집
+- [x] X(Twitter) 봇 - Nitter 스크래핑
+- [x] Meilisearch 검색
+- [x] 추천 검색어
+
+## 남은 작업
+
+### 어드민 API
+- [ ] 일정 CRUD (`POST/PUT/DELETE /api/schedules`)
+- [ ] 이미지 업로드 (`/api/images`)
+- [ ] 멤버 관리 (`POST/PUT/DELETE /api/members`)
+- [ ] 앨범 관리 (`POST/PUT/DELETE /api/albums`)
+- [ ] 카테고리 관리 (`/api/categories`)
+
+### 기타
+- [ ] 통계 API (`/api/stats`)
+- [ ] 어드민 사전 관리 (형태소 분석용)
+
+## 참고 사항
+
+- 기존 Express 코드는 `backend-backup/` 폴더에 보존
+- 마이그레이션 시 기존 코드 참조하여 동일 기능 구현
+- DB 스키마는 변경 없음 (기존 테이블 그대로 사용)