# Company-X Slack 메시지 전송 방법 (운영 검증) ## 작성일 - 2026-02-21 (KST) ## 목적 - Company-X 팀의 로빙 채널에 테스트 메시지를 안전하게 전송하는 방법을 기록한다. - Gateway 경유 실패 시, 원인 분리용 직접 전송 절차를 남긴다. ## 대상 - Slack Team: `T09C98KB933` (Company-X Team) - Slack Channel: `C09CP4MDX71` (robeing-team) ## 확인된 전송 경로 - 기본 경로: `Slack -> robeing-gateway(/slack/events) -> rb8001(/api/slack/events) -> skill-slack -> Slack` - 우회 경로(원인 분리): `slack_workspace.bot_token` 조회 후 `chat.postMessage` 직접 호출 ## 실측 결과 (2026-02-21) - Gateway `/slack/events` 경유: `500 Internal Server Error` - 직접 `chat.postMessage` 호출: 성공 (`ok: true`) - 메시지: `hello world` - Slack `ts`: `1771672969.619299` - 시각: - UTC: `2026-02-21 11:22:49` - KST: `2026-02-21 20:22:49` ## 재현 절차 1. Gateway 헬스 확인 ```bash curl -i -sS -m 5 http://127.0.0.1:8100/healthz | sed -n '1,8p' ``` 2. Company-X 팀 토큰 존재 확인 (`slack_workspace`) ```bash docker exec -i robeing-gateway python - <<'PY' import asyncio, os, asyncpg async def main(): dsn = os.environ['DATABASE_URL'].replace('postgresql+asyncpg://', 'postgresql://') conn = await asyncpg.connect(dsn) row = await conn.fetchrow(""" SELECT slack_team_id, left(bot_token,12) token_prefix FROM slack_workspace WHERE slack_team_id='T09C98KB933' LIMIT 1 """) print(dict(row) if row else None) await conn.close() asyncio.run(main()) PY ``` 3. 채널 메시지 전송 (`chat.postMessage`) ```bash docker exec -i robeing-gateway python - <<'PY' import asyncio, os, asyncpg, requests TEAM_ID='T09C98KB933' CHANNEL='C09CP4MDX71' TEXT='hello world' async def get_token(): dsn = os.environ['DATABASE_URL'].replace('postgresql+asyncpg://', 'postgresql://') conn = await asyncpg.connect(dsn) row = await conn.fetchrow('SELECT bot_token FROM slack_workspace WHERE slack_team_id=$1 LIMIT 1', TEAM_ID) await conn.close() return row['bot_token'] if row else None token = asyncio.run(get_token()) resp = requests.post( 'https://slack.com/api/chat.postMessage', headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json; charset=utf-8'}, json={'channel': CHANNEL, 'text': TEXT}, timeout=10, ) print(resp.status_code) print(resp.text) PY ``` ## 운영 주의사항 - 봇 토큰 평문을 문서/로그/커밋에 남기지 않는다. - 실패 원인 분리는 다음 순서로 한다. 1. Gateway health 2. `slack_workspace` 팀/토큰 매핑 3. Slack 사용자 UUID 매핑 4. rb8001 `/api/slack/events` 응답코드 - 직접 `chat.postMessage`는 장애 분리용 검증으로만 사용하고, 정상 운영은 Gateway 경유 경로를 우선한다.