dd/PROJECT_STRUCTURE.md

6.2 KiB

프로젝트 구조 및 설명

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)에 데이터 저장
export class CounterDurableObject {
  // WebSocket 세션 관리
  // 카운트 상태 관리
  // fetch() - WebSocket 업그레이드 처리
  // webSocketMessage() - 클라이언트 메시지 처리
  // webSocketClose() - 연결 종료 처리
  // broadcast() - 모든 클라이언트에 상태 전송
}

2. src/routes/api/counter/+server.ts - API 라우트

SvelteKit API 엔드포인트로 WebSocket 연결 요청을 Durable Object로 전달합니다:

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을 통해 서버와 통신합니다:

<script lang="ts">
  let count = $state(0);
  let online = $state(0);
  let ws = $state<WebSocket | null>(null);
  
  function connectWebSocket() { /* ... */ }
  function incrementCount() { /* ... */ }
  function resetCount() { /* ... */ }
</script>

4. src/hooks.server.ts - 서버 훅

Durable Object을 Worker에서 사용할 수 있도록 export합니다:

export { CounterDurableObject } from '$lib/counter-do';

5. wrangler.jsonc - Cloudflare 설정

Worker 및 Durable Objects 바인딩을 설정합니다:

{
  "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 어댑터

개발 워크플로우

로컬 개발

pnpm dev         # Vite 개발 서버
pnpm build       # 프로덕션 빌드
pnpm cf:dev      # Wrangler 로컬 서버

배포

pnpm deploy      # Cloudflare에 배포
pnpm cf:tail     # 실시간 로그

테스트

pnpm check       # TypeScript 및 Svelte 체크
pnpm format      # Prettier 포맷팅
pnpm lint        # 린팅 체크

환경 변수

현재 프로젝트는 환경 변수를 사용하지 않습니다. 모든 설정은 wrangler.jsonc에 있습니다.

필요한 경우 .env 파일을 추가하고 다음과 같이 사용할 수 있습니다:

# .env
VITE_API_URL=https://your-api.com
// 사용
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 통합
    • 커스텀 메트릭 수집