logo
홈블로그소개
4,206

Built with Next.js, Bun, Tailwind CSS and Shadcn/UI

·개인정보처리방침
Github

GSC 자동화 리포팅 체계 구축

Toma
2026년 7월 15일
약 14분
목차
🧾 GSC 검색 실적 → Teams 자동 리포팅 구축
1. 🎯 이 자동화는 무엇을 하는가?
2. 🔗 webhook이란?
Incoming Webhook의 의미
3. 🕰️ 기존 Teams Incoming Webhook(O365 Connector)
4. ⚙️ Power Automate Workflow란?
5. 🔍 기존 Incoming Webhook과 Power Automate Workflow의 차이
6. 🤔 왜 Power Automate Workflow를 선택했는가?
7. 🛠️ 실제 Power Automate 설정 방법
7-1. Flow 생성
7-2. 누가 Flow를 호출할 수 있는지 설정
7-3. Teams 게시 액션 추가
8. 🃏 MessageCard와 Adaptive Card
MessageCard
Adaptive Card
9. 📊 GSC 스크립트는 무엇을 하는가?
10. 🐙 GitHub Actions 설정
11. 🧪 curl로 webhook을 테스트하는 방법
12. 🚑 이번 작업에서 발생한 문제와 해결
12-1. DirectApiAuthorizationRequired
12-2. ApiVersionInvalid
12-3. 401 AuthenticationFailed
12-4. curl: (2) no URL specified
12-5. 카드 게시 액션에 메시지 ID가 나타남
13. 🔑 OAuth는 언제 쓰는가?
14. 📋 운영 시 기억할 점
이전 포스트타입 안전한 i18next 다국어 처리: 스키마에서 컴파일 타임 키 검증까지

목차

🧾 GSC 검색 실적 → Teams 자동 리포팅 구축
1. 🎯 이 자동화는 무엇을 하는가?
2. 🔗 webhook이란?
Incoming Webhook의 의미
3. 🕰️ 기존 Teams Incoming Webhook(O365 Connector)
4. ⚙️ Power Automate Workflow란?
5. 🔍 기존 Incoming Webhook과 Power Automate Workflow의 차이
6. 🤔 왜 Power Automate Workflow를 선택했는가?
7. 🛠️ 실제 Power Automate 설정 방법
7-1. Flow 생성
7-2. 누가 Flow를 호출할 수 있는지 설정
7-3. Teams 게시 액션 추가
8. 🃏 MessageCard와 Adaptive Card
MessageCard
Adaptive Card
9. 📊 GSC 스크립트는 무엇을 하는가?
10. 🐙 GitHub Actions 설정
11. 🧪 curl로 webhook을 테스트하는 방법
12. 🚑 이번 작업에서 발생한 문제와 해결
12-1. DirectApiAuthorizationRequired
12-2. ApiVersionInvalid
12-3. 401 AuthenticationFailed
12-4. curl: (2) no URL specified
12-5. 카드 게시 액션에 메시지 ID가 나타남
13. 🔑 OAuth는 언제 쓰는가?
14. 📋 운영 시 기억할 점

🧾 GSC 검색 실적 → Teams 자동 리포팅 구축

📌 매일 정해진 시간에 GitHub Actions가 Google Search Console 실적을 가져와 Teams 채널에 카드로 자동 게시합니다. 이 글은 그 파이프라인을 만들며 부딪힌 webhook·인증 문제와 해결 과정을 정리합니다.

1. 🎯 이 자동화는 무엇을 하는가?

매일 정해진 시간에 GitHub Actions가 실행됩니다. 실행된 스크립트는 Google Search Console(GSC)에서 검색 성과를 가져와 Teams의 GSC 리포트 채널에 카드 형태로 올립니다.

plain
GitHub Actions
  → GSC API 호출
  → 노출·클릭·CTR·평균순위 계산
  → Teams용 카드 JSON 생성
  → Power Automate webhook URL에 POST
  → Teams 채널에 카드 게시

현재 구현 파일은 다음과 같습니다.

  • scripts/gsc-report.mjs — GSC 조회와 카드 생성·전송
  • .github/workflows/gsc-report.yml — 매일 실행하는 GitHub Actions 워크플로우

2. 🔗 webhook이란?

Webhook은 **"어떤 이벤트가 발생했을 때, 정해진 URL로 HTTP 요청을 보내는 방식"**입니다.

일반적인 API 호출은 클라이언트가 "새 소식 있나요?"라고 서버에 물어보는 구조입니다.

plain
클라이언트 → 서버
"새 데이터 있나요?"

Webhook은 반대입니다. 이벤트가 발생한 시스템이 미리 등록된 URL로 먼저 알려줍니다.

plain
이벤트 발생 시스템 → webhook URL
"새 데이터가 생겼습니다."

이번 자동화에서는 GitHub Actions의 Node 스크립트가 발신자입니다. 매일 GSC 데이터를 계산한 뒤 Teams 알림을 위한 webhook URL에 POST 요청을 보냅니다.

plain
Node 스크립트 → Power Automate webhook URL

Incoming Webhook의 의미

Teams 입장에서 외부 시스템이 Teams 안으로 메시지를 넣는 것이므로 Incoming Webhook이라고 합니다.

반대로 Teams 사용자가 메시지를 보내면 외부 시스템이 반응하는 형태는 Outgoing Webhook이라고 부르지만, 이번 자동화와는 관계없습니다.


3. 🕰️ 기존 Teams Incoming Webhook(O365 Connector)

기존 방식은 Teams 채널에 Incoming Webhook Connector를 추가하고 URL 하나를 받는 방식입니다.

plain
Node 스크립트
  → Teams Incoming Webhook URL
  → Teams 채널

장점은 단순합니다.

  • URL에 JSON을 POST하면 바로 채널에 게시
  • 별도의 Flow 구성 불필요
  • MessageCard 형식을 많이 사용

⚠️ 하지만 Microsoft 365/O365 Connector 기반 Incoming Webhook은 앞으로 신규 구현의 기반으로 쓰기 적합하지 않습니다. Microsoft는 Teams 알림 자동화의 대체 경로로 Workflows/Power Automate 사용을 안내합니다. Microsoft Teams Incoming Webhook 문서


4. ⚙️ Power Automate Workflow란?

Power Automate는 Microsoft의 업무 자동화 서비스입니다. 여러 시스템의 이벤트를 받아 조건 처리, 데이터 변환, 메시지 전송 같은 작업을 연결할 수 있습니다.

이번 구성에서 Power Automate는 "중간 전달자" 역할을 합니다.

plain
GSC 리포트 스크립트
  → Power Automate Flow
  → Teams GSC 리포트 채널

이번 Flow는 두 단계로 이루어집니다.

  1. Teams 웹후크 요청이 수신된 경우 — 외부에서 JSON POST를 받는 시작점
  2. 채팅 또는 채널에서 카드 게시 — 전달받은 카드를 Teams의 지정 채널에 게시

즉, Power Automate는 "외부 데이터 수신 → Teams 카드 게시"를 담당합니다.


5. 🔍 기존 Incoming Webhook과 Power Automate Workflow의 차이

항목기존 Incoming WebhookPower Automate Workflow
Microsoft 구성 요소O365/M365 ConnectorPower Automate + Teams
구조외부 시스템이 Teams로 직접 POST외부 시스템 → Flow → Teams
메시지 형식주로 MessageCardAdaptive Card 권장
데이터 가공·분기거의 불가조건, 변환, 승인, 다중 채널 전송 가능
인증 설정URL 보유자가 호출익명/테넌트/특정 사용자 선택 가능
운영 관리채널 Connector 중심Flow 소유자·공동 소유자 중심
선택 이유단순하지만 은퇴 대상Microsoft의 현재 대체 경로

💡 Power Automate는 단순한 "새 URL"이 아니라, webhook을 트리거로 사용하는 자동화 Flow입니다.


6. 🤔 왜 Power Automate Workflow를 선택했는가?

이번 요구사항에는 Power Automate가 가장 자연스럽습니다.

  • Microsoft 공식 대체 경로다.
  • 서드파티 Webhook Bot을 추가하지 않아도 된다.
  • GSC 리포트를 특정 Teams 채널로 보낼 수 있다.
  • 향후 조건을 넣기 쉽다.
    • 클릭 수 급감 시 강조
    • 특정 요일에만 주간 요약 발송
    • 실패 시 별도 운영 채널 알림
  • 카드 형식과 게시 위치를 Flow에서 관리할 수 있다.

✅ 따라서 현재 구조는 **"Teams Connector 은퇴 대응 + Microsoft 1st-party만 사용"**이라는 제약에 맞습니다.


7. 🛠️ 실제 Power Automate 설정 방법

7-1. Flow 생성

Power Automate에서 자동화된 클라우드 Flow를 만들고 트리거를 추가합니다.

Teams 웹후크 요청이 수신된 경우

7-2. 누가 Flow를 호출할 수 있는지 설정

트리거의 **"누가 흐름을 트리거할 수 있나요?"**에는 다음 선택지가 있습니다.

선택지의미GitHub Actions에 적합한가
내 테넌트의 모든 사용자회사 Microsoft 계정 OAuth 필요아니오
내 테넌트의 특정 사용자지정 사용자/서비스 주체 OAuth 필요아니오
모든 사용자URL만으로 POST 가능예

이번 자동화는 세 번째 모든 사용자를 선택했습니다.

🔐 여기서 "모든 사용자"는 URL을 아는 시스템이 POST할 수 있다는 뜻입니다. 따라서 webhook URL은 GitHub Secret에 저장하고 코드·문서·채팅에 노출하지 않는 것이 원칙입니다.

Teams webhook 트리거는 호출자를 누구나, 테넌트 사용자, 특정 사용자로 제한할 수 있습니다. Teams 커넥터 문서

7-3. Teams 게시 액션 추가

다음 액션을 추가합니다.

채팅 또는 채널에서 카드 게시

설정값:

plain
게시자:    Flow bot
게시 위치: 채널
팀:        Technology
채널:      GSC 리포트
카드:      첨부 파일 적응형 카드

첨부 파일 적응형 카드를 선택하면 Power Automate는 받은 카드 배열을 하나씩 처리하도록 For each를 자동 생성할 수 있습니다.


8. 🃏 MessageCard와 Adaptive Card

MessageCard

기존 O365 Incoming Webhook에서 많이 쓰던 카드 형식입니다.

json
{
  "@type": "MessageCard",
  "summary": "GSC 일일 리포트"
}

기존 GSC 스크립트도 처음에는 MessageCard를 만들었습니다.

Adaptive Card

Teams와 Power Automate에서 권장되는 범용 카드 형식입니다.

json
{
  "type": "AdaptiveCard",
  "version": "1.4",
  "body": []
}

이번 Flow의 트리거와 카드 게시 액션이 Adaptive Card attachment를 중심으로 동작하므로, GSC 스크립트도 Adaptive Card 형식으로 변경했습니다.

현재 scripts/gsc-report.mjs는 다음 구조를 만듭니다.

plain
Webhook 요청
  └─ attachments
      └─ Adaptive Card
          ├─ 리포트 제목
          ├─ 기준일
          └─ FactSet
              ├─ 노출수
              ├─ 클릭수
              ├─ CTR
              └─ 평균순위

9. 📊 GSC 스크립트는 무엇을 하는가?

scripts/gsc-report.mjs의 역할은 네 가지입니다.

  1. GSC 서비스 계정으로 인증
  2. Search Analytics API에서 일별 성과 조회
  3. 기준일과 전일의 수치를 비교
  4. Adaptive Card를 만들고 Power Automate webhook으로 전송

⏱️ GSC 데이터는 실시간 데이터가 아닙니다. 그래서 스크립트는 안전하게 실행일 기준 3일 전을 기준일로 잡습니다.

plain
오늘:        7월 15일
리포트 기준일: 7월 12일
비교일:       7월 11일

10. 🐙 GitHub Actions 설정

GitHub Actions는 .github/workflows/gsc-report.yml의 cron에 따라 실행됩니다.

필요한 GitHub Repository Secret은 아래 2개 입니다.

  • GSC_SA_KEY : GCP 서비스 계정 생성 시 다운로드 받은 JSON 키 파일
  • GSC_TEAMS_WEBHOOK_URL : Power Automate Flow의 HTTP POST URL 문자열

11. 🧪 curl로 webhook을 테스트하는 방법

GitHub Actions를 실행하기 전에 curl로 webhook 연결을 먼저 검증했습니다.

성공한 요청은 아래와 같은 형태입니다.

bash
curl -i -X POST \
  'https://.../invoke?api-version=2024-10-01&sp=...&sv=1.0&sig=...' \
  -H 'Content-Type: application/json' \
  --data '{
    "type": "message",
    "attachments": [
      {
        "contentType": "application/vnd.microsoft.card.adaptive",
        "contentUrl": null,
        "content": {
          "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
          "type": "AdaptiveCard",
          "version": "1.4",
          "body": [
            {
              "type": "TextBlock",
              "text": "GSC webhook 테스트 성공"
            }
          ]
        }
      }
    ]
  }'

성공 시 HTTP 응답은 다음과 같습니다.

plain
HTTP/2 202

💡 202 Accepted는 Power Automate가 요청을 접수했고 Flow 실행을 시작했다는 뜻입니다. Teams 카드 게시까지 완료됐는지는 채널 또는 Flow 실행 기록에서 확인합니다.


12. 🚑 이번 작업에서 발생한 문제와 해결

12-1. DirectApiAuthorizationRequired

plain
OAuth authorization scheme is required

원인

  • 처음 만든 Flow가 "내 테넌트의 특정 사용자" 설정이었음
  • 익명 curl에는 OAuth 토큰이 없음

해결

  • 트리거 설정을 세 번째 **"모든 사용자"**로 변경
  • URL만으로 POST 가능한 Flow 구성

12-2. ApiVersionInvalid

plain
API version must be specified...

원인

  • 생성된 URL의 api-version=1이 현재 endpoint에서 지원되지 않음

해결

plain
api-version=2024-10-01

으로 변경했습니다.

12-3. 401 AuthenticationFailed

plain
missing or empty Authorization header

처음에는 익명 호출 설정 문제로 보였지만, 실제 원인은 curl URL의 잘못된 이스케이프였습니다.

잘못된 예:

bash
'https://...?api-version=2024-10-01&sp\=...&sig\=...'

⚠️ 작은따옴표 안의 백슬래시(\)는 shell에서 제거되지 않고 URL에 그대로 포함됩니다. 따라서 sp, sv, sig 파라미터 이름이 손상됩니다.

올바른 예:

bash
'https://...?api-version=2024-10-01&sp=...&sv=1.0&sig=...'

작은따옴표로 URL 전체를 감쌌다면 ?, =, & 앞에 백슬래시를 붙이지 않습니다.

12-4. curl: (2) no URL specified

원인

bash
curl -i -X POST
'https://...'

처럼 POST 뒤에서 줄바꿈해 명령이 끝난 경우입니다.

해결

bash
curl -i -X POST \
  'https://...' \

처럼 줄 끝에 \를 넣어 같은 명령으로 연결합니다.

12-5. 카드 게시 액션에 메시지 ID가 나타남

원인

  • 새 카드를 게시하는 액션이 아니라 기존 카드를 수정하는 액션을 선택함

해결

"채팅 또는 채널에서 카드 게시" 액션을 선택합니다. 새 카드 게시 액션에는 기존 메시지 ID가 필요하지 않습니다.


13. 🔑 OAuth는 언제 쓰는가?

현재처럼 익명 webhook이 허용되면 OAuth는 필요 없습니다.

다만 보안 정책상 "모든 사용자"를 사용할 수 없는 회사 환경이라면 OAuth를 사용합니다.

plain
GitHub Actions
  → Entra ID에서 access token 발급
  → Authorization: Bearer <token>
  → Power Automate Flow

이때 Flow는 "내 테넌트의 특정 사용자"로 만들고, Entra 서비스 주체의 Object ID를 허용 사용자로 등록합니다. Power Automate는 이 시나리오를 지원합니다. Power Automate OAuth 트리거 문서

✅ 이번 구성에서는 익명 webhook 호출이 실제로 202와 Teams 카드 표시까지 성공했으므로 OAuth는 사용하지 않습니다.


14. 📋 운영 시 기억할 점

🗒️ - webhook URL은 비밀번호처럼 다룬다.

  • URL을 GitHub Secret에만 저장한다.

  • 202은 요청 접수 성공이고, 카드 게시 실패 여부는 Power Automate 실행 기록에서 확인한다.

  • GSC 데이터는 2~3일 늦게 확정되는 것이 정상이다.

  • Flow는 개인 계정에 연결될 수 있으므로, 운영 담당자를 공동 소유자로 추가하는 것을 권장한다.

  • Teams 카드 형식은 향후에도 Adaptive Card를 기준으로 유지한다.