요새 PM 을 하고 있는데 내가 매일같이 하는일은 JIRA 칸반보드 뚫어지게 쳐다보는 일이다 O_O
일정이 지연된건 없는지, 이슈가 뭔지, 할당된 업무들은 어디까지 진행이 되고있는지, Due Date 체크등
매일같이 들여다보고 Gantt 차트로 변환해서 진행률 보고 아주 눈이 빠질꺼 같단말이지...
아 이거 매일같이 좀 누가 비서로 티켓은 몇개고 어디까지 일이 진행됬고 진행률은 뭐고 이런거 알려주는 비서가 있었음 좋겠는데............... 하지만 내 주변에 나의 잡일을 담당해줄 팀원은 없지 ^^
그래서 Agent를 간단하게 만들어보기로 했다.

간단하게 요런 구성으로 만들어볼 참이다.
지라에서 단순히 이슈만 수집한 후 거기에 대한 리스크관리와 분석은 LLM모델을 써서 시킬 참이다.
[ 개발환경 ]
Windows 11
IDE : VsCode
Python 3.13
LLM : gemini-2.5-flash (다른건 다 유료임 ㅠㅠ)
제미나이도 일일토큰 제한이 250이라 이걸 초과하면 과금이 된다 ㅠㅠ
☑️ 사전작업
1. JIRA에서 토큰 발급 받기
https://id.atlassian.com/manage-profile/security/api-tokens
Atlassian account
id.atlassian.com
해당 페이지가서 현재 내가 속한 소속의 API 키를 발급받는다!
그런다음 API 호출을 위해
이메일:[받은토큰] 을 Base64로 인코딩하여 헤더로 쓰자!
난 윈도우 계열이라 PowerShell을 이용했다
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("이메일:YOUR_NEW_API_TOKEN"))
요러면 아주 잘 변환해준다.
참고로 API 에 대한 Document는
https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/
https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/
developer.atlassian.com
여기에 잘 나와있다.
일단 Postman으로 냅다 호출부터 해보자
[GET] https://[본인소속].atlassian.net/rest/api/3/project
-h Authorization "Basic xxxxx"
해보면 잘된다. 좋아 나중에 긁어오면 되겠군
2. Gemini 토큰 발급하기.
https://aistudio.google.com/api-keys
로그인 - Google 계정
이메일 또는 휴대전화
accounts.google.com
해당 페이지 접속후 발급할수 있다.
토큰에 대한 할당량 확인은
https://console.cloud.google.com/iam-admin
Google 클라우드 플랫폼
로그인 Google 클라우드 플랫폼으로 이동
accounts.google.com
해당 페이지에서 확인할 수 있다.
할당량 및 시스템 한도에서

이와 같이 확인이 가능하다.
3. Slack WebHook 추가하기
https://slack.com/apps/A0F7XDUAZ-incoming-webhooks
수신 웹후크
> _Please note, this is a legacy custom integration - an outdated way for teams to integrate with Slack. These integrations lack newer features and they will be deprecated and possibly removed in the
slack.com
해당페이지에서 추가할수 있다.
✔️ Python API 로 서버 세팅하기
세팅전 Python 설치와 아래 해당패키지들은 필수로 설치한다.(나는 vscode 터미널에서 설치했다.)
# 가상환경 생성
py -m venv venv
# 가상환경 활성화
venv\Scripts\activate
# 패키지 설치
pip install -r requirements.txt
pip install google-generativeai
pip install google-genai
pip install --upgrade jira
# .env 파일 만들기
cp .env.example .env
code .env
1. JIRA API로 이슈 수집하기.
class JiraCollector:
"""JIRA data collector"""
def __init__(self, settings: Settings):
self.settings = settings
self.jira = JIRA(
server=settings.jira_url,
basic_auth=(settings.jira_email, settings.jira_api_token),
options={'rest_api_version': '3'}
)
self.tz = pytz.timezone(settings.timezone)
def get_my_issues(self) -> List[Dict[str, Any]]:
"""
Fetch issues based on criteria:
- Reporter = me
- Status != Done
- Due date is this week OR (No due date AND High priority)
"""
# Get week end date (Sunday)
now = datetime.now(self.tz)
week_end = now + timedelta(days=(6 - now.weekday()))
week_end_str = week_end.strftime('%Y-%m-%d')
# JQL query
jql = f"""
project = {self.settings.jira_project_key}
AND reporter = "{self.settings.jira_email}"
AND statusCategory != Done
AND (
duedate <= {week_end_str}
OR (duedate is EMPTY AND priority = High)
)
ORDER BY priority DESC, duedate ASC
"""
issues = self.jira.search_issues(
jql,
maxResults=100,
fields='summary,status,priority,duedate,assignee,labels,issuetype,updated'
)
return self._format_issues(issues)
def _format_issues(self, issues) -> List[Dict[str, Any]]:
"""Format issues for analysis"""
formatted = []
for issue in issues:
due_date = None
if issue.fields.duedate:
due_date = datetime.strptime(issue.fields.duedate, '%Y-%m-%d')
assignee_name = "Unassigned"
if issue.fields.assignee:
assignee_name = issue.fields.assignee.displayName
formatted.append({
'key': issue.key,
'summary': issue.fields.summary,
'status': issue.fields.status.name,
'priority': issue.fields.priority.name,
'due_date': issue.fields.duedate,
'assignee': assignee_name,
'issue_type': issue.fields.issuetype.name,
'labels': issue.fields.labels,
'url': f"{self.settings.jira_url}/browse/{issue.key}",
'updated': issue.fields.updated
})
return formatted
def get_overdue_count(self, issues: List[Dict[str, Any]]) -> int:
"""Count overdue issues"""
today = datetime.now(self.tz).date()
overdue = 0
for issue in issues:
if issue['due_date']:
due = datetime.strptime(issue['due_date'], '%Y-%m-%d').date()
if due < today:
overdue += 1
return overdue
def get_high_priority_no_due(self, issues: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""Get high priority issues without due date"""
return [
issue for issue in issues
if issue['priority'] == 'High' and not issue['due_date']
]
내가 속한 프로젝트에서 내가 생성한 이슈중, 완료상태가 아닌, Due date가 이번주 이내인거나, 없는거중 우선순위가 High인 이슈들을 가져온다.
2. Gemini 로 분석하여 보고서 생성하기.
"""
Gemini AI analyzer for JIRA issues
"""
import google.generativeai as genai
from typing import List, Dict, Any
import json
from src.config import Settings
class IssueAnalyzer:
"""Analyze JIRA issues using Gemini AI"""
def __init__(self, settings: Settings):
genai.configure(api_key=settings.gemini_api_key)
self.model = genai.GenerativeModel('gemini-2.5-flash')
def analyze_issues(self, issues: List[Dict[str, Any]]) -> str:
"""
Analyze issues and generate report
Returns formatted text for Slack
"""
if not issues:
return self._generate_no_issues_message()
prompt = self._create_analysis_prompt(issues)
response = self.model.generate_content(prompt)
return response.text
def _create_analysis_prompt(self, issues: List[Dict[str, Any]]) -> str:
"""Create prompt for Gemini"""
issues_json = json.dumps(issues, ensure_ascii=False, indent=2)
return f"""당신은 프로젝트 관리 AI 어시스턴트입니다.
아래 JIRA 이슈들을 분석하여 PM에게 간결한 일일 리포트를 작성해주세요.
## 이슈 데이터
```json
{issues_json}
```
## 리포트 작성 지침
1. **전체 요약**: 총 이슈 수, 우선순위 분포, 마감 임박 건수
2. **긴급 대응 필요**: 오늘/내일 마감, 지연된 이슈
3. **주의 필요**: High priority인데 Due date가 없는 이슈
4. **담당자별 현황**: assignee별 이슈 수 (미할당 포함)
5. **권장 조치**: 구체적이고 실행 가능한 액션 아이템
## 출력 형식
- Slack 메시지 형식 (마크다운)
- 이모지 적절히 활용
- 각 이슈는 [이슈키](URL) 형식으로 링크
- 간결하고 핵심만 (불필요한 설명 제거)
- 한국어로 작성
리포트를 작성해주세요:"""
def _generate_no_issues_message(self) -> str:
"""Generate message when no issues found"""
return """🎉 *오늘의 JIRA 리포트*
현재 조건에 맞는 이슈가 없습니다!
- 이번 주 마감 이슈: 없음
- High priority 미할당 이슈: 없음
✅ 모든 이슈가 정리되었거나 다음 주 이후 마감입니다."""
3. Slack에 알림봇으로 보고서 전송하기.
"""
Slack notification module
"""
import requests
import json
from datetime import datetime
from typing import Dict, Any
import pytz
from src.config import Settings
class SlackNotifier:
"""Send notifications to Slack"""
def __init__(self, settings: Settings):
self.webhook_url = settings.slack_webhook_url
self.tz = pytz.timezone(settings.timezone)
def send_report(self, report: str, issue_count: int) -> bool:
"""
Send daily report to Slack
Returns True if successful
"""
now = datetime.now(self.tz)
timestamp = now.strftime('%Y-%m-%d %H:%M KST')
# Build Slack message
message = {
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": f"📊 JIRA 일일 리포트 ({now.strftime('%m/%d %H:%M')})",
"emoji": True
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": report
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": f"총 {issue_count}개 이슈 | {timestamp}"
}
]
}
]
}
try:
response = requests.post(
self.webhook_url,
data=json.dumps(message),
headers={'Content-Type': 'application/json'},
timeout=10
)
if response.status_code == 200:
print(f"✅ Slack notification sent successfully at {timestamp}")
return True
else:
print(f"❌ Slack notification failed: {response.status_code} - {response.text}")
return False
except Exception as e:
print(f"❌ Error sending Slack notification: {str(e)}")
return False
def send_error(self, error_message: str) -> bool:
"""Send error notification to Slack"""
now = datetime.now(self.tz)
message = {
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "⚠️ JIRA Agent Error",
"emoji": True
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"```{error_message}```"
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": f"{now.strftime('%Y-%m-%d %H:%M KST')}"
}
]
}
]
}
try:
response = requests.post(
self.webhook_url,
data=json.dumps(message),
headers={'Content-Type': 'application/json'},
timeout=10
)
return response.status_code == 200
except Exception as e:
print(f"❌ Error sending error notification: {str(e)}")
return False

해보면 요렇게 대충 잘나온다!
흠... 좀 다듬어야 할꺼 같긴한데, 일단 구성은 했따!
'web > AI' 카테고리의 다른 글
| [AI] RAG 와 VectorDB (1) | 2025.12.17 |
|---|---|
| [AI] Qdrant 로 RAG 구축하기(1) (1) | 2025.12.16 |
| [AI] 챗봇만들기 프로젝트 (1) (0) | 2025.12.04 |
| [AI] MCP 프로토콜 (0) | 2025.12.03 |
| [AI] JIRA를 연동하여 주간업무 Agent 만들기(2) (0) | 2025.11.28 |