- Error Trigger: 임베드 형식으로 변경, 실패 노드/실행 ID 포함, fallback 처리 - Switch error: footer를 "봇 요약 처리 에러"로 구분 - 에러 유형 비교 테이블 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8.9 KiB
8.9 KiB
n8n 워크플로우 구성 가이드
워크플로우 개요
이 워크플로우는 2개의 YouTube 채널(머니코믹스, 슈카월드)의 새 영상을 YouTube Data API v3로 감지하고, FastAPI /api/news/summarize 엔드포인트를 호출하여 요약한 뒤, 응답 결과에 따라 Discord로 요약 또는 에러 알림을 전송하는 자동화 파이프라인입니다.
전체 흐름:
Schedule Trigger (매 정시)
├→ HTTP Request (머니코믹스 playlistItems) → Edit Fields (channel_name: 머니코믹스)
└→ HTTP Request (슈카월드 playlistItems) → Edit Fields (channel_name: 슈카월드)
↓
Merge (Append)
↓
Code (새 영상만 필터링)
↓
HTTP Request (POST /api/news/summarize)
↓
Switch (status 분기)
├→ ok → Discord 요약 전송
├→ skipped → No Operation
└→ error → Discord 에러 알림
사전 준비: YouTube Data API 키 발급
- Google Cloud Console → 프로젝트 생성/선택
- "YouTube Data API v3" 검색 → 사용 설정
- 사용자 인증 정보 → API 키 생성
- (권장) 키 제한 설정:
- API 제한: YouTube Data API v3만 허용
- 애플리케이션 제한: IP 주소 → n8n 서버 IP
- 일일 쿼터: 10,000 units (
playlistItems.list는 1 unit/요청 → 2채널 × 24회 = 48 units/일)
노드 구성 상세
1. Schedule Trigger
| 설정 항목 | 값 |
|---|---|
| Type | Schedule Trigger |
| Rule | Every Hour |
| Minute | 0 |
2. YouTube API — playlistItems (채널별 각 1개)
| 설정 항목 | 값 |
|---|---|
| Type | HTTP Request |
| Method | GET |
| URL | https://www.googleapis.com/youtube/v3/playlistItems |
| Send Query Parameters | ON |
| Specify Query Parameters | Using Individual Fields |
Query Parameters (Add Parameter로 추가):
| 파라미터 | 값 |
|---|---|
part |
snippet |
playlistId |
채널 업로드 목록 ID (아래 참고) |
maxResults |
5 |
key |
YouTube Data API v3 키 |
채널별 playlistId (채널 ID의 UC → UU로 변환):
| 채널 | 채널 ID | playlistId (업로드 목록) |
|---|---|---|
| 머니코믹스 | UCJo6G1u0e_-wS-JQn3T-zEw |
UUJo6G1u0e_-wS-JQn3T-zEw |
| 슈카월드 | UCsJ6RuBiTVWRX156FVbeaGg |
UUsJ6RuBiTVWRX156FVbeaGg |
응답 예시:
{
"items": [
{
"snippet": {
"publishedAt": "2026-03-25T06:00:00Z",
"title": "영상 제목",
"resourceId": { "videoId": "abc123" }
}
}
]
}
3. Edit Fields (채널별 각 1개)
| 설정 항목 | 값 |
|---|---|
| Type | Edit Fields (Set) |
| Mode | Manual Mapping |
| Fields to Set | channel_name (String) = 머니코믹스 또는 슈카월드 |
| Include Other Input Fields | All (기존 데이터 유지) |
4. Merge
| 설정 항목 | 값 |
|---|---|
| Type | Merge |
| Mode | Append |
5. Code (새 영상 필터링)
| 설정 항목 | 값 |
|---|---|
| Type | Code |
| Language | JavaScript |
| Mode | Run Once for All Items |
최근 1시간 이내 발행된 영상만 필터링합니다:
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000);
return $input.all().filter(item => {
const items = item.json.items || [];
return items.some(i => new Date(i.snippet.publishedAt) > oneHourAgo);
}).flatMap(item => {
const channelName = item.json.channel_name || '';
return (item.json.items || [])
.filter(i => new Date(i.snippet.publishedAt) > oneHourAgo)
.map(i => ({
json: {
video_url: `https://www.youtube.com/watch?v=${i.snippet.resourceId.videoId}`,
title: i.snippet.title,
channel_name: channelName,
}
}));
});
참고: Schedule Trigger가 매 정시 실행되므로, 1시간 이내 영상을 필터링하면 새 영상만 처리됩니다. 영상이 없으면 빈 배열이 반환되어 이후 노드가 실행되지 않습니다.
6. HTTP Request (요약 API 호출)
| 설정 항목 | 값 |
|---|---|
| Type | HTTP Request |
| Method | POST |
| URL | https://<서버주소>/api/news/summarize |
| Send Body | ON |
| Body Content Type | JSON |
| Specify Body | Using JSON |
Body (Expression 모드):
{
"video_url": "{{ $json.video_url }}",
"title": "{{ $json.title }}"
}
Headers (API_SECRET 사용 시):
| 헤더 | 값 |
|---|---|
X-Api-Secret |
설정한 시크릿 값 |
Options:
- Always Output Data: ON (에러 시에도 다음 노드로 전달)
주의: 영상 제목에 큰따옴표(
")가 포함된 경우 JSON이 깨질 수 있습니다. 반드시 Expression 모드를 사용하세요.
7. Switch (응답 분기)
| 설정 항목 | 값 |
|---|---|
| Type | Switch |
| Mode | Rules |
| Data Type | String |
| Value | {{ $json.status }} |
Rules:
| Rule | Operation | Value | Output |
|---|---|---|---|
| Rule 1 | Equal | ok |
→ Discord 요약 전송 |
| Rule 2 | Equal | skipped |
→ No Operation (무시) |
| Rule 3 | Equal | error |
→ Discord 에러 알림 |
8. Discord 요약 전송 (status=ok)
| 설정 항목 | 값 |
|---|---|
| Type | HTTP Request |
| Method | POST |
| URL | Discord 웹훅 URL |
| Send Body | ON |
| Body Content Type | JSON |
| Specify Body | Using JSON |
Body (Expression 모드):
{
"embeds": [{
"title": "📰 [{{ $json.channel_name }}] {{ $json.title }}",
"url": "{{ $json.video_url }}",
"description": "{{ $json.summary }}",
"color": 2829105,
"thumbnail": {
"url": "https://img.youtube.com/vi/{{ $json.video_url.split('v=')[1] }}/hqdefault.jpg"
},
"footer": {
"text": "YouTube 뉴스 요약 봇 • {{ $json.channel_name }}"
}
}]
}
9. Discord 에러 알림 (status=error)
| 설정 항목 | 값 |
|---|---|
| Type | HTTP Request |
| Method | POST |
| URL | Discord 웹훅 URL |
| Send Body | ON |
| Body Content Type | JSON |
| Specify Body | Using JSON |
Body (Expression 모드):
{
"embeds": [{
"title": "❌ [{{ $json.channel_name }}] 뉴스 요약 실패",
"color": 15548997,
"fields": [
{ "name": "영상 제목", "value": "{{ $json.title }}", "inline": false },
{ "name": "영상 URL", "value": "{{ $json.video_url }}", "inline": false },
{ "name": "에러 타입", "value": "`{{ $json.error_type }}`", "inline": true },
{ "name": "에러 내용", "value": "```\n{{ $json.error_message }}\n```", "inline": false }
],
"footer": {
"text": "봇 요약 처리 에러 — FastAPI 응답"
}
}]
}
에러 처리
에러 알림은 두 종류로 구분됩니다:
| 구분 | 발생 위치 | 원인 예시 | 알림 제목 |
|---|---|---|---|
| 워크플로우 에러 | n8n 자체 | API 연결 불가, 노드 설정 오류, YouTube API 실패 | ⚠️ n8n 워크플로우 에러 |
| 요약 처리 에러 | FastAPI 봇 | 자막 없음, 쿠키 만료, Claude API 오류 | ❌ [채널명] 뉴스 요약 실패 |
Error Trigger 워크플로우 (n8n 워크플로우 에러)
메인 워크플로우 자체가 실패하는 경우를 대비해 별도 에러 워크플로우를 만들 수 있습니다.
- 새 워크플로우 생성 → Error Trigger 노드 추가
- HTTP Request 노드로 Discord Webhook 호출:
| 설정 항목 | 값 |
|---|---|
| Type | HTTP Request |
| Method | POST |
| URL | Discord 웹훅 URL |
| Send Body | ON |
| Body Content Type | JSON |
| Specify Body | Using JSON |
Body (Expression 모드):
{
"embeds": [{
"title": "⚠️ n8n 워크플로우 에러",
"color": 16753920,
"description": "n8n 워크플로우 실행 중 에러가 발생했습니다. 봇 요약 처리가 아닌 **워크플로우 자체 문제**입니다.",
"fields": [
{ "name": "워크플로우", "value": "{{ $json.workflow.name }}", "inline": true },
{ "name": "실패 노드", "value": "{{ $json.execution.lastNodeExecuted }}", "inline": true },
{ "name": "에러 내용", "value": "```\n{{ $json.execution.error.message || '상세 내용 없음' }}\n```", "inline": false },
{ "name": "실행 ID", "value": "`{{ $json.execution.id }}`", "inline": true }
],
"footer": {
"text": "n8n Error Trigger — 워크플로우 에러"
}
}]
}
- 메인 워크플로우의 Settings → Error Workflow에서 이 에러 워크플로우를 지정
참고:
$json.execution.error.message가 빈 값일 수 있으므로|| '상세 내용 없음'으로 fallback 처리합니다.