ブログ下書き 2026-04-10
タイトル案
- 「Claude Code Schedule × Supabase Edge Functions で技術ブログを毎日自動生成・Qiita/dev.to に自動投稿する仕組みを作った」
- 「月$20の Claude Code で $200 相当の開発を自動化 — ブログ投稿・CS対応・競合監視まで全部 AI に任せた話」
- 「Flutter Web アプリの LP を44→52機能に拡張しながら、技術ブログも自動でクロスポストできるようになった話」
投稿先候補
- [x] Zenn
- [x] Qiita
- [x] note
- [x] はてなブログ
- [x] X Article
- [x] Medium
- [x] dev.to
- [x] Hashnode
- [x] Substack
- [x] GitHub Pages
- [x] NOTION
本文下書き(約2500字)
はじめに
「コードを書くだけで手一杯で、技術ブログを書く時間がない」
これはほぼすべての個人開発者が抱える悩みです。特に一人で21競合SaaSを超えるアプリを開発している場合、ブログどころか休む時間もありません。
私が開発している 自分株式会社(https://my-web-app-b67f4.web.app/)は、Notion・Evernote・MoneyForward・Slack・Amazon など21競合を1つに統合する Flutter Web + Supabase のAIライフマネジメントアプリです。今週、このアプリに「技術ブログ自動生成・自動クロスポスト」システムを実装し、Qiita と dev.to への初投稿に成功しました。
本記事では、Claude Code Schedule + Supabase Edge Functions で構築したブログ自動化の全体アーキテクチャと、実装の詳細を共有します。
実装した全体アーキテクチャ
Claude Code Schedule (毎日 08:00 JST)
↓ git log で直近7日のコミット確認
↓ 開発内容からブログ下書きを AI 生成
↓ docs/blog-drafts/YYYY-MM-DD.md に保存
↓ Zenn / GitHub Pages / クロスポスト版も生成
↓
Supabase REST API (blog_posts テーブル)
↓ draft として登録
↓
blog-auto-publisher Edge Function (Deno)
↓ Qiita API → 投稿 → URL 取得
↓ dev.to API → 投稿 → URL 取得
↓ blog_posts.status = "posted" に更新
↓
git commit & push → GitHub Actions → Firebase Hosting 自動デプロイ
すべて 自律的に動作します。私がやることは「コードを書くこと」だけ。
Step 1: blog-draft スケジュールタスク(Claude Code Schedule)
Claude Code Schedule の blog-draft タスクは毎日 08:00 JST に実行されます。
git log --oneline --since="7 days ago"
コミットが0件なら処理終了。開発活動があった日だけブログが生成されます。
Claude は git log の結果から最も技術的に面白いトピックを選び、以下の構成で Markdown を生成します:
## タイトル案(3案)
## 投稿先候補(11プラットフォーム)
## 本文(はじめに / 実装方法 / 詰まったポイント / まとめ)
Step 2: blog-post-manager Edge Function で Supabase に登録
生成した下書きを blog_posts テーブルに登録します。
POST https://smmkxxavexumewbfaqpy.supabase.co/rest/v1/blog_posts
{
"title": "タイトル",
"draft_path": "docs/blog-drafts/2026-04-10.md",
"status": "draft",
"target_platforms": ["qiita", "devto", "zenn", ...]
}
blog_posts テーブルのスキーマ:
id uuid PRIMARY KEY,
title text NOT NULL,
draft_path text,
status text DEFAULT 'draft', -- draft / posted / skipped
target_platforms text[],
posted_at timestamptz,
url text,
content_preview text,
created_at timestamptz DEFAULT now()
Step 3: blog-auto-publisher Edge Function(本命)
今週最も力を入れた実装が、この blog-auto-publisher Edge Function です。
Qiita API 投稿実装
async function publishToQiita(
title: string,
body: string,
tags: string[],
): Promise<{ url: string }> {
const tagObjects = tags.slice(0, 5).map((t) => ({ name: t.slice(0, 20) }));
const res = await fetch("https://qiita.com/api/v2/items", {
method: "POST",
headers: {
"Authorization": `Bearer ${QIITA_ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
title,
body,
tags: tagObjects,
private: false,
}),
});
const data = await res.json();
return { url: data.url };
}
dev.to API 投稿実装
async function publishToDevto(
title: string,
body: string,
tags: string[],
): Promise<{ url: string }> {
const res = await fetch("https://dev.to/api/articles", {
method: "POST",
headers: {
"api-key": DEVTO_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
article: {
title,
body_markdown: body,
tags: tags.slice(0, 4),
published: true,
},
}),
});
const data = await res.json();
return { url: data.url };
}
auto_publish アクションで一括投稿
case "auto_publish": {
const results: Record<string, unknown> = {};
for (const platform of post.target_platforms ?? []) {
if (platform === "qiita") {
results.qiita = await publishToQiita(post.title, body, tags);
} else if (platform === "devto") {
results.devto = await publishToDevto(post.title, body, tags);
}
}
const anySuccess = Object.values(results).some((r: unknown) => !(r as Record<string,string>).error);
if (anySuccess) {
await supabase.from("blog_posts")
.update({ status: "posted", posted_at: new Date().toISOString() })
.eq("id", id);
}
return json({ results });
}
詰まったポイント
1. Qiita のタグ制約
Qiita は1記事につき最大5タグ、各タグ名は20文字以内。tags.slice(0, 5).map(t => ({ name: t.slice(0, 20) })) で対応。
2. blog_posts テーブルに content_preview カラムがなかった
CLAUDE.md のスキーマに記載はあったが実テーブルには存在せず。マイグレーション追加:
ALTER TABLE blog_posts ADD COLUMN IF NOT EXISTS content_preview text;
3. GITHUB_TOKEN はブランチ保護をバイパスできない
GitHub Actions から直接 git push する際、ブランチ保護ルールで弾かれることが判明。最終的に「直接 push で問題ないブランチのみ CI からコミット」という方針に。
実際の投稿成果
Qiita: 「【実践】Claude Code Schedule でサポート対応を自動化する具体的な手順」
https://qiita.com/kanta13jp1/items/38f0383e0ea01b787900dev.to: "How I Automated CS with Claude Code Schedule"
https://dev.to/kanta13jp1/how-i-automated-cs-bug-fixes-...-18a6Zenn: データベースビュー設計の記事を
published: false → trueに変更し GitHub連携デプロイ確認
まとめ
Claude Code Schedule × Supabase Edge Functions で 技術ブログの生成から投稿まで完全自動化 できることを実証しました。
現時点での対応状況:
| プラットフォーム | 状態 |
|---|---|
| Qiita | 実装済み |
| dev.to | 実装済み |
| Zenn | 半自動(GitHub連携) |
| note / はてな / Medium 等 | 未実装(今後対応予定) |
自分株式会社は「21競合SaaS を1つに」を目指して開発を続けています。
サービス URL: https://my-web-app-b67f4.web.app/
Top comments (0)