|
|
@@ -0,0 +1,134 @@
|
|
|
+# CLAUDE.md
|
|
|
+
|
|
|
+## Project Overview
|
|
|
+
|
|
|
+bitForum - Next.js 15 App Router 기반 커뮤니티 프론트엔드 (https://bitforum.io)
|
|
|
+
|
|
|
+- **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/ → Next.js App Router (페이지, 레이아웃, API 라우트)
|
|
|
+ ├── (account)/ → 계정 관리 (프로필, 비밀번호 변경 등)
|
|
|
+ ├── (auth)/ → 인증 (로그인, 회원가입, 비밀번호 찾기)
|
|
|
+ ├── (forum)/ → 게시판 (게시글, 댓글, 글쓰기)
|
|
|
+ ├── api/ → Route Handler (백엔드 API 프록시)
|
|
|
+ ├── component/ → 공통 레이아웃 컴포넌트 (Layout, PopupModal 등)
|
|
|
+ ├── support/ → 고객지원 (FAQ, 공지, 이용안내, 제휴문의)
|
|
|
+ ├── news/ → 뉴스
|
|
|
+ └── docs/ → 문서 페이지
|
|
|
+components/ui/ → shadcn/ui 컴포넌트 (dialog, accordion 등)
|
|
|
+contexts/ → React Context Provider (Auth, Member, Config, SignalR)
|
|
|
+hooks/ → 커스텀 훅 (useAuth, useDragScroll 등)
|
|
|
+lib/
|
|
|
+ ├── api/ → 서버 사이드 API 호출 함수 (Server Actions)
|
|
|
+ └── utils/
|
|
|
+ ├── client.ts → 클라이언트 유틸 (fetchApi, cn, formatDate, throwError)
|
|
|
+ └── server.ts → 서버 유틸 (fetchJson, getAccessToken, checkPermission)
|
|
|
+types/ → TypeScript 타입 정의 (response/, request/, forum/, account/)
|
|
|
+constants/ → 상수 정의
|
|
|
+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/`)
|
|
|
+- 스타일: 각 페이지 디렉토리에 `style.scss` 파일
|
|
|
+- 파일 내용의 마지막 줄 제거 (빈 줄 없이 끝남)
|
|
|
+
|
|
|
+## 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 (암호화폐 시세, 채팅)
|
|
|
+
|
|
|
+## Code Conventions
|
|
|
+
|
|
|
+### 사용하는 패턴
|
|
|
+- `fetchApi<T>()` — 클라이언트에서 Route Handler 호출 (`lib/utils/client.ts`)
|
|
|
+- `fetchJson<T>()` — 서버에서 백엔드 직접 호출 (`lib/utils/server.ts`)
|
|
|
+- `ResultDto<T>` — 모든 API 응답 래퍼 (`{ success, status, message, data, errors }`)
|
|
|
+- `throwError(res)` — 에러 응답 시 예외 발생
|
|
|
+- `cn()` — Tailwind 클래스 병합 (clsx + tailwind-merge)
|
|
|
+- `dangerouslySetInnerHTML` — 서버에서 받은 HTML 콘텐츠 렌더링
|
|
|
+- Route Group — `(auth)`, `(account)`, `(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)
|
|
|
+
|
|
|
+```
|
|
|
+SignalRProvider → AuthProvider → MemberProvider → ConfigProvider → {children}
|
|
|
+```
|
|
|
+
|
|
|
+- `ConfigProvider`: `initialConfig` prop으로 서버에서 설정 전달 (React.cache)
|
|
|
+- `AuthProvider`: 로그인 상태 관리, 토큰 갱신
|
|
|
+- `MemberProvider`: 현재 사용자 정보
|
|
|
+- `SignalRProvider`: WebSocket 연결 (암호화폐, 채팅)
|
|
|
+
|
|
|
+## 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://bitforum.io → 사용자 프론트엔드
|
|
|
+- https://api.bitforum.io → 백엔드 API
|
|
|
+- https://admin.bitforum.io → 관리자 패널
|