n8n Form Trigger + Wait 노드 — 사람의 승인이 필요한 자동화

n8n Form Trigger + Wait 노드 — 사람의 승인이 필요한 자동화

"AI가 100점짜리 이메일 초안을 작성했다. 그런데 그냥 보내도 될까?" — 결국 사람의 최종 확인이 필요한 순간이 온다. 이것이 Human-in-the-Loop다.

Human-in-the-Loop란?

자동화 흐름 중간에 사람의 판단이나 승인을 삽입하는 패턴이다.

[자동 처리] → [PAUSE: 사람의 승인 대기] → [승인되면 실행]
                    ↑
              (이메일/Slack으로 승인 요청)

적합한 케이스

케이스 이유
AI 생성 이메일 발송 부정확한 내용이 고객에게 가면 안 됨
대규모 데이터 삭제 되돌릴 수 없는 작업
결제/환불 처리 금액 관련 최종 확인
채용 프로세스 인사 담당자 최종 판단
콘텐츠 발행 품질 검수 후 공개

Wait 노드 — 워크플로우 일시 정지

기본 모드

모드 설명
After Time Interval 지정 시간 후 자동 재개 (5분, 1시간, 1일 등)
At Specified Time 특정 날짜/시간에 재개
On Webhook Call 외부 Webhook 호출 시 재개 (승인 패턴)
On Form Submission n8n 폼 제출 시 재개

Webhook 기반 승인 패턴

[처리] → [Slack: 승인 요청 (링크 포함)] → [Wait: Webhook 대기]
                                                    │
                                            (승인자가 링크 클릭)
                                                    ↓
                                            [승인 후 처리 계속]

Wait 노드의 Resume URL이 핵심이다:

{{ $execution.resumeUrl }}
→ https://n8n.example.com/webhook/resume/exec_abc123

이 URL을 승인자에게 전달하고, 승인자가 이 URL을 호출하면 워크플로우가 재개된다.

승인/거부 분기

승인 URL과 거부 URL을 각각 만들어 분기:

승인 URL: {{ $execution.resumeUrl }}?action=approve
거부 URL: {{ $execution.resumeUrl }}?action=reject

Wait 노드 이후:

[IF: $json.action === "approve"]
  true → [실행]
  false → [취소 알림]

Form Trigger — 커스텀 입력 폼

n8n은 코드 없이 입력 폼을 생성할 수 있다.

Form Trigger 필드 설정

필드 타입 설명
Text 한 줄 텍스트 입력
Textarea 여러 줄 텍스트
Number 숫자
Date 날짜 선택
Dropdown 드롭다운 선택
File 파일 업로드

폼 예시: 휴가 신청

Form Title: "휴가 신청서"
Fields:
  - 이름 (Text, Required)
  - 부서 (Dropdown: [개발팀, 마케팅, 영업, 인사])
  - 휴가 시작일 (Date, Required)
  - 휴가 종료일 (Date, Required)
  - 사유 (Textarea)
  - 유형 (Dropdown: [연차, 반차, 병가, 경조])

Form URL: https://n8n.example.com/form/vacation-request


실전: AI 이메일 초안 → 관리자 승인 → 자동 발송

[Webhook: 고객 문의 접수]
  → [AI Agent: 답변 초안 생성]
  → [Slack: 관리자에게 승인 요청 (초안 + 승인/거부 버튼)]
  → [Wait: Webhook 대기]
  → [IF: 승인?]
     true → [Gmail: 이메일 발송] → [Slack: "✅ 발송 완료"]
     false → [Slack: "❌ 발송 취소됨"]

Slack 승인 요청 메시지

[
  {
    "type": "header",
    "text": { "type": "plain_text", "text": "📧 이메일 발송 승인 요청" }
  },
  {
    "type": "section",
    "text": { "type": "mrkdwn", "text": "*받는 사람:* {{ $json.to }}\n*제목:* {{ $json.subject }}" }
  },
  {
    "type": "section",
    "text": { "type": "mrkdwn", "text": "```{{ $json.draft }}```" }
  },
  {
    "type": "actions",
    "elements": [
      {
        "type": "button",
        "text": { "type": "plain_text", "text": "✅ 승인" },
        "style": "primary",
        "url": "{{ $execution.resumeUrl }}?action=approve"
      },
      {
        "type": "button",
        "text": { "type": "plain_text", "text": "❌ 거부" },
        "style": "danger",
        "url": "{{ $execution.resumeUrl }}?action=reject"
      }
    ]
  }
]

Wait 노드 타임아웃

승인자가 응답하지 않으면 워크플로우가 영원히 대기한다. 타임아웃을 설정하자.

Wait → Limit Wait Time: ON
  → Resume After: 24 hours

24시간 내 응답이 없으면 자동으로 재개되고, 타임아웃 분기 처리:

[Wait] → [IF: 타임아웃?]
  true → [Slack: "⏰ 승인 시간 초과. 자동 취소됨."]
  false → [정상 승인/거부 처리]

📝 정리

  • [x] Human-in-the-Loop: 자동화 중간에 사람의 판단/승인을 삽입하는 패턴
  • [x] Wait 노드: Time/Webhook/Form 방식으로 워크플로우 일시 정지
  • [x] Resume URL: $execution.resumeUrl로 승인 링크 생성
  • [x] Form Trigger: 코드 없이 커스텀 입력 폼 생성
  • [x] 타임아웃: Limit Wait Time으로 무한 대기 방지

다음 편 예고

27편: Credential 관리와 보안 — 프로덕션 환경 구축

API 키, OAuth 토큰, DB 비밀번호... 프로덕션 환경에서 Credential을 안전하게 관리하는 모범 사례.