Skip to content

Commit a34945d

Browse files
committed
docs: add portfolio case study for AI dev harness pipeline
1 parent 5b633d9 commit a34945d

1 file changed

Lines changed: 136 additions & 0 deletions

File tree

docs/portfolio-entry.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# Portfolio entry — Scrolloop AI 개발 파이프라인
2+
3+
zaewc.site에 붙이기 위한 짧은 형식과, 클릭해서 들어갈 수 있는 deep dive 두 가지 포함.
4+
5+
---
6+
7+
## 짧은 버전 (site의 사이드 프로젝트 항목에 그대로)
8+
9+
### Scrolloop — Multi-Agent AI 개발 자동화 파이프라인
10+
11+
자체 OSS 라이브러리에 GitHub 이슈 라벨링만으로 AI(Gemini)가 plan 생성 → 코드 수정 → 자체 평가까지 자동화하는 파이프라인을 구축. n8n과 GitHub Actions를 분리해 trust boundary를 명시적으로 설계.
12+
13+
- **n8n (오케스트레이션) + GitHub Actions (격리 실행) 분리 설계** — n8n은 webhook 수신·검증·dispatch만, 코드 수정은 격리된 Actions 컨테이너에서. `workflow_dispatch`가 두 시스템의 신뢰 경계.
14+
- **3-agent harness (Planner / Generator / Evaluator)** — 각 단계가 단일 책임, 산출물은 `.harness/<issue>/plan.md`·`review.md`로 PR diff에 commit해서 AI 결정 과정 전부 traceable.
15+
- **다층 보안**`X-Hub-Signature-256` 검증, author `OWNER`/`MEMBER`/`COLLABORATOR` 화이트리스트, 봇 재귀 가드, secret 파일 패턴 차단, 워크플로우에서 `NPM_TOKEN` / `id-token` 격리.
16+
- **MTU mismatch root-cause 디버깅** — 학교 NAT(1400) + Tailscale(1280) + Docker bridge(1500) 충돌로 큰 POST 패킷이 silent drop, n8n → GitHub API 호출이 "connection timed out"으로 발현. Docker bridge MTU 1280 고정으로 해결, 워크플로우에 WHY 주석으로 보존.
17+
- **Free tier API 한도 우회 설계** — gemini-2.5-flash / lite / 2.0-flash-lite 3-model CLI fallback + REST API 직접 호출 fallback. composite GitHub Action(`.github/actions/gemini`)으로 plan·implement·evaluate 3 job이 동일 로직 재사용.
18+
19+
링크: [github.com/zaewc/scrolloop](https://github.com/zaewc/scrolloop) · 워크플로우 [ai-dev.yml](https://github.com/zaewc/scrolloop/blob/develop/.github/workflows/ai-dev.yml) · 설계 문서 [docs/ai-pipeline.md](https://github.com/zaewc/scrolloop/blob/develop/docs/ai-pipeline.md)
20+
21+
스택: n8n · GitHub Actions · Gemini API · Tailscale Funnel · Docker Compose · TypeScript
22+
23+
---
24+
25+
## 깊이 들어가는 버전 (블로그/케이스 스터디 페이지용)
26+
27+
### 문제 정의
28+
29+
scrolloop는 직접 만든 가상 스크롤 OSS 라이브러리(React/Vue/Svelte 등 어댑터 6종). 새 기능·버그 처리 속도를 올리고 싶지만 모든 PR에 사람의 시간이 필요했음.
30+
31+
"GitHub 이슈에 라벨만 달면 AI가 plan + 코드 + 검증까지 끝낸 PR을 자동으로 만들어두면, 사람은 리뷰만 하면 된다"는 가설로 시작.
32+
33+
다만 **AI가 직접 코드를 수정**한다는 건 보안 모델이 복잡해진다. 그래서 단순한 "n8n에 코드 시키기"가 아니라, **trust boundary가 명시적으로 설계된 시스템**이 목표.
34+
35+
### 아키텍처 — 두 시스템의 분리
36+
37+
```
38+
GitHub Event ──▶ n8n (검증 · 분류 · dispatch)
39+
40+
41+
GitHub Actions (격리된 코드 실행)
42+
43+
44+
ai/issue-N branch ──▶ Pull Request → develop
45+
```
46+
47+
| 시스템 | 책임 | 권한 |
48+
| -------------- | ------------------------------------------------------------------------- | ---------------------------------------- |
49+
| n8n | webhook 수신, 라벨 검증, 작성자 권한 확인, prompt 합성, workflow_dispatch | GitHub PAT (PR/issue/actions 쓰기) |
50+
| GitHub Actions | git checkout, AI 호출, 코드 수정, 검증, commit, push, PR 생성 | repo scoped GITHUB_TOKEN, NPM_TOKEN 없음 |
51+
52+
**핵심 원칙**: n8n은 코드 수정 권한 자체가 없음. 오케스트레이션 도구로서 편리하지만 임의 코드 실행 환경으로 신뢰하지 않음. 모든 코드 변경은 ephemeral Actions 컨테이너에서, 격리된 secret 범위로 실행.
53+
54+
### Harness 엔지니어링 — 3-agent 구조
55+
56+
AI 한 번에 "이슈 → PR"을 끝내는 단일 호출은 환각 위험이 크고 결과를 검증하기 어렵다. Planner / Generator / Evaluator로 책임 분리:
57+
58+
| Agent | 역할 | 입력 | 출력 |
59+
| --------- | --------------------------------------------------- | ---------------------- | ----------------------------- |
60+
| Planner | 이슈 분석 → 구체 계획 (코드 수정 금지) | seed prompt | `plan.md` (artifact + commit) |
61+
| Generator | plan 그대로 구현 + 검증 (typecheck/lint/test/build) | `plan.md` | 코드 변경, 검증 로그, PR |
62+
| Evaluator | plan vs diff 비교, verdict | `plan.md` + `git diff` | `review.md` (PR 코멘트) |
63+
64+
각 산출물이 PR diff에 commit되므로 리뷰어가 "AI가 뭘 계획했고, 뭘 했고, 자기 평가는 어땠는지" PR 한 곳에서 추적 가능.
65+
66+
Verdict가 `BLOCKED`이면 워크플로우 자체를 실패시키고, `NEEDS_CHANGES`는 코멘트만 남기고 통과 — 리뷰어가 결정.
67+
68+
### 인프라 deployment
69+
70+
- **n8n 셀프호스팅** — Ubuntu 22.04 + Docker Compose + SQLite 영속화 + 기본 인증
71+
- **Tailscale Funnel로 공개 HTTPS** — 학교 NAT가 80/443 표준 포트를 막아 Let's Encrypt 불가, 도메인 마이그레이션 없이 `*.ts.net`으로 outbound 터널 → GitHub Webhook이 도달 가능한 공개 HTTPS endpoint 확보
72+
- **idempotent setup 스크립트** — Docker 설치, 시크릿 생성(`openssl rand`), 컨테이너 부팅, healthcheck 대기까지 한 줄
73+
74+
### 인상적인 버그 — MTU mismatch
75+
76+
n8n이 GitHub workflow_dispatch에 POST 보낼 때 마다 "connection timed out". 작은 GET (rate_limit 등)은 통과. 일관성 없는 실패 패턴이 의심스러웠음.
77+
78+
원인 추적:
79+
80+
- 호스트 `eth0` MTU **1400** (학교 NAT 환경)
81+
- Docker bridge MTU **1500** (기본값)
82+
- Tailscale `tailscale0` MTU **1280**
83+
- n8n 컨테이너가 1500-byte 프레임으로 응답 → eth0 통과 못 함 → fragmentation 후 drop
84+
85+
수정 한 줄:
86+
87+
```yaml
88+
networks:
89+
default:
90+
driver_opts:
91+
com.docker.network.driver.mtu: "1280"
92+
```
93+
94+
근본 원인 + 수정 의도를 워크플로우에 WHY 주석으로 보존:
95+
96+
```yaml
97+
# MTU pinned to 1280 because (a) the school NAT's eth0 only carries 1400-byte
98+
# frames and (b) Tailscale's tailscale0 interface is 1280. Without this,
99+
# Docker's default 1500-byte bridge fragments large outbound POSTs (e.g.
100+
# n8n -> api.github.com workflow_dispatch) and they get silently dropped...
101+
```
102+
103+
### Free tier API 한도 — fallback 체인 설계
104+
105+
Google AI Studio 무료 티어는 `gemini-2.5-flash` 일일 20 requests. CLI 내부에서 routing/summarization 용도로 같은 모델을 호출하기 때문에 우리가 `--model`로 다른 걸 지정해도 영향받음.
106+
107+
해결: composite action에서 다단계 fallback
108+
109+
1. CLI 시도 (모델 N개 순서대로) — 429 quota → next
110+
2. (옵션) REST API 직접 호출 — CLI의 내부 fallback 회피
111+
112+
`.github/actions/gemini/action.yml`로 분리해서 plan/implement/evaluate 3 job이 같은 로직 재사용.
113+
114+
### 보안 모델
115+
116+
n8n과 Actions 양쪽에 적용되는 정책:
117+
118+
- **fork PR 절대 거부** — secret 노출 방지
119+
- **작성자 화이트리스트**`OWNER` / `MEMBER` / `COLLABORATOR`만 트리거 가능
120+
- **봇 재귀 가드**`[bot]` 작성자 코멘트는 무시 (자기 자신이 만든 코멘트로 다시 트리거되지 않게)
121+
- **시크릿 분리** — n8n credentials store(`N8N_ENCRYPTION_KEY`로 암호화)에만, `.env` 안 둠
122+
- **보호 파일 패턴**`.github/workflows/cd.yml`, `.env*`, `*.pem`, `*.key`, `secrets.yml`, npm 토큰/리소스 등 AI 수정 금지 목록
123+
- **publish 권한 자체 제거** — Actions 워크플로우에 `id-token` 없음, `NPM_TOKEN` env 없음 → AI가 npm 배포 시도 자체 불가
124+
- **자동 머지 금지** — 모든 PR은 사람 검토 후 수동 머지
125+
126+
### 결과
127+
128+
- **GitHub 이슈에 `ai:ready` + `ai:plan|fix|test|docs` + `area:*` 라벨 → 자동 PR 생성** end-to-end 검증 완료
129+
- 운영 비용 **\$0** (모든 컴포넌트 free tier 안에서 동작)
130+
- n8n 워크플로우 3개, GitHub Actions 워크플로우 1개 + composite action 1개
131+
- README/설계 문서 4개 (`docs/ai-pipeline.md`, `docs/ai-dev-prompt-template.md`, `infra/n8n/README.md`, 본 portfolio entry)
132+
- 코드/설계 모두 [public repository](https://github.com/zaewc/scrolloop)에 공개
133+
134+
### 사용 기술
135+
136+
n8n · GitHub Actions · GitHub Webhooks · Gemini API (CLI + REST) · Tailscale Funnel · Docker Compose · Ubuntu · TypeScript · pnpm · turborepo

0 commit comments

Comments
 (0)