Skip to content

[FEAT] 연동할 레포지토리 목록 조회 API 구현#34

Merged
dldusgh318 merged 7 commits into
SeCause:developfrom
dldusgh318:feature/30-linkable-repo
Jun 10, 2026
Merged

[FEAT] 연동할 레포지토리 목록 조회 API 구현#34
dldusgh318 merged 7 commits into
SeCause:developfrom
dldusgh318:feature/30-linkable-repo

Conversation

@dldusgh318

@dldusgh318 dldusgh318 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

‼️ 관련 이슈

close #30


🔎 개요

연동할 레포지토리 목록 조회관련 API 구현했습니다.


📝 작업 내용

  • GET /analysis/request/accounts
    • 로그인한 유저의 GitHub 개인 계정과 소속 organization 목록 조회
  • GET /analysis/request/repositories
    • 선택한 GitHub 계정 또는 organization의 레포지토리 목록 조회
    • accountName 기준으로 개인 계정/organization 레포지토리 분기 처리
    • 레포지토리 검색 기능 추가
      • keyword query parameter로 레포지토리 이름 또는 owner 기준 검색
  • GET /analysis/request/repositories/{owner}/{repository}/branches
    • 선택한 레포지토리의 브랜치 목록 조회
  • GitHub API 호출 client, DTO, service, validator 분리
  • GitHub API/토큰/계정 조회 관련 커스텀 에러 코드 추가

👀 변경 사항

  • 기존 API 설계와 달라졌습니다. 기존에는 연동할 레포지토리 목록 조회 API 하나로 하려했으나, 흐름 상, 3개로 쪼개야할 거 같아 작업 내용과 같이 구현했습니다.

  • GitHub organization 및 private repository를 정상 조회하려면 OAuth 로그인 시 아래 scope가 필요합니다. (프론트한테 전달 완료)

read:user user:email read:org repo

📸 스크린샷 (Optional)

스크린샷 2026-06-09 16 25 53 스크린샷 2026-06-09 17 10 15 스크린샷 2026-06-09 16 26 23

✅ 체크리스트

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

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

GitHub 레포지토리 검색은 GitHub Search API를 별도로 사용하지 않고, 선택한 계정/조직의 레포지토리 목록을 조회한 뒤 서버에서 keyword 기준으로 필터링하도록 구현했습니다. 현재 화면 흐름에서는 선택 계정 범위 내 검색이므로 이 방식이 API 응답 형태와 권한 처리를 단순하게 유지할 수 있다고 판단했습니다.

Summary by CodeRabbit

릴리스 노트

  • 새 기능

    • GitHub 계정 연동 기능 추가 (개인 계정 및 조직 지원)
    • 연동 가능한 저장소 목록 조회 API 추가
    • 저장소의 브랜치 목록 조회 API 추가
  • 개선

    • GitHub 인증 관련 오류 메시지 개선
    • API 문서에 운영/로컬 환경 서버 정보 추가

@dldusgh318 dldusgh318 added this to the 분석 요청 API 구현 milestone Jun 9, 2026
@dldusgh318 dldusgh318 self-assigned this Jun 9, 2026
@dldusgh318 dldusgh318 added the ✨ FEAT New feature or request label Jun 9, 2026
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@dldusgh318, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 44 minutes and 45 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 46daa4a1-9e56-4bc1-b0db-eb985bfa166f

📥 Commits

Reviewing files that changed from the base of the PR and between ff1d006 and cb5fb29.

📒 Files selected for processing (3)
  • src/main/java/SeCause/SeCause_be/domain/analysis/validator/AnalysisRequestValidator.java
  • src/main/java/SeCause/SeCause_be/global/config/WebClientConfig.java
  • src/main/resources/application-local.yml
📝 Walkthrough

Walkthrough

CI/CD 워크플로우를 프로필 기반 설정으로 마이그레이션하고, GitHub API를 통해 인증된 사용자의 계정/저장소/브랜치 목록을 조회하는 새로운 REST API를 구현한다. 외부 API 통합, 입력 검증, 비즈니스 로직 및 HTTP 엔드포인트를 단계적으로 구성한다.

Changes

GitHub 저장소 조회 API 기능

Layer / File(s) Summary
설정 및 배포 기반
.github/workflows/cd.yml, .github/workflows/ci.yml, .gitignore, src/main/resources/application.yml, src/main/resources/application-local.yml, src/main/resources/application-dev.yml, src/main/java/SeCause/SeCause_be/global/config/SwaggerConfig.java
CI/CD 워크플로우에서 비밀을 통한 application.yml 생성 단계가 제거되고, application-local.ymlapplication-dev.yml 프로필 기반 설정이 추가된다. 기본 프로필은 local로 설정되며, Swagger 설정에 프로덕션 및 로컬 서버 URL이 구성된다.
도메인 오류 코드 및 예외
src/main/java/SeCause/SeCause_be/domain/analysis/code/AnalysisErrorCode.java, src/main/java/SeCause/SeCause_be/domain/user/code/UserErrorCode.java, src/main/java/SeCause/SeCause_be/domain/user/exception/UserException.java
GitHub API 호출 결과(인증 실패, 권한 거부, 계정 없음, 호출 실패)에 대응하는 AnalysisErrorCode 네 개 상수가 추가되고, 사용자 도메인의 UserErrorCodeUserException이 정의된다.
GitHub API 클라이언트 및 응답 모델
src/main/java/SeCause/SeCause_be/domain/analysis/client/GithubRepositoryClient.java, src/main/java/SeCause/SeCause_be/domain/analysis/dto/GithubUserAccountResponse.java, src/main/java/SeCause/SeCause_be/domain/analysis/dto/GithubAccountResponse.java, src/main/java/SeCause/SeCause_be/domain/analysis/dto/GithubRepositoryResponse.java, src/main/java/SeCause/SeCause_be/domain/analysis/dto/GithubBranchResponse.java
WebClient로 GitHub REST API(/user, /user/orgs, /user/repos, /orgs/{org}/repos, /repos/{owner}/{repo}/branches)를 호출하고 응답을 DTO로 매핑한다. 예외는 도메인 오류 코드로 일관되게 변환된다.
API 응답 모델 및 계약
src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableGithubAccountType.java, src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableGithubAccountResponse.java, src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableGithubAccountListResponse.java, src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryResponse.java, src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryListResponse.java, src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryBranchResponse.java, src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryBranchListResponse.java, src/main/java/SeCause/SeCause_be/domain/analysis/controller/AnalysisRequestApi.java
연동 가능한 계정 유형(개인/조직), 저장소, 브랜치 정보를 담는 DTO와 열거형이 정의되며, 세 가지 조회 엔드포인트(GET /accounts, GET /repositories, GET /repositories/{owner}/{repository}/branches)를 명시하는 공개 API 인터페이스가 작성된다.
요청 처리: 검증, 서비스, 컨트롤러
src/main/java/SeCause/SeCause_be/domain/analysis/validator/AnalysisRequestValidator.java, src/main/java/SeCause/SeCause_be/domain/analysis/service/AnalysisRequestService.java, src/main/java/SeCause/SeCause_be/domain/analysis/controller/AnalysisRequestController.java
사용자 존재 여부, GitHub 토큰, 계정명을 검증한 뒤, GitHub 클라이언트에서 수집한 데이터를 필터링·정렬하여 정규화된 응답을 반환하고, HTTP 엔드포인트에 바인딩한다.

Sequence Diagram

sequenceDiagram
    participant Client as 클라이언트
    participant Controller as AnalysisRequestController
    participant Service as AnalysisRequestService
    participant Validator as AnalysisRequestValidator
    participant GithubClient as GithubRepositoryClient
    participant GitHub as GitHub API
    
    Client->>Controller: GET /analysis/request/accounts
    Controller->>Service: getLinkableGithubAccounts(userId)
    Service->>Validator: validateLoginUser(userId)
    Validator-->>Service: User
    Service->>Validator: validateGithubToken(token)
    Validator-->>Service: token
    Service->>GithubClient: getUserAccount(token)
    GithubClient->>GitHub: GET /user
    GitHub-->>GithubClient: GithubUserAccountResponse
    GithubClient-->>Service: GithubUserAccountResponse
    Service->>GithubClient: getUserOrganizations(token)
    GithubClient->>GitHub: GET /user/orgs
    GitHub-->>GithubClient: List<GithubAccountResponse>
    GithubClient-->>Service: List<GithubAccountResponse>
    Service-->>Controller: LinkableGithubAccountListResponse
    Controller-->>Client: ApiResponse<LinkableGithubAccountListResponse>
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • SeCause/SeCause-BE#4: CI/CD 배포 워크플로우 업데이트로 .github/workflows/cd.yml의 배포 설정 변경과 관련이 있다.

Poem

🐰 GitHub의 정원을 탐험하며,
계정과 저장소를 정렬하고,
브랜치마다 새로운 기능을 피우네.
프로필 기반 설정으로 깔끔하게,
마치 당근을 수확하듯이! 🥕

🚥 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 제목이 변경사항의 주요 목적을 명확하게 설명합니다. '연동할 레포지토리 목록 조회 API 구현'은 GitHub 레포지토리 목록을 조회하는 API 구현이라는 핵심 변경사항을 정확히 반영합니다.
Linked Issues check ✅ Passed 연결된 이슈 #30의 모든 주요 요구사항이 충족되었습니다. GitHub 계정/레포지토리/브랜치 조회 엔드포인트 3개 구현, GitHub API 호출(/user/repos, /user/orgs, /orgs/{org}/repos), 응답 DTO 정의(이름, owner, defaultBranch, private), 토큰 기반 인증 처리가 모두 완료되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 이슈 #30의 범위 내에 있습니다. GitHub 클라이언트, 컨트롤러, 서비스, 검증기, DTO, 에러코드 및 설정 변경이 모두 레포지토리 목록 조회 API 구현이라는 목표에 직접 관련되어 있습니다.

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

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

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


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: 6

🧹 Nitpick comments (5)
.github/workflows/cd.yml (1)

72-76: ⚡ Quick win

배포 이미지는 latest 대신 커밋 SHA로 고정하세요.

Line [75]에서 latest를 사용하면 재시도/동시 실행 시 의도와 다른 이미지가 올라갈 수 있습니다. Line [56]에서 이미 SHA 태그를 푸시하므로 배포도 동일 태그를 쓰는 편이 안전합니다.

제안 diff
       - name: Deploy to server with Docker
         uses: appleboy/ssh-action@master
         env:
           DOCKER_REPO: ${{ secrets.DOCKER_REPO }}
+          IMAGE_TAG: ${{ github.sha }}
         with:
@@
-          envs: DOCKER_REPO
+          envs: DOCKER_REPO,IMAGE_TAG
           script: |
@@
-                image: ${DOCKER_REPO}:latest
+                image: ${DOCKER_REPO}:${IMAGE_TAG}
🤖 Prompt for 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.

In @.github/workflows/cd.yml around lines 72 - 76, Replace the hardcoded
":latest" in the docker-compose heredoc with the same SHA tag variable used when
pushing the image earlier so the deployed image matches the pushed image;
specifically update the generated docker-compose block where image:
${DOCKER_REPO}:latest is written to use the commit SHA variable (the same
variable used at the push step) instead of "latest" so docker-compose pulls
${DOCKER_REPO}:${SHA_TAG_VAR} and not ${DOCKER_REPO}:latest.
src/main/java/SeCause/SeCause_be/domain/analysis/code/AnalysisErrorCode.java (1)

13-16: 💤 Low value

선택적 개선: 에러 코드 접미사 패턴에 대한 설명 추가를 고려하세요.

GITHUB_TOKEN_INVALID"ANALYSIS_GITHUB4012" (401 + 접미사 2)를, GITHUB_ACCOUNT_NOT_FOUND"ANALYSIS_GITHUB4041" (404 + 접미사 1)을 사용하는 반면, 다른 코드들은 접미사가 없습니다. UserErrorCodeUSER_GITHUB4011이 있는 것으로 보아 도메인 간 충돌 방지를 위한 의도적 설계로 보이지만, 이러한 패턴이 문서화되어 있지 않으면 향후 유지보수 시 혼란을 줄 수 있습니다.

접미사 규칙을 enum 상단에 주석으로 추가하거나, 불필요한 경우 정규화를 고려해보세요.

🤖 Prompt for 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.

In `@src/main/java/SeCause/SeCause_be/domain/analysis/code/AnalysisErrorCode.java`
around lines 13 - 16, The enum values in AnalysisErrorCode (e.g.,
GITHUB_TOKEN_INVALID, GITHUB_ACCOUNT_NOT_FOUND) use numeric-suffix variants like
"ANALYSIS_GITHUB4012"/"ANALYSIS_GITHUB4041" while other codes lack suffixes;
either document this suffix convention or normalize the codes. Update the
AnalysisErrorCode enum declaration to include a short Javadoc/comment at the top
describing the suffix pattern (e.g., suffix meaning and cross-domain collision
avoidance with UserErrorCode such as USER_GITHUB4011), or rename/standardize the
constants so all GitHub-related codes follow a consistent format across
AnalysisErrorCode and UserErrorCode. Ensure the comment references the exact
pattern and examples (ANALYSIS_GITHUB4012, ANALYSIS_GITHUB4041) so future
maintainers understand the rule.
src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryListResponse.java (1)

9-10: ⚡ Quick win

리스트 래퍼 DTO도 List.copyOf로 고정하는 편이 안전합니다.

입력 리스트를 그대로 보관하면 생성 이후 외부 변경에 노출됩니다.

제안 패치
 public static LinkableRepositoryListResponse from(List<LinkableRepositoryResponse> repositories) {
-    return new LinkableRepositoryListResponse(repositories);
+    return new LinkableRepositoryListResponse(List.copyOf(repositories));
 }
🤖 Prompt for 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.

In
`@src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryListResponse.java`
around lines 9 - 10, The from factory method in LinkableRepositoryListResponse
currently stores the incoming List<LinkableRepositoryResponse> directly which
allows external mutation after construction; change it to create an unmodifiable
copy (e.g. via List.copyOf) when assigning to the internal field so the
constructor or the from method (LinkableRepositoryListResponse.from) stores
List.copyOf(repositories) (or have the constructor call List.copyOf on its
parameter) to ensure immutability.
src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableGithubAccountListResponse.java (1)

9-10: ⚡ Quick win

응답 DTO에 전달된 리스트를 방어적으로 복사하세요.

현재 from(...)가 입력 리스트 참조를 그대로 보관해서, 호출 측 변경이 응답 객체에 반영될 수 있습니다.

제안 패치
 public static LinkableGithubAccountListResponse from(List<LinkableGithubAccountResponse> accounts) {
-    return new LinkableGithubAccountListResponse(accounts);
+    return new LinkableGithubAccountListResponse(List.copyOf(accounts));
 }
🤖 Prompt for 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.

In
`@src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableGithubAccountListResponse.java`
around lines 9 - 10, from(List<LinkableGithubAccountResponse> accounts)
currently stores the incoming list reference directly; make a defensive copy so
external mutations don't affect the DTO by creating a new ArrayList copy (e.g.,
new ArrayList<>(accounts)) when constructing LinkableGithubAccountListResponse
or inside its constructor; update the constructor or the static factory method
in class LinkableGithubAccountListResponse to assign an unmodifiable/ copied
list (use Collections.unmodifiableList if immutability is desired) instead of
keeping the original reference.
src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryBranchListResponse.java (1)

9-10: ⚡ Quick win

브랜치 목록 응답도 외부 변경 차단이 필요합니다.

from(...)에서 전달 리스트를 복사하지 않으면 응답 불변성이 깨질 수 있습니다.

제안 패치
 public static LinkableRepositoryBranchListResponse from(List<LinkableRepositoryBranchResponse> branches) {
-    return new LinkableRepositoryBranchListResponse(branches);
+    return new LinkableRepositoryBranchListResponse(List.copyOf(branches));
 }
🤖 Prompt for 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.

In
`@src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryBranchListResponse.java`
around lines 9 - 10, The static factory method
LinkableRepositoryBranchListResponse.from(List<LinkableRepositoryBranchResponse>
branches) currently stores the caller-supplied list directly which breaks
response immutability; update from(...) (and the
LinkableRepositoryBranchListResponse constructor if needed) to defensively copy
the incoming list (e.g. new ArrayList<>(branches)) and expose or store an
unmodifiable view (Collections.unmodifiableList(...)) so external mutations
cannot affect the response state.
🤖 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/analysis/client/GithubRepositoryClient.java`:
- Around line 31-53: The getUserAccount method in GithubRepositoryClient uses
webClient.block() without a timeout; update it to enforce a request timeout
(e.g., call block with a Duration like block(Duration.ofSeconds(10))) or
configure the webClient instance with a global response timeout (build WebClient
with a ReactorClientHttpConnector using
HttpClient.create().responseTimeout(Duration.ofSeconds(10))). Modify either the
getUserAccount call or the webClient construction so that webClient calls time
out instead of blocking indefinitely, and keep the existing exception handling
(Unauthorized/Forbidden/RequestFailed) intact.
- Around line 113-137: getList in GithubRepositoryClient currently calls
webClient.block() without a timeout and doesn't handle GitHub pagination (only
per_page=100), risking hangs and truncated results; update getList to apply a
request timeout (either use block(Duration) or configure a connector/read/write
timeout on WebClient in WebClientConfig) and implement pagination by iterating
pages: perform requests (use exchangeToMono/flatMap to access response headers)
to read the Link header or include a page parameter (e.g., page query) in the
uriFunction and loop until no rel="next", aggregating results into a single
List<T> before returning; ensure error handling for timeouts maps to the
existing AnalysisException codes and reuse webClient and getList signatures (or
add an internal helper) so callers are unchanged.

In
`@src/main/java/SeCause/SeCause_be/domain/analysis/service/AnalysisRequestService.java`:
- Around line 63-69: 현재 validatedAccountName과 userAccount.login()을 대소문자 구분 없이
비교하지 않아 케이스가 다른 동일 계정명에 대해 개인 저장소 조회 대신 조직 검증 경로로 들어가는 문제가 있습니다;
validatedAccountName.equals(userAccount.login()) 비교를
validatedAccountName.equalsIgnoreCase(userAccount.login())로 바꾸거나 두 값을
toLowerCase()/toUpperCase로 정규화한 뒤 비교하도록 수정하고(참조: validatedAccountName,
userAccount.login(), githubRepositoryClient.getUserOwnedRepositories,
analysisRequestValidator.validateOrganizationAccount,
githubRepositoryClient.getUserOrganizations) 개인 계정 분기에서 항상 올바른 개인 저장소
조회(githubRepositoryClient.getUserOwnedRepositories)가 호출되도록 보장하세요.

In
`@src/main/java/SeCause/SeCause_be/domain/analysis/validator/AnalysisRequestValidator.java`:
- Around line 35-40: validateGithubAccountName currently returns the raw
accountName which allows equivalent names with whitespace/case differences to be
rejected later; normalize the input by trimming whitespace and applying a
consistent case (e.g., toLowerCase()) inside validateGithubAccountName before
validation and return, and ensure the same normalization is applied wherever the
code compares GitHub account strings (the comparison logic referenced near lines
47-49) so comparisons use the normalized form.

In `@src/main/resources/application-dev.yml`:
- Around line 35-36: application-dev.yml uses environment variable keys
refresh-secret and refresh-token-hash-secret mapped to ${REFRESH_SECRET} and
${REFRESH_TOKEN_HASH_SECRET}, which are inconsistent with other profiles; update
these placeholders to use the JWT-prefixed env vars (replace ${REFRESH_SECRET}
with ${JWT_REFRESH_SECRET} and ${REFRESH_TOKEN_HASH_SECRET} with
${JWT_REFRESH_HASH_SECRET}) so the keys (refresh-secret,
refresh-token-hash-secret) read from the same JWT_* environment variables used
by other profiles.

In `@src/main/resources/application.yml`:
- Around line 1-3: Remove the hard-coded spring.profiles.active: local default
from application.yml so the app doesn't fall back to the local profile when
SPRING_PROFILES_ACTIVE is absent; specifically, delete or unset the
spring.profiles.active entry (the "spring.profiles.active" key and its "local"
value) and rely on environment/property injection (SPRING_PROFILES_ACTIVE or
--spring.profiles.active) at runtime, or replace it with a non-binding
placeholder (e.g., leave it out or set to null) and document that profiles must
be provided when starting the app.

---

Nitpick comments:
In @.github/workflows/cd.yml:
- Around line 72-76: Replace the hardcoded ":latest" in the docker-compose
heredoc with the same SHA tag variable used when pushing the image earlier so
the deployed image matches the pushed image; specifically update the generated
docker-compose block where image: ${DOCKER_REPO}:latest is written to use the
commit SHA variable (the same variable used at the push step) instead of
"latest" so docker-compose pulls ${DOCKER_REPO}:${SHA_TAG_VAR} and not
${DOCKER_REPO}:latest.

In
`@src/main/java/SeCause/SeCause_be/domain/analysis/code/AnalysisErrorCode.java`:
- Around line 13-16: The enum values in AnalysisErrorCode (e.g.,
GITHUB_TOKEN_INVALID, GITHUB_ACCOUNT_NOT_FOUND) use numeric-suffix variants like
"ANALYSIS_GITHUB4012"/"ANALYSIS_GITHUB4041" while other codes lack suffixes;
either document this suffix convention or normalize the codes. Update the
AnalysisErrorCode enum declaration to include a short Javadoc/comment at the top
describing the suffix pattern (e.g., suffix meaning and cross-domain collision
avoidance with UserErrorCode such as USER_GITHUB4011), or rename/standardize the
constants so all GitHub-related codes follow a consistent format across
AnalysisErrorCode and UserErrorCode. Ensure the comment references the exact
pattern and examples (ANALYSIS_GITHUB4012, ANALYSIS_GITHUB4041) so future
maintainers understand the rule.

In
`@src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableGithubAccountListResponse.java`:
- Around line 9-10: from(List<LinkableGithubAccountResponse> accounts) currently
stores the incoming list reference directly; make a defensive copy so external
mutations don't affect the DTO by creating a new ArrayList copy (e.g., new
ArrayList<>(accounts)) when constructing LinkableGithubAccountListResponse or
inside its constructor; update the constructor or the static factory method in
class LinkableGithubAccountListResponse to assign an unmodifiable/ copied list
(use Collections.unmodifiableList if immutability is desired) instead of keeping
the original reference.

In
`@src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryBranchListResponse.java`:
- Around line 9-10: The static factory method
LinkableRepositoryBranchListResponse.from(List<LinkableRepositoryBranchResponse>
branches) currently stores the caller-supplied list directly which breaks
response immutability; update from(...) (and the
LinkableRepositoryBranchListResponse constructor if needed) to defensively copy
the incoming list (e.g. new ArrayList<>(branches)) and expose or store an
unmodifiable view (Collections.unmodifiableList(...)) so external mutations
cannot affect the response state.

In
`@src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryListResponse.java`:
- Around line 9-10: The from factory method in LinkableRepositoryListResponse
currently stores the incoming List<LinkableRepositoryResponse> directly which
allows external mutation after construction; change it to create an unmodifiable
copy (e.g. via List.copyOf) when assigning to the internal field so the
constructor or the from method (LinkableRepositoryListResponse.from) stores
List.copyOf(repositories) (or have the constructor call List.copyOf on its
parameter) to ensure immutability.
🪄 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: 858aa8ee-bbc1-4f23-85ff-67ea9c09d4b4

📥 Commits

Reviewing files that changed from the base of the PR and between 5b44e0d and ff1d006.

📒 Files selected for processing (26)
  • .github/workflows/cd.yml
  • .github/workflows/ci.yml
  • .gitignore
  • src/main/java/SeCause/SeCause_be/domain/analysis/client/GithubRepositoryClient.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/code/AnalysisErrorCode.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/controller/AnalysisRequestApi.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/controller/AnalysisRequestController.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/dto/GithubAccountResponse.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/dto/GithubBranchResponse.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/dto/GithubRepositoryResponse.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/dto/GithubUserAccountResponse.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableGithubAccountListResponse.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableGithubAccountResponse.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableGithubAccountType.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryBranchListResponse.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryBranchResponse.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryListResponse.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/dto/LinkableRepositoryResponse.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/service/AnalysisRequestService.java
  • src/main/java/SeCause/SeCause_be/domain/analysis/validator/AnalysisRequestValidator.java
  • src/main/java/SeCause/SeCause_be/domain/user/code/UserErrorCode.java
  • src/main/java/SeCause/SeCause_be/domain/user/exception/UserException.java
  • src/main/java/SeCause/SeCause_be/global/config/SwaggerConfig.java
  • src/main/resources/application-dev.yml
  • src/main/resources/application-local.yml
  • src/main/resources/application.yml
💤 Files with no reviewable changes (2)
  • .github/workflows/ci.yml
  • .gitignore

Comment on lines +35 to +36
refresh-secret: ${REFRESH_SECRET}
refresh-token-hash-secret: ${REFRESH_TOKEN_HASH_SECRET}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

JWT 리프레시 시크릿 환경변수 키가 다른 프로필과 불일치합니다.

Line [35]-Line [36] 키가 local 프로필(JWT_REFRESH_SECRET, JWT_REFRESH_HASH_SECRET)과 달라 배포 env 파일이 JWT_* 기준이면 dev 프로필에서 값 미주입으로 기동 실패할 수 있습니다.

제안 diff
-  refresh-secret: ${REFRESH_SECRET}
-  refresh-token-hash-secret: ${REFRESH_TOKEN_HASH_SECRET}
+  refresh-secret: ${JWT_REFRESH_SECRET}
+  refresh-token-hash-secret: ${JWT_REFRESH_HASH_SECRET}
🤖 Prompt for 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.

In `@src/main/resources/application-dev.yml` around lines 35 - 36,
application-dev.yml uses environment variable keys refresh-secret and
refresh-token-hash-secret mapped to ${REFRESH_SECRET} and
${REFRESH_TOKEN_HASH_SECRET}, which are inconsistent with other profiles; update
these placeholders to use the JWT-prefixed env vars (replace ${REFRESH_SECRET}
with ${JWT_REFRESH_SECRET} and ${REFRESH_TOKEN_HASH_SECRET} with
${JWT_REFRESH_HASH_SECRET}) so the keys (refresh-secret,
refresh-token-hash-secret) read from the same JWT_* environment variables used
by other profiles.

Comment on lines +1 to +3
spring:
profiles:
active: local No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

기본 설정에서 local 프로필 고정은 운영 오기동 위험이 큽니다.

Line [3]이 local로 고정되어 SPRING_PROFILES_ACTIVE 누락 시 운영 환경도 로컬 설정(JWT 로컬 기본값 포함)으로 기동될 수 있습니다. 기본 파일에서는 active를 고정하지 말고 런타임에서 명시적으로 주입하세요.

제안 diff
 spring:
   profiles:
-    active: local
+    active: ${SPRING_PROFILES_ACTIVE}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
spring:
profiles:
active: local
spring:
profiles:
active: ${SPRING_PROFILES_ACTIVE}
🤖 Prompt for 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.

In `@src/main/resources/application.yml` around lines 1 - 3, Remove the hard-coded
spring.profiles.active: local default from application.yml so the app doesn't
fall back to the local profile when SPRING_PROFILES_ACTIVE is absent;
specifically, delete or unset the spring.profiles.active entry (the
"spring.profiles.active" key and its "local" value) and rely on
environment/property injection (SPRING_PROFILES_ACTIVE or
--spring.profiles.active) at runtime, or replace it with a non-binding
placeholder (e.g., leave it out or set to null) and document that profiles must
be provided when starting the app.

@dldusgh318 dldusgh318 merged commit 4e1a829 into SeCause:develop Jun 10, 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

1 participant