diff --git a/src/main/java/com/teamEWSN/gitdeun/common/fastapi/FastApiClient.java b/src/main/java/com/teamEWSN/gitdeun/common/fastapi/FastApiClient.java index 203e944..d40a94a 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/fastapi/FastApiClient.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/fastapi/FastApiClient.java @@ -229,8 +229,8 @@ public SuggestionAutoResponse createAutoSuggestions( request.put("repo_url", repoUrl); request.put("prompt", prompt); request.put("include_children", true); - request.put("max_files", 10); - request.put("return_code", false); + request.put("max_files", 12); + request.put("return_code", true); try { return webClient.post() diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/controller/MindmapController.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/controller/MindmapController.java index cdfa0d1..46e61a9 100644 --- a/src/main/java/com/teamEWSN/gitdeun/mindmap/controller/MindmapController.java +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/controller/MindmapController.java @@ -5,9 +5,7 @@ import com.teamEWSN.gitdeun.common.jwt.CustomUserDetails; import com.teamEWSN.gitdeun.mindmap.dto.*; import com.teamEWSN.gitdeun.mindmap.dto.prompt.MindmapPromptAnalysisDto; -import com.teamEWSN.gitdeun.mindmap.dto.prompt.PromptApplyRequestDto; import com.teamEWSN.gitdeun.mindmap.dto.prompt.PromptHistoryResponseDto; -import com.teamEWSN.gitdeun.mindmap.dto.prompt.PromptPreviewResponseDto; import com.teamEWSN.gitdeun.mindmap.dto.request.MindmapCreateRequestDto; import com.teamEWSN.gitdeun.mindmap.service.MindmapOrchestrationService; import com.teamEWSN.gitdeun.mindmap.service.MindmapService; @@ -103,7 +101,7 @@ public ResponseEntity refreshMindmap( } // 비동기 서비스 호출 - mindmapOrchestrationService.refreshMindmap(mapId, authorizationHeader); + mindmapOrchestrationService.refreshMindmap(mapId, userDetails.getId(), authorizationHeader); // 즉시 202 Accepted 응답 반환 return ResponseEntity.accepted().build(); @@ -130,39 +128,43 @@ public ResponseEntity deleteMindmap( // 프롬프트 기록 관련 /** - * 프롬프트 분석 및 미리보기 생성 + * 프롬프트 분석요청 및 적용 */ @PostMapping("/{mapId}/prompts") - public ResponseEntity analyzePromptPreview( + public ResponseEntity analyzePrompt( @PathVariable Long mapId, @AuthenticationPrincipal CustomUserDetails userDetails, @RequestBody MindmapPromptAnalysisDto request, - @RequestHeader("Authorization") String authorizationHeader + @RequestHeader("Authorization") String authorizationHeader, + @RequestParam(name = "apply-immediately", defaultValue = "true") boolean applyImmediately ) { - PromptPreviewResponseDto responseDto = promptHistoryService.createPromptPreview( - mapId, - userDetails.getId(), - request, - authorizationHeader - ); - return ResponseEntity.ok(responseDto); + // 권한 검증은 동기적으로 먼저 수행 + if (!mindmapAuthService.hasEdit(mapId, userDetails.getId())) { + throw new GlobalException(ErrorCode.FORBIDDEN_ACCESS); + } + + // 비동기 서비스 호출 + mindmapOrchestrationService.promptMindmap(mapId, request.getPrompt(), userDetails.getId(), authorizationHeader, applyImmediately); + + // 즉시 202 Accepted 응답 반환 + return ResponseEntity.accepted().build(); } /** * 프롬프트 히스토리 적용 */ - @PostMapping("/{mapId}/prompts/apply") - public ResponseEntity applyPromptHistory( - @PathVariable Long mapId, - @AuthenticationPrincipal CustomUserDetails userDetails, - @RequestBody PromptApplyRequestDto request, - @RequestHeader("Authorization") String authorizationHeader - ) { - promptHistoryService.applyPromptHistory(mapId, userDetails.getId(), request); - - MindmapDetailResponseDto responseDto = mindmapService.getMindmap(mapId, userDetails.getId(), authorizationHeader); - return ResponseEntity.ok(responseDto); - } +// @PostMapping("/{mapId}/prompts/{historyId}") +// public ResponseEntity applyPromptHistory( +// @PathVariable Long mapId, +// @PathVariable Long historyId, +// @AuthenticationPrincipal CustomUserDetails userDetails, +// @RequestHeader("Authorization") String authorizationHeader +// ) { +// promptHistoryService.applyPromptHistory(mapId, historyId, userDetails.getId()); +// +// MindmapDetailResponseDto responseDto = mindmapService.getMindmap(mapId, userDetails.getId(), authorizationHeader); +// return ResponseEntity.ok(responseDto); +// } /** * 프롬프트 히스토리 목록 조회 (페이징) @@ -182,15 +184,15 @@ public ResponseEntity> getPromptHistories( /** * 특정 프롬프트 히스토리 미리보기 조회 */ - @GetMapping("/{mapId}/prompts/histories/{historyId}/preview") - public ResponseEntity getPromptHistoryPreview( - @PathVariable Long mapId, - @PathVariable Long historyId, - @AuthenticationPrincipal CustomUserDetails userDetails - ) { - PromptPreviewResponseDto responseDto = promptHistoryService.getPromptHistoryPreview(mapId, historyId, userDetails.getId()); - return ResponseEntity.ok(responseDto); - } +// @GetMapping("/{mapId}/prompts/histories/{historyId}/preview") +// public ResponseEntity getPromptHistoryPreview( +// @PathVariable Long mapId, +// @PathVariable Long historyId, +// @AuthenticationPrincipal CustomUserDetails userDetails +// ) { +// PromptPreviewResponseDto responseDto = promptHistoryService.getPromptHistoryPreview(mapId, historyId, userDetails.getId()); +// return ResponseEntity.ok(responseDto); +// } /** * 프롬프트 히스토리 삭제 (적용되지 않은 것만) @@ -213,6 +215,6 @@ public ResponseEntity getAppliedPromptHistory( @PathVariable Long mapId, @AuthenticationPrincipal CustomUserDetails userDetails ) { - return ResponseEntity.ok(promptHistoryService.getAppliedPromptHistory(mapId, userDetails.getId())); + return ResponseEntity.ok(promptHistoryService.getAppliedPromptHistory(mapId, userDetails.getId())); } } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/dto/prompt/PromptApplyRequestDto.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/dto/prompt/PromptApplyRequestDto.java deleted file mode 100644 index 548064f..0000000 --- a/src/main/java/com/teamEWSN/gitdeun/mindmap/dto/prompt/PromptApplyRequestDto.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.teamEWSN.gitdeun.mindmap.dto.prompt; - -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor -public class PromptApplyRequestDto { - private Long historyId; // 적용할 히스토리 ID -} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/dto/prompt/PromptHistoryResponseDto.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/dto/prompt/PromptHistoryResponseDto.java index fbe0698..1e1f6fa 100644 --- a/src/main/java/com/teamEWSN/gitdeun/mindmap/dto/prompt/PromptHistoryResponseDto.java +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/dto/prompt/PromptHistoryResponseDto.java @@ -12,7 +12,7 @@ public class PromptHistoryResponseDto { private Long historyId; private String prompt; - private String title; + private String summary; private Boolean applied; private LocalDateTime createdAt; } diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/dto/prompt/PromptPreviewResponseDto.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/dto/prompt/PromptPreviewResponseDto.java index 8fe5bbd..c077521 100644 --- a/src/main/java/com/teamEWSN/gitdeun/mindmap/dto/prompt/PromptPreviewResponseDto.java +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/dto/prompt/PromptPreviewResponseDto.java @@ -13,7 +13,7 @@ public class PromptPreviewResponseDto { private Long historyId; private String prompt; - private String title; + private String summary; // TODO: 프롬프트 미리보기용 맵 데이터 private MindmapGraphResponseDto mindmapGraph; diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapOrchestrationService.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapOrchestrationService.java index 4928cc1..cea5886 100644 --- a/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapOrchestrationService.java +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapOrchestrationService.java @@ -3,6 +3,7 @@ import com.teamEWSN.gitdeun.common.exception.ErrorCode; import com.teamEWSN.gitdeun.common.exception.GlobalException; import com.teamEWSN.gitdeun.common.fastapi.FastApiClient; +import com.teamEWSN.gitdeun.common.fastapi.FastApiClient.SuggestionAutoResponse; import com.teamEWSN.gitdeun.common.fastapi.dto.AnalysisResultDto; import com.teamEWSN.gitdeun.mindmap.dto.request.MindmapCreateRequestDto; import com.teamEWSN.gitdeun.mindmap.dto.request.ValidatedMindmapRequest; @@ -19,10 +20,12 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; import java.util.concurrent.CompletableFuture; +import static com.teamEWSN.gitdeun.notification.entity.NotificationType.*; + + @Slf4j @Service @RequiredArgsConstructor @@ -30,6 +33,7 @@ public class MindmapOrchestrationService { private final FastApiClient fastApiClient; private final MindmapService mindmapService; + private final PromptHistoryService promptHistoryService; private final NotificationService notificationService; private final UserRepository userRepository; private final MindmapRepository mindmapRepository; @@ -68,18 +72,19 @@ public void createMindmap(MindmapCreateRequestDto request, Long userId, String a }).whenComplete((mindmap, throwable) -> { // 3. 최종 결과에 따라 알림 전송 if (throwable != null) { - handleFailureAndNotify(throwable, userId, normalizedUrl); + handleFailureAndNotify(throwable, userId, normalizedUrl, "생성에", MINDMAP_CREATE); } else { - handleSuccessAndNotify(mindmap, userId); + handleSuccessAndNotify(mindmap, userId, "생성이", MINDMAP_CREATE); } }); } @Async("mindmapExecutor") - public void refreshMindmap(Long mapId, String authHeader) { + public void refreshMindmap(Long mapId, Long userId, String authHeader) { + Mindmap mindmap = null; try { log.info("비동기 새로고침 시작 - 마인드맵 ID: {}", mapId); - Mindmap mindmap = mindmapRepository.findByIdAndDeletedAtIsNull(mapId) + mindmap = mindmapRepository.findByIdAndDeletedAtIsNull(mapId) .orElseThrow(() -> new GlobalException(ErrorCode.MINDMAP_NOT_FOUND)); PromptHistory appliedPrompt = mindmap.getAppliedPromptHistory(); @@ -94,12 +99,19 @@ public void refreshMindmap(Long mapId, String authHeader) { authHeader ); - // 분석 결과를 DB에 업데이트 (트랜잭션) + // 분석 결과를 DB에 업데이트 (트랜잭션) 및 SSE 브로드캐스트 mindmapService.updateMindmapFromAnalysis(mapId, authHeader, analysisResult); log.info("비동기 새로고침 성공 - 마인드맵 ID: {}", mapId); + // 성공 알림 전송 + handleSuccessAndNotify(mindmap, userId, "새로고침이", MINDMAP_UPDATE); + } catch (Exception e) { log.error("비동기 새로고침 실패 - 마인드맵 ID: {}, 원인: {}", mapId, e.getMessage(), e); + // 실패 알림 전송 + if (mindmap != null) { + handleFailureAndNotify(e, userId, mindmap.getRepo().getGithubRepoUrl(), "새로고침에", MINDMAP_UPDATE); + } } } @@ -111,45 +123,91 @@ public void cleanUpMindmapData(String repoUrl, String authorizationHeader) { try { fastApiClient.deleteMindmapData(repoUrl, authorizationHeader); log.info("ArangoDB 데이터 비동기 삭제 완료: {}", repoUrl); + } catch (Exception e) { log.error("ArangoDB 데이터 비동기 삭제 실패 - 저장소: {}, 원인: {}", repoUrl, e.getMessage()); - // TODO: 실패 시 재시도 로직 또는 관리자 알림 등의 후속 처리 구현 가능 + } } - private void handleSuccessAndNotify(Mindmap mindmap, Long userId) { + /** + * 프롬프트를 기반으로 마인드맵을 분석하고 미리보기를 생성하는 비동기 프로세스 + */ + @Async("mindmapExecutor") + public void promptMindmap(Long mapId, String prompt, Long userId, String authHeader, boolean applyImmediately) { + Mindmap mindmap = null; + try { + log.info("비동기 프롬프트 분석 시작 - 마인드맵 ID: {}", mapId); + mindmap = mindmapRepository.findByIdAndDeletedAtIsNull(mapId) + .orElseThrow(() -> new GlobalException(ErrorCode.MINDMAP_NOT_FOUND)); + + String repoUrl = mindmap.getRepo().getGithubRepoUrl(); + + // FastAPI에 자동 분석 요청 + SuggestionAutoResponse suggestionResponse = fastApiClient.createAutoSuggestions(repoUrl, prompt, authHeader); + + // 분석 결과를 바탕으로 마인드맵 그래프 데이터 업데이트 및 캐시 갱신 + mindmapService.updateMindmapFromPromptAnalysis(mapId, authHeader); + + // 분석 결과를 바탕으로 PromptHistory 생성 및 SSE 알림 + PromptHistory newHistory = promptHistoryService.createPromptHistoryFromSuggestion(mapId, prompt, suggestionResponse); + + // 프롬프트 적용 여부 확인 후 알림 + if (applyImmediately) { + promptHistoryService.applyPromptHistory(mapId, newHistory.getId(), userId); + + log.info("비동기 프롬프트 분석 및 적용 성공 - 마인드맵 ID: {}", mapId); + handleSuccessAndNotify(mindmap, userId, "프롬프트 분석 및 적용이", ANALYSIS_PROMPT); + } else { + log.info("비동기 프롬프트 분석 성공 - 마인드맵 ID: {}", mapId); + handleSuccessAndNotify(mindmap, userId, "프롬프트 분석이", ANALYSIS_PROMPT); + } + + } catch (Exception e) { + log.error("비동기 프롬프트 분석 실패 - 마인드맵 ID: {}, 원인: {}", mapId, e.getMessage(), e); + // 실패 알림 전송 + if (mindmap != null) { + handleFailureAndNotify(e, userId, mindmap.getRepo().getGithubRepoUrl(), "프롬프트 분석에", ANALYSIS_PROMPT); + } + } + } + + + // 성공 알림 (메시지 동적 생성) + private void handleSuccessAndNotify(Mindmap mindmap, Long userId, String action, NotificationType type) { try { User user = userRepository.findByIdAndDeletedAtIsNull(userId) .orElseThrow(() -> new GlobalException(ErrorCode.USER_NOT_FOUND_BY_ID)); - String successMessage = String.format("마인드맵 '%s' 생성이 완료되었습니다.", mindmap.getTitle()); + String successMessage = String.format("마인드맵 '%s'의 %s 완료되었습니다.", mindmap.getTitle(), action); notificationService.createAndSendNotification( NotificationCreateDto.actionable( user, - NotificationType.SYSTEM_UPDATE, + type, successMessage, mindmap.getId(), null ) ); - log.info("마인드맵 생성 성공 및 알림 전송 완료 - ID: {}, 사용자: {}", mindmap.getId(), userId); + log.info("마인드맵 {} 성공 및 알림 전송 완료 - ID: {}, 사용자: {}", action, mindmap.getId(), userId); } catch (Exception e) { log.error("성공 알림 전송 실패 - 마인드맵 ID: {}, 사용자 ID: {}, 오류: {}", mindmap.getId(), userId, e.getMessage()); } } - private void handleFailureAndNotify(Throwable throwable, Long userId, String repoUrl) { + // 실패 알림 (메시지 동적 생성) + private void handleFailureAndNotify(Throwable throwable, Long userId, String repoUrl, String action, NotificationType type) { final Throwable cause = throwable.getCause() != null ? throwable.getCause() : throwable; - log.error("마인드맵 생성 최종 실패 - 사용자: {}, 저장소: {}, 원인: {}", userId, repoUrl, cause.getMessage()); + log.error("마인드맵 {} 최종 실패 - 사용자: {}, 저장소: {}, 원인: {}", action, userId, repoUrl, cause.getMessage()); try { userRepository.findByIdAndDeletedAtIsNull(userId).ifPresent(user -> { - String errorMessage = "마인드맵 생성에 실패했습니다: " + getSimplifiedErrorMessage(cause); + String errorMessage = String.format("마인드맵 %s 실패했습니다: %s", action, getSimplifiedErrorMessage(cause)); notificationService.createAndSendNotification( NotificationCreateDto.simple( user, - NotificationType.SYSTEM_UPDATE, + type, errorMessage ) ); diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapService.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapService.java index dc51c2b..bdb3a1a 100644 --- a/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapService.java +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapService.java @@ -115,7 +115,9 @@ public MindmapDetailResponseDto updateMindmapTitle(Long mapId, Long userId, Mind return responseDto; } - // 분석 결과를 바탕으로 기존 마인드맵을 업데이트 (새로고침) + /** + * 분석 결과를 바탕으로 기존 마인드맵을 업데이트 (새로고침) + */ @Transactional public MindmapDetailResponseDto updateMindmapFromAnalysis(Long mapId, String authHeader, AnalysisResultDto analysisResult) { Mindmap mindmap = mindmapRepository.findByIdAndDeletedAtIsNull(mapId) @@ -123,18 +125,40 @@ public MindmapDetailResponseDto updateMindmapFromAnalysis(Long mapId, String aut mindmap.getRepo().updateWithAnalysis(analysisResult); - // 새로고침 시 그래프 캐시 무효화 + // 공통 로직 호출 + return evictCacheAndBroadcastUpdate(mindmap, authHeader); + } + + /** + * 프롬프트 분석 후 마인드맵을 업데이트 (캐시 갱신 및 SSE 브로드캐스트) + */ + @Transactional + public MindmapDetailResponseDto updateMindmapFromPromptAnalysis(Long mapId, String authHeader) { + Mindmap mindmap = mindmapRepository.findByIdAndDeletedAtIsNull(mapId) + .orElseThrow(() -> new GlobalException(ErrorCode.MINDMAP_NOT_FOUND)); + + // 공통 로직 호출 + return evictCacheAndBroadcastUpdate(mindmap, authHeader); + } + + /** + * 마인드맵 업데이트 시 공통 로직 (캐시 무효화, 새 데이터 조회, SSE 전송) + */ + private MindmapDetailResponseDto evictCacheAndBroadcastUpdate(Mindmap mindmap, String authHeader) { + // 그래프 캐시 무효화 mindmapGraphCache.evictCache(mindmap.getRepo().getGithubRepoUrl()); + // 새로운 그래프 데이터 조회 MindmapGraphResponseDto graphData = mindmapGraphCache.getGraphWithHybridCache( mindmap.getRepo().getGithubRepoUrl(), authHeader ); + // DTO 변환 및 SSE 브로드캐스트 MindmapDetailResponseDto responseDto = mindmapMapper.toDetailResponseDto(mindmap, graphData); - mindmapSseService.broadcastUpdate(mapId, responseDto); + mindmapSseService.broadcastUpdate(mindmap.getId(), responseDto); - log.info("마인드맵 새로고침 DB 업데이트 완료 - ID: {}", mapId); + log.info("마인드맵 데이터 업데이트 및 SSE 브로드캐스트 완료 - ID: {}", mindmap.getId()); return responseDto; } @@ -160,6 +184,8 @@ public Repo deleteMindmap(Long mapId, Long userId) { return mindmap.getRepo(); // 후처리를 위해 Repo 반환 } + + /** * TODO: Webhook을 통한 마인드맵 업데이트 */ diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapSseService.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapSseService.java index 73e9aee..f52dd44 100644 --- a/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapSseService.java +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapSseService.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.teamEWSN.gitdeun.common.jwt.CustomUserDetails; import com.teamEWSN.gitdeun.mindmap.dto.MindmapDetailResponseDto; +import com.teamEWSN.gitdeun.mindmap.dto.prompt.PromptPreviewResponseDto; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -67,6 +68,14 @@ public void broadcastUpdate(Long mapId, MindmapDetailResponseDto data) { sendToMapSubscribers(mapId, "mindmap-update", data); } + /** + * 새로운 프롬프트 미리보기 준비 완료 브로드캐스트 + */ + public void broadcastPromptReady(Long mapId, PromptPreviewResponseDto data) { + sendToMapSubscribers(mapId, "prompt-ready", data); + } + + /** * 프롬프트 적용 브로드캐스트 */ diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/service/PromptHistoryService.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/service/PromptHistoryService.java index e7c198a..7f78401 100644 --- a/src/main/java/com/teamEWSN/gitdeun/mindmap/service/PromptHistoryService.java +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/service/PromptHistoryService.java @@ -2,10 +2,7 @@ import com.teamEWSN.gitdeun.common.exception.ErrorCode; import com.teamEWSN.gitdeun.common.exception.GlobalException; -import com.teamEWSN.gitdeun.common.fastapi.FastApiClient; -import com.teamEWSN.gitdeun.common.fastapi.dto.AnalysisResultDto; -import com.teamEWSN.gitdeun.mindmap.dto.prompt.MindmapPromptAnalysisDto; -import com.teamEWSN.gitdeun.mindmap.dto.prompt.PromptApplyRequestDto; +import com.teamEWSN.gitdeun.common.fastapi.FastApiClient.SuggestionAutoResponse; import com.teamEWSN.gitdeun.mindmap.dto.prompt.PromptHistoryResponseDto; import com.teamEWSN.gitdeun.mindmap.dto.prompt.PromptPreviewResponseDto; import com.teamEWSN.gitdeun.mindmap.entity.Mindmap; @@ -21,6 +18,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + @Slf4j @Service @@ -31,52 +30,41 @@ public class PromptHistoryService { private final PromptHistoryRepository promptHistoryRepository; private final MindmapRepository mindmapRepository; private final MindmapAuthService mindmapAuthService; - private final FastApiClient fastApiClient; private final MindmapSseService mindmapSseService; private final PromptHistoryMapper promptHistoryMapper; /** - * 프롬프트 분석 및 미리보기 생성 + * FastAPI의 제안 분석 결과를 바탕으로 프롬프트 히스토리를 생성하고 DB에 저장 */ - public PromptPreviewResponseDto createPromptPreview(Long mapId, Long userId, MindmapPromptAnalysisDto req, String authorizationHeader) { - if (!mindmapAuthService.hasEdit(mapId, userId)) { - throw new GlobalException(ErrorCode.FORBIDDEN_ACCESS); - } - + public PromptHistory createPromptHistoryFromSuggestion(Long mapId, String prompt, SuggestionAutoResponse suggestionResponse) { Mindmap mindmap = mindmapRepository.findByIdAndDeletedAtIsNull(mapId) .orElseThrow(() -> new GlobalException(ErrorCode.MINDMAP_NOT_FOUND)); - String repoUrl = mindmap.getRepo().getGithubRepoUrl(); - - try { - AnalysisResultDto analysisResult = fastApiClient.refreshMindmap(repoUrl, req.getPrompt(), authorizationHeader); - - // FastAPI로부터 받은 analysisSummary 사용 - String summary = analysisResult.getSummary(); - - // analysisSummary가 없거나 비어있는 경우 대체 로직 사용 - if (summary == null || summary.trim().isEmpty()) { - summary = generateFallbackSummary(req.getPrompt()); - } - - PromptHistory history = PromptHistory.builder() - .mindmap(mindmap) - .prompt(req.getPrompt()) - .summary(summary) - .applied(false) - .build(); + // chosen_scopes 리스트의 첫 번째 항목을 summary로 사용 + String summary; + List scopes = suggestionResponse.getChosen_scopes(); + if (scopes != null && !scopes.isEmpty()) { + summary = scopes.getFirst(); + } else { + // fallback 로직: AI가 추천 스코프를 찾지 못한 경우 + summary = generateFallbackSummary(prompt); + } - promptHistoryRepository.save(history); + PromptHistory history = PromptHistory.builder() + .mindmap(mindmap) + .prompt(prompt) + .summary(summary) + .applied(false) + .build(); - log.info("프롬프트 미리보기 생성 완료 - 마인드맵 ID: {}, 히스토리 ID: {}", mapId, history.getId()); + PromptHistory savedHistory = promptHistoryRepository.save(history); + log.info("프롬프트 히스토리 생성 완료 - 마인드맵 ID: {}, 히스토리 ID: {}", mapId, savedHistory.getId()); - // 매퍼를 활용한 변환 - return promptHistoryMapper.toPreviewResponseDto(history); + // DTO로 변환하여 SSE로 브로드캐스트 + PromptPreviewResponseDto previewDto = promptHistoryMapper.toPreviewResponseDto(savedHistory); + mindmapSseService.broadcastPromptReady(mapId, previewDto); - } catch (Exception e) { - log.error("프롬프트 미리보기 생성 실패: {}", e.getMessage(), e); - throw new RuntimeException("프롬프트 분석 중 오류가 발생했습니다: " + e.getMessage()); - } + return savedHistory; } /** @@ -132,7 +120,7 @@ public PromptHistoryResponseDto getAppliedPromptHistory(Long mapId, Long userId) /** * 프롬프트 히스토리 적용 */ - public void applyPromptHistory(Long mapId, Long userId, PromptApplyRequestDto req) { + public void applyPromptHistory(Long mapId, Long historyId, Long userId) { if (!mindmapAuthService.hasEdit(mapId, userId)) { throw new GlobalException(ErrorCode.FORBIDDEN_ACCESS); } @@ -140,7 +128,7 @@ public void applyPromptHistory(Long mapId, Long userId, PromptApplyRequestDto re Mindmap mindmap = mindmapRepository.findByIdAndDeletedAtIsNull(mapId) .orElseThrow(() -> new GlobalException(ErrorCode.MINDMAP_NOT_FOUND)); - PromptHistory historyToApply = promptHistoryRepository.findByIdAndMindmapId(req.getHistoryId(), mapId) + PromptHistory historyToApply = promptHistoryRepository.findByIdAndMindmapId(historyId, mapId) .orElseThrow(() -> new GlobalException(ErrorCode.PROMPT_HISTORY_NOT_FOUND)); mindmap.applyPromptHistory(historyToApply); diff --git a/src/main/java/com/teamEWSN/gitdeun/notification/entity/NotificationType.java b/src/main/java/com/teamEWSN/gitdeun/notification/entity/NotificationType.java index d1fc3a7..b50cf2a 100644 --- a/src/main/java/com/teamEWSN/gitdeun/notification/entity/NotificationType.java +++ b/src/main/java/com/teamEWSN/gitdeun/notification/entity/NotificationType.java @@ -3,11 +3,16 @@ public enum NotificationType { INVITE_MINDMAP, // 마인드맵 초대 ACCEPT_MINDMAP, // 초대 수락 - REJECT_MINDMAP, + REJECT_MINDMAP, // 초대 거절 MENTION_COMMENT, // 댓글에서 맨션 APPLICATION_RECEIVED, // 지원 신청 APPLICATION_ACCEPTED, // 지원 수락 APPLICATION_REJECTED, // 지원 거절 APPLICATION_WITHDRAWN_AFTER_ACCEPTANCE, // 지원 수락 철회 + + ANALYSIS_PROMPT, // 분석 프롬프트 + MINDMAP_CREATE, // 마인드맵 생성 + MINDMAP_UPDATE, // 마인드맵 업데이트 + MINDMAP_DELETE, // 마인드맵 삭제 SYSTEM_UPDATE // 시스템 업데이트(webhook) }