# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Real-time chat application with AI-powered moderation. Korean-language community chat ("Anvil Lounge") with an AI bot host (방장) that moderates conversations, answers questions, and provides weather/documentation lookups. ## Architecture ``` chat-app/ ├── frontend/ # React SPA (Vite + TypeScript) │ └── src/ │ ├── components/ # ChatRoom, MessageList, MessageInput │ ├── hooks/ # useWebSocket (WebSocket client with reconnection) │ └── utils/ # sanitize.ts (XSS prevention, markdown→HTML) └── worker/ # Cloudflare Worker + Durable Object └── src/ ├── index.ts # HTTP router, CORS handling ├── ChatRoom.ts # Durable Object: WebSocket hub, message persistence ├── AIManager.ts # OpenAI integration, moderation, tool calling ├── Context7Client.ts # Documentation lookup API ├── RateLimiter.ts # In-memory rate limiting └── validation.ts # Zod schemas for message validation ``` ### Key Design Patterns **Durable Objects with Hibernation API**: `ChatRoom` uses `webSocketMessage()`, `webSocketClose()`, `webSocketError()` handlers instead of event listeners. Session data stored via `ws.serializeAttachment()`. **AI Moderation Flow**: Messages are checked by AI for profanity before broadcast. Detected words are masked (첫 글자 + asterisks). Repeated violations trigger auto-silence via `trackViolation()` → DO storage transaction. **Storage Patterns**: All DO storage operations use transactions for atomicity and retry logic with jitter for resilience. ## Development Commands ```bash # Root-level (npm workspaces) npm run dev:worker # Start worker dev server (wrangler) npm run dev:frontend # Start Vite dev server (localhost:5173) npm run build:worker # Build worker npm run build:frontend # Build frontend (tsc + vite) npm run deploy:worker # Deploy to Cloudflare Workers npm run deploy:frontend # Deploy to Cloudflare Pages # Type checking cd worker && npx tsc --noEmit cd frontend && npx tsc --noEmit # Worker secrets wrangler secret put OPENAI_API_KEY ``` ## API Endpoints | Endpoint | Description | |----------|-------------| | `GET /api/rooms/:roomId/websocket` | WebSocket upgrade for chat | | `GET /api/rooms/:roomId/users` | List users in room | | `GET /api/health` | Health check | ## WebSocket Message Types **Client → Server**: `{ type: "message", content: string }` or `{ type: "rename", name: string }` **Server → Client**: `message`, `join`, `leave`, `userList`, `history`, `error` ## Configuration Alignment Frontend `config.ts` and backend `validation.ts` must stay in sync: - `maxMessageLength`: 2000 characters - `maxUserNameLength`: 50 characters ## Security Considerations - XSS prevention: `sanitize.ts` uses DOMPurify + custom URL validation (`isUrlSafe()`) to block encoded `javascript:` attacks - API key redaction: `sanitizeErrorForLogging()` in AIManager.ts strips credentials from error logs - CORS: Strict origin allowlist in `index.ts` (includes Pages preview deployments) - Input validation: All WebSocket messages validated with Zod schemas before processing ## External Services - **OpenAI API**: Chat completions with function calling (weather, docs, hosting info, silence user) - **Open-Meteo API**: Weather data (no API key required) - **Context7 API**: Documentation lookup for technical questions