RAG를 만들기 전에, 컨플루언스부터 통째로 꺼냈습니다.

columns
박건우
박건우Backend Developer
2026. 07. 10.

안녕하세요. 제로백데브 백엔드 개발자 박건우입니다.

이번 글에서는 사내 RAG의 문서 소스를 확보하기 위해, 컨플루언스에 흩어진 문서 370여 개를 통째로 빼내는 백업 툴을 만든 경험을 공유합니다.

지식은 있는데, 꺼낼 수가 없었다.

사내에 RAG 기반 문서 검색을 만들려고 했습니다. 우리 회사 문서를 LLM에게 물어보면 답해주는 구조인데, RAG의 성패는 모델이 아니라 넣어줄 문서의 품질에서 갈립니다. 그리고 우리 회사의 지식 대부분은 컨플루언스에 있었습니다. RAG 1차 소스로 잡은 범위만 해도 11개 스페이스, 페이지 약 370개. 회의록과 설계 문서에 첨부된 엑셀·PDF·이미지까지 치면 내려받아야 할 파일 수는 그 몇 배였습니다.

이걸 손으로 하나하나 내려받느니 바이브코딩으로 전부 받아주는 툴을 만드는 게 빠르겠다 싶었습니다. 단순히 받기만 하면 되는 것도 아니었습니다. RAG는 문서를 파싱 → 청킹 → 임베딩이라는 전처리를 거치는데, 컨플루언스 원본을 그대로 가져오면 이 전처리에서 처리할 게 너무 많습니다. 그래서 백업 단계에서 세 가지를 미리 챙기기로 했습니다.

  • 매크로가 렌더링된 깨끗한 본문 — 컨플루언스 내부 저장 원본은 <ac:structured-macro> 같은 전용 태그 덩어리입니다. API의 export_view 포맷으로 렌더링된 HTML을 받았습니다.

  • 첨부 원본 — 엑셀·PDF·이미지들이 본문만큼 중요한 문서가 많았습니다.

  • 원래 폴더 계층 구조 — 문서의 위치는 청킹할 때 메타데이터로 붙는 정보라, 검색 품질에 그대로 영향을 줍니다.

페이지 받고 저장하면 끝은 아니었다.

백업 툴 자체는 바이브코딩으로 정말 금방 나왔습니다. 다만 AI가 코드를 빨리 짜주는 것과 별개로, 뭘 어떻게 받아야 온전한지는 직접 부딪혀서 알아내야 했습니다. 기억에 남는 것만 추리면 이렇습니다.

  • 폴더가 API에 안 딸려옵니다. 페이지 목록 API는 페이지만 주고, 스페이스의 폴더 목록을 주는 엔드포인트는 없습니다. 페이지들의 부모 중 폴더인 id를 모아 GET /folders/{id}로 하나씩 역추적해서 트리를 재구성했습니다.

  • 응답 속 URL의 기준(base)이 세 종류입니다. API 호출, 첨부 다운로드 링크, 페이징 커서가 각각 다른 base를 요구합니다. base별로 join 헬퍼를 분리하고서야 404와 경로 중복이 사라졌습니다.

  • 이미지에 인증이 걸려 있습니다. drawio처럼 매크로가 렌더링한 이미지는 첨부 목록에 잡히지 않아서, 백업 세션의 인증 헤더를 물려받아 직접 내려받았습니다.

  • 형제 페이지가 서로의 첨부를 덮어씁니다. 회의록_v1.0.docx처럼 겹치는 파일명이 공유 폴더에서 조용히 유실되고 있었습니다. 첨부를 페이지 전용 폴더로 분리해 해결했습니다.

사내 문서를 통째로 긁는 스크립트라 안전장치에도 신경 썼습니다. 토큰은 실행할 때만 입력받아 메모리에서만 쓰고, 읽기 전용(GET)만 호출하고, 문서 제목을 폴더명으로 쓸 때 금지 문자와 경로 탈출을 걸러냈습니다.

결과: 폴더 구조 그대로, 첨부까지 온전하게

11개 스페이스, 약 370개 페이지가 원래 폴더 구조 그대로, 첨부까지 온전하게 내려왔습니다. 한 번 실행으로 끝나고, 중간에 멈춰도 이어받습니다. 이제 이 폴더가 다음 단계인 RAG의 문서 소스가 됩니다. RAG의 8할은 모델이 아니라 데이터 파이프라인입니다. 화려한 건 임베딩과 LLM이지만, 실제로 품이 드는 건 쓸 만한 문서를 온전히 확보하는 일이었습니다. 다음 편에서는 이렇게 확보한 문서를 실제로 RAG에 태우는 이야기로 찾아뵙겠습니다.