Files
chat-app/README.md
kappa 554c578345 Initial commit: Anvil Lounge chat application
- React frontend with Vite + TypeScript
- Cloudflare Worker backend with Durable Objects
- AI-powered chat moderation via OpenAI
- WebSocket-based real-time messaging
- XSS prevention, rate limiting, input validation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 10:17:27 +09:00

266 lines
7.4 KiB
Markdown

# 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