# CLAUDE.md ## Project Overview DPOT - Next.js 15 App Router 기반 Creators Support and donate platform frontend (https://dpot.web.or.kr) - **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, change-name, change-thumb, │ │ change-intro, change-summary, change-approve, verify-email, │ │ login-log, my-posts, my-comments, exp-logs, withdraw) │ ├── (forum)/ → 게시판 (board, post, comment, latest) │ ├── support/ → 고객지원 (faq, guide, contact) │ └── docs/ → 문서 페이지 ├── api/ → Route Handler (auth, document, faq, forum, mypage, popup, uploads) ├── auth/ → 인증 관련 ├── component/ → 공통 레이아웃 컴포넌트 (Layout, PopupModal, Editor, ChatSidebar 등) └── styles/ → 글로벌 스타일 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) 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/`) - 스타일: 각 페이지 디렉토리에 `style.scss` 파일 - 파일 내용의 마지막 줄 제거 (빈 줄 없이 끝남) - type 을 지정할 때 `|` 문자 양쪽에 공백 제거해(예시로 `string|null|undefined`) ## 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()` — 클라이언트에서 Route Handler 호출 (`lib/utils/client.ts`) - `fetchJson()` — 서버에서 백엔드 직접 호출 (`lib/utils/server.ts`) - `ResultDto` — 모든 API 응답 래퍼 (`{ success, status, message, data, errors }`) - `throwError(res)` — 에러 응답 시 예외 발생 - `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 연결 (채팅) — accessToken, signalRChatUrl prop - `AuthProvider`: 로그인 상태 관리, 토큰 갱신 - `MemberProvider`: 현재 사용자 정보 - `ConfigProvider`: `initialConfig` prop으로 서버에서 설정 전달 (React.cache) ## 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://dpot.web.or.kr -> 사용자 단 사용 URL - https://admin.dpot.web.or.kr -> 관리자 단 사용 URL - https://api.dpot.web.or.kr -> 사용자 단 통신 API URL