-
Notifications
You must be signed in to change notification settings - Fork 0
Frontend
trz-21 edited this page Jun 16, 2026
·
3 revisions
📌 이 페이지는 이 프로젝트의 살아있는 스펙(최종 현황) 이며 canonical 문서입니다. 코드/설계 변경 시 PR 머지 후 이 페이지를 갱신합니다. (작업 흐름: 개발-워크플로우)
위치:
frontend/(monorepo). Next.js 14 App Router.
frontend/
├── app/ # Next.js App Router
│ ├── layout.tsx # 루트 레이아웃 (QueryProvider, Geist 폰트)
│ ├── page.tsx # 루트: 미인증 → 랜딩 렌더 / 인증(토큰) → /dashboard
│ ├── terms/page.tsx # 이용약관 (공개, 플레이스홀더)
│ ├── privacy/page.tsx # 개인정보 처리방침 (공개, 플레이스홀더)
│ ├── (auth)/
│ │ ├── login/page.tsx # 2단 레이아웃(브랜드 패널 + 폼)
│ │ └── register/page.tsx
│ └── (dashboard)/
│ ├── layout.tsx # 인증 가드 + 헤더(Wordmark)
│ ├── dashboard/page.tsx # URL 입력 + 분석 히스토리(EmptyState)
│ └── analyses/
│ └── [id]/page.tsx # 분석 결과 상세 (폴링 + 진행 스테퍼 + 결과 헤더)
│
├── src/
│ ├── features/ # 도메인별 모듈
│ │ ├── auth/ # types.ts · api/ · store.ts (Zustand)
│ │ └── analysis/
│ │ ├── types.ts · api/
│ │ ├── hooks/useAnalysisPolling.ts
│ │ └── components/ # UrlInput · AnalysisCard · InsightReport · AnalysisProgress
│ │
│ └── shared/
│ ├── api/client.ts # apiClient (fetch 래퍼, 토큰 자동 주입)
│ └── components/ # ── 디자인 시스템 ──
│ ├── ui/ # Button · Card · Badge · Container · Input · cn (프리미티브)
│ ├── Wordmark.tsx # 브랜드 워드마크
│ ├── Footer.tsx # 공통 푸터
│ ├── Landing.tsx # 랜딩 페이지(히어로/가치/방법/신뢰/요금제)
│ └── EmptyState.tsx # 공통 빈 상태
│
└── tests/
├── unit/ # vitest 단위/통합
└── e2e/landing.spec.ts # Playwright 랜딩 스모크 (자세히: [[Harness]])
컴포넌트마다 동일 경로에
*.test.tsx단위 테스트가 동반된다. (예외:index.ts,types.ts) E2E는tests/e2e/에 항상 최소 1건 이상 유지 — 0건이면 CI가 실패한다. (Harness 참고)
- 브랜드 톤: 네이비/블루 + 화이트 (B2B SaaS, 신뢰·전문성)
-
토큰:
tailwind.config.ts의brand-50..950컬러 스케일 +fontFamily.sans/mono(Geist). 하드코딩 색 대신brand-*토큰 사용. ⚠️ Tailwindcontentglob에./src필수: 디자인 시스템 프리미티브와Container가 모두frontend/src/에 있다.contentglob에서./src가 빠지면max-w-5xl등 유틸이 purge돼 레이아웃이 edge-to-edge로 깨진다(#28에서 발생·수정). config 수정 시./app·./src를 모두 포함할 것.-
폰트: Geist(Sans/Mono) 를 본문 폰트로 적용(
globals.css,layout.tsx). -
프리미티브 (
src/shared/components/ui/, 신규 의존성 없음):-
Button(variant: primary/secondary/outline/ghost × size: sm/md/lg) -
Card(패딩은 소비자 지정) ·Badge(neutral/info/success/warning/danger) ·Container(max-w-5xl) ·Input(forwardRef) -
cn— 의존성 없는 className 병합 유틸
-
-
공통 컴포넌트:
Wordmark,Footer,Landing,EmptyState, 분석 진행AnalysisProgress - 외부 컴포넌트 라이브러리(shadcn 등) 미도입 — Tailwind 기반 경량 프리미티브로 번들 최소화.
-
미인증 방문자 → 랜딩 페이지 렌더(
Landing): 히어로 + 핵심가치 3 + 작동방식 + 신뢰 요소(데이터 출처·AI 방법론·보안) + 요금제 3종 + 푸터. -
인증(토큰 보유) →
/dashboard리다이렉트. - 하이드레이션 미스매치 방지를 위해 mount 이후에만 판별.
- 법적 페이지:
/terms,/privacy(공개, 플레이스홀더).
-
그라데이션 히어로 입력 영역(
brand-700→900, rounded-2xl, 돋보기 아이콘) — URL 입력(최대 3개,UrlInput: ✕ 삭제·+ 추가·리뷰 수 select 폭 제약) + 온보딩 카피 - 분석 시작 버튼 → POST /analyses → /analyses/[id]로 이동
- 최근 분석 히스토리:
AnalysisCard(상태 컬러 dot·호버 리프트·"결과 보기 →" 링크 아이콘), 빈 상태는EmptyState일러스트 - sticky + backdrop-blur 헤더
- 상태 폴링 (2초 간격, TanStack Query
refetchInterval) - Pending/Crawling/Analyzing: 3단계 진행 스테퍼(
AnalysisProgress: 수집→분석→완료) - Completed: 스탯 타일 히어로(상품 수·총 리뷰 수·생성 시각) + 인사이트 리포트(
InsightReport)- 방법론 블록(데이터 출처·표본 수·AI 분류 안내) + 섹션별 맥락 카피 + 면책 고지
- 섹션별 고유 액센트+아이콘: TOP3=블루 / 경쟁사 약점=앰버 / 구매 결정 요인=에메랄드 / 반복 불만=red / 긍정=green / 평점 분포=앰버
- 심각도 배지 한글화(high/medium → 높음/보통 등 — 소상공인 대상 신뢰도)
- PDF 내보내기 버튼 (Pro 플랜, 예정)
| 상태 종류 | 도구 | 예시 |
|---|---|---|
| 서버 상태 (API 데이터) | TanStack Query | 분석 목록, 분석 결과 |
| 클라이언트 UI 상태 | Zustand | 로그인 토큰, 사용자 정보 |
| 폼 상태 | React 로컬 state | URL 입력 폼 |
interface AuthStore {
token: string | null;
user: User | null;
setAuth: (token: string, user: User) => void;
logout: () => void;
}src/features/analysis/hooks/useAnalysisPolling.ts 로 추출. v5 에서 refetchInterval
콜백 인자는 query 객체이며 query.state.data 로 접근한다. 간격 분기는 순수 함수
pollInterval(status) 로 분리해 단위 테스트한다.
// completed/failed면 폴링 중단(false), 그 외 2초
export function pollInterval(status?: AnalysisStatus): number | false {
return status === 'completed' || status === 'failed' ? false : 2000;
}
export function useAnalysisPolling(analysisId: string) {
return useQuery({
queryKey: ['analysis', analysisId],
queryFn: () => getAnalysis(analysisId),
refetchInterval: (query) => pollInterval(query.state.data?.status),
enabled: !!analysisId,
});
}// src/shared/api/client.ts
// 토큰 자동 주입 + 에러 처리
// src/features/{domain}/types.ts
// {Action}Request / {Action}Response 인터페이스
// src/features/{domain}/api/index.ts
// export async function actionName(req: ActionRequest): Promise<ActionResponse>규칙: 인라인 타입(Promise<{ field: Type }>) 금지. 모든 API 함수는 명명된 타입 사용.
NEXT_PUBLIC_API_URL=http://localhost:8080
📚 스펙 네비게이션: Home · Service-Overview · Tech-Stack · API · Backend · Frontend · Harness · 개발-워크플로우