- 로빙 철학 반영 브리핑 구조 추가 - 레벨업/스킬/아이템 메타포 적용 - Block Kit JSON 실제 사용법 명시 - 고급 브리핑 메시지 예시 추가 - ideas 폴더로 이동
349 lines
8.8 KiB
Markdown
349 lines
8.8 KiB
Markdown
# Slack 메시지 포맷팅 가이드
|
||
|
||
**작성일**: 2025-08-28
|
||
**카테고리**: 기술 리서치
|
||
**관련**: Slack 통합, 브리핑 메시지
|
||
|
||
---
|
||
|
||
## 1. Slack 포맷팅 제약사항
|
||
|
||
### 지원 안 됨
|
||
- **HTML**: 태그 렌더링 불가, 파일 첨부만 가능
|
||
- **표준 Markdown**: 부분적 지원 (mrkdwn만 가능)
|
||
- **표(Table)**: 미지원
|
||
- **색상/폰트 크기**: 커스터마이징 불가
|
||
|
||
### 지원됨
|
||
- **mrkdwn**: Slack 전용 마크업
|
||
- **Block Kit**: 블록 기반 UI 구성
|
||
|
||
---
|
||
|
||
## 2. mrkdwn 문법
|
||
|
||
### 기본 서식
|
||
| 스타일 | 문법 | 예시 |
|
||
|--------|------|------|
|
||
| 굵게 | `*text*` | *굵은 텍스트* |
|
||
| 기울임 | `_text_` | _기울인 텍스트_ |
|
||
| 취소선 | `~text~` | ~취소선~ |
|
||
| 인라인 코드 | `` `code` `` | `코드` |
|
||
| 인용 | `> quote` | > 인용문 |
|
||
|
||
### 링크
|
||
```
|
||
<https://ro-being.com|로빙 홈페이지>
|
||
```
|
||
|
||
### 코드 블록
|
||
```
|
||
```
|
||
여러 줄
|
||
코드 블록
|
||
```
|
||
```
|
||
|
||
### 리스트
|
||
- 번호/불릿 목록은 자동 서식화
|
||
- 중첩 목록은 제한적 지원
|
||
|
||
---
|
||
|
||
## 3. Block Kit 구성
|
||
|
||
### 주요 블록 타입
|
||
1. **header**: 제목 (plain_text만)
|
||
2. **section**: 본문 (mrkdwn 지원)
|
||
3. **divider**: 구분선
|
||
4. **context**: 보조 정보 (mrkdwn 지원)
|
||
5. **image**: 이미지
|
||
6. **actions**: 버튼/메뉴
|
||
|
||
### 브리핑 메시지 예시
|
||
```json
|
||
{
|
||
"blocks": [
|
||
{
|
||
"type": "header",
|
||
"text": {
|
||
"type": "plain_text",
|
||
"text": "📅 2025년 8월 28일 브리핑"
|
||
}
|
||
},
|
||
{
|
||
"type": "section",
|
||
"text": {
|
||
"type": "mrkdwn",
|
||
"text": "*📧 중요 이메일*\n• `긴급` AWS 결제 알림\n• `중요` 투자사 미팅 요청"
|
||
}
|
||
},
|
||
{
|
||
"type": "divider"
|
||
},
|
||
{
|
||
"type": "section",
|
||
"fields": [
|
||
{"type": "mrkdwn", "text": "*📰 뉴스*\n3건"},
|
||
{"type": "mrkdwn", "text": "*📋 일정*\n2건"}
|
||
]
|
||
},
|
||
{
|
||
"type": "context",
|
||
"elements": [
|
||
{
|
||
"type": "mrkdwn",
|
||
"text": "업데이트: <!date^1724806800^{date} {time}|2025-08-28 09:00>"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 자주 사용하는 패턴
|
||
|
||
### 제목과 내용 구분
|
||
```
|
||
*📊 일일 통계*
|
||
• 대화: 15건
|
||
• 작업 완료: 8건
|
||
• 대기 중: 3건
|
||
```
|
||
|
||
### 상태 표시
|
||
```
|
||
✅ 완료: 서버 점검
|
||
🔄 진행 중: 데이터 백업
|
||
❌ 실패: API 연동
|
||
```
|
||
|
||
### 날짜 포맷 (Unix timestamp)
|
||
```
|
||
<!date^1724806800^{date_short} {time}|2025-08-28 09:00>
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Markdown → mrkdwn 변환 전략
|
||
|
||
### 변환 규칙
|
||
| Markdown | mrkdwn 대체 |
|
||
|----------|------------|
|
||
| `# 제목` | `*제목*` + divider |
|
||
| `## 부제목` | `*부제목*` |
|
||
| 표 | section.fields (2열) 또는 코드블록 |
|
||
| 이미지 | image 블록 |
|
||
| HTML | 제거 또는 텍스트 변환 |
|
||
|
||
### 코드 예시
|
||
```python
|
||
def markdown_to_mrkdwn(text):
|
||
# 헤딩 변환
|
||
text = re.sub(r'^# (.+)$', r'*\1*', text, flags=re.MULTILINE)
|
||
text = re.sub(r'^## (.+)$', r'*\1*', text, flags=re.MULTILINE)
|
||
|
||
# 링크 변환
|
||
text = re.sub(r'\[(.+?)\]\((.+?)\)', r'<\2|\1>', text)
|
||
|
||
# 굵게/기울임 (주의: 충돌 가능)
|
||
text = re.sub(r'\*\*(.+?)\*\*', r'*\1*', text)
|
||
text = re.sub(r'_(.+?)_', r'_\1_', text)
|
||
|
||
return text
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 제약사항 우회 방법
|
||
|
||
### 표 대체
|
||
```python
|
||
# 2열 표 → section.fields
|
||
"fields": [
|
||
{"type": "mrkdwn", "text": "*항목*\n값1"},
|
||
{"type": "mrkdwn", "text": "*수량*\n10"}
|
||
]
|
||
|
||
# 3열 이상 → 코드블록
|
||
```
|
||
항목 | 수량 | 상태
|
||
-------- | ---- | ----
|
||
이메일 | 5 | 읽음
|
||
작업 | 3 | 진행
|
||
```
|
||
```
|
||
|
||
### 긴 메시지 처리
|
||
- 블록 50개 제한
|
||
- 초기: 요약 표시
|
||
- 버튼 클릭 시: response_url로 상세 전송
|
||
|
||
### 색상 대체
|
||
- 이모지 활용: 🔴 긴급, 🟡 중요, 🟢 정상
|
||
- 굵게/구분선으로 시각적 분리
|
||
|
||
---
|
||
|
||
## 7. 브리핑 메시지 실제 구현
|
||
|
||
### 로빙 철학 반영 브리핑 구조
|
||
1. **존재형 철학**: "동반자적 조언" 형식
|
||
2. **시나리오 기반**: 우선순위·밤사이 처리·오늘의 제안
|
||
3. **레벨업 요소**: 경험치/스탯 성장 알림
|
||
4. **스킬/아이템**: API 아이템 장착, 스킬 실행 메타포
|
||
5. **다층 모듈**: 윤리/감정 레이어 반영
|
||
|
||
### 고급 브리핑 Block Kit JSON
|
||
```json
|
||
{
|
||
"blocks": [
|
||
{
|
||
"type": "header",
|
||
"text": {
|
||
"type": "plain_text",
|
||
"text": "📊 2025-08-29 모닝 브리핑 - Level 12",
|
||
"emoji": true
|
||
}
|
||
},
|
||
{
|
||
"type": "section",
|
||
"text": {
|
||
"type": "mrkdwn",
|
||
"text": "*우선순위 알림*\n1. *[긴급]* 09:00 투자사 미팅 - 슬라이드 7, 12, 15 검토 필요\n2. *[중요]* FDA 규제 변경 분석 보고서 초안 완료 (확인 요청)\n3. *[기회]* 경쟁사 CTO 퇴사 소식 - 인재 영입 검토"
|
||
}
|
||
},
|
||
{"type": "divider"},
|
||
{
|
||
"type": "section",
|
||
"text": {
|
||
"type": "mrkdwn",
|
||
"text": "*밤사이 수행*\n• 미국 파트너 이메일 3건 자동응답 _(신뢰 +0.2)_\n• 업계 뉴스 5건 요약 완료 _(시장분석 스킬 EXP +40)_\n• 내일 팀 미팅 어젠다 작성 완료 _(조율 스킬 성장)_"
|
||
}
|
||
},
|
||
{"type": "divider"},
|
||
{
|
||
"type": "section",
|
||
"text": {
|
||
"type": "mrkdwn",
|
||
"text": "*오늘 제안*\n- 에너지 레벨 낮음 → 오후 미팅 하나 연기 권장\n- 새로 획득한 *데이터 시각화 API* 아이템 장착 가능 _(효율 +15%)_"
|
||
}
|
||
},
|
||
{"type": "divider"},
|
||
{
|
||
"type": "context",
|
||
"elements": [
|
||
{
|
||
"type": "mrkdwn",
|
||
"text": "*성장 알림*: EXP +36 (INT +0.1, AGI +0.2) | 다음 레벨까지 420/800"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### Python 구현 예시
|
||
```python
|
||
def create_advanced_briefing(user_data, robeing_stats):
|
||
blocks = []
|
||
|
||
# 헤더 with 레벨
|
||
blocks.append({
|
||
"type": "header",
|
||
"text": {
|
||
"type": "plain_text",
|
||
"text": f"📊 {user_data['date']} 브리핑 - Level {robeing_stats['level']}"
|
||
}
|
||
})
|
||
|
||
# 우선순위 알림 (시나리오 기반)
|
||
priority_text = "*우선순위 알림*\n"
|
||
for idx, task in enumerate(user_data['priorities'], 1):
|
||
priority_text += f"{idx}. *[{task['priority']}]* {task['content']}\n"
|
||
|
||
blocks.append({
|
||
"type": "section",
|
||
"text": {"type": "mrkdwn", "text": priority_text}
|
||
})
|
||
|
||
# 밤사이 수행 (스킬 메타포)
|
||
night_text = "*밤사이 수행*\n"
|
||
for action in user_data['night_actions']:
|
||
skill_effect = f"_({action['skill']} {action['effect']})_"
|
||
night_text += f"• {action['description']} {skill_effect}\n"
|
||
|
||
blocks.append({"type": "divider"})
|
||
blocks.append({
|
||
"type": "section",
|
||
"text": {"type": "mrkdwn", "text": night_text}
|
||
})
|
||
|
||
# 성장 알림 (게임적 요소)
|
||
growth_text = f"*성장 알림*: EXP +{robeing_stats['exp_gained']} "
|
||
growth_text += f"(INT +{robeing_stats['int_gain']}, AGI +{robeing_stats['agi_gain']}) "
|
||
growth_text += f"| 다음 레벨까지 {robeing_stats['current_exp']}/{robeing_stats['next_level_exp']}"
|
||
|
||
blocks.append({"type": "divider"})
|
||
blocks.append({
|
||
"type": "context",
|
||
"elements": [{"type": "mrkdwn", "text": growth_text}]
|
||
})
|
||
|
||
return blocks
|
||
```
|
||
|
||
---
|
||
|
||
## 8. Block Kit 사용 방법
|
||
|
||
### ⚠️ 중요: JSON은 API로만 적용됨
|
||
- **Slack 채팅창에 JSON 붙여넣기**: ❌ 텍스트로만 표시됨
|
||
- **Block Kit Builder**: ✅ 미리보기 가능
|
||
- **API 호출 (chat.postMessage)**: ✅ 실제 적용
|
||
|
||
### Block Kit Builder 사용법
|
||
1. https://api.slack.com/tools/block-kit-builder 접속
|
||
2. JSON 붙여넣기 → 미리보기 확인
|
||
3. 수정 후 복사 → API 코드에 활용
|
||
|
||
### API 호출 예시
|
||
```python
|
||
import requests
|
||
|
||
url = "https://slack.com/api/chat.postMessage"
|
||
headers = {"Authorization": f"Bearer {SLACK_BOT_TOKEN}"}
|
||
payload = {
|
||
"channel": "C12345678", # 또는 DM ID
|
||
"blocks": [ ... 위의 JSON blocks 배열 ... ]
|
||
}
|
||
response = requests.post(url, headers=headers, json=payload)
|
||
```
|
||
|
||
## 9. 주의사항
|
||
|
||
### API 사용 시
|
||
- `text` 필드: 폴백용 (블록 미지원 클라이언트)
|
||
- `blocks` 필드: 실제 렌더링용
|
||
- `mrkdwn: true` 기본값 (일부 필드는 명시 필요)
|
||
|
||
### 성능
|
||
- 블록 50개 제한
|
||
- 메시지 크기 40KB 제한
|
||
- 이미지는 URL 참조만 (직접 업로드 별도)
|
||
|
||
### 호환성
|
||
- 모바일/데스크톱 차이 고려
|
||
- 알림 미리보기는 text 필드 사용
|
||
- 스레드 응답 시 블록 상속 안 됨
|
||
|
||
---
|
||
|
||
## 10. 참고 문서
|
||
- [Block Kit Builder](https://app.slack.com/block-kit-builder) - 실시간 미리보기
|
||
- [Message Formatting](https://api.slack.com/reference/surfaces/formatting)
|
||
- [Block Kit Reference](https://api.slack.com/reference/block-kit)
|
||
- [mrkdwn Syntax](https://api.slack.com/reference/surfaces/formatting#basics)
|
||
- [chat.postMessage API](https://api.slack.com/methods/chat.postMessage) |