Skip to content

ADR-27: 커밋 기반 분석 조회

🇺🇸 English Version

날짜작성자리포지토리
2026-02-03@KubrickCodeweb

Context

문제 상황

사용자는 리포지토리의 최신 분석 결과만 조회 가능. 그러나 데이터베이스에는 특정 커밋 SHA에 연결된 여러 분석 기록 존재. force-push 작업(git reset --hard && git push -f) 후 "Up to date" 메시지만 표시되고, 이전에 분석된 커밋 접근 불가.

사용자 요구사항

요구사항설명
히스토리 조회이전에 분석된 모든 커밋의 결과 조회
시간별 비교테스트 명세 변화 추적
회귀 디버깅특정 테스트 명세 변경 시점 식별
공유 가능한 분석 상태특정 커밋 분석 결과 링크 공유

기존 제약사항

제약사항출처영향
nuqs URL 상태Web ADR-16커밋 선택에 URL 파라미터 사용 필요
Zustand 범위Web ADR-26임시 상태 전용; 네비게이션 상태에 부적합
TanStack QueryWeb ADR-04분석 데이터 fetching 패턴 확립
Next.js App RouterWeb ADR-07URL 상태에 대한 SSR 고려 필요

Decision

nuqs를 사용한 URL 기반 커밋 선택과 CommitSelector UI 컴포넌트 도입.

핵심 원칙:

  1. URL을 진실의 원천으로: 커밋 선택이 URL에 유지 (?commit=abc1234)
  2. 점진적 개선: 파라미터 없을 시 최신 커밋으로 기본 설정
  3. nuqs 통합: SHA 형식 검증과 함께 parseAsString 사용
  4. 복합 상태: 커밋 선택과 기존 필터 조합

URL 구조

/repos/{owner}/{repo}/analysis?commit=abc1234
/repos/{owner}/{repo}/analysis?commit=abc1234&view=starred&q=auth

Options Considered

Option A: nuqs를 통한 URL 기반 커밋 선택 (채택)

기존 nuqs 패턴을 사용하여 선택된 커밋 SHA를 URL 쿼리 파라미터에 저장.

장점:

  • 정확한 분석 상태를 담은 공유 가능한 URL
  • 브라우저 히스토리 통합 (뒤로/앞으로 네비게이션)
  • SSR 호환으로 사전 fetching 가능
  • 기존 필터 패턴과 일관성 (ADR-16)
  • 다른 URL 상태와 조합 가능

단점:

  • URL 길이 증가 (7자 SHA 축약으로 완화)
  • 유효하지 않은 커밋 처리 필요
  • 커밋 삭제 시 오래된 북마크 처리 필요

Option B: Zustand를 통한 클라이언트 측 상태

선택된 커밋을 임시 클라이언트 상태로 Zustand 스토어에 저장.

장점:

  • 깔끔한 URL
  • 빠른 상태 변경
  • 크로스 컴포넌트 접근

단점:

  • 공유 불가
  • 페이지 새로고침 시 상태 손실
  • 브라우저 히스토리 미지원
  • ADR-26 범위 위반 (Zustand는 임시 상태 전용)

기각: 확립된 패턴과 모순; 공유 가능한 링크에 대한 불량 UX.

Option C: 경로 세그먼트 기반 선택

커밋 SHA를 URL 경로에 인코딩 (/analysis/{commit}).

장점:

  • RESTful 시맨틱
  • 깔끔한 URL 계층 구조

단점:

  • 라우팅 복잡성 증가
  • 쿼리 기반 필터와 불일치
  • 컴포넌트 업데이트가 아닌 페이지 전환 발생

기각: 구현 노력 증가; 필터 조합 불가.

Option D: 드롭다운만 (상태 지속성 없음)

로컬 상태만 있는 UI 컴포넌트.

기각: 수용 불가한 UX; 모든 네비게이션에서 선택 손실.

Implementation Details

API 엔드포인트

엔드포인트목적
GET /api/analyze/{owner}/{repo}/history분석된 커밋 목록 (최대 50개)
GET /api/analyze/{owner}/{repo}?commit={sha}특정 커밋의 분석 결과 조회

데이터 구조

typescript
interface AnalysisHistoryItem {
  id: string;
  commitSha: string;
  commitDate: string | null;
  completedAt: string;
  branchName: string | null;
  testCount: number;
  isHead: boolean;
}

URL 상태 Hook

typescript
import { parseAsString, useQueryState } from "nuqs";

const commitParser = parseAsString.withDefault("");

export const useCommitSelect = () => {
  const [commit, setCommit] = useQueryState("commit", commitParser);
  const validated = /^[a-f0-9]{7,40}$/.test(commit ?? "") ? commit : null;
  return { commit: validated, setCommit } as const;
};

CommitSelector 컴포넌트

  • 축약된 SHA (7자) 표시 드롭다운
  • 현재 HEAD 커밋에 [HEAD] 배지
  • 테스트 수, 브랜치명, 날짜 표시
  • 히스토리 항목이 2개 미만일 경우 정적 텍스트로 폴백

TanStack Query 통합

typescript
export const useAnalysisData = (owner: string, repo: string) => {
  const { commit } = useCommitSelect();

  return useQuery({
    queryKey: ["analysis", owner, repo, commit],
    queryFn: () => fetchAnalysis(owner, repo, commit),
  });
};

Consequences

Positive

  • 공유 가능한 분석 상태: /analysis?commit=abc1234&view=starred 같은 URL로 협업 가능
  • 브라우저 네비게이션: 뒤로/앞으로 버튼으로 커밋 히스토리 자연스럽게 탐색
  • SSR 최적화: URL 파라미터에서 서버가 올바른 분석 사전 fetch 가능
  • 패턴 일관성: ADR-16의 nuqs 패턴 확장
  • 디버깅 용이성: 지원팀이 정확한 상태를 위해 "URL 보내주세요" 요청 가능

Negative

  • URL 복잡성: 커밋 파라미터로 URL 길어짐 (SHA 축약으로 완화)
  • 유효하지 않은 상태 처리: 삭제된/사용 불가한 커밋 우아하게 처리 필요
  • 쿼리 무효화: 커밋 변경 시 TanStack Query 캐시 무효화 (예상된 동작)

References

Internal

External

Open-source test coverage insights