Files
aio-01d4-stu/Lecture/80-82-Project/student/02-ENVIRONMENT-AND-SERVICES.md
T

9.8 KiB

환경 · 외부 서비스 · 인증 · 비용

원본 요구는 Slack · Email · Jira · Notion · Database · API 연동을 말합니다. 3일 안에 21명이 모두 실제 회사 계정을 만들고 승인받기는 어렵고, 실제 서비스의 키 · 개인정보가 섞일 위험도 큽니다. 그래서 **같은 역할을 하는 연습용 서비스(데이터 API)**를 기본으로 쓰고, 실제 서비스 연동은 가산으로 둡니다. 설계서에는 "실제 운영이라면 무엇으로 바꾸나"를 함께 적습니다.

1. 환경 (64~79일차와 같음)

항목 값
워크플로우 n8n 2.42.6 (65일차 설치, http://localhost:5678)
LLM OpenAI gpt-4.1-mini, Credential OpenAI (.env) (id openAiCourse0001). Ollama는 쓰지 않습니다
임베딩 OpenAI text-embedding-3-large (같은 Credential, 71일차)
연습용 서비스 데이터 API (http://data-api:8800 · 터미널에서 http://localhost:8800), 단위 프로젝트 판: ~/aio-01d4-stu/Last3Mon/80/data-api
도구 tools/flow.py (check · push · call · test · bench · fault · llm · ops · doctor, 모두 -v)
코드 작성 CLI 코딩 에이전트 (codex · claude · agy), 팀 저장소의 AGENTS.md를 따름 (09-AGENT-WORKING-RULES)
실습 키트 ~/aio-01d4-stu/Last3Mon/80 (공통 시나리오 · 템플릿 · 도구, 80일차 전에 git pull)
팀 VM 팀마다 하나, 인터넷으로 접속 (주소 · 계정은 80일차 1교시 안내). 팀장이 n8n · 데이터 API · Credential을 올리고 배포 · 시연에 씀

첫날 확인

cd ~/aio-01d4-stu && git pull
cd ~/aio-01d4-stu/Last3Mon/65/n8n && docker compose start
cd ~/aio-01d4-stu/Last3Mon/80/data-api && docker compose up -d --force-recreate
cd ~/aio-01d4-stu/Last3Mon/80 && uv run tools/flow.py doctor        # 마지막 줄 ready

팀 안에서 n8n을 어떻게 나누나

각자 노트북의 n8n은 따로입니다. 다른 사람의 n8n에서 내 워크플로우는 보이지 않습니다. 팀이 함께 보는 기준은 팀 VM의 n8n입니다.

방식 하는 법 언제
저장소로 나누기 (기본) 워크플로우 JSON을 팀 저장소에 두고, 각자 git pull → flow.py push로 자기 노트북 n8n에 올려 개발 · 시험 늘
팀 VM에 배포 팀장이 VM에서 기본 브랜치를 git pull → flow.py push → 공통 시나리오 flow.py test 80일차 7교시 첫 배포, 81일차 4 · 7교시
시연 · 발표 산출물 발표 · 리허설 · 최종 발표는 팀 VM에서 80 · 81일차 8교시, 82일차
모듈 나누기 70일차처럼 하위 워크플로우(웹훅 또는 Execute Workflow)로 나눠 사람마다 한 파일 큰 워크플로우

팀 VM 준비 (80일차 3교시, 팀장): 노트북과 같은 순서로 n8n · 데이터 API를 켜고 flow.py doctor가 ready인지 봅니다. OpenAI · 웹훅 Header Auth · 데이터 API 키는 VM n8n의 Credential에만 넣습니다.

팀 VM은 인터넷에서 열립니다. n8n 로그인 비밀번호를 기본값으로 두지 않고, 팀 웹훅에는 Header Auth를 겁니다. VM 주소 · 비밀번호 · 키를 저장소 · 문서 · 발표 자료에 쓰지 않습니다 (팀 헌장 5절에는 "팀장에게 물을 것"으로).

워크플로우 이름 · 웹훅 경로 앞에 팀 이름을 붙입니다 (team1-support, team1-index). 같은 n8n에 여러 팀 것이 올라가도 겹치지 않습니다.

2. 외부 서비스를 무엇으로 대신하나

원본 요구의 서비스 하는 일 연습용 (데이터 API) 실제 운영이라면
Slack (문의 받기) 직원 메시지 수신 팀 Webhook POST /webhook/<팀>-support (본문에 channel, user) Slack Trigger 노드 (OAuth 앱, 이벤트 구독)
Slack · Email (알림) 담당자 · 관리자에게 알림 POST /alerts {"workflow", "node", "message", "severity", ...} → GET /alerts로 확인 Slack 메시지 노드, Send Email (SMTP)
Jira (티켓) 이관 티켓 생성 · 조회 POST /tickets {"key", "title", "requester", "category", "priority"} (같은 key는 중복으로 막음), GET /tickets-created Jira Software 노드 (API Token · OAuth)
Notion (지식 문서) 지식베이스 GET /docs, GET /docs/<name> (규정 문서 8개, 마크다운) + 팀이 더한 문서 Notion 노드, Confluence
Database (기록 · 상태) 실행 기록 · 캐시 · 대기열 POST /logs, /cache/<key>, POST /dlq (실패 대기열) Postgres · MySQL 노드
API (업무 시스템) 접수 건 · 직원 정보 GET /tickets/<id>?requester= (남의 건이면 403), GET /employees/<이름>, GET /faq?q= 사내 API (HTTP Request + Credential)
장애 연습 외부 서비스가 느리거나 멈춤 고장 스위치 flow.py fault faq|tickets slow|error|flaky, flow.py llm down|up 실제로는 일어남

설계서의 "외부 연동 노드" 표에는 연습용과 실제 운영용을 둘 다 적습니다 (인증 방식 · 오류 코드 · 한도가 다르기 때문). 연습용에서 정상 동작을 보이고, 실제 서비스로 바꿀 때 바뀌는 곳을 표시하면 됩니다.

조합 B · C의 어댑터 (81일차 4교시)

입구 · 뒷단 조합(11-TOPIC-GUIDE 7절)에서 A는 위 표의 연습용 그대로라 어댑터가 없습니다. B · C는 바깥 부품을 공통 계약 모양으로 바꾸는 어댑터를 더합니다. 두뇌(본체 워크플로우 <팀>-support)는 바꾸지 않습니다.

조합 입구 어댑터 뒷단 어댑터
B Telegram Trigger로 메시지를 받고, 변환 Code에서 message.text → question, chat.id → user로 바꿔 본체에 넘김. 답은 Telegram 노드로 같은 채팅방에 이관할 때 data-api POST /tickets 대신 Zammad 노드로 티켓 생성, 처리가 끝나면 Zammad 웹훅으로 n8n에 알림
C FastAPI가 웹 화면의 질문을 계약 모양으로 바꿔 n8n 팀 웹훅을 호출 FastAPI가 data-api와 같은 모양의 /tickets · /alerts를 직접 제공 (관리자 화면이 읽음)
  • 순서: A로 공통 시나리오 통과 → 어댑터. 공통 시나리오는 어떤 조합이든 팀 웹훅으로 돌립니다.
  • Telegram Trigger · Zammad 웹훅은 바깥에서 n8n을 불러야 하므로 팀 VM의 n8n에 둡니다 (노트북 n8n은 바깥에서 닿지 않음).
  • 봇 토큰 · Zammad 토큰은 n8n Credential에만, FastAPI의 키는 .env에만 둡니다 (아래 규칙과 같음).
  • 설계서의 "외부 연동 노드" 표 · 연결선 페이로드 표에 어댑터를 한 연결선으로 적습니다 (바깥 모양 → 계약 모양).

실제 서비스를 쓰고 싶은 팀 (가산)

  • 팀 공용 무료 · 연습용 계정만 씁니다 (회사 · 개인 업무 계정 금지).
  • 키 · 토큰은 n8n Credential에만 넣습니다. 워크플로우 JSON · 문서 · 스크린샷 · 저장소에 보이면 안 됩니다. 커밋 전에 tscan staged(73일차).
  • 실제 서비스가 안 되는 날(계정 승인 지연 · 한도)을 대비해 연습용으로도 똑같이 돌게 둡니다 (Switch 하나로 바꿀 수 있게).
  • 시연 전날까지 되지 않으면 연습용으로 시연합니다. 평가에서 불리하지 않습니다.

3. 인증 (원본 요구: OAuth · API Key와 에러 처리)

어디 연습용에서 하는 것 설계서에 쓸 것
팀 Webhook (들어오는 문) Webhook 노드 Authentication = Header Auth, Credential에 팀 키 (요청 머리글 X-Team-Key) 키가 없거나 틀리면 401 (n8n이 돌려줌), 운영은 Slack 서명 검증 · SSO
데이터 API (나가는 호출) 단위 프로젝트 판은 /tickets · /alerts 등 "외부 서비스" 경로에 X-Api-Key를 요구 → HTTP Request의 Header Auth Credential 키가 틀리면 401 → 재시도하지 않고 중단 + 알림
OpenAI 기존 Credential OpenAI (.env) 키 만료 · 한도 초과(429) 때의 처리
실제 서비스 (가산) 해당 노드의 OAuth2 · API Token Credential 토큰 만료 → 재인증 알림
  • 401 · 403은 다시 해도 안 됩니다. 재시도하지 말고 멈추고 알립니다. 429 · 5xx · timeout만 재시도합니다 (06-RELIABILITY-AND-SECURITY 1절).
  • Header Auth 키를 걸면 flow.py call · test도 키를 보내야 합니다: FLOW_WEBHOOK_KEY=<팀 키> uv run tools/flow.py test ... (단위 프로젝트 판 flow.py).

4. 비용과 호출 한도

  • 모든 팀이 강사의 OpenAI 키 하나를 함께 씁니다. 한 팀이 반복 시험을 크게 돌리면 다른 팀도 느려지고 한도에 걸릴 수 있습니다.
  • 시나리오 반복은 3회까지, bench는 -n 5까지를 기본으로 합니다. 더 필요하면 강사에게 말합니다.
  • LLM을 부르기 전에 끝낼 수 있는 것(400 · 차단 · 권한 없음 · 캐시)은 앞에서 끝냅니다 (72 · 73 · 75일차). 결과서에 요청당 LLM 호출 수(agents나 실행 기록)를 적으면 비용 설명이 됩니다.
  • 사용량은 75일차처럼 POST /usage로 남기면 GET /usage/summary로 팀별로 볼 수 있습니다 (가산).

5. 데이터 API를 되돌리기

상황 명령
만든 티켓 · DLQ · 알림 비우기 uv run tools/flow.py ops --reset
고장 스위치 끄기 uv run tools/flow.py fault all ok
LLM 멈춤 연습 되돌리기 uv run tools/flow.py llm up
전부 처음으로 cd ~/aio-01d4-stu/Last3Mon/80/data-api && docker compose up -d --force-recreate

데이터 API는 상태를 메모리에 둡니다. 다시 켜면 만든 티켓 · 로그 · 캐시가 사라집니다. 결과서에 쓸 기록은 runs/의 보고서 파일로 남깁니다.