Skip to content

finditem/QnA-Bot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

confluence-slack-bot

Confluence 문서를 자동으로 수집해 Supabase에 저장하고, Slack에서 들어온 질문에 대해 저장된 문서를 근거로 답변하는 Q&A 봇입니다.

해결하려는 문제

팀 문서와 회의록이 Confluence에 쌓여 있어도, 필요한 내용을 매번 직접 검색하고 여러 페이지를 읽어야 합니다. 이 프로젝트는 Confluence 문서를 주기적으로 동기화하고, Slack에서 자연어로 질문하면 관련 문서를 찾아 요약 답변과 참고 링크를 돌려주는 흐름을 제공합니다.

기술 스택

  • Runtime: Node.js, TypeScript
  • Database: Supabase Postgres
  • Serverless: Supabase Edge Functions
  • Document source: Atlassian Confluence API
  • AI: OpenAI Responses API
  • Chat interface: Slack Bot, Slack Events API
  • Local tooling: tsx, Supabase CLI

전체 흐름

Confluence
  -> sync-confluence Edge Function
  -> 문서 정규화 및 chunk 생성
  -> Supabase Postgres 저장

Slack mention
  -> slack-events Edge Function
  -> Slack signature 검증
  -> Supabase에서 관련 chunk 검색
  -> OpenAI로 근거 기반 답변 생성
  -> Slack thread에 답변 전송

데이터 수집 및 저장

sync-confluence 함수는 접근 가능한 Confluence space를 조회하고 각 page의 본문을 가져옵니다. CONFLUENCE_SPACE_KEYS가 비어 있으면 전체 space를 수집하고, 값이 있으면 지정한 space만 수집합니다.

수집된 page는 텍스트로 정규화한 뒤 hash를 계산해 confluence_pages에 upsert합니다. 이후 답변 검색에 적합하도록 본문을 chunk로 나누고 document_chunks에 저장합니다. Slack 질문과 답변 결과는 qa_logs에 남겨 운영 중 문제를 추적할 수 있게 했습니다.

주요 테이블:

  • confluence_pages: Confluence page 원문, 제목, URL, space, version, sync metadata
  • document_chunks: 검색과 답변 생성을 위한 page 단위 chunk
  • qa_logs: Slack 질문, 답변, 참고 chunk, 처리 상태, 에러 메시지
  • bot_channel_guides: 채널별 봇 사용 가이드 전송 기록

qa_logs는 후속 질문 처리를 위해 Slack thread metadata도 저장합니다.

  • slack_thread_ts: 같은 thread의 질문/답변을 묶기 위한 timestamp
  • slack_message_ts: 개별 Slack 메시지 timestamp

bot_channel_guides는 봇이 채널에 초대됐을 때 사용 가이드를 한 번만 보내기 위한 중복 방지 테이블입니다.

질문 답변 방식

Slack에서 봇을 멘션하면 slack-events 함수가 이벤트를 받습니다. 함수는 Slack signature를 검증한 뒤 질문 텍스트에서 봇 멘션을 제거하고, Supabase의 검색 함수로 관련 chunk를 찾습니다.

검색된 chunk만 OpenAI 프롬프트에 포함합니다. 답변은 문서 내용 안에서만 생성하도록 제한하고, Slack에서 읽기 좋게 섹션 제목과 blockquote bullet 형식으로 정리합니다. 질문은 룰 기반 intent로 분류해 답변 기준을 다르게 적용합니다.

Slack 전송 시에는 생성된 mrkdwn 답변을 섹션 제목 기준으로 파싱해 Block Kit context, divider, section block으로 재구성합니다. text는 fallback으로 함께 보내므로 알림, 검색, 구형 클라이언트에서도 내용을 확인할 수 있습니다.

스레드 안에서 다시 봇을 멘션하면 같은 thread의 최근 Q&A 로그를 함께 참고합니다. 이전 답변은 후속 질문의 맥락으로만 사용하고, 사실 판단은 항상 검색된 Confluence 문서를 우선합니다.

봇이 채널에 처음 초대되면 member_joined_channel 이벤트를 받아 사용 가이드 메시지를 자동으로 전송합니다. 가이드는 채널별로 한 번만 전송하며, 실제 Confluence 문서 기반 질문 예시, thread 후속 질문, 민감값 마스킹 정책을 안내합니다.

초대 가이드 질문 예시:

  • @qabot 07월 6일 미팅에서 나온 주요 논의 정리해줘
  • @qabot 배포 설정 파일에서 보안상 주의할 점 알려줘
  • @qabot 컴포넌트 가이드 기준으로 UI 작업할 때 주의사항 알려줘
  • @qabot AWS Savings Plans 내용 요약해줘

질문 유형별 답변 섹션:

  • meeting_summary: 요약, 주요 논의, 담당자별 작업, 이후 작업 공유, 참고 문서
  • security: 결론, 위험 요소, 권장 조치, 참고 문서
  • how_to: 목적, 절차, 주의사항, 참고 문서
  • owner_or_schedule: 확인된 담당자, 확인된 일정, 문서에 없는 정보, 참고 문서
  • general: 답변, 근거, 참고 문서

검색 키워드도 질문 유형에 따라 보강합니다. 예를 들어 보안 질문은 .env, 환경변수, secret, token, password 같은 키워드를 함께 검색하고, 회의록 질문은 미팅, 회의록, 요약, 논의, 작업을 함께 검색합니다.

보안 처리

Confluence 문서에 .env, API key, token, password, secret 같은 민감값이 포함될 수 있으므로 아래 단계에서 마스킹합니다.

  • 수집 단계: sync-confluence가 원문을 저장하기 전에 민감값을 [REDACTED]로 치환
  • 답변 단계: OpenAI 응답을 Slack에 보내기 전에 다시 한 번 [REDACTED]로 치환
  • prompt 단계: 민감값 원문을 출력하지 말고 변수명과 조치 사항만 안내하도록 제한

마스킹은 값만 숨기고 변수명은 남깁니다. 예를 들어 OPENAI_API_KEY=...OPENAI_API_KEY=[REDACTED] 형태로 저장/응답됩니다.

자동 동기화

Supabase pg_cronpg_net으로 sync-confluence Edge Function을 매일 실행합니다.

Job: sync-confluence-daily
Schedule: 0 15 * * *
Timezone: UTC 기준, KST 매일 00:00
Timeout: timeout_milliseconds:=120000

Supabase Dashboard의 Cron UI는 timeout을 짧게 덮어쓸 수 있으므로, cron job을 수정할 때는 SQL Editor에서 cron.jobcommand 값을 확인합니다.

Edge Functions

  • sync-confluence: Confluence 문서 수집, 정규화, chunk 저장
  • slack-events: Slack 이벤트 수신, 질문 검색, AI 답변 생성, Slack 응답 전송

현재 배포 URL:

https://vqtdrlqqlrakzrkiqpoy.supabase.co/functions/v1/slack-events

환경 변수

Supabase Edge Functions는 Supabase 기본 env 외에 아래 값을 사용합니다.

CONFLUENCE_BASE_URL=
CONFLUENCE_EMAIL=
CONFLUENCE_API_TOKEN=
CONFLUENCE_SPACE_KEYS=

OPENAI_API_KEY=
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_MODEL=

SLACK_BOT_TOKEN=
SLACK_BOT_USER_ID=
SLACK_SIGNING_SECRET=

SYNC_BATCH_SIZE=25
MAX_CONTEXT_CHARS=12000

CONFLUENCE_SPACE_KEYS, SYNC_BATCH_SIZE, MAX_CONTEXT_CHARS는 선택 값입니다. SLACK_BOT_USER_ID는 Slack auth.test 응답의 user_id 값이며, 봇 초대 이벤트에서 봇 자신이 채널에 들어온 경우만 가이드 메시지를 보내는 데 사용합니다.

로컬 명령어

npm run typecheck
npm run build
npm run test:intent
npm run sync:confluence
npm run test:search -- "질문 내용"
npm run test:qa -- "질문 내용"

질문 유형별 로컬 테스트 예시:

npm run test:qa -- "프론트엔드 최근 미팅 내용 정리해줘"
npm run test:qa -- ".env 관련 보안 문제 어떻게 처리해야 해?"
npm run test:qa -- "Slack 앱 설정 방법 알려줘"
npm run test:qa -- "이 작업 담당자가 누구야? 일정은 언제까지야?"
npm run test:qa -- "검색 품질 개선 내용 알려줘"

문서

About

Confluence 문서를 근거로 Slack에서 들어온 질문에 대해 답변하는 QnA 봇입니다.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors