Skip to content

Commit cfef93e

Browse files
committed
feat(evaluation): 프롬포트 수정 & merge 완료
2 parents f5f7159 + 849b234 commit cfef93e

File tree

11 files changed

+381
-142
lines changed

11 files changed

+381
-142
lines changed
Lines changed: 68 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package com.backend.domain.analysis.controller;
22

3+
import com.backend.domain.analysis.dto.request.AnalysisRequest;
34
import com.backend.domain.analysis.dto.response.AnalysisResultResponseDto;
45
import com.backend.domain.analysis.dto.response.HistoryResponseDto;
5-
import com.backend.domain.analysis.dto.request.AnalysisRequest;
66
import com.backend.domain.analysis.entity.AnalysisResult;
7-
import com.backend.domain.analysis.entity.Score;
87
import com.backend.domain.analysis.service.AnalysisService;
8+
import com.backend.domain.repository.dto.response.RepositoryResponse;
99
import com.backend.domain.repository.entity.Repositories;
1010
import com.backend.domain.repository.service.RepositoryService;
11+
import com.backend.global.exception.BusinessException;
12+
import com.backend.global.exception.ErrorCode;
1113
import com.backend.global.response.ApiResponse;
1214
import lombok.RequiredArgsConstructor;
1315
import org.springframework.http.ResponseEntity;
@@ -16,7 +18,6 @@
1618

1719
import java.util.ArrayList;
1820
import java.util.List;
19-
import java.util.Optional;
2021

2122
@RestController
2223
@RequiredArgsConstructor
@@ -25,54 +26,90 @@ public class AnalysisController {
2526
private final AnalysisService analysisService;
2627
private final RepositoryService repositoryService;
2728

29+
// POST: 분석 요청
2830
@PostMapping
2931
public ResponseEntity<ApiResponse<Void>> analyzeRepository(@RequestBody AnalysisRequest request) {
32+
if (request == null) {
33+
throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
34+
}
35+
3036
analysisService.analyze(request.githubUrl());
3137
return ResponseEntity.ok(ApiResponse.success());
3238
}
3339

34-
@GetMapping("/user/repository/{memberId}")
40+
// GET: 사용자의 모든 Repository 목록 조회
41+
@GetMapping("/{memberId}/repositories")
42+
@Transactional(readOnly = true)
43+
public ResponseEntity<List<RepositoryResponse>> getMemberHistory(
44+
@PathVariable Long memberId
45+
){
46+
if (memberId == null) {
47+
throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
48+
}
49+
50+
List<RepositoryResponse> repositories = repositoryService
51+
.findRepositoryByMember(memberId)
52+
.stream()
53+
.map(RepositoryResponse::new)
54+
.toList();
55+
56+
return ResponseEntity.ok(repositories);
57+
}
58+
59+
// GET: 특정 Repository의 분석 히스토리 조회, 모든 분석 결과 조회
60+
@GetMapping("/{memberId}/repositories/{repositoriesId}")
3561
@Transactional(readOnly = true)
36-
public ResponseEntity<List<HistoryResponseDto>> getMemberHistory(@PathVariable Long memberId){
37-
List<Repositories> repositories = repositoryService.findRepositoryByMember(memberId);
38-
List<HistoryResponseDto> historyList = new ArrayList<>();
62+
public ResponseEntity<HistoryResponseDto> getAnalysisByRepositoriesId(
63+
@PathVariable("memberId") Long memberId,
64+
@PathVariable("repositoriesId") Long repoId
65+
){
66+
// TODO: 추후 인증/인가 기능 완성 후 소유권 검증 로직 추가
67+
68+
// 1. Repository 정보 조회
69+
Repositories repository = repositoryService.findById(repoId)
70+
.orElseThrow(() -> new BusinessException(ErrorCode.GITHUB_REPO_NOT_FOUND));
3971

40-
for (Repositories repo : repositories) {
41-
Optional<AnalysisResult> optionalAnalysis = analysisService.findByRepositoryId(repo.getId());
72+
RepositoryResponse repositoryResponse = new RepositoryResponse(repository);
4273

43-
if (optionalAnalysis.isPresent()) { // 존재하는지 확인
44-
AnalysisResult analysisResult = optionalAnalysis.get();
45-
Score score = analysisResult.getScore();
74+
// 2. 분석 결과 목록 조회 (최신순 정렬)
75+
List<AnalysisResult> analysisResults =
76+
analysisService.getAnalysisResultList(repoId);
4677

47-
List<String> languages = repositoryService.findLanguagesByRepisotryId(repo.getId())
48-
.stream()
49-
.map(Enum::name) // RepositoryLanguage -> Language enum
50-
.toList();
78+
// 3. 버전 DTO 생성 (최신이 가장 큰 번호)
79+
List<HistoryResponseDto.AnalysisVersionDto> versions = new ArrayList<>();
80+
int versionNumber = analysisResults.size();
5181

52-
HistoryResponseDto dto = new HistoryResponseDto(repo, analysisResult, score, languages);
53-
historyList.add(dto);
54-
}
82+
for (AnalysisResult analysis : analysisResults) {
83+
versions.add(HistoryResponseDto.AnalysisVersionDto.from(analysis, versionNumber));
84+
versionNumber--;
5585
}
5686

57-
// 최신순 정렬
58-
historyList.sort((a, b) -> b.createDate().compareTo(a.createDate()));
87+
// 4. 응답 조합
88+
HistoryResponseDto response = HistoryResponseDto.of(repositoryResponse, versions);
5989

60-
return ResponseEntity.ok(historyList);
90+
return ResponseEntity.ok(response);
6191
}
6292

63-
@GetMapping("repository/{repositoriesId}")
93+
// GET: 특정 분석 결과 상세 조회
94+
@GetMapping("/{memberId}/repositories/{repositoryId}/results/{analysisId}")
6495
@Transactional(readOnly = true)
65-
public ResponseEntity<List<AnalysisResultResponseDto>> getAnalysisByRepositoriesId(@PathVariable("repositoriesId") Long repoId){
66-
List<AnalysisResult> optionalResult = analysisService.getAnalysisResultList(repoId);
67-
List<AnalysisResultResponseDto> resultList = new ArrayList<>();
96+
public ResponseEntity<AnalysisResultResponseDto> getAnalysisDetail(
97+
@PathVariable Long memberId,
98+
@PathVariable Long repositoryId,
99+
@PathVariable Long analysisId
100+
) {
101+
// TODO: 추후 인증/인가 검증
68102

103+
// 분석 결과 조회
104+
AnalysisResult analysisResult = analysisService.getAnalysisById(analysisId);
69105

70-
for(AnalysisResult result : optionalResult){
71-
Score score = result.getScore();
72-
AnalysisResultResponseDto dto = new AnalysisResultResponseDto(result, score);
73-
resultList.add(dto);
106+
if (!analysisResult.getRepositories().getId().equals(repositoryId)) {
107+
throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
74108
}
75109

76-
return ResponseEntity.ok(resultList);
110+
AnalysisResultResponseDto response =
111+
new AnalysisResultResponseDto(analysisResult, analysisResult.getScore());
112+
113+
return ResponseEntity.ok(response);
77114
}
78115
}
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
package com.backend.domain.analysis.dto.request;
22

3-
public record AnalysisRequest(String githubUrl) {}
3+
import jakarta.validation.constraints.NotBlank;
4+
import jakarta.validation.constraints.Pattern;
5+
6+
public record AnalysisRequest(
7+
@NotBlank(message = "GitHub URL은 필수입니다")
8+
@Pattern(regexp = "^https://github\\.com/[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+/?$",
9+
message = "올바른 GitHub 저장소 URL 형식이 아닙니다")
10+
String githubUrl
11+
) {}

backend/src/main/java/com/backend/domain/analysis/dto/response/AnalysisResultResponseDto.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
import com.backend.domain.analysis.entity.AnalysisResult;
44
import com.backend.domain.analysis.entity.Score;
55

6+
/**
7+
* 특정 분석 결과의 상세 정보 응답 DTO
8+
* 분석 점수, 피드백 등을 포함
9+
*/
610
public record AnalysisResultResponseDto(
711
int totalScore,
812
int readmeScore,
Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,44 @@
11
package com.backend.domain.analysis.dto.response;
22

33
import com.backend.domain.analysis.entity.AnalysisResult;
4-
import com.backend.domain.analysis.entity.Score;
5-
import com.backend.domain.repository.entity.Repositories;
4+
import com.backend.domain.repository.dto.response.RepositoryResponse;
65

76
import java.time.LocalDateTime;
87
import java.util.List;
98

9+
/**
10+
* Repository 상세 정보 + 분석 버전 목록 응답 DTO
11+
* 특정 Repository의 모든 분석 버전을 조회할 때 사용
12+
*/
1013
public record HistoryResponseDto(
11-
String repositoryName,
12-
LocalDateTime createDate,
13-
List<String> languages,
14-
int totalScore,
15-
boolean publicStatus
14+
RepositoryResponse repository, // Repository 기본 정보
15+
List<AnalysisVersionDto> analysisVersions
1616
) {
17-
public HistoryResponseDto(Repositories repositories, AnalysisResult analysisResult, Score score, List<String> languages){
18-
this(
19-
repositories.getName(),
20-
analysisResult.getCreateDate(),
21-
languages,
22-
score.getTotalScore(),
23-
repositories.isPublicRepository()
24-
);
25-
}
17+
public static HistoryResponseDto of(
18+
RepositoryResponse repository,
19+
List<AnalysisVersionDto> versions
20+
) {
21+
return new HistoryResponseDto(repository, versions);
22+
}
23+
24+
public record AnalysisVersionDto(
25+
Long analysisId,
26+
LocalDateTime analysisDate,
27+
Integer totalScore,
28+
String versionLabel
29+
) {
30+
public static AnalysisVersionDto from(
31+
AnalysisResult analysis,
32+
int versionNumber
33+
) {
34+
return new AnalysisVersionDto(
35+
analysis.getId(),
36+
analysis.getCreateDate(),
37+
analysis.getScore().getTotalScore(),
38+
String.format("v%d (%s)",
39+
versionNumber,
40+
analysis.getCreateDate().toLocalDate())
41+
);
42+
}
43+
}
2644
}

backend/src/main/java/com/backend/domain/analysis/service/AnalysisService.java

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.backend.domain.repository.dto.response.RepositoryData;
55
import com.backend.domain.analysis.entity.AnalysisResult;
66
import com.backend.domain.analysis.repository.AnalysisResultRepository;
7+
import com.backend.domain.repository.dto.response.RepositoryData;
78
import com.backend.domain.repository.service.RepositoryService;
89
import com.backend.global.exception.BusinessException;
910
import com.backend.global.exception.ErrorCode;
@@ -13,7 +14,6 @@
1314
import org.springframework.transaction.annotation.Transactional;
1415

1516
import java.util.List;
16-
import java.util.Optional;
1717

1818
@Slf4j
1919
@Service
@@ -24,25 +24,46 @@ public class AnalysisService {
2424
private final EvaluationService evaluationService; // ★ 추가
2525

2626

27+
/* Analysis 분석 프로세스 오케스트레이션 담당
28+
* 1. GitHub URL 파싱 및 검증
29+
* 2. Repository 도메인을 통한 데이터 수집
30+
* 3. Evaluation 도메인을 통한 AI 평가
31+
* 4. 분석 결과 저장
32+
* */
2733
@Transactional
2834
public void analyze(String githubUrl) {
2935
String[] repoInfo = parseGitHubUrl(githubUrl);
3036
String owner = repoInfo[0];
3137
String repo = repoInfo[1];
3238

3339
// Repository 데이터 수집
34-
RepositoryData repositoryData = repositoryService.fetchAndSaveRepository(owner, repo);
40+
RepositoryData repositoryData;
3541

36-
log.info("🫠 ResponseData: {}", repositoryData);
42+
// log.info("🫠 ResponseData: {}", repositoryData);
3743
// TODO: AI 평가, 저장
44+
try {
45+
repositoryData = repositoryService.fetchAndSaveRepository(owner, repo);
46+
log.info("🫠 Repository Data 수집 완료: {}", repositoryData);
47+
} catch (BusinessException e) {
48+
log.error("Repository 데이터 수집 실패: {}/{}", owner, repo, e);
49+
throw handleRepositoryFetchError(e, owner, repo);
50+
}
3851
evaluationService.evaluateAndSave(repositoryData); //
3952

53+
// TODO: AI 평가
54+
// EvaluationResult evaluation = evaluationService.evaluate(repositoryData);
55+
4056
}
4157

58+
// GitHub URL 파싱하여 owner와 repo 이름 추출
4259
private String[] parseGitHubUrl(String githubUrl) {
4360
log.info("🚩 분석 요청 url: {}", githubUrl);
4461

45-
if (githubUrl == null || !githubUrl.startsWith("https://github.com/")) {
62+
if (githubUrl == null) {
63+
throw new BusinessException(ErrorCode.INVALID_GITHUB_URL);
64+
}
65+
66+
if (!githubUrl.startsWith("https://github.com/")) {
4667
throw new BusinessException(ErrorCode.INVALID_GITHUB_URL);
4768
}
4869

@@ -60,13 +81,25 @@ private String[] parseGitHubUrl(String githubUrl) {
6081
return new String[]{parts[0].trim(), parts[1].trim()};
6182
}
6283

63-
// AnalysisRresult에서 repository id로 분석 결과 찾기
64-
public Optional<AnalysisResult> findByRepositoryId(Long RepositoryId) {
65-
return analysisResultRepository.findByRepositoriesId(RepositoryId);
84+
// Repository 데이터 수집 중 발생한 예외 처리
85+
private BusinessException handleRepositoryFetchError(BusinessException e, String owner, String repo) {
86+
return switch (e.getErrorCode()) {
87+
case GITHUB_REPO_NOT_FOUND ->
88+
new BusinessException(ErrorCode.GITHUB_REPO_NOT_FOUND);
89+
case GITHUB_RATE_LIMIT_EXCEEDED ->
90+
new BusinessException(ErrorCode.GITHUB_RATE_LIMIT_EXCEEDED);
91+
default -> e;
92+
};
93+
}
94+
95+
// 특정 Repository의 모든 분석 결과 조회 (최신순)
96+
public List<AnalysisResult> getAnalysisResultList(Long repositoryId){
97+
return analysisResultRepository.findAnalysisResultByRepositoriesId(repositoryId);
6698
}
6799

68-
// AnalysisResult를 list로 반환
69-
public List<AnalysisResult> getAnalysisResultList(Long RepositoryId){
70-
return analysisResultRepository.findAnalysisResultByRepositoriesId(RepositoryId);
100+
// 분석 결과 ID로 단건 조회
101+
public AnalysisResult getAnalysisById(Long analysisId) {
102+
return analysisResultRepository.findById(analysisId)
103+
.orElseThrow(() -> new BusinessException(ErrorCode.ANALYSIS_NOT_FOUND));
71104
}
72105
}

backend/src/main/java/com/backend/domain/evaluation/service/EvaluationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public AiResult callAiAndParse(RepositoryData data) {
7979
You are a senior software engineering reviewer.
8080
Analyze the given GitHub repository data and return ONLY a valid JSON. No commentary.
8181
82-
Scoring: total 100 (README 0~25, TEST 0~25, COMMIT 0~25, CICD 0~25).
82+
Scoring: total 100 (README 0~30, TEST 0~30, COMMIT 0~25, CICD 0~15).
8383
Consider test folders, CI configs (.github/workflows), commit frequency/messages, README depth, etc.
8484
8585
JSON schema:
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package com.backend.domain.repository.controller;
22

3-
import com.backend.domain.repository.entity.Repositories;
43
import com.backend.domain.repository.service.RepositoryService;
54
import lombok.RequiredArgsConstructor;
65
import org.springframework.web.bind.annotation.*;
76

87
@RestController
98
@RequiredArgsConstructor
109
@RequestMapping("/api/repository")
11-
public class RepositoriseController {
10+
public class RepositoryController {
1211
private final RepositoryService repositoryService;
1312

1413
// 리포지토리 삭제

backend/src/main/java/com/backend/domain/repository/dto/response/RepositoryResponse.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
import java.util.List;
66
import java.util.stream.Collectors;
77

8+
/**
9+
* Repository 기본 정보 응답 DTO
10+
* 사용자의 Repository 목록 조회 시 사용
11+
*/
812
public record RepositoryResponse(
913
Long id,
1014
String name,

0 commit comments

Comments
 (0)