diff --git a/.gitignore b/.gitignore index 957f7bd..0303921 100644 --- a/.gitignore +++ b/.gitignore @@ -57,4 +57,4 @@ claudedocs/*back* logs/ **/logs/ *.log -**/*.log +**/*.log \ No newline at end of file diff --git a/build/reports/problems/problems-report.html b/build/reports/problems/problems-report.html index c046c57..c86c3c1 100644 --- a/build/reports/problems/problems-report.html +++ b/build/reports/problems/problems-report.html @@ -650,7 +650,7 @@ code + .copy-button { diff --git a/design/backend/sequence/inner/meeting-대시보드조회.puml b/design/backend/sequence/inner/meeting-대시보드조회.puml deleted file mode 100644 index f1698fd..0000000 --- a/design/backend/sequence/inner/meeting-대시보드조회.puml +++ /dev/null @@ -1,129 +0,0 @@ -@startuml meeting-대시보드조회 -!theme mono - -title Meeting Service - 대시보드조회 내부 시퀀스 - -participant "DashboardController" as Controller -participant "DashboardService" as Service -participant "MeetingRepository" as MeetingRepo -participant "TodoRepository" as TodoRepo -participant "MinutesRepository" as MinutesRepo -database "Redis Cache<>" as Cache -database "Meeting DB<>" as DB - -[-> Controller: GET /dashboard -activate Controller - -note over Controller -사용자 정보는 헤더에서 추출 -(userId, userName, email) -end note - -Controller -> Service: getDashboardData(userId) -activate Service - -' 캐시 조회 -Service -> Cache: GET dashboard:{userId} -activate Cache -Cache --> Service: 캐시 조회 결과 -deactivate Cache - -alt Cache Hit - Service --> Service: 캐시 데이터 반환 -else Cache Miss - ' 예정된 회의 조회 - Service -> MeetingRepo: findUpcomingMeetings(userId) - activate MeetingRepo - MeetingRepo -> DB: 예정된 회의 조회 - activate DB - DB --> MeetingRepo: 예정된 회의 목록 - deactivate DB - MeetingRepo --> Service: List - deactivate MeetingRepo - - ' 진행 중 Todo 조회 - Service -> TodoRepo: findActiveTodos(userId) - activate TodoRepo - TodoRepo -> DB: 진행 중 Todo 조회 - activate DB - DB --> TodoRepo: 진행 중 Todo 목록 - deactivate DB - TodoRepo --> Service: List - deactivate TodoRepo - - ' 최근 회의록 조회 - Service -> MinutesRepo: findRecentMinutes(userId) - activate MinutesRepo - MinutesRepo -> DB: 최근 회의록 조회 - activate DB - DB --> MinutesRepo: 최근 회의록 목록 - deactivate DB - MinutesRepo --> Service: List - deactivate MinutesRepo - - ' 통계 정보 조회 - Service -> MeetingRepo: countUpcomingMeetings(userId) - activate MeetingRepo - MeetingRepo -> DB: 예정된 회의 개수 조회 - activate DB - DB --> MeetingRepo: 예정된 회의 개수 - deactivate DB - MeetingRepo --> Service: int count - deactivate MeetingRepo - - Service -> TodoRepo: countActiveTodos(userId) - activate TodoRepo - TodoRepo -> DB: 진행 중 Todo 개수 조회 - activate DB - DB --> TodoRepo: 진행 중 Todo 개수 - deactivate DB - TodoRepo --> Service: int count - deactivate TodoRepo - - Service -> TodoRepo: calculateTodoCompletionRate(userId) - activate TodoRepo - TodoRepo -> DB: Todo 완료율 조회 - activate DB - DB --> TodoRepo: Todo 완료율 - deactivate DB - TodoRepo --> Service: double rate - deactivate TodoRepo - - note over Service - 비즈니스 로직: - - 데이터 조합 및 정제 - - DTO 변환 - - 통계 계산 - end note - - Service -> Service: 대시보드 데이터 조합 - - ' 캐시 저장 - Service -> Cache: SET dashboard:{userId}\n(TTL: 5분) - activate Cache - Cache --> Service: 캐시 저장 완료 - deactivate Cache -end - -Service --> Controller: DashboardResponse -deactivate Service - -note over Controller -응답 데이터 구조: -{ - "upcomingMeetings": [...], - "activeTodos": [...], - "recentMinutes": [...], - "statistics": { - "upcomingMeetingsCount": n, - "activeTodosCount": n, - "todoCompletionRate": n - } -} -end note - -return 200 OK\nDashboardResponse - -deactivate Controller - -@enduml diff --git a/design/backend/sequence/inner/meeting-최종회의록확정.puml b/design/backend/sequence/inner/meeting-최종회의록확정.puml deleted file mode 100644 index fcd5e27..0000000 --- a/design/backend/sequence/inner/meeting-최종회의록확정.puml +++ /dev/null @@ -1,118 +0,0 @@ -@startuml -!theme mono - -title 최종 회의록 확정 내부 시퀀스 - -participant "API Gateway<>" as Gateway -participant "MinutesController" as Controller -participant "MeetingService" as Service -participant "Meeting" as Domain -participant "TranscriptService" as TranscriptService -participant "MeetingRepository" as Repository -database "PostgreSQL<>" as DB -database "Redis Cache<>" as Cache -queue "Event Hub<>" as EventHub - -Gateway -> Controller: POST /api/minutes/{minutesId}/finalize -activate Controller - -Controller -> Service: confirmTranscript(meetingId) -activate Service - -Service -> Repository: findById(meetingId) -activate Repository -Repository -> DB: 회의 정보 조회\n(회의ID 기준) -activate DB -DB --> Repository: meeting_row -deactivate DB -Repository --> Service: Meeting entity -deactivate Repository - -Service -> Domain: confirmTranscript() -activate Domain - -Domain -> Domain: validateCanConfirm() -note right of Domain -회의록 확정 검증 규칙: - -1. 상태 검증: - - 회의 상태 = COMPLETED (종료됨) - - 회의록 상태 = DRAFT (작성중) - ✗ IN_PROGRESS → 400 Bad Request - -2. 권한 검증: - - 확정 요청자 = 회의 생성자 OR - - 확정 요청자 ∈ 참석자 목록 - ✗ 권한 없음 → 403 Forbidden - -3. 필수 항목 검증: - - 회의록 제목: NOT NULL, 길이 >= 5 - - 참석자 목록: 최소 1명 이상 - - 주요 논의 내용: NOT NULL, 길이 >= 20 - - 결정 사항: 최소 1개 이상 OR - "결정사항 없음" 명시적 표시 - ✗ 누락 → 400 Bad Request - (누락 항목 목록 반환) - -4. 데이터 무결성: - - 섹션별 내용 완결성 확인 - - 참조 링크 유효성 확인 - - 첨부 파일 접근 가능 여부 - ✗ 무결성 위반 → 400 Bad Request - -5. 이력 검증: - - 마지막 수정 후 24시간 경과 경고 - - 미승인 AI 제안 존재 시 알림 - ⚠️ 경고만 표시, 진행 가능 -end note - -Domain -> Domain: changeStatus(CONFIRMED) - -Domain --> Service: updated Meeting -deactivate Domain - -Service -> TranscriptService: lockTranscript(meetingId) -activate TranscriptService -note right of TranscriptService -회의록 잠금: -- 더 이상 수정 불가 -- 버전 고정 -end note -TranscriptService --> Service: lockedTranscript -deactivate TranscriptService - -Service -> Repository: save(meeting) -activate Repository -Repository -> DB: 회의 상태 업데이트\n(상태='확정', 확정일시) -activate DB -DB --> Repository: affected_rows -deactivate DB -Repository --> Service: savedMeeting -deactivate Repository - -Service -> Cache: SET meeting:{id}\n(TTL: 10분) -activate Cache -note right of Cache - 회의 정보 캐싱: - - TTL: 10분 - - 자동 만료 -end note -Cache --> Service: OK -deactivate Cache - -Service ->> EventHub: publish(MinutesFinalized) -activate EventHub -note right of EventHub -비동기 이벤트: -- 참석자에게 최종본 알림 -- 공유 서비스로 전송 -end note -deactivate EventHub - -Service --> Controller: MeetingResponse -deactivate Service - -Controller --> Gateway: 200 OK -deactivate Controller - -@enduml diff --git a/design/backend/sequence/outer/Todo완료및회의록반영.puml b/design/backend/sequence/outer/Todo완료및회의록반영.puml deleted file mode 100644 index 790e4a3..0000000 --- a/design/backend/sequence/outer/Todo완료및회의록반영.puml +++ /dev/null @@ -1,74 +0,0 @@ -@startuml Todo완료및회의록반영 -!theme mono - -title Todo 완료 및 회의록 반영 플로우 - -actor "담당자" as User -participant "Web App" as Web -participant "API Gateway" as Gateway -participant "Meeting Service" as Meeting -participant "Redis Cache" as Redis -participant "Notification Service" as Notification - -note over Gateway - 라우팅 규칙: - /api/meetings/** → Meeting Service - /api/minutes/** → Meeting Service - /api/dashboard → User Service - /api/notifications/** → Notification Service - /api/auth/** → User Service - /api/todos/** → Meeting Service -end note - -autonumber - -== Todo 완료 처리 == -User -> Web: Todo 완료 버튼 클릭 -activate Web -Web -> Gateway: PATCH /api/todos/{todoId}/complete\n(userId, userName, completedAt) -activate Gateway -Gateway -> Meeting: PATCH /todos/{todoId}/complete\n(userId, userName, completedAt) -activate Meeting - -Meeting -> Meeting: Todo 상태 업데이트\n- 완료 시간 기록\n- 완료자 정보 저장\n- 상태: COMPLETED -Meeting -> Meeting: 관련 회의록에 완료 상태 반영\n- 회의록 섹션 업데이트\n- 완료 표시 (체크 아이콘)\n- 완료 시간 및 완료자 기록 -Meeting -> Meeting: DB에 저장 - -== 캐시 무효화 == -Meeting --> Redis: DELETE dashboard:{assigneeId} -note right -대시보드 캐시 무효화 -end note -Meeting --> Redis: DELETE minutes:detail:{minutesId} -note right -회의록 상세 캐시 무효화 -end note - -== 이벤트 발행 == -Meeting -> Notification: NotificationRequest 이벤트 발행 -activate Notification -note right - 이벤트 데이터: - - 발송수단: EMAIL - - 대상자: 회의록 작성자 - - 메시지: Todo 완료 안내 - - 메타데이터: todoId, 완료자, 완료 시간 -end note - -Meeting --> Gateway: 200 OK\n{todoId, status: COMPLETED,\ncompletedAt, completedBy} -deactivate Meeting -Gateway --> Web: 200 OK\n(Todo 완료 정보) -deactivate Gateway -Web --> User: Todo 완료 표시 -deactivate Web - -== 알림 발송 == -Notification -> Notification: NotificationRequest 이벤트 구독 -Notification -> Notification: 알림 메시지 생성\n- 수신자: 회의록 작성자\n- 내용: "Todo 완료됨" -Notification --> Notification: 이메일 발송\n(회의록 작성자에게) -note right -외부 Email Service 연동 -end note -deactivate Notification - -@enduml diff --git a/design/backend/sequence/outer/대시보드조회.puml b/design/backend/sequence/outer/대시보드조회.puml deleted file mode 100644 index 5def56b..0000000 --- a/design/backend/sequence/outer/대시보드조회.puml +++ /dev/null @@ -1,113 +0,0 @@ -@startuml 대시보드조회 -!theme mono - -title 대시보드조회 외부 시퀀스 - -actor "사용자" as User -participant "Web App" as Frontend -participant "API Gateway" as Gateway -participant "User Service" as UserService -participant "Meeting Service" as MeetingService -database "Redis Cache" as Cache -database "User DB" as UserDB -database "Meeting DB" as MeetingDB - -note over Gateway - 라우팅 규칙: - /api/meetings/** → Meeting Service - /api/minutes/** → Meeting Service - /api/dashboard → User Service - /api/notifications/** → Notification Service - /api/auth/** → User Service - /api/todos/** → Meeting Service -end note - -User -> Frontend: 대시보드 접근 -activate Frontend - -Frontend -> Gateway: GET /api/dashboard?\npage=1&size=10&sort=createdAt,desc -note right - 페이지네이션 파라미터: - - page: 페이지 번호 (기본값: 1) - - size: 페이지 크기 (기본값: 10) - - sort: 정렬 기준 (기본값: createdAt,desc) -end note -activate Gateway - -Gateway -> UserService: GET /dashboard?\npage=1&size=10&sort=createdAt,desc -activate UserService - -' 캐시 조회 -UserService -> Cache: GET dashboard:{userId} -activate Cache -Cache --> UserService: 캐시 조회 결과 -deactivate Cache - -alt Cache Hit - UserService -> UserService: 캐시 데이터 반환 -else Cache Miss - par 병렬 데이터 조회 - ' Meeting Service 호출 - UserService -> MeetingService: GET /api/v1/dashboard - note right - Meeting Service에서 조회: - - 예정된 회의 목록 - - 진행 중 Todo 목록 - - 최근 회의록 목록 - - 공유받은 회의록 - - 통계 정보 - end note - activate MeetingService - MeetingService -> Cache: GET dashboard:{userId} - activate Cache - Cache --> MeetingService: 캐시 조회 결과 - deactivate Cache - - alt Meeting Service 캐시 미존재 - MeetingService -> MeetingDB: 회의/Todo/회의록 데이터 조회 - activate MeetingDB - MeetingDB --> MeetingService: 조회 결과 - deactivate MeetingDB - - MeetingService -> Cache: SET dashboard:{userId}\n(TTL: 5분) - activate Cache - Cache --> MeetingService: 캐시 저장 - deactivate Cache - end - - MeetingService --> UserService: 회의 관련 데이터 응답\n{\n "upcomingMeetings": [...],\n "activeTodos": [...],\n "recentMinutes": [...],\n "sharedMinutes": [...],\n "statistics": {...}\n} - deactivate MeetingService - else - ' User Service 자체 데이터 조회 - UserService -> UserDB: 최근 활동 내역 조회 - activate UserDB - UserDB --> UserService: 활동 내역 - deactivate UserDB - end - - UserService -> UserService: 데이터 통합 및 조합 - note right - 대시보드 데이터 구성: - - Meeting Service 데이터 - - User Service 활동 내역 - - 통합 통계 정보 - end note - - UserService -> Cache: SET dashboard:{userId}\n(TTL: 5분) - activate Cache - Cache --> UserService: 캐시 저장 완료 - deactivate Cache -end - -UserService --> Gateway: 대시보드 데이터 응답\n{\n "upcomingMeetings": [...],\n "activeTodos": [...],\n "recentMinutes": [...],\n "recentActivities": [...],\n "statistics": {...},\n "pagination": {\n "page": 1,\n "size": 10,\n "totalElements": 45,\n "totalPages": 5,\n "hasNext": true\n }\n} -deactivate UserService - -Gateway --> Frontend: 200 OK\n대시보드 데이터 + 페이지네이션 정보 -deactivate Gateway - -Frontend -> Frontend: 대시보드 화면 렌더링\n- 예정된 회의 표시\n- Todo 목록 표시\n- 최근 회의록 표시\n- 통계 차트 표시 - -Frontend --> User: 대시보드 화면 표시 -deactivate Frontend - -@enduml diff --git a/design/backend/sequence/outer/회의시작및실시간회의록작성.puml b/design/backend/sequence/outer/회의시작및실시간회의록작성.puml index e519cd8..9e3bd59 100644 --- a/design/backend/sequence/outer/회의시작및실시간회의록작성.puml +++ b/design/backend/sequence/outer/회의시작및실시간회의록작성.puml @@ -33,7 +33,7 @@ activate Gateway Gateway -> Meeting: POST /meetings/{meetingId}/start activate Meeting -Meeting -> Meeting: 회의 세션 생성 +Meeting -> Meeting: 회의 세션 생성\n- Session 객체 생성\n- Minutes 초기화 (DRAFT)\n- WebSocket URL 생성 Meeting -> STT: POST /stt/recording/start\n(meetingId, participantIds) activate STT @@ -47,7 +47,7 @@ STT -> STT: 음성 녹음 준비 및 시작 STT --> Meeting: 200 OK (recordingId) deactivate STT -Meeting --> Gateway: 201 Created +Meeting --> Gateway: 201 Created\n- sessionId\n- meetingId\n- minutesId\n- status (IN_PROGRESS)\n- websocketUrl\n- sessionToken\n- startedAt\n- expiresAt deactivate Meeting Gateway --> Frontend: 201 Created diff --git a/design/backend/sequence/outer/회의예약및참석자초대.puml b/design/backend/sequence/outer/회의예약및참석자초대.puml index 96c96e4..139041c 100644 --- a/design/backend/sequence/outer/회의예약및참석자초대.puml +++ b/design/backend/sequence/outer/회의예약및참석자초대.puml @@ -27,7 +27,7 @@ end note User -> WebApp: 회의 정보 입력\n(제목, 날짜/시간, 장소, 참석자) activate WebApp -WebApp -> Gateway: POST /api/meetings\n+ JWT 토큰\n+ 사용자 정보 (userId, userName, email) +WebApp -> Gateway: POST /api/meetings/reserve\n+ JWT 토큰\n+ 사용자 정보 (userId, userName, email) activate Gateway Gateway -> Meeting: 회의 생성 요청 @@ -69,6 +69,30 @@ deactivate Gateway WebApp --> User: 회의 예약 완료 표시\n캘린더에 자동 등록 deactivate WebApp +== 템플릿 선택 (선택 사항) == +User -> WebApp: 템플릿 선택\n(일반, 스크럼, 킥오프, 주간) +activate WebApp + +WebApp -> Gateway: PUT /api/meetings/{meetingId}/template\n+ JWT 토큰\n+ templateId +activate Gateway + +Gateway -> Meeting: 템플릿 적용 요청 +activate Meeting + +Meeting -> MeetingDB: 템플릿 정보 저장 +activate MeetingDB +MeetingDB --> Meeting: 저장 완료 +deactivate MeetingDB + +Meeting --> Gateway: 200 OK\n템플릿 적용 완료 +deactivate Meeting + +Gateway --> WebApp: 템플릿 적용 응답 +deactivate Gateway + +WebApp --> User: 템플릿 적용 완료 +deactivate WebApp + == 참석자 초대 알림 (비동기) == EventHub -> Notification: NotificationRequest 이벤트 수신\n(Consumer Group: notification-service-group) diff --git a/design/backend/sequence/outer/회의종료및최종확정.puml b/design/backend/sequence/outer/회의종료및최종확정.puml index 1ac957e..7ffb03a 100644 --- a/design/backend/sequence/outer/회의종료및최종확정.puml +++ b/design/backend/sequence/outer/회의종료및최종확정.puml @@ -32,8 +32,15 @@ note right end note Gateway -> Meeting: 회의 종료 요청 -Meeting -> Meeting: 회의 종료 처리\n- 종료 시간 기록\n- 회의 통계 생성\n (총 시간, 참석자 수, 발언 횟수 등) -Meeting -> Meeting: DB 저장 +Meeting -> Meeting: 회의 종료 처리\n- 종료 시간 기록\n- 회의록 생성 (DRAFT 상태)\n- 회의 통계 생성\n (총 시간, 참석자 수 등) + +Meeting -> AI: AI 분석 요청\n- 키워드 추출\n- 안건별 요약 생성\n- Todo 항목 추출 +activate AI +AI -> AI: AI 분석 수행 +AI --> Meeting: AI 분석 결과\n(keywords, agendaSummaries, todos) +deactivate AI + +Meeting -> Meeting: DB 저장\n- Meeting 종료 상태\n- Minutes 생성 (DRAFT)\n- AgendaSection 저장\n- Todo 저장 Meeting -> Meeting: Redis 캐시 무효화\n(meeting:info:{meetingId}) Meeting -> EventHub: MeetingEnded 이벤트 발행\n(meetingId, userId, endTime) @@ -55,9 +62,9 @@ end note EventHub --> Meeting: 발행 완료 deactivate EventHub -Meeting -> Gateway: 202 Accepted\n(회의 종료 완료) -Gateway -> WebApp: 회의 종료 완료 응답 -WebApp -> User: 회의 통계 표시\n(총 시간, 참석자, 발언 횟수 등) +Meeting -> Gateway: 200 OK\n- minutesId\n- 회의 통계 (참석자 수, 시간, 안건 수, Todo 수)\n- 키워드 목록\n- 안건별 AI 요약 (한줄 요약, 상세 요약)\n- Todo 목록 +Gateway -> WebApp: 회의 종료 완료 응답\n(MeetingEndResponse) +WebApp -> User: 회의 종료 화면 표시\n- 통계 카드\n- 키워드 태그\n- 안건 아코디언 (AI 요약 + Todo) == 비동기 처리 - STT 종료 == EventHub --> STT: MeetingEnded 이벤트 수신 @@ -76,43 +83,62 @@ note right end note == 최종 회의록 확정 == -User -> WebApp: 최종 회의록 확정 버튼 클릭 -WebApp -> Gateway: POST /api/minutes/{minutesId}/finalize +User -> WebApp: 최종 회의록 확정 버튼 클릭\n(회의록 수정 화면 또는 회의 종료 화면) +WebApp -> Gateway: POST /api/meetings/minutes/{minutesId}/finalize note right 요청 헤더에 JWT 토큰 포함 - 요청 바디에 사용자 정보 포함 + X-User-Id, X-User-Name, X-User-Email end note Gateway -> Meeting: 회의록 확정 요청 -Meeting -> Meeting: 필수 항목 검사\n- 회의 제목\n- 참석자 목록\n- 주요 논의 내용\n- 결정 사항 +Meeting -> Meeting: 회의록 상태 변경\n- DRAFT → FINALIZED\n- finalizedAt 기록\n- finalizedBy 기록 -alt 필수 항목 미작성 - Meeting -> Gateway: 400 Bad Request\n(누락된 항목 정보) - Gateway -> WebApp: 검증 실패 응답 - WebApp -> User: 누락된 항목 안내\n(해당 섹션으로 자동 이동) -else 필수 항목 작성 완료 - Meeting -> Meeting: 회의록 최종 확정\n- 확정 버전 생성\n- 확정 시간 기록 - Meeting -> Meeting: DB 저장 (MinutesVersion) - Meeting -> Meeting: Redis 캐시 무효화 +Meeting -> Meeting: DB 저장\n- Minutes 상태 업데이트 +Meeting -> Meeting: Redis 캐시 저장\n(확정된 회의록, TTL: 10분) +Meeting -> Meeting: Redis 목록 캐시 무효화\n(사용자별 회의록 목록) - Meeting -> EventHub: NotificationRequest 이벤트 발행\n(회의록 확정 알림) - activate EventHub - note right - 이벤트 데이터: - - 발송수단: EMAIL - - 대상자: 참석자 전원 - - 메시지: 회의록 확정 안내 - - 메타데이터: 버전 번호, 확정 시간 - end note - EventHub --> Meeting: 발행 완료 - deactivate EventHub +Meeting -> EventHub: MinutesFinalizedEvent 발행\n(알림용 - 기존) +activate EventHub +note right + 간단한 이벤트 데이터: + - minutesId + - title + - userId + - userName +end note +EventHub --> Meeting: 발행 완료 +deactivate EventHub - Meeting -> Gateway: 200 OK\n(확정 버전 정보) - Gateway -> WebApp: 회의록 확정 완료 - WebApp -> User: 확정 완료 안내\n(버전 번호, 확정 시간) +Meeting -> EventHub: MinutesFinalizedEvent 발행\n(RAG용 - 완전한 데이터) +activate EventHub +note right + 완전한 이벤트 데이터: + - Meeting 정보 (meetingId, title, purpose, scheduledAt 등) + - Minutes 정보 (minutesId, status, version 등) + - Sections 정보 (모든 안건 섹션) + - 참석자 정보 +end note +EventHub --> Meeting: 발행 완료 +deactivate EventHub - EventHub --> Notification: NotificationRequest 이벤트 수신 - Notification -> Notification: 회의록 확정 알림 발송\n(참석자 전원) -end +Meeting -> Gateway: 200 OK\n(확정된 회의록 상세 정보) +Gateway -> WebApp: 회의록 확정 완료 +WebApp -> User: 확정 완료 토스트 표시\n회의록 상세 조회 화면으로 이동 + +== 비동기 처리 - 알림 발송 == +EventHub --> Notification: MinutesFinalizedEvent 수신\n(알림용) +Notification -> Notification: 회의록 확정 알림 발송\n(참석자 전원) +note right + 알림 내용: + - 회의 제목 + - 확정 시간 + - 회의록 링크 +end note + +== 비동기 처리 - RAG 저장 == +EventHub --> AI: MinutesFinalizedEvent 수신\n(RAG용) +activate AI +AI -> AI: RAG 서비스 연동\n- 벡터 DB 저장\n- 관련 회의록 검색 준비 +deactivate AI @enduml