이 문서는 AI 에이전트가 프로젝트를 이해하고 작업할 수 있도록 돕는 가이드입니다.
DaleStudy 조직의 GitHub App(https://github.com/apps/dalestudy)
Fork PR에서도 작동하도록 GitHub Projects v2의 Week 필드를 조회하고, Week 설정이 누락된 PR에 자동으로 경고 댓글을 작성하며, Week 설정이 완료되면 경고 댓글을 자동으로 삭제한다.
- 대상 Repository: https://github.com/DaleStudy/leetcode-study
- 트리거 방식:
- 실시간: GitHub Organization Webhook (
projects_v2_item,pull_request이벤트) - 수동:
POST /check-weeks엔드포인트 직접 호출
- 실시간: GitHub Organization Webhook (
- Runtime: Cloudflare Workers
- Language: JavaScript (ES Modules)
- Authentication: GitHub App (JWT + Installation Token)
- APIs: GitHub REST API, GitHub GraphQL API
~/work/github/
├── index.js # Worker 메인 코드 (엔드포인트 라우팅)
├── wrangler.jsonc # Cloudflare Workers 설정
├── .env # 로컬 환경 변수 (커밋 제외)
├── .gitignore # Git 제외 파일
├── handlers/ # 기능별 핸들러
│ ├── check-weeks.js # PR Week 설정 검사 (수동 호출용)
│ └── webhooks.js # GitHub webhook 이벤트 처리
├── utils/ # 공통 유틸리티
│ ├── cors.js # CORS 헤더 및 응답 유틸리티
│ ├── github.js # GitHub 인증 및 API 유틸리티
│ └── webhook.js # Webhook signature 검증
├── README.md # 프로젝트 설명
├── DEPLOYMENT.md # 배포 가이드
├── AGENTS.md # 이 파일 (AI 에이전트 가이드)
├── CLAUDE.md # Claude Code 참조 파일 (AGENTS.md로 리다이렉트)
└── *.pem # GitHub App Private Keys (커밋 제외)
- index.js (32줄): 엔드포인트 라우팅만 담당. pathname별 핸들러 호출
- handlers/: 기능별 핸들러
check-weeks.js: PR Week 설정 검사, 댓글 작성/삭제
- utils/: 여러 핸들러에서 공통으로 사용하는 유틸리티
cors.js: CORS 헤더 관리 및 응답 생성 (corsResponse,errorResponse)github.js: GitHub App 인증 (JWT, Installation Token), RSA 서명
- 기능별 핸들러 파일 생성 (예:
handlers/new-feature.js) index.js에 pathname 라우팅 추가
// handlers/new-feature.js 생성
export async function newFeature(request, env) {
// 비즈니스 로직
return corsResponse({ success: true });
}
// index.js에 라우팅 추가
import { newFeature } from "./handlers/new-feature.js";
if (url.pathname === "/new-feature") {
return newFeature(request, env);
}# 로컬 개발 서버 실행 (포트 8787)
wrangler dev
# 로컬 테스트 (별도 터미널)
curl -X POST http://localhost:8787/check-weeks \
-H "Content-Type: application/json" \
-d '{"repo_owner": "DaleStudy", "repo_name": "leetcode-study"}'# Worker 배포
wrangler deploy
# Secrets 설정
wrangler secret put APP_ID # GitHub App ID (숫자)
wrangler secret put PRIVATE_KEY # GitHub App Private Key (PEM 전체)
# Secrets 확인
wrangler secret list
# 실시간 로그 확인
wrangler tail# 배포된 Worker 테스트
curl -X POST https://github.dalestudy.com/check-weeks \
-H "Content-Type: application/json" \
-d '{"repo_owner": "DaleStudy", "repo_name": "leetcode-study"}'인증 흐름:
- RS256 알고리즘으로 JWT 생성 (Web Crypto API 사용)
- JWT로 Installation ID 조회
- Installation Token 발급 (10분 유효)
- 모든 API 요청에 Installation Token 사용
인증 관련 함수:
generateGitHubAppToken(): GitHub App Installation Token 발급 (전체 흐름 관리)createJWT(): RS256 JWT 생성 (GitHub App 인증용, 10분 유효)importPrivateKey(): PEM 형식 Private Key를 Web Crypto API용으로 변환 (PKCS8/PKCS1 모두 지원)sign(): RS256 서명 생성base64UrlEncode(): Base64 URL-safe 인코딩
현재 구현된 엔드포인트:
GitHub Organization webhook 수신용 엔드포인트
- 이벤트:
projects_v2_item,pull_request - 실시간 처리: Week 설정 변경 즉시 감지 및 댓글 작성/삭제
모든 Open PR에서 Week 설정을 검사하고 자동으로 댓글 작성/삭제 (수동 호출용)
Request:
repo_owner 생략 시 기본값으로 DaleStudy가 사용됩니다.
{
"repo_name": "leetcode-study"
}Response:
{
"success": true,
"total_prs": 3,
"checked": 3,
"commented": 1,
"deleted": 1,
"results": [
{ "pr": 1970, "week": null, "commented": true },
{ "pr": 1969, "week": "Week 8", "commented": false, "deleted": true }
]
}열려있는 답안 제출 PR을 일괄 승인합니다. excludes 배열로 특정 PR을 제외합니다. 이미 승인된 PR, maintenance 라벨, Draft 상태의 PR은 자동으로 스킵됩니다.
Request:
{ "repo_name": "leetcode-study", "excludes": [1972] }Response:
{
"success": true,
"action": "approve",
"repo": "DaleStudy/leetcode-study",
"total_open_prs": 5,
"processed": 2,
"approved": 2,
"skipped": 0,
"results": [
{ "pr": 1970, "title": "week8 solutions", "approved": true },
{ "pr": 1971, "title": "week8 extras", "approved": true }
]
}열려있는 PR을 일괄 병합합니다. 기본 병합 방식은 merge이며 merge_method 값으로 merge | squash | rebase 중 선택할 수 있습니다. excludes로 특정 PR을 제외할 수 있습니다. 승인 리뷰가 없거나 maintenance 라벨이 붙은 PR, Draft PR, GitHub mergeable_state !== "clean" PR은 스킵되며 unknown/behind 상태는 최대 1초 후 한 번 더 확인합니다.
Request:
{
"repo_name": "leetcode-study",
"merge_method": "squash",
"excludes": [1972]
}Response:
{
"success": true,
"action": "merge",
"repo": "DaleStudy/leetcode-study",
"merge_method": "squash",
"total_open_prs": 5,
"processed": 2,
"merged": 2,
"skipped": 0,
"results": [
{ "pr": 1970, "title": "week8 solutions", "merged": true, "sha": "abc123" },
{ "pr": 1971, "title": "week8 extras", "merged": true, "sha": "def456" }
]
}- Open PR 목록 조회 (GitHub REST API)
maintenance라벨 있는 PR 스킵- 각 PR의 Week 설정 확인 (GitHub GraphQL API - Projects v2 접근 필요)
- Week 없음 → 경고 댓글 작성 (중복 방지: Bot이 작성한 경고 댓글이 이미 있으면 스킵)
- Week 있음 → 기존 경고 댓글 삭제 (Bot이 작성한 Week 경고 댓글만)
repo_owner !== 'DaleStudy' 요청은 403 Forbidden 반환.
contents: read: PR 정보 조회issues: write: 댓글 작성 및 삭제pull_requests: read & write: PR 목록/상태 조회, 리뷰 생성, 병합 수행organization_projects: read: Projects v2의 Week 필드 접근 (GraphQL API)
절대 커밋 금지: .env, .dev.vars, *.pem, *.key
wrangler secret put APP_ID # GitHub App ID
wrangler secret put PRIVATE_KEY # GitHub App Private Key (PEM)APP_ID=123456
PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
wrangler deploy- Production: https://github.dalestudy.com
- Worker.dev: https://dalestudy.daleseo.workers.dev
자세한 배포 가이드는 DEPLOYMENT.md 참고.
https://github.com/settings/apps/dalestudy
- Webhook URL:
https://github.dalestudy.com/webhooks - Webhook Secret: (선택사항) 안전한 랜덤 문자열
- ✅ Active: 체크
Repository permissions:
- Contents: Read
- Issues: Read & write (issue_comment 이벤트용)
- Metadata: Read
- Pull requests: Read & write
- Projects: Read & write (Projects V2)
Subscribe to events:
- ☑️ Issue comments (
issue_comment- AI 코드 리뷰) - ☑️ Projects v2 item (
projects_v2_item- Week 체크) - ☑️ Pull requests (
pull_request- Week 체크)
# OpenAI API Key (AI 코드 리뷰용, 필수)
wrangler secret put OPENAI_API_KEY
# Webhook Secret (선택사항)
wrangler secret put WEBHOOK_SECRET저장소에 App이 설치되어 있는지 확인:
https://github.com/apps/dalestudy/installations
DaleStudy organization에 설치되어 있어야 하며, leetcode-study 저장소 접근 권한 필요
전체 PR을 한 번에 검사하고 싶을 때:
curl -X POST https://github.dalestudy.com/check-weeks \
-H "Content-Type: application/json" \
-d '{"repo_owner": "DaleStudy", "repo_name": "leetcode-study"}'- ❌ Node.js 모듈 사용 불가 (crypto, buffer 등)
- ✅ Web 표준 API만 사용 (fetch, Web Crypto API)
- ❌ npm 패키지 대부분 호환 안 됨 (@octokit/app 등)
- ✅ 순수 JavaScript + Web APIs로 구현
새로운 자동화 기능을 추가할 때 다음 단계를 따르세요:
- 엔드포인트 추가:
index.js의fetch()함수에 새로운 pathname 라우팅 추가 - 핸들러 함수 작성: 비즈니스 로직을 별도 함수로 분리 (예:
handleCheckAllPrs) - GitHub App 권한 확인: 필요한 권한이 있는지 확인하고 없으면 추가
- 문서 업데이트: AGENTS.md, README.md에 새 기능 문서화
- 테스트: 로컬(
wrangler dev)에서 먼저 테스트 후 배포
-
Octokit 사용 금지
- Cloudflare Workers에서 작동하지 않음
- fetch API 직접 사용
-
Private Key 처리
- PKCS8 또는 PKCS1 형식 지원
- Web Crypto API로 import
-
GraphQL 쿼리 주의
- GraphQL 쿼리에서 변수를 문자열 템플릿으로 직접 삽입 (GraphQL 변수 문법 사용 안 함)
- 입력값 검증이 중요 (SQL Injection 스타일 취약점 방지)
-
에러 핸들링
- Worker는 에러 발생 시 500 반환
- 로그는
wrangler tail로 확인
-
CORS 헤더
- 모든 응답에 CORS 헤더 포함 (
Access-Control-Allow-Origin: *)
- 모든 응답에 CORS 헤더 포함 (
-
코드 재사용
- GitHub 인증 로직 (
generateGitHubAppToken,createJWT등)은 모든 기능에서 공통으로 사용 - 새 기능 추가 시 기존 유틸리티 함수 활용
- GitHub 인증 로직 (