zioinfo-mail/plugins/harness-main/skills/harness/references/qa-agent-guide.md
DESKTOP-TKLFCPR\ython e228faabf5 feat(itsm): G-1~G-12 확장 기능 + 하네스/봇/설치스크립트 구현
G-1: 메신저 Webhook Relay + _send_to_room 실제 httpx 호출 구현
G-2: POST /api/tasks/bulk SR 대량작업 엔드포인트 (최대 100건)
G-3: 라이선스 만료 알림 스케줄러 (매일 09:00 KST)
G-4: 체험판 upgrade_banner 필드 + license.py 배너 로직
G-5: core/auto_rca.py + incidents/problem auto-rca 엔드포인트
G-6: core/deploy_impact.py + vibe impact-analysis 엔드포인트
G-7: core/ticket_classifier.py + SR 생성 시 AI 분류 + ai-suggestion API
G-8: VulnPatchRecord 모델 + vuln_scan 패치추적 4개 엔드포인트
G-9: core/jira_sync.py + gateway Jira/Confluence 연동 엔드포인트
G-10: core/push_notify.py + routers/push.py + PushSubscription 모델
G-11: approvals 다중승인 (위임/서명/기한초과/마감연장)
G-12: alembic.ini + migrations/ + cicd/migrate_to_postgres.sh

하네스: guardia-orchestrator 확장기능 Phase 반영
봇명령어: /sr /status /license /bulk 슬래시 명령어 추가
설치스크립트: setup/ (Ubuntu, CentOS, RHEL, Windows) --test 옵션 포함

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:18:52 +09:00

11 KiB

QA 에이전트 설계 가이드

빌드 하네스에 QA 에이전트를 포함할 때 참고하는 가이드. 실제 프로젝트(SatangSlide)에서 발견된 버그 패턴과 그 근본 원인 분석을 바탕으로, QA가 놓치기 쉬운 결함을 체계적으로 잡는 검증 방법론을 제공한다.


목차

  1. QA 에이전트가 놓치는 결함의 패턴
  2. 통합 정합성 검증 (Integration Coherence Verification)
  3. QA 에이전트 설계 원칙
  4. 검증 체크리스트 템플릿
  5. QA 에이전트 정의 템플릿

1. QA 에이전트가 놓치는 결함의 패턴

1-1. 경계면 불일치 (Boundary Mismatch)

가장 빈번한 결함. 두 컴포넌트가 각각 "올바르게" 구현되어 있지만, 연결 지점에서 계약이 어긋남.

경계면 불일치 예시 놓치는 이유
API 응답 → 프론트 훅 API가 { projects: [...] } 반환, 훅이 SlideProject[] 기대 각각 개별 검증하면 정상, 교차 비교 안 함
API 응답 필드명 → 타입 정의 API가 thumbnailUrl(camelCase), 타입이 thumbnail_url(snake_case) TypeScript 제네릭으로 캐스팅하면 컴파일러가 못 잡음
파일 경로 → 링크 href 페이지가 /dashboard/create에 있는데 링크가 /create로 지정 파일 구조와 href를 교차 비교하지 않음
상태 전이 맵 → 실제 status 업데이트 맵에 generating_template → template_approved 정의, 코드에서 전환 누락 맵 존재 확인만 하고, 모든 업데이트 코드를 추적하지 않음
API 엔드포인트 → 프론트 훅 API 존재하지만 대응 훅 없음 (호출 안 됨) API 목록과 훅 목록을 1:1 매핑하지 않음
즉시 응답 → 비동기 결과 API가 즉시 { status } 반환, 프론트가 data.failedIndices 접근 동기/비동기 응답 구분 없이 타입만 확인

1-2. 왜 정적 코드 리뷰로 못 잡나

  • TypeScript 제네릭의 한계: fetchJson<SlideProject[]>() — 런타임 응답이 { projects: [...] }여도 컴파일 통과
  • npm run build 통과 ≠ 정상 동작: 타입 캐스팅, any, 제네릭이 사용되면 빌드는 성공하지만 런타임에 실패
  • 존재 검증 vs 연결 검증의 차이: "API가 있는가?"와 "API의 응답이 호출측의 기대와 일치하는가?"는 전혀 다른 검증

2. 통합 정합성 검증 (Integration Coherence Verification)

QA 에이전트에 반드시 포함해야 하는 교차 비교 검증 영역.

2-1. API 응답 ↔ 프론트 훅 타입 교차 검증

방법: 각 API route의 NextResponse.json() 호출부와 대응 훅의 fetchJson<T> 타입 파라미터를 비교.

검증 단계:
1. API route에서 NextResponse.json()에 전달하는 객체의 shape 추출
2. 대응 훅에서 fetchJson<T>의 T 타입 확인
3. shape과 T가 일치하는지 비교
4. 래핑 여부 확인 (API가 { data: [...] }를 반환하면 훅이 .data를 꺼내는지)

특히 주의할 패턴:

  • 페이지네이션 API: { items: [], total, page } vs 프론트가 배열 기대
  • snake_case DB 필드 → camelCase API 응답 → 프론트 타입 정의 간 불일치
  • 즉시 응답 (202 Accepted) vs 최종 결과의 shape 차이

2-2. 파일 경로 ↔ 링크/라우터 경로 매핑

방법: src/app/ 하위 page 파일의 URL 경로를 추출하고, 코드 내 모든 href, router.push(), redirect() 값과 대조.

검증 단계:
1. src/app/ 하위 page.tsx 파일 경로에서 URL 패턴 추출
   - (group) → URL에서 제거
   - [param] → 동적 세그먼트
2. 코드 내 모든 href=, router.push(, redirect( 값 수집
3. 각 링크가 실제 존재하는 page 경로와 매칭되는지 확인
4. route group 내부 페이지의 URL 접두사 주의 (예: dashboard/ 하위)

2-3. 상태 전이 완전성 추적

방법: 코드에서 모든 status: 업데이트를 추출하여 상태 전이 맵과 대조.

검증 단계:
1. 상태 전이 맵(STATE_TRANSITIONS)에서 허용된 전이 목록 추출
2. 모든 API route에서 .update({ status: "..." }) 패턴 검색
3. 각 전이가 맵에 정의되어 있는지 확인
4. 맵에 정의된 전이 중 코드에서 실행되지 않는 것 식별 (죽은 전이)
5. 특히: 중간 상태(예: generating_template)에서 최종 상태(template_approved)로의 전환이 누락되지 않았는지

2-4. API 엔드포인트 ↔ 프론트 훅 1:1 매핑

방법: 모든 API route와 프론트 훅을 나열하여 짝이 맞는지 확인.

검증 단계:
1. src/app/api/ 하위 route.ts에서 HTTP 메서드별 엔드포인트 목록 추출
2. src/hooks/ 하위 use*.ts에서 fetch 호출 URL 목록 추출
3. API 엔드포인트 중 훅에서 호출하지 않는 것 식별 → "사용 안 됨" 플래그
4. "사용 안 됨"이 의도적인지 (관리 API 등) 아닌지 (호출 누락) 판단

3. QA 에이전트 설계 원칙

3-1. Explore 타입이 아닌 general-purpose 타입을 사용하라

QA 에이전트가 Explore 타입이면 읽기만 가능하다. 하지만 효과적인 QA는:

  • Grep으로 패턴 검색 (모든 NextResponse.json() 추출)
  • 스크립트 실행으로 자동 대조 (API shape vs 훅 타입)
  • 필요 시 수정까지 가능

권장: general-purpose 타입으로 설정하되, 에이전트 정의에서 "검증 → 리포트 → 수정 요청" 프로토콜을 명시.

3-2. 체크리스트는 "존재 확인"보다 "교차 비교"를 우선하라

약한 체크리스트 강한 체크리스트
API 엔드포인트가 존재하는가? API 엔드포인트의 응답 shape과 대응 훅의 타입이 일치하는가?
상태 전이 맵이 정의되어 있는가? 모든 status 업데이트 코드가 맵의 전이와 일치하는가?
페이지 파일이 존재하는가? 코드 내 모든 링크가 실제 존재하는 페이지를 가리키는가?
TypeScript strict mode인가? 제네릭 캐스팅으로 우회된 타입 안전성이 없는가?

3-3. "양쪽을 동시에 읽어라" 원칙

QA가 경계면 버그를 잡으려면, 한쪽만 읽어선 안 된다. 반드시:

  • API route 대응 훅을 같이 읽고
  • 상태 전이 맵 실제 업데이트 코드를 같이 읽고
  • 파일 구조 링크 경로를 같이 읽어야 한다

에이전트 정의에 이 원칙을 명시적으로 기재하라.

3-4. QA는 빌드 후가 아니라, 각 모듈 완성 직후에 실행하라

오케스트레이터에서 QA를 "Phase 4: 전체 완성 후"에만 배치하면:

  • 버그가 누적되어 수정 비용이 높아짐
  • 초기 경계면 불일치가 후속 모듈에 전파됨

권장 패턴: 각 백엔드 API 완성 시 즉시 해당 API + 대응 훅의 교차 검증 수행 (incremental QA).


4. 검증 체크리스트 템플릿

QA 에이전트 정의에 포함할 웹 애플리케이션용 통합 정합성 체크리스트.

### 통합 정합성 검증 (웹 앱)

#### API ↔ 프론트엔드 연결
- [ ] 모든 API route의 응답 shape과 대응 훅의 제네릭 타입이 일치
- [ ] 래핑된 응답({ items: [...] })은 훅에서 unwrap하는지 확인
- [ ] snake_case ↔ camelCase 변환이 일관되게 적용
- [ ] 즉시 응답(202)과 최종 결과의 shape이 프론트에서 구분되는지 확인
- [ ] 모든 API 엔드포인트에 대응하는 프론트 훅이 존재하고 실제로 호출됨

#### 라우팅 정합성
- [ ] 코드 내 모든 href/router.push 값이 실제 page 파일 경로와 매칭
- [ ] route group ((group))이 URL에서 제거되는 것을 고려한 경로 검증
- [ ] 동적 세그먼트([id])가 올바른 파라미터로 채워지는지 확인

#### 상태 머신 정합성
- [ ] 정의된 모든 상태 전이가 코드에서 실행됨 (죽은 전이 없음)
- [ ] 코드의 모든 status 업데이트가 전이 맵에 정의됨 (무단 전이 없음)
- [ ] 중간 상태에서 최종 상태로의 전환이 누락되지 않음
- [ ] 프론트에서 상태 기반 분기(if status === "X")의 X가 실제 도달 가능

#### 데이터 흐름 정합성
- [ ] DB 스키마 필드명과 API 응답 필드명의 매핑이 일관됨
- [ ] 프론트 타입 정의와 API 응답의 필드명이 일치
- [ ] 옵셔널 필드에 대한 null/undefined 처리가 양쪽에서 일관됨

5. QA 에이전트 정의 템플릿

빌드 하네스의 QA 에이전트에 포함할 핵심 섹션.

---
name: qa-inspector
description: "QA 검증 전문가. 스펙 준수, 통합 정합성, 디자인 품질을 검증."
---

# QA Inspector

## 핵심 역할
스펙 대비 구현 품질과 **모듈 간 통합 정합성**을 검증한다.

## 검증 우선순위

1. **통합 정합성** (가장 높음) — 경계면 불일치가 런타임 에러의 주요 원인
2. **기능 스펙 준수** — API/상태머신/데이터모델
3. **디자인 품질** — 색상/타이포/반응형
4. **코드 품질** — 미사용 코드, 명명 규칙

## 검증 방법: "양쪽 동시 읽기"

경계면 검증은 반드시 **양쪽 코드를 동시에 열어** 비교한다:

| 검증 대상 | 왼쪽 (생산자) | 오른쪽 (소비자) |
|----------|-------------|---------------|
| API 응답 shape | route.ts의 NextResponse.json() | hooks/의 fetchJson<T> |
| 라우팅 | src/app/ page 파일 경로 | href, router.push 값 |
| 상태 전이 | STATE_TRANSITIONS 맵 | .update({ status }) 코드 |
| DB → API → UI | 테이블 컬럼명 | API 응답 필드 → 타입 정의 |

## 팀 통신 프로토콜

- 발견 즉시 해당 에이전트에게 구체적 수정 요청 (파일:라인 + 수정 방법)
- 경계면 이슈는 양쪽 에이전트 **모두**에게 알림
- 리더에게: 검증 리포트 (통과/실패/미검증 항목 구분)

실제 사례: SatangSlide에서 발견된 버그

이 가이드의 모든 내용은 아래 실제 버그에서 추출한 교훈이다:

버그 경계면 원인
projects?.filter is not a function API→훅 API가 {projects:[]} 반환, 훅이 배열 기대
대시보드 모든 링크 404 파일경로→href /dashboard/ 접두사 누락
테마 이미지 안 보임 API→컴포넌트 thumbnailUrl vs thumbnail_url
테마 선택 저장 안 됨 API→훅 select-theme API 존재, 훅 없음
생성 페이지 영원히 대기 상태전이→코드 template_approved 전이 코드 누락
data.failedIndices 크래시 즉시응답→프론트 백그라운드 결과를 즉시 응답에서 접근
완료 후 슬라이드 보기 404 파일경로→href /projects//dashboard/projects/