# CLAUDE.md

## Project Overview

ANTOOZA(개미투자) - Next.js 15 App Router 기반 커머스·커뮤니티 플랫폼 frontend (https://antooza.com)

- **Framework**: Next.js 15.3+ (App Router, Server Components)
- **React**: 19.1+
- **Language**: TypeScript 5
- **Backend API**: https://localhost:4000 (ASP.NET Core Minimal API)

## Project Structure

```
app/
  ├── (auth)/          → 인증 (login, register, forgot-password, reset-password, welcome, approval)
  ├── (main)/          → 메인 레이아웃 그룹
  │   ├── (account)/   → 계정 관리 (profile, change-password, change-email 등)
  │   ├── (forum)/     → 게시판 (board, post, comment, latest)
  │   ├── channel/     → 채널 상세 ([channelSID])
  │   ├── note/        → 쪽지 (inbox, send)
  │   ├── notification/→ 알림 목록
  │   ├── support/     → 고객지원 (faq, guide, contact)
  │   └── docs/        → 문서 페이지
  ├── widget/          → OBS 위젯 (alert, goal, rank, crew — 별도 레이아웃)
  ├── remote/          → 후원 리모콘 ([channelSID] — 별도 레이아웃)
  ├── api/             → Route Handler (auth, channel, donation, note, notification, payment, forum 등)
  ├── auth/            → 인증 관련
  ├── component/       → 공통 레이아웃 컴포넌트
  │   ├── channel/     → ChannelSidebar (좌측), ChannelSidebarItem
  │   ├── NotificationBell, ProfileDropdown, ChargeModal
  │   └── Layout, PopupModal, Editor
  └── styles/          → 글로벌 + 컴포넌트 SCSS
components/ui/         → shadcn/ui 컴포넌트 (accordion, button, checkbox, dialog, dropdown-menu,
                          input, label, select, textarea, HotIndicator)
contexts/              → React Context Provider
  ├── authProvider.tsx      → 로그인 상태 관리, 토큰 갱신
  ├── memberProvider.tsx    → 현재 사용자 정보
  ├── configProvider.tsx    → 시스템 설정 (initialConfig prop, React.cache)
  ├── signalrProvider.tsx   → SignalR WebSocket (채팅)
  └── themeProvider.tsx     → 테마 관리
hooks/                 → 커스텀 훅 (useAuth, useChat, useDragScroll, useTheme, useErrorAlert,
                          useDonationAlert, useDonationHub, useNotification)
lib/
  ├── api/             → 서버 사이드 API 호출 함수 (Server Actions)
  │   ├── auth.ts      → 인증 API
  │   ├── account.ts   → 계정 관련 API
  │   ├── system.ts    → 시스템 설정 API
  │   ├── forum/       → board.ts, post.ts
  │   └── page/        → document.ts, faq.ts
  └── utils/
      ├── client.ts    → 클라이언트 유틸 (fetchApi, cn, formatDate, throwError)
      ├── server.ts    → 서버 유틸 (fetchJson, getAccessToken, checkPermission, getSignalRChatUrl)
      └── permission.ts → 권한 체크
types/                 → TypeScript 타입 정의
  ├── response/        → API 응답 타입 (common, account, forum, page)
  ├── request/         → 요청 페이로드 타입
  ├── forum/           → 게시판 도메인 타입 (post, comment, board, boardGroup 등)
  ├── account/         → 계정 타입 (member, loginLog)
  ├── chat.ts, broadcast.ts, config.ts
  └── editor.min.d.ts  → CKEditor 타입
constants/             → 상수 정의 (common.ts, forum.ts)
middleware.ts          → 인증 미들웨어 (토큰 검증, 리다이렉트)
```

## Code Style Rules

- 인덴트: 탭 사용
- PK/ID 변수명: `memberID`, `postID` (camelCase + 대문자 ID)
- 클라이언트 컴포넌트: 파일 최상단에 `'use client'` 선언
- 서버 전용 함수: `'use server'` 선언 (Server Actions, lib/utils/server.ts)
- 컴포넌트 파일명: PascalCase (`PopupModal.tsx`, `Layout.tsx`)
- 페이지/라우트: 소문자 kebab-case 디렉토리 (`support/faq/`)
- 스타일: `app/styles/` 에 컴포넌트별 SCSS 파일 (inline CSS 사용 금지 → SCSS 또는 Tailwind)
- SCSS 클래스명: BEM 네이밍 (`block__element--modifier`)
- 파일 내용의 마지막 줄 제거 (빈 줄 없이 끝남)
- type 을 지정할 때 `|` 문자 양쪽에 공백 제거해(예시로 `string|null|undefined`)
- button 태그에 submit type이 아니면 `type="button"` 필수
- C# 람다 `) => {` 한 줄에 붙여 작성 (개행 금지) — Frontend에서도 동일 스타일 적용
- `if (loading) return <p className="studio-page__empty">준비 중...</p>;` 이런 식으로 한 줄로 처리하지 말고 중괄호 사용해줘 그리고  다음 줄로 개행을 하도록 해

## Architecture Rules

- **서버 컴포넌트가 기본** — `'use client'` 없으면 RSC
- **클라이언트 상태**: React Context (AuthProvider, MemberProvider, ConfigProvider)
- **API 프록시 패턴**: 클라이언트 → `app/api/[도메인]/[...path]/route.ts` → 백엔드
  - 클라이언트에서 직접 백엔드 호출 안 함 (CORS, 쿠키 처리)
- **서버 데이터 흐름**: Server Component → `fetchJson()` → 백엔드 직접 호출
- **인증**: JWT Bearer 토큰 (accessToken/refreshToken, httpOnly 쿠키)
- **실시간**: SignalR WebSocket
  - AppHub (`/hubs/app`) — 채팅, 알림, 쪽지, 접속자, 크루 초대
  - DonationHub (`/hubs/donation`) — 후원 위젯/리모콘
- **결제**: 토스페이먼츠 PG (`@tosspayments/tosspayments-sdk`, V2 위젯)

## Code Conventions

### 사용하는 패턴
- `fetchApi<T>()` — 클라이언트에서 Route Handler 호출 (`lib/utils/client.ts`), 실패 시 자동 throw (에러 무시 시 `{ silent: true }`)
- `fetchJson<T>()` — 서버에서 백엔드 직접 호출 (`lib/utils/server.ts`)
- `ResultDto<T>` — 모든 API 응답 래퍼 (`{ success, status, message, data, errors }`)
- `cn()` — Tailwind 클래스 병합 (clsx + tailwind-merge)
- `dangerouslySetInnerHTML` — 서버에서 받은 HTML 콘텐츠 렌더링
- Route Group — `(auth)`, `(main)/(account)`, `(main)/(forum)` 으로 관련 페이지 그룹화
- `notFound()` — 데이터 없을 때 404 처리

### 사용하지 않는 패턴 (제안 금지)
- Redux, Zustand (Context + 로컬 상태 사용)
- GraphQL (REST API만 사용)
- 클라이언트에서 백엔드 직접 호출 (반드시 Route Handler 프록시 경유)
- CSS-in-JS (Tailwind + SCSS 사용)
- React Query / SWR (직접 fetch 사용)

## Styling

- **Tailwind CSS** — 기본 스타일링
- **SCSS** — 컴포넌트별 `style.scss`, 글로벌 `globals.scss`
- **CSS Modules** — `common.module.scss` (레이아웃 그리드)
- **shadcn/ui** — new-york 스타일, Radix UI 기반 (`components/ui/`)
- **CSS Variables** — HSL 형식 테마 변수 (`--background`, `--foreground` 등)
- **Font Awesome** — 아이콘 (@fortawesome 패키지)
- **Lucide React** — shadcn/ui 아이콘

## Provider 구조 (Root Layout)

```
ThemeProvider → SignalRProvider → AuthProvider → MemberProvider → ConfigProvider → {children}
```

- `ThemeProvider`: 테마 관리 (라이트/다크 모드)
- `SignalRProvider`: WebSocket 연결 (AppHub) — accessToken, signalRUrl prop
- `AuthProvider`: 로그인 상태 관리, 토큰 갱신
- `MemberProvider`: 현재 사용자 정보
- `ConfigProvider`: `initialConfig` prop으로 서버에서 설정 전달 (React.cache)

## 용어 규칙 (개미투자)

- **캐시 (Cash)**: 유상 충전 재화 — 토스페이먼츠 PG 충전 (PgCharged + Deposit 잔액). **상점 구매 전용**
- **토큰 (Token)**: 무상 활동 적립 재화 — 가입축하·출석·글·댓글·응원수신·모의투자 보상 (Reward + Airdrop 잔액). **활동·모의투자 전용, 상점 구매 불가** (구 명칭 포인트→코인→토큰, 2026-07 최종)
- 후원(Donation)·머니 개념은 개미투자 피벗(Phase B)에서 제거됨

## 레이아웃 구조

- **좌측 사이드바** (`ChannelSidebar`): 채널 목록, 온/오프라인 LED, 시청자 수, 다크모드/다국어/즐겨찾기
- **우측**: 방송 상세 페이지에서 채팅 표시 (고정 아님, 페이지별 조건부)
- **모바일**: 하단 네비게이션 제거 → 상단 가로 스크롤 탭 (YouTube 모바일 스타일)
- **위젯/리모콘**: 별도 Route Group, root layout 미사용

## API Route Handler 패턴

```typescript
// app/api/{도메인}/[...path]/route.ts
export async function POST(request: NextRequest, { params }: { params: Promise<{ path: string[] }> }) {
    const { path } = await params;
    const endpoint = `/api/${path.join('/')}`;
    const res: ResultDto = await fetchJson(endpoint, {
        method: 'POST',
        body: await request.arrayBuffer(),
        headers: { 'Content-Type': request.headers.get('content-type') || '' }
    });
    return NextResponse.json(res);
}
```

## Build & Run

```bash
# 개발 서버 (HTTPS, 포트 3000)
npm run dev

# 프로덕션 빌드
npm run build

# 프로덕션 실행
npm run start

# 린트
npm run lint
```

## 사용 Domain
- https://antooza.com -> 사용자 단 사용 URL
- https://admin.antooza.com  -> 관리자 단 사용 URL
- https://api.antooza.com -> 사용자 단 통신 API URL