feat: n8n 을 관측 계층으로 복원 (로컬, 폴링 방식) - #50
Merged
Merged
Conversation
n8n 을 되살리되 역할을 좁힌다. 저장소를 바꾸는 일은 GitHub Actions 가 계속 맡고, n8n 은 GitHub Actions 가 구조적으로 못 하는 일 하나를 담당한다 — 워크플로우마다 알림 스텝을 심지 않고 한 곳에서 모든 실패를 관측하는 것. 이번 회차에서 드러난 장애의 공통점이 "실패가 안 보인다"였다. 릴리스가 두 달간 조용히 깨져 있었고, 훅 두 개는 한 번도 안 돌았고, comment-fix 파이프라인은 넉 달간 한 번도 동작한 적이 없었다. 전부 아무도 몰랐다. ## 웹훅이 아니라 폴링 GitHub 은 실패한 웹훅 전달을 재시도하지 않는다. 로컬 인스턴스가 꺼져 있는 동안 온 웹훅은 영구히 유실된다. 폴링은 다운타임이 알림을 늦추기만 하고 잃지 않는다. outbound 요청만 쓰므로 터널(ngrok)도, 포트 개방도, 재시작마다 바뀌는 URL 도 없다. ## 복원한 것 - ci-failure-alert.json (신규) — 15분마다 실패한 워크플로우 실행을 조회해 새로 실패한 것만 Discord 로 알린다. 이미 알린 실행은 워크플로우 static data 에 마지막 run id 를 보관해 걸러낸다(Data Store 불필요). 첫 실행은 의도적으로 아무것도 알리지 않고 기준선만 세운다 — 그러지 않으면 도입 즉시 과거 실패 전체가 쏟아진다 - ci-failure-alert.test.mjs (신규) — dedup 로직 회귀 테스트 7케이스. 워크플로우 JSON 에서 Code 노드 코드를 직접 꺼내 실행하므로 사본이 어긋나지 않는다. 이 로직은 틀려도 조용히 잘못되므로(과거 전체를 쏟거나 아무것도 안 알림) 고정한다 - docker-compose.yml — 루프백(127.0.0.1)에만 바인딩, N8N_ENCRYPTION_KEY 를 필수로 바꿔 fail-closed(이전 기본값은 changeme123 이었다), 실행 이력 14일 자동 정리, 안 쓰는 NODE_FUNCTION_ALLOW_BUILTIN 제거 - scripts/n8n-setup.sh — 165줄에서 다시 씀. ngrok·크리덴셜 안내를 걷어냈고, 토큰 권한을 읽기 전용(Actions Read + Metadata Read)으로 명시한다 ## 되살리지 않은 것 - planning-pipeline.json — weekly-planning.yml 과 중복이다. 둘 다 켜면 이슈가 두 배로 생긴다. Actions 쪽을 남긴다 - comment-fix-pipeline.json, hermes-fix-callback.json — Hermes 로 보내고 받는 릴레이라 Hermes 없이는 동작하지 않는다 - auto-fix-pipeline.json — 인증 없는 웹훅이 페이로드가 지정한 아무 브랜치에나 커밋했다. 앞서 삭제를 결정한 것이고 그 판단이 유효하다 - .n8n/fly.toml — 호스트가 로컬로 바뀌었다 ## 원칙 n8n 에는 저장소 쓰기 권한을 주지 않는다. 관측 계층이 저장소를 바꿀 수 있으면 관측 계층이 아니다. CLAUDE.md 에 "새 자동화를 어디에 둘지" 판단 기준을 추가했다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Owner
Author
🧪 Test Coverage📦 Bundle Size
⚡ Benchmark🤖 Generated by jump-section AI Pipeline |
CLAUDE.md 는 매 실행마다 읽힌다. 로컬 세션뿐 아니라 claude-code-action 이 도는
CI 에서도 읽으므로 길이가 곧 비용이다. 그런데 분량의 3분의 1이 코드에서 읽을 수
있는 것의 사본이었고, 사본은 이미 원본과 어긋나기 시작했다.
## 뺀 것 (전부 사본이거나 중복)
- 주요 API 목록 25줄 → ScrollManager.ts 를 읽으라는 한 줄. 옵션 5개와 메서드
10개를 손으로 적어둔 것인데, 원본이 바뀌면 조용히 틀린 문서가 된다
- IntersectionObserver Mock 코드 19줄 → ScrollManager.test.ts 의 패턴을 따르라는
한 줄. 실제 목은 이미 그 파일에 있다
- 파일 구조 트리 18줄 → 삭제. 이미 낡아 있었고(.github/workflows, .n8n 누락)
저장소를 보면 알 수 있다. 파생 불가능한 규칙("core 는 단일 파일 유지")만 남겨
아키텍처 절로 옮겼다
- Flywheel 절의 ASCII 다이어그램과 기록 방법 → learnings.md 자체에 이미
"기록 방법" 절로 있다. 원장을 가리키게만 했다
- Hermes/n8n 제거 경위 서술 → 판단 기준(어디에 무엇을 두는지)만 남기고 역사는
원장과 PR 기록에 맡겼다
- 승격 규칙마다 반복되던 `.claude/flywheel/learnings.md #N` 전체 경로 → `(#N)` 로
줄이고 각주 한 줄로 설명
## 고친 것
- 커버리지 요구를 사실에 맞췄다. "새 기능: 80% 이상"이라고만 적혀 있었는데 전체
커버리지는 40%대다. 아무도 만족하지 못하는 수치가 규칙으로 적혀 있으면 문서
전체를 무시하게 만든다. 변경분 기준으로 판단하도록 명시했다
- 빌드 절에 "각 패키지는 자기 tsconfig.json 을 갖는다"를 추가했다. 이번에 릴리스를
두 번 막은 원인이고, 규칙으로 적어두지 않으면 다음에 또 빠진다
## 남긴 것
규칙은 하나도 빼지 않았다. strict mode, any 금지, 포맷팅, 일본어 혼입 금지, 브랜치
전략, AI PR 규칙, 보호 브랜치 가드, 토큰 최소 권한, SSOT, 부분문자열 가드 금지,
동반 작업 3종, 하위 호환성 4항, zero dependency, SSR 4항 — 전부 그대로다.
문서 첫 줄에 "규칙만 담고 코드에서 읽을 수 있는 것은 넣지 않는다"를 명시해 다시
불어나지 않게 했다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
HTTP 노드의 jsonBody 가 551자짜리 한 줄 표현식으로 중첩 객체를 만들고 있었다.
읽을 수도, prettier 로 포맷할 수도, 테스트할 수도 없고, n8n UI 의 작은 입력창에서
고쳐야 했다. 게다가 Code 노드가 head_branch -> branch 로 매핑한 것을 표현식이 다시
branch -> fields[0].value 로 옮겨서 같은 데이터를 두 번 지나갔다.
조립을 Code 노드로 합쳤다. 중간 매핑 단계가 통째로 사라지고, HTTP 노드는
`{{ JSON.stringify($json) }}` 한 줄이 됐다(551자 -> 28자). 노드 수는 그대로 4개다 —
줄인 건 노드가 아니라 읽을 수 없는 표현식이다.
가장 큰 이득은 테스트다. 표현식은 검증할 방법이 없었는데 이제 임베드 형태·짧은 sha·
커밋 첫 줄 120자 절단·head_commit/actor 누락 내성이 전부 회귀 테스트에 들어간다
(7 -> 9케이스).
Code 노드 이름도 "새 실패만 추리기"에서 "새 실패 추리기 + 임베드 조립"로 바꿨다 —
실제로 하는 일이 둘이다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
n8n 의 HTTP 노드는 item 당 한 번 실행된다. 나쁜 머지 하나로 워크플로우 3개가 동시에 깨지면 Discord 알림이 3개 따로 왔다 — 요청도 3번이고, Discord 는 웹훅당 요청 속도도 제한한다. Discord 는 한 메시지에 임베드를 10개까지 받으므로 묶어서 한 번만 보낸다. 10개를 넘으면 잘렸다는 사실을 content 로 함께 알린다 — 조용히 버리면 알림의 의미가 없다. GitHub 조회는 status=failure 를 유지한다. timed_out / cancelled / startup_failure 는 이 저장소 이력 100건에 0건이고, GitHub API 의 status 는 값을 하나만 받아서 늘리려면 요청을 그만큼 더 보내야 한다. 쓰지도 않을 경로를 위해 노드를 늘리지 않는다 — 근거와 재검토 시점을 노드 notes 에 남겼다. 회귀 테스트 9 -> 11케이스 (묶기, 오버플로 표기). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
n8n 을 되살리되 역할을 좁힌다. 저장소를 바꾸는 일은 GitHub Actions 가 계속 맡고,
n8n 은 GitHub Actions 가 구조적으로 못 하는 일 하나를 담당한다 — 워크플로우마다
알림 스텝을 심지 않고 한 곳에서 모든 실패를 관측하는 것.
이번 회차에서 드러난 장애의 공통점이 "실패가 안 보인다"였다. 릴리스가 두 달간
조용히 깨져 있었고, 훅 두 개는 한 번도 안 돌았고, comment-fix 파이프라인은 넉 달간
한 번도 동작한 적이 없었다. 전부 아무도 몰랐다.
웹훅이 아니라 폴링
GitHub 은 실패한 웹훅 전달을 재시도하지 않는다. 로컬 인스턴스가 꺼져 있는 동안 온
웹훅은 영구히 유실된다. 폴링은 다운타임이 알림을 늦추기만 하고 잃지 않는다.
outbound 요청만 쓰므로 터널(ngrok)도, 포트 개방도, 재시작마다 바뀌는 URL 도 없다.
복원한 것
실패한 것만 Discord 로 알린다. 이미 알린 실행은 워크플로우 static data 에 마지막
run id 를 보관해 걸러낸다(Data Store 불필요). 첫 실행은 의도적으로 아무것도 알리지
않고 기준선만 세운다 — 그러지 않으면 도입 즉시 과거 실패 전체가 쏟아진다
JSON 에서 Code 노드 코드를 직접 꺼내 실행하므로 사본이 어긋나지 않는다.
이 로직은 틀려도 조용히 잘못되므로(과거 전체를 쏟거나 아무것도 안 알림) 고정한다
바꿔 fail-closed(이전 기본값은 changeme123 이었다), 실행 이력 14일 자동 정리,
안 쓰는 NODE_FUNCTION_ALLOW_BUILTIN 제거
토큰 권한을 읽기 전용(Actions Read + Metadata Read)으로 명시한다
되살리지 않은 것
생긴다. Actions 쪽을 남긴다
릴레이라 Hermes 없이는 동작하지 않는다
커밋했다. 앞서 삭제를 결정한 것이고 그 판단이 유효하다
원칙
n8n 에는 저장소 쓰기 권한을 주지 않는다. 관측 계층이 저장소를 바꿀 수 있으면 관측
계층이 아니다. CLAUDE.md 에 "새 자동화를 어디에 둘지" 판단 기준을 추가했다.
Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com
검증: dedup 테스트 7/7, compose 구성 유효, 셸 문법, YAML 6개, test 9/9, format:check, n8n JSON 포맷 통과.
아직 실제로 돌려보지 않았습니다.
bash scripts/n8n-setup.sh→.env값 입력 → 다시 실행 → UI 에서 Import + Activate 후 "Execute Workflow" 로 수동 확인이 필요합니다.🤖 Generated with Claude Code