docs(refactor): SaaS 운영 리팩토링 로드맵 + Phase 0 정리·삭제 설계

비전 재정의(외주 메인 + 사주·타로·음악 별도 서비스) 기반 Phase 0~3 로드맵.
Phase 0: eBay 세트·packages/subscription·PortOne 잔재·죽은 페이지·고아 코드 삭제 설계.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAtcmKKtqDUe4NyVgy1aLQ
This commit is contained in:
2026-07-02 13:47:29 +09:00
parent 65f0a6bb41
commit 9241eac4e1

View File

@@ -0,0 +1,179 @@
# SaaS 운영 리팩토링 — 로드맵 + Phase 0(정리·삭제) 설계
- 날짜: 2026-07-02
- 배경: 4개 병렬 감사(공개 라우트/API/보존 서브시스템/admin)로 전 기능의 생사를 판정한 뒤, CEO가 운영 비전을 재정의함. 이 문서는 전체 로드맵과 Phase 0 상세 설계를 담는다.
---
## 1. 운영 비전 (CEO 확정)
### 1축 — SaaS 외주 개발 (메인)
- 모든 의뢰는 **발주서**로 관리
- 외주 프로그램 소개 페이지 (제품 소개 + 제품/의뢰 금액)
- 의뢰 폼 ↔ 이메일 연동
- 회원 관리 + 회원 페이지 (회원 정보, 발주서 확인)
- 관리자: 발주 관리 · 회원 관리 · 수익 관리 · 노출 서비스 관리 · 제품 관리 · 광고 관리
- 완성 제품(웹사이트·프로그램) 예시 페이지
### 2축 — 별도 서비스
- **사주**: 회원별로 보고, 결과를 마이페이지에서 재확인
- **타로**: 동일 패턴 (이 repo에 자체 구현)
- **음악**: "나의 이야기를 음악으로" — 개별 음악 제작 + 영상화까지, 고도화 필요
### 핵심 결정 (2026-07-02 Q&A)
| 결정 | 내용 |
|------|------|
| 발주서 정의 | **견적 수락 시 그 견적이 발주서로 전환**. 기존 contact→quote→order 상태머신 유지, 문서 개념만 통합. 마이페이지·admin 모두 발주서 중심 리네이밍 |
| 타로 구축 | 이 repo 자체 구현 (Next.js API에서 AI 직접 호출 + Supabase 회원별 저장). NAS tarot-lab 연동 아님 |
| 과금 | 별도 서비스(사주·타로·음악 체험) **무료**, **음악 영상화만 유료(계좌이체)**. 외주는 기존 발주서·계좌이체 |
| 삭제 확정 | eBay 세트 + packages/subscription + PortOne 잔재 |
| gyeol/CONTOUR | **의도적 숨김 보존** (삭제 안 함) |
| IA 재편 시점 | Phase 0은 삭제만. TopNav·홈 개편은 각 Phase에서 해당 기능과 함께 |
---
## 2. 로드맵 (4 Phase 순차, 각자 독립 스펙→플랜→구현)
| Phase | 내용 | 스펙 |
|-------|------|------|
| **0** | 정리·삭제 (이 문서) | 이 문서 §3 |
| **1** | 외주 코어 — 발주서 개념 통합(마이페이지·admin 리네이밍+뷰), `/work/website/samples` 8종을 "완성 제품 예시"로 정식 재노출, projects API 마이페이지 배선, admin 광고 관리 신설(admin/marketing 재편) | 추후 |
| **2** | 사주 재활성(무료화) + 타로 신규 구현, 회원별 결과 저장·마이페이지 재확인 탭 | 추후 |
| **3** | 음악 고도화 — 스토리 입력→음악 생성→영상화(유료·계좌이체 발주), studio 콜백 결함 해소 | 추후 |
**순차 이유**: 삭제부터 하면 이후 작업의 탐색 노이즈가 사라짐. mypage와 service_settings를 여러 Phase가 만지므로 병렬 진행 시 충돌. 매 Phase가 배포 가능 상태로 종료.
---
## 3. Phase 0 상세 — 정리·삭제
원칙: **비전에 없는 기능 + 도달 불가능한 죽은 코드 제거. IA(네비·홈)는 건드리지 않음.** 외부 URL 호환을 위해 next.config.ts 리다이렉트는 전부 유지.
### 3-1. 삭제 목록
#### A. eBay 세트 (특정 클라이언트 제안용 리드 도구 — 용도 종료)
| 대상 | 경로 |
|------|------|
| 문진 제출 API | `app/api/questionnaire/submit/route.ts` |
| admin 문진 페이지 | `app/admin/questionnaire/page.tsx` |
| admin 문진 API | `app/api/admin/questionnaire/route.ts`, `app/api/admin/questionnaire/[id]/route.ts` |
| admin 문서 페이지 | `app/admin/documents/page.tsx` |
| admin 문서 API | `app/api/admin/documents/[filename]/route.ts` |
| eBay 라이브러리 | `lib/ebay-tools/` (crawler·pricing·ai-analyzer·types, import 0회 확인) |
| 콘텐츠 | `CONTENT/ebay-tool-questionnaire.html`, `CONTENT/ebay-tool-proposal.html`, `CONTENT/ARCHITECTURE_EBAY_PARTS_TOOL.md` |
| 사이드바 | AdminSidebar에서 문진·문서 메뉴 항목 제거 |
| DB | `questionnaire_responses`, `ebay_search_history` DROP |
#### B. packages + subscription (SaaS 피벗 잔재 — 재개 시 재설계)
| 대상 | 경로 |
|------|------|
| 페이지 | `app/packages/` (page + layout) |
| 카탈로그 | `lib/saas-catalog.ts` (빈 배열) |
| 구독 API | `app/api/subscription/route.ts`, `app/api/subscription/[id]/route.ts` (프론트 호출 0회) |
| 구독 cron | `app/api/cron/subscription-expiry/route.ts` + `vercel.json` crons 항목(유일 항목이므로 crons 비움) |
| 서비스 토글 | `service_settings`에서 `packages` 행 제거, admin/services 목록·`HideableService` 타입에서 `'packages'` 제거 |
| DB | `subscriptions` DROP |
**파급 수정 (subscriptions 참조 3곳)**:
- `app/api/admin/stats/route.ts` — 구독 집계 제거
- `app/api/admin/members/route.ts` — 구독 카운트 제거
- `app/work/saju/result/page.tsx` — 구독 확인 로직 제거 (사주 무료화 방향과 일치)
#### C. PortOne 결제 잔재 (계좌이체 단일 소스 확정)
| 대상 | 경로 |
|------|------|
| 컴포넌트 | `app/components/PaymentButton.tsx` |
| 페이지 | `app/payment/` 전체 (test — 코드 스스로 "배포 전 삭제" 명시 · fail · success) |
| API | `app/api/payment/confirm/route.ts` |
| 라이브러리 | `lib/payment-channels.ts`, `lib/products.ts` (소비처가 전부 삭제 대상임을 확인) |
| 의존성 | `@portone/browser-sdk` (package.json) |
**파급 수정**: `app/work/saju/page.tsx`, `app/work/saju/result/SajuAISection.tsx`의 PaymentButton import·사용 제거 (무료 전환). `/payment/success`로 push하는 코드는 PaymentButton뿐이므로 함께 소멸.
#### D. 리다이렉트에 가려 렌더 불가능한 페이지 (redirect는 유지)
- `app/work/page.tsx` (`/work``/outsourcing`)
- `app/work/freelance/page.tsx` (`/work/freelance``/outsourcing`)
- `app/work/website/page.tsx` (`/work/website``/outsourcing`)
- `app/music/packs/page.tsx` (`/music/packs``/products`)
- 전이 고아: `app/components/ContactForm.tsx` (유일 소비처가 죽은 `/work/freelance`), `lib/freelance-portfolio.ts` (소비처가 죽은 `/work`·`/work/freelance`뿐)
주의: `app/work/website/samples/*` 8종은 **삭제 금지**`/services/website/samples/:slug` 리다이렉트 목적지로 도달 가능하며 Phase 1 재활용 자산.
#### E. 2026-06 라이트 재설계 잔재
- `app/components/deepfield/HeroField.tsx` (import 0회, 스펙상 "보존만"이었으나 새 비전으로 폐기 확정)
- `app/components/deepfield/useFieldMode.ts` (HeroField 전용)
- `lib/deepfield-mode.ts` + `lib/__tests__/deepfield-mode.test.ts` (체인 고아)
- 의존성 `three` 제거 (HeroField가 유일 사용처임을 확인)
- 잔존: `deepfield/{ScrollReveal,ShowcaseGrid,ShowcaseCard,CountUp}.tsx`는 활성 — 유지
#### F. 고아 API
- `app/api/track/[token]/route.ts` — 추적 페이지가 Supabase 직접 조회, 라우트 호출 0회
- `app/api/saju/lotto/route.ts` — 프론트 fetch 0회, 외부 엔진용. 비전 무관
### 3-2. 유지 목록 (비전에 엮이거나 의도적 보존)
| 자산 | 이유 | 활용 Phase |
|------|------|-----------|
| `app/api/projects/`, `app/api/projects/link/` | "회원 페이지에서 발주서 확인" 용도의 선구현(quotes+milestones 집계) | Phase 1 배선 |
| `/work/website/samples/*` 8종 | 완성 제품 예시 페이지 자산 | Phase 1 재노출 |
| telegram 3종 (webhook·connect·setup) + `lib/telegram.ts` | mypage 연결 UI 활성, 알림 채널 재활용 여지. 단 subscription-expiry 소비처 제거로 `sendMessage` 소비처가 줄어드는 것은 무방 | Phase 2~3 |
| gyeol 세트 (`/gyeol`, `/api/survey`, admin/survey, `survey_responses`) | CEO 의도적 숨김 보존 | — |
| `admin/marketing` | 광고 관리로 재편 예정 | Phase 1 |
| `admin/packs` 페이지 + `/api/admin/packs*` | 페이지는 자칭 레거시(products가 대체)나 API는 products 페이지·mypage 다운로드가 공유 — Phase 0에서는 건드리지 않고 Phase 1에서 products로 완전 통합 후 페이지 제거 검토 | Phase 1 |
| `portfolio/[token]` + `admin/portfolio-token` | 위시캣 등 지원용 토큰 공유 도구 | — |
| saju 페이지·API (analyze, save-interpretation) | 별도 서비스 2축, 무료화 후 재활성 | Phase 2 |
| music 페이지·studio API | 음악 고도화 기반 (콜백 결함은 Phase 3에서 해소) | Phase 3 |
| next.config.ts 리다이렉트 전체 | 외부 유입 URL 호환 | — |
### 3-3. DB 마이그레이션
신규 파일 `supabase/migrations/2026-07-02-phase0-cleanup.sql` 1개:
```sql
DROP TABLE IF EXISTS questionnaire_responses;
DROP TABLE IF EXISTS ebay_search_history;
DROP TABLE IF EXISTS subscriptions;
DELETE FROM service_settings WHERE id = 'packages';
```
- **클라우드 Supabase + NAS self-host 양쪽 적용** (운영 규칙)
- `survey_responses`는 건드리지 않음 (gyeol 보존)
- 기존 마이그레이션 파일(004_subscriptions.sql 등)은 이력이므로 삭제하지 않음
### 3-4. 검증
1. `npm test` (vitest) 통과 — deepfield-mode.test.ts 삭제 반영
2. `npm run build` 성공 (standalone)
3. 잔존 참조 grep 스윕 0건: `PaymentButton|payment-channels|lib/products|saas-catalog|ebay|questionnaire|subscription|freelance-portfolio|ContactForm|HeroField|useFieldMode|deepfield-mode|portone|from 'three'`
4. admin 사이드바에서 제거된 메뉴(문진·문서) 링크 없음 확인
5. 수동: `/admin/services`에 packages 미표시, `/admin/dashboard`·`/admin/members` 정상 렌더(구독 집계 제거 후)
### 3-5. 산출물
- 삭제 커밋(들) + 마이그레이션 파일 + CLAUDE.md 갱신(삭제된 기능 서술 제거: PortOne 보존 서술, 숨김 서비스 표에서 packages 등)
---
## 4. Phase 1~3 개요 (각자 별도 스펙에서 상세화)
### Phase 1 — 외주 코어 (발주서 통합)
- quotes의 `accepted` 이후 상태를 "발주서"로 표면화: 마이페이지 "내 발주서" 탭(projects API 배선), admin 발주 관리 뷰 리네이밍
- `/work/website/samples/*` → 완성 제품 예시 허브로 재노출(TopNav 반영)
- admin "광고 관리" 신설 (admin/marketing 재편)
- admin/packs 페이지의 products 통합 마무리 후 페이지 제거 검토
- 이메일 연동 점검 (contact·quote·order Resend 플로우)
### Phase 2 — 사주 + 타로 (회원 연동)
- 사주: service_settings 토글 ON + 무료화 + 결과 저장을 회원 계정에 연결, 마이페이지 재확인 탭
- 타로: 자체 구현 (AI 호출 API + 카드 UI + Supabase 저장 + 마이페이지)
- TopNav에 별도 서비스 진입점
### Phase 3 — 음악 고도화
- "나의 이야기를 음악으로": 스토리 입력 → 음악 생성(Suno, 폴링) → 영상화 의뢰(유료·계좌이체 발주서)
- `/api/studio/callback` 댕글링 해소(폴링 전용 확정 또는 콜백 구현)
---
## 5. 감사 근거 (2026-07-02 병렬 감사 요약)
- 공개 라우트: LIVE 11 / HIDDEN 8 / DEAD-shadowed 4 / ORPHAN 11
- API: admin 21종 전부 ACTIVE, 고아 5~6종(track·saju/lotto·subscription×2·projects×2), 외부 트리거 3종 정상
- admin: 고아 없음, packs만 명시적 레거시(products가 대체)
- 고아 파일: ebay-tools 4, deepfield 잔재 3, ContactForm, freelance-portfolio