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 sync --frozenjust servehttp://localhost:8080 에서 앱에 접근할 수 있습니다.
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-threadschema/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 APIzai_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_refSSM 조회) - schema/glossary RAG 조회는 LAAS endpoint를 계속 사용합니다.
# (최초 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 에픽 기반 자동 이슈 처리를 운영합니다.
- 오케스트레이터 설정(프로젝트별 정책/게이트/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.sqlite는state.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.md의Lane 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 researchdata_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
- Developer Workflow - 개발/테스트/배포 루프와 botctl simulate 회귀 점검
- AGENTS 경계 정책 - AGENTS.md와 README/docs의 역할 분리 규칙
- Slack 봇 가이드 - 메시지 포맷 예시, 실패 대응 매뉴얼, 트러블슈팅
- 배포 환경 설정 플레이북 - 배포 환경변수 변경 절차, 검증, 롤백
- 런타임 실행 구조 - 현재 코드 기준 실행 흐름
- 인프라/API 의존성 개요 - VPC 선택 관점의 인프라 + API 다이어그램
- Jira Orchestrator 프롬프트(정책 소스) - Jira polling/리파인/피드백/라벨 토글 규칙
- Jira Issue Runner 프롬프트(정책 소스) - 단일 이슈 구현/리뷰/PR/종료 분기 규칙
- Jira Automation State 템플릿 - state 파일 스키마/메타/lane/event 포맷
- Jira Automation Lanes Guide - lane 개념/설정 키/추가 절차/운영 체크리스트
| 엔드포인트 | 메서드 | 설명 |
|---|---|---|
/ |
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) |
환경/타깃 파일 값 |
| 파라미터 | 설명 |
|---|---|
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=miscAWS_REGION=ap-northeast-2STACK_NAME=data-boltLLM_PROVIDER=openai*_SSM_PATH(Slack/BigQuery/LLM/LAAS 시크릿 경로)
새 배포 파라미터가 필요하면 template.yaml + scripts/deploy_stack.sh + deploy/targets/prod.env를
같이 수정하고 코드리뷰를 거쳐 반영합니다.
- Slack API Apps로 이동
- Create New App → From scratch 클릭
- 앱 이름 입력 및 워크스페이스 선택
OAuth & Permissions로 이동하여 Bot Token Scopes 추가:
| Scope | 설명 |
|---|---|
chat:write |
메시지 전송 |
commands |
슬래시 커맨드 추가 |
app_mentions:read |
@멘션 수신 |
im:history |
DM 메시지 읽기 |
im:write |
DM 전송 |
- Event Subscriptions로 이동
- Enable Events를 On으로 토글
- Request URL 설정:
{Function URL}slack/events - 봇 이벤트 구독:
app_mentionmessage.im
Slash Commands → Create New Command로 이동:
| 커맨드 | Request URL | 설명 |
|---|---|---|
/hello |
{Function URL}slack/events |
인사 커맨드 예시 |
/longtask |
{Function URL}slack/events |
백그라운드 작업 예시 |
- Install App으로 이동
- Install to Workspace 클릭
- Bot User OAuth Token 복사 (
xoxb-로 시작)
- Basic Information으로 이동
- Signing Secret 복사
Slack 자격 증명은 SSM SecureString으로 저장 후 배포합니다.
just deploy는 시크릿 값을 읽거나 쓰지 않고, SSM 경로 참조만 전달합니다.
# 1) 시크릿 값을 개별 입력하여 SSM 동기화
just sync-secrets
# 2) 배포 (기본 target=prod)
just deploySSM 경로(예: SLACK_*_SSM_PATH)는 deploy/targets/prod.env에서 관리합니다.
just sync-secrets는 각 경로별로 값을 개별 입력받아 put-parameter를 수행합니다.
핸들러 예시와 백그라운드 패턴은 docs/guides/SLACK_GUIDE.md에 정리했습니다.
MIT