210 lines
6.2 KiB
Markdown
210 lines
6.2 KiB
Markdown
# 프로젝트 구조 및 설명
|
|
|
|
```
|
|
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
|
|
<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합니다:
|
|
|
|
```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 통합
|
|
- 커스텀 메트릭 수집
|
|
|