refactor: 프론트엔드 개선 계획 수립
- 기존 마이그레이션 문서 삭제 (admin-migration.md, frontend-refactoring.md, migration.md) - 새로운 개선 계획서 작성 (frontend-improvement.md) - constants 정리: CATEGORY_NAMES, ALBUM_TYPES, 불필요한 SNS 링크 삭제 - schedule.js: getMemberList에서 쉼표 구분 로직 제거 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
25d74d098d
commit
b314b70014
6 changed files with 180 additions and 2684 deletions
|
|
@ -1,549 +0,0 @@
|
||||||
# 관리자 페이지 마이그레이션 계획서
|
|
||||||
|
|
||||||
## 개요
|
|
||||||
|
|
||||||
- **목표**: `frontend/src/pages/pc/admin/` → `frontend-temp/src/pages/admin/`
|
|
||||||
- **현재 규모**: 12개 파일, 약 7,535 LOC
|
|
||||||
- **방식**: 일반 페이지와 동일한 Strangler Fig Pattern 적용
|
|
||||||
- **특이사항**: PC 전용 (모바일 관리자 페이지 없음)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 현재 구조 분석
|
|
||||||
|
|
||||||
### 관리자 페이지 (12개)
|
|
||||||
|
|
||||||
| 파일 | LOC | 설명 | 복잡도 |
|
|
||||||
|------|-----|------|--------|
|
|
||||||
| AdminLogin.jsx | 168 | 로그인 폼 | 낮음 |
|
|
||||||
| AdminDashboard.jsx | 167 | 대시보드 (통계) | 낮음 |
|
|
||||||
| AdminMembers.jsx | 180 | 멤버 목록 | 낮음 |
|
|
||||||
| AdminMemberEdit.jsx | 382 | 멤버 수정 폼 | 중간 |
|
|
||||||
| AdminAlbums.jsx | 222 | 앨범 목록 | 낮음 |
|
|
||||||
| AdminAlbumForm.jsx | 666 | 앨범 생성/수정 폼 | 높음 |
|
|
||||||
| AdminAlbumPhotos.jsx | 1,538 | 사진 업로드 (SSE) | 매우 높음 |
|
|
||||||
| AdminSchedule.jsx | 1,465 | 일정 목록/검색 | 매우 높음 |
|
|
||||||
| AdminScheduleForm.jsx | 1,173 | 일정 생성/수정 폼 | 높음 |
|
|
||||||
| AdminScheduleCategory.jsx | 463 | 카테고리 관리 | 중간 |
|
|
||||||
| AdminScheduleDict.jsx | 664 | 일정 사전 관리 | 중간 |
|
|
||||||
| AdminScheduleBots.jsx | 447 | 봇 관리 | 중간 |
|
|
||||||
|
|
||||||
### 관리자 컴포넌트 (3개)
|
|
||||||
|
|
||||||
| 파일 | 설명 |
|
|
||||||
|------|------|
|
|
||||||
| AdminLayout.jsx | 관리자 레이아웃 (헤더 + 본문) |
|
|
||||||
| AdminHeader.jsx | 관리자 헤더 (네비게이션) |
|
|
||||||
| NumberPicker.jsx | 숫자 입력 컴포넌트 |
|
|
||||||
|
|
||||||
### 관리자 API (8개)
|
|
||||||
|
|
||||||
| 파일 | 설명 |
|
|
||||||
|------|------|
|
|
||||||
| auth.js | 로그인/인증 |
|
|
||||||
| albums.js | 앨범 CRUD |
|
|
||||||
| members.js | 멤버 CRUD |
|
|
||||||
| schedules.js | 일정 CRUD |
|
|
||||||
| categories.js | 카테고리 CRUD |
|
|
||||||
| suggestions.js | 검색어 추천 관리 |
|
|
||||||
| bots.js | 봇 관리 |
|
|
||||||
| stats.js | 통계 조회 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 마이그레이션 전략
|
|
||||||
|
|
||||||
### 우선순위
|
|
||||||
|
|
||||||
복잡도와 의존성을 고려하여 순차적으로 진행:
|
|
||||||
|
|
||||||
1. **1단계**: 폴더 구조 재편 (기존 파일을 새 구조로 이동)
|
|
||||||
2. **2단계**: 관리자 기반 설정 (레이아웃, API, 인증)
|
|
||||||
3. **3단계**: 간단한 페이지 (로그인, 대시보드, 멤버)
|
|
||||||
4. **4단계**: 앨범 관리
|
|
||||||
5. **5단계**: 일정 관리 (가장 복잡)
|
|
||||||
|
|
||||||
### 코딩 가이드라인
|
|
||||||
|
|
||||||
공개 영역과 동일한 패턴 적용:
|
|
||||||
- `useQuery` / `useMutation` 사용
|
|
||||||
- 서비스 레이어 분리
|
|
||||||
- 공통 컴포넌트 재사용
|
|
||||||
- TypeScript JSDoc 타입 정의
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1단계: 폴더 구조 재편
|
|
||||||
|
|
||||||
기존 frontend-temp 파일들을 새로운 구조로 이동합니다.
|
|
||||||
|
|
||||||
### 1.1 현재 구조 → 새 구조
|
|
||||||
|
|
||||||
```
|
|
||||||
현재 → 새 구조
|
|
||||||
─────────────────────────────────────────────────────────
|
|
||||||
api/
|
|
||||||
├── client.js → api/common/client.js
|
|
||||||
├── index.js → (삭제, 각 폴더별 index.js로 대체)
|
|
||||||
├── auth.js → api/pc/admin/auth.js
|
|
||||||
├── schedules.js → api/pc/public/schedules.js
|
|
||||||
├── albums.js → api/pc/public/albums.js
|
|
||||||
└── members.js → api/pc/common/members.js
|
|
||||||
|
|
||||||
components/
|
|
||||||
├── common/ → components/common/
|
|
||||||
│ ├── Loading.jsx
|
|
||||||
│ ├── ErrorBoundary.jsx
|
|
||||||
│ ├── ErrorMessage.jsx
|
|
||||||
│ ├── Toast.jsx
|
|
||||||
│ ├── Lightbox.jsx
|
|
||||||
│ └── ...
|
|
||||||
├── pc/ → components/pc/public/
|
|
||||||
│ ├── Layout.jsx
|
|
||||||
│ ├── Header.jsx
|
|
||||||
│ ├── Footer.jsx
|
|
||||||
│ ├── Calendar.jsx
|
|
||||||
│ └── ScheduleCard.jsx
|
|
||||||
└── mobile/ → components/mobile/
|
|
||||||
├── Layout.jsx
|
|
||||||
├── Header.jsx
|
|
||||||
├── BottomNav.jsx
|
|
||||||
└── ...
|
|
||||||
|
|
||||||
hooks/
|
|
||||||
├── useMediaQuery.js → hooks/common/useMediaQuery.js
|
|
||||||
├── useLightbox.js → hooks/common/useLightbox.js
|
|
||||||
├── useCalendar.js → hooks/common/useCalendar.js
|
|
||||||
├── useAdminAuth.js → hooks/pc/admin/useAdminAuth.js
|
|
||||||
└── ...
|
|
||||||
|
|
||||||
pages/
|
|
||||||
├── home/pc/ → pages/pc/public/home/
|
|
||||||
├── home/mobile/ → pages/mobile/home/
|
|
||||||
├── schedule/pc/ → pages/pc/public/schedule/
|
|
||||||
├── schedule/mobile/ → pages/mobile/schedule/
|
|
||||||
├── album/pc/ → pages/pc/public/album/
|
|
||||||
├── album/mobile/ → pages/mobile/album/
|
|
||||||
├── members/pc/ → pages/pc/public/members/
|
|
||||||
└── members/mobile/ → pages/mobile/members/
|
|
||||||
```
|
|
||||||
|
|
||||||
### 1.2 import 경로 업데이트
|
|
||||||
|
|
||||||
파일 이동 후 모든 import 경로를 새 구조에 맞게 수정합니다.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Before
|
|
||||||
import { fetchApi } from '@/api/client';
|
|
||||||
import Loading from '@/components/common/Loading';
|
|
||||||
import Calendar from '@/components/pc/Calendar';
|
|
||||||
|
|
||||||
// After
|
|
||||||
import { fetchApi } from '@/api/common/client';
|
|
||||||
import Loading from '@/components/common/Loading';
|
|
||||||
import Calendar from '@/components/pc/public/Calendar';
|
|
||||||
```
|
|
||||||
|
|
||||||
### 1.3 index.js 파일 생성
|
|
||||||
|
|
||||||
각 폴더에 re-export용 index.js 생성:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// api/pc/public/index.js
|
|
||||||
export * from './schedules';
|
|
||||||
export * from './albums';
|
|
||||||
|
|
||||||
// api/pc/admin/index.js
|
|
||||||
export * from './auth';
|
|
||||||
export * from './schedules';
|
|
||||||
// ...
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2단계: 관리자 기반 설정
|
|
||||||
|
|
||||||
### 2.1 관리자 API 추가
|
|
||||||
|
|
||||||
**원칙**: 조회(GET)는 공개 API 재사용, CUD(Create/Update/Delete)는 관리자 API
|
|
||||||
|
|
||||||
```
|
|
||||||
api/
|
|
||||||
├── common/ # PC, Mobile 공통
|
|
||||||
│ └── client.js # fetch 래퍼 (fetchApi, fetchAuthApi)
|
|
||||||
│
|
|
||||||
├── pc/
|
|
||||||
│ ├── common/ # PC 내 공통 (public + admin 공유)
|
|
||||||
│ │ └── members.js # 멤버 조회 (일정 폼에서도 사용)
|
|
||||||
│ ├── public/ # PC 공개 API
|
|
||||||
│ │ ├── schedules.js
|
|
||||||
│ │ └── albums.js
|
|
||||||
│ └── admin/ # PC 관리자 API
|
|
||||||
│ ├── auth.js
|
|
||||||
│ ├── schedules.js
|
|
||||||
│ ├── albums.js
|
|
||||||
│ ├── members.js
|
|
||||||
│ ├── categories.js
|
|
||||||
│ ├── suggestions.js
|
|
||||||
│ ├── bots.js
|
|
||||||
│ └── stats.js
|
|
||||||
│
|
|
||||||
└── mobile/ # 모바일 (pc/public과 동일 API 사용 가능)
|
|
||||||
```
|
|
||||||
|
|
||||||
**사용 예시**:
|
|
||||||
```javascript
|
|
||||||
// PC 공개 페이지
|
|
||||||
import { fetchSchedules } from '@/api/pc/public';
|
|
||||||
|
|
||||||
// PC 관리자 페이지 - 조회는 pc/common 또는 pc/public 재사용
|
|
||||||
import { fetchMembers } from '@/api/pc/common';
|
|
||||||
import { createSchedule } from '@/api/pc/admin';
|
|
||||||
|
|
||||||
// 모바일 페이지
|
|
||||||
import { fetchSchedules } from '@/api/pc/public'; // 동일 API 재사용
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.2 관리자 레이아웃
|
|
||||||
|
|
||||||
`components/pc/admin/` 폴더 구조:
|
|
||||||
|
|
||||||
```
|
|
||||||
components/pc/admin/
|
|
||||||
├── Layout.jsx # AdminLayout
|
|
||||||
├── Header.jsx # AdminHeader (네비게이션)
|
|
||||||
└── NumberPicker.jsx
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.3 인증 훅 수정
|
|
||||||
|
|
||||||
현재 `useAdminAuth.js`를 관리자 전용으로 확장:
|
|
||||||
- 토큰 검증
|
|
||||||
- 자동 로그아웃
|
|
||||||
- 권한 체크
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3단계: 간단한 페이지
|
|
||||||
|
|
||||||
### 3.1 AdminLogin
|
|
||||||
|
|
||||||
- 로그인 폼 컴포넌트화
|
|
||||||
- `useMutation`으로 로그인 처리
|
|
||||||
- 에러 처리 표준화
|
|
||||||
|
|
||||||
### 3.2 AdminDashboard
|
|
||||||
|
|
||||||
- 통계 API 호출 (`useQuery`)
|
|
||||||
- 차트/카드 컴포넌트화
|
|
||||||
- 로딩/에러 상태 처리
|
|
||||||
|
|
||||||
### 3.3 AdminMembers / AdminMemberEdit
|
|
||||||
|
|
||||||
- 멤버 목록 테이블
|
|
||||||
- 멤버 수정 폼
|
|
||||||
- 이미지 업로드 처리
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4단계: 앨범 관리
|
|
||||||
|
|
||||||
### 4.1 AdminAlbums
|
|
||||||
|
|
||||||
- 앨범 목록 테이블
|
|
||||||
- 삭제 확인 모달
|
|
||||||
- 정렬/필터링
|
|
||||||
|
|
||||||
### 4.2 AdminAlbumForm
|
|
||||||
|
|
||||||
폼 필드:
|
|
||||||
- 기본 정보 (이름, 발매일, 타입)
|
|
||||||
- 트랙 목록 (동적 추가/삭제)
|
|
||||||
- 티저 목록 (동적 추가/삭제)
|
|
||||||
- 앨범 커버 업로드
|
|
||||||
|
|
||||||
컴포넌트 분리:
|
|
||||||
```
|
|
||||||
components/pc/admin/album/
|
|
||||||
├── AlbumBasicForm.jsx # 기본 정보
|
|
||||||
├── TrackListForm.jsx # 트랙 관리
|
|
||||||
├── TeaserListForm.jsx # 티저 관리
|
|
||||||
└── CoverUploader.jsx # 커버 업로드
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.3 AdminAlbumPhotos
|
|
||||||
|
|
||||||
가장 복잡한 페이지:
|
|
||||||
- SSE 스트리밍 업로드
|
|
||||||
- 진행률 표시
|
|
||||||
- 멤버 태깅
|
|
||||||
- 드래그 앤 드롭
|
|
||||||
|
|
||||||
훅 분리:
|
|
||||||
```
|
|
||||||
hooks/pc/admin/
|
|
||||||
├── usePhotoUpload.js # SSE 업로드 로직
|
|
||||||
├── usePhotoList.js # 사진 목록 관리
|
|
||||||
└── useMemberTag.js # 멤버 태깅
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5단계: 일정 관리
|
|
||||||
|
|
||||||
### 5.1 AdminSchedule
|
|
||||||
|
|
||||||
기능:
|
|
||||||
- 일정 목록 (가상 스크롤)
|
|
||||||
- 검색/필터링
|
|
||||||
- 일괄 삭제
|
|
||||||
|
|
||||||
훅 재사용:
|
|
||||||
- `useScheduleSearch` (공개 영역과 동일)
|
|
||||||
- `useScheduleFiltering` (공개 영역과 동일)
|
|
||||||
|
|
||||||
### 5.2 AdminScheduleForm
|
|
||||||
|
|
||||||
폼 필드:
|
|
||||||
- 기본 정보 (제목, 날짜, 시간)
|
|
||||||
- 카테고리 선택
|
|
||||||
- 멤버 선택
|
|
||||||
- 출처 정보
|
|
||||||
- 카테고리별 추가 필드 (YouTube, X)
|
|
||||||
|
|
||||||
컴포넌트 분리:
|
|
||||||
```
|
|
||||||
components/pc/admin/schedule/
|
|
||||||
├── ScheduleBasicForm.jsx # 기본 정보
|
|
||||||
├── CategorySelect.jsx # 카테고리 선택
|
|
||||||
├── MemberSelect.jsx # 멤버 다중 선택
|
|
||||||
├── SourceInput.jsx # 출처 입력
|
|
||||||
├── YouTubeForm.jsx # YouTube 영상 정보
|
|
||||||
└── XForm.jsx # X 게시글 정보
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.3 AdminScheduleCategory
|
|
||||||
|
|
||||||
- 카테고리 CRUD
|
|
||||||
- 색상 선택기
|
|
||||||
- 순서 변경 (드래그)
|
|
||||||
|
|
||||||
### 5.4 AdminScheduleDict
|
|
||||||
|
|
||||||
- 일정 사전 관리
|
|
||||||
- 자동완성 데이터
|
|
||||||
|
|
||||||
### 5.5 AdminScheduleBots
|
|
||||||
|
|
||||||
- 봇 목록/상태
|
|
||||||
- 동기화 실행
|
|
||||||
- 로그 확인
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 목표 구조
|
|
||||||
|
|
||||||
```
|
|
||||||
frontend-temp/src/
|
|
||||||
├── api/
|
|
||||||
│ ├── common/ # PC, Mobile 공통
|
|
||||||
│ │ └── client.js # fetch 래퍼
|
|
||||||
│ ├── pc/
|
|
||||||
│ │ ├── common/ # PC 내 공통 (public + admin 공유)
|
|
||||||
│ │ │ └── members.js # 멤버 조회 (폼에서 공유)
|
|
||||||
│ │ ├── public/ # PC 공개 API
|
|
||||||
│ │ │ ├── schedules.js
|
|
||||||
│ │ │ └── albums.js
|
|
||||||
│ │ └── admin/ # PC 관리자 API
|
|
||||||
│ │ ├── auth.js
|
|
||||||
│ │ ├── schedules.js
|
|
||||||
│ │ ├── albums.js
|
|
||||||
│ │ ├── members.js
|
|
||||||
│ │ ├── categories.js
|
|
||||||
│ │ ├── suggestions.js
|
|
||||||
│ │ ├── bots.js
|
|
||||||
│ │ └── stats.js
|
|
||||||
│ └── mobile/ # 모바일 API
|
|
||||||
│ └── (public과 동일하게 사용)
|
|
||||||
│
|
|
||||||
├── components/
|
|
||||||
│ ├── common/ # PC, Mobile 공통
|
|
||||||
│ │ ├── Loading.jsx
|
|
||||||
│ │ ├── ErrorBoundary.jsx
|
|
||||||
│ │ ├── ErrorMessage.jsx
|
|
||||||
│ │ ├── Toast.jsx
|
|
||||||
│ │ └── Lightbox/
|
|
||||||
│ ├── pc/
|
|
||||||
│ │ ├── common/ # PC 내 공통
|
|
||||||
│ │ │ └── (필요시)
|
|
||||||
│ │ ├── public/ # PC 공개 컴포넌트
|
|
||||||
│ │ │ ├── Layout.jsx
|
|
||||||
│ │ │ ├── Header.jsx
|
|
||||||
│ │ │ ├── Footer.jsx
|
|
||||||
│ │ │ ├── Calendar.jsx
|
|
||||||
│ │ │ └── ScheduleCard.jsx
|
|
||||||
│ │ └── admin/ # PC 관리자 컴포넌트
|
|
||||||
│ │ ├── Layout.jsx
|
|
||||||
│ │ ├── Header.jsx
|
|
||||||
│ │ ├── NumberPicker.jsx
|
|
||||||
│ │ ├── ConfirmDialog.jsx
|
|
||||||
│ │ ├── album/
|
|
||||||
│ │ │ ├── AlbumBasicForm.jsx
|
|
||||||
│ │ │ ├── TrackListForm.jsx
|
|
||||||
│ │ │ ├── TeaserListForm.jsx
|
|
||||||
│ │ │ └── CoverUploader.jsx
|
|
||||||
│ │ └── schedule/
|
|
||||||
│ │ ├── ScheduleBasicForm.jsx
|
|
||||||
│ │ ├── CategorySelect.jsx
|
|
||||||
│ │ ├── MemberSelect.jsx
|
|
||||||
│ │ ├── SourceInput.jsx
|
|
||||||
│ │ ├── YouTubeForm.jsx
|
|
||||||
│ │ └── XForm.jsx
|
|
||||||
│ └── mobile/ # 모바일 컴포넌트
|
|
||||||
│ ├── Layout.jsx
|
|
||||||
│ ├── Header.jsx
|
|
||||||
│ ├── BottomNav.jsx
|
|
||||||
│ ├── Calendar.jsx
|
|
||||||
│ └── ScheduleCard.jsx
|
|
||||||
│
|
|
||||||
├── hooks/
|
|
||||||
│ ├── common/ # PC, Mobile 공통
|
|
||||||
│ │ ├── useMediaQuery.js
|
|
||||||
│ │ ├── useLightbox.js
|
|
||||||
│ │ └── useCalendar.js
|
|
||||||
│ ├── pc/
|
|
||||||
│ │ ├── common/ # PC 내 공통
|
|
||||||
│ │ │ └── (필요시)
|
|
||||||
│ │ ├── public/ # PC 공개 훅
|
|
||||||
│ │ │ └── (필요시)
|
|
||||||
│ │ └── admin/ # PC 관리자 훅
|
|
||||||
│ │ ├── useAdminAuth.js
|
|
||||||
│ │ ├── usePhotoUpload.js
|
|
||||||
│ │ ├── usePhotoList.js
|
|
||||||
│ │ └── useMemberTag.js
|
|
||||||
│ └── mobile/ # 모바일 훅
|
|
||||||
│ └── (필요시)
|
|
||||||
│
|
|
||||||
├── pages/
|
|
||||||
│ ├── pc/
|
|
||||||
│ │ ├── public/ # PC 공개 페이지
|
|
||||||
│ │ │ ├── Home.jsx
|
|
||||||
│ │ │ ├── Schedule.jsx
|
|
||||||
│ │ │ ├── Album.jsx
|
|
||||||
│ │ │ └── Members.jsx
|
|
||||||
│ │ └── admin/ # PC 관리자 페이지
|
|
||||||
│ │ ├── Login.jsx
|
|
||||||
│ │ ├── Dashboard.jsx
|
|
||||||
│ │ ├── Members.jsx
|
|
||||||
│ │ ├── MemberEdit.jsx
|
|
||||||
│ │ ├── Albums.jsx
|
|
||||||
│ │ ├── AlbumForm.jsx
|
|
||||||
│ │ ├── AlbumPhotos.jsx
|
|
||||||
│ │ ├── Schedule.jsx
|
|
||||||
│ │ ├── ScheduleForm.jsx
|
|
||||||
│ │ ├── ScheduleCategory.jsx
|
|
||||||
│ │ ├── ScheduleDict.jsx
|
|
||||||
│ │ └── ScheduleBots.jsx
|
|
||||||
│ └── mobile/ # 모바일 페이지
|
|
||||||
│ ├── Home.jsx
|
|
||||||
│ ├── Schedule.jsx
|
|
||||||
│ ├── Album.jsx
|
|
||||||
│ └── Members.jsx
|
|
||||||
│
|
|
||||||
├── stores/ # 전역 상태 (플랫)
|
|
||||||
│ ├── useAuthStore.js
|
|
||||||
│ ├── useScheduleStore.js
|
|
||||||
│ └── useUIStore.js
|
|
||||||
│
|
|
||||||
├── utils/ # 유틸리티 (플랫)
|
|
||||||
│ ├── date.js
|
|
||||||
│ ├── format.js
|
|
||||||
│ └── schedule.js
|
|
||||||
│
|
|
||||||
└── constants/ # 상수 (플랫)
|
|
||||||
└── index.js
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 작업 체크리스트
|
|
||||||
|
|
||||||
### 1단계: 폴더 구조 재편 ✅
|
|
||||||
- [x] api/ 구조 변경 (common/, pc/common/, pc/public/, pc/admin/)
|
|
||||||
- [x] components/ 구조 변경 (common/, pc/public/, pc/admin/, mobile/)
|
|
||||||
- [x] hooks/ 구조 변경 (common/, pc/admin/)
|
|
||||||
- [x] pages/ 구조 변경 (pc/public/, mobile/)
|
|
||||||
- [x] 모든 import 경로 업데이트
|
|
||||||
- [x] 각 폴더에 index.js 생성 (re-export)
|
|
||||||
- [x] 개발 서버 동작 확인
|
|
||||||
|
|
||||||
### 2단계: 관리자 기반 설정 ✅
|
|
||||||
- [x] 관리자 API 마이그레이션 (api/pc/admin/)
|
|
||||||
- [x] AdminLayout 마이그레이션 (components/pc/admin/)
|
|
||||||
- [x] AdminHeader 마이그레이션 (components/pc/admin/)
|
|
||||||
- [x] useAdminAuth 훅 이동 (hooks/pc/admin/)
|
|
||||||
- [x] 관리자 라우트 설정 (App.jsx)
|
|
||||||
- [x] AdminLogin 페이지 마이그레이션
|
|
||||||
|
|
||||||
### 3단계: 간단한 페이지 ✅
|
|
||||||
- [x] AdminLogin 마이그레이션 (2단계에서 완료)
|
|
||||||
- [x] AdminDashboard 마이그레이션
|
|
||||||
- [x] AdminMembers 마이그레이션
|
|
||||||
- [x] AdminMemberEdit 마이그레이션
|
|
||||||
- [x] useToast 훅 추가
|
|
||||||
|
|
||||||
### 4단계: 앨범 관리 ✅
|
|
||||||
- [x] AdminAlbums 마이그레이션
|
|
||||||
- [x] AdminAlbumForm 마이그레이션
|
|
||||||
- [x] AdminAlbumPhotos 마이그레이션 (SSE 처리 포함)
|
|
||||||
|
|
||||||
### 5단계: 일정 관리 ✅
|
|
||||||
- [x] AdminSchedule 마이그레이션
|
|
||||||
- [x] AdminScheduleForm 마이그레이션
|
|
||||||
- [x] AdminScheduleCategory 마이그레이션
|
|
||||||
- [x] AdminScheduleDict 마이그레이션
|
|
||||||
- [x] AdminScheduleBots 마이그레이션
|
|
||||||
- [x] 카테고리별 폼 분기 페이지 마이그레이션 (form/index.jsx)
|
|
||||||
- [x] YouTubeForm 마이그레이션 (form/YouTubeForm.jsx)
|
|
||||||
- [x] XForm 마이그레이션 (form/XForm.jsx)
|
|
||||||
- [x] CategorySelector 마이그레이션 (form/components/CategorySelector.jsx)
|
|
||||||
- [x] YouTubeEditForm 마이그레이션 (edit/YouTubeEditForm.jsx)
|
|
||||||
|
|
||||||
### 6단계: 검증
|
|
||||||
- [ ] 공개 페이지 동작 확인 (PC/Mobile)
|
|
||||||
- [ ] 로그인/로그아웃 테스트
|
|
||||||
- [ ] 멤버 CRUD 테스트
|
|
||||||
- [ ] 앨범 CRUD 테스트
|
|
||||||
- [ ] 앨범 사진 업로드 테스트
|
|
||||||
- [ ] 일정 CRUD 테스트
|
|
||||||
- [ ] YouTube/X 일정 등록 테스트
|
|
||||||
- [ ] 카테고리 관리 테스트
|
|
||||||
- [ ] 봇 관리 테스트
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 예상 효과
|
|
||||||
|
|
||||||
| 항목 | Before | After | 개선 |
|
|
||||||
|------|--------|-------|------|
|
|
||||||
| 총 LOC | ~7,535 | ~5,500 | -27% |
|
|
||||||
| 중복 코드 | 30%+ | <10% | 공통 훅/컴포넌트 활용 |
|
|
||||||
| 컴포넌트 분리 | 12개 대형 파일 | 30개+ 작은 파일 | 유지보수성 향상 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 주의사항
|
|
||||||
|
|
||||||
1. **SSE 스트리밍**: AdminAlbumPhotos의 SSE 업로드는 별도 훅으로 분리하여 처리
|
|
||||||
2. **인증 처리**: 모든 관리자 API 호출에 토큰 자동 첨부
|
|
||||||
3. **에러 처리**: 401 에러 시 자동 로그아웃 및 리다이렉트
|
|
||||||
4. **폼 검증**: React Hook Form 또는 자체 검증 로직 사용
|
|
||||||
5. **낙관적 업데이트**: 목록 삭제 등에 useMutation의 onMutate 활용
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 참고
|
|
||||||
|
|
||||||
- 기존 문서: [frontend-refactoring.md](./frontend-refactoring.md)
|
|
||||||
- API 명세: [api.md](./api.md)
|
|
||||||
- 개발 가이드: [development.md](./development.md)
|
|
||||||
179
docs/frontend-improvement.md
Normal file
179
docs/frontend-improvement.md
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
# 프론트엔드 개선 계획서
|
||||||
|
|
||||||
|
## 1. 현재 문제점
|
||||||
|
|
||||||
|
### 1.1 API 구조
|
||||||
|
```
|
||||||
|
현재 구조:
|
||||||
|
api/
|
||||||
|
├── common/client.js # fetch 래퍼
|
||||||
|
├── index.js # 통합 export (혼란)
|
||||||
|
├── pc/
|
||||||
|
│ ├── admin/ # 관리자 API
|
||||||
|
│ ├── common/members.js # PC 공통?
|
||||||
|
│ └── public/ # 공개 API (어드민 함수도 섞여있음)
|
||||||
|
```
|
||||||
|
|
||||||
|
**문제점:**
|
||||||
|
- PC와 모바일이 같은 API를 사용하는데 `pc/` 폴더 안에 있음
|
||||||
|
- `api/pc/public/schedules.js`에 어드민 API 함수도 포함됨
|
||||||
|
- `transformSchedule` 함수가 여러 파일에 중복
|
||||||
|
- `api/index.js`에서 같은 함수가 여러 번 export됨
|
||||||
|
|
||||||
|
### 1.2 컴포넌트 구조
|
||||||
|
```
|
||||||
|
현재 구조:
|
||||||
|
components/
|
||||||
|
├── common/ # 공통 (OK)
|
||||||
|
├── mobile/ # 모바일 (폴더 구분 없음)
|
||||||
|
├── pc/
|
||||||
|
│ ├── admin/ # 관리자 (schedule 폴더만 있음)
|
||||||
|
│ └── public/ # 공개 (폴더 구분 없음)
|
||||||
|
```
|
||||||
|
|
||||||
|
**문제점:**
|
||||||
|
- `admin/`과 `public/` 내부에 기능별 폴더 구분이 없음
|
||||||
|
- 파일이 많아지면 찾기 어려움
|
||||||
|
|
||||||
|
### 1.3 중복 코드
|
||||||
|
- `getMemberList`: 16개 파일에서 사용, 일부는 로컬 정의
|
||||||
|
- `decodeHtmlEntities`: 여러 파일에 중복 정의
|
||||||
|
- `transformSchedule`: api/pc/public/schedules.js, api/pc/admin/schedules.js에 중복
|
||||||
|
- `Schedules.jsx`에 유틸 함수들이 로컬로 재정의됨
|
||||||
|
|
||||||
|
### 1.4 대형 파일
|
||||||
|
| 파일 | 라인 수 | 문제 |
|
||||||
|
|------|---------|------|
|
||||||
|
| AlbumPhotos.jsx | 1536 | 업로드, 관리, 일괄편집이 한 파일에 |
|
||||||
|
| Schedules.jsx | 1471 | 중복 유틸 함수, 컴포넌트 미분리 |
|
||||||
|
| ScheduleForm.jsx | 1046 | 폼 로직과 UI가 섞여있음 |
|
||||||
|
| ScheduleDict.jsx | 714 | 테이블과 모달이 한 파일에 |
|
||||||
|
| AlbumForm.jsx | 631 | 트랙/티저 관리가 인라인 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 개선 계획
|
||||||
|
|
||||||
|
### 2.1 API 구조 개선
|
||||||
|
|
||||||
|
```
|
||||||
|
개선 후:
|
||||||
|
api/
|
||||||
|
├── client.js # fetch 래퍼
|
||||||
|
├── transforms.js # 공통 변환 함수
|
||||||
|
├── public/ # 공개 API (PC/Mobile 공용)
|
||||||
|
│ ├── schedules.js
|
||||||
|
│ ├── albums.js
|
||||||
|
│ └── members.js
|
||||||
|
└── admin/ # 관리자 API
|
||||||
|
├── schedules.js
|
||||||
|
├── albums.js
|
||||||
|
├── members.js
|
||||||
|
├── categories.js
|
||||||
|
├── bots.js
|
||||||
|
└── stats.js
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 컴포넌트 구조 개선
|
||||||
|
|
||||||
|
```
|
||||||
|
개선 후:
|
||||||
|
components/
|
||||||
|
├── common/ # 공통 (유지)
|
||||||
|
├── mobile/
|
||||||
|
│ ├── layout/ # Layout, Header, BottomNav
|
||||||
|
│ └── schedule/ # ScheduleCard, BirthdayCard 등
|
||||||
|
├── pc/
|
||||||
|
│ ├── public/
|
||||||
|
│ │ ├── layout/ # Layout, Header, Footer
|
||||||
|
│ │ └── schedule/ # Calendar, ScheduleCard 등
|
||||||
|
│ └── admin/
|
||||||
|
│ ├── layout/ # Layout, Header
|
||||||
|
│ ├── common/ # ConfirmDialog, DatePicker 등
|
||||||
|
│ ├── schedule/ # CategorySelector 등
|
||||||
|
│ └── album/ # PhotoUploader 등
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 중복 코드 제거
|
||||||
|
|
||||||
|
#### utils/schedule.js 통합 사용
|
||||||
|
- `Schedules.jsx`의 로컬 함수들 제거
|
||||||
|
- 모든 곳에서 `@/utils/schedule` import
|
||||||
|
|
||||||
|
#### utils/format.js에 decodeHtmlEntities 통합
|
||||||
|
- 중복 정의 제거
|
||||||
|
|
||||||
|
#### api/transforms.js 생성
|
||||||
|
- `transformSchedule` 함수 통합
|
||||||
|
|
||||||
|
### 2.4 대형 파일 분리
|
||||||
|
|
||||||
|
#### AlbumPhotos.jsx (1536줄)
|
||||||
|
```
|
||||||
|
pages/pc/admin/albums/
|
||||||
|
├── AlbumPhotos.jsx # 메인 (상태 관리)
|
||||||
|
├── components/
|
||||||
|
│ ├── PhotoUploader.jsx # 업로드 UI
|
||||||
|
│ ├── PhotoGrid.jsx # 사진 그리드
|
||||||
|
│ ├── PhotoPreview.jsx # 미리보기 모달
|
||||||
|
│ └── BulkEditTools.jsx # 일괄 편집 도구
|
||||||
|
└── hooks/
|
||||||
|
└── usePhotoUpload.js # 업로드 로직
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Schedules.jsx (1471줄)
|
||||||
|
```
|
||||||
|
pages/pc/admin/schedules/
|
||||||
|
├── Schedules.jsx # 메인
|
||||||
|
├── components/
|
||||||
|
│ ├── ScheduleList.jsx # 목록 (가상화)
|
||||||
|
│ ├── ScheduleSearch.jsx # 검색 UI
|
||||||
|
│ └── MonthNavigator.jsx # 월 선택
|
||||||
|
└── hooks/
|
||||||
|
└── useScheduleList.js # 목록 조회 로직
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ScheduleForm.jsx (1046줄)
|
||||||
|
```
|
||||||
|
pages/pc/admin/schedules/
|
||||||
|
├── ScheduleForm.jsx # 메인
|
||||||
|
└── components/
|
||||||
|
├── BasicInfoForm.jsx # 기본 정보
|
||||||
|
├── MemberSelector.jsx # 멤버 선택
|
||||||
|
└── SourceInput.jsx # 출처 입력
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 작업 순서
|
||||||
|
|
||||||
|
### Phase 1: 구조 정리 (비파괴적)
|
||||||
|
1. [ ] API 구조 개선 (폴더 재배치, transforms.js 생성)
|
||||||
|
2. [ ] 중복 유틸 함수 제거 (Schedules.jsx 등)
|
||||||
|
3. [ ] 컴포넌트 폴더 구조화
|
||||||
|
|
||||||
|
### Phase 2: 대형 파일 분리
|
||||||
|
1. [ ] Schedules.jsx 분리
|
||||||
|
2. [ ] ScheduleForm.jsx 분리
|
||||||
|
3. [ ] AlbumPhotos.jsx 분리
|
||||||
|
4. [ ] ScheduleDict.jsx 분리
|
||||||
|
5. [ ] AlbumForm.jsx 분리
|
||||||
|
|
||||||
|
### Phase 3: 검증
|
||||||
|
1. [ ] 모든 페이지 동작 확인
|
||||||
|
2. [ ] 빌드 확인
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 삭제할 항목
|
||||||
|
|
||||||
|
### constants/index.js에서 삭제됨
|
||||||
|
- `CATEGORY_NAMES` (미사용)
|
||||||
|
- `ALBUM_TYPES` (미사용)
|
||||||
|
- `SOCIAL_LINKS.tiktok` (불필요)
|
||||||
|
- `SOCIAL_LINKS.fancafe` (불필요)
|
||||||
|
|
||||||
|
### 삭제 예정
|
||||||
|
- `api/pc/` 폴더 구조 (→ `api/public/`, `api/admin/`으로 변경)
|
||||||
|
- `api/pc/common/` (→ `api/public/`으로 통합)
|
||||||
|
- 각 파일의 중복 유틸 함수
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,455 +0,0 @@
|
||||||
# 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/pc/admin/`)
|
|
||||||
- [x] albums.js
|
|
||||||
- [x] members.js
|
|
||||||
- [x] schedules.js
|
|
||||||
- [x] categories.js
|
|
||||||
- [x] stats.js
|
|
||||||
- [x] bots.js
|
|
||||||
- [x] suggestions.js
|
|
||||||
|
|
||||||
### 훅 (hooks/)
|
|
||||||
- [x] useAlbumData.js
|
|
||||||
- [x] useMemberData.js
|
|
||||||
- [x] useScheduleData.js
|
|
||||||
- [x] useScheduleSearch.js
|
|
||||||
- [x] useScheduleFiltering.js
|
|
||||||
- [x] useCalendar.js
|
|
||||||
- [x] useMediaQuery.js
|
|
||||||
- [x] useAdminAuth.js
|
|
||||||
|
|
||||||
### 관리자 훅 (hooks/pc/admin/, hooks/common/)
|
|
||||||
- [x] useAdminAuth.js (hooks/pc/admin/)
|
|
||||||
- [x] useToast.js (hooks/common/)
|
|
||||||
|
|
||||||
### 스토어 (stores/)
|
|
||||||
- [x] useScheduleStore.js
|
|
||||||
- [x] useAuthStore.js
|
|
||||||
- [x] useUIStore.js
|
|
||||||
|
|
||||||
### 상수 (constants/)
|
|
||||||
- [x] index.js (CATEGORY_ID, MIN_YEAR, SEARCH_LIMIT 등)
|
|
||||||
|
|
||||||
### 유틸리티 (utils/)
|
|
||||||
- [x] index.js
|
|
||||||
- [x] date.js
|
|
||||||
- [x] format.js
|
|
||||||
- [x] cn.js (className 유틸)
|
|
||||||
- [x] schedule.js (일정 관련 유틸)
|
|
||||||
|
|
||||||
### 공통 컴포넌트 (components/common/)
|
|
||||||
- [x] Loading.jsx
|
|
||||||
- [x] ErrorBoundary.jsx
|
|
||||||
- [x] Toast.jsx
|
|
||||||
- [x] Lightbox.jsx (PC용)
|
|
||||||
- [x] MobileLightbox.jsx (Mobile용, Swiper 기반)
|
|
||||||
- [x] LightboxIndicator.jsx
|
|
||||||
- [x] Tooltip.jsx
|
|
||||||
- [x] ScrollToTop.jsx
|
|
||||||
|
|
||||||
### PC 컴포넌트 (components/pc/)
|
|
||||||
- [x] Layout.jsx
|
|
||||||
- [x] Header.jsx
|
|
||||||
- [x] Footer.jsx
|
|
||||||
- [x] Calendar.jsx
|
|
||||||
- [x] ScheduleCard.jsx
|
|
||||||
- [x] BirthdayCard.jsx
|
|
||||||
- [x] CategoryFilter.jsx
|
|
||||||
|
|
||||||
### Mobile 컴포넌트 (components/mobile/)
|
|
||||||
- [x] Layout.jsx
|
|
||||||
- [x] Header.jsx (MobileHeader)
|
|
||||||
- [x] BottomNav.jsx (MobileBottomNav)
|
|
||||||
- [x] Calendar.jsx
|
|
||||||
- [x] ScheduleCard.jsx
|
|
||||||
- [x] ScheduleListCard.jsx
|
|
||||||
- [x] ScheduleSearchCard.jsx
|
|
||||||
- [x] BirthdayCard.jsx
|
|
||||||
|
|
||||||
### 공용 일정 컴포넌트 (components/schedule/)
|
|
||||||
- [x] confetti.js (fireBirthdayConfetti)
|
|
||||||
- [x] AdminScheduleCard.jsx
|
|
||||||
|
|
||||||
### 관리자 컴포넌트 (components/pc/admin/)
|
|
||||||
- [x] Layout.jsx
|
|
||||||
- [x] Header.jsx
|
|
||||||
- [x] ConfirmDialog.jsx
|
|
||||||
- [x] CustomDatePicker.jsx
|
|
||||||
- [x] CustomTimePicker.jsx
|
|
||||||
- [x] NumberPicker.jsx
|
|
||||||
|
|
||||||
### 페이지 - Home (pages/home/)
|
|
||||||
- [x] pc/Home.jsx
|
|
||||||
- [x] mobile/Home.jsx
|
|
||||||
|
|
||||||
### 페이지 - Members (pages/members/)
|
|
||||||
- [x] pc/Members.jsx
|
|
||||||
- [x] mobile/Members.jsx
|
|
||||||
|
|
||||||
### 페이지 - Album (pages/album/)
|
|
||||||
- [x] pc/Album.jsx
|
|
||||||
- [x] pc/AlbumDetail.jsx
|
|
||||||
- [x] pc/AlbumGallery.jsx
|
|
||||||
- [x] pc/TrackDetail.jsx
|
|
||||||
- [x] mobile/Album.jsx
|
|
||||||
- [x] mobile/AlbumDetail.jsx
|
|
||||||
- [x] mobile/AlbumGallery.jsx
|
|
||||||
- [x] mobile/TrackDetail.jsx
|
|
||||||
|
|
||||||
### 페이지 - Schedule (pages/schedule/)
|
|
||||||
- [x] sections/DefaultSection.jsx
|
|
||||||
- [x] sections/XSection.jsx
|
|
||||||
- [x] sections/YoutubeSection.jsx
|
|
||||||
- [x] sections/utils.js
|
|
||||||
- [x] sections/index.js
|
|
||||||
- [x] pc/Schedule.jsx
|
|
||||||
- [x] pc/ScheduleDetail.jsx
|
|
||||||
- [x] pc/Birthday.jsx
|
|
||||||
- [x] mobile/Schedule.jsx
|
|
||||||
- [x] mobile/ScheduleDetail.jsx
|
|
||||||
- [x] mobile/Birthday.jsx
|
|
||||||
|
|
||||||
### 페이지 - Common (pages/common/)
|
|
||||||
- [x] pc/NotFound.jsx
|
|
||||||
- [x] mobile/NotFound.jsx
|
|
||||||
|
|
||||||
### 페이지 - Admin (pages/pc/admin/) - PC 전용
|
|
||||||
- [x] login/Login.jsx
|
|
||||||
- [x] dashboard/Dashboard.jsx
|
|
||||||
- [x] members/Members.jsx
|
|
||||||
- [x] albums/Albums.jsx
|
|
||||||
- [x] albums/AlbumForm.jsx
|
|
||||||
- [x] albums/AlbumPhotos.jsx
|
|
||||||
- [x] albums/AlbumTeasers.jsx
|
|
||||||
- [x] schedules/Schedules.jsx
|
|
||||||
- [x] schedules/ScheduleForm.jsx
|
|
||||||
- [x] schedules/ScheduleCategory.jsx
|
|
||||||
- [x] schedules/ScheduleDict.jsx
|
|
||||||
- [x] schedules/ScheduleBots.jsx
|
|
||||||
|
|
||||||
### 기타
|
|
||||||
- [x] App.jsx (BrowserView/MobileView 라우팅)
|
|
||||||
- [x] main.jsx
|
|
||||||
|
|
||||||
### CSS 파일
|
|
||||||
- [x] index.css
|
|
||||||
- [x] mobile.css (모바일 전용 스타일, 달력 등)
|
|
||||||
- [x] 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: 공통 컴포넌트
|
|
||||||
- [x] Phase 7: PC/Mobile 레이아웃 컴포넌트
|
|
||||||
- [x] Phase 8: App.jsx (BrowserView/MobileView 라우팅)
|
|
||||||
- [x] Phase 9: 공개 페이지 전체
|
|
||||||
- Home, Members, Album, AlbumDetail, AlbumGallery, TrackDetail
|
|
||||||
- Schedule, ScheduleDetail, Birthday
|
|
||||||
|
|
||||||
### 미완료 작업
|
|
||||||
|
|
||||||
#### 공개 영역
|
|
||||||
- ✅ 모두 완료
|
|
||||||
|
|
||||||
#### 관리자 영역
|
|
||||||
- [x] 관리자 API 전체 (api/pc/admin/)
|
|
||||||
- [x] 관리자 컴포넌트 전체 (components/pc/admin/)
|
|
||||||
- [x] 관리자 페이지 전체 (pages/pc/admin/)
|
|
||||||
- [x] useToast 훅 (hooks/common/)
|
|
||||||
- [x] useAdminAuth 훅 (hooks/pc/admin/)
|
|
||||||
|
|
||||||
### 최종 검증
|
|
||||||
- [ ] 모든 라우트 동작 확인
|
|
||||||
- [ ] PC/Mobile 전환 테스트
|
|
||||||
- [ ] 관리자 기능 테스트
|
|
||||||
- [ ] frontend-temp → frontend 교체
|
|
||||||
|
|
@ -9,29 +9,11 @@ export const CATEGORY_ID = {
|
||||||
X: 3,
|
X: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 카테고리 이름 매핑 */
|
|
||||||
export const CATEGORY_NAMES = {
|
|
||||||
[CATEGORY_ID.DEFAULT]: '기본',
|
|
||||||
[CATEGORY_ID.YOUTUBE]: 'YouTube',
|
|
||||||
[CATEGORY_ID.X]: 'X (Twitter)',
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 공식 SNS 링크 */
|
/** 공식 SNS 링크 */
|
||||||
export const SOCIAL_LINKS = {
|
export const SOCIAL_LINKS = {
|
||||||
youtube: 'https://www.youtube.com/@fromis9_official',
|
youtube: 'https://www.youtube.com/@fromis9_official',
|
||||||
instagram: 'https://www.instagram.com/officialfromis_9',
|
instagram: 'https://www.instagram.com/officialfromis_9',
|
||||||
twitter: 'https://twitter.com/realfromis_9',
|
x: 'https://twitter.com/realfromis_9',
|
||||||
tiktok: 'https://www.tiktok.com/@officialfromis_9',
|
|
||||||
fancafe: 'https://cafe.daum.net/officialfromis9',
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 앨범 타입 */
|
|
||||||
export const ALBUM_TYPES = {
|
|
||||||
FULL: '정규',
|
|
||||||
MINI: '미니',
|
|
||||||
SINGLE: '싱글',
|
|
||||||
DIGITAL: '디지털',
|
|
||||||
OST: 'OST',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 타임존 */
|
/** 타임존 */
|
||||||
|
|
|
||||||
|
|
@ -50,16 +50,10 @@ export function getScheduleTime(schedule) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 스케줄에서 멤버 이름 목록 추출
|
* 스케줄에서 멤버 이름 목록 추출
|
||||||
* 다양한 형식 처리 (member_names 문자열, 문자열 배열, 객체 배열)
|
|
||||||
* @param {object} schedule - 스케줄 객체
|
* @param {object} schedule - 스케줄 객체
|
||||||
* @returns {string[]} 멤버 이름 배열
|
* @returns {string[]} 멤버 이름 배열
|
||||||
*/
|
*/
|
||||||
export function getMemberList(schedule) {
|
export function getMemberList(schedule) {
|
||||||
// member_names 문자열이 있으면 사용 (쉼표 구분)
|
|
||||||
if (schedule.member_names) {
|
|
||||||
return schedule.member_names.split(',').map((n) => n.trim()).filter(Boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
const members = schedule.members || [];
|
const members = schedule.members || [];
|
||||||
if (members.length === 0) return [];
|
if (members.length === 0) return [];
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue