전체 활용 사례

// 업종별 — 그대로 따라가는 시나리오

회계법인 — 다중 클라이언트 matrix 수집

매월 1일 N개 클라이언트 자료를 matrix 로 병렬 수집, 클라이언트별 디렉터리로 분리해 한 PR.

GitHub Actions매월 1일 06:00 KST

이런 분께 월말 마감용 자료를 클라이언트별로 받아둬야 하는 세무사무소.

Openclients/2026-04

clients-monthly · 2026-04 · 12 clients

  • clients/client-a/2026-04/
  • clients/client-b/2026-04/
  • clients/_summary.md

01사전 점검

아래 명령을 그대로 붙여넣어 지금 내 환경이 준비됐는지 확인한다.

  • repo secret H6S_API_KEY 가 등록돼 있다

    gh secret list

    목록에 H6S_API_KEY 가 보인다

    아니면 — gh secret set H6S_API_KEY # 또는 repo Settings → Secrets

  • 워크스페이스에 대상 자격증명이 있다

    h6s credentials list

    그 기관에 매칭되는 자격증명이 1건 이상 보인다

    아니면 — h6s credentials create --interactive --cert

  • Actions 가 PR 을 만들 수 있다

    repo Settings → Actions → General → Workflow permissions

    "Read and write" + "Allow GitHub Actions to create pull requests" 체크

    아니면 — 두 옵션을 켠다 (yml 의 permissions 블록만으로도 동작하지만 repo 설정이 우선).

  • 클라이언트별 API Key secret 이 등록돼 있다

    gh secret list

    H6S_API_KEY_CLIENT_A · _B · _C … 가 보인다

    아니면 — 각 클라이언트 워크스페이스의 API Key 를 secret 으로 등록(워크스페이스=클라이언트).

02실행

아래 파일을 .github/workflows/ 에 저장하고 기본 브랜치에 commit. 첫 검증은 Actions 탭 → Run workflow 로 수동 트리거.

yaml
# 회계법인이 매월 1일에 N개 클라이언트 자료를 matrix 로 병렬 수집해
# 클라이언트별 디렉터리로 정리한 한 PR 을 만든다.
# 각 클라이언트는 별도 워크스페이스 = 별도 API Key. secrets 에 클라이언트별로 등록.
name: 회계법인 다중 클라이언트 월말 수집

on:
  schedule:
    - cron: '0 21 1 * *'   # 매월 1일 21:00 UTC = 다음날 KST 06:00
  workflow_dispatch: {}

jobs:
  fetch:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    strategy:
      fail-fast: false
      matrix:
        client:
          - { code: client-a, api_key_secret: H6S_API_KEY_CLIENT_A }
          - { code: client-b, api_key_secret: H6S_API_KEY_CLIENT_B }
          - { code: client-c, api_key_secret: H6S_API_KEY_CLIENT_C }
    steps:
      - uses: actions/checkout@v6

      - id: prev-month
        run: echo "value=$(date -u -d '1 month ago' +%Y-%m)" >> "$GITHUB_OUTPUT"

      - id: fetch-bank
        uses: bolta-io/h6s-action@v0
        with:
          api-key: ${{ secrets[matrix.client.api_key_secret] }}
          schema: bank.transactions.cb.v1
          provider: CB_KB
          month: ${{ steps.prev-month.outputs.value }}
          output-path: ./clients/${{ matrix.client.code }}/${{ steps.prev-month.outputs.value }}/bank/

      - id: fetch-sales
        uses: bolta-io/h6s-action@v0
        with:
          api-key: ${{ secrets[matrix.client.api_key_secret] }}
          schema: hometax.tax-invoices.sales.v1
          provider: HOMETAX
          month: ${{ steps.prev-month.outputs.value }}
          output-path: ./clients/${{ matrix.client.code }}/${{ steps.prev-month.outputs.value }}/tax/

      - id: fetch-purchase
        uses: bolta-io/h6s-action@v0
        with:
          api-key: ${{ secrets[matrix.client.api_key_secret] }}
          schema: hometax.tax-invoices.purchase.v1
          provider: HOMETAX
          month: ${{ steps.prev-month.outputs.value }}
          output-path: ./clients/${{ matrix.client.code }}/${{ steps.prev-month.outputs.value }}/tax/

      - uses: actions/upload-artifact@v4
        with:
          name: clients-${{ matrix.client.code }}-${{ steps.prev-month.outputs.value }}
          path: ./clients/${{ matrix.client.code }}/${{ steps.prev-month.outputs.value }}/
          retention-days: 30

  merge-pr:
    needs: fetch
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    steps:
      - uses: actions/checkout@v6

      - id: prev-month
        run: echo "value=$(date -u -d '1 month ago' +%Y-%m)" >> "$GITHUB_OUTPUT"

      - uses: actions/download-artifact@v4
        with:
          path: ./clients/

      - uses: peter-evans/create-pull-request@v6
        with:
          title: 'clients-monthly · ${{ steps.prev-month.outputs.value }}'
          body: |
            자동 생성. 클라이언트별 디렉터리에 월별 자료 (입출금 + 매출/매입 세금계산서).

            기간: ${{ steps.prev-month.outputs.value }}
          branch: clients/${{ steps.prev-month.outputs.value }}
          commit-message: 'chore(clients): ${{ steps.prev-month.outputs.value }} 일괄 수집'
          add-paths: clients/

matrix.client 에 {code, api_key_secret} 한 줄만 추가하면 클라이언트 N배 확장.

03검증

  • Actions 에서 클라이언트 수만큼 fetch job 이 (일부 실패해도) 끝나고 merge-pr 초록.
  • clients/<월> 브랜치 PR 에 client-a/ client-b/ … 디렉터리별 자료가 모인다.
  • 한 클라이언트 자격증명 누락 시 그 job 만 실패.

04흔한 에러

워크플로우는 초록인데 PR 이 안 생긴다

Actions 의 PR 생성 권한이 막혀 있거나 변경 파일이 없다(중복 실행).

해결 repo Settings → Actions 에서 PR 생성 허용. 같은 기간 재실행이면 정상.

fetch step 에서 NO_API_KEY 로 실패

secret 이름이 yml 의 secrets.H6S_API_KEY 와 다르다.

해결 secret 을 정확히 H6S_API_KEY 로 등록.

CREDENTIAL_INSUFFICIENT_FOR_PROVIDER

그 provider 에 매칭되는 자격증명이 워크스페이스에 없다.

해결 h6s credentials create --interactive --cert (공동인증서 1개로 전 기관 공용).

cron 시간이 지나도 안 돈다

yml 이 기본 브랜치에 없거나, repo 가 60일 비활성이라 scheduled workflow 가 멈췄다.

해결 기본 브랜치에 머지하고, 가끔 수동 트리거해 활성 유지.

05변형

같은 사례에서 자주 바꾸는 옵션. 다른 사례는 아래 이전/다음에서.

클라이언트 추가

yaml
- { code: client-d, api_key_secret: H6S_API_KEY_CLIENT_D }

현금영수증까지

yaml
- id: fetch-cash
        uses: bolta-io/h6s-action@v0
        with:
          api-key: ${{ secrets[matrix.client.api_key_secret] }}
          schema: hometax.cash-receipts.sales.v1
          provider: HOMETAX
          month: ${{ steps.prev-month.outputs.value }}
다음SaaS 스타트업 — 캐시 사이클 자연어 요약