Skip to content

Commit a47340e

Browse files
authored
Merge pull request #32 from DaleStudy/21
사용자 기능 구현
2 parents 08f188c + c915bd7 commit a47340e

File tree

15 files changed

+887
-13
lines changed

15 files changed

+887
-13
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ node_modules/
33

44
# Build output
55
dist/
6+
.wrangler/
67

78
# Environment variables
89
.env
910
.env.local
11+
.dev.vars
1012

1113
# OS files
1214
.DS_Store

AGENTS.md

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Project Overview
66

7-
디스코드 서버 멤버들을 자동으로 매칭하여 커피챗(1:1 대화)을 연결해주는 봇입니다. GitHub Actions로 2주마다 자동 실행되며, Discord Role 기반으로 참여자를 관리합니다.
7+
디스코드 서버 멤버들을 자동으로 매칭하여 커피챗(1:1 대화)을 연결해주는 봇입니다. GitHub Actions로 2주마다 자동 실행되며, Discord Role 기반으로 참여자를 관리합니다. `/coffee join``/coffee leave` 슬래시 명령어로 사용자가 직접 참여/탈퇴할 수 있으며, Cloudflare Workers로 서버리스 처리됩니다.
88

99
## Development Commands
1010

@@ -23,18 +23,34 @@ bun run lint
2323

2424
# 코드 포맷팅
2525
bun run format
26+
27+
# Worker 로컬 개발
28+
bun run worker:dev
29+
30+
# Worker 배포
31+
bun run worker:deploy
32+
33+
# 슬래시 명령어 등록
34+
bun run worker:register
2635
```
2736

2837
## Architecture
2938

30-
### 실행 흐름 (src/index.ts)
39+
### 매칭 실행 흐름 (src/index.ts)
3140

3241
1. **참여자 조회** (`discord.ts`) - Discord API로 특정 Role을 가진 멤버 목록 가져오기
3342
2. **매칭 이력 로드** (`matcher.ts`) - `data/history.json`에서 과거 매칭 기록 로드
3443
3. **매칭 생성** (`matcher.ts`) - Fisher-Yates 셔플 + 중복 방지 알고리즘
3544
4. **이력 저장** (`matcher.ts`) - 새로운 매칭을 history.json에 추가
3645
5. **Discord 발표** (`webhook.ts`) - Webhook으로 매칭 결과 채널에 공지
3746

47+
### 슬래시 명령어 처리 흐름 (worker/src/index.ts)
48+
49+
1. **서명 검증** (`verify.ts`) - Discord 요청의 Ed25519 서명 검증
50+
2. **PING/PONG** - Discord 연결 확인 응답
51+
3. **명령어 라우팅** (`handlers.ts`) - `/coffee join` 또는 `/coffee leave` 처리
52+
4. **Role 관리** (`discord-api.ts`) - Discord REST API로 Role 추가/제거
53+
3854
### 핵심 알고리즘 (matcher.ts)
3955

4056
- **중복 방지**: 최근 4회 매칭 이력과 비교하여 같은 조합 회피 (최대 100번 재시도)
@@ -43,15 +59,20 @@ bun run format
4359

4460
### 환경변수
4561

46-
**Secrets** (GitHub Secrets에 저장):
62+
**매칭 (GitHub Actions)**:
4763

48-
- `DISCORD_BOT_TOKEN` - Discord Bot 토큰 (Role 멤버 조회용)
49-
- `DISCORD_WEBHOOK_URL` - 매칭 결과 발표용 Webhook URL
64+
- `DISCORD_BOT_TOKEN` - Discord Bot 토큰 (Secret)
65+
- `DISCORD_WEBHOOK_URL` - 매칭 결과 발표용 Webhook URL (Secret)
66+
- `DISCORD_SERVER_ID` - 디스코드 서버 ID (Variable)
67+
- `DISCORD_ROLE_ID` - 커피챗 참여자 Role ID (Variable)
5068

51-
**Variables** (GitHub Variables에 저장):
69+
**Worker (Cloudflare)**:
5270

53-
- `DISCORD_SERVER_ID` - 디스코드 서버 ID
54-
- `DISCORD_ROLE_ID` - 커피챗 참여자 Role ID
71+
- `DISCORD_PUBLIC_KEY` - 서명 검증용 공개키 (wrangler.jsonc var)
72+
- `DISCORD_APPLICATION_ID` - Discord 앱 ID (wrangler.jsonc var)
73+
- `DISCORD_SERVER_ID` - 서버 ID (wrangler.jsonc var)
74+
- `DISCORD_ROLE_ID` - 커피챗 Role ID (wrangler.jsonc var)
75+
- `DISCORD_BOT_TOKEN` - Bot 토큰 (wrangler secret)
5576

5677
### GitHub Actions 자동화
5778

PLAN.md

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
# Coffee Chat Bot - 개발 계획
2+
3+
> 이 문서는 완료된 기능과 향후 추가할 기능들을 정리합니다.
4+
5+
---
6+
7+
## ✅ 완료된 기능 (MVP)
8+
9+
### 핵심 기능
10+
11+
#### B-1: 자동 매칭
12+
**상태**: ✅ 완료 (2026-01-26)
13+
14+
**구현 내용**:
15+
- GitHub Actions를 통한 2주마다 자동 실행
16+
- cron 스케줄: 매주 월요일 UTC 00:00 (KST 09:00)
17+
- 짝수 주차에만 실행 (홀수 주는 skip)
18+
- `workflow_dispatch`로 수동 트리거 가능
19+
20+
**구현 파일**:
21+
- `.github/workflows/match.yml`
22+
- `src/matcher.ts` - `createMatches()`
23+
24+
#### B-2: 매칭 발표
25+
**상태**: ✅ 완료 (2026-01-26)
26+
27+
**구현 내용**:
28+
- Discord Webhook으로 매칭 결과 채널에 공지
29+
- 참여자 멘션 포함 (`<@user_id>`)
30+
- 3인조 표시 자동 추가
31+
32+
**구현 파일**:
33+
- `src/webhook.ts` - `announceMatches()`
34+
35+
**메시지 포맷**:
36+
```
37+
☕ **이번 커피챗 매칭 발표!**
38+
39+
1. @user1 ↔ @user2
40+
2. @user3 ↔ @user4
41+
3. @user5 ↔ @user6 ↔ @user7 (3인조)
42+
43+
2주 안에 커피챗을 진행해주세요! ☕
44+
```
45+
46+
#### B-3: 중복 매칭 방지
47+
**상태**: ✅ 완료 (2026-01-26)
48+
49+
**구현 내용**:
50+
- `data/history.json`에서 최근 4회 매칭 이력 참조
51+
- 같은 조합이 나오면 재셔플 (최대 100번 시도)
52+
- Fisher-Yates 셔플 알고리즘 사용
53+
54+
**구현 파일**:
55+
- `src/matcher.ts` - `getRecentPairs()`, `shuffle()`
56+
57+
**데이터 구조**:
58+
```json
59+
{
60+
"matches": [
61+
{
62+
"date": "2026-01-26",
63+
"pairs": [
64+
["user_id_1", "user_id_2"],
65+
["user_id_3", "user_id_4"]
66+
]
67+
}
68+
]
69+
}
70+
```
71+
72+
#### B-4: 홀수 처리
73+
**상태**: ✅ 완료 (2026-01-26)
74+
75+
**구현 내용**:
76+
- 참여자가 홀수일 경우 마지막 조를 3인 1조로 구성
77+
- 마지막 사람을 마지막 조에 추가
78+
79+
**구현 파일**:
80+
- `src/matcher.ts` - `createMatches()` 마지막 로직
81+
82+
---
83+
84+
### 인프라 & CI/CD
85+
86+
#### GitHub Actions 자동화
87+
**상태**: ✅ 완료 (2026-01-26)
88+
89+
**구현 내용**:
90+
- 매칭 자동 실행 워크플로우
91+
- 매칭 후 `data/history.json` 변경사항을 자동 PR 생성
92+
- Biome 자동 포맷팅 추가 (2026-02-01)
93+
94+
**구현 파일**:
95+
- `.github/workflows/match.yml`
96+
- `.github/workflows/ci.yml`
97+
98+
#### CI 파이프라인
99+
**상태**: ✅ 완료 (2026-01-26)
100+
101+
**구현 내용**:
102+
- TypeScript 타입 체크 (`tsc --noEmit`)
103+
- Biome lint & format 체크
104+
- Bun 테스트 실행
105+
- PR 및 main push 시 자동 실행
106+
107+
**구현 파일**:
108+
- `.github/workflows/ci.yml`
109+
- `biome.json`
110+
111+
---
112+
113+
### 기술 스택
114+
115+
| 항목 | 선택 | 완료일 |
116+
|------|------|--------|
117+
| 런타임 | Bun | 2026-01-26 |
118+
| 언어 | TypeScript | 2026-01-26 |
119+
| 데이터 저장 | JSON 파일 | 2026-01-26 |
120+
| 매칭 실행 | GitHub Actions (cron) | 2026-01-26 |
121+
| 결과 발표 | Discord Webhook | 2026-01-26 |
122+
| 참여자 관리 | `/coffee join/leave` (Cloudflare Worker) | 2026-02-08 |
123+
| 코드 품질 | Biome (lint + format) | 2026-01-26 |
124+
125+
---
126+
127+
### 환경변수
128+
129+
| 환경변수 | 타입 | 용도 |
130+
|----------|------|------|
131+
| `DISCORD_BOT_TOKEN` | Secret | Discord Bot 토큰 (Role 멤버 조회) |
132+
| `DISCORD_WEBHOOK_URL` | Secret | 매칭 결과 발표용 Webhook |
133+
| `DISCORD_SERVER_ID` | Variable | 디스코드 서버 ID |
134+
| `DISCORD_ROLE_ID` | Variable | 커피챗 참여자 Role ID |
135+
136+
---
137+
138+
## 📋 Post-MVP 기능
139+
140+
### 1. 사용자 기능
141+
142+
#### U-1: 커피챗 참여 신청
143+
**상태**: ✅ 완료 (2026-02-08)
144+
145+
**구현 내용**:
146+
- `/coffee join` 슬래시 명령어로 커피챗 Role 자동 부여
147+
- Cloudflare Workers + Discord HTTP Interactions Endpoint 방식 (상시 서버 불필요)
148+
- ephemeral 응답으로 본인에게만 확인 메시지 표시
149+
150+
**구현 파일**:
151+
- `worker/src/handlers.ts` - `handleJoin()`
152+
- `worker/src/discord-api.ts` - `addRole()`
153+
154+
#### U-2: 커피챗 참여 탈퇴
155+
**상태**: ✅ 완료 (2026-02-08)
156+
157+
**구현 내용**:
158+
- `/coffee leave` 슬래시 명령어로 커피챗 Role 자동 제거
159+
- U-1과 동일한 Cloudflare Workers 인프라 사용
160+
161+
**구현 파일**:
162+
- `worker/src/handlers.ts` - `handleLeave()`
163+
- `worker/src/discord-api.ts` - `removeRole()`
164+
165+
---
166+
167+
### 2. 관리자 기능
168+
169+
#### A-1: 매칭 주기 설정
170+
**설명**: 매칭이 실행되는 주기 및 시간을 관리자가 설정
171+
172+
**현재 제약**:
173+
- 매칭 주기가 2주로 하드코딩됨 (`.github/workflows/match.yml`)
174+
- 변경하려면 GitHub Actions 워크플로우 파일 수정 필요
175+
176+
**향후 구현**:
177+
- 설정 파일 또는 Discord 명령어로 주기 변경
178+
- 예: `/coffee set-schedule weekly` 또는 `/coffee set-schedule biweekly`
179+
180+
---
181+
182+
### 3. 고급 매칭 기능
183+
184+
#### 채널/그룹별 매칭 풀 분리
185+
**설명**: 슬랙 Donut처럼 채널별로 독립적인 매칭 풀 운영
186+
187+
**배경**:
188+
- 디스코드는 슬랙과 달리 채널 멤버십 개념이 없음
189+
- 채널 참여 = 매칭 풀 참여 자동 연동 불가
190+
191+
**구현 방식 (옵션)**:
192+
1. **채널 + Role 연동**: 채널마다 전용 Role 생성
193+
2. **포럼/스레드 활용**: 관심사별 포럼 채널 참여자 매칭
194+
3. **명령어에 채널 지정**: `/coffee join #channel-name`
195+
196+
**데이터 구조 변경**:
197+
```json
198+
{
199+
"channels": {
200+
"채널_ID_1": {
201+
"matches": [...]
202+
},
203+
"채널_ID_2": {
204+
"matches": [...]
205+
}
206+
}
207+
}
208+
```
209+
210+
#### 관심사 기반 매칭 알고리즘
211+
**설명**: 직군, 관심사 등 다양한 기준으로 최적의 매칭
212+
213+
**구현 아이디어**:
214+
- 사용자 프로필 등록 (관심사, 직군, 경력 등)
215+
- 가중치 기반 매칭 점수 계산
216+
- 유사도가 낮은 사람끼리 매칭하여 다양성 증진
217+
218+
---
219+
220+
### 4. 피드백 & 품질 개선
221+
222+
#### 커피챗 피드백 수집
223+
**설명**: 커피챗 후기 수집 및 매칭 품질 개선
224+
225+
**구현 방식**:
226+
- 커피챗 2주 후 자동 DM 발송
227+
- 간단한 평점 시스템 (👍/👎 리액션)
228+
- 피드백 데이터를 매칭 알고리즘에 반영
229+
230+
---
231+
232+
### 5. 스케줄링 통합
233+
234+
#### 사용자 프로필 및 가용 시간 등록
235+
**설명**: 사용자 가용 시간(Availability) 등록 및 자동 일정 조율
236+
237+
**기능**:
238+
- 사용자가 선호하는 요일/시간대 등록
239+
- Google Calendar, Outlook 연동
240+
- 매칭 시 양측의 가용 시간 자동 제안
241+
242+
---
243+
244+
### 6. 배포 & 확장
245+
246+
#### 마켓플레이스 공개 배포
247+
**설명**: Discord 마켓플레이스에서 누구나 설치 가능한 오픈소스 봇
248+
249+
**요구사항**:
250+
- 멀티 테넌시 지원 (여러 서버에서 독립적으로 동작)
251+
- 데이터베이스 필요 (JSON 파일로는 한계)
252+
- 안정적인 호스팅 환경
253+
254+
---
255+
256+
## 우선순위
257+
258+
| 순위 | 기능 | 난이도 | 비고 |
259+
|------|------|--------|------|
260+
| 1 | A-1: 매칭 주기 설정 | 쉬움 | 설정 파일만 추가하면 됨 |
261+
| 2 | 채널/그룹별 매칭 풀 | 중간 | 데이터 구조 변경 필요 |
262+
| ~~3~~ | ~~U-1, U-2: 슬래시 명령어~~ | ~~중간~~ | ✅ 완료 (Cloudflare Worker) |
263+
| 4 | 피드백 수집 | 중간 | DM 발송 로직 추가 |
264+
| 5 | 관심사 기반 매칭 | 어려움 | 프로필 시스템 + 알고리즘 개선 |
265+
| 6 | 스케줄링 통합 | 어려움 | 외부 API 연동 |
266+
| 7 | 마켓플레이스 배포 | 어려움 | 멀티 테넌시 + DB + 호스팅 |
267+
268+
---
269+
270+
## 기술 부채
271+
272+
### 현재 제약사항
273+
274+
1. **JSON 파일 기반 저장소**
275+
- 동시성 제어 없음
276+
- 스케일링 한계
277+
- → PostgreSQL/MongoDB로 마이그레이션 필요
278+
279+
2. **GitHub Actions 실행**
280+
- 실시간 명령어 처리 불가
281+
- 매칭 주기 변경 시 코드 수정 필요
282+
- → 상시 실행 봇 + 설정 관리 시스템 필요
283+
284+
3. ~~**Role 수동 관리**~~ → ✅ 해결 (2026-02-08)
285+
- `/coffee join` / `/coffee leave` 명령어로 자동화 완료
286+
- Cloudflare Workers로 서버리스 구현
287+
288+
---
289+
290+
## 참고 자료
291+
292+
- 벤치마킹: [Donut (Slack)](https://www.donut.com/)
293+
- Discord API: https://discord.com/developers/docs
294+
- discord.js: https://discord.js.org/

0 commit comments

Comments
 (0)