mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 11:26:25 +00:00
외부 시퀀스 설계 가이드 및 설계서 추가
- 외부 시퀀스 설계 가이드 다운로드 (claude/sequence-outer-design.md) - 외부 시퀀스 설계 디렉토리 생성 (design/backend/sequence/) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
550cbb9be1
commit
e1d411e989
54
claude/sequence-outer-design.md
Normal file
54
claude/sequence-outer-design.md
Normal file
@ -0,0 +1,54 @@
|
||||
# 외부시퀀스설계가이드
|
||||
|
||||
[요청사항]
|
||||
- <작성원칙>을 준용하여 설계
|
||||
- <작성순서>에 따라 설계
|
||||
- [결과파일] 안내에 따라 파일 작성
|
||||
|
||||
[가이드]
|
||||
<작성원칙>
|
||||
- **유저스토리와 매칭**되어야 함. **불필요한 추가 설계 금지**
|
||||
- **논리아키텍처에 정의한 참여자와 일치**해야 함
|
||||
- UI/UX설계서의 '사용자 플로우'참조하여 설계
|
||||
- **해당 플로우에 참여하는** 프론트엔드, 모든 서비스, 인프라 컴포넌트(예: Gateway, Message Queue, Database), 외부시스템을 참여자로 추가
|
||||
- 플로우에 참여자들의 역할과 책임을 명확히 표시
|
||||
- 플로우 수행에 필요한 프론트엔드부터 End-to-End 호출을 순서대로 표시하고 한글 설명 추가
|
||||
- 마이크로서비스 내부의 처리 흐름은 표시하지 않음
|
||||
- 동기/비동기 통신 구분 (실선/점선)
|
||||
- 캐시, 큐 등 인프라 컴포넌트와의 상호작용 포함
|
||||
<작성순서>
|
||||
- 준비:
|
||||
- 유저스토리, UI/UX설계서, 논리아키텍처 분석 및 이해
|
||||
- "@analyze --play" 프로토타입이 있는 경우 웹브라우저에서 실행하여 서비스 이해
|
||||
- 실행:
|
||||
- <플로우 분류기준>에 따라 최적의 플로우를 결정함
|
||||
- 외부시퀀스설계서 작성
|
||||
- <병렬수행>가이드에 따라 병렬 수행
|
||||
- **PlantUML 스크립트 파일 생성 즉시 검사 실행**: 'PlantUML 문법 검사 가이드' 준용
|
||||
- 검토:
|
||||
- <작성원칙> 준수 검토
|
||||
- 스쿼드 팀원 리뷰: 누락 및 개선 사항 검토
|
||||
- 수정 사항 선택 및 반영
|
||||
<플로우 분류기준>
|
||||
- **핵심 비즈니스 플로우별**: 사용자가 목표를 달성하기 위한 주요 업무 흐름
|
||||
- **통합 패턴별**: 동기/비동기, 캐시 활용, 외부 연동 등 기술적 통합 방식
|
||||
- **사용자 시나리오별**: 엔드투엔드 사용자 경험 기준
|
||||
- **데이터 흐름별**: 데이터의 생성, 변환, 저장 과정
|
||||
<병렬수행>
|
||||
- **서브 에이전트를 활용한 병렬 작성 필수**
|
||||
- 서비스별 독립적인 에이전트가 각 외부시퀀스설계를 동시에 작업
|
||||
- 모든 설계 완료 후 전체 검증
|
||||
|
||||
[참고자료]
|
||||
- 유저스토리
|
||||
- UI/UX설계서
|
||||
- 논리아키텍처
|
||||
- 프로토타입
|
||||
|
||||
[예시]
|
||||
- 링크: https://raw.githubusercontent.com/cna-bootcamp/clauding-guide/refs/heads/main/samples/sample-시퀀스설계서(외부).puml
|
||||
|
||||
[결과파일]
|
||||
- **주요 비즈니스 플로우별로 파일을 분리하여 작성**
|
||||
- 플로우명은 한글로 네이밍
|
||||
- 위치: design/backend/sequence/outer/{플로우명}.puml
|
||||
164
design/backend/sequence/outer/01-사용자인증및대시보드조회.puml
Normal file
164
design/backend/sequence/outer/01-사용자인증및대시보드조회.puml
Normal file
@ -0,0 +1,164 @@
|
||||
@startuml 01-사용자인증및대시보드조회
|
||||
!theme mono
|
||||
|
||||
title 사용자 인증 및 대시보드 조회 (User Authentication and Dashboard)
|
||||
|
||||
actor "사용자" as User
|
||||
participant "Web App" as WebApp
|
||||
participant "API Gateway" as Gateway
|
||||
participant "User Service" as UserService
|
||||
participant "Meeting Service" as MeetingService
|
||||
participant "Todo Service" as TodoService
|
||||
participant "Redis\n(Cache)" as Redis
|
||||
database "User DB\n(PostgreSQL)" as UserDB
|
||||
database "Meeting DB\n(PostgreSQL)" as MeetingDB
|
||||
database "Todo DB\n(PostgreSQL)" as TodoDB
|
||||
|
||||
== 1. 사용자 인증 (User Authentication) ==
|
||||
|
||||
User -> WebApp: 1.1. 로그인 시도\n(사번, 비밀번호 입력)
|
||||
activate WebApp
|
||||
|
||||
WebApp -> Gateway: 1.2. POST /api/auth/login\n{employeeId, password}
|
||||
activate Gateway
|
||||
|
||||
Gateway -> UserService: 1.3. 인증 요청\nPOST /auth/login
|
||||
activate UserService
|
||||
|
||||
UserService -> UserService: 1.4. LDAP 연동 인증\n(사번, 비밀번호 검증)
|
||||
note right
|
||||
LDAP 서버와 통신하여
|
||||
사용자 인증 처리
|
||||
end note
|
||||
|
||||
alt 인증 성공
|
||||
UserService -> UserDB: 1.5. 사용자 정보 조회\nSELECT * FROM users WHERE employee_id = ?
|
||||
activate UserDB
|
||||
UserDB --> UserService: 사용자 정보 반환
|
||||
deactivate UserDB
|
||||
|
||||
UserService -> UserService: 1.6. JWT 토큰 생성\n(userId, 권한 정보 포함)
|
||||
|
||||
UserService -> Redis: 1.7. 사용자 프로필 캐싱\nSET user:profile:{userId}\n(TTL: 30분)
|
||||
activate Redis
|
||||
Redis --> UserService: 캐싱 완료
|
||||
deactivate Redis
|
||||
|
||||
UserService --> Gateway: 1.8. 인증 성공 응답\n{token, userId, userName}
|
||||
deactivate UserService
|
||||
|
||||
Gateway --> WebApp: 1.9. 로그인 성공\n{token, userId, userName}
|
||||
deactivate Gateway
|
||||
|
||||
WebApp -> WebApp: 1.10. JWT 토큰 저장\n(LocalStorage)
|
||||
|
||||
WebApp --> User: 1.11. 로그인 성공 메시지
|
||||
|
||||
else 인증 실패
|
||||
UserService --> Gateway: 인증 실패 (401 Unauthorized)
|
||||
Gateway --> WebApp: 인증 실패
|
||||
WebApp --> User: 로그인 실패 메시지
|
||||
end
|
||||
|
||||
== 2. 대시보드 데이터 조회 (Dashboard Data Loading) ==
|
||||
|
||||
WebApp -> Gateway: 2.1. GET /api/dashboard\n(Authorization: Bearer {token})
|
||||
activate Gateway
|
||||
|
||||
Gateway -> Gateway: 2.2. JWT 토큰 검증
|
||||
note right
|
||||
토큰 유효성 검증
|
||||
사용자 권한 확인
|
||||
end note
|
||||
|
||||
Gateway -> MeetingService: 2.3. 예정된 회의 조회\nGET /meetings/upcoming?userId={userId}
|
||||
activate MeetingService
|
||||
|
||||
MeetingService -> Redis: 2.4. 캐시 확인\nGET meeting:upcoming:{userId}
|
||||
activate Redis
|
||||
Redis --> MeetingService: Cache Miss (캐시 없음)
|
||||
deactivate Redis
|
||||
|
||||
MeetingService -> MeetingDB: 2.5. 예정된 회의 조회\nSELECT * FROM meetings\nWHERE user_id = ? AND status = 'SCHEDULED'\nORDER BY meeting_date LIMIT 5
|
||||
activate MeetingDB
|
||||
MeetingDB --> MeetingService: 예정된 회의 목록 (최대 5개)
|
||||
deactivate MeetingDB
|
||||
|
||||
MeetingService -> Redis: 2.6. 조회 결과 캐싱\nSET meeting:upcoming:{userId}\n(TTL: 10분)
|
||||
activate Redis
|
||||
Redis --> MeetingService: 캐싱 완료
|
||||
deactivate Redis
|
||||
|
||||
MeetingService --> Gateway: 2.7. 예정된 회의 목록 반환
|
||||
deactivate MeetingService
|
||||
|
||||
|||
|
||||
|
||||
Gateway -> TodoService: 2.8. 진행 중 Todo 조회\nGET /todos/in-progress?userId={userId}
|
||||
activate TodoService
|
||||
|
||||
TodoService -> Redis: 2.9. 캐시 확인\nGET todo:user:{userId}
|
||||
activate Redis
|
||||
Redis --> TodoService: Cache Hit (캐시 존재)
|
||||
note right
|
||||
Cache-Aside 패턴:
|
||||
캐시에서 직접 반환하여
|
||||
DB 부하 감소
|
||||
end note
|
||||
deactivate Redis
|
||||
|
||||
TodoService --> Gateway: 2.10. 진행 중 Todo 목록 반환\n(캐시에서 조회)
|
||||
deactivate TodoService
|
||||
|
||||
|||
|
||||
|
||||
Gateway -> MeetingService: 2.11. 최근 회의록 조회\nGET /transcripts/recent?userId={userId}
|
||||
activate MeetingService
|
||||
|
||||
MeetingService -> Redis: 2.12. 캐시 확인\nGET transcript:recent:{userId}
|
||||
activate Redis
|
||||
Redis --> MeetingService: Cache Miss
|
||||
deactivate Redis
|
||||
|
||||
MeetingService -> MeetingDB: 2.13. 최근 회의록 조회\nSELECT * FROM transcripts\nWHERE user_id = ? OR shared_with LIKE '%{userId}%'\nORDER BY created_at DESC LIMIT 6
|
||||
activate MeetingDB
|
||||
MeetingDB --> MeetingService: 최근 회의록 목록\n(내 회의록 3개 + 공유받은 회의록 3개)
|
||||
deactivate MeetingDB
|
||||
|
||||
MeetingService -> Redis: 2.14. 조회 결과 캐싱\nSET transcript:recent:{userId}\n(TTL: 10분)
|
||||
activate Redis
|
||||
Redis --> MeetingService: 캐싱 완료
|
||||
deactivate Redis
|
||||
|
||||
MeetingService --> Gateway: 2.15. 최근 회의록 목록 반환
|
||||
deactivate MeetingService
|
||||
|
||||
|||
|
||||
|
||||
Gateway -> TodoService: 2.16. Todo 통계 조회\nGET /todos/stats?userId={userId}
|
||||
activate TodoService
|
||||
|
||||
TodoService -> Redis: 2.17. 캐시 확인\nGET todo:stats:{userId}
|
||||
activate Redis
|
||||
Redis --> TodoService: Cache Hit
|
||||
deactivate Redis
|
||||
|
||||
TodoService --> Gateway: 2.18. Todo 통계 반환\n{total, inProgress, completionRate}
|
||||
deactivate TodoService
|
||||
|
||||
|||
|
||||
|
||||
Gateway --> WebApp: 2.19. 대시보드 데이터 통합 응답\n{\n upcomingMeetings: [...],\n inProgressTodos: [...],\n recentTranscripts: [...],\n todoStats: {...}\n}
|
||||
deactivate Gateway
|
||||
|
||||
WebApp -> WebApp: 2.20. 대시보드 UI 렌더링\n- 통계 카드 표시\n- 예정된 회의 목록\n- 진행 중 Todo 목록\n- 최근 회의록 목록
|
||||
note right
|
||||
반응형 레이아웃:
|
||||
- 데스크톱: 좌측 사이드바
|
||||
- 모바일: 하단 탭 바
|
||||
end note
|
||||
|
||||
WebApp --> User: 2.21. 대시보드 화면 표시\n(맞춤형 정보 제공)
|
||||
deactivate WebApp
|
||||
|
||||
@enduml
|
||||
186
design/backend/sequence/outer/02-회의예약및초대.puml
Normal file
186
design/backend/sequence/outer/02-회의예약및초대.puml
Normal file
@ -0,0 +1,186 @@
|
||||
@startuml 02-회의예약및초대
|
||||
!theme mono
|
||||
|
||||
title 회의 예약 및 초대 (Meeting Reservation and Invitation)
|
||||
|
||||
actor "사용자\n(회의록 작성자)" as User
|
||||
participant "Web App" as WebApp
|
||||
participant "API Gateway" as Gateway
|
||||
participant "Meeting Service" as MeetingService
|
||||
participant "User Service" as UserService
|
||||
participant "Notification Service" as NotificationService
|
||||
participant "RabbitMQ\n(Message Broker)" as RabbitMQ
|
||||
participant "Redis\n(Cache)" as Redis
|
||||
database "Meeting DB\n(PostgreSQL)" as MeetingDB
|
||||
database "User DB\n(PostgreSQL)" as UserDB
|
||||
database "Notification DB\n(PostgreSQL)" as NotificationDB
|
||||
|
||||
== 1. 회의 예약 (Meeting Reservation) ==
|
||||
|
||||
User -> WebApp: 1.1. 회의 예약 화면 접근\n(플로팅 액션 버튼 → 📅 회의 예약)
|
||||
activate WebApp
|
||||
|
||||
WebApp --> User: 1.2. 회의 예약 폼 표시\n(제목, 날짜/시간, 장소, 참석자)
|
||||
note right
|
||||
입력 필드:
|
||||
- 회의 제목 (최대 100자, 필수)
|
||||
- 날짜/시간 (필수)
|
||||
- 장소 (최대 200자, 선택)
|
||||
- 참석자 목록 (이메일, 최소 1명 필수)
|
||||
end note
|
||||
|
||||
User -> WebApp: 1.3. 회의 정보 입력 완료\n- 제목: "프로젝트 킥오프 회의"\n- 날짜: 2025-02-01 14:00\n- 장소: "회의실 A"\n- 참석자: ["user1@company.com", "user2@company.com"]
|
||||
|
||||
WebApp -> WebApp: 1.4. 입력 유효성 검증\n- 필수 필드 확인\n- 날짜/시간 형식 검증\n- 이메일 형식 검증
|
||||
|
||||
WebApp -> Gateway: 1.5. POST /api/meetings\n{\n title: "프로젝트 킥오프 회의",\n dateTime: "2025-02-01T14:00:00",\n location: "회의실 A",\n participants: ["user1@company.com", "user2@company.com"]\n}\n(Authorization: Bearer {token})
|
||||
activate Gateway
|
||||
|
||||
Gateway -> Gateway: 1.6. JWT 토큰 검증\n- 사용자 인증 확인\n- 회의 생성 권한 확인
|
||||
|
||||
Gateway -> MeetingService: 1.7. 회의 생성 요청\nPOST /meetings
|
||||
activate MeetingService
|
||||
|
||||
MeetingService -> MeetingService: 1.8. 회의 데이터 생성\n- 회의 ID 생성 (UUID)\n- 생성 시간 기록\n- 상태: SCHEDULED
|
||||
|
||||
MeetingService -> MeetingDB: 1.9. 회의 정보 저장\nINSERT INTO meetings\n(id, title, date_time, location, creator_id, status, created_at)\nVALUES (?, ?, ?, ?, ?, 'SCHEDULED', NOW())
|
||||
activate MeetingDB
|
||||
MeetingDB --> MeetingService: 회의 생성 완료
|
||||
deactivate MeetingDB
|
||||
|
||||
MeetingService -> MeetingDB: 1.10. 참석자 정보 저장\nINSERT INTO meeting_participants\n(meeting_id, user_email, role)\nVALUES (?, ?, 'PARTICIPANT')
|
||||
activate MeetingDB
|
||||
MeetingDB --> MeetingService: 참석자 저장 완료
|
||||
deactivate MeetingDB
|
||||
|
||||
MeetingService -> Redis: 1.11. 회의 정보 캐싱\nSET meeting:info:{meetingId}\n{\n title, dateTime, location,\n participants, status\n}\n(TTL: 10분)
|
||||
activate Redis
|
||||
Redis --> MeetingService: 캐싱 완료
|
||||
note right
|
||||
Cache-Aside 패턴:
|
||||
생성 즉시 캐싱하여
|
||||
후속 조회 성능 향상
|
||||
end note
|
||||
deactivate Redis
|
||||
|
||||
== 2. 이벤트 발행 (Event Publishing) ==
|
||||
|
||||
MeetingService -> RabbitMQ: 1.12. MeetingCreated 이벤트 발행\n- Exchange: meeting.events\n- Routing Key: meeting.created\n- Payload: {\n meetingId,\n title,\n dateTime,\n location,\n creatorId,\n participants: [user1@company.com, user2@company.com]\n }
|
||||
activate RabbitMQ
|
||||
note right
|
||||
Publisher-Subscriber 패턴:
|
||||
이벤트 기반 느슨한 결합
|
||||
end note
|
||||
|
||||
RabbitMQ --> MeetingService: 1.13. 이벤트 발행 성공
|
||||
deactivate RabbitMQ
|
||||
|
||||
MeetingService --> Gateway: 1.14. 회의 생성 응답\n{\n meetingId,\n title,\n dateTime,\n location,\n status: "SCHEDULED",\n createdAt\n}
|
||||
deactivate MeetingService
|
||||
|
||||
Gateway --> WebApp: 1.15. 회의 예약 성공 응답
|
||||
deactivate Gateway
|
||||
|
||||
WebApp --> User: 1.16. 예약 완료 메시지 표시\n"회의가 성공적으로 예약되었습니다."
|
||||
deactivate WebApp
|
||||
|
||||
== 3. 초대 알림 발송 (Invitation Notification) ==
|
||||
|
||||
RabbitMQ -> NotificationService: 2.1. MeetingCreated 이벤트 수신\n- Queue: notification.meeting.queue
|
||||
activate NotificationService
|
||||
activate RabbitMQ
|
||||
|
||||
NotificationService -> NotificationService: 2.2. 이벤트 처리\n- 참석자 목록 추출\n- 알림 템플릿 로딩
|
||||
|
||||
NotificationService -> UserService: 2.3. 참석자 정보 조회\nGET /users/by-emails?emails=user1@company.com,user2@company.com
|
||||
activate UserService
|
||||
|
||||
UserService -> Redis: 2.4. 캐시 확인\nMGET user:profile:user1, user:profile:user2
|
||||
activate Redis
|
||||
Redis --> UserService: Cache Hit (일부 캐시 존재)
|
||||
deactivate Redis
|
||||
|
||||
UserService -> UserDB: 2.5. 캐시 미스 사용자 DB 조회\nSELECT * FROM users\nWHERE email IN (?, ?)
|
||||
activate UserDB
|
||||
UserDB --> UserService: 사용자 정보 반환
|
||||
deactivate UserDB
|
||||
|
||||
UserService -> Redis: 2.6. 조회 결과 캐싱\nSET user:profile:{userId}\n(TTL: 30분)
|
||||
activate Redis
|
||||
Redis --> UserService: 캐싱 완료
|
||||
deactivate Redis
|
||||
|
||||
UserService --> NotificationService: 2.7. 참석자 정보 반환\n[{userId, name, email}, ...]
|
||||
deactivate UserService
|
||||
|
||||
NotificationService -> NotificationService: 2.8. 알림 메시지 생성\n- 제목: "[회의 초대] 프로젝트 킥오프 회의"\n- 내용: "홍길동님께서 회의에 초대하셨습니다.\n 일시: 2025-02-01 14:00\n 장소: 회의실 A"
|
||||
|
||||
NotificationService -> NotificationDB: 2.9. 알림 기록 저장\nINSERT INTO notifications\n(meeting_id, recipient_email, type, content, status, created_at)\nVALUES (?, ?, 'MEETING_INVITATION', ?, 'PENDING', NOW())
|
||||
activate NotificationDB
|
||||
NotificationDB --> NotificationService: 알림 기록 저장 완료
|
||||
deactivate NotificationDB
|
||||
|
||||
loop 각 참석자에 대해
|
||||
NotificationService -> NotificationService: 2.10. 이메일 발송\n- To: user1@company.com\n- Subject: [회의 초대] 프로젝트 킥오프 회의\n- Body: 회의 상세 정보 + 참여 링크
|
||||
note right
|
||||
Email/SMS Service 연동:
|
||||
- SMTP 또는 SendGrid 사용
|
||||
- 발송 실패 시 재시도 (최대 3회)
|
||||
end note
|
||||
|
||||
NotificationService -> NotificationDB: 2.11. 알림 상태 업데이트\nUPDATE notifications\nSET status = 'SENT', sent_at = NOW()\nWHERE id = ?
|
||||
activate NotificationDB
|
||||
NotificationDB --> NotificationService: 업데이트 완료
|
||||
deactivate NotificationDB
|
||||
end
|
||||
|
||||
NotificationService --> RabbitMQ: 2.12. 이벤트 처리 완료 (ACK)
|
||||
deactivate RabbitMQ
|
||||
|
||||
NotificationService -> NotificationService: 2.13. 리마인더 일정 생성\n- 회의 시작 30분 전 알림\n- 일정: 2025-02-01 13:30
|
||||
note right
|
||||
Queue-Based Load Leveling:
|
||||
리마인더는 별도 큐로 관리
|
||||
(reminder.queue)
|
||||
end note
|
||||
|
||||
deactivate NotificationService
|
||||
|
||||
== 4. 결과 확인 (Result Confirmation) ==
|
||||
|
||||
User -> WebApp: 3.1. 대시보드 화면 새로고침
|
||||
activate WebApp
|
||||
|
||||
WebApp -> Gateway: 3.2. GET /api/dashboard\n(Authorization: Bearer {token})
|
||||
activate Gateway
|
||||
|
||||
Gateway -> MeetingService: 3.3. 예정된 회의 조회\nGET /meetings/upcoming?userId={userId}
|
||||
activate MeetingService
|
||||
|
||||
MeetingService -> Redis: 3.4. 캐시 확인\nGET meeting:upcoming:{userId}
|
||||
activate Redis
|
||||
Redis --> MeetingService: Cache Miss (새로운 회의 추가로 캐시 무효화됨)
|
||||
deactivate Redis
|
||||
|
||||
MeetingService -> MeetingDB: 3.5. 예정된 회의 조회\nSELECT * FROM meetings\nWHERE user_id = ? AND status = 'SCHEDULED'\nORDER BY meeting_date LIMIT 5
|
||||
activate MeetingDB
|
||||
MeetingDB --> MeetingService: 예정된 회의 목록\n(새로 생성한 회의 포함)
|
||||
deactivate MeetingDB
|
||||
|
||||
MeetingService -> Redis: 3.6. 조회 결과 재캐싱\nSET meeting:upcoming:{userId}\n(TTL: 10분)
|
||||
activate Redis
|
||||
Redis --> MeetingService: 캐싱 완료
|
||||
deactivate Redis
|
||||
|
||||
MeetingService --> Gateway: 3.7. 예정된 회의 목록 반환
|
||||
deactivate MeetingService
|
||||
|
||||
Gateway --> WebApp: 3.8. 대시보드 데이터 반환
|
||||
deactivate Gateway
|
||||
|
||||
WebApp -> WebApp: 3.9. 대시보드 UI 업데이트\n- 예정된 회의 개수 증가\n- 새 회의 목록에 표시
|
||||
|
||||
WebApp --> User: 3.10. 업데이트된 대시보드 표시\n(새로 예약한 회의 확인 가능)
|
||||
deactivate WebApp
|
||||
|
||||
@enduml
|
||||
73
design/backend/sequence/outer/03-회의시작및템플릿선택.puml
Normal file
73
design/backend/sequence/outer/03-회의시작및템플릿선택.puml
Normal file
@ -0,0 +1,73 @@
|
||||
@startuml 회의시작및템플릿선택
|
||||
!theme mono
|
||||
|
||||
title 회의 시작 및 템플릿 선택 (Flow 3)
|
||||
|
||||
actor "사용자" as User
|
||||
participant "Web App" as Web
|
||||
participant "API Gateway" as Gateway
|
||||
participant "Meeting Service" as Meeting
|
||||
participant "STT Service" as STT
|
||||
participant "RabbitMQ" as MQ
|
||||
participant "Redis" as Cache
|
||||
database "PostgreSQL" as DB
|
||||
|
||||
== 템플릿 선택 ==
|
||||
User -> Web: 회의 템플릿 선택\n(일반/스크럼/킥오프/주간)
|
||||
Web -> Gateway: GET /api/meetings/templates
|
||||
Gateway -> Meeting: 템플릿 목록 조회
|
||||
Meeting -> Cache: 템플릿 캐시 확인
|
||||
alt 캐시 존재
|
||||
Cache --> Meeting: 템플릿 목록 반환
|
||||
else 캐시 미존재
|
||||
Meeting -> DB: SELECT * FROM templates
|
||||
DB --> Meeting: 템플릿 데이터
|
||||
Meeting -> Cache: 템플릿 캐시 저장
|
||||
end
|
||||
Meeting --> Gateway: 템플릿 목록 응답
|
||||
Gateway --> Web: 200 OK + 템플릿 목록
|
||||
Web --> User: 템플릿 선택 UI 표시
|
||||
|
||||
== 회의 시작 ==
|
||||
User -> Web: 회의 시작 버튼 클릭
|
||||
Web -> Gateway: POST /api/meetings/{meetingId}/start\n+ templateId
|
||||
Gateway -> Meeting: 회의 시작 요청
|
||||
|
||||
Meeting -> DB: BEGIN TRANSACTION
|
||||
Meeting -> DB: UPDATE meetings\nSET status='ongoing',\nstarted_at=NOW()
|
||||
DB --> Meeting: 업데이트 완료
|
||||
|
||||
Meeting -> DB: INSERT INTO meeting_sessions\n(meeting_id, template_id,\nsession_status='active')
|
||||
DB --> Meeting: 세션 생성 완료
|
||||
|
||||
Meeting -> DB: INSERT INTO meeting_transcripts\n(session_id, template_id,\ncontent='{}')
|
||||
DB --> Meeting: 회의록 초기화 완료
|
||||
|
||||
Meeting -> DB: COMMIT
|
||||
Meeting -> Cache: 회의 상태 캐시 업데이트\n(status='ongoing')
|
||||
|
||||
== 이벤트 발행 ==
|
||||
Meeting ->> MQ: Publish "MeetingStarted" Event\n{\n meetingId,\n sessionId,\n templateId,\n startedAt,\n participants\n}
|
||||
note right
|
||||
비동기 이벤트 발행
|
||||
- Exchange: meeting.events
|
||||
- Routing Key: meeting.started
|
||||
end note
|
||||
|
||||
Meeting --> Gateway: 200 OK + sessionId
|
||||
Gateway --> Web: 회의 시작 성공 응답
|
||||
Web --> User: 회의 진행 화면 전환
|
||||
|
||||
== STT 서비스 시작 ==
|
||||
MQ -->> STT: Consume "MeetingStarted" Event
|
||||
STT -> STT: 오디오 녹음 세션 초기화
|
||||
STT -> Cache: 녹음 세션 상태 저장\n(sessionId, status='recording')
|
||||
STT -> STT: 마이크 활성화 및\n오디오 스트림 시작
|
||||
|
||||
note over STT
|
||||
STT 서비스 준비 완료
|
||||
- 5초 단위 음성 인식 시작
|
||||
- 실시간 텍스트 변환 대기
|
||||
end note
|
||||
|
||||
@enduml
|
||||
108
design/backend/sequence/outer/04-회의진행및실시간회의록작성.puml
Normal file
108
design/backend/sequence/outer/04-회의진행및실시간회의록작성.puml
Normal file
@ -0,0 +1,108 @@
|
||||
@startuml 회의진행및실시간회의록작성
|
||||
!theme mono
|
||||
|
||||
title 회의 진행 및 실시간 회의록 작성 (Flow 4)
|
||||
|
||||
actor "참여자 A" as UserA
|
||||
actor "참여자 B" as UserB
|
||||
participant "Web App A\n(WebSocket)" as WebA
|
||||
participant "Web App B\n(WebSocket)" as WebB
|
||||
participant "STT Service" as STT
|
||||
participant "AI Service" as AI
|
||||
participant "Collaboration\nService" as Collab
|
||||
participant "RabbitMQ" as MQ
|
||||
participant "Redis" as Cache
|
||||
database "PostgreSQL" as DB
|
||||
|
||||
== 실시간 음성 인식 (5초 단위) ==
|
||||
loop 5초마다 반복
|
||||
STT -> STT: 오디오 청크 수집\n(5초분)
|
||||
STT -> STT: 음성-텍스트 변환\n(Speech-to-Text)
|
||||
|
||||
STT ->> MQ: Publish "TranscriptReady" Event\n{\n sessionId,\n timestamp,\n speaker: "참여자A",\n text: "변환된 텍스트",\n confidence: 0.95\n}
|
||||
note right
|
||||
비동기 이벤트 발행
|
||||
- Exchange: transcript.events
|
||||
- Routing Key: transcript.ready
|
||||
end note
|
||||
end
|
||||
|
||||
== AI 기반 회의록 자동 생성 ==
|
||||
MQ -->> AI: Consume "TranscriptReady" Event
|
||||
|
||||
AI -> AI: 텍스트 분석 및 구조화\n(키워드, 주제, 맥락 파악)
|
||||
|
||||
AI -> Cache: 템플릿 구조 조회\n(sessionId)
|
||||
Cache --> AI: 템플릿 섹션 정보\n(agenda, decisions, tasks)
|
||||
|
||||
AI -> AI: 템플릿 섹션에 맞춰\n내용 자동 분류
|
||||
note right
|
||||
예시:
|
||||
- "결정사항" → decisions
|
||||
- "TODO" → action_items
|
||||
- "논의내용" → discussions
|
||||
end note
|
||||
|
||||
AI -> DB: INSERT INTO transcript_segments\n(session_id, section,\ncontent, timestamp)
|
||||
DB --> AI: 세그먼트 저장 완료
|
||||
|
||||
AI ->> MQ: Publish "TranscriptUpdated" Event\n{\n sessionId,\n segmentId,\n section,\n content,\n updatedAt\n}
|
||||
|
||||
== 실시간 협업 및 동기화 ==
|
||||
MQ -->> Collab: Consume "TranscriptUpdated" Event
|
||||
|
||||
Collab -> Cache: 현재 회의록 상태 조회
|
||||
Cache --> Collab: 최신 회의록 데이터
|
||||
|
||||
Collab -> Collab: 변경 사항 감지 및\n충돌 검사 (CRDT 알고리즘)
|
||||
|
||||
Collab ->> WebA: WebSocket Push\n{\n type: "transcript.update",\n section: "decisions",\n content: "...",\n author: "AI"\n}
|
||||
Collab ->> WebB: WebSocket Push\n{\n type: "transcript.update",\n section: "decisions",\n content: "...",\n author: "AI"\n}
|
||||
|
||||
WebA --> UserA: 회의록 UI 실시간 업데이트
|
||||
WebB --> UserB: 회의록 UI 실시간 업데이트
|
||||
|
||||
== 참여자 실시간 편집 ==
|
||||
UserA -> WebA: 회의록 내용 수정\n("결정사항" 섹션 편집)
|
||||
WebA ->> Collab: WebSocket Send\n{\n type: "edit",\n section: "decisions",\n content: "수정된 내용",\n cursorPosition: 42\n}
|
||||
|
||||
Collab -> Collab: 동시 편집 충돌 검사\n(Operational Transform)
|
||||
|
||||
alt 충돌 없음
|
||||
Collab -> DB: UPDATE transcript_segments\nSET content='수정된 내용'
|
||||
DB --> Collab: 업데이트 완료
|
||||
|
||||
Collab -> Cache: 최신 회의록 캐시 갱신
|
||||
|
||||
Collab ->> WebB: WebSocket Push\n{\n type: "peer.edit",\n section: "decisions",\n content: "수정된 내용",\n author: "참여자A"\n}
|
||||
WebB --> UserB: 참여자A의 수정사항 반영
|
||||
|
||||
else 충돌 발생
|
||||
Collab -> Collab: 충돌 해결 알고리즘 적용\n(Last-Write-Wins + Merge)
|
||||
|
||||
Collab -> DB: UPDATE transcript_segments\nSET content='병합된 내용'
|
||||
|
||||
Collab ->> WebA: WebSocket Push\n{\n type: "conflict.resolved",\n mergedContent: "병합된 내용"\n}
|
||||
Collab ->> WebB: WebSocket Push\n{\n type: "conflict.resolved",\n mergedContent: "병합된 내용"\n}
|
||||
|
||||
WebA --> UserA: 병합된 내용으로 UI 업데이트
|
||||
WebB --> UserB: 병합된 내용으로 UI 업데이트
|
||||
end
|
||||
|
||||
== 실시간 커서 및 선택 영역 공유 ==
|
||||
UserB -> WebB: 텍스트 선택 또는 커서 이동
|
||||
WebB ->> Collab: WebSocket Send\n{\n type: "cursor.move",\n userId: "userB",\n position: 120,\n selection: {start: 100, end: 130}\n}
|
||||
|
||||
Collab ->> WebA: WebSocket Push\n{\n type: "peer.cursor",\n userId: "userB",\n userName: "참여자B",\n position: 120,\n color: "#FF5733"\n}
|
||||
|
||||
WebA --> UserA: 참여자B의 커서 위치 표시\n(다른 색상으로 강조)
|
||||
|
||||
note over WebA, WebB
|
||||
실시간 협업 기능:
|
||||
- 동시 편집 지원 (CRDT)
|
||||
- 충돌 자동 해결
|
||||
- 커서 위치 공유
|
||||
- 변경 이력 추적
|
||||
end note
|
||||
|
||||
@enduml
|
||||
140
design/backend/sequence/outer/05-회의종료및Todo자동추출.puml
Normal file
140
design/backend/sequence/outer/05-회의종료및Todo자동추출.puml
Normal file
@ -0,0 +1,140 @@
|
||||
@startuml
|
||||
!theme mono
|
||||
|
||||
title Flow 5: 회의 종료 및 Todo 자동 추출 (Meeting End and Auto Todo Extraction)
|
||||
|
||||
actor "사용자\n(User)" as User
|
||||
participant "Web App" as Web
|
||||
participant "API Gateway" as Gateway
|
||||
participant "Meeting Service" as Meeting
|
||||
participant "STT Service" as STT
|
||||
participant "AI Service" as AI
|
||||
participant "Todo Service" as Todo
|
||||
participant "Notification Service" as Notification
|
||||
queue "RabbitMQ" as MQ
|
||||
database "Redis" as Cache
|
||||
database "PostgreSQL" as DB
|
||||
|
||||
== 회의 종료 (Meeting End) ==
|
||||
|
||||
User -> Web: 1. 회의 종료 버튼 클릭\n(Click "End Meeting" button)
|
||||
activate Web
|
||||
|
||||
Web -> Gateway: 2. PATCH /api/meetings/{meetingId}/end\n(End meeting request)
|
||||
activate Gateway
|
||||
|
||||
Gateway -> Meeting: 3. 회의 종료 요청\n(Forward end meeting request)
|
||||
activate Meeting
|
||||
|
||||
Meeting -> DB: 4. 회의 상태 조회\n(Query meeting status)
|
||||
activate DB
|
||||
DB --> Meeting: 회의 정보 반환\n(Return meeting info)
|
||||
deactivate DB
|
||||
|
||||
Meeting -> DB: 5. 회의 상태를 "ended"로 업데이트\n종료 시간 기록\n(Update status to "ended", record end time)
|
||||
activate DB
|
||||
DB --> Meeting: 업데이트 완료\n(Update confirmed)
|
||||
deactivate DB
|
||||
|
||||
Meeting -> DB: 6. 회의 통계 생성\n(참여자 수, 발언 시간, 총 시간 등)\n(Generate meeting statistics)
|
||||
activate DB
|
||||
DB --> Meeting: 통계 저장 완료\n(Statistics saved)
|
||||
deactivate DB
|
||||
|
||||
Meeting -> Cache: 7. 캐시 업데이트\n(Update cache with final status)
|
||||
activate Cache
|
||||
Cache --> Meeting: 캐시 업데이트 완료\n(Cache updated)
|
||||
deactivate Cache
|
||||
|
||||
Meeting ->> MQ: 8. "MeetingEnded" 이벤트 발행\n(Publish "MeetingEnded" event)\n{meetingId, endTime, stats}
|
||||
activate MQ
|
||||
|
||||
Meeting --> Gateway: 9. 회의 종료 응답\n(Return end meeting response)
|
||||
deactivate Meeting
|
||||
|
||||
Gateway --> Web: 10. 종료 확인 응답\n(Return confirmation)
|
||||
deactivate Gateway
|
||||
|
||||
Web --> User: 11. 회의 종료 완료 메시지 표시\n(Display meeting ended message)
|
||||
deactivate Web
|
||||
|
||||
== STT 녹음 중지 (Stop STT Recording) ==
|
||||
|
||||
MQ ->> STT: 12. "MeetingEnded" 이벤트 수신\n(Receive "MeetingEnded" event)
|
||||
activate STT
|
||||
|
||||
STT -> STT: 13. 녹음 중지 및 최종 처리\n(Stop recording and final processing)
|
||||
|
||||
STT -> DB: 14. 최종 음성 데이터 저장\n(Save final audio data)
|
||||
activate DB
|
||||
DB --> STT: 저장 완료\n(Save confirmed)
|
||||
deactivate DB
|
||||
|
||||
STT -> DB: 15. 전사 완료 상태 업데이트\n(Update transcription status to completed)
|
||||
activate DB
|
||||
DB --> STT: 업데이트 완료\n(Update confirmed)
|
||||
deactivate DB
|
||||
|
||||
deactivate STT
|
||||
deactivate MQ
|
||||
|
||||
== AI Todo 자동 추출 (AI Auto Todo Extraction) ==
|
||||
|
||||
MQ ->> AI: 16. "MeetingEnded" 이벤트 수신\n(Receive "MeetingEnded" event)
|
||||
activate MQ
|
||||
activate AI
|
||||
|
||||
AI -> DB: 17. 전체 회의록 조회\n(Query full transcript)
|
||||
activate DB
|
||||
DB --> AI: 회의록 텍스트 반환\n(Return transcript text)
|
||||
deactivate DB
|
||||
|
||||
AI -> AI: 18. AI 분석 수행\n- 실행 항목(Action Items) 식별\n- 담당자(Assignee) 추출\n- 마감일 추론\n(AI analysis:\n- Identify action items\n- Extract assignees\n- Infer deadlines)
|
||||
|
||||
AI -> DB: 19. AI 추출 결과 저장\n(Save AI extraction results)
|
||||
activate DB
|
||||
DB --> AI: 저장 완료\n(Save confirmed)
|
||||
deactivate DB
|
||||
|
||||
AI ->> MQ: 20. "TodoExtracted" 이벤트 발행\n(Publish "TodoExtracted" event)\n{meetingId, todos: [{description, assignee, dueDate, transcriptSection}]}
|
||||
deactivate AI
|
||||
|
||||
== Todo 생성 및 연결 (Todo Creation and Linking) ==
|
||||
|
||||
MQ ->> Todo: 21. "TodoExtracted" 이벤트 수신\n(Receive "TodoExtracted" event)
|
||||
activate Todo
|
||||
|
||||
loop 각 Todo 항목마다 (For each todo item)
|
||||
Todo -> DB: 22. Todo 생성\n- 회의 연결 (meetingId)\n- 전사 섹션 연결 (transcriptSectionId)\n- 담당자 정보\n- 마감일\n(Create todo with:\n- Meeting link\n- Transcript section link\n- Assignee info\n- Due date)
|
||||
activate DB
|
||||
DB --> Todo: Todo 생성 완료\n(Todo created)
|
||||
deactivate DB
|
||||
|
||||
Todo ->> MQ: 23. "TodoCreated" 이벤트 발행\n(Publish "TodoCreated" event)\n{todoId, meetingId, assignee}
|
||||
end
|
||||
|
||||
deactivate Todo
|
||||
|
||||
== 담당자 알림 (Assignee Notification) ==
|
||||
|
||||
MQ ->> Notification: 24. "TodoCreated" 이벤트 수신\n(Receive "TodoCreated" event)
|
||||
activate Notification
|
||||
|
||||
Notification -> DB: 25. 담당자 정보 조회\n(Query assignee information)
|
||||
activate DB
|
||||
DB --> Notification: 사용자 정보 및 이메일\n(Return user info and email)
|
||||
deactivate DB
|
||||
|
||||
Notification -> Notification: 26. Todo 할당 이메일 생성\n- Todo 내용\n- 마감일\n- 회의록 링크\n(Generate todo assignment email:\n- Todo description\n- Due date\n- Transcript link)
|
||||
|
||||
Notification -> Notification: 27. 이메일 발송\n(Send email to assignee)
|
||||
|
||||
Notification -> DB: 28. 알림 전송 기록 저장\n(Save notification log)
|
||||
activate DB
|
||||
DB --> Notification: 저장 완료\n(Save confirmed)
|
||||
deactivate DB
|
||||
|
||||
deactivate Notification
|
||||
deactivate MQ
|
||||
|
||||
@enduml
|
||||
183
design/backend/sequence/outer/06-회의록확정및공유.puml
Normal file
183
design/backend/sequence/outer/06-회의록확정및공유.puml
Normal file
@ -0,0 +1,183 @@
|
||||
@startuml
|
||||
!theme mono
|
||||
|
||||
title Flow 6: 회의록 확정 및 공유 (Transcript Confirmation and Sharing)
|
||||
|
||||
actor "사용자\n(User)" as User
|
||||
participant "Web App" as Web
|
||||
participant "API Gateway" as Gateway
|
||||
participant "Meeting Service" as Meeting
|
||||
participant "Notification Service" as Notification
|
||||
queue "RabbitMQ" as MQ
|
||||
database "Redis" as Cache
|
||||
database "PostgreSQL" as DB
|
||||
|
||||
== 회의록 검토 (Transcript Review) ==
|
||||
|
||||
User -> Web: 1. 회의록 최종 검토\n(Review final transcript)
|
||||
activate Web
|
||||
|
||||
Web -> Gateway: 2. GET /api/meetings/{meetingId}/transcript\n(Get transcript for review)
|
||||
activate Gateway
|
||||
|
||||
Gateway -> Meeting: 3. 회의록 조회 요청\n(Forward transcript query)
|
||||
activate Meeting
|
||||
|
||||
Meeting -> Cache: 4. 캐시에서 회의록 조회\n(Check cache for transcript)
|
||||
activate Cache
|
||||
Cache --> Meeting: 캐시 히트/미스\n(Cache hit/miss)
|
||||
deactivate Cache
|
||||
|
||||
alt 캐시 미스 (Cache miss)
|
||||
Meeting -> DB: 5. DB에서 회의록 조회\n(Query transcript from DB)
|
||||
activate DB
|
||||
DB --> Meeting: 회의록 데이터 반환\n(Return transcript data)
|
||||
deactivate DB
|
||||
|
||||
Meeting -> Cache: 6. 캐시에 저장\n(Store in cache)
|
||||
activate Cache
|
||||
Cache --> Meeting: 저장 완료\n(Stored)
|
||||
deactivate Cache
|
||||
end
|
||||
|
||||
Meeting --> Gateway: 7. 회의록 반환\n(Return transcript)
|
||||
deactivate Meeting
|
||||
|
||||
Gateway --> Web: 8. 회의록 데이터\n(Return transcript data)
|
||||
deactivate Gateway
|
||||
|
||||
Web --> User: 9. 회의록 표시\n(Display transcript)
|
||||
deactivate Web
|
||||
|
||||
== 필수 항목 검증 (Validate Required Sections) ==
|
||||
|
||||
User -> Web: 10. 회의록 확정 요청\n(Request transcript confirmation)
|
||||
activate Web
|
||||
|
||||
Web -> Web: 11. 필수 항목 검증\n- 회의 제목 존재 여부\n- 참석자 목록 존재 여부\n- 주요 결정사항 작성 여부\n(Validate required sections:\n- Title exists\n- Participants list exists\n- Key decisions documented)
|
||||
|
||||
alt 필수 항목 누락 (Missing required sections)
|
||||
Web --> User: 12. 필수 항목 누락 경고\n(Display missing sections warning)
|
||||
deactivate Web
|
||||
else 검증 통과 (Validation passed)
|
||||
|
||||
Web -> Gateway: 13. POST /api/meetings/{meetingId}/confirm\n(Confirm transcript request)
|
||||
activate Gateway
|
||||
|
||||
Gateway -> Meeting: 14. 회의록 확정 요청\n(Forward confirmation request)
|
||||
activate Meeting
|
||||
|
||||
Meeting -> DB: 15. 회의록 확정 처리\n- 최종 버전 생성 (version++)\n- 확정 상태로 변경 (status: "confirmed")\n- 확정 일시 기록\n(Confirm transcript:\n- Create final version\n- Update status to "confirmed"\n- Record confirmation time)
|
||||
activate DB
|
||||
DB --> Meeting: 확정 완료\n(Confirmation saved)
|
||||
deactivate DB
|
||||
|
||||
Meeting -> Cache: 16. 캐시 무효화\n(Invalidate cache)
|
||||
activate Cache
|
||||
Cache --> Meeting: 캐시 삭제 완료\n(Cache invalidated)
|
||||
deactivate Cache
|
||||
|
||||
Meeting --> Gateway: 17. 확정 완료 응답\n(Return confirmation response)
|
||||
deactivate Meeting
|
||||
|
||||
Gateway --> Web: 18. 확정 완료\n(Confirmation successful)
|
||||
deactivate Gateway
|
||||
|
||||
Web --> User: 19. 확정 완료 메시지 표시\n(Display confirmation message)
|
||||
deactivate Web
|
||||
end
|
||||
|
||||
== 공유 설정 (Configure Sharing) ==
|
||||
|
||||
User -> Web: 20. 공유 설정 화면 열기\n(Open sharing configuration)
|
||||
activate Web
|
||||
|
||||
Web --> User: 21. 공유 옵션 표시\n- 수신자 선택\n- 권한 설정 (읽기/편집)\n- 공유 범위 (전체/일부)\n(Display sharing options:\n- Select recipients\n- Set permissions\n- Choose scope)
|
||||
deactivate Web
|
||||
|
||||
User -> Web: 22. 공유 설정 입력\n- 수신자 목록\n- 권한 레벨\n- 메시지 (선택)\n(Input sharing settings:\n- Recipients list\n- Permission level\n- Optional message)
|
||||
activate Web
|
||||
|
||||
Web -> Gateway: 23. POST /api/meetings/{meetingId}/share\n{recipients, permissions, message}\n(Submit sharing request)
|
||||
activate Gateway
|
||||
|
||||
Gateway -> Meeting: 24. 공유 설정 요청\n(Forward sharing request)
|
||||
activate Meeting
|
||||
|
||||
Meeting -> DB: 25. 공유 링크 생성\n- 고유 공유 ID 생성 (UUID)\n- 공유 권한 저장\n- 유효기간 설정 (선택)\n(Generate share link:\n- Create unique share ID\n- Save permissions\n- Set expiration if configured)
|
||||
activate DB
|
||||
DB --> Meeting: 공유 정보 저장 완료\n(Share info saved)
|
||||
deactivate DB
|
||||
|
||||
Meeting -> Cache: 26. 공유 링크 캐시 저장\n(Cache share link)
|
||||
activate Cache
|
||||
Cache --> Meeting: 캐시 저장 완료\n(Cached)
|
||||
deactivate Cache
|
||||
|
||||
Meeting ->> MQ: 27. "TranscriptShared" 이벤트 발행\n(Publish "TranscriptShared" event)\n{meetingId, shareId, recipients, permissions}
|
||||
activate MQ
|
||||
|
||||
Meeting --> Gateway: 28. 공유 링크 반환\n(Return share link)
|
||||
deactivate Meeting
|
||||
|
||||
Gateway --> Web: 29. 공유 링크 및 확인\n(Return share link)
|
||||
deactivate Gateway
|
||||
|
||||
Web --> User: 30. 공유 완료 메시지 및 링크 표시\n(Display share link and confirmation)
|
||||
deactivate Web
|
||||
|
||||
== 공유 알림 발송 (Send Share Notifications) ==
|
||||
|
||||
MQ ->> Notification: 31. "TranscriptShared" 이벤트 수신\n(Receive "TranscriptShared" event)
|
||||
activate Notification
|
||||
|
||||
loop 각 수신자마다 (For each recipient)
|
||||
Notification -> DB: 32. 수신자 정보 조회\n(Query recipient information)
|
||||
activate DB
|
||||
DB --> Notification: 사용자 정보 및 이메일\n(Return user info and email)
|
||||
deactivate DB
|
||||
|
||||
Notification -> Notification: 33. 공유 알림 이메일 생성\n- 회의 정보\n- 공유 링크\n- 권한 레벨\n- 발신자 메시지\n(Generate share notification email:\n- Meeting info\n- Share link\n- Permission level\n- Sender message)
|
||||
|
||||
Notification -> Notification: 34. 이메일 발송\n(Send email to recipient)
|
||||
|
||||
Notification -> DB: 35. 알림 전송 기록 저장\n(Save notification log)
|
||||
activate DB
|
||||
DB --> Notification: 저장 완료\n(Save confirmed)
|
||||
deactivate DB
|
||||
end
|
||||
|
||||
deactivate Notification
|
||||
deactivate MQ
|
||||
|
||||
== 참여자 알림 (Participant Notification) ==
|
||||
|
||||
note over Notification
|
||||
모든 회의 참여자에게도
|
||||
회의록 확정 알림 발송
|
||||
(Send confirmation notification
|
||||
to all meeting participants)
|
||||
end note
|
||||
|
||||
Notification ->> Notification: 36. 참여자 알림 처리\n(Process participant notifications)
|
||||
activate Notification
|
||||
|
||||
Notification -> DB: 37. 참여자 목록 조회\n(Query participants list)
|
||||
activate DB
|
||||
DB --> Notification: 참여자 정보 반환\n(Return participants info)
|
||||
deactivate DB
|
||||
|
||||
loop 각 참여자마다 (For each participant)
|
||||
Notification -> Notification: 38. 확정 알림 이메일 생성\n- 회의록 확정 알림\n- 회의록 보기 링크\n- 주요 내용 요약\n(Generate confirmation email:\n- Transcript confirmed\n- View link\n- Summary)
|
||||
|
||||
Notification -> Notification: 39. 이메일 발송\n(Send email)
|
||||
|
||||
Notification -> DB: 40. 알림 기록 저장\n(Save notification log)
|
||||
activate DB
|
||||
DB --> Notification: 저장 완료\n(Saved)
|
||||
deactivate DB
|
||||
end
|
||||
|
||||
deactivate Notification
|
||||
|
||||
@enduml
|
||||
62
design/backend/sequence/outer/07-회의록목록조회및상세조회.puml
Normal file
62
design/backend/sequence/outer/07-회의록목록조회및상세조회.puml
Normal file
@ -0,0 +1,62 @@
|
||||
@startuml
|
||||
!theme mono
|
||||
|
||||
title 회의록 목록 조회 및 상세 조회 Flow
|
||||
|
||||
actor "User" as user
|
||||
participant "Web App" as web
|
||||
participant "API Gateway" as gateway
|
||||
participant "Meeting Service" as meeting
|
||||
participant "AI Service" as ai
|
||||
participant "Redis" as redis
|
||||
participant "PostgreSQL" as db
|
||||
|
||||
== 회의록 목록 조회 ==
|
||||
|
||||
user -> web: 회의록 목록 화면 진입
|
||||
web -> gateway: GET /api/meetings/transcripts\n(filters: status, date, participants)
|
||||
gateway -> meeting: 회의록 목록 조회 요청\n(필터 및 정렬 조건 포함)
|
||||
|
||||
meeting -> redis: 캐시 조회\n(key: transcripts:filter:{hash})
|
||||
alt 캐시 히트
|
||||
redis --> meeting: 캐시된 목록 반환
|
||||
else 캐시 미스
|
||||
meeting -> db: SELECT transcripts\nWHERE status, date, participants\nORDER BY created_at
|
||||
db --> meeting: 회의록 목록 데이터
|
||||
meeting -> redis: 캐시 저장\n(TTL: 5분)
|
||||
end
|
||||
|
||||
meeting --> gateway: 회의록 목록 응답
|
||||
gateway --> web: 200 OK\n{transcripts: [...]}
|
||||
web --> user: 회의록 목록 표시\n(필터/정렬 적용)
|
||||
|
||||
== 회의록 상세 조회 ==
|
||||
|
||||
user -> web: 회의록 항목 클릭
|
||||
web -> gateway: GET /api/meetings/transcripts/{id}
|
||||
gateway -> meeting: 회의록 상세 조회 요청
|
||||
|
||||
meeting -> redis: 캐시 조회\n(key: transcript:{id})
|
||||
alt 캐시 히트
|
||||
redis --> meeting: 캐시된 상세 데이터
|
||||
else 캐시 미스
|
||||
meeting -> db: SELECT transcript, content,\nparticipants, action_items\nWHERE id = {id}
|
||||
db --> meeting: 회의록 상세 데이터
|
||||
meeting -> redis: 캐시 저장\n(TTL: 10분)
|
||||
end
|
||||
|
||||
== 연관 회의록 자동 링크 ==
|
||||
|
||||
meeting ->> ai: 연관 회의록 요청\n(transcript_id, threshold: 0.7)
|
||||
ai -> db: Vector 유사도 검색\n(임베딩 기반, similarity > 70%)
|
||||
db --> ai: 유사 회의록 목록\n(최대 5개)
|
||||
ai --> meeting: 연관 회의록 ID 목록
|
||||
|
||||
meeting -> db: 연관 회의록 메타데이터 조회
|
||||
db --> meeting: 연관 회의록 제목, 날짜, 참석자
|
||||
|
||||
meeting --> gateway: 회의록 상세 + 연관 목록 응답
|
||||
gateway --> web: 200 OK\n{transcript: {...},\nrelated: [...]}
|
||||
web --> user: 회의록 상세 표시\n+ 연관 회의록 링크
|
||||
|
||||
@enduml
|
||||
78
design/backend/sequence/outer/08-맥락기반용어설명제공.puml
Normal file
78
design/backend/sequence/outer/08-맥락기반용어설명제공.puml
Normal file
@ -0,0 +1,78 @@
|
||||
@startuml
|
||||
!theme mono
|
||||
|
||||
title 맥락 기반 용어 설명 제공 Flow
|
||||
|
||||
actor "User" as user
|
||||
participant "Web App" as web
|
||||
participant "API Gateway" as gateway
|
||||
participant "RAG Service" as rag
|
||||
participant "Vector DB" as vectordb
|
||||
participant "PostgreSQL" as db
|
||||
|
||||
== 실시간 용어 감지 ==
|
||||
|
||||
user -> web: 회의록 내용 조회 중
|
||||
web -> gateway: GET /api/meetings/transcripts/{id}
|
||||
gateway -> rag: 회의록 내용 전달\n(기술 용어 감지 요청)
|
||||
|
||||
rag -> rag: NLP 기반 기술 용어 추출\n(confidence > 70%)
|
||||
note right of rag
|
||||
- 도메인 용어 사전 매칭
|
||||
- 컨텍스트 분석
|
||||
- 신뢰도 점수 계산
|
||||
end note
|
||||
|
||||
rag --> gateway: 감지된 용어 목록\n{terms: [{word, position, confidence}]}
|
||||
gateway --> web: 회의록 + 하이라이트 용어
|
||||
web --> user: 회의록 표시\n(기술 용어 하이라이트)
|
||||
|
||||
== 용어 설명 요청 ==
|
||||
|
||||
user -> web: 하이라이트 용어 호버
|
||||
web -> gateway: GET /api/rag/terms/explain\n?term={용어}&context={문장}&meeting_id={id}
|
||||
gateway -> rag: 맥락 기반 용어 설명 요청
|
||||
|
||||
== Vector 유사도 검색 ==
|
||||
|
||||
rag -> vectordb: Vector 검색\n(term embedding, similarity search)
|
||||
note right of vectordb
|
||||
- 과거 회의록 임베딩 검색
|
||||
- 관련 문서 임베딩 검색
|
||||
- 유사도 임계값: 0.7
|
||||
end note
|
||||
|
||||
vectordb --> rag: 유사 문서 조각 목록\n(최대 10개, similarity > 70%)
|
||||
|
||||
rag -> db: 관련 컨텍스트 메타데이터 조회\n(project_id, issue_id, meeting_ids)
|
||||
db --> rag: 프로젝트, 이슈, 회의 정보
|
||||
|
||||
== 설명 생성 ==
|
||||
|
||||
rag -> rag: LLM 기반 설명 생성
|
||||
note right of rag
|
||||
생성 내용:
|
||||
1. 간단한 정의
|
||||
2. 현재 회의에서의 맥락적 의미
|
||||
3. 관련 프로젝트/이슈
|
||||
4. 과거 회의 참조 (최대 3개)
|
||||
end note
|
||||
|
||||
rag -> db: 과거 회의 제목 및 날짜 조회\n(meeting_ids, LIMIT 3)
|
||||
db --> rag: 회의 메타데이터
|
||||
|
||||
rag --> gateway: 용어 설명 응답\n{definition, context_meaning,\nrelated_projects, past_meetings}
|
||||
gateway --> web: 200 OK\n{explanation: {...}}
|
||||
web --> user: 툴팁/사이드 패널에 설명 표시
|
||||
note left of user
|
||||
표시 내용:
|
||||
- 📖 정의: "..."
|
||||
- 💬 맥락: "이 회의에서는..."
|
||||
- 🔗 관련: 프로젝트 A, 이슈 #123
|
||||
- 📅 과거 회의:
|
||||
• 2025-08-15 기획 회의
|
||||
• 2025-07-20 기술 검토
|
||||
• 2025-06-10 아키텍처 논의
|
||||
end note
|
||||
|
||||
@enduml
|
||||
94
design/backend/sequence/outer/09-Todo완료및회의록반영.puml
Normal file
94
design/backend/sequence/outer/09-Todo완료및회의록반영.puml
Normal file
@ -0,0 +1,94 @@
|
||||
@startuml
|
||||
!theme mono
|
||||
|
||||
title Flow 9: Todo 완료 및 회의록 반영 (Todo Completion and Transcript Update)
|
||||
|
||||
actor User as user
|
||||
participant "Web App" as web
|
||||
participant "API Gateway" as gateway
|
||||
participant "Todo Service" as todo
|
||||
participant "RabbitMQ" as mq
|
||||
participant "Meeting Service" as meeting
|
||||
participant "Notification Service" as notification
|
||||
participant "Redis" as redis
|
||||
participant "PostgreSQL\n(Todo DB)" as tododb
|
||||
participant "PostgreSQL\n(Meeting DB)" as meetingdb
|
||||
participant "WebSocket\nConnection" as ws
|
||||
|
||||
== Todo 완료 처리 (Todo Completion Processing) ==
|
||||
|
||||
user -> web: Todo 완료 버튼 클릭\n(Click "Complete" button)
|
||||
web -> gateway: PUT /api/todos/{todoId}/complete\n(Todo 완료 요청)
|
||||
|
||||
gateway -> todo: PUT /todos/{todoId}/complete\n(Todo 완료 처리 요청)
|
||||
activate todo
|
||||
|
||||
todo -> tododb: UPDATE todos\nSET status='COMPLETED',\ncompleted_at=NOW(),\ncompleted_by={userId}\nWHERE id={todoId}
|
||||
tododb --> todo: 완료 상태 저장 완료\n(Completion status saved)
|
||||
|
||||
todo -> redis: DEL cache:todo:{todoId}\n(Todo 캐시 무효화)
|
||||
redis --> todo: 캐시 삭제 완료
|
||||
|
||||
todo --> gateway: 200 OK\n{todo: {..., status: "COMPLETED"}}
|
||||
gateway --> web: 200 OK
|
||||
web --> user: Todo 완료 표시\n(Show completion checkmark)
|
||||
|
||||
== 비동기 이벤트 발행 (Async Event Publishing) ==
|
||||
|
||||
todo ->> mq: Publish "TodoCompleted"\n{todoId, meetingId, userId,\ncompletedAt}
|
||||
deactivate todo
|
||||
|
||||
mq ->> meeting: Consume "TodoCompleted"\n(Todo 완료 이벤트 수신)
|
||||
activate meeting
|
||||
|
||||
== 회의록 업데이트 (Meeting Transcript Update) ==
|
||||
|
||||
meeting -> redis: GET cache:transcript:{meetingId}\n(회의록 캐시 조회)
|
||||
alt 캐시 히트 (Cache Hit)
|
||||
redis --> meeting: 회의록 데이터 반환
|
||||
else 캐시 미스 (Cache Miss)
|
||||
meeting -> meetingdb: SELECT * FROM transcripts\nWHERE meeting_id={meetingId}
|
||||
meetingdb --> meeting: 회의록 데이터 반환
|
||||
end
|
||||
|
||||
meeting -> meeting: Todo 섹션에 완료 상태 반영\n(Update todo section:\ncheckmark, completed_at,\ncompleted_by)
|
||||
|
||||
meeting -> meetingdb: UPDATE transcripts\nSET content={updatedContent},\nupdated_at=NOW()\nWHERE meeting_id={meetingId}
|
||||
meetingdb --> meeting: 회의록 업데이트 완료
|
||||
|
||||
meeting -> redis: DEL cache:transcript:{meetingId}\n(회의록 캐시 무효화)
|
||||
redis --> meeting: 캐시 삭제 완료
|
||||
|
||||
== 알림 발송 (Notification Sending) ==
|
||||
|
||||
meeting ->> mq: Publish "TranscriptUpdated"\n{meetingId, updateType:\n"TODO_COMPLETED",\ntodoId, userId}
|
||||
deactivate meeting
|
||||
|
||||
mq ->> notification: Consume "TranscriptUpdated"\n(회의록 업데이트 이벤트 수신)
|
||||
activate notification
|
||||
|
||||
notification -> meetingdb: SELECT creator_id\nFROM transcripts\nWHERE meeting_id={meetingId}
|
||||
meetingdb --> notification: 회의록 작성자 ID 반환
|
||||
|
||||
notification -> notification: 알림 메시지 생성\n("Todo가 완료되었습니다")
|
||||
|
||||
notification ->> user: 회의록 작성자에게\n완료 알림 전송\n(Send completion notification)
|
||||
|
||||
deactivate notification
|
||||
|
||||
== 실시간 동기화 (Real-time Sync) ==
|
||||
|
||||
mq ->> ws: Consume "TranscriptUpdated"\n(실시간 동기화 이벤트)
|
||||
activate ws
|
||||
|
||||
ws -> redis: GET ws:participants:{meetingId}\n(현재 회의록 조회 중인\n참여자 목록 조회)
|
||||
redis --> ws: 참여자 WebSocket 세션 목록
|
||||
|
||||
loop 각 참여자에게 (For each participant)
|
||||
ws ->> web: WebSocket Push\n{type: "TODO_COMPLETED",\ntodoId, completedAt,\ncompletedBy}
|
||||
web -> web: 화면에 완료 상태 실시간 반영\n(Update UI with completion status)
|
||||
end
|
||||
|
||||
deactivate ws
|
||||
|
||||
@enduml
|
||||
328
design/backend/sequence/outer/README.md
Normal file
328
design/backend/sequence/outer/README.md
Normal file
@ -0,0 +1,328 @@
|
||||
# 외부 시퀀스 설계서 (Outer Sequence Design)
|
||||
|
||||
## 개요
|
||||
|
||||
본 문서는 회의록 작성 및 공유 개선 서비스의 **외부 시퀀스 다이어그램**을 설명합니다.
|
||||
외부 시퀀스는 **마이크로서비스 간의 통신 흐름**을 나타내며, 주요 사용자 플로우별로 서비스 간 상호작용을 정의합니다.
|
||||
|
||||
### 문서 정보
|
||||
- **작성일**: 2025-10-22
|
||||
- **작성자**: 홍길동 (Architect)
|
||||
- **버전**: 2.0
|
||||
- **설계 원칙**: 공통설계원칙 및 외부시퀀스설계가이드 준용
|
||||
|
||||
### 병렬 처리 전략 적용
|
||||
- **Group A (순차)**: 회의 생애주기 플로우 (플로우 10-13)
|
||||
- **Group B (독립)**: Todo 관리 플로우 (플로우 14)
|
||||
- **Group C (독립)**: 회의록 조회/수정 플로우 (플로우 15)
|
||||
- 3개 서브 에이전트가 병렬로 작업하여 전체 작업 시간 약 60% 단축
|
||||
|
||||
---
|
||||
|
||||
## 외부 시퀀스 목록
|
||||
|
||||
### 1. 사용자 인증 및 대시보드 조회
|
||||
- **파일**: [01-사용자인증및대시보드조회.puml](./01-사용자인증및대시보드조회.puml)
|
||||
- **관련 유저스토리**: AFR-USER-010, AFR-USER-020
|
||||
- **참여 서비스**:
|
||||
- Web App
|
||||
- API Gateway
|
||||
- User Service
|
||||
- Meeting Service
|
||||
- Todo Service
|
||||
- Redis (Cache)
|
||||
- PostgreSQL (User DB, Meeting DB, Todo DB)
|
||||
|
||||
**주요 흐름**:
|
||||
1. **사용자 인증**:
|
||||
- 사용자가 사번과 비밀번호로 로그인
|
||||
- User Service가 LDAP 연동하여 인증
|
||||
- JWT 토큰 생성 및 사용자 프로필 Redis 캐싱 (TTL: 30분)
|
||||
- 인증 성공 시 토큰 반환
|
||||
|
||||
2. **대시보드 데이터 조회**:
|
||||
- 예정된 회의 조회 (Meeting Service)
|
||||
- Redis 캐시 확인 → Cache Miss → DB 조회 → 캐싱 (TTL: 10분)
|
||||
- 진행 중 Todo 조회 (Todo Service)
|
||||
- Redis 캐시 확인 → Cache Hit → 캐시에서 직접 반환
|
||||
- 최근 회의록 조회 (Meeting Service)
|
||||
- Redis 캐시 확인 → Cache Miss → DB 조회 → 캐싱 (TTL: 10분)
|
||||
- Todo 통계 조회 (Todo Service)
|
||||
- Redis 캐시 확인 → Cache Hit → 캐시에서 직접 반환
|
||||
|
||||
**적용 패턴**:
|
||||
- **Cache-Aside Pattern**: 캐시 우선 조회로 DB 부하 감소
|
||||
- **JWT 인증**: API Gateway에서 일괄 토큰 검증
|
||||
- **LDAP 연동**: 기업 사용자 인증
|
||||
|
||||
**성능 목표**:
|
||||
- API 응답 시간 (P95): < 500ms
|
||||
- Cache Hit Rate: > 70%
|
||||
|
||||
---
|
||||
|
||||
### 2. 회의 예약 및 초대
|
||||
- **파일**: [02-회의예약및초대.puml](./02-회의예약및초대.puml)
|
||||
- **관련 유저스토리**: UFR-MEET-010
|
||||
- **참여 서비스**:
|
||||
- Web App
|
||||
- API Gateway
|
||||
- Meeting Service
|
||||
- User Service
|
||||
- Notification Service
|
||||
- RabbitMQ (Message Broker)
|
||||
- Redis (Cache)
|
||||
- PostgreSQL (Meeting DB, User DB, Notification DB)
|
||||
|
||||
**주요 흐름**:
|
||||
1. **회의 예약**:
|
||||
- 사용자가 회의 정보 입력 (제목, 날짜/시간, 장소, 참석자)
|
||||
- 입력 유효성 검증 (필수 필드, 날짜 형식, 이메일 형식)
|
||||
- Meeting Service가 회의 생성 및 DB 저장
|
||||
- 회의 정보 Redis 캐싱 (TTL: 10분)
|
||||
|
||||
2. **이벤트 발행**:
|
||||
- Meeting Service가 `MeetingCreated` 이벤트를 RabbitMQ에 발행
|
||||
- Exchange: `meeting.events`
|
||||
- Routing Key: `meeting.created`
|
||||
- Notification Service가 이벤트 구독
|
||||
|
||||
3. **초대 알림 발송**:
|
||||
- Notification Service가 `MeetingCreated` 이벤트 수신
|
||||
- User Service에서 참석자 정보 조회 (캐시 우선)
|
||||
- 알림 메시지 생성 및 DB 저장
|
||||
- 각 참석자에게 이메일 초대 발송
|
||||
- 알림 상태 업데이트 (PENDING → SENT)
|
||||
- 리마인더 일정 생성 (회의 시작 30분 전)
|
||||
|
||||
4. **결과 확인**:
|
||||
- 사용자가 대시보드에서 새로 예약한 회의 확인
|
||||
- 캐시 무효화 후 DB 재조회 및 재캐싱
|
||||
|
||||
**적용 패턴**:
|
||||
- **Publisher-Subscriber Pattern**: 이벤트 기반 느슨한 결합
|
||||
- **Queue-Based Load Leveling**: 대량 알림 발송 시 부하 분산
|
||||
- **Cache-Aside Pattern**: 사용자 정보 캐싱으로 성능 향상
|
||||
- **Asynchronous Processing**: 알림 발송은 비동기로 처리
|
||||
|
||||
**이벤트 스키마**:
|
||||
```json
|
||||
{
|
||||
"eventType": "MeetingCreated",
|
||||
"payload": {
|
||||
"meetingId": "uuid",
|
||||
"title": "프로젝트 킥오프 회의",
|
||||
"dateTime": "2025-02-01T14:00:00",
|
||||
"location": "회의실 A",
|
||||
"creatorId": "userId",
|
||||
"participants": ["user1@company.com", "user2@company.com"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**성능 목표**:
|
||||
- 회의 생성 응답 시간: < 300ms
|
||||
- 알림 발송 지연 시간: < 5초
|
||||
|
||||
---
|
||||
|
||||
## 설계 원칙
|
||||
|
||||
### 1. 통신 패턴
|
||||
|
||||
#### 동기 통신 (REST API)
|
||||
- **적용 대상**: 즉시 응답이 필요한 단순 조회
|
||||
- **특징**:
|
||||
- API Gateway를 통한 일관된 인증/인가
|
||||
- 캐시 우선 전략으로 직접 의존성 최소화
|
||||
|
||||
#### 비동기 통신 (Message Queue)
|
||||
- **적용 대상**: 이벤트 기반 통신, 느슨한 결합
|
||||
- **특징**:
|
||||
- RabbitMQ Topic Exchange를 통한 Pub/Sub 패턴
|
||||
- 이벤트 발행자와 구독자 간 느슨한 결합
|
||||
- 대량 작업 시 Queue-Based Load Leveling
|
||||
|
||||
### 2. 캐싱 전략 (Cache-Aside)
|
||||
|
||||
| 데이터 유형 | TTL | 캐시 키 패턴 | 무효화 시점 |
|
||||
|------------|-----|--------------|------------|
|
||||
| 사용자 프로필 | 30분 | `user:profile:{userId}` | 프로필 수정 시 |
|
||||
| 사용자 권한 | 1시간 | `user:auth:{userId}` | 권한 변경 시 |
|
||||
| 회의 정보 | 10분 | `meeting:info:{meetingId}` | 회의 수정 시 |
|
||||
| 회의 참여자 | 10분 | `meeting:participants:{meetingId}` | 참여자 변경 시 |
|
||||
| Todo 목록 | 5분 | `todo:user:{userId}` | Todo 상태 변경 시 |
|
||||
| Todo 통계 | 5분 | `todo:stats:{userId}` | Todo 완료 시 |
|
||||
|
||||
**캐시 처리 플로우**:
|
||||
1. 조회 요청 → Redis 캐시 확인
|
||||
2. Cache Hit → 캐시 데이터 반환
|
||||
3. Cache Miss → DB 조회 → Redis 저장 (TTL 설정) → 데이터 반환
|
||||
4. 데이터 수정 시 → DB 업데이트 → Redis 캐시 무효화
|
||||
|
||||
### 3. 이벤트 기반 아키텍처
|
||||
|
||||
#### RabbitMQ Exchange/Queue 구성
|
||||
- **Topic Exchange**: `meeting.events`, `transcript.events`, `todo.events`
|
||||
- **Queue 네이밍**: `{service}.{event-category}.queue`
|
||||
- **Routing Key 패턴**: `{event}.{action}` (예: `meeting.created`, `todo.completed`)
|
||||
|
||||
#### 주요 이벤트
|
||||
|
||||
| 이벤트 | 발행자 | 구독자 | 목적 |
|
||||
|--------|--------|--------|------|
|
||||
| **MeetingCreated** | Meeting Service | Notification Service<br/>AI Service | 참석자 알림 발송<br/>회의 분석 준비 |
|
||||
| **MeetingEnded** | Meeting Service | STT Service<br/>AI Service<br/>Todo Service<br/>Notification Service | 회의록 생성<br/>AI 분석 시작<br/>Todo 추출<br/>종료 알림 |
|
||||
| **TodoCreated** | Todo Service | Notification Service | 담당자 알림 발송 |
|
||||
|
||||
---
|
||||
|
||||
## 다이어그램 렌더링 방법
|
||||
|
||||
### PlantUML 렌더링
|
||||
|
||||
#### 1. Visual Studio Code 플러그인 사용
|
||||
1. PlantUML 확장 설치: `jebbs.plantuml`
|
||||
2. `.puml` 파일 열기
|
||||
3. `Alt + D` (미리보기) 또는 우클릭 → `Preview Current Diagram`
|
||||
|
||||
#### 2. 온라인 렌더링
|
||||
- [PlantUML Online Editor](https://www.plantuml.com/plantuml/uml/)
|
||||
- 파일 내용 복사 → 붙여넣기 → 렌더링
|
||||
|
||||
#### 3. 로컬 PlantUML 서버
|
||||
```bash
|
||||
# Docker로 PlantUML 서버 실행
|
||||
docker run -d --name plantuml -p 38080:8080 plantuml/plantuml-server:latest
|
||||
|
||||
# 브라우저에서 접근
|
||||
http://localhost:38080
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 다음 단계
|
||||
|
||||
### 1. 내부 시퀀스 설계
|
||||
각 서비스 내부의 상세 처리 흐름을 설계합니다:
|
||||
- User Service 내부 시퀀스 (인증 처리, 프로필 관리)
|
||||
- Meeting Service 내부 시퀀스 (회의 생성, 회의록 관리)
|
||||
- Notification Service 내부 시퀀스 (알림 발송, 리마인더 관리)
|
||||
|
||||
### 2. API 명세 작성
|
||||
각 서비스별 REST API 명세를 OpenAPI 3.0 형식으로 작성합니다.
|
||||
|
||||
### 3. 클래스 설계
|
||||
엔티티, DTO, 서비스 클래스 설계를 진행합니다.
|
||||
|
||||
### 4. 데이터 설계
|
||||
각 서비스별 데이터베이스 스키마 설계를 진행합니다.
|
||||
|
||||
---
|
||||
|
||||
## 참고 자료
|
||||
|
||||
- [논리 아키텍처 설계서](../../logical/logical-architecture.md)
|
||||
- [유저스토리](../../../userstory.md)
|
||||
- [아키텍처 패턴 적용 방안](../../../pattern/architecture-pattern.md)
|
||||
- [클라우드 디자인 패턴 요약](../../../../claude/cloud-design-patterns.md)
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## 신규 플로우 (v2.0)
|
||||
|
||||
### 10. 회의 예약 및 초대
|
||||
- **파일**: [회의예약및초대.puml](./회의예약및초대.puml)
|
||||
- **관련 유저스토리**: UFR-MEET-010
|
||||
- **참여 서비스**: Frontend, API Gateway, Meeting Service, User Service, Redis, RabbitMQ, Notification Service, Meeting DB
|
||||
- **주요 특징**:
|
||||
- Cache-Aside 패턴으로 참석자 정보 조회 (Redis 캐시 우선)
|
||||
- 회의 정보 저장 및 캐싱 (TTL: 10분)
|
||||
- MeetingCreated 이벤트 비동기 발행
|
||||
- Notification Service가 참석자 전원에게 초대 이메일 발송
|
||||
|
||||
### 11. 회의 시작 및 회의록 작성
|
||||
- **파일**: [회의시작및회의록작성.puml](./회의시작및회의록작성.puml)
|
||||
- **관련 유저스토리**: UFR-MEET-030, UFR-STT-010/020, UFR-AI-010, UFR-RAG-010/020, UFR-COLLAB-010
|
||||
- **참여 서비스**: Frontend, API Gateway, Meeting Service, STT Service, AI Service, RAG Service, Collaboration Service, Redis, RabbitMQ, Azure Speech, LLM Server, 각 서비스 DB
|
||||
- **주요 특징**:
|
||||
- 실시간 음성 인식 (Azure Speech, 5초 간격)
|
||||
- AI 기반 회의록 자동 작성 (LLM)
|
||||
- WebSocket 실시간 동기화 (델타만 전송)
|
||||
- RAG 기반 전문용어 감지 및 맥락 설명 제공
|
||||
- 가장 복잡한 플로우 (동기+비동기+실시간 혼합)
|
||||
|
||||
### 12. 회의 종료 및 Todo 추출
|
||||
- **파일**: [회의종료및Todo추출.puml](./회의종료및Todo추출.puml)
|
||||
- **관련 유저스토리**: UFR-MEET-040/050, UFR-AI-020, UFR-TODO-010
|
||||
- **참여 서비스**: Frontend, API Gateway, Meeting Service, AI Service, Todo Service, Notification Service, Redis, RabbitMQ, LLM Server, 각 서비스 DB
|
||||
- **주요 특징**:
|
||||
- 회의 통계 자동 생성 (duration, 참석자 수, 발언 수)
|
||||
- AI Todo 자동 추출 (액션 아이템 식별, 담당자 자동 지정)
|
||||
- 이벤트 체인: MeetingEnded → TodoExtracted → TodoCreated
|
||||
- Todo 목록 캐싱 (TTL: 5분)
|
||||
- 담당자에게 자동 알림 발송
|
||||
|
||||
### 13. 회의록 확정 및 공유
|
||||
- **파일**: [회의록확정및공유.puml](./회의록확정및공유.puml)
|
||||
- **관련 유저스토리**: UFR-MEET-060
|
||||
- **참여 서비스**: Frontend, API Gateway, Meeting Service, Notification Service, Redis, RabbitMQ, Meeting DB
|
||||
- **주요 특징**:
|
||||
- 필수 항목 자동 검사 (제목, 참석자, 논의 내용, 결정 사항)
|
||||
- 고유 공유 링크 생성 (UUID 기반)
|
||||
- 공유 보안 설정 (비밀번호, 유효기간)
|
||||
- TranscriptShared 이벤트 발행
|
||||
- 다음 회의 일정 자동 캘린더 등록 (선택)
|
||||
|
||||
### 14. Todo 완료 및 회의록 반영
|
||||
- **파일**: [Todo완료및회의록반영.puml](./Todo완료및회의록반영.puml)
|
||||
- **관련 유저스토리**: UFR-TODO-030
|
||||
- **참여 서비스**: Frontend, API Gateway, Todo Service, Meeting Service, Notification Service, Redis, RabbitMQ, 각 서비스 DB
|
||||
- **주요 특징** (**차별화 포인트**):
|
||||
- Todo 완료가 회의록에 실시간 반영되는 양방향 연동
|
||||
- 완료 시간 및 완료자 정보 자동 기록
|
||||
- TodoCompleted 이벤트 → Meeting Service가 회의록 자동 업데이트
|
||||
- 모든 Todo 완료 시 전체 완료 알림 자동 발송
|
||||
- Cache-Aside 패턴으로 회의록 조회 최적화
|
||||
|
||||
### 15. 회의록 조회 및 수정
|
||||
- **파일**: [회의록조회및수정.puml](./회의록조회및수정.puml)
|
||||
- **관련 유저스토리**: UFR-MEET-046/047/055, UFR-COLLAB-010
|
||||
- **참여 서비스**: Frontend, API Gateway, Meeting Service, Collaboration Service, Redis, Meeting DB
|
||||
- **주요 특징**:
|
||||
- Cache-Aside 패턴으로 목록/상세 조회 (TTL: 10분)
|
||||
- 권한 검증 (본인 작성 회의록만 수정 가능)
|
||||
- 수정 이력 자동 기록 (수정자, 수정 시간, 변경 내용)
|
||||
- WebSocket 실시간 동기화 (델타만 전송)
|
||||
- 버전 관리 (새 버전 생성, 이전 버전 보관)
|
||||
- 확정완료 → 작성중 자동 상태 변경
|
||||
|
||||
---
|
||||
|
||||
## 설계 원칙 적용
|
||||
|
||||
### PlantUML 문법 검사
|
||||
✅ **모든 파일 검증 통과** (Docker 기반 PlantUML 검사 완료)
|
||||
- `!theme mono` 적용
|
||||
- 동기: 실선 (→), 비동기: 점선 (->>) 명확 구분
|
||||
- `..>` 사용 금지 (sequence diagram 원칙 준수)
|
||||
|
||||
### 논리 아키텍처 일치성
|
||||
- ✅ 참여자: 논리 아키텍처의 서비스, DB, 메시지 큐 구조 일치
|
||||
- ✅ 통신 방식: 동기(REST), 비동기(RabbitMQ), 실시간(WebSocket) 일치
|
||||
- ✅ 캐시 전략: Cache-Aside 패턴, TTL 설정 일치
|
||||
|
||||
### 유저스토리 커버리지
|
||||
- ✅ 신규 6개 플로우가 11개 유저스토리 완전 커버
|
||||
- ✅ 기존 9개 플로우와 통합하여 전체 시스템 커버
|
||||
|
||||
---
|
||||
|
||||
## 문서 이력
|
||||
|
||||
| 버전 | 작성일 | 작성자 | 변경 내용 |
|
||||
|------|--------|--------|----------|
|
||||
| 1.0 | 2025-01-22 | 길동 (Architect) | 초안 작성 (Flow 1-9) |
|
||||
| 2.0 | 2025-10-22 | 길동 (Architect) | 신규 6개 플로우 추가 (Flow 10-15), 병렬 처리 전략 적용 |
|
||||
211
design/backend/sequence/outer/Todo완료및회의록반영.puml
Normal file
211
design/backend/sequence/outer/Todo완료및회의록반영.puml
Normal file
@ -0,0 +1,211 @@
|
||||
@startuml Todo완료및회의록반영
|
||||
!theme mono
|
||||
|
||||
title 외부 시퀀스 다이어그램: Todo 완료 및 회의록 반영\n(Flow 5: Todo Completion and Meeting Minutes Reflection)
|
||||
|
||||
' 참여자 정의
|
||||
actor "사용자\n(Todo 담당자)" as User
|
||||
participant "Frontend" as FE
|
||||
participant "API Gateway" as GW
|
||||
participant "Todo Service" as TodoSvc
|
||||
participant "Meeting Service" as MeetingSvc
|
||||
participant "Notification Service" as NotifySvc
|
||||
database "Todo DB" as TodoDB
|
||||
database "Meeting DB" as MeetingDB
|
||||
queue "RabbitMQ" as MQ
|
||||
database "Redis Cache" as Redis
|
||||
|
||||
== Todo 완료 요청 ==
|
||||
|
||||
User -> FE: Todo 완료 버튼 클릭
|
||||
activate FE
|
||||
|
||||
FE -> FE: 완료 여부 확인 다이얼로그 표시
|
||||
FE --> User: 확인 요청 표시
|
||||
User -> FE: 완료 확인
|
||||
|
||||
FE -> GW: PUT /todos/{todoId}/complete
|
||||
activate GW
|
||||
note right: JWT 인증 및 권한 검증
|
||||
|
||||
GW -> TodoSvc: PUT /todos/{todoId}/complete
|
||||
activate TodoSvc
|
||||
|
||||
== Todo 완료 처리 ==
|
||||
|
||||
TodoSvc -> TodoDB: Todo 상태 업데이트\n(상태=완료, 완료시간, 완료자 기록)
|
||||
activate TodoDB
|
||||
TodoDB --> TodoSvc: 업데이트 완료
|
||||
deactivate TodoDB
|
||||
|
||||
note right of TodoSvc
|
||||
완료 처리 정보:
|
||||
- 완료 시간 자동 기록
|
||||
- 완료자 정보 저장
|
||||
- 완료 상태로 변경
|
||||
end note
|
||||
|
||||
== 캐시 무효화 ==
|
||||
|
||||
TodoSvc -> Redis: DEL todo:user:{userId}
|
||||
activate Redis
|
||||
Redis --> TodoSvc: 캐시 삭제 완료
|
||||
deactivate Redis
|
||||
|
||||
TodoSvc -> Redis: DEL todo:stats:{userId}
|
||||
activate Redis
|
||||
Redis --> TodoSvc: 캐시 삭제 완료
|
||||
deactivate Redis
|
||||
|
||||
note right of Redis
|
||||
캐시 무효화 대상:
|
||||
- todo:user:{userId}
|
||||
- todo:stats:{userId}
|
||||
end note
|
||||
|
||||
== TodoCompleted 이벤트 발행 ==
|
||||
|
||||
TodoSvc -> MQ: publish TodoCompleted\n(todoId, meetingId, userId, completedAt)
|
||||
activate MQ
|
||||
|
||||
note right of MQ
|
||||
이벤트 내용:
|
||||
- todoId: Todo ID
|
||||
- meetingId: 관련 회의 ID
|
||||
- userId: 완료자 ID
|
||||
- completedAt: 완료 시간
|
||||
- sectionId: 회의록 섹션 ID
|
||||
end note
|
||||
|
||||
TodoSvc --> GW: 200 OK\n(완료 처리 결과 반환)
|
||||
deactivate TodoSvc
|
||||
GW --> FE: 200 OK
|
||||
deactivate GW
|
||||
|
||||
FE -> FE: Todo 완료 상태 UI 업데이트
|
||||
FE --> User: 완료 처리 완료 표시
|
||||
deactivate FE
|
||||
|
||||
== Meeting Service: TodoCompleted 이벤트 구독 ==
|
||||
|
||||
MQ ->> MeetingSvc: TodoCompleted 이벤트 수신
|
||||
activate MeetingSvc
|
||||
|
||||
note right of MeetingSvc
|
||||
비동기 처리:
|
||||
구독자가 이벤트 수신
|
||||
end note
|
||||
|
||||
MeetingSvc -> Redis: GET meeting:info:{meetingId}
|
||||
activate Redis
|
||||
|
||||
alt 캐시 Hit
|
||||
Redis --> MeetingSvc: 회의 정보 반환
|
||||
else 캐시 Miss
|
||||
Redis --> MeetingSvc: null
|
||||
MeetingSvc -> MeetingDB: SELECT 회의 정보
|
||||
activate MeetingDB
|
||||
MeetingDB --> MeetingSvc: 회의 정보 반환
|
||||
deactivate MeetingDB
|
||||
|
||||
MeetingSvc -> Redis: SETEX meeting:info:{meetingId}\n(TTL: 10분)
|
||||
Redis --> MeetingSvc: 캐시 저장 완료
|
||||
end
|
||||
|
||||
deactivate Redis
|
||||
|
||||
note right of MeetingSvc
|
||||
Cache-Aside 패턴 적용:
|
||||
1. 캐시 조회 시도
|
||||
2. 캐시 미스 시 DB 조회
|
||||
3. 조회 결과 캐시 저장
|
||||
end note
|
||||
|
||||
== 회의록에 완료 상태 자동 반영 ==
|
||||
|
||||
MeetingSvc -> MeetingDB: UPDATE 회의록 Todo 섹션\n(완료 상태, 완료 시간, 완료자)
|
||||
activate MeetingDB
|
||||
|
||||
note right of MeetingDB
|
||||
회의록 반영 내용:
|
||||
- Todo 섹션에 완료 표시 (✅)
|
||||
- 완료 시간 기록
|
||||
- 완료자 정보 표시
|
||||
- 양방향 연결 유지
|
||||
end note
|
||||
|
||||
MeetingDB --> MeetingSvc: 업데이트 완료
|
||||
deactivate MeetingDB
|
||||
|
||||
== 캐시 무효화 ==
|
||||
|
||||
MeetingSvc -> Redis: DEL meeting:info:{meetingId}
|
||||
activate Redis
|
||||
Redis --> MeetingSvc: 캐시 삭제 완료
|
||||
deactivate Redis
|
||||
|
||||
note right of MeetingSvc
|
||||
회의록 수정 시 캐시 무효화:
|
||||
다음 조회 시 최신 정보 반영
|
||||
end note
|
||||
|
||||
== TranscriptUpdated 이벤트 발행 (선택) ==
|
||||
|
||||
MeetingSvc -> MQ: publish TranscriptUpdated\n(meetingId, updateType=TODO_COMPLETED)
|
||||
note right of MeetingSvc
|
||||
선택적 이벤트:
|
||||
실시간 협업 중인 경우
|
||||
다른 참석자에게 알림 가능
|
||||
end note
|
||||
|
||||
deactivate MeetingSvc
|
||||
|
||||
== Notification Service: TodoCompleted 이벤트 구독 ==
|
||||
|
||||
MQ ->> NotifySvc: TodoCompleted 이벤트 수신
|
||||
activate NotifySvc
|
||||
|
||||
NotifySvc -> NotifySvc: 알림 내용 생성
|
||||
note right of NotifySvc
|
||||
알림 내용:
|
||||
- Todo 완료 알림
|
||||
- 회의록 작성자에게 발송
|
||||
- 완료자 정보 포함
|
||||
end note
|
||||
|
||||
NotifySvc -> NotifySvc: 회의록 알림 발송\n(이메일)
|
||||
note right of NotifySvc
|
||||
알림 발송 대상:
|
||||
- 회의록 작성자
|
||||
- 참석자 (선택)
|
||||
end note
|
||||
|
||||
== 모든 Todo 완료 확인 ==
|
||||
|
||||
NotifySvc -> TodoDB: SELECT COUNT(*)\nWHERE meetingId={meetingId}\nAND status != COMPLETED
|
||||
activate TodoDB
|
||||
TodoDB --> NotifySvc: 미완료 Todo 개수 반환
|
||||
deactivate TodoDB
|
||||
|
||||
alt 모든 Todo 완료
|
||||
NotifySvc -> NotifySvc: 전체 완료 알림 생성
|
||||
note right of NotifySvc
|
||||
전체 완료 알림:
|
||||
- "모든 Todo가 완료되었습니다"
|
||||
- 회의록 작성자 및 참석자 전원 발송
|
||||
end note
|
||||
NotifySvc -> NotifySvc: 전체 완료 알림 발송\n(이메일)
|
||||
end
|
||||
|
||||
deactivate NotifySvc
|
||||
deactivate MQ
|
||||
|
||||
note over User, Redis
|
||||
차별화 포인트:
|
||||
- Todo 완료가 회의록에 실시간 반영되어 양방향 연동
|
||||
- 회의 결과 추적 용이
|
||||
- 완료 시간 및 완료자 정보 자동 기록
|
||||
- 모든 Todo 완료 시 전체 완료 알림 자동 발송
|
||||
end note
|
||||
|
||||
@enduml
|
||||
BIN
design/backend/sequence/outer/회의록조회및수정.png
Normal file
BIN
design/backend/sequence/outer/회의록조회및수정.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
123
design/backend/sequence/outer/회의록조회및수정.puml
Normal file
123
design/backend/sequence/outer/회의록조회및수정.puml
Normal file
@ -0,0 +1,123 @@
|
||||
@startuml 회의록조회및수정
|
||||
!theme mono
|
||||
|
||||
title 플로우 6: 회의록 조회 및 수정
|
||||
|
||||
actor "Frontend" as FE
|
||||
participant "API Gateway" as GW
|
||||
participant "Meeting Service" as MS
|
||||
participant "Collaboration Service" as CS
|
||||
participant "Redis" as RD
|
||||
database "Meeting DB" as MDB
|
||||
|
||||
== 회의록 목록 조회 ==
|
||||
FE -> GW: 회의록 목록 조회 요청\n(필터/정렬/검색 조건)
|
||||
activate GW
|
||||
GW -> MS: 목록 조회 요청
|
||||
activate MS
|
||||
|
||||
MS -> RD: 캐시 조회 (Cache-Aside)\nKey: meeting:list:{userId}:{filter}
|
||||
activate RD
|
||||
|
||||
alt Cache Hit
|
||||
RD --> MS: 캐시 데이터 반환
|
||||
MS --> GW: 목록 데이터 반환
|
||||
GW --> FE: 목록 표시
|
||||
else Cache Miss
|
||||
RD --> MS: 캐시 없음
|
||||
deactivate RD
|
||||
MS -> MDB: DB 조회\n(필터, 정렬, 검색 조건 적용)
|
||||
activate MDB
|
||||
MDB --> MS: 목록 데이터
|
||||
deactivate MDB
|
||||
MS -> RD: 캐시 저장 (TTL 10분)\nKey: meeting:list:{userId}:{filter}
|
||||
activate RD
|
||||
RD --> MS: 저장 완료
|
||||
deactivate RD
|
||||
MS --> GW: 목록 데이터 반환
|
||||
GW --> FE: 목록 표시
|
||||
end
|
||||
|
||||
deactivate MS
|
||||
deactivate GW
|
||||
|
||||
== 회의록 상세 조회 ==
|
||||
FE -> GW: 회의록 클릭\n회의록 상세 조회 요청
|
||||
activate GW
|
||||
GW -> MS: 상세 조회 요청 (meetingId)
|
||||
activate MS
|
||||
|
||||
MS -> RD: 캐시 조회 (Cache-Aside)\nKey: meeting:info:{meetingId}
|
||||
activate RD
|
||||
|
||||
alt Cache Hit
|
||||
RD --> MS: 캐시 데이터 반환\n(회의 정보, 섹션별 내용, 관련 회의록)
|
||||
MS --> GW: 상세 데이터 반환
|
||||
GW --> FE: 상세 정보 표시
|
||||
else Cache Miss
|
||||
RD --> MS: 캐시 없음
|
||||
deactivate RD
|
||||
MS -> MDB: DB 조회\n(회의 정보, 섹션별 내용, 관련 회의록)
|
||||
activate MDB
|
||||
MDB --> MS: 상세 데이터
|
||||
deactivate MDB
|
||||
MS -> RD: 캐시 저장 (TTL 10분)\nKey: meeting:info:{meetingId}
|
||||
activate RD
|
||||
RD --> MS: 저장 완료
|
||||
deactivate RD
|
||||
MS --> GW: 상세 데이터 반환
|
||||
GW --> FE: 상세 정보 표시
|
||||
end
|
||||
|
||||
deactivate MS
|
||||
deactivate GW
|
||||
|
||||
== 회의록 수정 ==
|
||||
FE -> GW: 수정 버튼 클릭
|
||||
activate GW
|
||||
GW -> MS: 권한 확인 요청
|
||||
activate MS
|
||||
MS -> MS: 수정 권한 검증\n(본인 작성 회의록만 수정 가능)
|
||||
|
||||
alt 권한 없음
|
||||
MS --> GW: 권한 오류
|
||||
GW --> FE: 수정 불가 알림
|
||||
else 권한 있음
|
||||
MS --> GW: 권한 확인 완료
|
||||
GW --> FE: 수정 모드 진입
|
||||
deactivate GW
|
||||
|
||||
FE -> GW: 회의록 수정 내용 전송
|
||||
activate GW
|
||||
GW -> MS: 수정 요청
|
||||
|
||||
MS -> MDB: 수정 내용 저장\n수정 이력 기록\n(수정자, 수정 시간, 변경 내용)
|
||||
activate MDB
|
||||
MDB --> MS: 저장 완료
|
||||
deactivate MDB
|
||||
|
||||
MS -> RD: 캐시 무효화\nKey: meeting:info:{meetingId}
|
||||
activate RD
|
||||
RD --> MS: 무효화 완료
|
||||
deactivate RD
|
||||
|
||||
MS ->> CS: 실시간 동기화 요청\n(비동기)
|
||||
activate CS
|
||||
CS ->> FE: WebSocket: 모든 참석자에게\n수정 델타 전송\n수정 영역 하이라이트 (3초간)
|
||||
deactivate CS
|
||||
|
||||
MS -> MDB: 새 버전 번호 생성\n이전 버전 보관
|
||||
activate MDB
|
||||
MDB --> MS: 버전 관리 완료
|
||||
deactivate MDB
|
||||
|
||||
note over MS: 확정완료 상태였던 경우\n작성중 상태로 변경
|
||||
|
||||
MS --> GW: 수정 완료 응답
|
||||
GW --> FE: 수정 완료 표시
|
||||
end
|
||||
|
||||
deactivate MS
|
||||
deactivate GW
|
||||
|
||||
@enduml
|
||||
243
design/backend/sequence/outer/회의록확정및공유.puml
Normal file
243
design/backend/sequence/outer/회의록확정및공유.puml
Normal file
@ -0,0 +1,243 @@
|
||||
@startuml 회의록확정및공유
|
||||
!theme mono
|
||||
|
||||
title 회의록 확정 및 공유 플로우 (UFR-MEET-060)
|
||||
|
||||
actor "사용자" as User
|
||||
participant "Frontend" as FE
|
||||
participant "API Gateway" as GW
|
||||
participant "Meeting Service" as MS
|
||||
participant "Notification Service" as NS
|
||||
participant "Redis" as Cache
|
||||
database "Meeting DB" as MDB
|
||||
queue "RabbitMQ" as MQ
|
||||
|
||||
== 회의록 확정 ==
|
||||
User -> FE: 회의록 확정 버튼 클릭
|
||||
activate FE
|
||||
|
||||
FE -> GW: POST /api/meetings/{meetingId}/minutes/finalize
|
||||
activate GW
|
||||
|
||||
GW -> MS: 회의록 확정 요청
|
||||
activate MS
|
||||
|
||||
MS -> MS: 필수 항목 검사\n(제목, 참석자, 논의 내용, 결정 사항)
|
||||
|
||||
alt 필수 항목 누락
|
||||
MS --> GW: 400 Bad Request\n{error: "필수 항목 누락", missingFields}
|
||||
deactivate MS
|
||||
GW --> FE: 오류 반환
|
||||
deactivate GW
|
||||
FE --> User: 필수 항목 누락 안내
|
||||
deactivate FE
|
||||
else 필수 항목 완료
|
||||
MS -> MDB: INSERT INTO minutes_versions\n(확정 버전 생성, 확정 시간 기록)\nUPDATE meetings SET minutes_status = 'finalized'
|
||||
activate MDB
|
||||
MDB --> MS: 확정 버전 ID 반환
|
||||
deactivate MDB
|
||||
|
||||
MS -> Cache: DEL meeting:info:{meetingId}\n(캐시 무효화)
|
||||
activate Cache
|
||||
Cache --> MS: OK
|
||||
deactivate Cache
|
||||
|
||||
MS --> GW: 200 OK\n{versionId, status: "finalized"}
|
||||
deactivate MS
|
||||
|
||||
GW --> FE: 회의록 확정 완료
|
||||
deactivate GW
|
||||
|
||||
FE --> User: 회의록 확정 완료 화면 표시
|
||||
deactivate FE
|
||||
end
|
||||
|
||||
== 회의록 공유 설정 ==
|
||||
User -> FE: 공유 설정 입력\n(대상: 참석자/전체/특정인, 권한: 읽기/편집, 방식: 링크/이메일)
|
||||
activate FE
|
||||
|
||||
FE -> GW: POST /api/meetings/{meetingId}/share\n{targets, permission, method, password, expiresAt}
|
||||
activate GW
|
||||
|
||||
GW -> MS: 공유 설정 요청
|
||||
activate MS
|
||||
|
||||
MS -> MS: 고유 공유 링크 생성\n(UUID 기반 URL)
|
||||
MS -> MDB: INSERT INTO share_settings\n(공유 대상, 권한, 링크, 비밀번호, 유효기간 저장)
|
||||
activate MDB
|
||||
MDB --> MS: 공유 설정 ID 반환
|
||||
deactivate MDB
|
||||
|
||||
MS -> Cache: SET share:link:{shareId}\n(공유 링크 정보 캐싱, TTL: 유효기간)
|
||||
activate Cache
|
||||
Cache --> MS: OK
|
||||
deactivate Cache
|
||||
|
||||
MS ->> MQ: TranscriptShared 이벤트 발행\n{meetingId, shareId, targets, shareUrl, method}
|
||||
activate MQ
|
||||
note right of MQ
|
||||
이벤트: TranscriptShared
|
||||
Routing Key: transcript.shared
|
||||
end note
|
||||
MQ -->> MS: ACK
|
||||
deactivate MQ
|
||||
|
||||
MS --> GW: 200 OK\n{shareUrl, shareId, expiresAt}
|
||||
deactivate MS
|
||||
|
||||
GW --> FE: 공유 링크 반환
|
||||
deactivate GW
|
||||
|
||||
FE --> User: 공유 링크 및 설정 표시
|
||||
deactivate FE
|
||||
|
||||
== 공유 알림 발송 (비동기) ==
|
||||
MQ ->> NS: TranscriptShared 이벤트 전달
|
||||
activate NS
|
||||
note right of NS
|
||||
구독: transcript.shared
|
||||
큐: notification.transcript.shared
|
||||
end note
|
||||
|
||||
alt 공유 방식: 이메일
|
||||
loop 각 대상
|
||||
NS -> NS: 이메일 템플릿 생성\n(회의 제목, 공유 링크, 유효기간, 비밀번호)
|
||||
NS -> NS: 이메일 발송
|
||||
end
|
||||
else 공유 방식: 링크만
|
||||
NS -> NS: 알림 생성\n(링크 복사 완료)
|
||||
end
|
||||
|
||||
NS -->> MQ: ACK
|
||||
deactivate NS
|
||||
|
||||
== 다음 회의 일정 자동 등록 (선택) ==
|
||||
opt 회의록에 다음 회의 언급 존재
|
||||
User -> FE: 다음 회의 일정 자동 등록 확인
|
||||
activate FE
|
||||
|
||||
FE -> GW: POST /api/meetings/{meetingId}/schedule-next
|
||||
activate GW
|
||||
|
||||
GW -> MS: 다음 회의 일정 등록 요청
|
||||
activate MS
|
||||
|
||||
MS -> MDB: SELECT next_meeting_info\nFROM minutes\nWHERE meeting_id = {meetingId}
|
||||
activate MDB
|
||||
MDB --> MS: 다음 회의 정보 반환\n{suggestedDate, suggestedTime, suggestedAttendees}
|
||||
deactivate MDB
|
||||
|
||||
MS -> MS: 캘린더 등록 데이터 생성\n(제목, 날짜, 시간, 참석자)
|
||||
MS -> MDB: INSERT INTO meetings\n(다음 회의 생성, 이전 회의 ID 링크)
|
||||
activate MDB
|
||||
MDB --> MS: 다음 회의 ID 반환
|
||||
deactivate MDB
|
||||
|
||||
MS ->> MQ: MeetingCreated 이벤트 발행\n(다음 회의 초대)
|
||||
activate MQ
|
||||
MQ -->> MS: ACK
|
||||
deactivate MQ
|
||||
|
||||
MS --> GW: 200 OK\n{nextMeetingId, status: "scheduled"}
|
||||
deactivate MS
|
||||
|
||||
GW --> FE: 다음 회의 등록 완료
|
||||
deactivate GW
|
||||
|
||||
FE --> User: 다음 회의 등록 완료 표시
|
||||
deactivate FE
|
||||
end
|
||||
|
||||
== 공유 링크 접근 (외부 사용자) ==
|
||||
actor "외부 사용자" as External
|
||||
External -> FE: 공유 링크 접근\n(GET /share/{shareId})
|
||||
activate FE
|
||||
|
||||
FE -> GW: 공유 링크 검증 요청
|
||||
activate GW
|
||||
|
||||
GW -> MS: 공유 설정 조회
|
||||
activate MS
|
||||
|
||||
MS -> Cache: GET share:link:{shareId}
|
||||
activate Cache
|
||||
|
||||
alt Cache Hit
|
||||
Cache --> MS: 공유 설정 반환
|
||||
else Cache Miss
|
||||
Cache --> MS: null
|
||||
MS -> MDB: SELECT * FROM share_settings\nWHERE share_id = {shareId}\nAND expires_at > NOW()
|
||||
activate MDB
|
||||
|
||||
alt 유효한 공유 링크
|
||||
MDB --> MS: 공유 설정 반환
|
||||
deactivate MDB
|
||||
|
||||
MS -> Cache: SET share:link:{shareId}\n(TTL: 남은 유효기간)
|
||||
Cache --> MS: OK
|
||||
else 만료 또는 존재하지 않음
|
||||
MDB --> MS: null
|
||||
deactivate MDB
|
||||
Cache --> MS: null
|
||||
MS --> GW: 404 Not Found\n{error: "공유 링크가 만료되었거나 존재하지 않습니다"}
|
||||
deactivate MS
|
||||
GW --> FE: 오류 반환
|
||||
deactivate GW
|
||||
FE --> External: 오류 화면 표시
|
||||
deactivate FE
|
||||
end
|
||||
end
|
||||
deactivate Cache
|
||||
|
||||
alt 비밀번호 설정된 경우
|
||||
MS --> GW: 비밀번호 요청
|
||||
deactivate MS
|
||||
GW --> FE: 비밀번호 입력 화면
|
||||
deactivate GW
|
||||
|
||||
External -> FE: 비밀번호 입력
|
||||
FE -> GW: 비밀번호 검증 요청
|
||||
activate GW
|
||||
|
||||
GW -> MS: 비밀번호 검증
|
||||
activate MS
|
||||
|
||||
alt 비밀번호 일치
|
||||
MS -> MDB: SELECT minutes\nFROM meetings\nWHERE meeting_id = {meetingId}
|
||||
activate MDB
|
||||
MDB --> MS: 회의록 반환
|
||||
deactivate MDB
|
||||
|
||||
MS --> GW: 200 OK\n{minutes, permission}
|
||||
deactivate MS
|
||||
|
||||
GW --> FE: 회의록 데이터 반환
|
||||
deactivate GW
|
||||
|
||||
FE --> External: 회의록 표시\n(권한에 따라 읽기/편집)
|
||||
deactivate FE
|
||||
else 비밀번호 불일치
|
||||
MS --> GW: 401 Unauthorized\n{error: "비밀번호가 일치하지 않습니다"}
|
||||
deactivate MS
|
||||
GW --> FE: 오류 반환
|
||||
deactivate GW
|
||||
FE --> External: 오류 화면 표시
|
||||
deactivate FE
|
||||
end
|
||||
else 비밀번호 미설정
|
||||
MS -> MDB: SELECT minutes\nFROM meetings\nWHERE meeting_id = {meetingId}
|
||||
activate MDB
|
||||
MDB --> MS: 회의록 반환
|
||||
deactivate MDB
|
||||
|
||||
MS --> GW: 200 OK\n{minutes, permission}
|
||||
deactivate MS
|
||||
|
||||
GW --> FE: 회의록 데이터 반환
|
||||
deactivate GW
|
||||
|
||||
FE --> External: 회의록 표시\n(권한에 따라 읽기/편집)
|
||||
deactivate FE
|
||||
end
|
||||
|
||||
@enduml
|
||||
170
design/backend/sequence/outer/회의시작및회의록작성.puml
Normal file
170
design/backend/sequence/outer/회의시작및회의록작성.puml
Normal file
@ -0,0 +1,170 @@
|
||||
@startuml 회의시작및회의록작성
|
||||
!theme mono
|
||||
|
||||
title 회의 시작 및 회의록 작성 플로우 (UFR-MEET-030, UFR-STT-010/020, UFR-AI-010, UFR-RAG-010/020, UFR-COLLAB-010)
|
||||
|
||||
actor "참석자" as User
|
||||
participant "Frontend" as FE
|
||||
participant "API Gateway" as GW
|
||||
participant "Meeting Service" as MS
|
||||
participant "STT Service" as STT
|
||||
participant "AI Service" as AI
|
||||
participant "RAG Service" as RAG
|
||||
participant "Collaboration Service" as CS
|
||||
participant "Redis" as Cache
|
||||
database "Meeting DB" as MDB
|
||||
database "STT DB" as STTDB
|
||||
database "AI DB" as AIDB
|
||||
database "RAG DB" as RAGDB
|
||||
queue "RabbitMQ" as MQ
|
||||
participant "Azure Speech" as Azure
|
||||
participant "LLM Server" as LLM
|
||||
|
||||
== 회의 시작 ==
|
||||
User -> FE: 회의 시작 버튼 클릭
|
||||
activate FE
|
||||
|
||||
FE -> GW: POST /api/meetings/{meetingId}/start
|
||||
activate GW
|
||||
|
||||
GW -> MS: 회의 시작 요청
|
||||
activate MS
|
||||
|
||||
MS -> MDB: UPDATE meetings\nSET start_time = NOW(), status = 'in_progress'\n세션 생성
|
||||
activate MDB
|
||||
MDB --> MS: 회의 시작 시간 기록 완료
|
||||
deactivate MDB
|
||||
|
||||
MS ->> MQ: MeetingStarted 이벤트 발행\n{meetingId, sessionId, startTime}
|
||||
activate MQ
|
||||
note right of MQ
|
||||
이벤트: MeetingStarted
|
||||
Routing Key: meeting.started
|
||||
end note
|
||||
MQ -->> MS: ACK
|
||||
deactivate MQ
|
||||
|
||||
MS --> GW: 200 OK\n{sessionId, status: "in_progress"}
|
||||
deactivate MS
|
||||
|
||||
GW --> FE: 회의 세션 정보 반환
|
||||
deactivate GW
|
||||
|
||||
FE --> User: 회의 진행 화면 표시
|
||||
deactivate FE
|
||||
|
||||
== 음성 녹음 시작 (비동기) ==
|
||||
MQ ->> STT: MeetingStarted 이벤트 전달
|
||||
activate STT
|
||||
note right of STT
|
||||
구독: meeting.started
|
||||
큐: stt.meeting.started
|
||||
end note
|
||||
|
||||
STT -> STTDB: INSERT INTO sessions\n(세션 생성)
|
||||
activate STTDB
|
||||
STTDB --> STT: 세션 ID 반환
|
||||
deactivate STTDB
|
||||
|
||||
STT -> STT: 음성 녹음 시작\n(실시간 스트림)
|
||||
STT -->> MQ: ACK
|
||||
deactivate STT
|
||||
|
||||
== 실시간 음성 인식 (5초 간격 반복) ==
|
||||
loop 발언 발생 (5초마다)
|
||||
User -> FE: 음성 발언
|
||||
activate FE
|
||||
|
||||
FE -> STT: 오디오 스트림 전송
|
||||
activate STT
|
||||
|
||||
STT -> Azure: 음성-텍스트 변환 요청\n(실시간 스트림)
|
||||
activate Azure
|
||||
Azure --> STT: 변환된 텍스트 반환\n{speaker, text, timestamp}
|
||||
deactivate Azure
|
||||
|
||||
STT -> STTDB: INSERT INTO transcripts\n(발언 텍스트 저장)
|
||||
activate STTDB
|
||||
STTDB --> STT: OK
|
||||
deactivate STTDB
|
||||
|
||||
STT ->> MQ: TranscriptReady 이벤트 발행\n{sessionId, speaker, text, timestamp}
|
||||
activate MQ
|
||||
note right of MQ
|
||||
이벤트: TranscriptReady
|
||||
Routing Key: transcript.ready
|
||||
주기: 5초
|
||||
end note
|
||||
MQ -->> STT: ACK
|
||||
deactivate MQ
|
||||
deactivate STT
|
||||
|
||||
== AI 회의록 자동 작성 (비동기) ==
|
||||
MQ ->> AI: TranscriptReady 이벤트 전달
|
||||
activate AI
|
||||
note right of AI
|
||||
구독: transcript.ready
|
||||
큐: ai.transcript.ready
|
||||
end note
|
||||
|
||||
AI -> AI: 회의 맥락 이해\n주제별 분류\n문장 다듬기
|
||||
AI -> LLM: 회의록 자동 작성 요청\n{context, transcript, history}
|
||||
activate LLM
|
||||
LLM --> AI: 회의록 초안 반환\n{summary, topics, keyPoints}
|
||||
deactivate LLM
|
||||
|
||||
AI -> AIDB: INSERT INTO minutes_draft\n(회의록 초안 저장)
|
||||
activate AIDB
|
||||
AIDB --> AI: OK
|
||||
deactivate AIDB
|
||||
|
||||
AI -> CS: 실시간 동기화 요청\n{delta, version}
|
||||
activate CS
|
||||
|
||||
CS -> FE: WebSocket 푸시\n(회의록 델타 전송)
|
||||
activate FE
|
||||
FE -> User: 회의록 실시간 업데이트 표시
|
||||
deactivate FE
|
||||
|
||||
CS --> AI: 동기화 완료
|
||||
deactivate CS
|
||||
|
||||
AI -->> MQ: ACK
|
||||
deactivate AI
|
||||
|
||||
== 전문용어 자동 감지 및 설명 (비동기) ==
|
||||
MQ ->> RAG: TranscriptReady 이벤트 전달
|
||||
activate RAG
|
||||
note right of RAG
|
||||
구독: transcript.ready
|
||||
큐: rag.transcript.ready
|
||||
end note
|
||||
|
||||
RAG -> RAG: 전문용어 자동 감지\n(NER, 도메인 사전)
|
||||
RAG -> RAGDB: SELECT explanation\nFROM terms\nWHERE term IN (detected_terms)
|
||||
activate RAGDB
|
||||
RAGDB --> RAG: 용어 설명 반환
|
||||
deactivate RAGDB
|
||||
|
||||
alt 맥락 기반 설명 필요
|
||||
RAG -> LLM: 맥락 기반 설명 생성 요청\n{term, context, domain}
|
||||
activate LLM
|
||||
LLM --> RAG: 맥락적 설명 반환
|
||||
deactivate LLM
|
||||
|
||||
RAG -> RAGDB: INSERT INTO explanations\n(생성된 설명 저장)
|
||||
activate RAGDB
|
||||
RAGDB --> RAG: OK
|
||||
deactivate RAGDB
|
||||
end
|
||||
|
||||
RAG -> FE: WebSocket 푸시\n(용어 설명 툴팁 데이터)
|
||||
activate FE
|
||||
FE -> User: 용어 설명 툴팁 표시
|
||||
deactivate FE
|
||||
|
||||
RAG -->> MQ: ACK
|
||||
deactivate RAG
|
||||
end
|
||||
|
||||
@enduml
|
||||
91
design/backend/sequence/outer/회의예약및초대.puml
Normal file
91
design/backend/sequence/outer/회의예약및초대.puml
Normal file
@ -0,0 +1,91 @@
|
||||
@startuml 회의예약및초대
|
||||
!theme mono
|
||||
|
||||
title 회의 예약 및 초대 플로우 (UFR-MEET-010)
|
||||
|
||||
actor "사용자" as User
|
||||
participant "Frontend" as FE
|
||||
participant "API Gateway" as GW
|
||||
participant "Meeting Service" as MS
|
||||
participant "User Service" as US
|
||||
participant "Redis" as Cache
|
||||
database "Meeting DB" as MDB
|
||||
queue "RabbitMQ" as MQ
|
||||
participant "Notification Service" as NS
|
||||
|
||||
User -> FE: 회의 정보 입력\n(제목, 날짜/시간, 장소, 참석자)
|
||||
activate FE
|
||||
|
||||
FE -> GW: POST /api/meetings\n(회의 예약 요청)
|
||||
activate GW
|
||||
|
||||
GW -> MS: 회의 생성 요청
|
||||
activate MS
|
||||
|
||||
== 참석자 정보 조회 (Cache-Aside 패턴) ==
|
||||
loop 각 참석자
|
||||
MS -> Cache: GET user:profile:{userId}
|
||||
activate Cache
|
||||
|
||||
alt Cache Hit
|
||||
Cache --> MS: 사용자 정보 반환
|
||||
else Cache Miss
|
||||
Cache --> MS: null
|
||||
MS -> US: GET /api/users/{userId}\n(사용자 프로필 조회)
|
||||
activate US
|
||||
US --> MS: 사용자 정보 반환
|
||||
deactivate US
|
||||
|
||||
MS -> Cache: SET user:profile:{userId}\n(TTL: 10분)
|
||||
Cache --> MS: OK
|
||||
end
|
||||
deactivate Cache
|
||||
end
|
||||
|
||||
== 회의 정보 저장 ==
|
||||
MS -> MDB: INSERT INTO meetings\n(회의 정보 저장)
|
||||
activate MDB
|
||||
MDB --> MS: 회의 ID 반환
|
||||
deactivate MDB
|
||||
|
||||
MS -> Cache: SET meeting:info:{meetingId}\n(TTL: 10분)
|
||||
activate Cache
|
||||
Cache --> MS: OK
|
||||
deactivate Cache
|
||||
|
||||
== 초대 이벤트 발행 (비동기) ==
|
||||
MS ->> MQ: MeetingCreated 이벤트 발행\n{meetingId, title, attendees, datetime}
|
||||
activate MQ
|
||||
note right of MQ
|
||||
이벤트: MeetingCreated
|
||||
Routing Key: meeting.created
|
||||
end note
|
||||
MQ -->> MS: ACK
|
||||
deactivate MQ
|
||||
|
||||
MS --> GW: 회의 ID 반환\n{meetingId, status: "scheduled"}
|
||||
deactivate MS
|
||||
|
||||
GW --> FE: 201 Created\n회의 생성 완료
|
||||
deactivate GW
|
||||
|
||||
FE --> User: 회의 예약 완료 화면 표시
|
||||
deactivate FE
|
||||
|
||||
== 초대 이메일 발송 (비동기) ==
|
||||
MQ ->> NS: MeetingCreated 이벤트 전달
|
||||
activate NS
|
||||
note right of NS
|
||||
구독: meeting.created
|
||||
큐: notification.meeting.created
|
||||
end note
|
||||
|
||||
loop 각 참석자
|
||||
NS -> NS: 이메일 템플릿 생성\n(회의 제목, 일시, 장소, 초대 링크)
|
||||
NS -> NS: 이메일 발송
|
||||
end
|
||||
|
||||
NS -->> MQ: ACK
|
||||
deactivate NS
|
||||
|
||||
@enduml
|
||||
194
design/backend/sequence/outer/회의종료및Todo추출.puml
Normal file
194
design/backend/sequence/outer/회의종료및Todo추출.puml
Normal file
@ -0,0 +1,194 @@
|
||||
@startuml 회의종료및Todo추출
|
||||
!theme mono
|
||||
|
||||
title 회의 종료 및 Todo 추출 플로우 (UFR-MEET-040/050, UFR-AI-020, UFR-TODO-010)
|
||||
|
||||
actor "사용자" as User
|
||||
participant "Frontend" as FE
|
||||
participant "API Gateway" as GW
|
||||
participant "Meeting Service" as MS
|
||||
participant "AI Service" as AI
|
||||
participant "Todo Service" as TS
|
||||
participant "Notification Service" as NS
|
||||
participant "Redis" as Cache
|
||||
database "Meeting DB" as MDB
|
||||
database "AI DB" as AIDB
|
||||
database "Todo DB" as TODB
|
||||
queue "RabbitMQ" as MQ
|
||||
participant "LLM Server" as LLM
|
||||
|
||||
== 회의 종료 ==
|
||||
User -> FE: 회의 종료 버튼 클릭
|
||||
activate FE
|
||||
|
||||
FE -> GW: POST /api/meetings/{meetingId}/end
|
||||
activate GW
|
||||
|
||||
GW -> MS: 회의 종료 요청
|
||||
activate MS
|
||||
|
||||
MS -> MDB: UPDATE meetings\nSET end_time = NOW(), status = 'completed'\n통계 생성 (duration, 참석자 수, 발언 수)
|
||||
activate MDB
|
||||
MDB --> MS: 회의 종료 시간 기록 및 통계 생성 완료
|
||||
deactivate MDB
|
||||
|
||||
MS ->> MQ: MeetingEnded 이벤트 발행\n{meetingId, sessionId, endTime, statistics}
|
||||
activate MQ
|
||||
note right of MQ
|
||||
이벤트: MeetingEnded
|
||||
Routing Key: meeting.ended
|
||||
end note
|
||||
MQ -->> MS: ACK
|
||||
deactivate MQ
|
||||
|
||||
MS --> GW: 200 OK\n{status: "completed", statistics}
|
||||
deactivate MS
|
||||
|
||||
GW --> FE: 회의 종료 확인
|
||||
deactivate GW
|
||||
|
||||
FE --> User: 회의 종료 화면 표시
|
||||
deactivate FE
|
||||
|
||||
== AI Todo 자동 추출 (비동기) ==
|
||||
MQ ->> AI: MeetingEnded 이벤트 전달
|
||||
activate AI
|
||||
note right of AI
|
||||
구독: meeting.ended
|
||||
큐: ai.meeting.ended
|
||||
end note
|
||||
|
||||
AI -> AIDB: SELECT transcript, summary\nFROM minutes_draft\nWHERE session_id = {sessionId}
|
||||
activate AIDB
|
||||
AIDB --> AI: 회의록 전체 내용 반환
|
||||
deactivate AIDB
|
||||
|
||||
AI -> AI: 액션 아이템 식별\n(동사 패턴, 시간 표현, 담당자 언급)
|
||||
AI -> LLM: Todo 추출 요청\n{transcript, context, attendees}
|
||||
activate LLM
|
||||
LLM --> AI: Todo 목록 반환\n{tasks: [{description, assignee, dueDate, priority, linkedSection}]}
|
||||
deactivate LLM
|
||||
|
||||
AI -> AIDB: UPDATE minutes_draft\nSET todos_extracted = TRUE\n(Todo 추출 완료 표시)
|
||||
activate AIDB
|
||||
AIDB --> AI: OK
|
||||
deactivate AIDB
|
||||
|
||||
AI ->> MQ: TodoExtracted 이벤트 발행\n{meetingId, todos: [{description, assignee, dueDate, priority, linkedSection}]}
|
||||
activate MQ
|
||||
note right of MQ
|
||||
이벤트: TodoExtracted
|
||||
Routing Key: todo.extracted
|
||||
end note
|
||||
MQ -->> AI: ACK
|
||||
deactivate MQ
|
||||
|
||||
AI -->> MQ: ACK (MeetingEnded)
|
||||
deactivate AI
|
||||
|
||||
== Todo 생성 및 할당 (비동기) ==
|
||||
MQ ->> TS: TodoExtracted 이벤트 전달
|
||||
activate TS
|
||||
note right of TS
|
||||
구독: todo.extracted
|
||||
큐: todo.extracted
|
||||
end note
|
||||
|
||||
loop 각 Todo
|
||||
TS -> TODB: INSERT INTO todos\n(Todo 생성, 담당자 할당, 회의록 섹션 링크)
|
||||
activate TODB
|
||||
TODB --> TS: Todo ID 반환
|
||||
deactivate TODB
|
||||
|
||||
TS -> Cache: SET todo:list:{userId}\n(사용자별 Todo 목록 캐싱, TTL: 5분)
|
||||
activate Cache
|
||||
Cache --> TS: OK
|
||||
deactivate Cache
|
||||
|
||||
TS ->> MQ: TodoCreated 이벤트 발행\n{todoId, assignee, description, dueDate, linkedSection}
|
||||
activate MQ
|
||||
note right of MQ
|
||||
이벤트: TodoCreated
|
||||
Routing Key: todo.created
|
||||
end note
|
||||
MQ -->> TS: ACK
|
||||
deactivate MQ
|
||||
end
|
||||
|
||||
TS -->> MQ: ACK (TodoExtracted)
|
||||
deactivate TS
|
||||
|
||||
== Todo 할당 알림 (비동기) ==
|
||||
MQ ->> NS: TodoCreated 이벤트 전달
|
||||
activate NS
|
||||
note right of NS
|
||||
구독: todo.created
|
||||
큐: notification.todo.created
|
||||
end note
|
||||
|
||||
NS -> NS: 알림 템플릿 생성\n(Todo 설명, 기한, 회의록 링크)
|
||||
NS -> NS: 담당자에게 알림 발송\n(이메일, 푸시 알림)
|
||||
|
||||
NS -->> MQ: ACK
|
||||
deactivate NS
|
||||
|
||||
== 회의 통계 및 Todo 목록 조회 ==
|
||||
User -> FE: 회의 상세 화면 조회
|
||||
activate FE
|
||||
|
||||
FE -> GW: GET /api/meetings/{meetingId}/summary
|
||||
activate GW
|
||||
|
||||
GW -> MS: 회의 통계 및 Todo 목록 조회
|
||||
activate MS
|
||||
|
||||
MS -> Cache: GET meeting:info:{meetingId}
|
||||
activate Cache
|
||||
|
||||
alt Cache Hit
|
||||
Cache --> MS: 회의 정보 반환
|
||||
else Cache Miss
|
||||
Cache --> MS: null
|
||||
MS -> MDB: SELECT * FROM meetings\nWHERE meeting_id = {meetingId}
|
||||
activate MDB
|
||||
MDB --> MS: 회의 정보 반환
|
||||
deactivate MDB
|
||||
|
||||
MS -> Cache: SET meeting:info:{meetingId}\n(TTL: 10분)
|
||||
Cache --> MS: OK
|
||||
end
|
||||
deactivate Cache
|
||||
|
||||
MS -> TS: GET /api/todos?meetingId={meetingId}
|
||||
activate TS
|
||||
|
||||
TS -> Cache: GET todo:list:meeting:{meetingId}
|
||||
activate Cache
|
||||
|
||||
alt Cache Hit
|
||||
Cache --> TS: Todo 목록 반환
|
||||
else Cache Miss
|
||||
Cache --> TS: null
|
||||
TS -> TODB: SELECT * FROM todos\nWHERE meeting_id = {meetingId}
|
||||
activate TODB
|
||||
TODB --> TS: Todo 목록 반환
|
||||
deactivate TODB
|
||||
|
||||
TS -> Cache: SET todo:list:meeting:{meetingId}\n(TTL: 5분)
|
||||
Cache --> TS: OK
|
||||
end
|
||||
deactivate Cache
|
||||
|
||||
TS --> MS: Todo 목록 반환
|
||||
deactivate TS
|
||||
|
||||
MS --> GW: 회의 통계 및 Todo 목록 반환\n{statistics, todos}
|
||||
deactivate MS
|
||||
|
||||
GW --> FE: 200 OK
|
||||
deactivate GW
|
||||
|
||||
FE --> User: 회의 통계 및 Todo 목록 표시
|
||||
deactivate FE
|
||||
|
||||
@enduml
|
||||
Loading…
x
Reference in New Issue
Block a user