docs(design): #329 admin/page.tsx 분리 + 유틸 통일 설계서 (Architect)
5개 패널을 _panels/<Panel>.tsx로 추출 + localStorage→getAdminToken + SSE→consumeSseStream. 내부 로직 변경 없음(점진적 접근). 설계서: docs/design/329-admin-split/README.md (Approved) Refs: #329 (Architect)
This commit is contained in:
107
docs/design/329-admin-split/README.md
Normal file
107
docs/design/329-admin-split/README.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# 설계서: admin/page.tsx 분리 + 토큰/SSE 유틸 통일 (#329)
|
||||
|
||||
> **상태**: Approved
|
||||
> **작성**: [AI] Architect · **최종수정**: 2026-06-15
|
||||
> **추적성** — Redmine: #329 · 부모: #304 (현행화 frontend-admin, 09-Done)
|
||||
> · 구현 파일: `frontend/src/app/admin/page.tsx`, `frontend/src/app/admin/_panels/*.tsx` (신규), `frontend/src/lib/admin-utils.ts`
|
||||
> · 테스트: 수동 (각 탭 진입 + 기존 시나리오 회귀)
|
||||
|
||||
## 1. 목적 (Why)
|
||||
|
||||
`admin/page.tsx`가 2817 LOC 단일 파일. 5개 패널이 같은 파일 안에 함께 있어 (a) 빌드 변경 시 무관한 패널까지 재빌드/재배포, (b) 코드 리뷰 시 충돌 가능성↑, (c) 로직 격리 어려움. 또한 `localStorage` 직접 호출 + SSE 파싱 코드 중복이 남아있어 #304 후속에서 한 번 더 정리.
|
||||
|
||||
## 2. 범위 (Scope)
|
||||
|
||||
- **포함**
|
||||
- 5개 패널을 `app/admin/_panels/<Panel>.tsx`로 추출 (Next.js underscore prefix로 라우팅 제외).
|
||||
- `page.tsx`는 탭 라우팅 + 헤더 + 패널 import만.
|
||||
- 남은 `localStorage.getItem("tasteby_token")` 호출 → `getAdminToken()`/`authHeaders()` 교체.
|
||||
- SSE 파싱 중복(약 5~6곳) → `consumeSseStream()` 활용.
|
||||
- 공유 타입(`AdminUser`/`UserFavorite`/`UserReview`/`UserMemo`/`VideoSortKey`)을 _panels 파일 내부 또는 `api.ts`에 옮김(짧은 타입만).
|
||||
- **제외**
|
||||
- 패널 내부 로직 변경 (state/effect 그대로).
|
||||
- catch{/*ignore*/} 일괄 로깅 (별도 후속).
|
||||
- ad-hoc 타입 캐스팅 정리 (별도 후속).
|
||||
- 디자인 시스템 색상 통일.
|
||||
|
||||
## 3. 인수조건
|
||||
|
||||
- [ ] 5개 파일 신규: `_panels/{Channels,Videos,Restaurants,Users,Daemon}Panel.tsx`.
|
||||
- [ ] `page.tsx` < 200 LOC (이전 2817).
|
||||
- [ ] localStorage 직접 호출이 admin 페이지 내에 0건.
|
||||
- [ ] SSE reader 직접 호출(`response.body?.getReader()`)이 0건.
|
||||
- [ ] 모든 탭 진입 + 기존 시나리오 회귀 없음(빌드 통과 + 수동 smoke).
|
||||
- [ ] dev 빌드 + 운영 배포 성공.
|
||||
|
||||
## 4. 컨텍스트 & 제약
|
||||
|
||||
- Next.js 16 (App Router). `_` prefix 디렉토리는 route 제외.
|
||||
- `"use client"` 지시문 각 패널 파일 상단에 필요.
|
||||
- React Server Components 미사용 (모두 클라이언트 컴포넌트).
|
||||
- `useAuth()` 훅이 `auth-context`에 있음. 부모 `AdminPage`가 isAdmin 판정 후 prop으로 패널에 전달.
|
||||
- 패널 간 상태 공유 없음 (각각 독립).
|
||||
|
||||
## 5. 아키텍처 개요
|
||||
|
||||
```
|
||||
app/admin/
|
||||
page.tsx ← 탭 라우팅 + 헤더 + CacheFlushButton + 패널 import
|
||||
_panels/
|
||||
ChannelsPanel.tsx ← 214 LOC
|
||||
VideosPanel.tsx ← 1272 LOC (가장 큼)
|
||||
RestaurantsPanel.tsx ← 667 LOC
|
||||
UsersPanel.tsx ← 332 LOC
|
||||
DaemonPanel.tsx ← 223 LOC
|
||||
|
||||
lib/admin-utils.ts (이미 존재)
|
||||
├─ getAdminToken()
|
||||
├─ authHeaders()
|
||||
└─ consumeSseStream()
|
||||
```
|
||||
|
||||
## 6. 함수 명세
|
||||
|
||||
| 단위 | 책임 | 비고 |
|
||||
|------|------|------|
|
||||
| `page.tsx` (재작성) | 탭 라우팅 + 패널 import | < 200 LOC |
|
||||
| `_panels/*.tsx` (신규 5개) | 각 패널 로직 그대로 옮김 | "use client" |
|
||||
| `localStorage` 호출 (~10곳) | `getAdminToken()`/`authHeaders()`로 통일 | 의미 동일 |
|
||||
| SSE `getReader` (~5곳) | `consumeSseStream(resp, onEvent)`로 통일 | 의미 동일 |
|
||||
|
||||
## 7. 흐름
|
||||
|
||||
1. `_panels/` 디렉토리 생성.
|
||||
2. 각 패널 함수 + 그에 종속된 타입/상수를 `<Panel>Panel.tsx`로 잘라 옮김.
|
||||
3. 각 파일에 `"use client"` + import 추가.
|
||||
4. `localStorage.getItem("tasteby_token")` → `getAdminToken()` 일괄.
|
||||
5. SSE `getReader/decoder/buf.split/match` 패턴 → `consumeSseStream(resp, onEvent)` 일괄.
|
||||
6. `page.tsx` 재작성 — 탭 라우팅 + 패널 import.
|
||||
7. `npm run build`.
|
||||
8. `pm2 restart` 또는 `deploy.sh --frontend-only`.
|
||||
|
||||
## 8. 엣지케이스
|
||||
|
||||
- **순환 import**: 패널 간 의존 없음 → 안전.
|
||||
- **Type 중복**: `AdminUser` 등 패널 내부 타입은 그대로 옮김. 공유 타입은 `api.ts`에 있음.
|
||||
- **default export vs named**: 각 패널은 named export. `page.tsx`에서 `import { ChannelsPanel } from "./_panels/ChannelsPanel"`.
|
||||
- **빌드 크기**: 동일(코드 splitting은 별도 작업).
|
||||
|
||||
## 9. 테스트
|
||||
|
||||
- 빌드: `npm run build` 통과.
|
||||
- 수동:
|
||||
- `/admin` 접근 → 5탭 모두 진입 가능.
|
||||
- 채널 추가, 영상 강제 추출(SSE), 식당 검색/수정, 유저 권한 토글, 데몬 설정 변경 — 모두 정상.
|
||||
- 자동: 별도 후속(테스트 인프라 #343).
|
||||
|
||||
## 10. 리스크 & 대안
|
||||
|
||||
- **선택**: 5개 파일 추출 + 내부 로직 그대로.
|
||||
- **대안 A**: 추출 + 내부 리팩터링 동시 — 회귀 위험↑, 별도 후속이 안전.
|
||||
- **대안 B**: Atomic Design (atoms/molecules/organisms) — 큰 재구조화. 미루기.
|
||||
- **트레이드오프**: 외형은 동일, 유지보수성/충돌 가능성만 개선. 점진적 접근.
|
||||
|
||||
## 11. 미해결 질문
|
||||
|
||||
- 공통 panel layout(헤더/리스트/페이징) 추상화 — 후속.
|
||||
- VideosPanel 1272 LOC 내부 분할(상태 머신 + SSE 흐름 분리) — 별도 후속.
|
||||
Reference in New Issue
Block a user