catalog-intake 스킬 추가: Google Forms 제보 검토·수용 자동화 + README 문서화#131
Merged
Conversation
Google Forms 제보를 검토·수용까지 반자동 처리하는 catalog-intake 스킬 (.claude/skills/catalog-intake/)을 추가한다. 그동안 수작업이던 제보 반영을 자동화. - normalize_csv.py: 제보 CSV → 카탈로그 스키마 정규화, Id 파생/충돌 검사, gap 플래그 - check_urls.py: 설치 URL을 Windows Edge로 위장해 생존/파일명 확인 (봇 차단 우회) - fetch_logo.py: 공식 로고 → 배경 투명 정사각 PNG - SKILL.md: pull→정규화→검증→PR 오케스트레이션. 결과 3분류(완전반영/미완-추적이슈/중복제외) - references/field-mapping.md: 폼→스키마 매핑, 설치기·사일런트 스위치 시드표 README.md의 카탈로그 품질 관리 도구 절에 스킬 사용법을 문서화. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Google Forms로 접수된 “식탁보 사이트 추가/수정/삭제 요청” 제보를 CSV로 받아 정규화 → URL 확인(Edge UA 스푸핑) → 로고 생성 → 검증/PR 후보 생성까지 반자동으로 처리하는 catalog-intake Claude Code 스킬을 추가하고, 사용법을 README에 문서화합니다. 기존 수작업 제보 반영 흐름을 site-health 워크플로 철학(자동 처리 + 사람 최종 판정)으로 일관되게 확장하는 변경입니다.
Changes:
catalog-intake스킬 오케스트레이션 문서(SKILL.md) 및 폼→스키마 매핑/시드표 문서 추가- CSV 정규화, URL 생존/파일명 확인(Edge 헤더), 로고 자동 수집/투명 정사각 PNG 변환 스크립트 추가
- README에 제보 인테이크 스킬 개요/절차/참고 링크 추가
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | catalog-intake 스킬 목적/처리 단계/참고 문서를 사용자에게 안내 |
| .claude/skills/catalog-intake/SKILL.md | intake 파이프라인, 안전 경계선, 사람/자동 경계, 실행 커맨드 정의 |
| .claude/skills/catalog-intake/scripts/normalize_csv.py | Google Forms CSV를 스키마 친화 JSON으로 정규화하고 gap 플래그를 산출 |
| .claude/skills/catalog-intake/scripts/check_urls.py | Edge UA/Client Hints로 보안 플러그인 URL의 생존/리다이렉트/파일명/콘텐츠 타입 확인 |
| .claude/skills/catalog-intake/scripts/fetch_logo.py | 사이트에서 로고 후보를 수집해 배경 투명화 + 정사각 PNG로 변환 |
| .claude/skills/catalog-intake/references/field-mapping.md | 폼 필드 매핑, Category 매핑, gap 의미, 설치기 시드표 문서화 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+173
to
+186
| display_name_en = get("display_name_en") | ||
| category_ko = get("category_ko") | ||
| category = CATEGORY_MAP.get(category_ko, "Other") | ||
| package_urls = split_package_urls(get("package_urls")) | ||
| id_suggested = derive_id(display_name_en) | ||
|
|
||
| gaps: list[str] = [] | ||
| # 폼은 사일런트 스위치를 받지 않으므로 항상 조사 필요 | ||
| if package_urls: | ||
| gaps.append("arguments-missing") | ||
| gaps.append("package-name-derive") | ||
| if category_ko in CATEGORY_NEEDS_DECISION: | ||
| gaps.append("category-needs-decision") | ||
| id_collision = bool(id_suggested and id_suggested in existing_ids) |
Comment on lines
+101
to
+121
| try: | ||
| # HEAD 우선(가벼움). 일부 서버는 HEAD 미지원 → Range GET 으로 폴백. | ||
| resp = client.head(url, follow_redirects=True) | ||
| if resp.status_code >= 400 or resp.status_code == 405: | ||
| resp = client.get(url, follow_redirects=True, | ||
| headers={"Range": "bytes=0-0"}) | ||
| except httpx.HTTPError as exc: | ||
| result["error"] = f"{type(exc).__name__}: {exc}" | ||
| return result | ||
|
|
||
| cd = resp.headers.get("content-disposition") | ||
| result.update({ | ||
| "ok": resp.status_code < 400, | ||
| "status": resp.status_code, | ||
| "final_url": str(resp.url), | ||
| "redirected": str(resp.url) != url, | ||
| "content_type": resp.headers.get("content-type", ""), | ||
| "content_length": resp.headers.get("content-length", ""), | ||
| "filename": filename_from(str(resp.url), cd), | ||
| }) | ||
| return result |
Comment on lines
+77
to
+82
| for info in infos: | ||
| ip = ipaddress.ip_address(info[4][0]) | ||
| if (ip.is_private or ip.is_loopback or ip.is_link_local | ||
| or ip.is_reserved or ip.is_multicast): | ||
| return False, f"blocked-ip: {ip}" | ||
| return True, "ok" |
Comment on lines
+255
to
+256
| out = trim_and_square(im, args.size) | ||
| out.save(args.output, format="PNG", optimize=True) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
요약
GitHub에 익숙하지 않은 사용자를 위한 Google Forms 제보를 검토부터 카탈로그 수용까지 반자동으로 처리하는 Claude Code 스킬
catalog-intake를 추가하고,README.md에 문서화합니다. 그동안 수작업이던 제보 반영을 자동화합니다.구성 (
.claude/skills/catalog-intake/)SKILL.mdscripts/normalize_csv.pyscripts/check_urls.pyscripts/fetch_logo.pyreferences/field-mapping.md처리 철학 (site-health 워크플로 계승)
검출·정규화는 자동, 최종 판정과 merge는 사람. 결과는 3분류로만 정리하며, "수동 확인 필요"를 이유로 조용히 드롭하지 않습니다.
검증됨
src/checksites.cs(Playwright Edge 131)와 동일하게 맞춤.참고
uv run <script>시 의존성이 자동 설치됩니다.🤖 Generated with Claude Code