# CI/CD設計書

## 1. ドキュメント情報

| 項目           | 内容                                       |
| -------------- | ------------------------------------------ |
| ドキュメント名 | CI/CD設計書                                |
| プロジェクト名 | パーソナル技術ブログシステム (blog-modern) |
| バージョン     | 1.0.0                                      |
| 作成日         | 2026-03-02                                 |
| 作成者         | インフラチーム                             |
| ステータス     | 正式版                                     |

### 変更履歴

| バージョン | 日付       | 変更者         | 変更内容 |
| ---------- | ---------- | -------------- | -------- |
| 1.0.0      | 2026-03-02 | インフラチーム | 初版作成 |

---

## 2. CI/CDパイプライン概要

### 2.1 システム構成概要

本システムは、Astro フレームワークで構築されたブログサイト（blog-modern）を GitHub Actions でビルドし、Cloudflare Pages に自動デプロイする CI/CD パイプラインと、AI による記事自動生成ワークフローで構成される。

GitHub リポジトリは **private** である（ソースコードは非公開で運用する方針）。公開サイトは Cloudflare Pages（`https://dawneel.lacue.uk/blog-modern/`）から配信されるため、リポジトリ可視性は公開サイトに影響しない。

**技術スタック:**

| コンポーネント               | 技術                                               | バージョン |
| ---------------------------- | -------------------------------------------------- | ---------- |
| 静的サイトジェネレータ       | Astro                                              | 5.17.x     |
| CSSフレームワーク            | Tailwind CSS                                       | 4.2.x      |
| ランタイム                   | Node.js                                            | 22.x       |
| CI/CDプラットフォーム        | GitHub Actions                                     | -          |
| ホスティング                 | Cloudflare Pages（プロジェクト: dawneel-blog）     | -          |
| デプロイCLI                  | Wrangler                                           | 4.x        |
| 検索インデックス生成         | Pagefind                                           | 最新       |
| AI記事生成（プライマリ）     | Claude Code CLI (claude-opus-4-8)                  | 最新       |
| AI記事生成（フォールバック） | Claude API (claude-opus-4-8) / OpenAI API (gpt-4o) | -          |
| スクリプト実行               | tsx                                                | -          |

### 2.2 パイプライン全体フロー

```mermaid
flowchart TD
    subgraph trigger_push["push トリガー"]
        A1["開発者がコードをPush<br/>(blog-modern/** 変更)"]
        A2[workflow_dispatch]
        A3["cron: 毎日 03:00 JST<br/>(予約記事の自動公開ビルド)"]
    end

    subgraph trigger_schedule["スケジュールトリガー"]
        B1["cron: 毎月1日・15日 03:00 JST<br/>(前日18:00 UTC 起動 + JST日付ガード)"]
        B2[workflow_dispatch]
    end

    subgraph deploy_pipeline["デプロイパイプライン (deploy.yml)"]
        C1[Checkout]
        C2[Setup Node.js 22]
        C3["npm ci"]
        C4["Astro Build"]
        C5["Pagefind インデックス生成"]
        C6["_site/ へ配置<br/>(ルートは /blog-modern/ へリダイレクト)"]
        C7["wrangler pages deploy<br/>→ Cloudflare Pages"]
    end

    subgraph ai_pipeline["AI自動投稿パイプライン (ai-auto-post.yml)"]
        D1[Checkout]
        D2[Setup Node.js 22]
        D3[Install tsx]
        D4[トピック選定]
        D5[AI記事生成]
        D5b["AI自動校閲<br/>(FAIL→再生成1回 / 再FAIL→draft保存)"]
        D6[Markdownファイル出力]
        D7[Git Commit & Push]
        D8[gh workflow run deploy.yml]
    end

    A1 -->|paths filter| C1
    A2 --> C1
    A3 --> C1
    C1 --> C2 --> C3 --> C4 --> C5 --> C6 --> C7

    B1 --> D1
    B2 --> D1
    D1 --> D2 --> D3 --> D4 --> D5 --> D5b --> D6 --> D7 --> D8

    D8 -->|"明示 dispatch<br/>(GITHUB_TOKEN の push では<br/>push トリガーが発火しないため)"| C1

    subgraph manual_post["手動投稿 (Claude Code)"]
        E1["Claude Code との対話で記事作成 (draft)"]
        E2["ユーザーレビュー・承認"]
        E3["draft: false でコミット & プッシュ<br/>(未来の pubDate = 予約投稿)"]
    end

    E1 --> E2 --> E3
    E3 -->|"push トリガー<br/>(運営者の push は通常どおり発火)"| C1

    style deploy_pipeline fill:#e8f5e9,stroke:#4caf50
    style ai_pipeline fill:#e3f2fd,stroke:#2196f3
    style manual_post fill:#fff3e0,stroke:#ff9800
    style trigger_push fill:#f3e5f5,stroke:#9c27b0
    style trigger_schedule fill:#fce4ec,stroke:#e91e63
```

### 2.3 デプロイフロー概念図

```mermaid
flowchart LR
    subgraph sources["ソースコード"]
        S1[blog-modern/]
    end

    subgraph github["GitHub (private リポジトリ)"]
        G1[main ブランチ]
        G2[GitHub Actions]
    end

    subgraph cloudflare["Cloudflare"]
        CF["Cloudflare Pages<br/>(dawneel-blog)<br/>https://dawneel.lacue.uk"]
    end

    S1 --> G1
    G1 -->|push event / workflow_dispatch| G2
    G2 -->|wrangler pages deploy| CF
```

---

## 3. ワークフロー一覧

| No. | ワークフロー名 | ファイル                             | トリガー                                                     | 概要                                                                          |
| --- | -------------- | ------------------------------------ | ------------------------------------------------------------ | ----------------------------------------------------------------------------- |
| 1   | Deploy Blogs   | `.github/workflows/deploy.yml`       | `push` (main, blog-modern/\*\* または配布用設計書の変更時) / `schedule` (毎日 03:00 JST) / `workflow_dispatch` | ブログをビルドし、Pagefind インデックスを生成して Cloudflare Pages へデプロイ。定期実行は予約記事の自動公開を兼ねる |
| 2   | AI Auto Post   | `.github/workflows/ai-auto-post.yml` | `schedule` (毎月1日・15日 03:00 JST) / `workflow_dispatch`   | AIで記事を自動生成してコミットし、デプロイを明示起動                          |

### ワークフロー間の依存関係

```mermaid
flowchart LR
    W2["AI Auto Post"] -->|"gh workflow run deploy.yml<br/>(明示 dispatch)"| W1["Deploy Blogs"]

    style W1 fill:#e8f5e9,stroke:#4caf50
    style W2 fill:#e3f2fd,stroke:#2196f3
```

AI Auto Post ワークフローが記事をコミット＆プッシュした後、`gh workflow run deploy.yml` により Deploy Blogs ワークフローを明示的に起動する。**`GITHUB_TOKEN` による push は他ワークフローの push トリガーを発火しない**（GitHub Actions の無限連鎖防止の仕様）ため、push だけではデプロイが自動起動しないことへの対応である。

---

## 4. デプロイワークフロー詳細（deploy.yml）

### 4.1 トリガー条件

```yaml
on:
  push:
    branches: [main]
    paths:
      - "blog-modern/**"
      - "docs/basic-design.md"
      - "docs/cicd-design.md"
  schedule:
    - cron: "0 18 * * *"
  workflow_dispatch:
```

| 条件         | 説明                                                                                             |
| ------------ | ------------------------------------------------------------------------------------------------ |
| ブランチ     | `main` ブランチへの push のみ                                                                    |
| パスフィルタ | `blog-modern/**` 配下または配布用設計書 (docs/) に変更がある場合に実行                                          |
| 定期実行     | 毎日 18:00 UTC (03:00 JST)。予約投稿 (未来の pubDate を持つ公開待ち記事) を日付到来時に自動公開するための再ビルド |
| 手動実行     | `workflow_dispatch` により GitHub UI から手動実行可能。AI Auto Post からの明示 dispatch にも使用 |

### 4.2 ジョブ構成

単一の `build-deploy` ジョブで、ビルドからデプロイまでを一気通貫で実行する。

| ジョブ名       | 実行環境        | 依存ジョブ | 説明                                                                                                          |
| -------------- | --------------- | ---------- | ------------------------------------------------------------------------------------------------------------- |
| `build-deploy` | `ubuntu-latest` | なし       | チェックアウト、依存関係インストール、ビルド、検索インデックス生成、サイト統合、Cloudflare Pages へのデプロイ |

### 4.3 ステップ詳細

| No. | ステップ名                          | アクション / コマンド                                                               | 説明                                                                                              |
| --- | ----------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| 1   | Checkout                            | `actions/checkout@v4`                                                               | リポジトリのソースコードをチェックアウト                                                          |
| 2   | Setup Node.js                       | `actions/setup-node@v4`                                                             | Node.js 22 のセットアップ                                                                         |
| 3   | Install blog-modern dependencies    | `npm ci`（working-directory: blog-modern）                                          | 依存関係を厳密インストール                                                                        |
| 4   | Build blog-modern                   | `npm run build`（working-directory: blog-modern）                                   | Astro による静的サイトビルド。出力先は `blog-modern/dist/`                                        |
| 5   | Index blog-modern search (Pagefind) | `npx --yes pagefind --site dist`（working-directory: blog-modern）                  | `dist/pagefind/` に全文検索インデックスを生成                                                     |
| 6   | Combine outputs                     | `cp -r` による `_site/` への配置                                                    | `dist/` を `_site/blog-modern/` へコピーし、ルートに `/blog-modern/` へのリダイレクト HTML を生成。配布用設計書 (docs/ 原本) を `downloads/` へコピー |
| 7   | Deploy to Cloudflare Pages          | `npx --yes wrangler@4 pages deploy _site --project-name=dawneel-blog --branch=main` | `_site/` 全体を Cloudflare Pages プロジェクト `dawneel-blog` へデプロイ                           |

### 4.4 環境設定

**パーミッション:**

```yaml
permissions:
  contents: read # リポジトリ読み取りのみ（デプロイはリポジトリへ書き込まない）
```

デプロイはリポジトリへの書き込みを行わないため、`contents: read` のみの最小権限とする。

**同時実行制御:**

```yaml
concurrency:
  group: pages
  cancel-in-progress: true
```

| 設定             | 値      | 説明                                                                       |
| ---------------- | ------- | -------------------------------------------------------------------------- |
| グループ名       | `pages` | 同一グループの実行は直列化される                                           |
| 実行中キャンセル | `true`  | 新しい実行が開始されると、進行中の実行をキャンセルし常に最新コミットを配信 |

**Cloudflare 認証（環境変数）:**

```yaml
env:
  CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
  CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
```

### 4.5 サイト統合と公開URL

Combine outputs ステップでビルド成果物を配信用のサイトツリーに配置する。

```bash
mkdir -p _site/blog-modern
cp -r blog-modern/dist/* _site/blog-modern/
# Root redirect to blog-modern
cat > _site/index.html << 'HEREDOC'
<!DOCTYPE html>
<html>
<head><meta http-equiv="refresh" content="0;url=/blog-modern/"></head>
<body><a href="/blog-modern/">Go to Blog</a></body>
</html>
HEREDOC
# 配布用設計書は docs/ の原本を単一ソースとしてデプロイ時にコピーする
cp docs/basic-design.md docs/cicd-design.md _site/blog-modern/downloads/
```

| パス            | 内容                                                  |
| --------------- | ----------------------------------------------------- |
| `/`             | `/blog-modern/` へのリダイレクト                      |
| `/blog-modern/` | ブログ本体（`https://dawneel.lacue.uk/blog-modern/`） |
| `/blog-modern/downloads/*.md` | 配布用設計書 (docs/ 原本のコピー) |

### 4.6 Astro ビルド設定

`blog-modern/astro.config.mjs` における主要設定:

| 設定項目               | 設定値                             |
| ---------------------- | ---------------------------------- |
| `site`                 | `https://dawneel.lacue.uk`         |
| `base`                 | `/blog-modern`                     |
| インテグレーション     | MDX, Sitemap                       |
| CSS                    | Tailwind CSS 4 (Vite プラグイン)   |
| シンタックスハイライト | Shiki (github-light / github-dark) |

---

## 5. AI自動投稿ワークフロー詳細（ai-auto-post.yml）

### 5.1 ワークフロー概要

AI Auto Post ワークフローは、スケジュールまたは手動トリガーにより Claude Code CLI (フォールバック: Claude API / OpenAI API) でブログ記事を自動生成する。生成した記事をコミット・プッシュした後、`gh workflow run deploy.yml` で Deploy Blogs ワークフローを明示的に起動して公開する。

### 5.2 スケジュール設定

```yaml
schedule:
  - cron: "0 18 14,28,29,30,31 * *"
```

| 項目         | 値                              | 説明                                                       |
| ------------ | ------------------------------- | ---------------------------------------------------------- |
| cron 式      | `0 18 14,28,29,30,31 * *`       | UTC 18:00（JST 翌日 03:00）に候補日すべてで起動            |
| 実行日       | 毎月 1日、15日（JST）           | 起動後に JST 日付を判定し、1日・15日以外は即スキップ       |
| タイムゾーン | UTC（GitHub Actions 標準）      | JST 03:00 に相当                                           |

> **注意:** GitHub Actions の cron スケジュールは UTC 基準で定義される。JST 03:00 は前日の UTC 18:00 にあたり、cron 式では「月末日」を表現できないため、15日の前日 (14日) と 1日の前日 (28〜31日) すべてで起動して実行時の JST 日付ガードで判定する方式を取る。深夜 03:00 の実行は、サブスクリプションの利用枠を運営者が使用しない時間帯に充てる意図である。また、GitHub Actions のスケジュール実行は負荷状況により数分〜数十分の遅延が発生する場合がある。

### 5.3 手動トリガー（workflow_dispatch）

GitHub UI（または `gh workflow run`）から手動実行できる。主なパラメータは以下の通り。

| パラメータ | 型     | 必須 | デフォルト | 説明                                                |
| ---------- | ------ | ---- | ---------- | --------------------------------------------------- |
| `topic`    | string | No   | （空文字） | 記事トピック。空の場合は `topics.json` から自動選択 |
| `provider` | choice | Yes  | `claude-cli` | AI プロバイダ。`claude-cli` / `claude` / `openai`  |
| `dry_run`  | boolean | No  | `false`    | 記事生成のみ行いコミット・公開しない検証モード      |

### 5.4 ジョブ構成

| ジョブ名   | 実行環境        | 説明                                                   |
| ---------- | --------------- | ------------------------------------------------------ |
| `generate` | `ubuntu-latest` | 記事生成、コミット、プッシュ、デプロイ起動を一連で実行 |

**パーミッション:**

```yaml
permissions:
  contents: write # コミット & プッシュに必要
  # Needed to dispatch the deploy workflow after committing a new post
  actions: write
```

### 5.5 ステップ詳細

| No. | ステップ名      | アクション / コマンド                         | 説明                                                                          |
| --- | --------------- | --------------------------------------------- | ----------------------------------------------------------------------------- |
| 1   | Checkout        | `actions/checkout@v4`                         | リポジトリをチェックアウト                                                    |
| 2   | Setup Node.js   | `actions/setup-node@v4`                       | Node.js 22 をセットアップ                                                     |
| 3   | Install tsx     | `npm install -g tsx`                          | TypeScript 実行ランタイム（tsx）をグローバルインストール                      |
| 4   | Generate post   | `tsx scripts/generate-post.ts`                | AI API を呼び出して記事を生成（詳細は 5.6 参照）                              |
| 5   | Commit and push | `git commit` / `git push` / `gh workflow run` | 生成記事をコミット・プッシュし、deploy.yml を明示 dispatch（詳細は 5.7 参照） |

### 5.6 AI記事生成プロセス

記事生成スクリプト `scripts/generate-post.ts` の処理フローを以下に示す。

```mermaid
flowchart TD
    START[開始] --> PARSE[引数パース]
    PARSE --> MODE{自動モード?}

    MODE -->|--auto| TOPIC_AUTO[topics.json から<br/>未使用トピックを選択]
    MODE -->|--topic 指定| TOPIC_MANUAL[指定トピックを使用]

    TOPIC_AUTO --> CHECK{未使用トピック<br/>あり?}
    CHECK -->|なし| EXIT_OK[正常終了<br/>No unused topics]
    CHECK -->|あり| BUILD_PROMPT[プロンプト構築]

    TOPIC_MANUAL --> BUILD_PROMPT

    BUILD_PROMPT --> CALL_API[AI API 呼び出し<br/>Primary Provider]
    CALL_API --> API_OK{成功?}
    API_OK -->|Yes| GEN_META[メタデータ生成<br/>frontmatter / slug]
    API_OK -->|No| FALLBACK[フォールバック<br/>AI API 呼び出し]
    FALLBACK --> FALLBACK_OK{成功?}
    FALLBACK_OK -->|Yes| GEN_META
    FALLBACK_OK -->|No| EXIT_ERR[エラー終了<br/>process.exit 1]

    GEN_META --> WRITE_FILE[Markdownファイル書き出し]
    WRITE_FILE --> MARK_USED{自動モード?}
    MARK_USED -->|Yes| UPDATE_JSON[topics.json の<br/>used フラグ更新]
    MARK_USED -->|No| DONE[完了]
    UPDATE_JSON --> DONE

    style EXIT_ERR fill:#ffcdd2,stroke:#e53935
    style EXIT_OK fill:#fff9c4,stroke:#f9a825
    style DONE fill:#c8e6c9,stroke:#388e3c
```

#### 5.6.1 トピック管理

トピックは `scripts/topics.json` で管理される。

**データ構造:**

```typescript
interface Topic {
  title: string; // 記事タイトル
  category: string; // カテゴリ（AI入門、入門、技術解説 等）
  tags: string[]; // タグ配列
  audience: string; // 対象読者
  used: boolean; // 使用済みフラグ
}
```

**自動選択ロジック:**

1. `topics.json` を読み込む
2. `used: false` のトピックをフィルタリング
3. 最初の未使用トピックを選択（配列順）
4. 記事生成後、当該トピックの `used` を `true` に更新

**登録済みトピック（初期状態）:**

| No. | タイトル                                                      | カテゴリ | 対象読者                 |
| --- | ------------------------------------------------------------- | -------- | ------------------------ |
| 1   | 【新卒向け】生成AIとは？ChatGPTからClaude Codeまで            | AI入門   | IT未経験の新卒エンジニア |
| 2   | 【新卒向け】GitHubの使い方 - 初めてのバージョン管理           | 入門     | IT未経験の新卒エンジニア |
| 3   | 【新卒向け】プログラミング学習ロードマップ2026                | AI入門   | IT未経験の新卒エンジニア |
| 4   | Markdown完全ガイド - エンジニアの文書術                       | 技術解説 | 若手エンジニア           |
| 5   | 【新卒向け】AIを使った効率的な学習方法                        | AI入門   | IT未経験の新卒エンジニア |
| 6   | 【新卒向け】コマンドライン入門 - ターミナルの基本操作         | 入門     | IT未経験の新卒エンジニア |
| 7   | GitHub Copilotで変わるコーディング - AIペアプログラミング入門 | AI入門   | 若手エンジニア           |
| 8   | 【新卒向け】API入門 - Webサービスの仕組みを理解する           | 入門     | IT未経験の新卒エンジニア |
| 9   | Docker入門 - コンテナ技術の基礎を学ぶ                         | 技術解説 | 若手エンジニア           |
| 10  | CI/CD入門 - GitHub Actionsで始める自動化                      | 技術解説 | 若手エンジニア           |

※ 初期登録分。トピックは運用に合わせて随時追加・消費される。

#### 5.6.2 AI API 呼び出し

**プロンプト構成:**

```
You are a technical blog writer. Write a blog post in Japanese about "{topic}".

Requirements:
- Target audience: {audience}
- Category: {category}
- Write in a friendly, educational tone
- Include code examples where appropriate
- Use Markdown with proper headings (## for H2, ### for H3)
- Include a practical "まとめ" (summary) section at the end
- Total length: 1500-2500 characters
- Do NOT include frontmatter (---) - just the article body starting from ## はじめに
```

**API エンドポイント:**

| プロバイダ         | エンドポイント                               | モデル            | 最大トークン |
| ------------------ | -------------------------------------------- | ----------------- | ------------ |
| Claude Code CLI    | （`claude -p` によるヘッドレス実行 / サブスクリプション認証） | `claude-opus-4-8` | -            |
| Claude (Anthropic) | `https://api.anthropic.com/v1/messages`      | `claude-opus-4-8` | 10000        |
| OpenAI             | `https://api.openai.com/v1/chat/completions` | `gpt-4o`          | 4096         |

#### 5.6.3 記事出力形式

**Frontmatter:**

```yaml
---
title: "{トピックタイトル}"
description: "{本文先頭120文字からの抜粋}"
pubDate: YYYY-MM-DD
tags: ["tag1", "tag2", ...]
category: "{カテゴリ}"
draft: false
aiGenerated: true
---
```

**ファイル命名規則:**

- パス: `blog-modern/src/content/blog/{slug}.md`
- slug: `{YYYYMMDD}-{hash}` （日付 + タイトルハッシュ値の Base36 表現先頭6文字）

### 5.7 コミット & プッシュ & デプロイ起動

```yaml
- name: Commit and push
  env:
    GH_TOKEN: ${{ github.token }}
  run: |
    git config user.name "AI Auto Post"
    git config user.email "ai-bot@users.noreply.github.com"
    git add -A
    if git diff --staged --quiet; then
      echo "No changes to commit"
    else
      git commit -m "feat: auto-generated blog post [ai-post]"
      git push
      # Pushes made with GITHUB_TOKEN never fire the push trigger of
      # other workflows, so dispatch the deploy workflow explicitly
      # (workflow_dispatch is exempt from that restriction).
      gh workflow run deploy.yml --ref main
    fi
```

| 項目               | 値                                         | 説明                                             |
| ------------------ | ------------------------------------------ | ------------------------------------------------ |
| コミッター名       | `AI Auto Post`                             | bot 用のユーザー名                               |
| コミッターメール   | `ai-bot@users.noreply.github.com`          | bot 用のメールアドレス                           |
| コミットメッセージ | `feat: auto-generated blog post [ai-post]` | Conventional Commits 準拠                        |
| 空コミット防止     | `git diff --staged --quiet`                | 変更がない場合はコミット・デプロイ起動をスキップ |
| デプロイ起動       | `gh workflow run deploy.yml --ref main`    | Deploy Blogs ワークフローを明示的に dispatch     |

**デプロイ起動の設計判断:**

GitHub Actions では、ワークフローの無限連鎖を防ぐため、`GITHUB_TOKEN` を用いた push は他のワークフローの `push` トリガーを発火しない。本システムのデプロイは push トリガーで起動する設計のため、AI Auto Post からの push だけではデプロイが自動起動しない。この制約への対応として、push 後に `gh workflow run deploy.yml --ref main` を実行して明示的に dispatch する（`workflow_dispatch` はこの制約の対象外）。このために `permissions.actions: write` を付与している。この明示 dispatch ステップは削除禁止である。

### 5.8 フォールバック戦略

AI 記事生成におけるフォールバック処理を以下に示す。

```mermaid
flowchart TD
    START[AI API 呼び出し開始] --> PRIMARY[プライマリプロバイダで生成]
    PRIMARY --> P_OK{成功?}
    P_OK -->|Yes| SUCCESS[記事生成完了]
    P_OK -->|No| LOG_WARN[警告ログ出力<br/>Trying fallback...]
    LOG_WARN --> FALLBACK[フォールバックプロバイダで生成]
    FALLBACK --> F_OK{成功?}
    F_OK -->|Yes| SUCCESS
    F_OK -->|No| ERROR[エラー終了<br/>process.exit 1]

    style SUCCESS fill:#c8e6c9,stroke:#388e3c
    style ERROR fill:#ffcdd2,stroke:#e53935
    style LOG_WARN fill:#fff9c4,stroke:#f9a825
```

指定プロバイダを先頭に、残りを `claude-cli` → `claude` → `openai` の固定順で試行する。

| プライマリ設定 | フォールバック順                  |
| -------------- | --------------------------------- |
| `claude-cli`   | `claude` → `openai`               |
| `claude`       | `claude-cli` → `openai`           |
| `openai`       | `claude-cli` → `claude`           |

フォールバック発生時のログ出力例:

```
[generate-post] claude failed: Claude API error: 429 {...}. Trying fallback...
```

フォールバックも失敗した場合、スクリプトは `process.exit(1)` で終了し、GitHub Actions ワークフローは失敗ステータスとなる。

### 5.9 自動校閲ゲート

生成された記事は、コミット前に別の AI 呼び出しによる校閲を通す。品質が基準に達しない記事が深夜の無人実行でそのまま公開されることを防ぐ仕組みである。

| 項目       | 内容                                                                                 |
| ---------- | ------------------------------------------------------------------------------------ |
| 判定基準   | 文体（です・ます調）/ 書き出し / 概念先行の構成 / 用語定義 / 分量 / まとめの有無     |
| 出力形式   | 指摘の箇条書きを先に列挙し、最終行で `VERDICT: PASS` / `VERDICT: FAIL` を判定        |
| FAIL 時    | 指摘内容をプロンプトに添えて1回だけ再生成し、再校閲する                              |
| 再 FAIL 時 | `draft: true` で保存する（公開判定によりサイトには出ず、人手レビュー待ちとなる）    |
| 校閲障害時 | フェイルオープン（判定不能・理由なしの FAIL は PASS 扱いとし、公開を妨げない）      |

---

## 6. 手動投稿（Claude Code連携）

### 6.1 概要

手動枠の記事は、Claude Code との対話フローで作成し、必ず運営者のレビューを通す。レビュー通過後は `draft: false` かつ公開予定日の `pubDate` を設定してコミットする（予約投稿）。未来日付の記事はビルド対象から除外されるため即座には公開されず、毎日 03:00 JST の定期ビルドが日付到来時に自動公開する。

### 6.2 手動投稿フロー

```mermaid
sequenceDiagram
    actor Dev as 運営者
    participant CC as Claude Code
    participant FS as ファイルシステム
    participant Git as Git / GitHub
    participant CF as Cloudflare Pages

    Dev->>CC: 記事の作成・修正を指示
    CC->>FS: 記事生成・保存<br/>blog-modern/src/content/blog/
    Dev->>CC: レビュー・修正指示 → 承認
    CC->>Git: draft: false でコミット & プッシュ<br/>(pubDate = 公開予定日)
    Git-->>Git: 未来日付の記事はビルド除外<br/>毎日 03:00 JST の定期ビルドが日付到来で公開
    Git->>CF: wrangler pages deploy
    CC->>Dev: 完了報告<br/>ファイルパス・タイトル・タグ・デプロイ予定
```

> **補足:** 運営者自身の push は `GITHUB_TOKEN` によるものではないため、push トリガーが通常どおり発火する。明示 dispatch が必要なのは AI Auto Post ワークフローのみである。

### 6.3 生成記事フォーマット

```markdown
---
title: "記事タイトル"
description: "記事の説明（100-150文字）"
pubDate: YYYY-MM-DD
tags: ["tag1", "tag2", "tag3"]
category: "カテゴリ名"
draft: false
aiGenerated: false
---

## はじめに

（導入文）

## 本文セクション

（内容）

## まとめ

（まとめ）
```

※ 手動投稿（運営者執筆）の記事は `aiGenerated: false` とし、AI Generated バッジを表示しない。

### 6.4 AI自動投稿との比較

| 項目               | AI Auto Post（GitHub Actions）                         | 手動投稿（Claude Code）      |
| ------------------ | ------------------------------------------------------ | ---------------------------- |
| 実行環境           | GitHub Actions ランナー                                | ローカル開発環境             |
| トリガー           | スケジュール / workflow_dispatch                       | 運営者の対話指示             |
| AI プロバイダ      | Claude Code CLI（フォールバック: Claude / OpenAI API） | Claude Code 自体             |
| トピック選定       | topics.json / 手動入力                                 | 運営者との対話で決定         |
| レビュー           | AI 自動校閲（FAIL 時は再生成 → 再 FAIL は draft 退避）                                       | 運営者が確認後に承認（必須） |
| デプロイ起動       | `gh workflow run` による明示 dispatch                  | push トリガーで自動          |
| コミットメッセージ | 定型文                                                 | コンテキストに応じた内容     |
| 用途               | 定期的な自動投稿                                       | 任意のタイミングでの手動投稿 |

---

## 7. ブランチ戦略

### 7.1 ブランチ運用方針

本プロジェクトでは、シンプルさを重視した **main ブランチ直接運用** を基本方針とする。

```mermaid
gitgraph
    commit id: "initial"
    commit id: "feat: blog post"
    branch feature/new-layout
    commit id: "WIP: layout"
    commit id: "fix: responsive"
    checkout main
    merge feature/new-layout id: "merge"
    commit id: "feat: ai post [ai-post]"
    commit id: "feat: ai post [ai-post] " type: HIGHLIGHT
```

### 7.2 ブランチ種別

| ブランチ    | 用途                           | 保護ルール    |
| ----------- | ------------------------------ | ------------- |
| `main`      | 本番デプロイ対象。直接 push 可 | デプロイ対象  |
| `feature/*` | 新機能開発（任意）             | PR マージ推奨 |
| `fix/*`     | バグ修正（任意）               | PR マージ推奨 |

### 7.3 運用上の考慮事項

- AI Auto Post ワークフローは `main` ブランチに直接コミット・プッシュする
- Claude Code からの手動投稿も `main` ブランチに直接プッシュする（公開は運営者レビュー通過後のみ）
- サイト構造やテンプレートの変更など、影響範囲が大きい変更は feature ブランチでの作業を推奨
- PR 前には lint、typecheck、test を通すこと（プロジェクト規約準拠）

---

## 8. シークレット管理

### 8.1 GitHub Secrets 一覧

| シークレット名            | 用途                                               | 使用ワークフロー | 必須                                              |
| ------------------------- | -------------------------------------------------- | ---------------- | ------------------------------------------------- |
| `CLOUDFLARE_API_TOKEN`    | Cloudflare Pages デプロイ認証                      | Deploy Blogs     | Yes                                               |
| `CLOUDFLARE_ACCOUNT_ID`   | Cloudflare アカウント識別子                        | Deploy Blogs     | Yes                                               |
| `CLAUDE_CODE_OAUTH_TOKEN` | Claude Code CLI 認証トークン（サブスクリプション） | AI Auto Post     | Yes（claude-cli プロバイダ使用時）                |
| `ANTHROPIC_API_KEY`       | Claude API 認証キー                                | AI Auto Post     | Yes（claude プロバイダ使用時 / フォールバック用） |
| `OPENAI_API_KEY`          | OpenAI API 認証キー                                | AI Auto Post     | Yes（openai プロバイダ使用時 / フォールバック用） |

### 8.2 シークレット設定箇所

GitHub リポジトリの `Settings` > `Secrets and variables` > `Actions` に設定する。

### 8.3 シークレットの参照方法

```yaml
env:
  CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
  CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
```

### 8.4 セキュリティ上の注意事項

| 項目                   | 対応方針                                                                                      |
| ---------------------- | --------------------------------------------------------------------------------------------- |
| シークレットのログ出力 | GitHub Actions はシークレット値を自動マスクする                                               |
| フォーク先での実行     | フォークリポジトリからの PR ではシークレットにアクセスできない                                |
| ローテーション         | API キーは定期的にローテーションすることを推奨                                                |
| 最小権限               | Cloudflare API トークンは Pages 編集権限のみを付与し、GitHub Secrets 以外の場所には保存しない |

### 8.5 Cloudflare API トークン

デプロイワークフローは Cloudflare API トークンで認証する。トークンは Cloudflare Pages の編集権限のみを付与した専用トークンとし、GitHub Secrets にのみ保存する。デプロイがリポジトリ外部（Cloudflare）への書き込みで完結するため、ワークフロー側の GitHub 権限は `contents: read` のみで足りる。

---

## 9. 監視・通知

### 9.1 GitHub Actions 標準通知

GitHub Actions の標準機能により、以下のタイミングで通知が送信される。

| イベント         | 通知先                    | 条件             |
| ---------------- | ------------------------- | ---------------- |
| ワークフロー失敗 | リポジトリ Watch ユーザー | デフォルトで有効 |

### 9.2 通知設定

GitHub リポジトリの `Settings` > `Actions` > `Notifications` で以下を設定する:

- **ワークフロー失敗時の通知**: リポジトリ管理者のメールアドレスに送信
- **通知頻度**: 各ワークフロー失敗時に即座に通知

### 9.3 監視対象項目

| 監視項目                            | 確認方法                                 | 確認頻度       |
| ----------------------------------- | ---------------------------------------- | -------------- |
| デプロイワークフロー成功率          | GitHub Actions ダッシュボード            | Push 毎        |
| AI Auto Post 実行状況               | GitHub Actions ダッシュボード            | 毎月 1日・15日 |
| topics.json の残りトピック数        | リポジトリ内ファイル確認                 | 月次           |
| API キー・トークンの有効期限        | 各プロバイダ / Cloudflare の管理画面     | 月次           |
| Cloudflare Pages デプロイステータス | Cloudflare ダッシュボード（Deployments） | デプロイ毎     |

### 9.4 ログ確認

各ワークフロー実行のログは、GitHub リポジトリの `Actions` タブから確認可能。AI Auto Post ワークフローのログには以下の情報が出力される:

```
[generate-post] blog=modern, auto=true, provider=claude
[generate-post] Auto-selected topic: "【新卒向け】生成AIとは？ChatGPTからClaude Codeまで"
[generate-post] Calling claude API...
[generate-post] Created: /path/to/blog-modern/src/content/blog/20260301-abc123.md
[generate-post] Marked topic "【新卒向け】生成AIとは？ChatGPTからClaude Codeまで" as used.
```

---

## 10. 障害対応

### 10.1 障害分類と対応手順

#### 10.1.1 ビルド失敗

```mermaid
flowchart TD
    FAIL[ビルド失敗] --> CHECK_LOG[Actions ログ確認]
    CHECK_LOG --> TYPE{失敗原因}

    TYPE -->|依存関係エラー| FIX_DEP["package-lock.json 更新<br/>npm ci 再実行"]
    TYPE -->|TypeScriptエラー| FIX_TS["型エラー修正<br/>ローカルで npm run build 確認"]
    TYPE -->|Astroエラー| FIX_ASTRO["Astro 設定確認<br/>コンテンツファイル検証"]
    TYPE -->|Node.jsバージョン| FIX_NODE["ワークフローの<br/>node-version 確認"]

    FIX_DEP --> PUSH[修正をコミット & プッシュ]
    FIX_TS --> PUSH
    FIX_ASTRO --> PUSH
    FIX_NODE --> PUSH
    PUSH --> VERIFY[再実行を確認]
```

| 失敗パターン       | 想定原因                                       | 対応手順                                                                   |
| ------------------ | ---------------------------------------------- | -------------------------------------------------------------------------- |
| `npm ci` 失敗      | `package-lock.json` と `package.json` の不整合 | ローカルで `npm install` を実行し `package-lock.json` を再生成してコミット |
| Astro ビルドエラー | 不正な Markdown / frontmatter                  | エラーログで対象ファイルを特定し、frontmatter の YAML 構文を修正           |
| メモリ不足         | ランナーのメモリ制限超過                       | `NODE_OPTIONS=--max-old-space-size=4096` を環境変数に追加                  |

#### 10.1.2 デプロイ失敗（Cloudflare Pages）

| 失敗パターン        | 想定原因                                                    | 対応手順                                                                                |
| ------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| wrangler 認証エラー | `CLOUDFLARE_API_TOKEN` の無効化・権限不足                   | トークンを再発行（Pages 編集権限のみ）し、GitHub Secrets を更新                         |
| アカウントエラー    | `CLOUDFLARE_ACCOUNT_ID` の誤り                              | Cloudflare ダッシュボードでアカウント ID を確認し、GitHub Secrets を更新                |
| プロジェクト未検出  | `--project-name` と Cloudflare Pages プロジェクト名の不一致 | プロジェクト名（`dawneel-blog`）を Cloudflare ダッシュボードで確認                      |
| 同時実行競合        | 複数デプロイの衝突                                          | `concurrency`（cancel-in-progress: true）により自動解消。頻発する場合は push 頻度を調整 |

**手動再デプロイ手順:**

1. GitHub リポジトリの `Actions` タブを開く
2. `Deploy Blogs` ワークフローを選択
3. `Run workflow` ボタンから `main` ブランチを指定して手動実行

#### 10.1.3 AI API 失敗

```mermaid
flowchart TD
    FAIL[AI API 呼び出し失敗] --> TYPE{エラー種別}

    TYPE -->|401 Unauthorized| AUTH["API キー確認<br/>GitHub Secrets 再設定"]
    TYPE -->|429 Rate Limit| RATE["レート制限到達<br/>フォールバックで自動リトライ"]
    TYPE -->|500 Server Error| SERVER["プロバイダ側障害<br/>フォールバックで自動リトライ"]
    TYPE -->|Network Error| NET["ネットワーク障害<br/>GitHub Actions ランナー<br/>の問題を確認"]
    TYPE -->|Both Failed| BOTH["両プロバイダ失敗<br/>手動対応"]

    RATE --> FALLBACK[フォールバック<br/>プロバイダで再試行]
    SERVER --> FALLBACK

    AUTH --> FIX_KEY[API キーを再発行<br/>GitHub Secrets 更新]
    NET --> RETRY[ワークフロー手動再実行]
    BOTH --> MANUAL[手動で記事作成<br/>or 次回スケジュール待ち]

    style BOTH fill:#ffcdd2,stroke:#e53935
    style MANUAL fill:#fff9c4,stroke:#f9a825
```

| 失敗パターン        | 想定原因                           | 自動対応                               | 手動対応                           |
| ------------------- | ---------------------------------- | -------------------------------------- | ---------------------------------- |
| プライマリ API 失敗 | レート制限 / サーバーエラー        | フォールバックプロバイダで自動リトライ | -                                  |
| 両 API 失敗         | 全プロバイダ障害 / キー無効        | なし（`exit 1`）                       | API キー確認後、手動再実行         |
| トピック枯渇        | `topics.json` の全トピック使用済み | 正常終了（`exit 0`、コミットなし）     | `topics.json` に新規トピックを追加 |

#### 10.1.4 コミット & プッシュ & デプロイ起動失敗

| 失敗パターン   | 想定原因                                                | 対応手順                                                                                    |
| -------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| push 拒否      | ブランチ保護ルール                                      | リポジトリ Settings でブランチ保護ルールを確認。bot ユーザーに push 権限を付与              |
| コンフリクト   | 同時実行による競合                                      | `concurrency` 設定の確認。必要に応じて `cancel-in-progress` を調整                          |
| 認証失敗       | `GITHUB_TOKEN` の権限不足                               | ワークフローの `permissions.contents: write` を確認                                         |
| デプロイ未起動 | `GITHUB_TOKEN` の push は push トリガーを発火しない仕様 | `gh workflow run deploy.yml` の明示 dispatch ステップと `permissions.actions: write` を確認 |

### 10.2 エスカレーション基準

| 対応レベル     | 条件                             | 対応者               |
| -------------- | -------------------------------- | -------------------- |
| L1: 自動復旧   | フォールバックで成功             | 不要（自動）         |
| L2: 手動再実行 | 一時的なエラー（ネットワーク等） | 開発担当者           |
| L3: 設定修正   | API キー期限切れ / 設定不備      | インフラ担当者       |
| L4: 構成変更   | ワークフロー定義の修正が必要     | プロジェクトリーダー |

---

## 付録

### A. ファイル構成

```
power-test1/
├── .github/
│   └── workflows/
│       ├── deploy.yml             # ビルド・Cloudflare Pages デプロイ
│       └── ai-auto-post.yml       # AI 自動投稿
├── scripts/
│   ├── generate-post.ts           # AI 記事生成スクリプト
│   └── topics.json                # トピック管理ファイル
├── blog-modern/
│   ├── astro.config.mjs           # Astro 設定（base: /blog-modern）
│   ├── package.json               # 依存関係定義
│   └── src/
│       └── content/
│           └── blog/              # 記事格納ディレクトリ
└── docs/
    ├── basic-design.md            # 基本設計書
    └── cicd-design.md             # 本ドキュメント
```

### B. GitHub Actions で使用するアクション・CLIツール一覧

| アクション / ツール  | バージョン   | 用途                                       |
| -------------------- | ------------ | ------------------------------------------ |
| `actions/checkout`   | v4           | リポジトリチェックアウト                   |
| `actions/setup-node` | v4           | Node.js セットアップ                       |
| `pagefind`（npx）    | 最新         | 全文検索インデックス生成                   |
| `wrangler`（npx）    | 4.x          | Cloudflare Pages へのデプロイ              |
| `gh` CLI             | ランナー標準 | deploy.yml の明示 dispatch（AI Auto Post） |

### C. 用語集

| 用語                 | 説明                                                                                            |
| -------------------- | ----------------------------------------------------------------------------------------------- |
| Astro                | 高速な静的サイトジェネレータ。コンテンツ重視のサイト構築に最適化                                |
| Cloudflare Pages     | Cloudflare が提供する静的サイトホスティングサービス。private リポジトリのままサイトを公開できる |
| Wrangler             | Cloudflare の公式 CLI。`wrangler pages deploy` で Cloudflare Pages にデプロイする               |
| Pagefind             | 静的サイト向けの全文検索ライブラリ。CI でインデックスを生成                                     |
| GitHub Actions       | GitHub が提供する CI/CD プラットフォーム                                                        |
| workflow_dispatch    | GitHub Actions のワークフローを手動（または API / gh CLI）でトリガーする機能                    |
| Conventional Commits | コミットメッセージの標準化規約（feat:, fix: 等）                                                |
| frontmatter          | Markdown ファイル冒頭のメタデータ定義部分（YAML 形式）                                          |
| tsx                  | TypeScript を直接実行するためのランタイム                                                       |
| Claude Code          | Anthropic が提供する CLI ベースの AI コーディングツール                                         |

---

_以上_
