「ブログを作りたい。でもサーバーの管理も、データベースの設計も、全部一人でやるのは重い」——そう感じたことはありませんか。この記事では、ヘッドレスCMSのmicroCMSとNext.js、そしてAIエージェントを組み合わせて、本格的な技術ブログを最初から最後まで作る手順を解説します。題材にするのは、このブログ「DECODE」そのものです。実際に動いているプロジェクトを例にするので、読み終わったときには「環境設定から表示確認まで」の一連の流れが、自分の手で再現できるようになっているはずです。
はじめに:このチュートリアルで作るもの
まず、この記事を読み終えたときに何ができるようになるのかを宣言します。作るのは次のようなブログです。記事の執筆・公開はmicroCMSの管理画面で行い、読者が見るページはNext.jsが生成します。記事を公開すると自動でサイトに反映され、検索・カテゴリ・タグ・ページネーション・記事内目次まで備えた、実用レベルのメディアになります。デザインには独自のカラーシステムを持たせ、スマートフォンでの閲覧を前提にした1カラムのレイアウトです。
このチュートリアルのポイントは3つあります。1つ目はAIエージェントへの指示設計です。気合いでプロンプトを書くのではなく、プロジェクトのルールファイルを用意して品質を固定化する方法を紹介します。2つ目は型安全なCMS連携です。CMSから返ってくるデータは形が変わることがあるため、Zodというライブラリで実行時に検証します。3つ目はSSGとISRによる運用です。基本はビルド時にページを生成し、記事更新時だけWebhookで再生成する仕組みで、速さと鮮度の両立を狙います。
対象読者は、HTMLとCSSと少しのJavaScriptが分かり、ReactやNext.jsは触り始めという方です。ターミナルの基本操作ができれば大丈夫です。逆に、すでにNext.jsでCMS連携済みのアプリを運用している方には物足りないかもしれません。その場合は11章のAIエージェント活用術だけでも読んでみてください。
この記事自体が「AIエージェントと一緒に書かれた記事」です。構成案の提示から本文の執筆、microCMSへの投稿までをエージェントに任せる流れも、11章で紹介します。読みながら「ここはエージェントにやらせられるな」と想像してみてください。
各章で書いていることを読ませて「この感じで実装して」と指示してもOK
全体像をつかむ:3つの登場人物
実装に入る前に、システム全体の見取り図を掴みましょう。登場人物は3つです。microCMSは「記事の倉庫」、Next.jsは「厨房と店舗」、Vercelは「土地と建物」です。あなたがmicroCMSの管理画面で記事を書いて公開すると、Next.jsが倉庫から原稿を取り出してHTMLという料理に仕上げ、Vercelという建物の中でお客さんに提供します。あなたが直接サーバーを管理する必要はありません。
データの流れをもう少し具体的に書くと、次のようになります。公開時はNext.jsがmicroCMSのAPIを叩いて全記事を取得し、1記事ごとに静的なHTMLを生成します。これをSSG(Static Site Generation)と呼びます。記事を更新したときは、microCMSのWebhookがNext.js側の再検証用APIを呼び出し、関連するページだけ作り直します。これがISR(Incremental Static Regeneration)です。普段の閲覧は作り置きのHTMLを返すだけなので、表示が速く、サーバー代もかかりません。
開発中の流れも同じ分担です。手元のPCでは pnpm dev で開発サーバーを立ち上げ、ブラウザで表示を確認しながら進めます。GitHubに push するとVercelが自動で本番公開するので、「書く→確かめる→公開する」の循環が短く保てます。初心者のうちは、この循環を小さく速く回すことが上達の近道です。1つの機能を足したらすぐ画面で確かめ、壊れていないことを確認してから次へ進みましょう。
技術 | 役割 | このプロジェクトでの版 |
|---|---|---|
Next.js (App Router) | ページ生成・表示 | 16系 |
microCMS | 記事・カテゴリ・タグの管理 | API経由で利用 |
Vercel | ホスティング・自動デプロイ | Git連携 |
Zod | CMSレスポンスの実行時検証 | 4系 |
Tailwind CSS | スタイリング | 4系 |
SSGとISRの違いを一言で言うと、「お弁当を作り置きするか、注文が入ってから一部だけ作り直すか」の違いです。作り置き(SSG)は速いけれど中身が古くなることがあり、作り直し(ISR)を組み合わせることで鮮度を保ちます。
WordPressと何が違うの?→ WordPressは「倉庫と店舗が一体」なので手軽ですが、アクセスのたびに調理(動的生成)します。今回の構成は「倉庫と店舗を分離」するので、店舗側の表示が速く、デザインの自由度も高いのが特徴です。
準備:道具とアカウントをそろえる
まずは道具の準備です。必要なのはNode.js、パッケージ管理のpnpm、Git、そして3つのアカウント(GitHub・microCMS・Vercel)です。Node.jsのバージョンは24系を使います。このプロジェクトではバージョンのブレを防ぐために、次の2箇所で固定しています。
# .nvmrc (使いたい版を書くだけ)
24
# package.json の一部
"engines": {
"node": ">=24.0.0"
}ターミナルで次のコマンドを実行して、版を確認してください。nvmを使っている場合は nvm use と打つだけで切り替わります。
node -v # v24.x.x と表示されればOK
pnpm -v # なければ npm install -g pnpm で導入アカウントは3つとも無料枠で始められます。microCMSではサービス(=倉庫の建物)を1つ作り、VercelとGitHubは後ほど連携します。この段階では「作っただけ」で構いません。具体的な設定はこの後の章で順番に行います。
なぜNodeの版を固定するの?→ Next.jsの版ごとに必要なNodeの最低版が決まっており、開発者やデプロイ環境で版がずれると「自分のPCでは動くのに本番で動かない」が起きます。ファイルに書いておけば全員が同じ版を使えます。
microCMS側の設定:記事の入れ物を作る
次に倉庫側、つまりmicroCMSのAPIを作ります。microCMSの管理画面で「APIの作成」を選び、エンドポイント名を articles にします。このプロジェクトの記事スキーマは次の通りです。タイトル・本文・サムネイル画像・カテゴリ参照・タグ参照・公開日時を持ちます。
フィールドID | 種類 | 用途 |
|---|---|---|
title | テキスト | 記事タイトル |
body | リッチエディタ | 本文HTML |
thumbnail / img | 画像 | 一覧・詳細の画像 |
cat | 複数参照(カテゴリ) | 分類(表示は先頭1件) |
tag | 複数参照(タグ) | 細分のタグ |
publishedAt | 日時 | 公開日・NEW判定に使用 |
カテゴリ用に categories API(フィールド cat)、タグ用に tags API(フィールド tag・description)も作ります。次にAPIキーです。読み取り専用のキーを発行し、権限はGETのみに絞ります。書き込み操作は後述の投稿スクリプト用のキーと分けるのが安全です。
キーを分ける理由は被害の限定です。読み取りキーが漏れても、せいぜい記事が読まれるだけです。一方、書き込み権限のあるキーが漏れると記事を改ざん・削除されてしまいます。権限は「その作業に必要な最小限」が原則です。まずはGET専用キーで表示確認まで進め、投稿スクリプトを使う段になって書き込みキーを発行する順番がおすすめです。
カテゴリとタグは何が違うの?→ カテゴリは「本棚の棚板」のような大きな分類、タグは「付箋」のような細かい目印です。このブログではカテゴリを紫、タグをティールと色分けし、一目で役割が分かるようにしています。
catが「複数参照型」なのがポイントです。フィルタの書き方が単一参照と異なり、後述の取得コードでは
cat[contains]IDの形になります。ここを間違えるとカテゴリページが空になるので覚えておきましょう。
Next.jsプロジェクトの作成
倉庫ができたら店舗を作ります。Next.jsの雛形を作り、このプロジェクトと同じ依存パッケージを入れます。App Router・TypeScript・Tailwindを使うのが前提です。
pnpm create next-app@latest my-blog --typescript --tailwind --app
cd my-blog
pnpm add microcms-js-sdk zod lucide-react
pnpm add -D vitest各パッケージの役割は次の通りです。microcms-js-sdk は倉庫への問い合わせ係、zod は返ってきた荷物を開けて中身を検品する係、lucide-react はアイコン集、vitest は小さな部品の動作確認(単体テスト)用です。アイコンは絵文字ではなく lucide-react に統一すると、見た目とアクセシビリティが安定します。
このプロジェクトの配置ルールも真似すると後が楽です。ページ本体は src/app/ に置き、見た目だけの部品は src/components/ui/、動きのある部品は src/components/feature/、CMS連携は src/lib/microcms.ts、型は src/types/article.ts に集めます。「どこに何を書くか」が決まっていると、AIエージェントに作業を頼むときの指示も明確になります。
パッケージ管理はpnpmに統一し、ロックファイルは pnpm-lock.yaml だけを残します。npmでインストールしてしまうと別形式のロックファイルが混ざり、チーム開発やデプロイ時に「どっちが正?」という混乱を招きます。使う道具を1つに絞るのは、地味ですが効くルールです。
最初から完璧な配置を目指さなくて大丈夫です。まずは動くものを作り、「同じようなコードが2箇所に出てきたら共通化する」という順番で十分です。このブログの目次機能も、後から切り出された部品の一つです。
環境変数で両者をつなぐ
倉庫と店舗をつなぐ合鍵が環境変数です。プロジェクト直下に .env.local を作り、次の2つを書きます。1つ目は倉庫の住所、2つ目は合鍵です。
MICROCMS_DOMAIN=your-service-id
MICROCMS_API_KEY=your-api-key.env.local はGitに上げてはいけません。代わりにキー名だけを書いた .env.example をリポジトリに入れ、他の人や未来の自分が「何を設定すればいいか」分かるようにします。
# .env.example (値ではなくキー名だけを置く)
MICROCMS_DOMAIN=
MICROCMS_API_KEY=
MICROCMS_WEBHOOK_SECRET=Webhook用の秘密もここに並べておくと、公開設定の章で迷いません。そして取得層のファイルの先頭で、起動時に存在チェックを行います。
if (!process.env.MICROCMS_API_KEY || !process.env.MICROCMS_DOMAIN) {
throw new Error(
"必須環境変数が設定されていません: MICROCMS_API_KEY / MICROCMS_DOMAIN",
);
}この数行があるだけで、「キーを設定し忘れたまま起動して、原因不明のエラーに悩む」という事故を防げます。起動直後に分かりやすいメッセージで失敗するのは、親切な設計です。
秘匿値に
NEXT_PUBLIC_を付けてはいけません。この接頭辞が付いた変数はブラウザに送られるJavaScriptに埋め込まれ、誰でも読める状態になります。APIキーはサーバー側だけで使い、ブラウザ側の部品から直接参照しないのが鉄則です。
型安全なデータ取得層を作る
ここがこのチュートリアルの核心の1つです。CMSのAPIは「今は」想定通りの形で返ってきますが、スキーマ変更や一時的な不整合で形が変わることがあります。TypeScriptの型はコンパイル時の約束にすぎず、実行時のデータまでは守ってくれません。そこでZodスキーマで実行時に検品します。
まず src/types/article.ts でスキーマを定義し、型はそこから自動生成します。型を手書きして二重管理しないのがルールです。
import { z } from "zod";
export const ArticleSchema = z.object({
id: z.string(),
title: z.string(),
body: z.string(),
publishedAt: z.string(),
// thumbnail / cat / tag などは省略(実際は追加する)
});
export type Article = z.infer<typeof ArticleSchema>;次に src/lib/microcms.ts でSDKの直呼びを包んだ関数を作ります。取得もキャッシュ設定もここに集約し、ページ側からSDKを直接触らせません。
const res = await client.getList<Article>({
endpoint: "articles",
queries: { limit, offset, orders: "-publishedAt" },
customRequestInit: {
next: { tags: ["articles"], revalidate: 60 },
},
});
const parsed = ArticleListSchema.parse(res);
return { articles: parsed.contents, totalCount: parsed.totalCount };Schema.parse() が成功すれば、そのデータは型通りであることが保証されます。失敗した場合は構造化ログを出して null を返し、ページ側でフォールバック表示に切り替えます。「壊れたデータを表示してしまう」より「記事が取れませんでしたと正直に表示する」ほうが、読み手にとっても運営にとっても親切です。
エラーの扱い分けも決めておきます。Zodの検証失敗は「想定内の事故」としてログに残してフォールバック、通信エラーも同様にフォールバック、そして想定外の例外は上位のエラー画面に任せます。さらに catch の空ブロックは禁止です。握りつぶされたエラーは、後から原因を追うときの最大の敵になります。失敗したら必ず何かを残す——ログでもフォールバックUIでも構いません。
as Articleで済ませちゃダメ?→asは「型検査官に見て見ぬふりをさせる」行為です。データが壊れていてもコンパイルは通るため、実行時に白い画面になります。parse()は実際に中身を開けて確認する検品作業です。
ページを作る:一覧と詳細
データの通り道ができたら、ページを作ります。App Routerでは、フォルダとファイルの配置がそのままURLになります。src/app/page.tsx がトップページ、src/app/articles/[id]/page.tsx が記事詳細です。 Server Componentを優先し、操作が必要な部品(検索窓や共有ボタン)だけをClient Componentにします。
記事詳細ページの骨格は次のような形です。データ取得→存在しなければ404→部品に渡して表示、という流れです。
export default async function ArticlePage({ params }) {
const article = await getArticle(params.id);
if (!article) notFound();
return <ArticleDetail article={article} canonicalUrl={url} />;
}ビルド時に全記事のページを先作りするため、各記事IDを列挙する関数も用意します。これがSSGの実体です。
export async function generateStaticParams() {
const data = await getArticles(1, 100);
return (data?.articles ?? []).map((a) => ({ id: a.id }));
}記事が増えて100件を超えたら件数を見直す必要がありますが、個人ブログの規模では当面十分です。表示側の部品は、画像・日付・NEWバッジ・タイトル・カテゴリ・タグという順番で情報を並べます。この順序自体がデザインで、読み手の視線を誘導します。
公開から3日以内の記事にはNEWバッジを付けます。判定ロジックは1箇所の関数に集約し、一覧と詳細の両方から使い回します。同じ判定を2箇所に書くと、仕様変更のときに片方だけ直し忘れる事故が起きます。「3日」という数字を変えたくなったら1箇所直せば全体に反映される——この小さな工夫が、長生きするコードの条件です。
// 公開3日以内ならNEW表示(1箇所に集約して再利用)
export function isNew(publishedAt: string): boolean {
const diff = Date.now() - new Date(publishedAt).getTime();
return diff < 1000 * 60 * 60 * 24 * 3;
}ページ本体(
app/)に仕事をさせすぎないのがコツです。データ取得と部品の配置だけを書いて、見た目の詳細はcomponents/に逃がします。こうするとAIエージェントに「一覧のカードだけ直して」と頼みやすくなります。
機能を足す:検索・目次・ページネーション
一覧と詳細が表示できたら、少しずつ機能を足します。一度に全部作らず、「1機能ずつ足して表示確認する」のが初心者に優しい進め方です。このブログにある機能の作り方を3つ紹介します。
1つ目は検索です。microCMSの全文検索パラメータ q を使うだけなので、取得関数は数行の追加で済みます。
queries: {
limit,
offset,
orders: "-publishedAt",
q: query, // 検索キーワード
},2つ目は記事内目次です。本文HTMLからh2を抜き出して連番ID(toc-1 など)を振り、タイトル下にアンカーリストを表示します。本文側のh2にも同じIDを注入するので、クリックで該当箇所へジャンプできます。日本語の見出しをスラッグ化するとエンコード問題が起きがちなので、連番にするのが堅実です。
// h2を抜き出して目次化する抜粋
export function extractToc(html: string): TocItem[] {
const items: TocItem[] = [];
const re = /<h2[^>]*>([\s\S]*?)<\/h2>/gi;
let match: RegExpExecArray | null;
let index = 0;
while ((match = re.exec(html)) !== null) {
const text = match[1].replace(/<[^>]*>/g, "").trim();
if (text.length === 0) continue;
index += 1;
items.push({ id: `toc-${index}`, text });
}
return items;
}3つ目はページネーションです。総件数と1ページの件数から総ページ数を割り、前後ボタンだけの最小構成にします。凝ったページ番号は後回しで構いません。なお、stickyヘッダーで見出しが隠れないよう、h2には scroll-margin-top を付けておきます。
.article-content h2 {
scroll-margin-top: 72px; /* stickyヘッダー56px + 余白 */
}機能追加のたびに単体テストを1つ書く習慣がおすすめです。この目次機能にも9件のテストがあり、空見出しのスキップや重複見出しの一意性を確認しています。小さな安心の積み重ねが、後の大きな改修を支えます。
デザインを整える:色に役割を持たせる
機能が揃ったら見た目です。このブログが以前抱えていた課題は「色が緑系だけでメリハリがない」ことでした。解決策は、色の数を増やすことではなく色に役割を持たせることです。採用した配色の役割表がこちらです。
役割 | 色 | 使う場所 |
|---|---|---|
キー(操作系) | 青 #3b5ba9 | ロゴ・リンク・主ボタン・見出し装飾 |
アクセント(注意) | 橙 #d9480f | NEWバッジ・注目CTAのみ |
分類 | 紫 #5e3fa1 | カテゴリ表示 |
細分 | ティール #2a6b5e | タグ(ベタ塗り+白文字) |
帯 | 紺 #1c2733 | フッター・ヒーロー陰影 |
装飾 | 黄緑 #a9c46a | 装飾のみ |
記事が存在しないIDで開かれたら notFound() で404画面に誘導し、記事が0件の一覧では空状態のメッセージを表示します。エラーと空っぽは別物なので表示も分けます。「壊れているのか、まだ無いだけなのか」が読み手に伝わることが大切です。
フォントも顔の一部です。見出しやロゴには等幅のJetBrains Mono、本文にはNoto Sans JPを使い分けます。ターミナル調のヒーローと読みやすい本文の対比が、このブログの雰囲気を作っています。フォントは外部サービスではなく next/font で同梱し、表示のちらつきと余計な通信を避けます。
実装はCSS変数に集約します。色の実値は globals.css の :root にだけ書き、部品側は変数名で参照します。直接16進数を書くことは禁止です。
:root {
--color-primary: #3b5ba9;
--color-primary-gradient: linear-gradient(135deg, #3b5ba9 0%, #4fa3c4 100%);
--color-attention: #d9480f;
--color-category: #5e3fa1;
--color-tag-bg: #2a6b5e;
--color-tag-fg: #ffffff;
--color-band: #1c2733;
}グラデーションはボタンや強調などの「アクション」に限定し、背景全体には使いません。制限があるからこそ、ここぞという場所でグラデーションが映えます。NEWバッジを橙のベタ塗りにしたのも同じ理由で、「注意は注意の色だけが使う」ことで希少性を保っています。
タグの白文字は読みやすいの?→ 背景ティールと白文字のコントラスト比は6倍以上あり、アクセシビリティの基準(4.5倍)を満たしています。色を決めたらコントラスト比を確認する癖をつけましょう。
AIエージェント活用術:指示のコツと投稿フロー
ここからはAIエージェントの活用方法です。コツは「毎回丁寧なプロンプトを書く」ことではなく、プロジェクトのルールをファイルに固定化することです。このプロジェクトでは AGENTS.md というファイルに、配置・命名・禁止事項・作業手順を書いています。エージェントは作業開始時にこれを読むので、「any禁止」「SDK直呼び禁止」「秘匿値のNEXT_PUBLIC_化禁止」などが自動的に守られます。
# AGENTS.md の抜粋イメージ
- 開始前: ①該当節を読む ②類似コードを確認 ③Props/Zodから書く
- 禁止: any / SDK直呼び / console.log残置
- CI (PR前): lint → type-check → build大きな作業は「プランモード」で先に計画を立て、了承後に実装させるのが安全です。この記事の目次機能も、構成→見出し→実装の順で段階的に進めました。いきなり作らせるより手戻りが少なくなります。
記事の投稿自体もスクリプト化されています。scripts/mcms.py を使うと、ターミナルからmicroCMSへ記事・カテゴリ・タグを作成できます。本文はHTMLファイルで渡します。
# 下書きで作成する(安全な試し方)
python3 scripts/mcms.py articles create \
--title "はじめての記事" \
--body-file body.html \
--cat 技術 --tag Next.js --draft
# 公開するのは公開コマンドで
python3 scripts/mcms.py articles publish --id <ID>この記事も同じ流れで投稿できます。まず --draft で下書き保存し、管理画面で見た目を確認してから公開するのがおすすめです。カテゴリやタグの名称は自動でIDに解決されるので、名前で指定して大丈夫です。
作業を頼むときの粒度も大切です。「ブログを作って」のような丸投げではなく、「取得層の関数だけ作って」「この部品の色だけ変えて」のように小さく区切ります。小さな単位なら結果の確認が容易で、間違いがあっても修正範囲が限定されます。確認のたびに pnpm run lint と pnpm run type-check を回す習慣を付けると、壊れた状態を次に持ち越さずに済みます。
エージェントに曖昧な指示を出すと曖昧な成果物が返ります。「トップページにならったモックHTMLで複数パターンを比較してから決める」のように、比較方法まで指定すると意思決定の質が上がります。色決めの章はまさにこの進め方でした。
深掘り:mcms.pyはどういう仕組みで生まれたか
11章で登場した投稿スクリプトを、もう少し詳しく見てみましょう。mcms.py は標準ライブラリだけ(python3 + argparse + urllib)で書かれた約300行のCLIです。外部依存がないので、pip installなしでそのまま動きます。
仕組みの要点は3つです。1つ目はAPIの使い分けです。記事の作成・更新・削除・参照にはコンテンツAPIを使い、公開・下書き戻しだけ管理APIを使います。2つ目は認証の解決順で、コマンド引数→環境変数→ .env.local の順に探します。3つ目は参照の名前解決で、カテゴリやタグは名称で指定すると自動でIDに変換されます。存在しない名前はそのまま送られるので、タグは事前に作成しておく必要があります。
python3 scripts/mcms.py articles list --limit 5
python3 scripts/mcms.py articles create --title "下書き" --body-file body.html --draft
python3 scripts/mcms.py articles publish --id <ID>では、こうしたスクリプトはどんなプロンプトで生まれるのでしょうか。実際に有効だった指示の形を紹介します。ポイントは「仕様を列挙すること」で、実装方法の指定は最小限にしています。
microCMSを操作するPythonスクリプト scripts/mcms.py を作ってください。
条件:
- 標準ライブラリのみ(argparse + urllib)。外部依存なし
- 対象は articles / categories / tags、操作は list/get/create/update/publish/close/delete
- 記事作成は --title/--body/--body-file/--cat/--tag/--draft を受け付け、catとtagは名称からIDに解決する
- 認証は --domain/--key 引数、なければ環境変数、なければ .env.local の順で取得する
- publish/close のみ管理API(ステータス変更権限)、それ以外はコンテンツAPIを使う
- 結果はJSONで標準出力に出し、HTTPエラーの場合は終了コード1で終える
- 使い方をファイル先頭のdocstringに書くこのように「何ができるか・何を受け付けるか・何を守るか」を箇条書きにすると、エージェントは迷わず一発で動くものを作れます。逆に「便利なスクリプトを作って」だけだと、権限分離や終了コードなどの細部が抜け落ちます。仕様の粒度が成果物の質を決める、という好例です。
生成物が期待通りかは、作らせる前に「使い方の例」を書かせると見抜けます。docstringの使用例が自分のやりたい操作と一致していれば、そのスクリプトは使えます。
公開する:Vercelデプロイと更新の反映
仕上げは公開です。GitHubのリポジトリとVercelを連携させると、main ブランチに push するだけで自動デプロイされます。環境変数(MICROCMS_API_KEY など)はVercelの管理画面にも登録します。ここでも NEXT_PUBLIC_ を付けていないことが重要になります。サーバー側の秘密はサーバー側に置きます。
デプロイの段取りは「まず develop のような別ブランチで試し、本番は main から」という順番が安全です。このプロジェクトでは feature/* から develop を経て main へ統合し、main への直 push を禁止しています。本番が自動公開されるからこそ、本番に流す前のワンクッションが効きます。公開前には pnpm run build が通ることと、ロボット向けの robots.txt やサイトマップが出力されていることも確認します。
記事を更新したときにサイトへ反映する仕組みが、再検証用APIです。microCMSのWebhookが記事の公開・更新時にこのAPIを呼び出し、署名を検証してから対象ページを作り直します。
export async function POST(req: NextRequest) {
const signature = req.headers.get("X-MICROCMS-Signature");
const body = await req.text();
const secret = process.env.MICROCMS_WEBHOOK_SECRET;
// 署名を検証してから再生成する
const expected = `sha256=${createHmac("sha256", secret).update(body).digest("hex")}`;
if (signature !== expected) {
return new Response("Unauthorized", { status: 401 });
}
revalidateTag("articles", { expire: 60 });
revalidatePath("/", "page");
return new Response("OK", { status: 200 });
}署名検証のポイントは、「microCMSと自分だけが知っている秘密を使い、送られてきた本文から署名を再計算して突き合わせる」ことです。これにより、第三者が再生成APIを勝手に叩くことを防げます。Webhookのシークレットも環境変数で管理します。
再デプロイしなくても反映されるの?→ はい。ISRの再検証は「ページの作り直し」であり、アプリ全体のデプロイとは別物です。記事更新のたびにデプロイしていたら時間も回数ももったいないので、この仕組みが効きます。
表示確認チェックリストとトラブル対処
公開前の表示確認は、チェックリストで行います。目視だけに頼らず項目化すると、見落としが減ります。
確認箇所 | 観点 |
|---|---|
トップページ | 新着・特集・カテゴリ別に記事が並ぶか |
記事詳細 | 目次からジャンプできるか、画像・コード表示は崩れないか |
検索 | キーワードで絞り込めるか、空結果の表示は適切か |
カテゴリ・タグ | 色分け(紫・ティール)が意図通りか |
スマートフォン | 幅480px想定の1カラムで横はみ出しがないか |
更新反映 | microCMS公開後に再検証で反映されるか |
よくある失敗と対処も3つ紹介します。1つ目はカテゴリページが空です。原因の多くはフィルタの書き間違いで、cat[contains]ID の形式になっているか確認します。2つ目は環境変数エラーで起動しないです。.env.local のキー名と取得層の存在チェックのメッセージを見比べます。3つ目は型エラーでビルド失敗です。CMSのスキーマを変えたらZodスキーマの更新を忘れずに行い、ログの context 欄で箇所を特定します。
品質ゲートとして、PR前には pnpm run lint → pnpm run type-check → pnpm run build の順で実行します。この順番にも意味があり、軽い検査から重い検査へと進むことで、問題の切り分けが速くなります。
pnpm run lint && pnpm run type-check && pnpm run build「動いたら終わり」ではなく「確認してから終わり」が合言葉です。チェックリストは最初は小さくて構いません。トラブルが起きるたびに1行足していけば、あなた専用の運用手順書になります。
まとめと次のステップ
この記事では、AIエージェント・microCMS・Next.jsを組み合わせたブログ作りを、環境設定から表示確認まで一通り辿りました。振り返ると、重要なのは個別の技術よりも「分担」です。記事管理はmicroCMSに、ページ生成はNext.jsに、公開基盤はVercelに、品質の番人はZodとルールファイルに任せます。それぞれが得意な仕事だけをするので、全体がシンプルに保たれます。
次のステップとしては、OGP画像の自動生成、全文検索の強化、サイト内回遊を促す関連記事の改善などが考えられます。広告やアクセス解析の導入も、メディアとして育てるなら検討時期が来るでしょう。まずはこの記事の手順で自分のブログを公開し、1本目の記事を投稿してみてください。その1本目の投稿には、ぜひ mcms.py を使ってみましょう。ターミナルから投稿できた瞬間に、この構成の気持ちよさが実感できるはずです。
最後に、この記事で紹介した順番をもう一度確認しましょう。道具の準備→倉庫の設定→店舗の作成→合鍵の共有→検品の仕組み→ページの組立て→機能の追加→見た目の整理→AIとの協業→公開と反映の確認。この順番通りに進めれば、どこで躓いても「今どの段階か」が分かります。分からなくなったら全体像の章に戻り、地図を確認してください。迷子にならない旅が、一番速い旅です。






