일을 하는 것에서 그치는 것이 아닌, 일을 잘 하고 싶은 조직에서 좋은 문화를 구성하는 것은 일의 생산성이나 품질에도 여러 이점을 가져온다
필자가 개발하고자 하는 "CoffeePal"은 문제에 막혀 길을 잃어버린 사람이나 소소한 스몰 토크로 일에도 능률을 키울 수 있는 그러한 앱을 만들 고자 커피 친구
라는 의미에서 커피팔을 기획하게 되었다
먼저 사내 커뮤니케이션 툴인 Slack
에서 상호작용을 통해, 쉽고 빠르게 커피 친구를 매칭해줘야 하는 요구사항이 있다
이에 앞서 간단하게 Slack Workflow를 통하여, 전반적인 흐름을 파악해 본다
Trigger Point 생성
테스트 용이기 때문에, Trigger는 :커피:
이모지로 반응하였을 때 워크플로가 실행 되도록 한다
활성화 하기
반응한 메시지를 전송한 사용자에게 메시지를 보내어, 커피팔 매칭을 시작할 지 여부를 확인한다
양식에서 정보 수집
개인화된 서비스를 위해 MBTI, 생년월일을 입력 받는다.
해당 데이터의 기입은 Optional 하게 만든다
대상, 일시, 주제를 지정한다
커피팔 대상과 커피 일정, 그리고 전반적인 주제를 사전에 정의한다.
커피팔 대상에게 초대 메시지 보내기
앞서 지정한 데이터를 통해 커피팔에게 간략하게 초대 메시지를 보낸다
개인적으로 Slack 워크플로
를 처음 사용해 보았는데, UI가 깔끔하고 사용성이 괜찮음을 느꼈다
다만, 사용자와 "상호작용"이라기 보다는, 일방적인 소통에 가깝기 때문에 slack app으로 확장 해보도록 한다
먹고 싶지 않은 음식을 억지로 먹여주는 느낌... 이랄까요?
미리 저장된 데이터를 기반으로 사용자 기반의 매칭을 할 수 있어야 한다
App을 사용한 상호작용을 위해 컴퓨팅 리소스를 확보한다
사용자에게 한눈에 봐도 알 수 있는 UI 제공
slack API에서 App 생성하기
From scratch
를 클릭API Gateway는 HTTP 요청을 Lambda 함수로 라우팅 할 수 있는 매우 유용한 트리거입니다. Slack Events API와 Lambda를 연동하기 위해서는 API Gateway를 통한 설정이 필요합니다.
라고 생각하던 와중... 서버가 이미 있다면 굳이 람다로 구현을 해야하는가?
이미 있는 서버를 안쓰는 것이 더 낭비가 아닌가? 🤔 고민에 빠졌습니다
서버는 남는 개발 서버를 활용하여 처리를 하고 소켓 모드로 일괄 처리하는 방안을 생각하게 되었습니다
소켓 모드란?
소켓 모드를 켜면 이러한 페이로드를 공개 HTTP 앤드포인트인 요청 URL로 보내는 대신 WebSocket 연결을 통해 앱의 상호 작용과 이벤트를 라우팅합니다.
앤드 포인트를 사용하지 않음으로서 여러 요청에 대한 보안적인 위협을 피할 수 있습니다.
또한 여러 Event에 대해 일일이 구독을 하지 않아도 됩니다
전역 토큰에 권한을 부여 → 서버 내에서 권한을 사용하여 슬랙 제어
channels:read
: 채널의 사용자 정보 취득chat:write
: 채널에서 쓰기 권한chat:write.public
: 채널에 invite 되어 있지 않아도 쓰기 권한groups:read
: private 채널 정보 취득groups:write
: private 채널에 쓰기 권한im:write
: DM 발송 권한mpim:write
: group DM 발송 권한reminders:write
: 리마인더 설정 권한Slack 애플리케이션을 개발하기 위한 프레임워크
주로 Node.js, Python, JavaScript와 같은 언어로 작성되었으며, Slack 플랫폼과 통합된 애플리케이션을 쉽게 만들 수 있도록 도와줍니다.
굳이...? 싶지만...
안쓰면 불필요한 작업이 너무 많아집니다. 이는 곧 낮은 생산 속도, 유지 보수도 힘들어지죠
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
import os
import json
import base64
import urllib.parse
def lambda_handler(event, context):
bot_token = os.getenv('BOT_KEY')
# 토큰으로 인증
client = WebClient(token=bot_token)
# Base64 인코딩 여부 확인 및 디코딩
if event.get('isBase64Encoded', False):
try:
# Base64 인코딩된 본문을 디코딩하여 문자열로 변환
decoded_body = base64.b64decode(event['body']).decode('utf-8')
event_body = urllib.parse.unquote_plus(decoded_body)[8:]
except Exception as e:
print(f"Error decoding base64 body: {e}")
return {
'statusCode': 400,
'body': json.dumps({'message': 'Invalid base64 encoded body'})
}
ele:
event_body = event['body']
print(event_body)
# 디코딩된 본문을 JSON으로 파싱
try:
event_data = json.loads(event_body)
except json.JSONDecodeError:
print("JSONDecodeError occurred. The body may not be in valid JSON format.")
return {
'statusCode': 400,
'body': json.dumps({'message': 'Invalid request body'})
}
# Event 타입 확인
event_type = event_data.get('event', {}).get('type')
# Event 타입에 따라 분기로 처리
app = App(token=settings.SLACK_BOT_TOKEN)
logger = logging.getLogger(__name__)
# app_home_opened 이벤트 핸들러 등록
@app.event("app_home_opened")
def handle_app_home_opened(
event: Union[
str,
Pattern,
Dict[str, Optional[Union[str, Sequence[Optional[Union[str, Pattern]]]]]],
],
client: WebClient = None,
) -> SlackResponse:
...
# 버튼 액션 핸들러 등록
@app.action("suggest_coffee_chat_button")
def handle_random_coffee_chat_button(
ack, body, client: WebClient = None
) -> SlackResponse:
...
특정 이벤트 / 액션 / 뷰 를 디버깅 할 때에 Bolt를 활용하면 인증, event, action에 따른 분기 처리, 미들웨어 설정 등등...
서비스 로직을 수행하기전 거쳐야 했던 중복되는 과정들을 생략하고 서비스 로직에 집중할 수 있습니다.
Bolt에서 제공되는 기능 중 크게 5가지를 사용하게 됩니다.
슬랙 앱 개발의 꽃은 역시 Block Kit이라 말할 수 있습니다.
각 화살표는 Block을 나타내며 type에 따라 구분되는데 이를 Stacking 하여 하나의 View를 형성합니다.
ex.
HOME_OPENED = {
"type": "home",
"blocks": [
...
],
}
섹션을 활용하여 직관적인 UI로 사용자 경험을 최적화 합니다
가로 섹션
세로 섹션
Slack API는 Restful API 답게 Stateless (무상태성)을 띕니다.
각 요청이 독립적이며, 서버가 클라이언트의 이전 요청에 대한 정보를 유지하지 않는것이죠
Input 없이는 유저의 이전 View에서의 상태를 알 수 없기 때문에 상호작용이 불가합니다.
랜덤 커피챗을 예로 들어 보겠습니다
서버가 만약 순간적인 단절이 생겼을 때에도
다시 요청 시, 이전 Input 값을 토대로 무상태성 요청을 보낼 수 있어
안정성이 보장됩니다
개발자로 살아오며 “우분투" 정신에 깊게 공감하고 있었습니다
'우리가 함께 있기에 내가 있다(I am because you are)'
우리가 함께할 수 있는 환경을 구성하는 것도 중요하다 생각됩니다.
모든 이가 소통에 두려움을 느끼지 않고 "함께"가 되었으면 하는 마음에
기술적인 어려움에 부딪히거나, 보다 긴밀한 협업을 위해 아이스 브레이킹이 필요하시다면 여러분도 슬랙봇을 만들어 보세요 :)