Compare commits

..

No commits in common. "1d9fa37fe731dd8f2b3f29381107359efa06dbdc" and "72419c320ae35a6b410c7dba41b951cf16f0ad89" have entirely different histories.

15 changed files with 882 additions and 153 deletions

16
Jenkinsfile vendored
View File

@ -163,22 +163,22 @@ podTemplate(
git clone https://\${GIT_USERNAME}:\${GIT_TOKEN}@\${REPO_URL} manifest-repo git clone https://\${GIT_USERNAME}:\${GIT_TOKEN}@\${REPO_URL} manifest-repo
cd manifest-repo cd manifest-repo
# overlays/dev/kustomization.yaml의 images 섹션 업데이트 # 각 서비스별 이미지 태그 업데이트 (sed 사용)
cd hgzero-back/kustomize/overlays/dev cd hgzero-back/kustomize/base
services="user meeting stt notification" services="user meeting stt notification"
for service in \$services; do for service in \$services; do
echo "Updating \$service image tag in kustomization.yaml..." echo "Updating \$service image tag..."
sed -i "s|name: ${registry}/${imageOrg}/\$service\$|name: ${registry}/${imageOrg}/\$service|g" kustomization.yaml sed -i "s|image: ${registry}/${imageOrg}/\$service:.*|image: ${registry}/${imageOrg}/\$service:${environment}-${imageTag}|g" \\
sed -i "/name: ${registry}\\/${imageOrg}\\/\$service\$/!b;n;s|newTag:.*|newTag: ${environment}-${imageTag}|" kustomization.yaml \$service/deployment.yaml
# 변경 사항 확인 # 변경 사항 확인
echo "Updated \$service image tag:" echo "Updated \$service deployment.yaml:"
grep -A1 "name: ${registry}/${imageOrg}/\$service" kustomization.yaml grep "image: ${registry}/${imageOrg}/\$service" \$service/deployment.yaml
done done
# Git 설정 및 푸시 # Git 설정 및 푸시
cd ../../../.. cd ../../..
git config user.name "Jenkins" git config user.name "Jenkins"
git config user.email "jenkins@hgzero.com" git config user.email "jenkins@hgzero.com"
git add . git add .

View File

@ -15,7 +15,7 @@ class Settings(BaseSettings):
# Claude API # Claude API
claude_api_key: str = "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" claude_api_key: str = "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"
claude_model: str = "claude-sonnet-4-5-20250929" claude_model: str = "claude-sonnet-4-5-20250929"
claude_max_tokens: int = 8192 # 4096 → 8192 증가 (더 많은 제안사항 생성 가능) claude_max_tokens: int = 4096
claude_temperature: float = 0.7 claude_temperature: float = 0.7
# Redis # Redis

View File

@ -1,11 +1,9 @@
"""AI 제안사항 추출 프롬프트 (Hallucination 방지 최적화)""" """AI 제안사항 추출 프롬프트 (회의록 작성 MVP 최적화)"""
def get_suggestions_prompt(transcript_text: str) -> tuple[str, str]: def get_suggestions_prompt(transcript_text: str) -> tuple[str, str]:
""" """
회의 텍스트에서 AI 제안사항을 추출하는 프롬프트 생성 회의 텍스트에서 AI 제안사항을 추출하는 프롬프트 생성 (회의록 MVP용)
Hallucination 방지를 위해 예시를 모두 제거하고 명확한 지침만 제공
Returns: Returns:
(system_prompt, user_prompt) 튜플 (system_prompt, user_prompt) 튜플
@ -13,12 +11,6 @@ def get_suggestions_prompt(transcript_text: str) -> tuple[str, str]:
system_prompt = """당신은 실시간 회의록 작성 AI 비서입니다. system_prompt = """당신은 실시간 회의록 작성 AI 비서입니다.
**🚨 중요 원칙 (최우선)**:
1. **오직 제공된 회의 내용만 분석** - 추측, 가정, 예시 내용 절대 금지
2. **실제 발언된 내용만 추출** - 없는 내용 만들어내지 않기
3. **회의 내용에 명시되지 않은 정보는 절대 추가하지 않기**
4. **불확실한 내용은 추출하지 않기** - 명확한 내용만 추출
**핵심 역할**: **핵심 역할**:
회의 발언되는 내용을 실시간으로 분석하여, 회의록 작성자가 놓칠 있는 중요한 정보를 즉시 메모로 제공합니다. 회의 발언되는 내용을 실시간으로 분석하여, 회의록 작성자가 놓칠 있는 중요한 정보를 즉시 메모로 제공합니다.
@ -26,62 +18,415 @@ def get_suggestions_prompt(transcript_text: str) -> tuple[str, str]:
1. 회의 안건, 결정 사항, 이슈, 액션 아이템을 자동으로 분류 1. 회의 안건, 결정 사항, 이슈, 액션 아이템을 자동으로 분류
2. 담당자, 기한, 우선순위 구조화된 정보로 정리 2. 담당자, 기한, 우선순위 구조화된 정보로 정리
3. 단순 발언 반복이 아닌, 실무에 바로 사용 가능한 형식으로 요약 3. 단순 발언 반복이 아닌, 실무에 바로 사용 가능한 형식으로 요약
4. 구어체 종결어미(~, ~, ~습니다) 제거하고 명사형으로 정리 4. 회의록 작성 시간을 70% 단축시키는 것이 목표
**분류 카테고리**: **핵심 원칙**:
- 📋 회의 안건: "오늘 안건은 ~", "논의할 주제는 ~" - 인사말, 반복, 불필요한 추임새는 완전히 제거
- 결정사항: "~로 결정", "~로 합의", "~로 확정" - 실제 회의록에 들어갈 내용만 추출
- 🎯 액션 아이템: "~팀에서 ~", "~까지 완료", "~를 검토" - 명확하고 간결하게 (20-50)
- 이슈/문제점: "문제 발생", "이슈 있음", "우려 사항" - 구어체 종결어미(~, ~, ~습니다) 제거하고 명사형으로 정리"""
- 💡 제안/아이디어: "제안", "~하는 것이 좋을 것 같음", "검토 필요"
- 📊 진행상황: "~% 완료", "~진행 중", "~논의 중"
- 🔔 후속조치: "다음 회의에서", "추후 결정", "보류"
**제외 대상 (반드시 제외)**: user_prompt = f"""다음 회의 대화를 실시간으로 분석하여 **회의록 메모**를 작성하세요.
- 인사말: "안녕하세요", "감사합니다", "수고하셨습니다"
- 추임새: "", "네네", "그러니까", "저기"
- 형식적 발언: "녹음 시작", "회의 종료", "회의 시작"
**출력 형식**:
- JSON만 출력 (주석, 설명, 마크다운 코드블록 금지)
- 구조: {"suggestions": [{"content": "분류: 내용", "confidence": 0.85}]}
- confidence: 0.90-1.0(명확), 0.80-0.89(일반), 0.70-0.79(암묵적), 0.65-0.69(논의중)"""
user_prompt = f"""🚨 **매우 중요**: 아래 제공된 회의 내용만 분석하세요.
- 회의 내용에 없는 정보는 절대 추가하지 마세요
- 예시나 가정을 만들어내지 마세요
- 불확실한 내용은 추출하지 마세요
# 회의 내용 (이것만 분석하세요)
# 회의 내용
{transcript_text} {transcript_text}
---
# 분석 작업 # 회의록 항목별 패턴 학습
회의 내용에서 **실제로 언급된 내용만** 추출하세요: ## 📋 1. 회의 안건 (Agenda)
1. 📋 회의 안건 ### 패턴 인식
2. 결정사항 - "오늘 회의 안건은 ~"
3. 🎯 액션 아이템 (담당자/기한이 있으면 반드시 포함) - "논의할 주제는 ~"
4. 이슈/문제점 - "다룰 내용은 ~"
5. 💡 제안/아이디어 - "검토할 사항은 ~"
6. 📊 진행상황
7. 🔔 후속조치
**필수 규칙**: ### ✅ 좋은 예시
- 구어체 종결어미 제거 (명사형으로 정리) **입력**: "오늘 회의 안건은 신제품 출시 일정과 마케팅 전략입니다."
- 담당자와 기한이 있으면 반드시 포함 **출력**:
- 인사말, 추임새, 형식적 발언 제외 ```json
- 20-70자로 간결하게 {{
- JSON 형식으로만 출력 "content": "📋 회의 안건: 신제품 출시 일정, 마케팅 전략",
"confidence": 0.95
}}
```
**출력 형식**: **입력**: "다음 주 프로젝트 킥오프에 대해 논의하겠습니다."
{{"suggestions": [{{"content": "분류: 내용", "confidence": 0.85}}]}} **출력**:
```json
{{
"content": "📋 회의 안건: 다음 주 프로젝트 킥오프",
"confidence": 0.90
}}
```
지금 바로 분석을 시작하세요.""" ### ❌ 나쁜 예시
**입력**: "오늘 회의 안건은 신제품 출시 일정입니다."
**나쁜 출력**:
```json
{{
"content": "오늘 회의 안건은 신제품 출시 일정입니다", 구어체 그대로 반복
"confidence": 0.90
}}
```
**이유**: 구어체 종결어미(~입니다) 그대로 반복. "📋 회의 안건: 신제품 출시 일정"으로 구조화해야
---
## ✅ 2. 결정 사항 (Decisions)
### 패턴 인식
- "결정 사항은 ~", "~로 결정했습니다"
- "~하기로 했습니다", "~로 합의했습니다"
- "~로 확정됐습니다"
- "최종 결론은 ~"
### ✅ 좋은 예시
**입력**: "회의 결과, 신규 프로젝트는 다음 달부터 착수하기로 결정했습니다."
**출력**:
```json
{{
"content": "✅ 결정사항: 신규 프로젝트 다음 달 착수",
"confidence": 0.95
}}
```
**입력**: "최종 결론은 외주 개발사와 계약하기로 합의했습니다."
**출력**:
```json
{{
"content": "✅ 결정사항: 외주 개발사와 계약 진행",
"confidence": 0.92
}}
```
### ❌ 나쁜 예시
**입력**: "신규 프로젝트는 다음 달부터 착수하기로 결정했습니다."
**나쁜 출력**:
```json
{{
"content": "신규 프로젝트는 다음 달부터 착수하기로 결정했습니다", 원문 그대로
"confidence": 0.90
}}
```
**이유**: 발언을 그대로 반복. "✅ 결정사항: 신규 프로젝트 다음 달 착수" 구조화해야
---
## 🎯 3. 액션 아이템 (Action Items)
### 패턴 인식
- "~팀에서 ~해 주세요"
- "~님이 ~까지 ~하기로 했습니다"
- "~을 ~까지 완료하겠습니다"
- "~을 검토해 보겠습니다"
### ✅ 좋은 예시
**입력**: "개발팀에서 API 문서를 이번 주 금요일까지 작성해 주세요."
**출력**:
```json
{{
"content": "🎯 개발팀: API 문서 작성 (기한: 이번 주 금요일)",
"confidence": 0.95
}}
```
**입력**: "김 팀장님이 내일까지 견적서를 검토해서 회신하기로 했습니다."
**출력**:
```json
{{
"content": "🎯 김 팀장: 견적서 검토 및 회신 (기한: 내일)",
"confidence": 0.93
}}
```
**입력**: "제가 고객사에 연락해서 미팅 일정 잡도록 하겠습니다."
**출력**:
```json
{{
"content": "🎯 고객사 미팅 일정 조율 예정",
"confidence": 0.85
}}
```
### ❌ 나쁜 예시
**입력**: "개발팀에서 API 문서를 이번 주 금요일까지 작성해 주세요."
**나쁜 출력 1**:
```json
{{
"content": "개발팀에서 API 문서를 이번 주 금요일까지 작성해 주세요", 원문 반복
"confidence": 0.90
}}
```
**나쁜 출력 2**:
```json
{{
"content": "API 문서 작성", 담당자와 기한 누락
"confidence": 0.80
}}
```
**이유**: "🎯 개발팀: API 문서 작성 (기한: 이번 주 금요일)" 형식으로 구조화해야
---
## ⚠️ 4. 이슈/문제점 (Issues)
### 패턴 인식
- "문제가 있습니다", "이슈가 발생했습니다"
- "우려되는 점은 ~"
- "해결이 필요한 부분은 ~"
- "리스크가 있습니다"
### ✅ 좋은 예시
**입력**: "현재 서버 성능 이슈가 발생해서 긴급 점검이 필요합니다."
**출력**:
```json
{{
"content": "⚠️ 이슈: 서버 성능 문제 발생, 긴급 점검 필요",
"confidence": 0.92
}}
```
**입력**: "예산이 부족할 것 같다는 우려가 있습니다."
**출력**:
```json
{{
"content": "⚠️ 이슈: 예산 부족 우려",
"confidence": 0.80
}}
```
### ❌ 나쁜 예시
**입력**: "현재 서버 성능 이슈가 발생했습니다."
**나쁜 출력**:
```json
{{
"content": "현재 서버 성능 이슈가 발생했습니다", 구어체 그대로
"confidence": 0.85
}}
```
**이유**: "⚠️ 이슈: 서버 성능 문제 발생"으로 구조화하고 구어체 제거해야
---
## 💡 5. 아이디어/제안 (Suggestions)
### 패턴 인식
- "제안하는 바는 ~"
- "~하는 것이 좋을 것 같습니다"
- "~을 고려해 볼 필요가 있습니다"
### ✅ 좋은 예시
**입력**: "자동화 테스트를 도입하는 것을 검토해 보면 좋을 것 같습니다."
**출력**:
```json
{{
"content": "💡 제안: 자동화 테스트 도입 검토",
"confidence": 0.85
}}
```
---
## 📊 6. 진행 상황/보고 (Progress)
### 패턴 인식
- "~까지 완료했습니다"
- "현재 ~% 진행 중입니다"
- "~단계까지 진행됐습니다"
### ✅ 좋은 예시
**입력**: "현재 설계 단계는 80% 완료됐고, 다음 주부터 개발 착수 가능합니다."
**출력**:
```json
{{
"content": "📊 진행상황: 설계 80% 완료, 다음 주 개발 착수 예정",
"confidence": 0.90
}}
```
---
## ❌ 제외해야 할 내용 (반드시 제외)
### 인사말
**입력**: "안녕하세요, 여러분. 회의 시작하겠습니다."
**출력**: (메모 없음 - 인사말은 제외)
### 단순 반복
**입력**: "녹음을 시작합니다. 녹음을 시작합니다."
**출력**: (메모 없음 - 형식적 발언 제외)
### 추임새/불필요한 발언
**입력**: "음, 그러니까, 네 네, 저기요..."
**출력**: (메모 없음 - 추임새 제외)
### 형식적 마무리
**입력**: "수고하셨습니다. 회의를 마치겠습니다."
**출력**: (메모 없음 - 형식적 마무리 제외)
---
# 실전 회의 시뮬레이션
## 예시 1: 프로젝트 킥오프 회의
**입력**:
"안녕하세요. 오늘 회의 안건은 신규 프로젝트 킥오프입니다. 프로젝트명은 HGZero이고, 목표는 회의록 자동화입니다. 개발팀에서 다음 주 월요일까지 기술 스택을 검토해 주세요. 예산은 5천만원으로 확정됐습니다."
**출력**:
```json
{{
"suggestions": [
{{
"content": "📋 회의 안건: 신규 프로젝트(HGZero) 킥오프 - 회의록 자동화",
"confidence": 0.95
}},
{{
"content": "🎯 개발팀: 기술 스택 검토 (기한: 다음 주 월요일)",
"confidence": 0.93
}},
{{
"content": "✅ 결정사항: 프로젝트 예산 5천만원 확정",
"confidence": 0.95
}}
]
}}
```
---
## 예시 2: 이슈 대응 회의
**입력**:
"현재 프로덕션 서버에서 성능 저하가 발생하고 있습니다. 인프라팀에서 긴급 점검을 진행하기로 했고, 오늘 오후 3시까지 원인 파악하겠습니다. 고객사에는 임시로 사과 공지를 게시하기로 결정했습니다."
**출력**:
```json
{{
"suggestions": [
{{
"content": "⚠️ 이슈: 프로덕션 서버 성능 저하 발생",
"confidence": 0.95
}},
{{
"content": "🎯 인프라팀: 긴급 점검 및 원인 파악 (기한: 오늘 오후 3시)",
"confidence": 0.93
}},
{{
"content": "✅ 결정사항: 고객사 사과 공지 게시",
"confidence": 0.90
}}
]
}}
```
---
## 예시 3: 일반 업무 회의 (나쁜 예시 포함)
**입력**:
"안녕하세요, 안녕하세요. 녹음을 시작합니다. 음, 그러니까 마케팅 캠페인을 다음 달에 진행하기로 했습니다. 김 과장님이 기획안을 이번 주까지 작성해 주세요. 감사합니다."
** 나쁜 출력**:
```json
{{
"suggestions": [
{{
"content": "안녕하세요", 인사말 포함
"confidence": 0.50
}},
{{
"content": "녹음을 시작합니다", 형식적 발언
"confidence": 0.60
}},
{{
"content": "마케팅 캠페인을 다음 달에 진행하기로 했습니다", 구어체 그대로
"confidence": 0.80
}}
]
}}
```
** 좋은 출력**:
```json
{{
"suggestions": [
{{
"content": "✅ 결정사항: 마케팅 캠페인 다음 달 진행",
"confidence": 0.92
}},
{{
"content": "🎯 김 과장: 캠페인 기획안 작성 (기한: 이번 주)",
"confidence": 0.93
}}
]
}}
```
---
# 출력 형식
반드시 아래 JSON 형식으로만 응답하세요:
```json
{{
"suggestions": [
{{
"content": "📋/✅/🎯/⚠️/💡/📊 분류: 구체적인 내용 (담당자/기한 포함)",
"confidence": 0.85
}}
]
}}
```
---
# 최종 작성 규칙
## ✅ 반드시 지켜야 할 규칙
1. **이모지 분류 필수**
- 📋 회의 안건
- 결정사항
- 🎯 액션 아이템
- 이슈/문제점
- 💡 제안/아이디어
- 📊 진행상황
2. **구조화 필수**
- 담당자가 있으면 반드시 명시
- 기한이 있으면 반드시 포함
- 형식: "담당자: 업무 내용 (기한: XX)"
3. **구어체 종결어미 제거**
- "~입니다", "~했습니다", "~해요", "~합니다"
- 명사형 종결: "~ 진행", "~ 완료", "~ 확정", "~ 검토"
4. **반드시 제외**
- 인사말 ("안녕하세요", "감사합니다", "수고하셨습니다")
- 반복/추임새 ("네 네", "음 음", "그러니까", "저기")
- 형식적 발언 ("녹음 시작", "회의 종료", "회의 시작")
5. **길이**
- 20-70 (너무 짧거나 길지 않게)
6. **confidence 기준**
- 0.90-1.0: 명확한 결정사항, 기한 포함
- 0.80-0.89: 일반적인 액션 아이템
- 0.70-0.79: 암묵적이거나 추측 필요
7. **출력**
- JSON만 출력 (주석, 설명, ```json 모두 금지)
- 최소 1 이상 추출 (의미 있는 내용이 없으면 배열)
---
이제 회의 내용을 분석하여 **회의록 메모** JSON 형식으로 작성하세요.
학습한 패턴을 활용하여 회의 안건, 결정사항, 액션 아이템, 이슈 등을 자동으로 분류하고 구조화하세요.
반드시 구어체 종결어미(~, ~, ~습니다) 제거하고 명사형으로 정리하세요."""
return system_prompt, user_prompt return system_prompt, user_prompt

View File

@ -122,7 +122,7 @@ class ClaudeService:
confidence=s.get("confidence", 0.85) confidence=s.get("confidence", 0.85)
) )
for s in suggestions_data for s in suggestions_data
if s.get("confidence", 0) >= 0.65 # 신뢰도 0.65 이상 (0.7 → 0.65 낮춤) if s.get("confidence", 0) >= 0.7 # 신뢰도 0.7 이상만
] ]
logger.info(f"AI 제안사항 {len(suggestions)}개 추출 완료") logger.info(f"AI 제안사항 {len(suggestions)}개 추출 완료")

View File

@ -0,0 +1,129 @@
@startuml meeting-대시보드조회
!theme mono
title Meeting Service - 대시보드조회 내부 시퀀스
participant "DashboardController" as Controller
participant "DashboardService" as Service
participant "MeetingRepository" as MeetingRepo
participant "TodoRepository" as TodoRepo
participant "MinutesRepository" as MinutesRepo
database "Redis Cache<<E>>" as Cache
database "Meeting DB<<E>>" as DB
[-> Controller: GET /dashboard
activate Controller
note over Controller
사용자 정보는 헤더에서 추출
(userId, userName, email)
end note
Controller -> Service: getDashboardData(userId)
activate Service
' 캐시 조회
Service -> Cache: GET dashboard:{userId}
activate Cache
Cache --> Service: 캐시 조회 결과
deactivate Cache
alt Cache Hit
Service --> Service: 캐시 데이터 반환
else Cache Miss
' 예정된 회의 조회
Service -> MeetingRepo: findUpcomingMeetings(userId)
activate MeetingRepo
MeetingRepo -> DB: 예정된 회의 조회
activate DB
DB --> MeetingRepo: 예정된 회의 목록
deactivate DB
MeetingRepo --> Service: List<Meeting>
deactivate MeetingRepo
' 진행 중 Todo 조회
Service -> TodoRepo: findActiveTodos(userId)
activate TodoRepo
TodoRepo -> DB: 진행 중 Todo 조회
activate DB
DB --> TodoRepo: 진행 중 Todo 목록
deactivate DB
TodoRepo --> Service: List<Todo>
deactivate TodoRepo
' 최근 회의록 조회
Service -> MinutesRepo: findRecentMinutes(userId)
activate MinutesRepo
MinutesRepo -> DB: 최근 회의록 조회
activate DB
DB --> MinutesRepo: 최근 회의록 목록
deactivate DB
MinutesRepo --> Service: List<Minutes>
deactivate MinutesRepo
' 통계 정보 조회
Service -> MeetingRepo: countUpcomingMeetings(userId)
activate MeetingRepo
MeetingRepo -> DB: 예정된 회의 개수 조회
activate DB
DB --> MeetingRepo: 예정된 회의 개수
deactivate DB
MeetingRepo --> Service: int count
deactivate MeetingRepo
Service -> TodoRepo: countActiveTodos(userId)
activate TodoRepo
TodoRepo -> DB: 진행 중 Todo 개수 조회
activate DB
DB --> TodoRepo: 진행 중 Todo 개수
deactivate DB
TodoRepo --> Service: int count
deactivate TodoRepo
Service -> TodoRepo: calculateTodoCompletionRate(userId)
activate TodoRepo
TodoRepo -> DB: Todo 완료율 조회
activate DB
DB --> TodoRepo: Todo 완료율
deactivate DB
TodoRepo --> Service: double rate
deactivate TodoRepo
note over Service
비즈니스 로직:
- 데이터 조합 및 정제
- DTO 변환
- 통계 계산
end note
Service -> Service: 대시보드 데이터 조합
' 캐시 저장
Service -> Cache: SET dashboard:{userId}\n(TTL: 5분)
activate Cache
Cache --> Service: 캐시 저장 완료
deactivate Cache
end
Service --> Controller: DashboardResponse
deactivate Service
note over Controller
응답 데이터 구조:
{
"upcomingMeetings": [...],
"activeTodos": [...],
"recentMinutes": [...],
"statistics": {
"upcomingMeetingsCount": n,
"activeTodosCount": n,
"todoCompletionRate": n
}
}
end note
return 200 OK\nDashboardResponse
deactivate Controller
@enduml

View File

@ -0,0 +1,118 @@
@startuml
!theme mono
title 최종 회의록 확정 내부 시퀀스
participant "API Gateway<<E>>" as Gateway
participant "MinutesController" as Controller
participant "MeetingService" as Service
participant "Meeting" as Domain
participant "TranscriptService" as TranscriptService
participant "MeetingRepository" as Repository
database "PostgreSQL<<E>>" as DB
database "Redis Cache<<E>>" as Cache
queue "Event Hub<<E>>" as EventHub
Gateway -> Controller: POST /api/minutes/{minutesId}/finalize
activate Controller
Controller -> Service: confirmTranscript(meetingId)
activate Service
Service -> Repository: findById(meetingId)
activate Repository
Repository -> DB: 회의 정보 조회\n(회의ID 기준)
activate DB
DB --> Repository: meeting_row
deactivate DB
Repository --> Service: Meeting entity
deactivate Repository
Service -> Domain: confirmTranscript()
activate Domain
Domain -> Domain: validateCanConfirm()
note right of Domain
회의록 확정 검증 규칙:
1. 상태 검증:
- 회의 상태 = COMPLETED (종료됨)
- 회의록 상태 = DRAFT (작성중)
✗ IN_PROGRESS → 400 Bad Request
2. 권한 검증:
- 확정 요청자 = 회의 생성자 OR
- 확정 요청자 ∈ 참석자 목록
✗ 권한 없음 → 403 Forbidden
3. 필수 항목 검증:
- 회의록 제목: NOT NULL, 길이 >= 5
- 참석자 목록: 최소 1명 이상
- 주요 논의 내용: NOT NULL, 길이 >= 20
- 결정 사항: 최소 1개 이상 OR
"결정사항 없음" 명시적 표시
✗ 누락 → 400 Bad Request
(누락 항목 목록 반환)
4. 데이터 무결성:
- 섹션별 내용 완결성 확인
- 참조 링크 유효성 확인
- 첨부 파일 접근 가능 여부
✗ 무결성 위반 → 400 Bad Request
5. 이력 검증:
- 마지막 수정 후 24시간 경과 경고
- 미승인 AI 제안 존재 시 알림
⚠️ 경고만 표시, 진행 가능
end note
Domain -> Domain: changeStatus(CONFIRMED)
Domain --> Service: updated Meeting
deactivate Domain
Service -> TranscriptService: lockTranscript(meetingId)
activate TranscriptService
note right of TranscriptService
회의록 잠금:
- 더 이상 수정 불가
- 버전 고정
end note
TranscriptService --> Service: lockedTranscript
deactivate TranscriptService
Service -> Repository: save(meeting)
activate Repository
Repository -> DB: 회의 상태 업데이트\n(상태='확정', 확정일시)
activate DB
DB --> Repository: affected_rows
deactivate DB
Repository --> Service: savedMeeting
deactivate Repository
Service -> Cache: SET meeting:{id}\n(TTL: 10분)
activate Cache
note right of Cache
회의 정보 캐싱:
- TTL: 10분
- 자동 만료
end note
Cache --> Service: OK
deactivate Cache
Service ->> EventHub: publish(MinutesFinalized)
activate EventHub
note right of EventHub
비동기 이벤트:
- 참석자에게 최종본 알림
- 공유 서비스로 전송
end note
deactivate EventHub
Service --> Controller: MeetingResponse
deactivate Service
Controller --> Gateway: 200 OK
deactivate Controller
@enduml

View File

@ -0,0 +1,74 @@
@startuml Todo완료및회의록반영
!theme mono
title Todo 완료 및 회의록 반영 플로우
actor "담당자" as User
participant "Web App" as Web
participant "API Gateway" as Gateway
participant "Meeting Service" as Meeting
participant "Redis Cache" as Redis
participant "Notification Service" as Notification
note over Gateway
라우팅 규칙:
/api/meetings/** → Meeting Service
/api/minutes/** → Meeting Service
/api/dashboard → User Service
/api/notifications/** → Notification Service
/api/auth/** → User Service
/api/todos/** → Meeting Service
end note
autonumber
== Todo 완료 처리 ==
User -> Web: Todo 완료 버튼 클릭
activate Web
Web -> Gateway: PATCH /api/todos/{todoId}/complete\n(userId, userName, completedAt)
activate Gateway
Gateway -> Meeting: PATCH /todos/{todoId}/complete\n(userId, userName, completedAt)
activate Meeting
Meeting -> Meeting: Todo 상태 업데이트\n- 완료 시간 기록\n- 완료자 정보 저장\n- 상태: COMPLETED
Meeting -> Meeting: 관련 회의록에 완료 상태 반영\n- 회의록 섹션 업데이트\n- 완료 표시 (체크 아이콘)\n- 완료 시간 및 완료자 기록
Meeting -> Meeting: DB에 저장
== 캐시 무효화 ==
Meeting --> Redis: DELETE dashboard:{assigneeId}
note right
대시보드 캐시 무효화
end note
Meeting --> Redis: DELETE minutes:detail:{minutesId}
note right
회의록 상세 캐시 무효화
end note
== 이벤트 발행 ==
Meeting -> Notification: NotificationRequest 이벤트 발행
activate Notification
note right
이벤트 데이터:
- 발송수단: EMAIL
- 대상자: 회의록 작성자
- 메시지: Todo 완료 안내
- 메타데이터: todoId, 완료자, 완료 시간
end note
Meeting --> Gateway: 200 OK\n{todoId, status: COMPLETED,\ncompletedAt, completedBy}
deactivate Meeting
Gateway --> Web: 200 OK\n(Todo 완료 정보)
deactivate Gateway
Web --> User: Todo 완료 표시
deactivate Web
== 알림 발송 ==
Notification -> Notification: NotificationRequest 이벤트 구독
Notification -> Notification: 알림 메시지 생성\n- 수신자: 회의록 작성자\n- 내용: "Todo 완료됨"
Notification --> Notification: 이메일 발송\n(회의록 작성자에게)
note right
외부 Email Service 연동
end note
deactivate Notification
@enduml

View File

@ -0,0 +1,113 @@
@startuml 대시보드조회
!theme mono
title 대시보드조회 외부 시퀀스
actor "사용자" as User
participant "Web App" as Frontend
participant "API Gateway" as Gateway
participant "User Service" as UserService
participant "Meeting Service" as MeetingService
database "Redis Cache" as Cache
database "User DB" as UserDB
database "Meeting DB" as MeetingDB
note over Gateway
라우팅 규칙:
/api/meetings/** → Meeting Service
/api/minutes/** → Meeting Service
/api/dashboard → User Service
/api/notifications/** → Notification Service
/api/auth/** → User Service
/api/todos/** → Meeting Service
end note
User -> Frontend: 대시보드 접근
activate Frontend
Frontend -> Gateway: GET /api/dashboard?\npage=1&size=10&sort=createdAt,desc
note right
페이지네이션 파라미터:
- page: 페이지 번호 (기본값: 1)
- size: 페이지 크기 (기본값: 10)
- sort: 정렬 기준 (기본값: createdAt,desc)
end note
activate Gateway
Gateway -> UserService: GET /dashboard?\npage=1&size=10&sort=createdAt,desc
activate UserService
' 캐시 조회
UserService -> Cache: GET dashboard:{userId}
activate Cache
Cache --> UserService: 캐시 조회 결과
deactivate Cache
alt Cache Hit
UserService -> UserService: 캐시 데이터 반환
else Cache Miss
par 병렬 데이터 조회
' Meeting Service 호출
UserService -> MeetingService: GET /api/v1/dashboard
note right
Meeting Service에서 조회:
- 예정된 회의 목록
- 진행 중 Todo 목록
- 최근 회의록 목록
- 공유받은 회의록
- 통계 정보
end note
activate MeetingService
MeetingService -> Cache: GET dashboard:{userId}
activate Cache
Cache --> MeetingService: 캐시 조회 결과
deactivate Cache
alt Meeting Service 캐시 미존재
MeetingService -> MeetingDB: 회의/Todo/회의록 데이터 조회
activate MeetingDB
MeetingDB --> MeetingService: 조회 결과
deactivate MeetingDB
MeetingService -> Cache: SET dashboard:{userId}\n(TTL: 5분)
activate Cache
Cache --> MeetingService: 캐시 저장
deactivate Cache
end
MeetingService --> UserService: 회의 관련 데이터 응답\n{\n "upcomingMeetings": [...],\n "activeTodos": [...],\n "recentMinutes": [...],\n "sharedMinutes": [...],\n "statistics": {...}\n}
deactivate MeetingService
else
' User Service 자체 데이터 조회
UserService -> UserDB: 최근 활동 내역 조회
activate UserDB
UserDB --> UserService: 활동 내역
deactivate UserDB
end
UserService -> UserService: 데이터 통합 및 조합
note right
대시보드 데이터 구성:
- Meeting Service 데이터
- User Service 활동 내역
- 통합 통계 정보
end note
UserService -> Cache: SET dashboard:{userId}\n(TTL: 5분)
activate Cache
Cache --> UserService: 캐시 저장 완료
deactivate Cache
end
UserService --> Gateway: 대시보드 데이터 응답\n{\n "upcomingMeetings": [...],\n "activeTodos": [...],\n "recentMinutes": [...],\n "recentActivities": [...],\n "statistics": {...},\n "pagination": {\n "page": 1,\n "size": 10,\n "totalElements": 45,\n "totalPages": 5,\n "hasNext": true\n }\n}
deactivate UserService
Gateway --> Frontend: 200 OK\n대시보드 데이터 + 페이지네이션 정보
deactivate Gateway
Frontend -> Frontend: 대시보드 화면 렌더링\n- 예정된 회의 표시\n- Todo 목록 표시\n- 최근 회의록 표시\n- 통계 차트 표시
Frontend --> User: 대시보드 화면 표시
deactivate Frontend
@enduml

View File

@ -33,7 +33,7 @@ activate Gateway
Gateway -> Meeting: POST /meetings/{meetingId}/start Gateway -> Meeting: POST /meetings/{meetingId}/start
activate Meeting activate Meeting
Meeting -> Meeting: 회의 세션 생성\n- Session 객체 생성\n- Minutes 초기화 (DRAFT)\n- WebSocket URL 생성 Meeting -> Meeting: 회의 세션 생성
Meeting -> STT: POST /stt/recording/start\n(meetingId, participantIds) Meeting -> STT: POST /stt/recording/start\n(meetingId, participantIds)
activate STT activate STT
@ -47,7 +47,7 @@ STT -> STT: 음성 녹음 준비 및 시작
STT --> Meeting: 200 OK (recordingId) STT --> Meeting: 200 OK (recordingId)
deactivate STT deactivate STT
Meeting --> Gateway: 201 Created\n- sessionId\n- meetingId\n- minutesId\n- status (IN_PROGRESS)\n- websocketUrl\n- sessionToken\n- startedAt\n- expiresAt Meeting --> Gateway: 201 Created
deactivate Meeting deactivate Meeting
Gateway --> Frontend: 201 Created Gateway --> Frontend: 201 Created

View File

@ -27,7 +27,7 @@ end note
User -> WebApp: 회의 정보 입력\n(제목, 날짜/시간, 장소, 참석자) User -> WebApp: 회의 정보 입력\n(제목, 날짜/시간, 장소, 참석자)
activate WebApp activate WebApp
WebApp -> Gateway: POST /api/meetings/reserve\n+ JWT 토큰\n+ 사용자 정보 (userId, userName, email) WebApp -> Gateway: POST /api/meetings\n+ JWT 토큰\n+ 사용자 정보 (userId, userName, email)
activate Gateway activate Gateway
Gateway -> Meeting: 회의 생성 요청 Gateway -> Meeting: 회의 생성 요청
@ -69,30 +69,6 @@ deactivate Gateway
WebApp --> User: 회의 예약 완료 표시\n캘린더에 자동 등록 WebApp --> User: 회의 예약 완료 표시\n캘린더에 자동 등록
deactivate WebApp deactivate WebApp
== 템플릿 선택 (선택 사항) ==
User -> WebApp: 템플릿 선택\n(일반, 스크럼, 킥오프, 주간)
activate WebApp
WebApp -> Gateway: PUT /api/meetings/{meetingId}/template\n+ JWT 토큰\n+ templateId
activate Gateway
Gateway -> Meeting: 템플릿 적용 요청
activate Meeting
Meeting -> MeetingDB: 템플릿 정보 저장
activate MeetingDB
MeetingDB --> Meeting: 저장 완료
deactivate MeetingDB
Meeting --> Gateway: 200 OK\n템플릿 적용 완료
deactivate Meeting
Gateway --> WebApp: 템플릿 적용 응답
deactivate Gateway
WebApp --> User: 템플릿 적용 완료
deactivate WebApp
== 참석자 초대 알림 (비동기) == == 참석자 초대 알림 (비동기) ==
EventHub -> Notification: NotificationRequest 이벤트 수신\n(Consumer Group: notification-service-group) EventHub -> Notification: NotificationRequest 이벤트 수신\n(Consumer Group: notification-service-group)

View File

@ -32,15 +32,8 @@ note right
end note end note
Gateway -> Meeting: 회의 종료 요청 Gateway -> Meeting: 회의 종료 요청
Meeting -> Meeting: 회의 종료 처리\n- 종료 시간 기록\n- 회의록 생성 (DRAFT 상태)\n- 회의 통계 생성\n (총 시간, 참석자 수 등) Meeting -> Meeting: 회의 종료 처리\n- 종료 시간 기록\n- 회의 통계 생성\n (총 시간, 참석자 수, 발언 횟수 등)
Meeting -> Meeting: DB 저장
Meeting -> AI: AI 분석 요청\n- 키워드 추출\n- 안건별 요약 생성\n- Todo 항목 추출
activate AI
AI -> AI: AI 분석 수행
AI --> Meeting: AI 분석 결과\n(keywords, agendaSummaries, todos)
deactivate AI
Meeting -> Meeting: DB 저장\n- Meeting 종료 상태\n- Minutes 생성 (DRAFT)\n- AgendaSection 저장\n- Todo 저장
Meeting -> Meeting: Redis 캐시 무효화\n(meeting:info:{meetingId}) Meeting -> Meeting: Redis 캐시 무효화\n(meeting:info:{meetingId})
Meeting -> EventHub: MeetingEnded 이벤트 발행\n(meetingId, userId, endTime) Meeting -> EventHub: MeetingEnded 이벤트 발행\n(meetingId, userId, endTime)
@ -62,9 +55,9 @@ end note
EventHub --> Meeting: 발행 완료 EventHub --> Meeting: 발행 완료
deactivate EventHub deactivate EventHub
Meeting -> Gateway: 200 OK\n- minutesId\n- 회의 통계 (참석자 수, 시간, 안건 수, Todo 수)\n- 키워드 목록\n- 안건별 AI 요약 (한줄 요약, 상세 요약)\n- Todo 목록 Meeting -> Gateway: 202 Accepted\n(회의 종료 완료)
Gateway -> WebApp: 회의 종료 완료 응답\n(MeetingEndResponse) Gateway -> WebApp: 회의 종료 완료 응답
WebApp -> User: 회의 종료 화면 표시\n- 통계 카드\n- 키워드 태그\n- 안건 아코디언 (AI 요약 + Todo) WebApp -> User: 회의 통계 표시\n(총 시간, 참석자, 발언 횟수 등)
== 비동기 처리 - STT 종료 == == 비동기 처리 - STT 종료 ==
EventHub --> STT: MeetingEnded 이벤트 수신 EventHub --> STT: MeetingEnded 이벤트 수신
@ -83,62 +76,43 @@ note right
end note end note
== 최종 회의록 확정 == == 최종 회의록 확정 ==
User -> WebApp: 최종 회의록 확정 버튼 클릭\n(회의록 수정 화면 또는 회의 종료 화면) User -> WebApp: 최종 회의록 확정 버튼 클릭
WebApp -> Gateway: POST /api/meetings/minutes/{minutesId}/finalize WebApp -> Gateway: POST /api/minutes/{minutesId}/finalize
note right note right
요청 헤더에 JWT 토큰 포함 요청 헤더에 JWT 토큰 포함
X-User-Id, X-User-Name, X-User-Email 요청 바디에 사용자 정보 포함
end note end note
Gateway -> Meeting: 회의록 확정 요청 Gateway -> Meeting: 회의록 확정 요청
Meeting -> Meeting: 회의록 상태 변경\n- DRAFT → FINALIZED\n- finalizedAt 기록\n- finalizedBy 기록 Meeting -> Meeting: 필수 항목 검사\n- 회의 제목\n- 참석자 목록\n- 주요 논의 내용\n- 결정 사항
Meeting -> Meeting: DB 저장\n- Minutes 상태 업데이트 alt 필수 항목 미작성
Meeting -> Meeting: Redis 캐시 저장\n(확정된 회의록, TTL: 10분) Meeting -> Gateway: 400 Bad Request\n(누락된 항목 정보)
Meeting -> Meeting: Redis 목록 캐시 무효화\n(사용자별 회의록 목록) Gateway -> WebApp: 검증 실패 응답
WebApp -> User: 누락된 항목 안내\n(해당 섹션으로 자동 이동)
else 필수 항목 작성 완료
Meeting -> Meeting: 회의록 최종 확정\n- 확정 버전 생성\n- 확정 시간 기록
Meeting -> Meeting: DB 저장 (MinutesVersion)
Meeting -> Meeting: Redis 캐시 무효화
Meeting -> EventHub: MinutesFinalizedEvent 발행\n(알림용 - 기존) Meeting -> EventHub: NotificationRequest 이벤트 발행\n(회의록 확정 알림)
activate EventHub activate EventHub
note right note right
간단한 이벤트 데이터: 이벤트 데이터:
- minutesId - 발송수단: EMAIL
- title - 대상자: 참석자 전원
- userId - 메시지: 회의록 확정 안내
- userName - 메타데이터: 버전 번호, 확정 시간
end note end note
EventHub --> Meeting: 발행 완료 EventHub --> Meeting: 발행 완료
deactivate EventHub deactivate EventHub
Meeting -> EventHub: MinutesFinalizedEvent 발행\n(RAG용 - 완전한 데이터) Meeting -> Gateway: 200 OK\n(확정 버전 정보)
activate EventHub Gateway -> WebApp: 회의록 확정 완료
note right WebApp -> User: 확정 완료 안내\n(버전 번호, 확정 시간)
완전한 이벤트 데이터:
- Meeting 정보 (meetingId, title, purpose, scheduledAt 등)
- Minutes 정보 (minutesId, status, version 등)
- Sections 정보 (모든 안건 섹션)
- 참석자 정보
end note
EventHub --> Meeting: 발행 완료
deactivate EventHub
Meeting -> Gateway: 200 OK\n(확정된 회의록 상세 정보) EventHub --> Notification: NotificationRequest 이벤트 수신
Gateway -> WebApp: 회의록 확정 완료 Notification -> Notification: 회의록 확정 알림 발송\n(참석자 전원)
WebApp -> User: 확정 완료 토스트 표시\n회의록 상세 조회 화면으로 이동 end
== 비동기 처리 - 알림 발송 ==
EventHub --> Notification: MinutesFinalizedEvent 수신\n(알림용)
Notification -> Notification: 회의록 확정 알림 발송\n(참석자 전원)
note right
알림 내용:
- 회의 제목
- 확정 시간
- 회의록 링크
end note
== 비동기 처리 - RAG 저장 ==
EventHub --> AI: MinutesFinalizedEvent 수신\n(RAG용)
activate AI
AI -> AI: RAG 서비스 연동\n- 벡터 DB 저장\n- 관련 회의록 검색 준비
deactivate AI
@enduml @enduml

Binary file not shown.

Before

Width:  |  Height:  |  Size: 566 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB