[이전 편: 급여명세서 발송 자동화 완성기 ↑]
급여명세서 자동 발송을 완성한 후, 가장 번거로운 업무가 남아있었습니다.
"각 매장 담당자들한테 변동사항 물어보고, 정리해서 노무사한테 보내기"
매달 25일이면 시작되는 이 루틴:
📧 각 매장에 "이번 달 변동사항 있나요?" 메일
📱 답장 안 오면 카톡으로 재촉
📝 제각각 형식으로 온 답장들 해석하기
📊 엑셀에 정리해서 노무사 전달
왜 이게 어려웠냐면
담당자들이 보내는 답장이 이런 식이거든요:
"이미 종로점 파트타이머 신봉주 총20일+추가근무45분"
"최현규 연장근무 총 29.5시간 ( 1.5계산 ) 택시비 30,900원"
"이미 연남점 휴일근무 6월3일 정윤조"
"남구로 특이사항 없음"
자유롭게 써주니까 고마운데, 이걸 일일이 정리하는 게 귀찮은 일이죠.
물론 핵심은 담당자의 퇴사지만...
그래서 이것도 자동화했습니다
사용한 도구:
n8n (워크플로우 엔진)
Notion (데이터베이스)
Claude MCP (설계 도우미)
Basic LLM Chain (자연어 → 구조화 데이터)
워크플로우:
매월 25일 10시 → 점장/팀장들에게 자동 메일 발송
↓
자유 형식 이메일 회신 수집
↓
Basic LLM Chain으로 텍스트 파싱해서 구조화
↓
매장별로 자동 그룹핑 → Notion DB 저장
↓
28일 17시 → HTML 리포트 생성해서 노무사 전달
Basic LLM Chain을 선택한 이유
지난 스터디에서 khai님이 보여준 Basic LLM Chain을 적용해봤습니다.
해야 할 일이 명확했거든요:
Input: 자유 형식 텍스트
Output: JSON 구조화 데이터
처리 과정: 단순하고 명료함
굳이 복잡한 AI Agent로 처리 시간을 오래 걸리게 할 필요 없이, 간단한 Chain 하나로 충분했습니다.
System Message Prompt 설계
가장 중요했던 건 정확한 System Message 작성이었습니다:
당신은 근무 시간 관리 전문가입니다. 복잡한 이메일에서 근무 내역을 JSON으로 추출하는 것이 임무입니다.
응답은 반드시 다음 형식의 JSON만 반환하세요:
{\"workRecords\": [{\"employee\": \"직원명\", \"workType\": \"근무유형\", \"hours\": 시간, \"days\": 일수, \"details\": \"상세내용\", \"store\": \"매장명\"}]}
추출 규칙:
1. 직원명 추출: 신봉주, 최현규, 전윤지, 이사랑, 원아연, 노현종, 정윤조 등
2. 매장명 추출: 종로점, 홍대점, 연남점, 남구로점 등
3. 근무 유형 분류:
- 파트타이머 → 파트타이머 추가 근무
- 연장근무, 추가근무 → 추가 근무
- 휴일근무 → 휴일 근무
- 기타수당, 택시비, 식대 → 기타 특이사항
4. 시간/일수 추출: 29.5시간, 20일, 8시간 등
5. 상세내용: 원본 텍스트 요약
예시 입력: '이미 종로점 파트타이머 신봉주 총20일+추가근무45분'
예시 출력: {\"employee\": \"신봉주\", \"workType\": \"파트타이머 추가 근무\", \"days\": 20, \"hours\": 0.75, \"details\": \"총20일+추가근무45분\", \"store\": \"종로점\"}
모든 필드는 문자열 또는 숫자여야 합니다. null, undefined 절대 금지!
결과 비교
처음 시도했을 때:
{
"workRecords": [
{
"employee": undefined,
"workType": undefined,
"details": "20일 - undefined"
}
]
}
직원명도 매장명도 다 undefined...
System Message 개선 후:
{
"workRecords": [
{
"employee": "신봉주",
"workType": "파트타이머 추가 근무",
"hours": 0.75,
"days": 20,
"details": "총20일+추가근무45분",
"store": "종로점"
},
{
"employee": "최현규",
"workType": "추가 근무",
"hours": 29.5,
"details": "연장근무 총 29.5시간 택시비 30,900원",
"store": "매장 미확인"
}
]
}
13명의 복잡한 데이터를 13개 레코드로 완벽 분리 성공!
중간에 만난 기술적 문제들
1. JSON 파싱 에러 LLM이 생성한 JSON에 이스케이프 문자가 들어가서 오류 발생
// 해결: 이스케이프 문자 제거
content = content.replace(/\\\"/g, '"');
2. Gmail 노드 검색 옵션 search operation이 없어서 헤맸는데 getMany 안에 search 옵션이 있었습니다.
3. Notion DB 저장 시 속성 타입 오류 People 타입에 텍스트 넣어서 에러 → Rich Text로 변경해서 해결
노무사용 리포트도 브랜딩 적용
회사 CI 가이드에 맞춰서 전문적인 HTML 리포트를 만들었습니다.
브랜딩 요소:
색상: Deep Brown (#3D2914) 계열
폰트: Noto Sans KR
로고: "IMI COFFEE" 강조
카드형 레이아웃, 그라데이션 효과
최종 리포트 형태:
IMI COFFEE
2025년 7월 급여 변동사항 리포트
📅 보고 기간: 2025년 7월
📊 총 데이터 수: 4개
📧 담당자: 이미커피 관리팀
1. 종로점 근무 내역 (1건)
담당자: 종로점 담당자
[종로점] 근무 내역:
• 신봉주: 0.75시간20일 - 총20일+추가근무45분
2. 연남점 근무 내역 (2건)
담당자: 연남점 담당자
[연남점] 근무 내역:
• 정윤조: 8시간0일 - 6월3일 ( 8시간 기타수당 0.5 계산)
• 정윤조: 8시간0일 - 6월 6일 ( 8시간 기타수당 0.5 계산)
최종 완성된 자동화
이제 사람이 할 일:
25일: 메일 확인 (자동 발송됨)
28일: 리포트 확인 (자동 생성됨)
기존 vs 현재:
기존: 매월 3-4시간 수작업
현재: 월 10분 확인만
느낀 점
System Message 설계가 핵심이었습니다. 예외 케이스 들을 하나씩 정의하고 명확한 규칙을 만드니까 13명 데이터를 완벽하게 분리해냈습니다.
복잡해 보이는 업무도 단계별로 쪼개면 다 됩니다.
물론 중간에 JSON 파싱 에러로 머리 아팠지만, 결국 차근차근 해결했습니다.
드디어 완성
A. 급여 변동사항 자동 수집 ✅
B. 급여명세서 자동 발송 ✅
이제 진짜로 급여 업무 완전 자동화 완성입니다.
다음 달부터는 거의 아무것도 안 해도 알아서 돌아가는 시스템이 갖춰졌습니다.
별걸 다 하는 요즘이지만, 이런 작은 자동화가 쌓이고 쌓이면 분명 큰 변화가 될 거라고 생각합니다.
그냥… 또 해봤다는 기록입니다. ☕