심화확장성

확장성: 저장소와 팀이 늘어날 때

이 과정의 도구는 저장소 하나, 업무 6건, PM 한 명을 기준으로 만들었다. 업무가 500건, 저장소가 10개, 팀이 4개로 늘면 같은 명령이 API 호출 한도에 걸리거나, 스냅숏 파일이 커지거나, 저장소마다 같은 이슈 번호가 생겨 사례가 섞인다. 이 페이지는 규모가 커질 때 바뀌는 부분과 그대로 쓰는 부분을 나눈다.

규모별 운영

규모업무와 Project기록 수집분석
팀 1개, 저장소 1개 (이 과정)저장소 이슈, 사용자 소유 ProjectPM이 스크립트를 실행한다. 스냅숏만 Actions가 찍는다키트 스크립트
팀 여러 개, 저장소 여러 개저장소마다 이슈, 조직 소유 Project 하나에 여러 저장소의 항목저장소별로 event-log.sh를 돌려 합친다. 업무 키 접두어를 팀마다 다르게 둔다키트 스크립트, PM4Py
조직 전체팀별 Project, 조직 공통 필드와 이슈 유형GitHub App이나 웹훅으로 사건을 받아 저장한다프로세스 마이닝 도구, 데이터 저장소

규모가 바뀌어도 바뀌지 않는 것은 기록 규칙이다. 업무 키가 있는 제목, 예·아니오로 확인하는 완료 조건, 닫는 키워드가 있는 PR, 양식을 지킨 결정 기록이 있어야 어느 규모에서든 이벤트 로그가 만들어진다.

API 호출 한도

인증 방식REST APIGraphQL API
개인 토큰, gh auth login시간당 5,000회시간당 5,000점
Actions의 GITHUB_TOKEN저장소당 시간당 1,000회저장소당 시간당 1,000점
GitHub App 설치 토큰시간당 5,000회부터, 저장소·사용자 수에 따라 12,500회까지-

이와 별도로 동시 요청 100개, REST 분당 900점, GraphQL 분당 2,000점의 보조 한도가 있다. 남은 한도는 아래 명령으로 확인한다.

gh api rate_limit --jq '.resources.core, .resources.graphql | "\(.remaining)/\(.limit), 초기화 \(.reset | todate)"'
스크립트호출 수업무 500건일 때
event-log.sh이슈 목록 1 + 업무마다 타임라인 1(사건 100개마다 1) + PR 목록REST 약 500회
branch-report.sh브랜치 100개마다 GraphQL 1브랜치 수에 따른다
discussion-digest.sh댓글 목록(100개마다 1) + 토론 목록 1 + 기간 안 토론마다 1 + PR 목록 1기간에 따른다
wiki-sync.sh마일스톤 1 + 댓글 목록(100개마다 1) + 토론 1댓글 수에 따른다

event-log.sh를 날마다 전체로 돌리면 업무 수만큼 호출이 늘어난다. 업무가 수백 건을 넘으면 --since로 최근에 갱신된 업무만 다시 읽고, 마일스톤이나 달 단위로 파일을 나눠 pm-data 브랜치에 저장한다. 나눈 파일은 첫 줄(머리글)만 한 번 남기고 합친다.

{ head -1 pm-lab/logs/2026-10.csv; for f in pm-lab/logs/*.csv; do tail -n +2 "$f"; done; } > pm-lab/event-log-all.csv

기록 보관

  • 저장소 이벤트 API는 최근 90일, 최대 300건만 돌려준다. 오래 남겨야 하는 기록은 이슈 타임라인처럼 사라지지 않는 곳에서 읽거나, 날마다 수집해 저장한다.
  • Project 스냅숏은 항목 수에 비례해 커진다. 항목 하나를 1KB로 잡으면 항목 1,000개 × 평일 250일은 한 해 약 250MB다. Git은 비슷한 파일을 차이(delta)로 압축해 저장하지만, GitHub는 저장소를 1GB 아래, 적어도 5GB 아래로 유지하라고 권한다. 키트의 워크플로는 이슈 본문을 빼고 저장한다. 더 줄이려면 키와 Status만 남긴다.
  • 마일스톤 마감일과 Project 필드 값은 현재 값만 남는다. 바꾼 이력은 결정 기록과 스냅숏이 대신한다.
jq -c '[.items[] | {n: .content.number, s: .status}]' snapshots/2026-11-11.json

여러 저장소와 사례 ID

저장소가 둘 이상이면 이슈 번호 #3이 저장소마다 있다. event-log.sh는 제목 앞의 업무 키([LP-03])를 사례 ID로 쓰고, 키가 없을 때만 #번호를 쓴다. 팀마다 다른 접두어(LP-, PAY-, OPS-)를 쓰면 로그를 합쳐도 사례가 섞이지 않는다. 한 업무가 여러 저장소의 PR로 끝나는 경우에는 업무 하나를 사례로 삼는 로그가 그 관계를 다 담지 못한다. 업무, PR, 리뷰를 각각 객체로 두는 객체 중심 이벤트 로그(OCEL)가 이런 경우를 다룬다.

자동화

항목제약조치
예약 실행 시각정각 무렵에는 밀리거나 빠질 수 있다정각을 피하고, gh run list로 빠진 날을 확인한다
예약 실행 정지공개 저장소는 60일 동안 활동이 없으면 예약 실행이 꺼진다gh workflow enable으로 다시 켠다
Project 읽기 권한GITHUB_TOKEN은 사용자나 조직 소유 Project를 읽지 못한다개인 토큰이나 GitHub App 토큰을 비밀값으로 넣는다. 토큰에 만료일을 둔다
Status 변경을 실시간으로 받기스냅숏은 하루 단위다조직 소유 Project는 projects_v2_item 웹훅으로 항목 변경을 받을 수 있다. 받는 서버가 필요하다

분석 도구로 넘기기

event-log.csv는 대부분의 프로세스 마이닝 도구가 읽는 형식이다. 표준 형식 XES가 필요하면 PM4Py로 바꾼다.

import pandas as pd
import pm4py

df = pd.read_csv("pm-lab/event-log.csv", keep_default_na=False)
df["timestamp"] = pd.to_datetime(df["timestamp"])
log = pm4py.format_dataframe(df, case_id="case_id", activity_key="activity", timestamp_key="timestamp")
pm4py.write_xes(log, "pm-lab/event-log.xes")

로그를 팀 밖으로 보낼 때는 사람 아이디가 든 resource 열을 뺀다.

cut -d, -f1-3,5 pm-lab/event-log.csv > pm-lab/event-log-anon.csv

마치며...

규모가 커지면 바뀌는 것은 호출 횟수, 저장 위치, 사례 ID를 정하는 방법이고, 분석의 순서(기록 → 이벤트 로그 → 발견 · 적합성 검사 · 대기 시간)는 그대로다. 어느 규모에서든 먼저 정할 것은 수집 주기와 보관 위치, 그리고 사람 단위 분석을 하지 않는다는 팀의 합의다.