diff --git a/claude/sequence-outer-design.md b/claude/sequence-outer-design.md new file mode 100644 index 0000000..fc60efe --- /dev/null +++ b/claude/sequence-outer-design.md @@ -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 diff --git a/design/backend/sequence/outer/01-사용자인증및대시보드조회.puml b/design/backend/sequence/outer/01-사용자인증및대시보드조회.puml new file mode 100644 index 0000000..ec0102a --- /dev/null +++ b/design/backend/sequence/outer/01-사용자인증및대시보드조회.puml @@ -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 diff --git a/design/backend/sequence/outer/02-회의예약및초대.puml b/design/backend/sequence/outer/02-회의예약및초대.puml new file mode 100644 index 0000000..5a866f0 --- /dev/null +++ b/design/backend/sequence/outer/02-회의예약및초대.puml @@ -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 diff --git a/design/backend/sequence/outer/03-회의시작및템플릿선택.puml b/design/backend/sequence/outer/03-회의시작및템플릿선택.puml new file mode 100644 index 0000000..d3f592b --- /dev/null +++ b/design/backend/sequence/outer/03-회의시작및템플릿선택.puml @@ -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 diff --git a/design/backend/sequence/outer/04-회의진행및실시간회의록작성.puml b/design/backend/sequence/outer/04-회의진행및실시간회의록작성.puml new file mode 100644 index 0000000..13bcde3 --- /dev/null +++ b/design/backend/sequence/outer/04-회의진행및실시간회의록작성.puml @@ -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 diff --git a/design/backend/sequence/outer/05-회의종료및Todo자동추출.puml b/design/backend/sequence/outer/05-회의종료및Todo자동추출.puml new file mode 100644 index 0000000..05690bb --- /dev/null +++ b/design/backend/sequence/outer/05-회의종료및Todo자동추출.puml @@ -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 diff --git a/design/backend/sequence/outer/06-회의록확정및공유.puml b/design/backend/sequence/outer/06-회의록확정및공유.puml new file mode 100644 index 0000000..ff6ba9a --- /dev/null +++ b/design/backend/sequence/outer/06-회의록확정및공유.puml @@ -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 diff --git a/design/backend/sequence/outer/07-회의록목록조회및상세조회.puml b/design/backend/sequence/outer/07-회의록목록조회및상세조회.puml new file mode 100644 index 0000000..1d34425 --- /dev/null +++ b/design/backend/sequence/outer/07-회의록목록조회및상세조회.puml @@ -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 diff --git a/design/backend/sequence/outer/08-맥락기반용어설명제공.puml b/design/backend/sequence/outer/08-맥락기반용어설명제공.puml new file mode 100644 index 0000000..e631042 --- /dev/null +++ b/design/backend/sequence/outer/08-맥락기반용어설명제공.puml @@ -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 diff --git a/design/backend/sequence/outer/09-Todo완료및회의록반영.puml b/design/backend/sequence/outer/09-Todo완료및회의록반영.puml new file mode 100644 index 0000000..e306497 --- /dev/null +++ b/design/backend/sequence/outer/09-Todo완료및회의록반영.puml @@ -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 diff --git a/design/backend/sequence/outer/README.md b/design/backend/sequence/outer/README.md new file mode 100644 index 0000000..723e177 --- /dev/null +++ b/design/backend/sequence/outer/README.md @@ -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
AI Service | 참석자 알림 발송
회의 분석 준비 | +| **MeetingEnded** | Meeting Service | STT Service
AI Service
Todo Service
Notification Service | 회의록 생성
AI 분석 시작
Todo 추출
종료 알림 | +| **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), 병렬 처리 전략 적용 | diff --git a/design/backend/sequence/outer/Todo완료및회의록반영.puml b/design/backend/sequence/outer/Todo완료및회의록반영.puml new file mode 100644 index 0000000..4e39185 --- /dev/null +++ b/design/backend/sequence/outer/Todo완료및회의록반영.puml @@ -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 diff --git a/design/backend/sequence/outer/회의록조회및수정.png b/design/backend/sequence/outer/회의록조회및수정.png new file mode 100644 index 0000000..c29396b Binary files /dev/null and b/design/backend/sequence/outer/회의록조회및수정.png differ diff --git a/design/backend/sequence/outer/회의록조회및수정.puml b/design/backend/sequence/outer/회의록조회및수정.puml new file mode 100644 index 0000000..5bb9164 --- /dev/null +++ b/design/backend/sequence/outer/회의록조회및수정.puml @@ -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 diff --git a/design/backend/sequence/outer/회의록확정및공유.puml b/design/backend/sequence/outer/회의록확정및공유.puml new file mode 100644 index 0000000..0e17357 --- /dev/null +++ b/design/backend/sequence/outer/회의록확정및공유.puml @@ -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 diff --git a/design/backend/sequence/outer/회의시작및회의록작성.puml b/design/backend/sequence/outer/회의시작및회의록작성.puml new file mode 100644 index 0000000..52a968f --- /dev/null +++ b/design/backend/sequence/outer/회의시작및회의록작성.puml @@ -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 diff --git a/design/backend/sequence/outer/회의예약및초대.puml b/design/backend/sequence/outer/회의예약및초대.puml new file mode 100644 index 0000000..d9839b8 --- /dev/null +++ b/design/backend/sequence/outer/회의예약및초대.puml @@ -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 diff --git a/design/backend/sequence/outer/회의종료및Todo추출.puml b/design/backend/sequence/outer/회의종료및Todo추출.puml new file mode 100644 index 0000000..5681748 --- /dev/null +++ b/design/backend/sequence/outer/회의종료및Todo추출.puml @@ -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