AI로 사내 회의실 예약봇 만들기 — n8n부터 Chrome 확장까지
매번 Wiki 페이지를 찾아 표를 병합하는 번거로움을 없애기 위해 만든 회의실 예약봇 개발기
데모
주요 기능
- 팀 전체가 사용할 수 있어야 한다
- Wiki 계정(아이디/비밀번호)으로 로그인
- 채팅 한 줄로 예약할 수 있는 간편한 UI
- 예약자명 자동 처리
- 예약 셀에 “부서명 (@사용자이름)” 형식으로 기록
- 로그인한 계정으로 Confluence
@멘션자동 삽입
- 자연어 예약 / 조회
- “금요일 오후 2시 4회의실 예약해줘”처럼 말하면 됨
- 예약뿐 아니라 “비어있어?”로 가용 여부 조회 가능
- 요일 생략 시 오늘 날짜 자동 인식
- “2시 4회의실” 입력만으로 오늘 날짜에 예약
- 주말 입력 시 다음 주 월요일로 자동 처리
- 중복 예약 방지 및 만석 감지
- 이미 예약된 시간대에 요청 시 충돌 안내
- 해당 요일 전체 만석일 경우 별도 안내
- 소요 시간 지정
- 기본 1시간 (2슬롯 rowspan), “30분”, “2시간” 등 직접 지정 가능
사용한 Wiki API
| API | 용도 |
|---|---|
GET /rest/api/content | 이번 주 예약 페이지 검색 (title, spaceKey 파라미터) |
GET /rest/api/user?username= | 로그인 사용자 검증 및 Confluence userKey 조회 |
PUT /rest/api/content/{pageId} | 예약 완료 후 페이지 HTML 업데이트 |
왜 만들었는가
사내에서는 직원들이 회의실을 잡을 때 Atlassian Confluence Wiki를 사용하여 예약을 하고 있습니다.
회의실을 잡을 때마다 이번 주 Wiki 페이지를 찾아야 하고, 1시간을 예약한다면 표를 병합해야 한다는 번거로움이 있었습니다. 팀 업무상 회의가 많다 보니 이러한 문제를 해결하기 위해 사내 회의실 예약봇을 AI를 통해 만들기로 하였습니다.
과정
처음에는 n8n을 활용해 챗봇을 만들려 했습니다. n8n을 통한 Wiki 페이지 생성과 자동화 효율성이 사내에서 입소문을 타면서, 팀 전체가 n8n에 큰 관심을 갖게 되었기 때문입니다. 이러한 분위기 속에서 첫 번째 프로토타입 개발도 자연스럽게 n8n으로 시작되었습니다.
하지만 n8n을 셀프 호스팅으로 운영하다 보니, 비개발자 팀원들이 이를 활용하려면 각자 환경을 구축하거나 복잡한 설정 과정을 거쳐야 하는 번거로움이 있었습니다. 도구가 오히려 업무의 짐이 되는 상황이었죠.
고민 끝에 결정한 해답은 크롬 확장 프로그램이었습니다. 우리 팀의 업무 환경을 관찰해 보니, 개발자와 비개발자 할 것 없이 업무의 90% 이상이 웹 브라우저 안에서 이루어지고 있었습니다. WEHAGO 메신저, 사내 Wiki, 각종 서비스까지 모두 크롬 탭 안에 있었죠.
별도의 설치나 학습 없이, 항상 켜져 있는 브라우저에서 아이콘 클릭 한 번으로 예약을 끝내는 경험. Wiki 계정만 있다면 누구나 즉시 사용할 수 있는 이 구조야말로 우리 팀의 업무 동선에 가장 자연스럽게 녹아드는 자동화라고 생각합니다.
1. n8n 챗봇 버전 (Wiki 회의실 예약 챗봇)
첫 번째로 만든 건 순수 n8n 워크플로우 기반의 채팅봇입니다. n8n 내장 Chat Trigger UI로 대화하면 Gemini AI가 자연어를 파싱하고, Confluence REST API로 Wiki 페이지를 조회·수정합니다.
n8n 워크플로우 구조
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
[Chat Trigger] ↓ [Gemini - 자연어 파싱] → { room, day, time, action, meeting_name, duration_slots } ↓ [Code - 이번 주 날짜 계산] ↓ [HTTP - Wiki 페이지 검색] ↓ [IF - 페이지 존재 여부] ├─ 없음 → "이번 주 예약 페이지를 찾을 수 없습니다." └─ 있음 → [HTTP - 로그인 사용자 userKey 조회] ↓ [Code - 테이블 파싱 & 가용성 확인] ↓ [IF - book / check 분기] ├─ check → 가용 여부 메시지 반환 └─ book → [IF - 예약 가능 여부] ├─ 불가 → 충돌 안내 └─ 가능 → [Code - HTML rowspan 수정] ↓ [HTTP - Wiki PUT 업데이트] ↓ [Code - 완료 안내]
핵심은 Wiki 테이블의 HTML을 직접 파싱하고 rowspan을 수동 계산하는 부분입니다. Confluence는 1시간 예약 시 첫 번째 셀에 rowspan="2"를 삽입하고 다음 행의 해당 <td>를 제거하는 방식으로 병합합니다. 단순히 셀을 교체하는 것이 아니라 rowspan 추적 맵을 유지하며 가상 컬럼 인덱스를 계산해야 했습니다.
2. 크롬 확장 프로그램 버전
n8n 챗봇은 잘 동작했지만 팀원들이 n8n을 설치해야 쓸 수 있다는 문제가 있었습니다. 크롬 확장은 폴더 하나만 배포하면 되기 때문에 팀 전체가 설치 없이 바로 사용할 수 있습니다.
2.1 n8n Webhook 연동 크롬 확장 (Wiki 회의실 예약 - Webhook)
역할을 명확히 나눈 구조입니다. 로그인과 인증은 크롬 확장이 직접 처리하고, 자연어 파싱과 Wiki API 작업은 n8n Webhook이 담당합니다.
동작 흐름:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[크롬 확장]
↓ 팝업 열림
[내부망 체크] — wiki.사내.com:8080 HEAD 요청 (5초 타임아웃)
├─ 실패 → "사내 내부망 사용자만 이용 가능합니다."
└─ 성공 →
[세션 확인]
├─ 세션 없음 → [로그인 화면]
│ ↓ ID / PW 입력
│ Confluence API: GET /rest/api/user?username=
│ → userKey, displayName 수신
│ → authHeader(Base64 인코딩)를 세션에 저장 (평문 PW 미저장)
└─ 세션 있음 → [채팅 화면]
↓ 채팅 입력
n8n Webhook POST /webhook/room-booking
body: { chatInput, authHeader, userKey, defaultTitle }
로그인 시 btoa(id:pw)로 만든 authHeader만 세션에 보관하고, n8n에 전달할 때도 이 값을 그대로 사용합니다. n8n은 받은 authHeader로 Confluence API를 직접 호출하기 때문에 n8n 서버에 계정 정보를 따로 등록할 필요가 없습니다.
n8n 워크플로우 구조 (Webhook 수신 후):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
[Webhook Trigger] — chatInput, authHeader, userKey, defaultTitle 수신 ↓ [Gemini - 자연어 파싱] → { room, day, time, action, meeting_name, duration_slots } ↓ [HTTP - Wiki 페이지 검색] ← Authorization: {authHeader} ↓ [Code - 테이블 파싱 & 가용성 확인] ↓ [IF - book / check 분기] ├─ check → 가용 여부 메시지 반환 └─ book → [Code - HTML rowspan 수정] ← userKey로 @멘션 생성 ↓ [HTTP - Wiki PUT 업데이트] ← Authorization: {authHeader} ↓ [Respond to Webhook] — 완료 메시지 반환
챗봇 버전 대비 개선 사항:
| 항목 | 챗봇 버전 | Webhook 버전 |
|---|---|---|
| 인증 | n8n에 하드코딩된 크레덴셜 | 로그인 사용자의 authHeader를 동적으로 전달 |
| 멘션 | 고정 계정 | 로그인 사용자의 Confluence userKey |
| 회의명 | CoreDevCell 고정 | 설정 화면에서 팀별 기본값 지정 가능 |
| 만석 감지 | 미처리 | 해당 요일 전체 슬롯 순회 후 안내 |
| n8n 설치 | 각자 설치 필요 | 팀 공용 서버 1대만 있으면 됨 |
설정 화면에서 n8n 서버 URL과 기본 회의명을 지정할 수 있어, 팀 서버로 전환할 때는 URL만 바꾸면 된다고 생각했습니다.
2.2 n8n 없이 Wiki API만으로 동작하는 최종 버전
Webhook 연동 버전도 잘 동작했지만 팀 서버를 만들어야 하는 비용과 팀 서버가 없는 환경에서는 n8n을 띄워야 한다는 의존성이 남아 있었습니다. 그래서 n8n 로직 전체를 Chrome Extension JavaScript로 이식한 완전 독립 버전을 만들었습니다.
변경 포인트:
parser.js— Gemini AI 대신 규칙 기반 자연어 파싱으로 교체 요일·시간·회의실·회의명·소요시간을 정규식으로 추출하며, AI 호출 없이도 대부분의 입력을 처리booking.js— n8n HTTP/Code 노드를 함수로 이식fetchPage()→checkAndBook()→ Confluence PUT 흐름을 직접 구현popup.js— UI만 담당, n8n fetch 로직 제거
동작 흐름:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
사용자 입력
↓
parser.js: parseIntent(text) ← 규칙 기반 파싱
↓ intent 객체
booking.js: checkAndBook(...)
├─ Confluence GET — 이번 주 페이지 조회
├─ HTML 파싱 — rowspan 테이블 파싱
├─ action=check → 가용 여부 반환
└─ action=book
├─ 만석 체크
├─ 충돌 체크
└─ HTML 수정 → Confluence PUT
↓
popup.js: appendMessage('bot', message)
마치며
처음에는 n8n의 워크플로우 기능으로 빠르게 프로토타입을 만들었고, 그 과정에서 Confluence HTML 파싱과 rowspan 처리라는 까다로운 문제를 풀었습니다. 그 로직을 검증한 뒤 Chrome Extension으로 이식하면서 팀원 누구나 설치 없이 사용할 수 있는 형태로 발전시켜 공유했습니다.
AI를 활용한 것은 설계와 구현의 속도였습니다. Confluence Wiki HTML 구조 분석, rowspan 알고리즘 설계, Chrome Extension 보안 설계까지 AI로 프로그래밍하면서 혼자서라면 시도도 못했던 작업을 하루 이틀 만에 완성할 수 있었습니다.




