사이트 발행 성공과 Google 색인 관측은 별도 상태다. 외부 API 장애로 발행이 실패하거나 재시작 때 추적 정보가 사라지지 않도록 분리. - Google 클라이언트·배치·DB·Teams 알림 모듈 분리 - 기존 스케줄러 연결, 재시도·중복 실행 방지와 선택 설정 추가 - ORM·초기 DDL·마이그레이션·운영 설정 문서 동시 갱신 검증: 관련 59건 통과, compose 설정·diff 검사 통과. 추가 회귀 23건 통과, 기존 발행 검수 실패 1건은 변경 전 코드에서도 재현. 운영 배포·Google/Teams 실호출 미실행.
100 lines
6.5 KiB
Markdown
100 lines
6.5 KiB
Markdown
# Google Search Console 자동 추적
|
|
|
|
`발행 DB 감지 → 공개 사이트맵 확인/제출 → 색인 조회 → 상태 저장·Teams 알림`
|
|
|
|
## 경계
|
|
|
|
- 기존 API의 스케줄러에서 10분마다 실행한다. 컨테이너 추가 없음.
|
|
- `sites.status=PUBLISHED`인 사이트만 등록하므로 초안/목업 디렉토리 나열을 작업 원장으로 쓰지 않는다.
|
|
- 발행 DB에서 재발견한다. 발행 순간 별도 큐 적재가 실패하는 틈이 없고 재시작해도 이어진다.
|
|
- 발행 트랜잭션/잡과 독립적이다. Google 실패가 사이트 발행을 실패로 바꾸지 않는다.
|
|
- 한 번에 신규 발행 100개 등록, 조회는 오래 기다린 5개 처리. 정상 조회는 24시간 후 반복.
|
|
- 현재 렌더러의 단일 루트 urlset만 지원하고 읽기 상한은 5MB다. 향후 sitemap index 분할 시 확장한다.
|
|
- 오류는 1·2·4·8·16·24시간 간격 재시도. 기본 주기 기준 하루 최대 720회 검사이며,
|
|
다른 도구의 같은 속성 사용량도 Google 할당량에 포함된다. 대량 백로그는 여러 날에 걸쳐 소진한다.
|
|
- PostgreSQL transaction advisory lock으로 다중 API 프로세스의 동시 배치를 막는다.
|
|
단일 배치는 외부 호출 동안 트랜잭션/연결 1개를 점유한다(검사 1건 최대 90초, 최대 5건).
|
|
- 사이트맵 제출 성공과 URL 색인 성공은 별개다. `first_indexed_at`은 **우리가 처음 PASS를 관측한 시각**이다.
|
|
Google 내부 색인 시각이나 최신 발행 버전 반영 시각이 아니다. 원본 `lastCrawlTime`도 함께 보관한다.
|
|
- 재발행 시 해당 발행의 관측 상태를 초기화한다. 지난 관측 이력 전체를 누적하는 이벤트 저장소는 아니다.
|
|
- `SITE_PUBLIC_HOST` 변경은 기존 지침대로 재발행이 필요하다. 사이트 주소의 단일 출처는 `site_payload`다.
|
|
|
|
## 최초 설정 (운영자)
|
|
|
|
1. Search Console에서 발행 도메인의 소유권 확인. URL-prefix 속성이면
|
|
`https://web4ai.o2osolution.ai/`, 도메인 속성이면 `sc-domain:web4ai.o2osolution.ai` 형태.
|
|
2. Google Cloud에서 Search Console API 활성화, 전용 서비스 계정 생성.
|
|
3. Search Console 속성 설정 → 사용자 및 권한에서 그 서비스 계정 이메일에 전체 사용자 권한 부여.
|
|
Google 로그인용 `GOOGLE_CLIENT_ID`와는 다른 인증이다.
|
|
4. 서비스 계정 JSON 키는 **저장소 밖**에 보관한다. 권한을 최소화하고 git/이미지/로그에 넣지 않는다.
|
|
5. 루트 `.env` 설정:
|
|
|
|
```dotenv
|
|
GSC_ENABLED=1
|
|
GSC_PROPERTY_URL=https://web4ai.o2osolution.ai/
|
|
GSC_CREDENTIALS_HOST_FILE=/secure/location/search-console.json
|
|
GSC_ALERT_DAYS=7
|
|
GSC_ALERT_WEBHOOK_URL=
|
|
```
|
|
|
|
키 생성/권한 부여/실제 알림 전송은 구현 검증 중 자동 수행하지 않는다.
|
|
|
|
## 배포
|
|
|
|
먼저 새 이미지에 requirements를 설치하고 `0014_search_console.sql`을 기존 마이그레이션 도구로 적용한다.
|
|
프로젝트 전체 마이그레이션 순서를 확인한 뒤 실행한다. 아래는 운영자가 실행할 명령이며 자동 배포하지 않았다.
|
|
|
|
```bash
|
|
docker compose exec -T solution-backend python scripts/migrate.py
|
|
docker compose -f docker-compose.yml -f docker-compose.search-console.yml up -d --build solution-backend
|
|
```
|
|
|
|
선택 compose 파일은 API에만 키를 읽기 전용 마운트하고 `GSC_CREDENTIALS_FILE`을 설정한다.
|
|
없는 파일을 디렉토리로 자동 생성하지 않는다. 이후 배포에서도 이 override를 함께 사용해야 한다.
|
|
로컬 Python 실행은 `GSC_CREDENTIALS_FILE`에 로컬 키 파일 경로를 지정한다.
|
|
켜진 스케줄러는 첫 10분 주기부터 기존 발행 사이트도 등록한다. `GSC_ENABLED=0`이면 DB/Google 호출 모두 생략한다.
|
|
|
|
## 알림
|
|
|
|
Teams Workflows의 webhook 수신 → 채널에 Adaptive Card 게시 흐름 URL을
|
|
`GSC_ALERT_WEBHOOK_URL`에 넣는다. 비우면 외부 전송 없이 경고 로그/DB만 남는다.
|
|
API/사이트맵 오류 또는 발행 후 기본 7일 미색인 시 알린다. 성공한 알림은 사이트별 24시간 중복 억제.
|
|
전송 실패는 `alerted_at`을 갱신하지 않아 다음 검사 때 재시도한다.
|
|
외부 전송 후 DB commit 전에 죽으면 중복 알림이 가능하다(at-least-once).
|
|
키·토큰·webhook URL·Google 오류 본문은 알림에 포함하지 않는다.
|
|
|
|
## 결과 확인
|
|
|
|
```bash
|
|
docker compose exec -T solution-backend python scripts/search_console_status.py
|
|
```
|
|
|
|
읽기 전용이며 Google API를 추가 호출하지 않는다. 프론트 화면/API 계약은 변경하지 않았다.
|
|
|
|
| 파일 | 책임 |
|
|
|---|---|
|
|
| `services/search_console_client.py` | 인증·Google HTTP·오류 정규화 |
|
|
| `services/search_console_settings.py` | 선택 설정·속성 URL 범위 |
|
|
| `services/search_console_service.py` | 배치 흐름·재시도·관측 결과 |
|
|
| `crud/search_console_crud.py` | 발행 감지·등록·조회 순서·동시 실행 잠금 |
|
|
| `services/search_console_alerts.py` | 알림 조건·Teams 전송 |
|
|
|
|
## 구글 지원 범위 / 남은 운영 작업
|
|
|
|
- [사이트맵 제출 API](https://developers.google.com/webmaster-tools/v1/sitemaps/submit)는 지원된다.
|
|
- [URL Inspection API](https://developers.google.com/webmaster-tools/v1/urlInspection.index/inspect)는
|
|
Google이 이미 알고 있는 상태 조회용이며 실시간 페이지 테스트나 색인 요청 API가 아니다.
|
|
- 일반 숙박 사이트는 [Indexing API](https://developers.google.com/search/apis/indexing-api/v3/using-api) 대상이 아니다.
|
|
- [검사 할당량](https://developers.google.com/webmaster-tools/limits)은 속성당 하루 2,000회다.
|
|
- [Teams webhook 형식](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook).
|
|
- 실제 서비스 계정 권한/사이트맵 제출/색인 관측/Teams 수신은 설정 후 운영 검증이 필요하다.
|
|
- 기존 루트 사이트맵의 백업 URL 정리와 IndexNow 개별 사이트맵 참조 문제는 이 기능과 별도다.
|
|
이 기능은 기존 공개 사이트맵을 제출하며 내용을 다시 만들거나 목업을 삭제하지 않는다.
|
|
|
|
## 구현 검증 (2026-09-15)
|
|
|
|
- 격리 PostgreSQL에서 클라이언트·배치·스키마·IndexNow 관련 59건 통과.
|
|
- 발행·설정·사이트 목록 회귀검사: 23건 통과, `test_unverified_fact_blocks_publish` 1건 실패.
|
|
해당 실패는 변경 전 HEAD `9773bc0`의 발행 코드에서도 동일 재현됨(GSC 비활성).
|
|
- Google/Teams 실호출 없음. 서비스 계정 권한·실제 제출·채널 수신은 운영 설정 후 검증 대상.
|