Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion discord-github-worker/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
config.json
# Dependencies
node_modules/

# Wrangler
.wrangler/
.dev.vars

# Environment
.env
config.json

# Python (legacy)
__pycache__/
*.pyc

# OS
.DS_Store
Thumbs.db
147 changes: 147 additions & 0 deletions discord-github-worker/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Discord-GitHub-Notion 통합 Worker: Cloudflare Workers에서 실행되는 TypeScript 기반 서버리스 애플리케이션으로, GitHub 이슈와 Discord 포럼 포스트, Notion 데이터베이스를 양방향으로 동기화합니다.

## Development Commands

```bash
# 디렉토리 이동
cd discord-github-worker

# 로컬 개발 서버 실행
npm run dev

# Cloudflare Workers에 배포
npm run deploy

# 실시간 로그 확인
npm run tail
```

## Configuration Management

### Secrets 설정 (민감 정보)
```bash
wrangler secret put DISCORD_PUBLIC_KEY
wrangler secret put DISCORD_BOT_TOKEN
wrangler secret put GITHUB_PRIVATE_KEY
wrangler secret put GITHUB_WEBHOOK_SECRET
wrangler secret put NOTION_API_KEY # 선택사항
```

### KV Namespace 설정
```bash
# 최초 1회만 실행
wrangler kv namespace create MAPPING

# 출력된 ID를 wrangler.toml의 kv_namespaces.id에 입력
```

### Environment Variables
`wrangler.toml`의 `[vars]` 섹션에서 설정:
- `GITHUB_APP_ID`: GitHub App ID
- `GITHUB_OWNER`: GitHub 레포지토리 소유자
- `GITHUB_REPO`: GitHub 레포지토리 이름
- `DISCORD_FORUM_CHANNEL_ID`: 이슈 동기화용 Discord 포럼 채널 ID
- `DISCORD_PR_CHANNEL_ID`: PR 알림용 Discord 채널 ID
- `NOTION_DATABASE_ID`: Notion 데이터베이스 ID (선택사항)

Secrets (`wrangler secret put`으로 설정):
- `DISCORD_PUBLIC_KEY`: Discord 앱 공개 키
- `DISCORD_BOT_TOKEN`: Discord 봇 토큰
- `GITHUB_PRIVATE_KEY`: GitHub App 비공개 키
- `GITHUB_WEBHOOK_SECRET`: GitHub Webhook 시크릿
- `NOTION_API_TOKEN`: Notion Integration 토큰 (선택사항)
- `NOTION_DATA_SOURCE_ID`: Notion 데이터베이스 ID (선택사항)

## Architecture

### Request Flow

```
┌─────────────┐ /discord ┌──────────────────┐
│ Discord │ ──────────────────▶│ │
│ Interaction │ │ │
└─────────────┘ │ Cloudflare │
│ Worker │
┌─────────────┐ /github │ (index.ts) │
│ GitHub │ ──────────────────▶│ │
│ Webhook │ │ │
└─────────────┘ └──────────────────┘
┌──────────────────┐
│ KV Namespace │
│ (MAPPING) │
└──────────────────┘
```

### Core Components

**src/index.ts**: 메인 엔트리포인트
- `/discord`: Discord Interaction 엔드포인트 (서명 검증 + 커맨드 라우팅)
- `/github`: GitHub Webhook 엔드포인트 (서명 검증 + 이벤트 라우팅)
- `/health`: 헬스체크

**src/discord.ts**: Discord 이벤트 핸들러
- `/sync`: 현재 포스트의 연결된 GitHub 이슈 확인
- `/comment`: Discord에서 GitHub 이슈로 댓글 전송 (deferred response로 3초 제한 회피)
- `handleForumMessage()`: Gateway 이벤트 처리 (구현 예정)

**src/github.ts**: GitHub Webhook 핸들러
- `issues.opened`: Discord 포럼 포스트 + Notion 페이지 생성
- `issues.closed/reopened`: Discord 알림 + Notion 상태 업데이트
- `issue_comment.created`: GitHub 댓글 → Discord 포스트 (무한 루프 방지 로직 포함)
- `pull_request.*`: PR 알림 전송 (opened/closed/reopened/ready_for_review만 처리, draft 제외)

**src/utils/mapping.ts**: KV 기반 양방향 매핑
- `issue:{owner}/{repo}/{issueNumber}` → Discord 포스트 ID
- `post:{postId}` → `{owner}/{repo}/{issueNumber}`
- `notion:{owner}/{repo}/{issueNumber}` → Notion 페이지 ID

**src/utils/discord-api.ts**: Discord API 클라이언트
- `createForumPost()`: 포럼 채널에 새 포스트(스레드) 생성
- `sendMessageToThread()`: 포스트에 댓글 추가
- `sendPRNotification()`: Embed를 사용한 PR 알림
- `verifyDiscordSignature()`: Ed25519 서명 검증

**src/utils/github-api.ts**: GitHub API 클라이언트 (GitHub App 인증)
- `createJWT()`: RS256 JWT 생성 (PKCS#1 → PKCS#8 자동 변환)
- `getInstallationToken()`: Repository별 Installation Access Token 획득
- `addIssueComment()`: 이슈에 댓글 추가
- `verifyGitHubSignature()`: HMAC-SHA256 서명 검증

**src/utils/notion-api.ts**: Notion API 클라이언트
- `createNotionPage()`: 데이터베이스에 이슈 페이지 생성
- `updateNotionPageStatus()`: 이슈 상태(Open/Closed) 업데이트
- Notion 속성: 제목, 이슈번호, GitHub 링크, 상태, 작성자, 생성일

### Key Design Patterns

**무한 루프 방지**
- Discord → GitHub 댓글: `**{username}** commented on Discord:` 접두사 추가
- GitHub → Discord 댓글: 댓글 본문에 "commented on Discord:" 포함 시 무시

**서명 검증**
- Discord: Ed25519 (`x-signature-ed25519`, `x-signature-timestamp`)
- GitHub: HMAC-SHA256 (`x-hub-signature-256`)

**비동기 작업 처리**
- `/comment` 명령: `InteractionResponseType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE` 즉시 반환 후 `ctx.waitUntil()`로 백그라운드 작업 실행
- 3초 Discord Interaction 제한 회피

**GitHub App 인증**
- PEM 포맷 private key를 PKCS#8로 변환하여 Web Crypto API 호환
- Base64 인코딩된 PEM도 자동 디코딩 처리
- Repository별로 동적 Installation Token 획득 (캐싱 없음)

## Important Notes

- Discord 메시지/타이틀 길이 제한: 2000자 (초과 시 자동 truncate)
- GitHub private key는 base64 인코딩 또는 PEM 형식 모두 지원
- Notion 통합은 선택사항 (`NOTION_API_KEY`와 `NOTION_DATABASE_ID` 미설정 시 스킵)
- PR draft는 `opened` 이벤트에서 자동 무시됨
30 changes: 3 additions & 27 deletions discord-github-worker/README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,5 @@
# Discord-GitHub Issue Worker
# Discord-GitHub-Notion Worker

디스코드와 깃허브 이슈를 연동하는 워커입니다.
GitHub, Discord, Notion 3-way 동기화를 위한 Cloudflare Worker.

## 기능

- GitHub 이슈 생성/업데이트 시 Discord 알림
- Discord 명령어로 GitHub 이슈 생성
- 이슈 상태 변경 추적

## 설정

`config.json` 파일을 생성하고 다음 내용을 입력하세요:

```json
{
"discord_token": "YOUR_DISCORD_BOT_TOKEN",
"discord_channel_id": "YOUR_CHANNEL_ID",
"github_token": "YOUR_GITHUB_TOKEN",
"github_repo": "owner/repo"
}
```

## 실행

```bash
pip install -r requirements.txt
python main.py
```
자세한 내용은 [docs/README.md](docs/README.md) 참고.
6 changes: 0 additions & 6 deletions discord-github-worker/config.example.json

This file was deleted.

118 changes: 118 additions & 0 deletions discord-github-worker/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Discord-GitHub-Notion Integration Worker

Cloudflare Workers 기반 서버리스 애플리케이션.
GitHub 이슈, Discord 포럼 포스트, Notion 데이터베이스를 양방향으로 동기화한다.

## Architecture

```
┌─────────────┐ POST /discord ┌──────────────────┐ GitHub API
│ Discord │ ─────────────────────▶│ │────────────────▶ Issues, Comments
│ Interaction │ │ │
└─────────────┘ │ Cloudflare │ Notion API
│ Worker │────────────────▶ Database Pages
┌─────────────┐ POST /github │ │
│ GitHub │ ─────────────────────▶│ │ Discord API
│ Webhook │ │ │────────────────▶ Forum Posts, Embeds
└─────────────┘ └────────┬─────────┘
KV Namespace
(양방향 매핑 저장)
issue ↔ post ↔ notion
```

## Features

### GitHub → Discord
| 이벤트 | 동작 |
|--------|------|
| 이슈 생성 | 포럼 채널에 새 포스트 생성 |
| 이슈 댓글 | 연결된 포스트에 메시지 전송 |
| 이슈 close/reopen | 포스트에 상태 변경 알림 |
| PR opened/closed/merged | PR 채널에 Embed 알림 |

### GitHub → Notion
| 이벤트 | 동작 |
|--------|------|
| 이슈 생성 | 데이터베이스에 페이지 추가 |
| 이슈 close/reopen | 페이지 상태 업데이트 |

### Discord → GitHub
| 커맨드 | 동작 |
|--------|------|
| `/issue create` | Modal 폼으로 GitHub 이슈 생성 (라벨 지원) |
| `/comment <message>` | 연결된 GitHub 이슈에 댓글 전송 |
| `/sync` | 현재 포스트의 연결된 이슈 정보 확인 |

## Tech Stack

- **Runtime**: Cloudflare Workers
- **Language**: TypeScript
- **Storage**: Cloudflare KV (양방향 매핑)
- **Auth**: GitHub App (JWT + Installation Token), Discord Ed25519 서명 검증

## Project Structure

```
discord-github-worker/
├── src/
│ ├── index.ts # 라우터 (엔트리포인트)
│ ├── discord.ts # Discord Interaction 핸들러
│ ├── github.ts # GitHub Webhook 핸들러
│ └── utils/
│ ├── discord-api.ts # Discord API 호출
│ ├── github-api.ts # GitHub App 인증 + API 호출
│ ├── notion-api.ts # Notion API 호출
│ └── mapping.ts # KV 매핑 관리
├── scripts/
│ └── register-commands.js # 슬래시 커맨드 등록
├── wrangler.toml # Cloudflare Workers 설정
└── docs/
└── README.md # 이 문서
```

## KV Mapping Schema

```
issue:{owner}/{repo}/{number} → Discord Post ID
post:{postId} → {owner}/{repo}/{number}
notion:{owner}/{repo}/{number} → Notion Page ID
```

## Setup

### 1. KV Namespace 생성
```bash
wrangler kv namespace create MAPPING
# 출력된 ID를 wrangler.toml에 입력
```

### 2. Secrets 설정
```bash
wrangler secret put DISCORD_PUBLIC_KEY
wrangler secret put DISCORD_BOT_TOKEN
wrangler secret put GITHUB_PRIVATE_KEY
wrangler secret put GITHUB_WEBHOOK_SECRET
wrangler secret put NOTION_API_TOKEN # 선택
wrangler secret put NOTION_DATA_SOURCE_ID # 선택
```

### 3. 슬래시 커맨드 등록
```bash
DISCORD_APP_ID=xxx DISCORD_BOT_TOKEN=xxx node scripts/register-commands.js
```

### 4. 배포
```bash
npm run deploy
```

### 5. Webhook 연결
- **Discord**: Bot Settings → Interactions Endpoint URL → `https://<worker>.workers.dev/discord`
- **GitHub**: Repo Settings → Webhooks → `https://<worker>.workers.dev/github`
- Events: Issues, Issue comments, Pull requests

## Loop Prevention

Discord→GitHub 댓글에 `commented on Discord:` 마커를 포함시키고,
GitHub→Discord 동기화 시 해당 마커가 있는 댓글은 무시하여 무한 루프를 방지한다.
25 changes: 0 additions & 25 deletions discord-github-worker/main.py

This file was deleted.

Loading