Skip to content

[FEAT] 레포지토리 분석 결과 조회 API 구현#25

Merged
dldusgh318 merged 7 commits into
SeCause:developfrom
dldusgh318:develop
Jun 1, 2026
Merged

[FEAT] 레포지토리 분석 결과 조회 API 구현#25
dldusgh318 merged 7 commits into
SeCause:developfrom
dldusgh318:develop

Conversation

@dldusgh318

@dldusgh318 dldusgh318 commented May 28, 2026

Copy link
Copy Markdown
Contributor

‼️ 관련 이슈

close #19


🔎 개요

레포지토리 분석 결과의 보안 이슈를 조회하는 API를 구현했습니다.


📝 작업 내용

  • 레포지토리 이슈 목록 조회 API 구현
  • 취약 파일 목록 조회 API 구현
  • 이슈 상세 조회 API 구현
  • severity 필터링 및 페이지네이션 응답 적용
  • 코드 취약점/인프라 취약점을 Vulnerability 상속 구조 기준으로 함께 조회
  • 인증된 사용자 본인 소유 레포지토리 분석 결과만 조회되도록 검증
  • QueryDSL 기반 조회 로직 구현
  • Swagger 문서화 및 실패 응답 예시 추가
  • 도메인별 ErrorCode 및 커스텀 Exception 적용
    • ProjectRepositoryErrorCode, ProjectRepositoryException
    • AnalysisErrorCode, AnalysisException

현재 PR 단위가 커져서, 스웨거로 간단한 테스트만 진행했으며 테스트 코드는 확인해본 후 다음 PR때 올리겠습니다


👀 변경 사항

  • 이슈 조회 관련 컨트롤러, 서비스, DTO가 domain.projectRepository 하위에 추가되었습니다.
  • 이슈 조회 로직은 analysis_results -> vulnerability -> analysis/repositoryFile 구조를 기준으로 동작합니다.
  • 코드 취약점의 lineStart, lineEnd는 코드 취약점인 경우에만 내려가며, 인프라 취약점은 null일 수 있습니다.
  • 요청한 레포지토리 또는 분석 결과가 없을 경우 COMMON404 대신 도메인별 에러 코드가 반환됩니다.
    • PROJECT_REPOSITORY404
    • ANALYSIS_RESULT404

📸 스크린샷 (Optional)

레포지토리 이슈 목록 조회

스크린샷 2026-05-28 10 43 16

취약점 파일 목록 조회

스크린샷 2026-05-28 10 44 19

이슈 상세 조회

스크린샷 2026-05-28 10 44 07

관련 에러 응답

스크린샷 2026-05-28 10 43 54 스크린샷 2026-05-28 10 43 47

✅ 체크리스트

  • label, milestone, assignees, reviewers 등을 지정했습니다.
  • 성능 개선/최적화 관련 내용이 있는지 확인했습니다.
  • 변경 사항에 대한 테스트를 했습니다.
  • 테스트 시 사용한 로그를 삭제했습니다.

💬 고민사항 및 리뷰 요구사항 (Optional)

  • QueryDSL 조회에서 analysis_results -> vulnerability -> analysis -> repository, vulnerability -> repositoryFile 조인이 사용됩니다.
  • 사용자 소유권 검증과 파일 정보 조회를 위해 필요한 조인이며, 코드 취약점의 라인 정보 조회를 위해 CodeVulnerability는 left join으로 처리했습니다.
  • 모두 PK/FK 기반 조인이므로 적절한 인덱스가 있으면 큰 문제는 없을 것으로 보이며, 추후 데이터가 많아질 경우 analysis_results.vulnerability_id, vulnerabilities.analysis_id, vulnerabilities.repository_file_id 기준 인덱스를 추가해 최적화할 수 있습니다.
  • validate 관련 로직이 많아질 거 같은데, validator 패턴을 따로 도입할까 고민중입니다. 의견 부탁드립니다

Summary by CodeRabbit

릴리스 노트

  • New Features

    • 저장소 보안 이슈 목록 조회 추가(심각도 필터, 페이징)
    • 취약 파일 목록 조회 추가
    • 보안 이슈 상세 정보 조회 추가
  • Documentation

    • OpenAPI 문서 업그레이드 및 엔드포인트 문서화 개선
  • Chores

    • 데이터베이스 ENUM 및 확장 추가
    • 의존성 업데이트(쿼리 빌더 및 OpenAPI 버전) 및 쿼리 설정 추가

@dldusgh318 dldusgh318 self-assigned this May 28, 2026
@dldusgh318 dldusgh318 added the ✨ FEAT New feature or request label May 28, 2026
@dldusgh318 dldusgh318 requested a review from boogiewooki02 May 28, 2026 01:47
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8efb5879-02a4-4841-8356-a8774f8349bf

📥 Commits

Reviewing files that changed from the base of the PR and between f7fab7b and 57faded.

📒 Files selected for processing (7)
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/code/ProjectRepositoryErrorCode.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/controller/RepositoryIssueApi.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/controller/RepositoryIssueController.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/service/RepositoryIssueService.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/validator/ProjectRepositoryValidator.java
  • src/main/java/SeCause/SeCause_be/global/apiPayload/exception/handler/ExceptionAdvice.java
  • src/main/resources/schema.sql
💤 Files with no reviewable changes (1)
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/code/ProjectRepositoryErrorCode.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/main/resources/schema.sql
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/controller/RepositoryIssueController.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/controller/RepositoryIssueApi.java

📝 Walkthrough

Walkthrough

레포지토리 분석 결과 조회 API를 구현합니다. QueryDSL 기반 데이터 접근, 다중 응답 DTO, 심각도 필터링 및 페이지네이션, 사용자별 권한 검증을 추가하여 3개 엔드포인트(이슈 목록, 취약 파일, 이슈 상세)를 제공합니다.

Changes

Repository Analysis Query API

Layer / File(s) Summary
Foundation: Dependencies and Configuration
build.gradle, src/main/resources/schema.sql, src/main/java/SeCause/SeCause_be/global/config/QueryDslConfig.java
QueryDSL 5.1.0 Jakarta 의존성 및 annotationProcessor 추가, springdoc-openapi-starter-webmvc-ui3.0.3으로 업데이트, PostgreSQL vector 확장 및 ENUM 타입(파일 유형·분석 상태·심각도·참조 유형) 초기화 DDL 추가, JPAQueryFactory 빈 등록.
Error Handling Contract
src/main/java/SeCause/SeCause_be/domain/analysis/code/AnalysisErrorCode.java, src/main/java/SeCause/SeCause_be/domain/analysis/exception/AnalysisException.java, src/main/java/SeCause/SeCause_be/domain/projectRepository/code/ProjectRepositoryErrorCode.java, src/main/java/SeCause/SeCause_be/domain/projectRepository/exception/ProjectRepositoryException.java
AnalysisErrorCode(ANALYSIS_RESULT_NOT_FOUND)와 ProjectRepositoryErrorCode(PROJECT_REPOSITORY_NOT_FOUND) enum 및 대응 예외 클래스들을 추가하여 일관된 에러 코드/예외 계약을 정의함.
API Contract and Response DTOs
src/main/java/SeCause/SeCause_be/domain/projectRepository/controller/RepositoryIssueApi.java, src/main/java/SeCause/SeCause_be/domain/projectRepository/dto/*
OpenAPI 문서화된 RepositoryIssueApi 인터페이스(이슈 목록/취약 파일/이슈 상세)와 관련 응답 DTO들(RepositoryIssueListResponse, RepositoryIssueDetailResponse, RepositoryIssueSummaryResponse, VulnerableFileListResponse, VulnerableFileSummaryResponse, SecurityReferenceResponse) 및 RepositoryIssueSeverity enum을 추가.
Repository and Data Access Layer
src/main/java/SeCause/SeCause_be/domain/analysis/repository/AnalysisResultRepository*.java, src/main/java/SeCause/SeCause_be/domain/projectRepository/repository/ProjectRepositoryRepository.java
AnalysisResultRepository(JpaRepository + custom 계약), AnalysisResultRepositoryImpl(QueryDSL로 이슈 목록·취약 파일·이슈 상세·보안 참조 조회 구현: groupBy, aggregation, left join 등), ProjectRepositoryRepository(소유권 검증용 exists 메서드) 추가.
Service Layer with Validation
src/main/java/SeCause/SeCause_be/domain/projectRepository/service/RepositoryIssueService.java, src/main/java/SeCause/SeCause_be/domain/projectRepository/validator/ProjectRepositoryValidator.java
RepositoryIssueService(읽기 전용 트랜잭션)에서 소유권 검증, RepositoryIssueSeveritySeverity 변환, 페이지 오프셋 계산 후 리포지토리 호출; 상세 조회 시 결과 없으면 AnalysisException 발생. ProjectRepositoryValidator는 소유권 존재 여부 검사 후 예외 발생.
Controller Implementation and Wiring
src/main/java/SeCause/SeCause_be/domain/projectRepository/controller/RepositoryIssueController.java
RepositoryIssueApi 구현체로 3개 엔드포인트를 제공하고 Service 호출 결과를 ApiResponse.onSuccess()로 감싸 반환.
ConstraintViolationException Handler
src/main/java/SeCause/SeCause_be/global/apiPayload/exception/handler/ExceptionAdvice.java
ConstraintViolationException 전용 @ExceptionHandler 추가, propertyPath에서 필드명 추출하여 검증 에러 맵을 구성하고 GlobalErrorCode.VALIDATION_ERROR 응답을 반환.
UserController Response Type Update
src/main/java/SeCause/SeCause_be/domain/user/controller/UserController.java
getMe 반환 타입을 ResponseEntity<ApiResponse<UserMeResponse>>에서 ApiResponse<UserMeResponse>로 변경.

Sequence Diagram

sequenceDiagram
  participant Client
  participant RepositoryIssueController
  participant RepositoryIssueService
  participant AnalysisResultRepository
  participant ProjectRepositoryRepository
  participant Database

  Client->>RepositoryIssueController: GET /api/repositories/{repositoryId}/analysis/issues?severity=CRITICAL&page=1&size=20
  RepositoryIssueController->>RepositoryIssueService: getRepositoryIssues(repositoryId, userId, severity, page, size)
  RepositoryIssueService->>ProjectRepositoryRepository: existsByRepositoryIdAndUserUserIdAndDeletedFalse(repositoryId, userId)
  ProjectRepositoryRepository->>Database: SELECT EXISTS(...)
  Database-->>ProjectRepositoryRepository: true/false
  RepositoryIssueService->>AnalysisResultRepository: findRepositoryIssues(repositoryId, userId, severity, pageable)
  AnalysisResultRepository->>Database: QueryDSL SELECT (joins, groupBy, aggregation)
  Database-->>AnalysisResultRepository: result set
  AnalysisResultRepository-->>RepositoryIssueService: RepositoryIssueListResponse (paged)
  RepositoryIssueService-->>RepositoryIssueController: RepositoryIssueListResponse
  RepositoryIssueController-->>Client: ApiResponse<RepositoryIssueListResponse>
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related PRs

  • SeCause/SeCause-BE#17: 공통 예외 처리 프레임워크(GeneralException, BaseErrorCode)와 관련된 변경과 연관됩니다.

Poem

🐰 숲 속 코드 따라 달려가,
QueryDSL로 취약점 주섬주섬 담아,
페이지 세어 정리해 전해드리니,
분석 결과, 안전히 배달했어요. 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목 '[FEAT] 레포지토리 분석 결과 조회 API 구현'은 변경사항의 핵심인 저장소 분석 결과 조회 API 구현을 명확하게 설명합니다.
Linked Issues check ✅ Passed PR의 구현 내용이 #19 이슈의 모든 주요 요구사항을 충족합니다: 레포지토리 이슈 목록/취약파일 목록/이슈 상세 조회 API, 심각도 필터링, 페이지네이션, 코드/인프라 취약점 통합 조회, 사용자 인증 및 소유권 검증.
Out of Scope Changes check ✅ Passed 변경 사항 대부분이 분석 결과 조회 API 구현과 직접 관련이 있습니다. UserController 반환타입 변경과 springdoc-openapi 버전 업그레이드는 API 응답 형식 통일 및 Swagger 문서화 개선과 관련된 범위 내 변경입니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/SeCause/SeCause_be/domain/projectRepository/service/RepositoryIssueService.java`:
- Around line 71-74: The validatePageRequest method currently only checks for
page < 1 or size < 1; add an upper bound for size (e.g., define a constant
MAX_PAGE_SIZE = 100) and throw
ProjectRepositoryException(ProjectRepositoryErrorCode.INVALID_PAGE_REQUEST) when
size > MAX_PAGE_SIZE; update validatePageRequest to compare against
MAX_PAGE_SIZE and include the constant near the top of RepositoryIssueService
(or as a private static final field) so callers of validatePageRequest will be
protected from excessively large page sizes.

In `@src/main/resources/schema.sql`:
- Around line 1-34: Remove the stray marker lines "^^^ END OF SCRIPT ^^^" and
terminate statements properly: add a semicolon after "CREATE EXTENSION IF NOT
EXISTS vector" and ensure each DO $$ ... END $$ block ends with "END $$;" so the
type creations (file_type_enum, analysis_status_enum, severity_enum,
reference_type_enum) are valid; keep the CREATE TYPE names as-is and only adjust
the trailing markers and semicolons so the SQL executes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dfa3c9f4-5e1e-49b4-b2d2-5a63c5e1d4ce

📥 Commits

Reviewing files that changed from the base of the PR and between e7b05c8 and f7fab7b.

📒 Files selected for processing (22)
  • build.gradle
  • src/main/java/SeCause/SeCause_be/domain/analysis/code/AnalysisErrorCode.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/exception/AnalysisException.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/repository/AnalysisResultRepository.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/repository/AnalysisResultRepositoryCustom.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/repository/AnalysisResultRepositoryImpl.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/code/ProjectRepositoryErrorCode.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/controller/RepositoryIssueApi.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/controller/RepositoryIssueController.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/dto/RepositoryIssueDetailResponse.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/dto/RepositoryIssueListResponse.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/dto/RepositoryIssueSeverity.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/dto/RepositoryIssueSummaryResponse.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/dto/SecurityReferenceResponse.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/dto/VulnerableFileListResponse.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/dto/VulnerableFileSummaryResponse.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/exception/ProjectRepositoryException.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/repository/ProjectRepositoryRepository.java
  • src/main/java/SeCause/SeCause_be/domain/projectRepository/service/RepositoryIssueService.java
  • src/main/java/SeCause/SeCause_be/domain/user/controller/UserController.java
  • src/main/java/SeCause/SeCause_be/global/config/QueryDslConfig.java
  • src/main/resources/schema.sql

Comment thread src/main/resources/schema.sql Outdated

@boogiewooki02 boogiewooki02 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전체적으로 QueryDSL을 활용해서 조회 API에 필요한 데이터만 조인하는 구조가 잘 잡혀 있는 것 같습니다.
고생하셨습니다!

Comment on lines +71 to +74
private void validatePageRequest(int page, int size) {
if (page < 1 || size < 1) {
throw new ProjectRepositoryException(ProjectRepositoryErrorCode.INVALID_PAGE_REQUEST);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

페이지 size에 상한이 없어서 큰 값 요청 시 한 번에 과도한 조회가 발생할 수 있어 보입니다. 최대 size를 제한하는 방어 로직이 있으면 좋겠습니다!

Comment on lines +21 to +22
@Tag(name = "Repository Issue", description = "레포지토리 분석 이슈 API")
public interface RepositoryIssueApi {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런식으로 스웨거 문서 내용을 따로 분리해서 관리할 수 있군요! 덕분에 컨트롤러 코드가 훨씬 깔끔해지는 것 같아요!

@dldusgh318 dldusgh318 merged commit 5b44e0d into SeCause:develop Jun 1, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ FEAT New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 레포지토리 분석 결과 조회 API 구현

2 participants