# 프로젝트 구조 및 설명 ``` dd/ ├── src/ │ ├── lib/ │ │ └── counter-do.ts # Durable Object 구현체 │ ├── routes/ │ │ ├── api/counter/ │ │ │ └── +server.ts # WebSocket 엔드포인트 (API Route) │ │ ├── +layout.svelte # 전역 레이아웃 │ │ └── +page.svelte # 메인 페이지 (실시간 카운터 UI) │ ├── app.d.ts # TypeScript 전역 타입 정의 │ ├── app.css # Tailwind CSS 글로벌 스타일 │ ├── app.html # HTML 템플릿 │ └── hooks.server.ts # SvelteKit 서버 훅 (Durable Object export) ├── static/ │ └── robots.txt # SEO용 robots.txt ├── .svelte-kit/ # SvelteKit 빌드 출력 │ ├── cloudflare/ │ │ ├── _worker.js # 생성된 Worker 파일 │ │ └── _app/ # 클라이언트 자산 │ └── output/ │ ├── client/ # 클라이언트 빌드 │ └── server/ # 서버 빌드 ├── wrangler.jsonc # Cloudflare Workers 설정 ├── svelte.config.js # SvelteKit 설정 ├── vite.config.ts # Vite 설정 ├── tailwind.config.ts # Tailwind CSS 설정 ├── tsconfig.json # TypeScript 설정 ├── package.json # 프로젝트 의존성 ├── README.md # 프로젝트 문서 ├── QUICKSTART.md # 빠른 시작 가이드 └── DEPLOYMENT.md # 배포 가이드 ``` ## 주요 파일 설명 ### 1. `src/lib/counter-do.ts` - Durable Object Cloudflare Durable Objects 클래스로, 다음을 담당합니다: - WebSocket 연결 관리 - 카운터 상태 저장 및 업데이트 - 모든 클라이언트에 상태 브로드캐스트 - 영구 저장소(Durable Objects Storage)에 데이터 저장 ```typescript export class CounterDurableObject { // WebSocket 세션 관리 // 카운트 상태 관리 // fetch() - WebSocket 업그레이드 처리 // webSocketMessage() - 클라이언트 메시지 처리 // webSocketClose() - 연결 종료 처리 // broadcast() - 모든 클라이언트에 상태 전송 } ``` ### 2. `src/routes/api/counter/+server.ts` - API 라우트 SvelteKit API 엔드포인트로 WebSocket 연결 요청을 Durable Object로 전달합니다: ```typescript export const GET: RequestHandler = async ({ request, platform }) => { const id = platform?.env.COUNTER.idFromName('global-counter'); const stub = platform.env.COUNTER.get(id); return stub.fetch(request); }; ``` ### 3. `src/routes/+page.svelte` - 클라이언트 UI 실시간 카운터 UI를 렌더링하고 WebSocket을 통해 서버와 통신합니다: ```svelte ``` ### 4. `src/hooks.server.ts` - 서버 훅 Durable Object을 Worker에서 사용할 수 있도록 export합니다: ```typescript export { CounterDurableObject } from '$lib/counter-do'; ``` ### 5. `wrangler.jsonc` - Cloudflare 설정 Worker 및 Durable Objects 바인딩을 설정합니다: ```jsonc { "durable_objects": { "bindings": [{ "name": "COUNTER", "class_name": "CounterDurableObject" }] }, "migrations": [...] } ``` ## 데이터 흐름 ### WebSocket 연결 흐름 ``` 클라이언트 브라우저 ↓ (WebSocket 연결 요청) /api/counter (+server.ts) ↓ (Durable Object ID 생성) Durable Object Stub ↓ (fetch() 호출) CounterDurableObject ↓ (WebSocket 페어 생성) 클라이언트 ← → 서버 (양방향 통신) ``` ### 카운트 증가 흐름 ``` 클라이언트: 버튼 클릭 ↓ (WebSocket 메시지) Durable Object: webSocketMessage() ↓ (카운트 증가) Durable Object Storage: 저장 ↓ (broadcast()) 모든 연결된 클라이언트: 실시간 업데이트 ``` ## 기술 스택 ### 프론트엔드 - **Svelte 5**: 최신 Svelte 5의 Runes API 사용 - **Tailwind CSS 4**: 유틸리티 우선 CSS 프레임워크 - **TypeScript**: 타입 안전성 ### 백엔드 - **SvelteKit**: 풀스택 웹 프레임워크 - **Cloudflare Workers**: 서버리스 엣지 컴퓨팅 - **Durable Objects**: 상태 저장 및 협업 - **WebSocket Hibernation API**: 저비용 실시간 통신 ### 빌드 & 배포 - **Vite**: 빠른 빌드 도구 - **Wrangler**: Cloudflare Workers CLI - **@sveltejs/adapter-cloudflare**: SvelteKit → Cloudflare 어댑터 ## 개발 워크플로우 ### 로컬 개발 ```bash pnpm dev # Vite 개발 서버 pnpm build # 프로덕션 빌드 pnpm cf:dev # Wrangler 로컬 서버 ``` ### 배포 ```bash pnpm deploy # Cloudflare에 배포 pnpm cf:tail # 실시간 로그 ``` ### 테스트 ```bash pnpm check # TypeScript 및 Svelte 체크 pnpm format # Prettier 포맷팅 pnpm lint # 린팅 체크 ``` ## 환경 변수 현재 프로젝트는 환경 변수를 사용하지 않습니다. 모든 설정은 `wrangler.jsonc`에 있습니다. 필요한 경우 `.env` 파일을 추가하고 다음과 같이 사용할 수 있습니다: ```env # .env VITE_API_URL=https://your-api.com ``` ```typescript // 사용 import { env } from '$env/dynamic/public'; console.log(env.VITE_API_URL); ``` ## 확장 아이디어 1. **여러 카운터 룸** - URL 파라미터로 룸 ID 전달 - 각 룸마다 독립적인 Durable Object 인스턴스 2. **사용자 인증** - Cloudflare Access 통합 - 사용자별 권한 관리 3. **영속적 히스토리** - SQLite (D1) 통합 - 카운트 변경 로그 4. **실시간 채팅** - WebSocket을 활용한 채팅 기능 - 메시지 브로드캐스팅 5. **분석 및 모니터링** - Cloudflare Analytics 통합 - 커스텀 메트릭 수집