WebSocket: Claude Code 활용 가이드
websocket: Claude Code 활용. 실용적인 팁과 코드 예시를 포함합니다.
WebSocketチャット앱をClaude Code로作る
실시간チャット앱はWebSocketの代表的なユースケースです。Claude Code를 활용하면 인증付きのチャットルーム、メッセージ履歴、オンラインステータスまで含めた本格的なチャット앱を효율적으로구축할 수 있습니다。
프로젝트の初期セットアップ
> WebSocketチャット앱を作りたい。
> Node.js + Express + Socket.IO で서버を、
> React + TypeScript で프론트엔드を구축して。
> ルーム機能とメッセージ履歴를 구현해줘。
Claude Code는 이プロンプトから、서버と클라이언트の両方を一貫した아키텍처で생성してくれます。
서버サイドの구현
// server/src/chat-server.ts
import { Server, Socket } from 'socket.io';
import { createServer } from 'http';
import express from 'express';
interface Message {
id: string;
roomId: string;
sender: string;
content: string;
timestamp: number;
}
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: { origin: process.env.CLIENT_URL || 'http://localhost:3000' },
});
// メッセージ履歴を메모리に保持(本番ではDBを使用)
const messageHistory = new Map<string, Message[]>();
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) return next(new Error('認証が必要です'));
// 토큰검증ロジック
next();
});
io.on('connection', (socket: Socket) => {
const username = socket.handshake.auth.username;
socket.on('join-room', (roomId: string) => {
socket.join(roomId);
// 過去のメッセージを전송
const history = messageHistory.get(roomId) || [];
socket.emit('message-history', history.slice(-50));
io.to(roomId).emit('user-status', { username, status: 'online' });
});
socket.on('send-message', (data: { roomId: string; content: string }) => {
const message: Message = {
id: crypto.randomUUID(),
roomId: data.roomId,
sender: username,
content: data.content,
timestamp: Date.now(),
};
if (!messageHistory.has(data.roomId)) {
messageHistory.set(data.roomId, []);
}
messageHistory.get(data.roomId)!.push(message);
io.to(data.roomId).emit('new-message', message);
});
socket.on('disconnect', () => {
io.emit('user-status', { username, status: 'offline' });
});
});
httpServer.listen(4000, () => console.log('Chat server running on :4000'));
클라이언트サイドの구현
// client/src/hooks/useChat.ts
import { useEffect, useState, useCallback } from 'react';
import { io, Socket } from 'socket.io-client';
interface Message {
id: string;
roomId: string;
sender: string;
content: string;
timestamp: number;
}
export function useChat(roomId: string, token: string, username: string) {
const [messages, setMessages] = useState<Message[]>([]);
const [socket, setSocket] = useState<Socket | null>(null);
const [isConnected, setIsConnected] = useState(false);
useEffect(() => {
const s = io('http://localhost:4000', {
auth: { token, username },
});
s.on('connect', () => {
setIsConnected(true);
s.emit('join-room', roomId);
});
s.on('message-history', (history: Message[]) => {
setMessages(history);
});
s.on('new-message', (message: Message) => {
setMessages((prev) => [...prev, message]);
});
s.on('disconnect', () => setIsConnected(false));
setSocket(s);
return () => { s.disconnect(); };
}, [roomId, token, username]);
const sendMessage = useCallback((content: string) => {
socket?.emit('send-message', { roomId, content });
}, [socket, roomId]);
return { messages, sendMessage, isConnected };
}
メッセージ컴포넌트
// client/src/components/ChatRoom.tsx
import { useChat } from '../hooks/useChat';
import { useState } from 'react';
export function ChatRoom({ roomId, token, username }: {
roomId: string;
token: string;
username: string;
}) {
const { messages, sendMessage, isConnected } = useChat(roomId, token, username);
const [input, setInput] = useState('');
const handleSend = () => {
if (!input.trim()) return;
sendMessage(input);
setInput('');
};
return (
<div className="flex flex-col h-screen">
<div className="p-4 border-b flex justify-between">
<h2>Room: {roomId}</h2>
<span className={isConnected ? 'text-green-500' : 'text-red-500'}>
{isConnected ? '接続中' : '切断'}
</span>
</div>
<div className="flex-1 overflow-y-auto p-4 space-y-2">
{messages.map((msg) => (
<div key={msg.id} className={msg.sender === username ? 'text-right' : ''}>
<span className="text-sm text-gray-500">{msg.sender}</span>
<p className="bg-gray-100 rounded-lg p-2 inline-block">{msg.content}</p>
</div>
))}
</div>
<div className="p-4 border-t flex gap-2">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleSend()}
className="flex-1 border rounded px-3 py-2"
placeholder="Type a message..."
/>
<button onClick={handleSend} className="bg-blue-500 text-white px-4 rounded">
送信
</button>
</div>
</div>
);
}
프로덕션 환경での주의点
Claude Code에다음의点を추가で依頼すると、本番品質に近づけられます。
- メッセージの永続化: RedisやPostgreSQLにメッセージを저장する
- レート制限: スパム防止のためのメッセージ전송制限
- XSS対策: 사용자입력のサニタイズ処理
- 再接続ロジック: 切断時の自動再接続とメッセージ再취득
関連リソース
WebSocketの基礎的な구현パターン에 대해서는WebSocket/실시간通信の구현가이드도 참고하세요.인증周りの구현は인증機能の구현で詳しく解説しています。또한、チャットボットとの통합を考えている場合はチャットボット개발도 확인하세요.
Socket.IO의 공식 문서(socket.io/docs)も併せて확인するとよいでしょう。
Claude Code 워크플로우를 한 단계 업그레이드하세요
지금 바로 Claude Code에 복사해 쓸 수 있는 검증된 프롬프트 템플릿 50선.
이 글을 작성한 사람
Masa
Claude Code를 적극 활용하는 엔지니어. 10개 언어, 2,000페이지 이상의 테크 미디어 claudecode-lab.com을 운영 중.
관련 글
Claude Code로 리팩토링을 자동화하는 방법
Claude Code를 활용해 코드 리팩토링을 효율적으로 자동화하는 방법을 알아봅니다. 실전 프롬프트와 구체적인 리팩토링 패턴을 소개합니다.
Claude Code로 사이드 프로젝트 개발 속도를 극대화하는 방법 [예제 포함]
Claude Code를 활용해 개인 프로젝트 개발 속도를 획기적으로 높이는 방법을 알아봅니다. 실전 예제와 아이디어부터 배포까지의 워크플로를 포함합니다.
Complete CORS Configuration Guide: Claude Code 활용 가이드
complete cors configuration guide: Claude Code 활용. 실용적인 팁과 코드 예시를 포함합니다.