n8n 이란 무엇인가: GitHub PR → Notion 개발일지 + Slack 알림 만들기
개발하다 보면 손으로 반복하는 잔무가 쌓인다.
- PR merge 되면 개발일지에 뭘 했는지 정리
- 팀 슬랙에 "PR #123 merge 됨" 알리기
- CI 실패하면 알림
- 매일 아침 Notion 데일리 페이지 새로 만들기
각각 작은 일이지만 매번 신경 쓰기 귀찮고, 잊어버리면 히스토리가 사라진다. 이런 걸 코드 한 줄 없이 노드 연결로 자동화하는 게 n8n이다.
이번 글에서는 n8n이 뭐고, 다른 자동화 도구랑 뭐가 다른지, 그리고 실제로 "GitHub PR merge → Claude로 개발일지 초안 → Notion + Slack" 파이프라인을 어떻게 만들었는지를 정리한다.
n8n이란
n8n은 오픈소스 워크플로우 자동화 도구다. 한 문장으로 요약하면:
"여러 SaaS를 노드로 연결해서 이벤트에 반응하는 파이프라인을 만드는 도구"
Zapier / Make(Integromat)와 같은 카테고리인데, 차별점은 세 가지다.
1. 오픈소스 + 셀프호스팅 가능 → 데이터가 내 서버 밖으로 안 나감
2. 노드 안에서 JS/파이썬 코드 직접 작성 가능 → SaaS 조합만으로 안 되는 로직 처리
3. HTTP Request 노드로 아무 REST API나 붙일 수 있음 → 지원 안 되는 서비스도 문제없음
Zapier는 편하지만 실행당 과금 + 데이터가 외부로 나감. n8n은 도커로 띄우면 호스팅 비용 외에 실행 비용이 0에 수렴한다. 개인/스타트업이 쓰기에 좋다.
핵심 개념 3개만 잡으면 된다
n8n을 처음 켜면 노드가 300개 넘어서 압도된다. 근데 실제로 알아야 할 개념은 셋뿐이다.
1. Workflow
노드들을 연결한 하나의 파이프라인. 하나의 목적을 가진다.
예: "PR merge 되면 → 개발일지 만들고 → Slack에 알리기" = 워크플로우 1개
2. Node
파이프라인의 각 단계. 세 종류를 알면 90% 커버 된다.
Trigger Node : 파이프라인 시작점 (외부 이벤트 감지)
- Webhook, GitHub Trigger, Schedule, Cron 등
Action Node : 각 SaaS/서비스에 대한 동작
- Notion, Slack, GitHub, Google Sheets, ...
- 내부적으론 각 API를 감싼 래퍼
HTTP Request : 지원 안 되는 API 붙일 때 쓰는 만능 노드
- 사실상 curl 그 자체
3. Credential
API 호출용 인증 정보. 한 번 등록하면 여러 노드에서 재사용 가능.
- OAuth2 방식 : Google, Slack native 노드 등
- API Key : Anthropic, OpenAI 등
- Header Auth : 만능 (HTTP Request 노드에서 아무 서비스나)
실전: PR merge → Notion 개발일지 + Slack 알림
내가 만든 워크플로우다. 최종 그래프는 이렇게 생겼다.
각 단계가 하는 일을 한 줄씩.
GitHub Trigger : leesangeok/Tick 리포지토리의 PR 이벤트 웹훅 수신
IF: merged & valid : merged=true, base=main 인 것만 통과
Get commits/files : 해당 PR의 커밋/파일 목록 GitHub API 로 조회
Merge : 두 브랜치 결과를 하나의 아이템으로 합침
Build LLM prompt : "다음 커밋과 파일로 개발일지 초안 만들어줘" 프롬프트 조립
Claude : Anthropic API 호출로 마크다운 초안 생성
MD → Notion blocks : 마크다운을 Notion block 배열로 변환
search today's page : 오늘 날짜 페이지가 있는지 Notion 에서 검색
IF: page exists : 있으면 append, 없으면 새 페이지 생성
Slack: notify : #dev-log 채널로 "PR merge 됨" 알림 전송
왜 HTTP Request 노드로 다 짰나
n8n에는 Slack, Notion, Anthropic native 노드가 다 있는데도, 나는 대부분을 HTTP Request + Header Auth 조합으로 짰다. 이유:
1. native 노드는 편하지만 최신 API 스펙에 밀림
- Slack chat.postMessage 의 새 파라미터, Notion 최신 블록 타입 등
2. Header Auth 한 번 만들면 어떤 API 든 붙일 수 있음
3. 디버깅할 때 curl 로 그대로 재현 가능
Header Auth credential 만들기는 30초면 된다.
Name : Authorization
Value : Bearer xoxb-... (Slack Bot Token)
Bearer ntn_... (Notion Integration Token)
(Anthropic 은 x-api-key: sk-ant-... 로 Name/Value 다름)
이 credential 을 HTTP Request 노드의 Authentication 드롭다운에서 선택하면 끝.
Slack chat.postMessage 노드 설정 예시
내가 실제로 쓴 설정.
Method : POST
URL : https://slack.com/api/chat.postMessage
Authentication : Generic Credential Type → Header Auth
Credential : Slack (Header Auth)
Send Headers : ON
Name : Content-Type
Value : application/json; charset=utf-8
Send Body : ON
Body Content Type : JSON
JSON:
{
"channel": "#dev-log",
"text": "{{ $json.text_summary }}",
"blocks": [ ... ]
}
여기서 놓치면 안 되는 포인트 하나.
Content-Type: application/json; charset=utf-8헤더는 반드시 명시해야 한다.
Slack chat.postMessage는 JSON body 를 보낼 때 이 헤더가 없으면 body 를
form-urlencoded 로 파싱하려 든다. 그러다 token= form 필드가 없어서
invalid_auth 를 뱉는다. 토큰이 정상이어도.
이거 모르면 하루 종일 토큰만 의심하다가 시간을 태우게 된다. (→ 이 삽질 케이스는 시리즈 다음 글에 따로 정리)
워크플로우 활성화 후 확인 포인트
Publish 를 켜기 전에 아래를 꼭 확인한다.
1. Executions 탭에서 최근 실행 히스토리 확인 가능
- 성공/실패, 각 노드별 input/output 을 그대로 볼 수 있음
2. 실패한 노드는 오른쪽 상단 "Retry" 버튼으로 그 시점부터 재실행 가능
3. Trigger 는 Publish 상태에서만 실제 이벤트 수신
- Edit 모드에서는 "Listen for test event" 로 1회성 수신만 됨
특히 3번을 모르면 "왜 웹훅이 안 와?" 하고 몇십 분 날린다. 편집 중에는 트리거가 죽어 있는 게 정상이다.
정리
n8n의 관점을 한 줄로 요약하면:
"내 API 콜을 노드 그래프로 눈에 보이게 관리한다"
코드로 짜도 되는 걸 굳이 n8n으로 짜는 이유는:
1. 실행 히스토리, 재시도, 로그가 UI 로 그냥 됨 → 관측성이 무료
2. Trigger + Cron + Wait 같은 흐름 제어가 코드보다 압도적으로 편함
3. 다음번에 바꿀 때 코드 다시 안 만지고 노드 하나만 붙이면 됨
반대로 로직이 복잡해지고 상태 관리가 필요해지면 그때는 백엔드로 옮기는 게 맞다. "저비용으로 흐름을 눈에 보이게 만든다"가 n8n 을 쓰는 기준이다.
다음 글에서는 이 워크플로우를 만들다 실제로 하루를 태운 invalid_auth
디버깅 케이스 스터디를 정리한다.