fromis_9/docs/admin-migration.md
caadiq 1d5626568a feat: 일정 추가 폼 카테고리별 분기 마이그레이션
- form/index.jsx: 카테고리 선택 메인 페이지
- form/YouTubeForm.jsx: YouTube URL 기반 일정 추가
- form/XForm.jsx: X 게시글 ID 기반 일정 추가
- form/components/CategorySelector.jsx: 카테고리 선택기
- edit/YouTubeEditForm.jsx: YouTube 일정 수정 폼
- App.jsx 라우트 업데이트
  - /admin/schedule/new → 새로운 카테고리 선택 폼
  - /admin/schedule/new-legacy → 기존 레거시 폼
  - /admin/schedule/youtube/:id/edit → YouTube 수정 폼

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 21:11:59 +09:00

17 KiB

관리자 페이지 마이그레이션 계획서

개요

  • 목표: 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 경로를 새 구조에 맞게 수정합니다.

// 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 생성:

// 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 사용 가능)

사용 예시:

// 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단계: 폴더 구조 재편

  • api/ 구조 변경 (common/, pc/common/, pc/public/, pc/admin/)
  • components/ 구조 변경 (common/, pc/public/, pc/admin/, mobile/)
  • hooks/ 구조 변경 (common/, pc/admin/)
  • pages/ 구조 변경 (pc/public/, mobile/)
  • 모든 import 경로 업데이트
  • 각 폴더에 index.js 생성 (re-export)
  • 개발 서버 동작 확인

2단계: 관리자 기반 설정

  • 관리자 API 마이그레이션 (api/pc/admin/)
  • AdminLayout 마이그레이션 (components/pc/admin/)
  • AdminHeader 마이그레이션 (components/pc/admin/)
  • useAdminAuth 훅 이동 (hooks/pc/admin/)
  • 관리자 라우트 설정 (App.jsx)
  • AdminLogin 페이지 마이그레이션

3단계: 간단한 페이지

  • AdminLogin 마이그레이션 (2단계에서 완료)
  • AdminDashboard 마이그레이션
  • AdminMembers 마이그레이션
  • AdminMemberEdit 마이그레이션
  • useToast 훅 추가

4단계: 앨범 관리

  • AdminAlbums 마이그레이션
  • AdminAlbumForm 마이그레이션
  • AdminAlbumPhotos 마이그레이션 (SSE 처리 포함)

5단계: 일정 관리

  • AdminSchedule 마이그레이션
  • AdminScheduleForm 마이그레이션
  • AdminScheduleCategory 마이그레이션
  • AdminScheduleDict 마이그레이션
  • AdminScheduleBots 마이그레이션
  • 카테고리별 폼 분기 페이지 마이그레이션 (form/index.jsx)
  • YouTubeForm 마이그레이션 (form/YouTubeForm.jsx)
  • XForm 마이그레이션 (form/XForm.jsx)
  • CategorySelector 마이그레이션 (form/components/CategorySelector.jsx)
  • 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 활용

참고