-
Notifications
You must be signed in to change notification settings - Fork 0
프로젝트 초기 설정 #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
프로젝트 초기 설정 #9
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
712308a
feat: 프로젝트 초기 설정
DaleSeo de924ae
refactor: 환경변수 네이밍 및 관리 방식 개선
DaleSeo 3f39ea3
ci: create a PR instead of pushing
DaleSeo 1c6bb3b
fix: handle case when no matches are created and improve error handling
DaleSeo c6b8d41
test: add tests for match creation and webhook announcement
DaleSeo 0419e02
fix: 테스트 파일의 타입 캐스팅 오류 수정
DaleSeo 61373fa
ci: Biome lint/format 및 CI 워크플로우 추가
DaleSeo d22e65d
chore: add agent context files
DaleSeo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| name: CI | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: [main] | ||
|
|
||
| jobs: | ||
| test: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup Bun | ||
| uses: oven-sh/setup-bun@v2 | ||
|
|
||
| - name: Install dependencies | ||
| run: bun install | ||
|
|
||
| - name: Type check | ||
| run: bun run typecheck | ||
|
|
||
| - name: Lint & Format check | ||
| run: bun run lint | ||
|
|
||
| - name: Run tests | ||
| run: bun test |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| name: Coffee Chat Matching | ||
|
|
||
| on: | ||
| schedule: | ||
| # 매주 월요일 UTC 00:00 (KST 09:00) | ||
| - cron: "0 0 * * 1" | ||
| workflow_dispatch: # 수동 실행 가능 | ||
|
|
||
| jobs: | ||
| match: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup Bun | ||
| uses: oven-sh/setup-bun@v2 | ||
|
|
||
| - name: Install dependencies | ||
| run: bun install | ||
|
|
||
| - name: Check if this is a matching week | ||
| id: check-week | ||
| run: | | ||
| WEEK_NUM=$(date +%V) | ||
| if [ $((WEEK_NUM % 2)) -eq 0 ]; then | ||
| echo "skip=false" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "skip=true" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Run matching | ||
| if: steps.check-week.outputs.skip == 'false' || github.event_name == 'workflow_dispatch' | ||
| env: | ||
| DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }} | ||
| DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} | ||
| DISCORD_SERVER_ID: ${{ vars.DISCORD_SERVER_ID }} | ||
| DISCORD_ROLE_ID: ${{ vars.DISCORD_ROLE_ID }} | ||
| run: bun run match | ||
|
|
||
| - name: Create Pull Request | ||
| if: steps.check-week.outputs.skip == 'false' || github.event_name == 'workflow_dispatch' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| BRANCH_NAME="chore/update-match-history-$(date +%Y-%m-%d)" | ||
| git checkout -b "$BRANCH_NAME" | ||
| git add data/history.json | ||
| git diff --staged --quiet && exit 0 | ||
| git commit -m "chore: update match history" | ||
| git push -u origin "$BRANCH_NAME" | ||
| gh pr create --fill --body "자동 생성된 커피챗 매칭 히스토리 업데이트입니다." | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| # Dependencies | ||
| node_modules/ | ||
|
|
||
| # Build output | ||
| dist/ | ||
|
|
||
| # Environment variables | ||
| .env | ||
| .env.local | ||
|
|
||
| # OS files | ||
| .DS_Store | ||
|
|
||
| # IDE | ||
| .idea/ | ||
| .vscode/ | ||
|
|
||
| # Logs | ||
| *.log | ||
| npm-debug.log* | ||
|
|
||
| CLAUDE.md |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| # CLAUDE.md | ||
|
|
||
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
|
|
||
| ## Project Overview | ||
|
|
||
| 디스코드 서버 멤버들을 자동으로 매칭하여 커피챗(1:1 대화)을 연결해주는 봇입니다. GitHub Actions로 2주마다 자동 실행되며, Discord Role 기반으로 참여자를 관리합니다. | ||
|
|
||
| ## Development Commands | ||
|
|
||
| ```bash | ||
| # 매칭 실행 (로컬 테스트) | ||
| bun run match | ||
|
|
||
| # 테스트 실행 | ||
| bun test | ||
|
|
||
| # 타입 체크 | ||
| bun run typecheck | ||
|
|
||
| # Lint 체크 | ||
| bun run lint | ||
|
|
||
| # 코드 포맷팅 | ||
| bun run format | ||
| ``` | ||
|
|
||
| ## Architecture | ||
|
|
||
| ### 실행 흐름 (src/index.ts) | ||
|
|
||
| 1. **참여자 조회** (`discord.ts`) - Discord API로 특정 Role을 가진 멤버 목록 가져오기 | ||
| 2. **매칭 이력 로드** (`matcher.ts`) - `data/history.json`에서 과거 매칭 기록 로드 | ||
| 3. **매칭 생성** (`matcher.ts`) - Fisher-Yates 셔플 + 중복 방지 알고리즘 | ||
| 4. **이력 저장** (`matcher.ts`) - 새로운 매칭을 history.json에 추가 | ||
| 5. **Discord 발표** (`webhook.ts`) - Webhook으로 매칭 결과 채널에 공지 | ||
|
|
||
| ### 핵심 알고리즘 (matcher.ts) | ||
|
|
||
| - **중복 방지**: 최근 4회 매칭 이력과 비교하여 같은 조합 회피 (최대 100번 재시도) | ||
| - **홀수 처리**: 참여자가 홀수일 경우 마지막 조를 3인 1조로 구성 | ||
| - **데이터 구조**: `data/history.json`에 날짜별 매칭 기록 저장 | ||
|
|
||
| ### 환경변수 | ||
|
|
||
| **Secrets** (GitHub Secrets에 저장): | ||
|
|
||
| - `DISCORD_BOT_TOKEN` - Discord Bot 토큰 (Role 멤버 조회용) | ||
| - `DISCORD_WEBHOOK_URL` - 매칭 결과 발표용 Webhook URL | ||
|
|
||
| **Variables** (GitHub Variables에 저장): | ||
|
|
||
| - `DISCORD_SERVER_ID` - 디스코드 서버 ID | ||
| - `DISCORD_ROLE_ID` - 커피챗 참여자 Role ID | ||
|
|
||
| ### GitHub Actions 자동화 | ||
|
|
||
| `.github/workflows/match.yml`: | ||
|
|
||
| - **스케줄**: 매주 월요일 UTC 00:00 (KST 09:00) | ||
| - **격주 실행**: 짝수 주에만 매칭 실행 (홀수 주는 skip) | ||
| - **수동 실행**: `workflow_dispatch`로 언제든지 수동 트리거 가능 | ||
| - **이력 관리**: 매칭 후 `data/history.json` 변경사항을 PR로 자동 생성 | ||
|
|
||
| ## Code Style | ||
|
|
||
| - **Runtime**: Bun (TypeScript 네이티브 지원) | ||
| - **Formatter**: Biome (tab indent, recommended rules) | ||
| - **Testing**: Bun test (`*.test.ts` 파일) | ||
| - **Import**: ESM (`type: "module"`) | ||
|
|
||
| ## Testing | ||
|
|
||
| 테스트 파일은 `*.test.ts` 형식으로 작성하며, Bun의 test runner를 사용합니다. | ||
|
|
||
| ```typescript | ||
| // expect().toBeDefined() 후 non-null assertion 사용 패턴 | ||
| expect(capturedBody).toBeDefined(); | ||
| const parsed = JSON.parse(capturedBody!); // OK in tests | ||
| ``` | ||
|
|
||
| 이 패턴 때문에 `biome.json`에서 `noNonNullAssertion` 규칙이 비활성화되어 있습니다. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| { | ||
| "$schema": "https://biomejs.dev/schemas/2.3.12/schema.json", | ||
| "vcs": { | ||
| "enabled": true, | ||
| "clientKind": "git", | ||
| "useIgnoreFile": true | ||
| }, | ||
| "formatter": {}, | ||
| "linter": { | ||
| "rules": { | ||
| "style": { | ||
| "noNonNullAssertion": "off" | ||
| } | ||
| } | ||
| } | ||
| } |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "matches": [] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| { | ||
| "name": "coffee", | ||
| "version": "1.0.0", | ||
| "description": "디스코드 커피챗 매칭 봇", | ||
| "type": "module", | ||
| "scripts": { | ||
| "match": "bun run src/index.ts", | ||
| "test": "bun test", | ||
| "lint": "biome check .", | ||
| "format": "biome format --write .", | ||
| "typecheck": "tsc --noEmit" | ||
| }, | ||
| "dependencies": { | ||
| "discord.js": "^14.25.1" | ||
| }, | ||
| "devDependencies": { | ||
| "@biomejs/biome": "^2.3.12", | ||
| "@types/bun": "latest", | ||
| "typescript": "^5.9.3" | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import { Client, GatewayIntentBits } from "discord.js"; | ||
| import type { Participant } from "./types.ts"; | ||
|
|
||
| function getEnvOrThrow(key: string): string { | ||
| const value = process.env[key]; | ||
| if (!value) { | ||
| throw new Error(`환경변수 ${key}가 설정되지 않았습니다.`); | ||
| } | ||
| return value; | ||
| } | ||
|
|
||
| const DISCORD_BOT_TOKEN = getEnvOrThrow("DISCORD_BOT_TOKEN"); | ||
| const SERVER_ID = getEnvOrThrow("DISCORD_SERVER_ID"); | ||
| const ROLE_ID = getEnvOrThrow("DISCORD_ROLE_ID"); | ||
|
|
||
| export async function getParticipants(): Promise<Participant[]> { | ||
| const client = new Client({ | ||
| intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers], | ||
| }); | ||
|
|
||
| await client.login(DISCORD_BOT_TOKEN); | ||
|
|
||
| try { | ||
| const guild = await client.guilds.fetch(SERVER_ID); | ||
| const members = await guild.members.fetch(); | ||
|
|
||
| const participants = members | ||
| .filter((member) => member.roles.cache.has(ROLE_ID) && !member.user.bot) | ||
| .map((member) => ({ | ||
| id: member.user.id, | ||
| username: member.user.username, | ||
| })); | ||
|
|
||
| return participants; | ||
| } finally { | ||
| await client.destroy(); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.