From b2f66756e225d71e0d1a1a755e9f2cf183e807e4 Mon Sep 17 00:00:00 2001 From: hjmoons Date: Wed, 22 Oct 2025 17:32:02 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=EB=82=B4=EB=B6=80=20=EC=8B=9C=ED=80=80?= =?UTF-8?q?=EC=8A=A4=20=EC=8B=A4=EC=8B=9C=EA=B0=84=20=EC=B6=94=EC=B2=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20DB=EC=A1=B0=ED=9A=8C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sequence/inner/ai-결정사항제안.puml | 146 +++++++---------- .../sequence/inner/ai-논의사항제안.puml | 112 +++++-------- .../sequence/inner/ai-실시간Todo추출.puml | 151 ++++++------------ 3 files changed, 150 insertions(+), 259 deletions(-) diff --git a/design/backend/sequence/inner/ai-결정사항제안.puml b/design/backend/sequence/inner/ai-결정사항제안.puml index db871af..2acae10 100644 --- a/design/backend/sequence/inner/ai-결정사항제안.puml +++ b/design/backend/sequence/inner/ai-결정사항제안.puml @@ -6,27 +6,22 @@ title AI Service 내부 시퀀스 - 결정사항제안 participant "SuggestionController" as Controller participant "DecisionSuggestionService" as Service participant "LLMClient" as LLM -participant "SuggestionRepository" as Repo participant "TranscriptRepository" as TranscriptRepo database "Azure OpenAI<>" as OpenAI +database "Redis Cache<>" as Cache database "PostgreSQL<>" as DB == 실시간 결정사항 제안 요청 == note over Controller TranscriptService로부터 호출 - 또는 API 직접 호출: - POST /api/ai/suggestions/decision - Body: { - "meetingId": "{meetingId}", - "transcriptText": "최근 대화 내용" - } + (회의록 자동작성 프로세스 내부) end note Controller -> Service: suggestDecisions(meetingId, transcriptText) activate Service -== 회의 맥락 및 이전 결정 조회 == +== 회의 맥락 조회 == Service -> TranscriptRepo: getMeetingContext(meetingId) activate TranscriptRepo @@ -40,17 +35,15 @@ deactivate DB TranscriptRepo --> Service: meetingContext deactivate TranscriptRepo -Service -> Repo: getPreviousDecisions(meetingId) -activate Repo +Service -> Cache: GET decisions:{meetingId} +activate Cache +note right + 이전에 감지한 결정사항 조회 + (중복 제거용) +end note -Repo -> DB: SELECT content FROM ai_suggestions\nWHERE meeting_id = {meetingId}\nAND suggestion_type = 'DECISION'\nAND status = 'APPLIED' -activate DB - -DB --> Repo: 이미 확정된 결정사항 -deactivate DB - -Repo --> Service: previousDecisions -deactivate Repo +Cache --> Service: previousDecisions +deactivate Cache == LLM 기반 결정사항 패턴 감지 == @@ -69,7 +62,7 @@ note right 사용자 프롬프트: - 회의 참석자: {participants} - - 이미 확정된 결정: {previousDecisions} + - 이미 감지한 결정: {previousDecisions} - 현재 대화 내용: {transcriptText} 지시사항: @@ -140,7 +133,7 @@ Service -> Service: 결정사항 검증 note right 검증 기준: - 신뢰도 70% 이상만 선택 - - 중복 제거 (이미 확정된 결정) + - 중복 제거 (이미 감지한 결정) - 명확성 검증 * 주어, 목적어가 명확한가? * 결정 내용이 구체적인가? @@ -155,46 +148,32 @@ loop 각 제안마다 추가 정보: - 생성 시각 - 회의 진행 시점 (분) - - 원문 위치 (라인 번호) - - 상태: PENDING - - 관련 논의사항 참조 + - 원문 위치 정보 + - 고유 ID (UUID) end note end -== 제안 저장 == +== 임시 캐시 저장 (선택적) == -loop 각 검증된 제안마다 +Service -> Cache: APPEND decisions:{meetingId} +activate Cache +note right + Redis에 임시 저장: + - Key: decisions:{meetingId} + - Value: JSON array (제안 목록) + - TTL: 2시간 (회의 시간) + - APPEND로 기존 목록에 추가 - Service -> Repo: saveSuggestion(meetingId, decision) - activate Repo + 목적: + - 중복 감지용 + - 재접속 시 복원용 +end note - Repo -> DB: INSERT INTO ai_suggestions - activate DB - note right - 저장 데이터: - - meeting_id - - suggestion_type: 'DECISION' - - content: {decision 내용} - - category: 결정 카테고리 - - decision_maker: 결정자 - - participants: 참여자 목록 (JSON) - - confidence_score: 0.0-1.0 - - extracted_from: 원문 - - context: 결정 배경 - - status: PENDING - - created_at - end note +Cache --> Service: 저장 완료 +deactivate Cache - DB --> Repo: suggestionId - deactivate DB - - Repo --> Service: suggestionId - deactivate Repo - -end - -== 응답 구성 == +== 응답 반환 == Service -> Service: 응답 데이터 구성 note right @@ -208,20 +187,22 @@ note right "decisionMaker": "김철수", "confidence": 0.85, "extractedFrom": "원문 발췌", - "context": "결정 배경 설명", - "canApply": true + "context": "결정 배경 설명" } ], "totalCount": 제안 개수, - "displayHint": "오른쪽 탭 '결정사항' 섹션" + "timestamp": "생성 시각" } end note -Service --> Controller: 결정사항 제안 생성 완료 +Service --> Controller: 결정사항 제안 목록 deactivate Service -Controller --> Controller: 200 OK 응답 반환 +Controller --> Controller: 이벤트 데이터에 포함하여 반환 note right + TranscriptSummaryCreated 이벤트에 + decisionSuggestions 필드로 포함 + 프론트엔드 처리: - 오른쪽 "추천" 탭의 "결정사항" 섹션 표시 - "적용" 버튼 활성화 @@ -234,49 +215,36 @@ end note note over Controller 사용자가 "적용" 버튼 클릭 시: - PUT /api/ai/suggestions/{suggestionId}/apply -end note + 프론트엔드에서 직접 Meeting Service 호출 -Controller -> Service: applySuggestion(suggestionId, meetingId) -activate Service + PUT /api/meetings/{meetingId}/transcript + Body: { + "addDecisionSection": { + "content": "결정 내용", + "category": "기술", + "decisionMaker": "김철수" + } + } -Service -> Repo: updateSuggestionStatus(suggestionId, "APPLIED") -activate Repo - -Repo -> DB: UPDATE ai_suggestions\nSET status = 'APPLIED',\napplied_at = NOW() -activate DB - -DB --> Repo: 업데이트 완료 -deactivate DB - -Repo --> Service: 완료 -deactivate Repo - -Service -> Service: 결정사항을 회의록에 추가 -note right - Meeting Service API 호출하여 + Meeting Service에서 회의록의 "결정사항" 섹션에 항목 추가 end note -Service --> Controller: 적용 완료 -deactivate Service - -Controller --> Controller: 200 OK - note over Controller, DB 처리 시간: - 맥락 조회: 100-200ms - LLM 패턴 감지: 2-3초 - 검증 및 필터링: 100-200ms -- 저장 처리: 200-300ms -총 처리 시간: 약 3-4초 +- 캐시 저장: 50-100ms +총 처리 시간: 약 2.5-3.5초 -제안 정책: -- 신뢰도 70% 이상만 제안 -- 명확한 결정 표현 우선 -- 중복 제거 (이미 확정된 것 제외) -- 카테고리별로 최대 10개까지 -- 실시간으로 계속 감지 +특징: +- DB 영구 저장 없음 (임시 데이터) +- Redis 캐시만 활용 + * 중복 감지용 + * 재접속 복원용 +- 프론트엔드 메모리에서 관리 +- "적용" 시에만 회의록에 반영 end note @enduml diff --git a/design/backend/sequence/inner/ai-논의사항제안.puml b/design/backend/sequence/inner/ai-논의사항제안.puml index 9a496f5..1780ca5 100644 --- a/design/backend/sequence/inner/ai-논의사항제안.puml +++ b/design/backend/sequence/inner/ai-논의사항제안.puml @@ -6,21 +6,16 @@ title AI Service 내부 시퀀스 - 논의사항제안 participant "SuggestionController" as Controller participant "DiscussionSuggestionService" as Service participant "LLMClient" as LLM -participant "SuggestionRepository" as Repo participant "TranscriptRepository" as TranscriptRepo database "Azure OpenAI<>" as OpenAI +database "Redis Cache<>" as Cache database "PostgreSQL<>" as DB == 실시간 논의사항 제안 요청 == note over Controller TranscriptService로부터 호출 - 또는 API 직접 호출: - POST /api/ai/suggestions/discussion - Body: { - "meetingId": "{meetingId}", - "transcriptText": "최근 대화 내용" - } + (회의록 자동작성 프로세스 내부) end note Controller -> Service: suggestDiscussionTopics(meetingId, transcriptText) @@ -139,42 +134,30 @@ loop 각 제안마다 - 생성 시각 - 제안 신뢰도 점수 - 회의 진행 시점 (분) - - 상태: PENDING + - 고유 ID (UUID) end note end -== 제안 저장 == +== 임시 캐시 저장 (선택적) == -loop 각 검증된 제안마다 +Service -> Cache: SET suggestions:discussion:{meetingId} +activate Cache +note right + Redis에 임시 저장: + - Key: suggestions:discussion:{meetingId} + - Value: JSON array (제안 목록) + - TTL: 2시간 (회의 시간) - Service -> Repo: saveSuggestion(meetingId, suggestion) - activate Repo + 목적: + - 재접속 시 복원용 + - WebSocket 재연결 대응 +end note - Repo -> DB: INSERT INTO ai_suggestions - activate DB - note right - 저장 데이터: - - meeting_id - - suggestion_type: 'DISCUSSION' - - content: {topic, reason} - - priority: HIGH/MEDIUM/LOW - - related_agenda: "안건 항목" - - estimated_time: 예상 시간 - - confidence_score: 0.0-1.0 - - status: PENDING - - created_at - end note +Cache --> Service: 저장 완료 +deactivate Cache - DB --> Repo: suggestionId - deactivate DB - - Repo --> Service: suggestionId - deactivate Repo - -end - -== 응답 구성 == +== 응답 반환 == Service -> Service: 응답 데이터 구성 note right @@ -187,20 +170,22 @@ note right "reason": "제안 이유", "priority": "HIGH", "relatedAgenda": "관련 안건", - "estimatedTime": 10, - "canApply": true + "estimatedTime": 10 } ], "totalCount": 제안 개수, - "displayHint": "오른쪽 탭에 표시" + "timestamp": "생성 시각" } end note -Service --> Controller: 논의사항 제안 생성 완료 +Service --> Controller: 논의사항 제안 목록 deactivate Service -Controller --> Controller: 200 OK 응답 반환 +Controller --> Controller: 이벤트 데이터에 포함하여 반환 note right + TranscriptSummaryCreated 이벤트에 + discussionSuggestions 필드로 포함 + 프론트엔드 처리: - 오른쪽 "추천" 탭에 표시 - "적용" 버튼 활성화 @@ -214,48 +199,33 @@ end note note over Controller 사용자가 "적용" 버튼 클릭 시: - PUT /api/ai/suggestions/{suggestionId}/apply -end note + 프론트엔드에서 직접 Meeting Service 호출 -Controller -> Service: applySuggestion(suggestionId, meetingId) -activate Service + PUT /api/meetings/{meetingId}/transcript + Body: { + "addDiscussionSection": { + "topic": "논의 주제", + "content": "" + } + } -Service -> Repo: updateSuggestionStatus(suggestionId, "APPLIED") -activate Repo - -Repo -> DB: UPDATE ai_suggestions\nSET status = 'APPLIED',\napplied_at = NOW() -activate DB - -DB --> Repo: 업데이트 완료 -deactivate DB - -Repo --> Service: 완료 -deactivate Repo - -Service -> Service: 논의사항을 회의록에 추가하는 로직 실행 -note right - Meeting Service에 API 호출하여 + Meeting Service에서 회의록에 새로운 논의 섹션 추가 end note -Service --> Controller: 적용 완료 -deactivate Service - -Controller --> Controller: 200 OK - note over Controller, DB 처리 시간: - 맥락 정보 조회: 100-200ms - LLM 제안 생성: 2-3초 - 검증 및 필터링: 100-200ms -- 저장 처리: 200-300ms -총 처리 시간: 약 3-4초 +- 캐시 저장: 50-100ms +총 처리 시간: 약 2.5-3.5초 -제안 정책: -- 최대 5개까지만 제안 -- 우선순위 HIGH가 1개 이상 -- 이미 논의한 주제는 제외 -- 제안은 회의 중 언제든 생성 가능 +특징: +- DB 영구 저장 없음 (임시 데이터) +- Redis 캐시만 활용 (재접속 복원용) +- 프론트엔드 메모리에서 관리 +- "적용" 시에만 회의록에 반영 end note @enduml diff --git a/design/backend/sequence/inner/ai-실시간Todo추출.puml b/design/backend/sequence/inner/ai-실시간Todo추출.puml index d9e3c02..cee7c00 100644 --- a/design/backend/sequence/inner/ai-실시간Todo추출.puml +++ b/design/backend/sequence/inner/ai-실시간Todo추출.puml @@ -6,21 +6,16 @@ title AI Service 내부 시퀀스 - 실시간Todo추출 participant "SuggestionController" as Controller participant "RealtimeTodoService" as Service participant "LLMClient" as LLM -participant "SuggestionRepository" as Repo participant "TranscriptRepository" as TranscriptRepo database "Azure OpenAI<>" as OpenAI +database "Redis Cache<>" as Cache database "PostgreSQL<>" as DB == 실시간 액션아이템 추출 요청 == note over Controller TranscriptService로부터 호출 - 또는 API 직접 호출: - POST /api/ai/suggestions/action-item - Body: { - "meetingId": "{meetingId}", - "transcriptText": "최근 대화 내용" - } + (회의록 자동작성 프로세스 내부) end note Controller -> Service: extractRealtimeActionItems(meetingId, transcriptText) @@ -40,17 +35,15 @@ deactivate DB TranscriptRepo --> Service: meetingContext deactivate TranscriptRepo -Service -> Repo: getPreviousActionItems(meetingId) -activate Repo +Service -> Cache: GET action-items:{meetingId} +activate Cache +note right + 이전에 추출한 액션아이템 조회 + (중복 제거용) +end note -Repo -> DB: SELECT content FROM ai_suggestions\nWHERE meeting_id = {meetingId}\nAND suggestion_type = 'ACTION_ITEM'\nAND status IN ('PENDING', 'APPLIED') -activate DB - -DB --> Repo: 이미 추출된 액션아이템 -deactivate DB - -Repo --> Service: previousActionItems -deactivate Repo +Cache --> Service: previousActionItems +deactivate Cache == LLM 기반 액션아이템 패턴 감지 == @@ -169,47 +162,32 @@ loop 각 제안마다 추가 정보: - 생성 시각 - 회의 진행 시점 (분) - - 원문 위치 (라인 번호) - - 상태: PENDING - - 관련 결정사항 참조 - - 관련 논의 섹션 참조 + - 원문 위치 정보 + - 고유 ID (UUID) end note end -== 제안 저장 == +== 임시 캐시 저장 (선택적) == -loop 각 검증된 제안마다 +Service -> Cache: APPEND action-items:{meetingId} +activate Cache +note right + Redis에 임시 저장: + - Key: action-items:{meetingId} + - Value: JSON array (제안 목록) + - TTL: 2시간 (회의 시간) + - APPEND로 기존 목록에 추가 - Service -> Repo: saveSuggestion(meetingId, actionItem) - activate Repo + 목적: + - 중복 감지용 + - 재접속 시 복원용 +end note - Repo -> DB: INSERT INTO ai_suggestions - activate DB - note right - 저장 데이터: - - meeting_id - - suggestion_type: 'ACTION_ITEM' - - content: 할 일 내용 - - assignee: 담당자 - - due_date: 마감일 - - priority: HIGH/MEDIUM/LOW - - confidence_score: 0.0-1.0 - - extracted_from: 원문 - - related_decision_id: 관련 결정 - - status: PENDING - - created_at - end note +Cache --> Service: 저장 완료 +deactivate Cache - DB --> Repo: suggestionId - deactivate DB - - Repo --> Service: suggestionId - deactivate Repo - -end - -== 응답 구성 == +== 응답 반환 == Service -> Service: 응답 데이터 구성 note right @@ -224,20 +202,22 @@ note right "priority": "HIGH", "confidence": 0.85, "extractedFrom": "원문 발췌", - "relatedDecision": "decision-uuid", - "canApply": true + "relatedDecision": "decision-uuid" } ], "totalCount": 제안 개수, - "displayHint": "오른쪽 탭 '액션아이템' 섹션" + "timestamp": "생성 시각" } end note -Service --> Controller: 액션아이템 제안 생성 완료 +Service --> Controller: 액션아이템 제안 목록 deactivate Service -Controller --> Controller: 200 OK 응답 반환 +Controller --> Controller: 이벤트 데이터에 포함하여 반환 note right + TranscriptSummaryCreated 이벤트에 + actionItemSuggestions 필드로 포함 + 프론트엔드 처리: - 오른쪽 "추천" 탭의 "액션아이템" 섹션 표시 - "적용" 버튼 활성화 @@ -251,36 +231,14 @@ end note note over Controller 사용자가 "적용" 버튼 클릭 시: - PUT /api/ai/suggestions/{suggestionId}/apply - Body: { - "assignee": "김철수" (수정 가능), - "dueDate": "2025-02-01" (수정 가능) - } -end note + 프론트엔드에서 직접 Meeting Service 호출 -Controller -> Service: applySuggestion(suggestionId, updateData) -activate Service - -Service -> Repo: updateSuggestionStatus(suggestionId, "APPLIED") -activate Repo - -Repo -> DB: UPDATE ai_suggestions\nSET status = 'APPLIED',\napplied_at = NOW(),\nassignee = {updateData.assignee},\ndue_date = {updateData.dueDate} -activate DB - -DB --> Repo: 업데이트 완료 -deactivate DB - -Repo --> Service: 완료 -deactivate Repo - -Service -> Service: Meeting Service에 Todo 생성 요청 -note right - POST /meetings/{meetingId}/todos + POST /api/meetings/{meetingId}/todos Body: { "content": "할 일 내용", - "assignee": "담당자", - "dueDate": "마감일", - "priority": "우선순위", + "assignee": "김철수", + "dueDate": "2025-02-01", + "priority": "HIGH", "relatedSection": "관련 회의록 섹션" } @@ -290,31 +248,26 @@ note right - 담당자에게 알림 발송 end note -Service --> Controller: 적용 완료 -deactivate Service - -Controller --> Controller: 200 OK - note over Controller, DB 처리 시간: - 맥락 조회: 100-200ms - LLM 패턴 감지: 1-2초 - 검증 및 필터링: 100-200ms -- 저장 처리: 200-300ms -총 처리 시간: 약 2-3초 +- 캐시 저장: 50-100ms +총 처리 시간: 약 1.5-2.5초 -제안 정책: -- 신뢰도 70% 이상만 제안 -- 명확한 액션 표현 우선 -- 중복 제거 (유사도 90% 기준) -- 실시간으로 계속 감지 -- 최대 20개까지 누적 표시 -- 적용된 것은 회색 처리 +특징: +- DB 영구 저장 없음 (임시 데이터) +- Redis 캐시만 활용 + * 중복 감지용 + * 재접속 복원용 +- 프론트엔드 메모리에서 관리 +- "적용" 시에만 Todo 생성 차이점 (회의 종료 후 Todo 추출과): -- 실시간: 5초마다 즉시 추출 -- 종료 후: 전체 회의록 기반 종합 추출 -- 실시간은 "후보"로 제시 +- 실시간: 5초마다 즉시 추출, 임시 제안 +- 종료 후: 전체 회의록 기반 종합 추출, 자동 생성 +- 실시간은 "후보"로 제시, 사용자 선택 - 종료 후는 "확정" 추출 후 자동 생성 end note From c2d8ad52f0ff893776031593b2a99ddc681df802 Mon Sep 17 00:00:00 2001 From: yabo0812 Date: Wed, 22 Oct 2025 17:35:05 +0900 Subject: [PATCH 2/2] =?UTF-8?q?06-=EA=B2=80=EC=A6=9D=EC=99=84=EB=A3=8C=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=ED=97=A4=EB=8D=94=20=EB=B0=8F=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 11 +++++++++++ design/uiux/prototype/06-검증완료.html | 24 ++++++++++++------------ 2 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..078c2d9 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,11 @@ +{ + "permissions": { + "allow": [ + "Bash(git add:*)", + "Bash(git commit:*)", + "Bash(git push)" + ], + "deny": [], + "ask": [] + } +} diff --git a/design/uiux/prototype/06-검증완료.html b/design/uiux/prototype/06-검증완료.html index 1ee4812..0946877 100644 --- a/design/uiux/prototype/06-검증완료.html +++ b/design/uiux/prototype/06-검증완료.html @@ -82,7 +82,7 @@
- +

검증 완료

@@ -134,7 +134,7 @@ 2명 검증 완료 - + @@ -154,7 +154,7 @@ 3명 검증 완료 · 잠금됨 - + @@ -169,7 +169,7 @@ 1명 검증 완료 - + @@ -181,7 +181,7 @@ 아직 검증되지 않음 - + @@ -209,8 +209,8 @@ @@ -229,8 +229,8 @@ @@ -244,13 +244,13 @@