@startuml meeting-회의록수정 !theme mono title Meeting Service - 회의록수정 내부 시퀀스 participant "MinutesController" as Controller participant "MinutesService" as Service participant "MinutesRepository" as MinutesRepo participant "SectionRepository" as SectionRepo participant "VersionService" as VersionService participant "CollaborationService" as CollabService database "Meeting DB<>" as DB database "Redis Cache<>" as Cache participant "WebSocket<>" as WebSocket [-> Controller: PATCH /minutes/{minutesId} activate Controller note over Controller 경로 변수: minutesId 요청 데이터: { "title": "수정된 제목", "sections": [ { "sectionId": "uuid", "content": "수정된 내용", "aiSummary": "수정된 요약" } ] } 사용자 정보: userId, userName, email end note Controller -> Controller: 입력 검증 Controller -> Service: updateMinutes(minutesId, request, userId) activate Service ' 회의록 정보 조회 Service -> MinutesRepo: findById(minutesId) activate MinutesRepo MinutesRepo -> DB: 회의록 정보 조회 activate DB DB --> MinutesRepo: 회의록 정보 deactivate DB MinutesRepo --> Service: Minutes deactivate MinutesRepo note over Service 비즈니스 규칙 검증: - 회의록 존재 확인 - 수정 권한 확인 (생성자만) - 잠긴 섹션 수정 시도 검증 - 확정된 회의록은 DRAFT로 상태 변경 end note Service -> Service: 회의록 존재 확인 Service -> Service: 수정 권한 검증\n(생성자만 가능) alt 권한 없음 Service --> Controller: 403 Forbidden\n수정 권한 없음 note right 에러 응답 형식: { "error": { "code": "ACCESS_DENIED", "message": "회의록 수정 권한이 없습니다", "details": "생성자만 회의록을 수정할 수 있습니다", "timestamp": "2025-10-23T12:00:00Z", "path": "/api/minutes/{minutesId}" } } end note return 403 Forbidden else 권한 있음 ' 잠긴 섹션 확인 Service -> SectionRepo: findLockedSections(minutesId) activate SectionRepo SectionRepo -> DB: SELECT * FROM minutes_sections\nWHERE minutesId = ?\nAND isLocked = true activate DB DB --> SectionRepo: 잠긴 섹션 목록 deactivate DB SectionRepo --> Service: List
deactivate SectionRepo Service -> Service: 잠긴 섹션 수정 여부 검증 alt 잠긴 섹션 수정 시도 Service --> Controller: 400 Bad Request\n잠긴 섹션은 수정 불가 note right 에러 응답 형식: { "error": { "code": "SECTION_LOCKED", "message": "잠긴 섹션은 수정할 수 없습니다", "details": "해당 섹션은 잠금 상태로 수정이 제한됩니다", "timestamp": "2025-10-23T12:00:00Z", "path": "/api/minutes/{minutesId}" } } end note return 400 Bad Request else 수정 가능 ' 수정 이력 저장 (버전 관리) Service -> VersionService: createModificationHistory(minutesId, userId, changes) activate VersionService VersionService -> DB: 수정 이력 저장 activate DB DB --> VersionService: 이력 저장 완료 deactivate DB VersionService --> Service: 저장 성공 deactivate VersionService ' 회의록 제목 수정 alt 제목 변경됨 Service -> MinutesRepo: updateTitle(minutesId, newTitle) activate MinutesRepo MinutesRepo -> DB: 회의록 제목 수정 activate DB DB --> MinutesRepo: 업데이트 완료 deactivate DB MinutesRepo --> Service: 업데이트 성공 deactivate MinutesRepo end ' 섹션별 내용 수정 loop 각 섹션마다 Service -> SectionRepo: updateSection(sectionId, content, aiSummary) activate SectionRepo SectionRepo -> DB: 섹션 내용 및 AI 요약 수정 activate DB DB --> SectionRepo: 업데이트 완료 deactivate DB SectionRepo --> Service: 업데이트 성공 deactivate SectionRepo end ' 회의록 상태 변경 (확정 → 작성중) alt 확정된 회의록 수정 Service -> MinutesRepo: updateStatus(minutesId, "DRAFT") activate MinutesRepo MinutesRepo -> DB: 확정된 회의록을 다시 작성 중(DRAFT)으로 변경 activate DB DB --> MinutesRepo: 업데이트 완료 deactivate DB MinutesRepo --> Service: 상태 변경 완료 deactivate MinutesRepo end ' 캐시 무효화 Service -> Cache: DELETE minutes:detail:{minutesId} activate Cache Cache --> Service: 삭제 완료 deactivate Cache Service -> Cache: DELETE minutes:info:{minutesId} activate Cache Cache --> Service: 삭제 완료 deactivate Cache note over Service 실시간 협업: - WebSocket을 통해 참석자에게 수정 사항 전송 - 수정 델타만 전송 (전체 내용 아님) - 수정자 정보 포함 end note ' 실시간 동기화 Service -> CollabService: broadcastUpdate(minutesId, changes, userId) activate CollabService note over CollabService WebSocket 메시지 형식: { "type": "MINUTES_UPDATED", "minutesId": "uuid", "changes": [...], "modifiedBy": { "userId": "...", "userName": "..." }, "timestamp": "..." } end note CollabService -> WebSocket: broadcast to room:{minutesId} activate WebSocket WebSocket --> CollabService: 전송 완료 deactivate WebSocket CollabService --> Service: 동기화 완료 deactivate CollabService Service --> Controller: MinutesUpdateResponse deactivate Service note over Controller 응답 데이터: { "minutesId": "uuid", "status": "DRAFT", "updatedAt": "2025-01-23T16:00:00", "updatedBy": "userId", "version": "v1.1" } end note return 200 OK\nMinutesUpdateResponse end end deactivate Controller @enduml