# CI 자동 검증 연결하기

> 코드를 올릴 때마다 검증이 저절로 돌게 만드는 방법이에요. AI에게 붙여넣기 한 번이면 연결이 끝나고, 결과는 GitHub와 테스트 실행 탭에 함께 남아요. 직접 연결하는 법과 자주 묻는 질문까지 정리했어요.

## 이게 뭔가요

**배포하기 전에 자동으로 리허설을 한 번 돌리는 것**이라고 생각하면 쉬워요. 지금까지는 검증을 사람이 직접 눌러서 돌렸어요. CI 연동을 해 두면, 코드가 바뀔 때마다(예: 새 코드를 올리거나 검토 요청을 열 때) Specnote가 알아서 테스트를 한 번 검증해요.

여기서 CI란 코드를 올릴 때마다 정해진 검사를 자동으로 돌려 주는 장치예요. GitHub를 쓰신다면 GitHub Actions가 그 역할을 해요. Specnote는 그 자동 검사 한 자리에 "테스트 검증"을 끼워 넣는 거예요.

한 가지 안심하셔도 되는 점이 있어요. **검증을 실제로 돌리는 건 Specnote 서버예요.** 여러분의 코드가 도는 자리(CI)에서는 브라우저를 띄우거나 무거운 일을 하지 않아요. CI는 그저 "지금 검증해 줘" 하고 방아쇠만 당기고, 결과가 나올 때까지 기다렸다가 받아 오는 역할만 해요. 그래서 여러분 쪽 설정은 가볍고, 운영 비밀번호나 키가 넘어갈 일도 없어요.

검증이 끝나면 결과는 두 곳에 남아요.

- **검토 요청(PR) 화면** — 통과·실패 요약이 한국어로 붙어서, 코드를 합치기 전에 무엇이 깨졌는지 바로 보여요.
- **테스트 실행 탭** — 이번 검증이 하나의 실행 묶음으로 쌓여, 나중에 되짚어 볼 수 있어요.

> Specnote 서버가 여는 것은 **공개된 사이트 주소**여야 해요. 내 PC에서만 도는 `localhost` 주소는 서버가 접속할 수 없어 검증할 수 없습니다. 배포·미리보기 주소가 없다면 아래 "로컬에서만 앱이 도는데도 되나요?"를 봐 주세요.

## 어떤 테스트를 CI에 넣을지 고르기

만든 테스트를 전부 CI에서 돌릴 필요는 없어요. "이건 배포 전마다 꼭 통과해야 해" 싶은 것만 골라 넣으면 됩니다. 테스트마다 **CI 포함** 스위치를 켜면 그 테스트가 CI 검증 대상이 돼요.

이 켜고 끄기는 **바로 반영돼요.** 다음 검증부터 새로 켠 테스트는 자동으로 포함되고, 끈 테스트는 빠져요. 따로 저장하거나 다시 연결할 필요가 없어요. 코드를 올렸을 때 CI가 도는 순간, 그때 켜져 있는 테스트만 검증해요.

이 켜고 끄기는 **사람만** 할 수 있어요. 연결한 AI는 테스트를 만들고 돌릴 수는 있어도, 무엇을 CI 검증에 넣을지는 정하지 않습니다. "배포를 막을 수도 있는 기준"은 사람이 정한다는 원칙이에요.

CI 포함으로 켠 테스트는 작업실 보드의 **CI** 탭에 한데 모여요. 여기서 각 테스트가 어떻게 흘러왔는지 한눈에 볼 수 있어요.

- **마지막 검증 결과** — 가장 최근 회차가 통과였는지 실패였는지.
- **최근 5회 판정** — 최근 다섯 번이 각각 통과였는지 실패였는지를 나란히.
- **통과율** — 지금까지 몇 퍼센트나 통과했는지.
- **널뛰기 배지** — 통과와 실패를 오락가락하는(불안정한) 테스트에 붙어요. 이 배지가 붙은 테스트는 "진짜 버그"보다 "테스트 자체가 흔들리는" 경우가 많아, 먼저 다듬어 두면 좋아요.

## AI에게 맡기기 (권장)

가장 쉬운 방법이에요. 아래 내용을 복사해서 평소 쓰는 AI 코딩 도구(Claude Code·Cursor 등)에 붙여넣기만 하면, AI가 연결에 필요한 일을 대신해요. 토큰 발급, 워크플로우 파일 만들기, 커밋까지 전부요.

> Specnote 자동 검증을 이 저장소의 GitHub Actions에 연결해줘. 1) specnote_get_ci_workflow 도구로 워크플로우 파일 내용을 받아 .github/workflows/specnote-verify.yml 로 저장해줘 (specId 는 "<내 워크스페이스 ID>", 배포/스테이징 주소가 있으면 standard, 로컬 개발 서버만 있으면 local 모드). 2) specnote_issue_ci_token 도구로 CI 전용 토큰을 발급해줘. 3) 발급된 토큰을 GitHub 저장소 비밀값 SPECNOTE_TOKEN 으로 등록해줘 — gh CLI 가 있으면 `gh secret set SPECNOTE_TOKEN`, 없으면 GitHub 저장소 → Settings → Secrets and variables → Actions 경로를 나에게 안내해줘. 4) 검증 대상 주소(스테이징/프리뷰)가 필요하면 나에게 물어보고 `gh variable set SPECNOTE_TARGET_URL` 로 등록해줘. 5) 워크플로우 파일을 커밋·푸시하고, 무엇을 연결했는지 알려줘.

`<내 워크스페이스 ID>`는 지금 이 워크스페이스의 ID로 바꿔 주세요. AI가 물어보면 그대로 알려 주면 돼요. (테스트 실행 탭의 "CI 연동" 카드에서 복사하면 워크스페이스 ID가 이미 채워져 있어요.)

## 직접 연결하기

손수 연결하고 싶다면, 테스트 실행 탭의 "CI 연동" 카드에서 **[직접 연결하기]** 버튼을 누르면 웹에서 3단계로 끝낼 수 있어요. 토큰 발급, 값이 채워진 워크플로우 파일 복사·다운로드, 연결 확인까지 한 자리에서 해요. 명령까지 값이 채워진 채로 나오니 그대로 복사해 쓰면 됩니다.

버튼 없이 손으로 하고 싶다면 절차는 이래요.

1. **토큰 발급** — 마이페이지 → MCP 연결에서 CI 전용 토큰을 발급해요. 이 토큰은 검증을 시작하는 열쇠예요.
2. **워크플로우 파일 만들기** — 저장소에 `.github/workflows/specnote-verify.yml` 파일을 만들어요. 내용은 위 AI 프롬프트의 specnote_get_ci_workflow 도구가 워크스페이스 값이 채워진 상태로 그대로 내려줘요.
3. **비밀값 등록** — GitHub 저장소 → Settings → Secrets and variables → Actions 에서, 방금 발급한 토큰을 `SPECNOTE_TOKEN` 이라는 이름의 비밀값(secret)으로 등록해요.
4. **검증 주소 등록** — 같은 화면의 Variables 탭에서 `SPECNOTE_TARGET_URL` 이라는 변수(variable)에, 검증할 사이트 주소(스테이징이나 미리보기 주소)를 넣어요.

이 네 가지가 끝나면, 코드를 올릴 때마다 워크플로우가 저절로 돌면서 검증을 시작해요.

## GitHub Actions가 아니어도 돼요 — API로 직접 연결

GitLab·Jenkins·CircleCI·Bitbucket, 심지어 짧은 셸 스크립트까지 — 어떤 CI든 붙일 수 있어요. 특별한 플러그인은 필요 없고, 딱 세 가지만 있으면 돼요.

1. **CI 토큰** — 마이페이지나 "직접 연결하기" 마법사, 또는 연결한 AI(MCP)로 발급해 CI 비밀값으로 넣어요. 요청할 때 `Authorization: Bearer <토큰>` 헤더로 보냅니다.
2. **검증 시작** — `POST /api/ci/runs` 에 워크스페이스 ID(specId)와 검증할 공개 주소(targetUrl)를 담아 보내면, 그 자리에서 검증이 시작되고 실행 묶음 ID를 돌려줘요.
3. **결과 기다리기** — `GET /api/ci/runs/{실행 묶음 ID}` 를 10초 간격으로 확인해요. 상태(status)가 `COMPLETED`·`ERROR`·`CANCELED` 중 하나가 되면 끝난 거예요. 응답의 `summaryMarkdown` 은 사람이 바로 읽을 수 있는 한국어 요약이고, `failCount` 가 0보다 크면 실패로 처리하면 됩니다.

> GitLab을 쓰신다면 전용 템플릿(`.gitlab-ci.yml`)이 따로 있어요. "직접 연결하기" 마법사에서 GitLab CI를 고르거나, 연결한 AI에게 `specnote_get_ci_workflow` 의 provider를 gitlab으로 요청하면 값이 채워진 파일을 그대로 받을 수 있어요.

### 아무 CI에나 붙이는 스크립트

아래는 GitHub·GitLab 전용 값 없이 어디서나 돌아가는 최소 예시예요(필요한 건 `curl`과 `jq`뿐). `<워크스페이스 ID>`는 이 워크스페이스의 ID로, `SPECNOTE_TOKEN`·`TARGET_URL`은 CI 비밀값·변수로 넣으세요.

```bash
#!/usr/bin/env bash
set -euo pipefail

API="https://specnote.io"
SPEC_ID="<워크스페이스 ID>"
TARGET_URL="${TARGET_URL:-<검증할 공개 주소>}"
: "${SPECNOTE_TOKEN:?SPECNOTE_TOKEN 이 필요해요}"

# 1) 검증 시작(트리거)
BODY=$(jq -nc --arg specId "$SPEC_ID" --arg targetUrl "$TARGET_URL" \
  '{specId: $specId, targetUrl: $targetUrl, meta: {provider: "generic"}}')
CREATE=$(curl -sS --fail-with-body -X POST "$API/api/ci/runs" \
  -H "Authorization: Bearer $SPECNOTE_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$BODY")
RUN_ID=$(echo "$CREATE" | jq -r ".runGroupId // empty")
if [ -z "$RUN_ID" ]; then
  echo "검증을 시작하지 못했어요:"; echo "$CREATE"
  exit 1
fi

# 2) 완료까지 폴링(10초 간격)
for i in $(seq 1 180); do
  RES=$(curl -sS --fail-with-body "$API/api/ci/runs/$RUN_ID" \
    -H "Authorization: Bearer $SPECNOTE_TOKEN")
  STATUS=$(echo "$RES" | jq -r ".status // empty")
  case "$STATUS" in COMPLETED|ERROR|CANCELED) break ;; esac
  sleep 10
done

# 3) 사람이 읽는 요약 + 실패 시 종료 코드 1
echo "$RES" | jq -r ".summaryMarkdown // \"결과를 가져오지 못했어요.\""
FAIL=$(echo "$RES" | jq -r ".failCount // 0")
[ "$FAIL" -gt 0 ] && exit 1 || exit 0
```

몇 가지 기억할 점이 있어요. 이건 CI 종류와 상관없이 똑같아요.

- **공개 주소가 필요해요.** Specnote 서버가 접속할 수 있는 주소여야 해요. 내 PC에서만 도는 `localhost` 주소는 안 되고, 그럴 땐 임시 통로(터널)로 공개 주소를 만들어 `TARGET_URL`로 넘기세요.
- **처음엔 보고 모드로.** 위 예시는 실패하면 종료 코드 1을 돌려줘요. 익숙해지기 전까지는 그 줄을 빼서, 실패해도 파이프라인을 막지 않게 두는 걸 권해요.
- **켠 테스트만 돌아요.** 실행 결과에서 [CI 포함]으로 켠 시나리오만 검증돼요. 이 규칙은 GitHub든 GitLab이든 직접 API든 똑같아요.

## 보고 모드 ↔ 차단 모드

연결하면 처음에는 **보고 모드**로 시작해요. 검증이 실패하더라도 코드를 합치는 걸 막지는 않고, 결과만 알려 주는 방식이에요. 워크플로우 파일 안의 `continue-on-error: true` 한 줄이 이 역할을 해요.

익숙해지고 통과율이 안정된 뒤에는, 그 한 줄을 지워서 **차단 모드**로 바꿀 수 있어요. 차단 모드에서는 검증이 실패하면 코드 합치기가 막혀요. 처음부터 차단 모드로 두면 잠깐의 오탐에도 발이 묶일 수 있으니, **통과율이 안정된 뒤에 차단 모드로 전환하는 것을 권해요.**

## 자주 묻는 질문

**로컬에서만 앱이 도는데도 되나요?**
네. 배포된 주소가 없어도 돼요. 이 경우 CI가 잠깐 앱을 띄우고 임시 통로(터널)를 열어, 그동안만 공개 주소처럼 접속할 수 있게 해요. AI 프롬프트에서 "local 모드"라고 알려 주면 그 방식으로 만들어 줘요. 다만 임시 통로는 속도·수명이 보장되지 않아서, 배포나 미리보기 주소가 있다면 그쪽이 더 안정적이에요.

**비용이 드나요?**
CI로 도는 검증도 일반 검증과 똑같이 크레딧이 들어요. **한 번 재생할 때 실제로 걸린 시간만큼 아주 작은 크레딧이 조금씩 쌓여 청구돼요.** 한 번에 여러 테스트를 돌리면 그만큼 더 쌓이고, 잔액이 1크레딧에 못 미치면 그 회차는 실행되지 않아요(충전 후 다시 돌리면 됩니다). AI를 새로 부르지는 않아 자동 추출처럼 많이 들지는 않지만, "완전 무료"는 아니라는 점만 기억해 주세요.

**토큰을 다시 발급하면 어떻게 되나요?**
CI 토큰은 이름이 하나로 고정돼 있어서, 다시 발급하면 이전 토큰은 자동으로 폐기되고 새 토큰만 살아 있어요. 토큰을 잃어버렸거나 새로 돌리고 싶을 때 부담 없이 재발급하면 돼요. (재발급하면 GitHub 비밀값 `SPECNOTE_TOKEN`도 새 값으로 바꿔 주세요.)

**검증이 안 돌아요.**
가장 흔한 원인은 검증 대상 주소예요. `SPECNOTE_TARGET_URL` 변수에 넣은 사이트 주소가 지금 접속되는 공개 주소인지 확인해 주세요. 주소가 바뀌었다면 그 값을 새 주소로 고쳐 주면 돼요.

검증을 직접 눌러 돌리는 기본 방법은 [검증 돌리고 결과 읽기](/ko/docs/running-and-results)에서, 코드 연결이 아직이라면 [내 코드와 연결하기](/ko/docs/connect-your-code)를 먼저 봐 주세요.

---

Source: https://specnote.io/ko/docs/connect-ci
