Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions .github/workflows/catalog-quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
name: Catalog Quality Check with Auto Issue Reporting

# 카탈로그 검사 도구(catalogutil.cs / checkimages.cs)를 주기적으로 실행하여
# 발견된 오류를 하나의 추적(tracking) 이슈로 자동 등록/갱신합니다.
# 검출은 자동, 실제 수정(카탈로그 갱신)은 사람 또는 AI 에이전트가 담당합니다.

on:
schedule:
# 매주 월요일 00:00 UTC (한국시간 월요일 09:00)
- cron: '0 0 * * 1'
workflow_dispatch:
inputs:
assign_copilot:
description: '생성/갱신된 추적 이슈를 Copilot 코딩 에이전트에 배정합니다.'
type: boolean
default: false
push:
branches:
- main
paths:
- 'docs/Catalog.xml'
- 'docs/images/**'

permissions:
contents: read
issues: write

jobs:
quality-check:
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
ISSUE_LABEL: catalog-quality
ISSUE_MARKER: '<!-- catalog-quality-report -->'
steps:
- uses: actions/checkout@v4

- name: Setup .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x

# 이미지 검증 (오프라인, 결정론적): 누락/미사용 로고 이미지를 검출합니다.
- name: Run image validation (checkimages.cs)
id: checkimages
run: |
code=0
dotnet run --file src/checkimages.cs -- ./docs/Catalog.xml ./docs/images \
> checkimages.log 2>&1 || code=$?
echo "exit_code=$code" >> "$GITHUB_OUTPUT"

# 스키마 검증 및 리소스 생성 (URL 접속성 경고 포함).
- name: Run catalog validation (catalogutil.cs)
id: catalogutil
run: |
code=0
dotnet run --file src/catalogutil.cs -- ./docs/ ./outputs/ \
> catalogutil.log 2>&1 || code=$?
echo "exit_code=$code" >> "$GITHUB_OUTPUT"

- name: Build issue body and decide action
id: report
run: |
set -euo pipefail

IMAGES_EXIT="${{ steps.checkimages.outputs.exit_code }}"
UTIL_EXIT="${{ steps.catalogutil.outputs.exit_code }}"

# 도구가 문제(비정상 종료 코드)를 보고했는지 판단합니다.
PROBLEMS=0
if [ "${IMAGES_EXIT:-0}" != "0" ] || [ "${UTIL_EXIT:-0}" != "0" ]; then
PROBLEMS=1
fi
echo "problems=$PROBLEMS" >> "$GITHUB_OUTPUT"

{
echo "$ISSUE_MARKER"
echo "## 카탈로그 품질 검사 리포트"
echo
echo "이 이슈는 \`catalog-quality\` 워크플로우가 자동으로 생성/갱신합니다."
echo "검출은 자동으로 이뤄지며, 실제 카탈로그 수정은 사람 또는 AI 에이전트가 담당합니다."
echo
echo "- **실행 시각(UTC)**: $(date -u '+%Y-%m-%dT%H:%M:%SZ')"
echo "- **커밋**: \`${GITHUB_SHA}\`"
echo "- **워크플로우 실행**: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
echo
echo "### 이미지 검증 (checkimages.cs) — 종료 코드 \`${IMAGES_EXIT:-N/A}\`"
echo
echo '```text'
# ANSI 이스케이프가 남아 있을 경우를 대비해 제거합니다.
sed -r 's/\x1B\[[0-9;]*[A-Za-z]//g' checkimages.log || cat checkimages.log
echo '```'
echo
echo "### 스키마/URL 검증 (catalogutil.cs) — 종료 코드 \`${UTIL_EXIT:-N/A}\`"
echo
echo "> 참고: URL 접속성 경고에는 CI 환경의 일시적 네트워크 문제가 포함될 수 있습니다."
echo
echo '```text'
sed -r 's/\x1B\[[0-9;]*[A-Za-z]//g' catalogutil.log || cat catalogutil.log
echo '```'
echo
echo "### 권장 조치"
echo
echo "- **누락된 이미지**: 해당 서비스의 공식 로고를 \`docs/images/<Category>/<Id>.png\`로 추가하세요. (\`src/fetchfavicon.cs\` 참고)"
echo "- **미사용 이미지**: Catalog.xml에서 삭제된 서비스의 이미지라면 함께 제거하세요."
echo "- **스키마 오류**: Catalog.xml의 구조/속성을 XSD에 맞게 수정하세요."
echo
echo "수정 후 다음으로 재검증하세요:"
echo
echo '```bash'
echo "dotnet run --file src/checkimages.cs -- ./docs/Catalog.xml ./docs/images"
echo "dotnet run --file src/catalogutil.cs -- ./docs/ ./outputs/"
echo '```'
echo
echo "---"
echo "*generated by \`.github/workflows/catalog-quality.yml\`*"
} > issue-body.md

- name: Create or update tracking issue
env:
PROBLEMS: ${{ steps.report.outputs.problems }}
ASSIGN_COPILOT: ${{ github.event.inputs.assign_copilot }}
run: |
set -euo pipefail

# 라벨이 없으면 생성합니다.
gh label create "$ISSUE_LABEL" \
--description "자동 카탈로그 품질 검사 리포트" \
--color BFD4F2 --force >/dev/null 2>&1 || true

# 열려 있는 기존 추적 이슈를 찾습니다 (라벨 기준, 최대 1건).
EXISTING=$(gh issue list --state open --label "$ISSUE_LABEL" \
--limit 1 --json number --jq '.[0].number // empty')

TITLE="[카탈로그 품질] 자동 검사에서 문제가 발견되었습니다"

if [ "$PROBLEMS" = "1" ]; then
if [ -n "$EXISTING" ]; then
echo "기존 추적 이슈 #$EXISTING 를 갱신합니다."
gh issue edit "$EXISTING" --body-file issue-body.md
gh issue comment "$EXISTING" \
--body "🔄 최신 검사 결과로 이슈 본문을 갱신했습니다. (실행 ${GITHUB_RUN_ID})"
ISSUE_NUMBER="$EXISTING"
else
echo "새 추적 이슈를 생성합니다."
ISSUE_URL=$(gh issue create --title "$TITLE" \
--body-file issue-body.md --label "$ISSUE_LABEL")
echo "생성됨: $ISSUE_URL"
ISSUE_NUMBER=$(basename "$ISSUE_URL")
fi

# 요청 시 Copilot 코딩 에이전트에 배정 (best-effort).
if [ "${ASSIGN_COPILOT:-false}" = "true" ] && [ -n "${ISSUE_NUMBER:-}" ]; then
gh issue edit "$ISSUE_NUMBER" --add-assignee "@copilot" \
|| echo "Copilot 배정에 실패했습니다 (수동 배정이 필요할 수 있습니다)."
fi
else
echo "문제가 발견되지 않았습니다."
if [ -n "$EXISTING" ]; then
echo "기존 추적 이슈 #$EXISTING 를 닫습니다."
gh issue comment "$EXISTING" \
--body "✅ 최신 자동 검사에서 더 이상 문제가 발견되지 않아 이슈를 닫습니다. (실행 ${GITHUB_RUN_ID})"
gh issue close "$EXISTING"
fi
fi
125 changes: 125 additions & 0 deletions .github/workflows/savings-bank-merger-watch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
name: Savings Bank Merger Watch (AI Agent Assisted)

# 기관 통폐합이 잦은 저축은행 업계 특성을 감안하여, 주기적으로 AI 에이전트에게
# "최근 저축은행 통폐합/명칭변경/폐업 뉴스"를 조사하도록 위임하는 이슈를 자동 생성합니다.
# 실제 뉴스 검색·판정은 AI 에이전트(Copilot 코딩 에이전트 / Claude Code 등)가 수행하고,
# 카탈로그 반영(merge)은 사람이 최종 검토합니다.

on:
schedule:
# 매월 1일 00:00 UTC (한국시간 매월 1일 09:00)
- cron: '0 0 1 * *'
workflow_dispatch:
inputs:
assign_copilot:
description: '생성된 조사 이슈를 Copilot 코딩 에이전트에 배정합니다.'
type: boolean
default: false

permissions:
contents: read
issues: write

jobs:
merger-watch:
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
ISSUE_LABEL: savings-bank-merger-watch
steps:
- uses: actions/checkout@v4

- name: Extract savings bank entries from catalog
id: extract
run: |
set -euo pipefail

# Catalog.xml에서 DisplayName에 "저축은행"이 포함된 Service 항목을 추출합니다.
grep -oP '<Service\s+Id="[^"]*"[^>]*DisplayName="[^"]*저축은행[^"]*"[^>]*Url="[^"]*"' \
docs/Catalog.xml > matches.txt || true

: > entries.md
COUNT=0
while IFS= read -r line; do
ID=$(printf '%s' "$line" | grep -oP 'Id="\K[^"]*' | head -n1 || true)
NAME=$(printf '%s' "$line" | grep -oP 'DisplayName="\K[^"]*' | head -n1 || true)
URL=$(printf '%s' "$line" | grep -oP 'Url="\K[^"]*' | head -n1 || true)
[ -z "$ID" ] && continue
echo "- \`$ID\` — $NAME (<$URL>)" >> entries.md
COUNT=$((COUNT + 1))
done < matches.txt

echo "count=$COUNT" >> "$GITHUB_OUTPUT"
echo "저축은행 항목 $COUNT건을 추출했습니다."

- name: Build research issue body
run: |
set -euo pipefail
PERIOD=$(date -u '+%Y-%m')
echo "period=$PERIOD" >> "$GITHUB_ENV"

{
echo "<!-- savings-bank-merger-watch:${PERIOD} -->"
echo "## 저축은행 통폐합 점검 요청 (${PERIOD})"
echo
echo "저축은행 업계는 인수합병·통폐합·명칭변경이 잦습니다. 이 이슈는 매월 자동 생성되며,"
echo "**AI 에이전트가 최근 업계 뉴스를 조사하여 카탈로그에 반영이 필요한 변경을 식별**하도록 위임합니다."
echo
echo "### AI 에이전트 작업 지침"
echo
echo "1. 아래 카탈로그에 등록된 저축은행 목록을 기준으로, **최근(대략 지난 3~6개월) 국내 저축은행의 통폐합/인수합병/명칭변경/영업정지·폐업** 관련 뉴스를 검색하세요."
echo " - 참고 출처: 금융감독원, 저축은행중앙회(<https://www.fsb.or.kr/>), 주요 경제 뉴스."
echo "2. 확인된 변경 건마다 다음을 정리하세요."
echo " - 대상 기관(현재 카탈로그 \`Id\`/\`DisplayName\`), 변경 유형(통폐합/명칭변경/폐업), 공식 발표·뉴스 **출처 URL**, 시점."
echo " - 카탈로그 반영 방향 제안: \`Url\` 교체 / \`DisplayName\`·\`Id\` 갱신 / 항목 삭제 / 신규 항목 추가."
echo "3. **검증**: 변경 후보 기관의 현재 사이트 접속 상태를 확인하세요."
echo
echo '```bash'
echo "dotnet run --file src/checksites.cs -- probe ./docs/ ./health-report/ --only <id1,id2,...>"
echo '```'
echo
echo "4. 실제 반영이 필요한 건은 이 이슈에 코멘트로 근거(출처 URL 포함)와 함께 제안하고, 승인 후 PR로 처리하세요."
echo " - **자동 삭제 금지**: 폐업·통폐합으로 삭제가 필요한 항목은 반드시 사람의 승인을 받으세요."
echo "5. 조사 결과 반영할 변경이 없으면, 확인한 범위를 코멘트로 남기고 이 이슈를 닫아도 됩니다."
echo
echo "### 현재 카탈로그의 저축은행 목록 (${{ steps.extract.outputs.count }}건)"
echo
if [ -s entries.md ]; then
cat entries.md
else
echo "_(추출된 항목이 없습니다. 추출 로직을 확인하세요.)_"
fi
echo
echo "---"
echo "*generated by \`.github/workflows/savings-bank-merger-watch.yml\`*"
} > issue-body.md

- name: Create research issue (deduplicated per month)
env:
ASSIGN_COPILOT: ${{ github.event.inputs.assign_copilot }}
run: |
set -euo pipefail

gh label create "$ISSUE_LABEL" \
--description "저축은행 통폐합 AI 점검 요청" \
--color D4C5F9 --force >/dev/null 2>&1 || true

# 제목에 해당 연-월(${period})이 포함된 열린 이슈를 찾아 중복 생성을 방지합니다.
EXISTING=$(gh issue list --state open --label "$ISSUE_LABEL" \
--limit 100 --json number,title \
--jq "map(select(.title | contains(\"$period\"))) | .[0].number // empty")

if [ -n "$EXISTING" ]; then
echo "이번 달(${period}) 조사 이슈 #$EXISTING 가 이미 존재합니다. 건너뜁니다."
exit 0
fi

TITLE="[저축은행 통폐합 점검] ${period} — 업계 통폐합 뉴스 조사 요청"
ISSUE_URL=$(gh issue create --title "$TITLE" \
--body-file issue-body.md --label "$ISSUE_LABEL")
echo "생성됨: $ISSUE_URL"

if [ "${ASSIGN_COPILOT:-false}" = "true" ]; then
gh issue edit "$(basename "$ISSUE_URL")" --add-assignee "@copilot" \
|| echo "Copilot 배정에 실패했습니다 (수동 배정이 필요할 수 있습니다)."
fi
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,15 @@ dotnet run .\src\checksites.cs issue .\health-report\<timestamp>\

자동 검출과 사람 판정의 분리, GitHub 이슈 자동 등록, AI 어시스트(Claude Code 등)를 활용한 후속 카탈로그 갱신 방법은 [docs/SITE_HEALTH_WORKFLOW.md](docs/SITE_HEALTH_WORKFLOW.md)를 참고하세요.

#### AI 에이전트 기반 카탈로그 품질 관리 (자동 이슈 등록)

카탈로그 검사 도구에서 발견되는 오류를 GitHub 이슈로 자동 등록하고, AI 에이전트(Copilot 코딩 에이전트·Claude Code 등)의 도움을 받아 해결하는 워크플로가 준비되어 있습니다. 검출은 자동, 최종 판정과 카탈로그 반영(merge)은 사람이 담당합니다.

- **[`.github/workflows/catalog-quality.yml`](.github/workflows/catalog-quality.yml)**: `checkimages.cs`·`catalogutil.cs`를 주기적으로 실행하여 발견된 오류를 하나의 추적 이슈로 등록/갱신하고, 문제가 해소되면 자동으로 닫습니다.
- **[`.github/workflows/savings-bank-merger-watch.yml`](.github/workflows/savings-bank-merger-watch.yml)**: 통폐합이 잦은 저축은행 업계를 대상으로, 매월 AI 에이전트에게 업계 통폐합 뉴스 조사를 위임하는 이슈를 자동 생성합니다.

두 워크플로의 전체 흐름과 AI 에이전트 작업 지침은 [docs/CATALOG_QUALITY_WORKFLOW.md](docs/CATALOG_QUALITY_WORKFLOW.md)를 참고하세요.

#### 제보 인테이크 스킬 (catalog-intake)

GitHub에 익숙하지 않은 사용자를 위한 [Google Forms 제보](https://forms.gle/Pw6pBKhqF1e5Nesw6)를, **검토부터 카탈로그 수용까지 반자동으로 처리**하는 Claude Code 스킬입니다. [.claude/skills/catalog-intake/](.claude/skills/catalog-intake/)에 있으며, 그동안 수작업으로 처리하던 제보 반영을 자동화합니다.
Expand Down
77 changes: 77 additions & 0 deletions docs/CATALOG_QUALITY_WORKFLOW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# AI 에이전트 기반 카탈로그 품질 관리 워크플로

이 문서는 카탈로그 검사 도구에서 발견되는 오류를 GitHub 이슈로 자동 등록하고, AI 에이전트(Copilot 코딩 에이전트 · Claude Code 등)의 도움을 받아 이를 해결하는 절차를 설명합니다. 아울러 통폐합이 잦은 저축은행 업계를 대상으로, AI 에이전트에게 업계 뉴스 조사를 위임하는 워크플로도 함께 다룹니다.

전체 철학은 [사이트 헬스 워크플로](SITE_HEALTH_WORKFLOW.md)와 동일합니다 — **검출(detect)은 자동, 최종 판정과 카탈로그 반영(merge)은 사람**이 합니다. AI 에이전트는 검출·조사·초안 작성을 돕는 도구이지 판결자가 아닙니다.

## 1. 카탈로그 품질 자동 검사 (`catalog-quality.yml`)

카탈로그 검사 도구를 주기적으로 실행하여 발견된 오류를 하나의 추적(tracking) 이슈로 자동 등록/갱신합니다.

### 트리거

- **스케줄**: 매주 월요일 00:00 UTC (한국시간 월요일 09:00)
- **수동 실행**: Actions 탭에서 `workflow_dispatch`
- `assign_copilot` 옵션을 켜면 생성/갱신된 추적 이슈를 Copilot 코딩 에이전트에 배정합니다.
- **푸시**: `docs/Catalog.xml` 또는 `docs/images/**` 변경이 `main`에 반영될 때

### 동작

1. [`checkimages.cs`](../src/checkimages.cs)로 누락/미사용 로고 이미지를 검출합니다. (오프라인, 결정론적)
2. [`catalogutil.cs`](../src/catalogutil.cs)로 XML 스키마 검증 및 URL 접속성 점검을 수행합니다.
3. 두 도구 중 하나라도 문제를 보고하면(비정상 종료 코드), 검사 리포트를 담은 **추적 이슈**를 생성하거나 기존 이슈를 갱신합니다.
4. 문제가 모두 해소되면 열려 있던 추적 이슈를 자동으로 닫습니다.

이슈는 `catalog-quality` 라벨로 관리되며, **열려 있는 추적 이슈는 항상 최대 1건**입니다(중복 등록 방지). 이슈 본문에는 도구 출력 전문과 권장 조치, 재검증 명령이 포함되어 AI 에이전트가 바로 후속 작업에 착수할 수 있습니다.

### AI 에이전트로 해결하기

추적 이슈를 Copilot 코딩 에이전트에 배정하거나, 이슈 본문을 Claude Code에 전달하세요. 이슈 본문의 권장 조치를 따라:

- **누락된 이미지**: 해당 기관 공식 로고를 `docs/images/<Category>/<Id>.png`로 추가 ([`fetchfavicon.cs`](../src/fetchfavicon.cs) 활용).
- **미사용 이미지**: 삭제된 서비스의 잔여 이미지라면 함께 제거.
- **스키마 오류**: `Catalog.xml`을 `Catalog.xsd`에 맞게 수정.

수정 후 재검증:

```bash
dotnet run --file src/checkimages.cs -- ./docs/Catalog.xml ./docs/images
dotnet run --file src/catalogutil.cs -- ./docs/ ./outputs/
```

## 2. 저축은행 통폐합 점검 (`savings-bank-merger-watch.yml`)

저축은행 업계는 인수합병·통폐합·명칭변경·영업정지가 잦습니다. 이 워크플로는 매월 AI 에이전트에게 **"최근 저축은행 통폐합 뉴스"를 조사**하도록 위임하는 이슈를 자동 생성합니다.

### 트리거

- **스케줄**: 매월 1일 00:00 UTC (한국시간 매월 1일 09:00)
- **수동 실행**: Actions 탭에서 `workflow_dispatch` (`assign_copilot` 옵션 지원)

### 동작

1. `Catalog.xml`에서 이름에 "저축은행"이 포함된 서비스 항목을 모두 추출합니다.
2. 추출한 목록과 AI 에이전트 작업 지침을 담은 **조사 요청 이슈**를 생성합니다. (`savings-bank-merger-watch` 라벨)
3. 같은 달에 이미 조사 이슈가 열려 있으면 중복 생성하지 않습니다.

### AI 에이전트의 역할

이슈에 배정된 AI 에이전트는 다음을 수행합니다.

1. 카탈로그의 저축은행 목록을 기준으로 최근(지난 3~6개월) 국내 저축은행 통폐합/인수합병/명칭변경/폐업 뉴스를 검색 (금융감독원, [저축은행중앙회](https://www.fsb.or.kr/), 경제 뉴스 등).
2. 확인된 변경 건마다 대상 기관, 변경 유형, **출처 URL**, 시점, 반영 방향(URL 교체 / 명칭·Id 갱신 / 삭제 / 신규 추가)을 정리.
3. [`checksites.cs`](../src/checksites.cs) `probe`로 대상 사이트 상태를 검증.
4. 근거(출처 URL 포함)와 함께 이슈에 제안하고, 승인 후 PR로 처리.

> **자동 삭제 금지**: 폐업·통폐합으로 항목 삭제가 필요한 경우 반드시 사람의 승인을 받으세요.

## 자동 vs 사람 판정 경계선

| 단계 | 자동 | 사람/승인 필요 |
|------|:---:|:---:|
| 도구 실행 및 문제 검출 | ✓ | |
| 이슈 등록/갱신/종료 | ✓ | |
| 뉴스 조사·초안 작성 (AI) | ✓ | |
| 이미지 추가 (누락 보완) | ✓ | |
| 항목 삭제 / Id 변경 / 통폐합 반영 | | ✓ |
| PR 병합(merge) | | ✓ |