Phase 3: 댓글→명령 파서 + Telegram 알림 + 충돌감시
선행 상태
- Phase 1 (REST API + Markdown 렌더) ✅ 라이브
- Phase 2 (대시보드 + 프로젝트 계층 + PDF) ✅ 라이브
- Claims API ✅ (Phase 1에서 구현됨)
- AI namespace prefix ✅ (slug 생성에 내장)
A. 댓글→명령 파서 (comment-hook)
A.1 새 파일: bridge.py
scratchpad가 댓글 저장 후 comms-hub에 webhook을 보냄 (PM이 scratchpad 수정 담당). comms-hub는 이 webhook을 받아서 댓글 내용을 파싱.
# bridge.py
def parse_comment(slug: str, body: str, anchor: str | None) -> list[Action]:
"""댓글에서 AI 명령 패턴을 감지하여 액션 목록 반환."""
A.2 감지할 패턴
| 패턴 | 액션 |
|---|---|
@codex 또는 코덱스한테 |
to: codex directive 메시지 생성 |
@claude-code 또는 클코한테 |
to: claude-code directive 메시지 생성 |
@claude-app 또는 클앱한테 |
to: claude-app directive 메시지 생성 |
승인 / 수용 / ㅇㅋ / ok |
해당 slug의 최신 메시지 status → approved |
리젝 / 다시 / 안돼 |
status → rejected |
P0 / 긴급 |
priority → p0 |
이어서 / 계속 |
status → continue 처리 |
A.3 slug → message 매핑
webhook에서 slug가 옴. 이 slug로 store에서 해당 메시지를 찾아야 함.
store.messages에서msg.slug == slug또는msg.html_file에 slug 포함된 것 검색- 레거시 HTML이면 (store에 없으면) 무시
A.4 엔드포인트
@app.post("/api/comms/comment-hook")
def comment_hook(payload: CommentHookPayload) -> dict:
"""scratchpad에서 호출. 댓글 파싱 후 자동 액션 실행."""
# payload: {slug, body, anchor, ts, id}
actions = parse_comment(payload.slug, payload.body, payload.anchor)
results = execute_actions(actions, store, ...)
return {"actions": len(results), "results": results}
A.5 directive 메시지 자동 생성
@codex 이어서 P2 머지해 같은 댓글이 들어오면:
{
"from": "jadong",
"to": ["codex"],
"type": "directive",
"project": "(slug에서 추론)",
"title": "(댓글 본문 첫 줄)",
"content_md": "(댓글 전문)",
"ref": "(해당 보고서 메시지 ID)"
}
B. Telegram 알림
B.1 새 파일: notify.py
# notify.py
import httpx
async def send_telegram(text: str, bot_token: str, chat_id: str) -> bool:
"""Telegram Bot API sendMessage 호출."""
url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
resp = await httpx.AsyncClient().post(url, json={
"chat_id": chat_id,
"text": text,
"parse_mode": "HTML",
"disable_web_page_preview": True,
})
return resp.status_code == 200
B.2 환경변수
TELEGRAM_BOT_TOKEN=8620124076:AAFV52f6J7IPtJaoRPmPZHcBkvN-bc4sCdY
TELEGRAM_CHAT_ID= # 자동님이 봇에 /start 보낸 후 설정
둘 다 비어있으면 Telegram 알림 비활성 (에러 없이 skip).
B.3 알림 트리거
| 이벤트 | 메시지 포맷 |
|---|---|
| 새 메시지 (work-order, decision-request, alert) | 📨 [{from} → {to}] {type}\n"{title}"\n📂 {project}\n🔗 {url} |
| 상태 변경 (done, approved, rejected) | ✅/❌ [{ai}] {id} → {status}\n📄 {title} |
| 댓글→명령 파서 액션 발생 | 💬 자동님 댓글 → {action_summary} |
B.4 httpx 의존성
requirements.txt에 httpx>=0.28 추가. 또는 stdlib urllib.request로 동기 호출해도 OK (volume 적으므로).
B.5 /api/comms/telegram-setup
봇에 /start 보낸 후 chat_id 자동 감지 엔드포인트:
@app.post("/api/comms/telegram-setup")
def telegram_setup():
"""getUpdates로 최신 chat_id 감지하여 .env에 저장."""
C. Enhanced Health
/api/comms/health 확장:
{
"ok": true,
"comms_hub": "running",
"scratchpad": "(localhost:8769 GET / 응답 여부)",
"weasyprint": true,
"telegram": {"configured": true, "bot_ok": true},
"disk_pct": 42,
"messages_total": 12,
"messages_today": 3,
"active_claims": 0,
"syncthing_conflicts": 0,
"uptime_seconds": 3600,
"last_activity": {
"claude-code": "2026-05-06T01:12:10+09:00",
"codex": null
}
}
D. Syncthing 충돌 감지
D.1 새 파일: conflict_watch.sh
EC2에서 크론으로 실행:
#!/bin/bash
# 5분마다 실행
CONFLICTS=$(find /home/ubuntu/reports -name "*.sync-conflict-*" 2>/dev/null)
if [ -n "$CONFLICTS" ]; then
curl -s -X POST http://127.0.0.1:8770/api/comms/msg \
-H "Content-Type: application/json" \
-d "{\"from\":\"jadong\",\"to\":[\"claude-code\"],\"type\":\"alert\",\"project\":\"comms-hub\",\"title\":\"Syncthing conflict 감지\",\"content_md\":\"$CONFLICTS\"}"
fi
E. 구현 파일 목록
| 파일 | 액션 | 설명 |
|---|---|---|
bridge.py |
신규 | 댓글 파싱 + 액션 실행 |
notify.py |
신규 | Telegram 알림 전송 |
conflict_watch.sh |
신규 | Syncthing 충돌 감지 크론 스크립트 |
server.py |
수정 | comment-hook + telegram-setup + health 확장 |
models.py |
수정 | CommentHookPayload 모델 추가 |
requirements.txt |
수정 | httpx 추가 (선택) |
F. 금지 사항
- scratchpad 코드 수정 금지 (PM이 별도 처리)
- Phase 1/2 라우트 시그니처 변경 금지
- 기존 reports/ HTML 수정 금지
- DB 도입 금지
G. 검증 체크리스트
T1: comment-hook 기본 동작
curl -s -X POST http://localhost:8770/api/comms/comment-hook \
-H "Content-Type: application/json" \
-d "{\"slug\":\"2026-05-06-cc-comms-hub-phase-1-배포-완료\",\"body\":\"승인\",\"anchor\":null,\"ts\":\"2026-05-06T01:00:00+09:00\",\"id\":\"test123\"}"
# 기대: 해당 메시지 status → approved
T2: AI directive 자동 생성
curl -s -X POST http://localhost:8770/api/comms/comment-hook \
-H "Content-Type: application/json" \
-d "{\"slug\":\"2026-05-06-cc-comms-hub-phase-1-배포-완료\",\"body\":\"@codex 이거 리팩터링 해줘\",\"anchor\":\"Phase 1 배포 완료\",\"ts\":\"2026-05-06T01:00:00+09:00\",\"id\":\"test456\"}"
# 기대: to=codex, type=directive 메시지 자동 생성
T3: Telegram (비활성 상태에서 에러 없음)
# TELEGRAM_CHAT_ID 미설정 상태에서 메시지 생성 → Telegram skip, 에러 없음
T4: Enhanced health
curl -s http://localhost:8770/api/comms/health | python3 -m json.tool
# 기대: messages_total, disk_pct, weasyprint, telegram 필드 존재
T5: conflict_watch.sh 실행 가능
bash conflict_watch.sh # .sync-conflict 파일 없으면 무동작
H. 완료 보고
- 구현/수정 파일 + 줄 수
- T1~T5 결과
- 설계 결정 사항