# Chat App Cloudflare Workers + Durable Objects + React 기반 실시간 멀티유저 채팅 애플리케이션 ## 아키텍처 ``` ┌─────────────────┐ WebSocket ┌──────────────────┐ ┌─────────────────┐ │ React │ ←───────────────→ │ Cloudflare │ ←─→ │ Durable Object │ │ Frontend │ │ Worker │ │ (ChatRoom) │ │ (Pages) │ │ (라우팅) │ │ (상태관리) │ └─────────────────┘ └──────────────────┘ └─────────────────┘ ↓ ┌──────────────────┐ │ OpenAI API │ │ (AI 방장) │ └──────────────────┘ ``` ## 기술 스택 | 분류 | 기술 | |------|------| | 백엔드 | Cloudflare Workers, Durable Objects | | 실시간 통신 | WebSocket Hibernation API | | AI | OpenAI GPT-4o-mini, Function Calling | | 프론트엔드 | React + Vite + TypeScript | | 검증 | Zod (입력 검증) | | 보안 | DOMPurify (XSS 방지), Rate Limiting | | 배포 | Cloudflare Workers + Pages | ## 프로젝트 구조 ``` chat-app/ ├── worker/ # Cloudflare Worker 백엔드 │ ├── src/ │ │ ├── index.ts # Worker 엔트리포인트, 라우팅, CORS │ │ ├── ChatRoom.ts # Durable Object 채팅방 클래스 │ │ ├── AIManager.ts # AI 방장 (OpenAI 연동) │ │ ├── Context7Client.ts # 기술 문서 검색 클라이언트 │ │ ├── validation.ts # Zod 입력 검증 스키마 │ │ └── RateLimiter.ts # 슬라이딩 윈도우 Rate Limiter │ ├── wrangler.toml # Worker 설정 │ └── package.json ├── frontend/ # React 프론트엔드 │ ├── src/ │ │ ├── App.tsx │ │ ├── components/ │ │ │ ├── ChatRoom.tsx # 채팅방 UI │ │ │ ├── MessageList.tsx # 메시지 목록 │ │ │ └── MessageInput.tsx# 입력창 │ │ ├── hooks/ │ │ │ └── useWebSocket.ts # WebSocket 연결 훅 │ │ └── utils/ │ │ └── sanitize.ts # XSS 방지 유틸리티 │ ├── vite.config.ts │ └── package.json └── package.json # 모노레포 루트 ``` ## 기능 ### 채팅 기능 - 실시간 메시지 송수신 - 사용자 입장/퇴장 알림 - 접속자 목록 표시 - 사용자 이름 변경 ### AI 방장 (@방장) - IT 기술 관련 질문 응답 - 자동 환영 메시지 - 채팅 중재 (부적절한 언어 경고) - 명령어 처리 (/help, /rules, /pricing 등) - Context7 API 연동 기술 문서 검색 ### 보안 기능 - CORS 제한 (특정 도메인만 허용) - 입력값 검증 (Zod 스키마) - XSS 방지 (DOMPurify + 안전한 마크다운) - Rate Limiting (사용자별 요청 제한) - API 타임아웃 (15초) - 보안 헤더 (CSP, X-Frame-Options 등) ## API 엔드포인트 ### WebSocket ``` GET /api/rooms/:roomId/websocket?name=사용자이름 ``` WebSocket 연결을 위한 엔드포인트 ### REST ``` GET /api/rooms/:roomId/users # 채팅방 접속자 목록 GET /api/health # 헬스체크 ``` ## WebSocket 메시지 형식 ### 클라이언트 → 서버 ```typescript // 메시지 전송 { type: 'message', content: '안녕하세요' } // 이름 변경 { type: 'rename', name: '새이름' } ``` ### 서버 → 클라이언트 ```typescript // 일반 메시지 { type: 'message', id: 'uuid', name: '사용자', content: '내용', timestamp: 1234567890, isBot?: boolean } // 입장 { type: 'join', id: 'uuid', name: '사용자', timestamp: 1234567890 } // 퇴장 { type: 'leave', id: 'uuid', name: '사용자', timestamp: 1234567890 } // 사용자 목록 { type: 'userList', users: ['사용자1', '사용자2'], timestamp: 1234567890 } // 에러 { type: 'error', message: '에러 메시지', timestamp: 1234567890 } ``` ## 로컬 개발 ### 요구사항 - Node.js 18+ - pnpm ### 설치 및 실행 ```bash # 의존성 설치 pnpm install # Worker 로컬 실행 cd worker pnpm dev # Frontend 로컬 실행 (새 터미널) cd frontend pnpm dev ``` ### 환경변수 Worker: - `OPENAI_API_KEY`: OpenAI API 키 (wrangler.toml 또는 secrets) ## 배포 ### Worker 배포 ```bash cd worker pnpm deploy ``` ### Frontend 배포 ```bash cd frontend pnpm build pnpm pages:deploy ``` ## 배포 URL | 서비스 | URL | |--------|-----| | Worker API | https://chat-worker.kappa-d8e.workers.dev | | Frontend | https://chat-frontend-4wf.pages.dev | | Custom Domain | https://chat.anvil.it.com | ## 보안 구현 상세 ### CORS 설정 ```typescript const ALLOWED_ORIGINS = [ 'https://chat.anvil.it.com', 'https://chat-frontend-4wf.pages.dev', 'http://localhost:5173', 'http://localhost:3000', ]; ``` - 정확한 도메인 매칭만 허용 - Pages 프리뷰 도메인 패턴 제한 (`[commit].chat-frontend-4wf.pages.dev`) ### 입력 검증 ```typescript // 메시지: 1-2000자 const MessageSchema = z.object({ type: z.literal('message'), content: z.string().min(1).max(2000).trim(), }); // Room ID: 영문숫자, 하이픈, 언더스코어만 const RoomIdSchema = z.string() .min(1).max(100) .regex(/^[a-zA-Z0-9_-]+$/); // 사용자 이름: 1-50자 const UserNameSchema = z.string().min(1).max(50).trim(); ``` ### Rate Limiting | 대상 | 제한 | 차단 시간 | |------|------|-----------| | AI 요청 | 15회/분 | 2분 | | 중재 위반 | 3회/5분 | 30분 | ### 보안 헤더 ``` X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1; mode=block Referrer-Policy: strict-origin-when-cross-origin Content-Security-Policy: default-src 'self'; connect-src 'self' wss: https:; ... ``` ## AI 방장 명령어 | 명령어 | 설명 | |--------|------| | /help | 도움말 보기 | | /rules | 채팅방 규칙 | | /users | 현재 접속자 목록 | | /pricing | Anvil Hosting 요금 안내 | | /specs | 서버 스펙 안내 | | /regions | 리전 정보 | | /contact | 텔레그램 상담 연결 | | @방장 [질문] | AI에게 질문하기 | ## AI Function Calling AI 방장은 다음 기능을 호출할 수 있습니다: | 함수 | 설명 | |------|------| | `searchDocumentation` | 기술 문서 검색 (Context7 API) | | `getAnvilHostingInfo` | Anvil Hosting 정보 조회 (pricing, specs, regions, features, contact) | | `getCurrentDateTime` | 현재 날짜/시간 조회 (한국 기준) | | `getWeather` | 도시별 날씨 조회 (Open-Meteo API) | ### 텔레그램 봇 연동 Anvil Hosting 문의 시 자동으로 텔레그램 봇 연결 안내: - 봇: [@AnvilForgeBot](https://t.me/AnvilForgeBot) ### 날씨 지원 도시 서울, 부산, 도쿄, 오사카, 뉴욕, 런던 ### 사용 예시 ``` @방장 오늘 날짜가 뭐야? @방장 서울 날씨 어때? @방장 도쿄 날씨 알려줘 ``` ## 라이선스 Private - Anvil Hosting