Skip to content

wanteddev/data-bolt

Repository files navigation

Data Bolt

A Slack bot on AWS Lambda with Litestar

아키텍처

Litestar로 구축되고 Lambda Web Adapter를 사용하여 AWS Lambda에 배포되는 서버리스 애플리케이션입니다.

구성 요소:

  • Web Function: Function URL을 통해 HTTP 요청 처리

  • Slack Background Function: 장시간 Slack 작업을 비동기로 처리

  • Single Container Image: 모든 함수가 동일한 Docker 이미지 공유

사전 요구사항

  • uv - Python 패키지 관리자
  • just - 커맨드 러너
  • Docker - 컨테이너 이미지 빌드용
  • 적절한 자격 증명이 구성된 AWS CLI

빠른 시작

1. 의존성 설치

uv sync --frozen

2. 로컬 실행

just serve

http://localhost:8080 에서 앱에 접근할 수 있습니다.

2-1. Slack 없이 로컬 시뮬레이션 (botctl)

botctl은 Slack 이벤트 없이 메시지 처리 흐름을 바로 테스트하는 CLI입니다.

uv sync --frozen
uv run botctl simulate --text "안녕하세요"
uv run botctl simulate --case sql_gen --json
uv run botctl chat
uv run botctl chat --thread-ts demo-thread

schema/glossary RAG 키는 LAAS_API_KEY(env)를 우선 사용하고, 값이 없으면 SSM(/data-bolt/llm/laas-api-key)에서 조회합니다.

PydanticAI 런타임 정책:

  • 대화 히스토리는 Slack thread를 기반으로 매 턴 재구성합니다.
  • 실행 툴은 dry-run -> 승인 필요 여부 -> execute 순서를 강제합니다.
  • 승인 필요 시 Slack 버튼(실행 승인/실행 취소)을 제공하고, 승인 컨텍스트는 DynamoDB TTL에 보관합니다.
  • LLM provider는 LLM_PROVIDER=openai|zai_coding_plan를 지원합니다.
    • openai: OpenAI Responses API
    • zai_coding_plan: z.ai coding plan endpoint + Chat Completions
  • provider 상세값(base_url, model_name, api_key_ref)은 src/data_bolt/tasks/analyst_agent/llm_provider_profiles.yaml에서 관리합니다.
  • 로컬 개발에서는 LLM_API_KEY 환경변수로 키를 직접 주입할 수 있습니다. (LLM_API_KEY가 없으면 api_key_ref SSM 조회)
  • schema/glossary RAG 조회는 LAAS endpoint를 계속 사용합니다.

3. 빌드 및 배포

# (최초 1회 또는 값 변경 시) 시크릿 값을 개별 입력하여 SSM 동기화
just sync-secrets

# (최초 1회) wanted-www 계정의 GCP BigQuery 서비스 계정 키를 현재 계정 SSM으로 복사
AWS_PROFILE=misc AWS_REGION=ap-northeast-2 just sync-gcp-credentials

# 컨테이너 이미지 빌드
just build

# AWS에 배포 (기본 target=prod)
just deploy
# 또는 명시적으로
DEPLOY_TARGET=prod just deploy

# 배포된 URL 확인
just url

이미지 매니페스트 정책:

  • just build는 Lambda 호환성을 위해 buildx --provenance=false --sbom=false --load를 강제합니다.
  • just deploy는 ECR에 푸시된 이미지의 imageManifestMediaType을 검사하고, Lambda 비호환 포맷(OCI index / Docker manifest list)이면 배포를 중단합니다.

사용 가능한 명령어

명령어 설명
just serve 로컬 개발 서버 실행
just build [tag] 컨테이너 이미지 빌드
just deploy [tag] ECR에 푸시하고 스택 배포 (기본 DEPLOY_TARGET=prod)
just url 배포된 Function URL 확인
just invoke-job 예약된 작업 수동 실행
just deployed-version 배포된 이미지 정보 표시
just lock 의존성 lockfile 업데이트
just sync-secrets 시크릿 값을 개별 입력받아 SSM SecureString에 동기화 (기본 DEPLOY_TARGET=prod)
just sync-gcp-credentials wanted-www의 Google 서비스 계정 JSON을 현재 프로필 SSM으로 복사

Jira polling + pi issue-runner 자동화(초안)

아래 파일로 Jira 에픽 기반 자동 이슈 처리를 운영합니다.

  • 오케스트레이터 설정(프로젝트별 정책/게이트/JQL/lane): .agents/automation/orchestrator.toml
  • 상태 파일 템플릿(버전 관리): .agents/automation/runtime/state.template.md
  • 상태 파일(런타임, 자동 생성): .agents/automation/runtime/state.md
  • 상태 DB(런타임, 자동 생성): .agents/automation/runtime/state.sqlite
  • 오케스트레이터 프롬프트: .agents/automation/prompts/jira_orchestrator.md
  • 이슈 실행 프롬프트: .agents/automation/prompts/jira_issue_runner.md
  • lane 실행 프롬프트(예시): .agents/automation/prompts/jira_research_lane_runner.md
  • 오케스트레이터 1회 tick: .agents/automation/scripts/run_orchestrator_tick.sh
  • issue-runner 런치: .agents/automation/scripts/launch_issue_runner.sh
  • lane 공통 런치: .agents/automation/scripts/launch_lane_runner.sh
  • 리파인용 clean 리뷰 worktree 준비(shared 기본): .agents/automation/scripts/prepare_review_worktree.sh
  • 상태 스냅샷 동기화(SQLite): .agents/automation/scripts/orchestrator_state_store.py
  • pi JSON 로그 정돈 필터(jq): .agents/automation/scripts/lib/pi-exec-like.jq

운영 정책:

  • state.md는 런타임 산출물이라 Git에 커밋하지 않습니다.
  • state.sqlitestate.md 스냅샷을 저장하는 런타임 DB이며 Git에 커밋하지 않습니다.
  • 오케스트레이터만 state.md를 갱신합니다. (single-writer)
  • Human gate는 Jira 상태 Start Soon 입니다. 사람이 Start Soon으로 바꾼 이슈만 자동 실행됩니다.
  • 기본 로그 모드는 pi --mode json + jq 필터(.agents/automation/scripts/lib/pi-exec-like.jq) 기반의 정돈된 출력입니다.
  • --json-filter-file <path>로 필터 파일을 교체할 수 있습니다.
  • --json-stream-log 옵션을 주면 raw JSON 스트리밍 로그를 그대로 출력합니다.
  • triage/enrich 단계는 Jira 요청 + 코드베이스 분석(rg, read) 기반으로 수행합니다.
  • 리파인 분석은 clean origin/main 기준 리뷰용 worktree에서 수행합니다. (기본: shared 1개 경로 재사용 + 매 호출 reset/clean)
  • 리파인 피드백은 별도 헤더/라벨 없이 Jira 코멘트로 수집하며, 이슈별 last_feedback_seen_at 워터마크로 신규 코멘트를 판정합니다.
  • 리파인 중 결정 불가 이슈는 HUMAN_REVIEW_REQUIRED + WAITING_FEEDBACK로 남기고, orchestrator-waiting-feedback 라벨을 부여합니다.
  • 사람 피드백으로 해소되면 orchestrator-waiting-feedback 라벨을 제거하고 ENRICHED/READY 판단을 재수행합니다.
  • PR 충돌은 issue-runner가 양쪽 변경 의도를 이해해 자동 해결을 우선 시도합니다.
  • lane은 orchestrator.toml[[lanes]]로 선언하며, 기본값은 enabled=false로 두고 검증 후 활성화합니다.
  • enabled lane은 tick 시작 시 launcher_script/prompt_file 경로가 사전 검증됩니다.
  • lane 실행 산출물은 RUN_ROOT/lane-<LANE_ID>/<RUN_ID>/에 기록되고, state.mdLane Runs/Lane Outputs에 집계됩니다.

예시:

# 오케스트레이터 1회 실행
.agents/automation/scripts/run_orchestrator_tick.sh

# JSON 스트리밍 로그가 필요할 때만 활성화
.agents/automation/scripts/run_orchestrator_tick.sh --json-stream-log

# 단일 이슈 issue-runner 런치
.agents/automation/scripts/launch_issue_runner.sh --issue AI-2699

# 단일 lane runner 런치 (lane enabled=true 필요)
.agents/automation/scripts/launch_lane_runner.sh --lane-id research

프로젝트 구조

data_bolt/
├── src/data_bolt/
│   ├── __init__.py
│   ├── app.py              # Litestar 애플리케이션

│   └── slack/
│       ├── __init__.py
│       ├── app.py          # Slack Bolt 앱 설정
│       ├── handlers.py     # 커맨드 & 이벤트 핸들러
│       └── background.py   # 백그라운드 작업 프로세서
├── deploy/
│   └── targets/
│       └── prod.env        # 배포 타깃 설정(기본: prod, AWS_PROFILE=misc)
├── scripts/
│   └── ...                 # 빌드/배포 스크립트
├── dot_env.example         # 로컬 개발 환경변수 예시 파일 (cp dot_env.example .env)
├── docs/
│   └── guides/
│       └── SLACK_GUIDE.md  # Slack 알림 포맷 및 실패 대응 가이드
├── template.yaml           # CloudFormation 스택
├── Dockerfile
├── pyproject.toml
└── justfile

문서

엔드포인트

엔드포인트 메서드 설명
/ GET 헬스 체크
/healthz GET 로드 밸런서 헬스 체크

| /slack/events | POST | Slack 웹훅 엔드포인트 (커맨드, 이벤트, 인터랙션) | | /slack/background | POST | 백그라운드 작업 프로세서 (내부 사용) |

설정

환경 변수

변수 설명 기본값
DEPLOY_TARGET 배포 타깃 이름 prod
DEPLOY_TARGET_FILE 배포 타깃 설정 파일 경로 deploy/targets/prod.env
AWS_PROFILE AWS CLI 프로필(기본 prod 타깃에서는 misc) 환경/타깃 파일 값

CloudFormation 파라미터

파라미터 설명
ImageUri ECR 이미지 참조
SlackBotTokenSsmPath Slack Bot Token SSM SecureString 경로
SlackSigningSecretSsmPath Slack Signing Secret SSM SecureString 경로
BigqueryGoogleCredentialsSsmPath BigQuery 서비스 계정 JSON SSM SecureString 경로

배포 설정 변경하기

배포 설정은 로컬 .env가 아니라 deploy/targets/<target>.env에서 관리합니다.

기본 타깃은 prod이며, deploy/targets/prod.env에 다음과 같은 값이 있습니다.

  • AWS_PROFILE=misc
  • AWS_REGION=ap-northeast-2
  • STACK_NAME=data-bolt
  • LLM_PROVIDER=openai
  • *_SSM_PATH (Slack/BigQuery/LLM/LAAS 시크릿 경로)

새 배포 파라미터가 필요하면 template.yaml + scripts/deploy_stack.sh + deploy/targets/prod.env를 같이 수정하고 코드리뷰를 거쳐 반영합니다.

Slack 봇 설정

1. Slack 앱 생성

  1. Slack API Apps로 이동
  2. Create New AppFrom scratch 클릭
  3. 앱 이름 입력 및 워크스페이스 선택

2. 봇 권한 설정

OAuth & Permissions로 이동하여 Bot Token Scopes 추가:

Scope 설명
chat:write 메시지 전송
commands 슬래시 커맨드 추가
app_mentions:read @멘션 수신
im:history DM 메시지 읽기
im:write DM 전송

3. 이벤트 활성화

  1. Event Subscriptions로 이동
  2. Enable Events를 On으로 토글
  3. Request URL 설정: {Function URL}slack/events
  4. 봇 이벤트 구독:
    • app_mention
    • message.im

4. 슬래시 커맨드 추가

Slash CommandsCreate New Command로 이동:

커맨드 Request URL 설명
/hello {Function URL}slack/events 인사 커맨드 예시
/longtask {Function URL}slack/events 백그라운드 작업 예시

5. 워크스페이스에 설치

  1. Install App으로 이동
  2. Install to Workspace 클릭
  3. Bot User OAuth Token 복사 (xoxb-로 시작)

6. Signing Secret 확인

  1. Basic Information으로 이동
  2. Signing Secret 복사

7. Slack 자격 증명으로 배포

Slack 자격 증명은 SSM SecureString으로 저장 후 배포합니다. just deploy는 시크릿 값을 읽거나 쓰지 않고, SSM 경로 참조만 전달합니다.

# 1) 시크릿 값을 개별 입력하여 SSM 동기화
just sync-secrets

# 2) 배포 (기본 target=prod)
just deploy

SSM 경로(예: SLACK_*_SSM_PATH)는 deploy/targets/prod.env에서 관리합니다. just sync-secrets는 각 경로별로 값을 개별 입력받아 put-parameter를 수행합니다.

Slack 핸들러 추가하기

핸들러 예시와 백그라운드 패턴은 docs/guides/SLACK_GUIDE.md에 정리했습니다.

라이선스

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages