Use Cases (更新: 2026/6/6)

Contentful連携で日本語記事が消える事故を、Claude Codeで防ぐ

Claude CodeでContentful(ヘッドレスCMS)をNext.js/Astroに連携。下書きプレビュー・日本語locale・ISR再生成まで、僕がハマった事故と回避策をコード付きで。

Contentful連携で日本語記事が消える事故を、Claude Codeで防ぐ

「Contentfulつないどいて」とClaude Codeに頼んだ翌日、本番サイトを開いたら日本語記事が全部英語になっていました。

正確には、英語が出ていたのはまだマシなほう。下書き中の記事はプレビューですら見えず、編集者から「私が今書いてる原稿、どこにも表示されないんですけど」と連絡が来ました。コードは動いている。SDKも入っている。なのに、現場では事故っている。

このギャップ、Contentful連携あるあるです。原因はだいたいコードの構文ではなく、API・トークン・localeの「境界」の設計ミス。今日はその境界を、僕が実際に踏んだ地雷ごと、コピペで動くコードと一緒に潰していきます。

この記事の要点

  • Contentful連携が事故るのは、Delivery API・Preview API・Management APIの役割を混ぜるから。最初に表で分ける。
  • 「日本語が英語になる」の犯人はほぼlocale設定。コードより先にContentful側のlocalized設定を疑う。
  • 下書きプレビューはPreview token + preview.contentful.com、本番はDelivery token + cdn.contentful.comここを1文字混ぜると401か空表示
  • Next.jsはDraft Mode + revalidatePath、AstroはSSG + Webhook再ビルド。役割で分けると破綻しない。
  • Claude Codeには「境界」を最初に指示するほど出力が安定する。曖昧な「いい感じに」は事故の合図。

まず、3つのAPIをごちゃ混ぜにしない

Contentful連携で最初にやるのは、コードを書くことじゃありません。どのAPIをどこで使うか決めることです。ここを曖昧にしたままClaude Codeに丸投げすると、Preview tokenで公開記事を取りに行ったり、管理用トークンをブラウザに漏らしたり、権限事故とキャッシュ事故が同時に起きます。

ヘッドレスCMSという言葉に馴染みがない人向けに一応書いておくと、Contentfulは「本文や画像だけをAPIで配るCMS」です。WordPressのように管理画面と表示画面が一体になっておらず、表示側(Next.jsやAstro)は自分で作る。だから連携の善し悪しは、表示側がどのAPIを正しく叩けるかで決まります。

僕が今使っている整理がこれです。最初にこの表を作って、Claude Codeに渡す。

API用途使うトークン使ってよい場所
Content Delivery API公開済みコンテンツの取得Delivery tokenサーバー側のSSG/ISR、Astro build、Next.js Server Component
Content Preview API下書きや未公開変更の確認Preview tokenプレビュー用のサーバー処理だけ
Content Management APIcontent type作成、entry更新、publishManagement token / PATローカルの移行スクリプト、CIの管理ジョブ
Images API画像のリサイズ、format変換Delivery/Previewと同じ文脈画像URL生成、OGP、サムネイル

公式のContentful JavaScript SDKでは、SDKはDelivery APIとPreview APIに使い、Preview APIのときは host: "preview.contentful.com" とpreview access tokenを指定します。Management APIのPersonal Access Token(PAT)はユーザー権限そのものに紐づくので、パスワードと同じ扱いで環境変数に隔離する。詳しくはContentfulのPAT解説を読んでおくと安心です。

Claude Codeへの最初の指示は、こんな感じで境界を全部言い切ります。「いい感じに」は禁句。

このリポジトリにContentfulブログ連携を追加してください。
- 公開取得はContent Delivery APIだけを使う
- 下書き確認はContent Preview APIだけを使う
- Content Management API tokenはscripts配下のモデル作成に限定する
- localeはja-JPを既定、en-USも取得できるようにする
- Next.jsはApp RouterのdraftModeとrevalidatePath、AstroはSSGを想定する
- 既存の未コミット変更には触れず、追加/変更ファイルを最後に一覧化する

この6行を渡すかどうかで、出てくるコードの安定度がまるで変わります。僕は最初これをサボって「Contentfulブログ作って」とだけ言い、見事に全部混ざったコードを受け取りました。

用途で設計が変わる:ブログとLPを同じ型にするな

「Contentful連携」とひとくくりにしがちですが、ブログとLPとドキュメントでは必要なフィールドもキャッシュ方針も別物です。Claude Codeに「ブログCMS」とだけ言うより、用途ごとに必要な構造を指定したほうが、出力がブレません。

ユースケース必要なContentfulフィールドキャッシュ方針収益導線
技術ブログtitle、slug、excerpt、body、heroImage、author、tags、publishedAtSSG + Webhookで再検証無料PDF、関連記事、研修相談
プロダクトLPheadline、sections、pricingCopy、faq、ctaLabelISR短め、公開直後は手動revalidate購入ボタン、Gumroad、問い合わせ
ドキュメントサイトcategory、version、body、relatedDocs、updatedAtSSG中心、検索indexも同期有料テンプレート、サポート契約
多言語ニュースlocale別title/body、canonicalSlug、regionlocale別のビルドとプレビュー地域別CTA、現地語の問い合わせ

僕が最初にやらかしたのは、LPとブログを同じ blogPost content typeで押し切ったことでした。LPにはセクション単位のCTAや価格表が要るのに、ブログ用の body(Rich Text)一本で済ませた。すると編集者が、本文の中にボタン文言や価格を直接打ち込み始めるんです。

これが後で効いてくる。計測イベントを仕込もうとしても、CTAがどこにあるか構造化されていない。A/Bテストしようにも差し替え箇所が特定できない。Claude Codeに「CTAの計測を入れて」と頼んでも、本文に埋まった文字列が相手だと検証しようがない。構造化をサボると、未来の自分の自動化を縛るという、地味だけど痛い教訓でした。

環境変数で、公開・プレビュー・管理を物理的に分ける

トークンを混ぜない一番確実な方法は、環境変数の名前からして役割を分けることです。最初に .env.example を作って、Claude Codeに「どの変数がどのAPI向けか」を読ませます。

# .env.example
CONTENTFUL_SPACE_ID=your_space_id
CONTENTFUL_ENVIRONMENT=master
CONTENTFUL_DEFAULT_LOCALE=ja-JP
CONTENTFUL_DELIVERY_TOKEN=delivery_token_for_published_content
CONTENTFUL_PREVIEW_TOKEN=preview_token_for_drafts
CONTENTFUL_MANAGEMENT_TOKEN=management_token_for_local_scripts
CONTENTFUL_PREVIEW_SECRET=random_secret_for_next_draft_mode
CONTENTFUL_REVALIDATE_SECRET=random_secret_for_webhooks
NEXT_PUBLIC_SITE_URL=http://localhost:3000

ここで一番危ないのが、NEXT_PUBLIC_ を付けた変数にPreview tokenやManagement tokenを入れること。NEXT_PUBLIC_ はブラウザのバンドルに丸ごと露出します。Delivery tokenは読み取り専用なのでまだマシですが、それでも基本はサーバー側の取得で閉じる。Preview tokenは未公開記事が読めてしまうので、クライアントに出した瞬間に下書きが世界に公開されたのと同じです。

もう1つの落とし穴が環境名。多くのプロジェクトで既定は master ですが、本番運用では production やenvironment aliasに切り替えることがあります。権限が「masterだけ」のユーザーやPATで production を読みに行くと、しれっと403。Contentfulの環境権限は細かく設定できるので、Contentfulのenvironment permissionsを見て、CI用トークンが対象環境を読めるか先に確認してください。僕はこれで「ローカルでは動くのにCIで403」を半日溶かしました。

空のSpaceにcontent modelを作る(CMA)

ここからコードです。まず空の検証用Spaceに、ブログの最小モデルをContent Management APIで作ります。CMAは記事の取得には使いません。content typeやentryを作る・更新する・publishするための管理用APIです。

// scripts/setup-contentful-model.ts
import "dotenv/config";
import * as contentfulManagement from "contentful-management";

// 環境変数が無ければ即落とす。後でnull由来の謎エラーに悩まないため
function must(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is required`);
  return value;
}

const client = contentfulManagement.createClient({
  accessToken: must("CONTENTFUL_MANAGEMENT_TOKEN"),
});

async function main() {
  const space = await client.getSpace(must("CONTENTFUL_SPACE_ID"));
  const environment = await space.getEnvironment(
    process.env.CONTENTFUL_ENVIRONMENT ?? "master",
  );

  // 著者モデル
  const author = await environment.createContentTypeWithId("author", {
    name: "Author",
    displayField: "name",
    fields: [
      { id: "name", name: "Name", type: "Symbol", required: true },
      { id: "slug", name: "Slug", type: "Symbol", required: true },
      { id: "bio", name: "Bio", type: "Text", localized: true },
      { id: "avatar", name: "Avatar", type: "Link", linkType: "Asset" },
    ],
  });
  await author.publish();

  // ブログ記事モデル。bodyとexcerptはlocalizedにして多言語に備える
  const blogPost = await environment.createContentTypeWithId("blogPost", {
    name: "Blog Post",
    displayField: "title",
    fields: [
      { id: "title", name: "Title", type: "Symbol", required: true, localized: true },
      { id: "slug", name: "Slug", type: "Symbol", required: true },
      { id: "excerpt", name: "Excerpt", type: "Text", localized: true },
      { id: "body", name: "Body", type: "RichText", required: true, localized: true },
      { id: "heroImage", name: "Hero image", type: "Link", linkType: "Asset" },
      {
        id: "author",
        name: "Author",
        type: "Link",
        linkType: "Entry",
        validations: [{ linkContentType: ["author"] }],
      },
      { id: "tags", name: "Tags", type: "Array", items: { type: "Symbol" } },
      { id: "publishedAt", name: "Published at", type: "Date", required: true },
    ],
  });
  await blogPost.publish();
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});

注意点が1つ。このスクリプトは空のSpace専用です。既にcontent typeがある環境で流すとID重複でコケます。本番では既存モデルを取得して差分を確認し、破壊的な変更はmigrationとして扱う。Claude Codeに頼むときも「既存モデルを消さない」「field IDを変えない」「削除前にdiffを出す」と必ず釘を刺してください。Contentfulはfield名(表示名)を変えてもAPI identifierは保てますが、field IDを変えると既存コードもGraphQL schemaも壊れます

Delivery/Preview共通の型付きクライアント

取得層はNext.jsでもAstroでも使い回せる形にします。TypeScriptの EntryFieldTypes を使うと、Contentfulのentry構造をコード上の型で表現できる。型生成ツールを入れる前でも、手書きの型から始めるとClaude Codeの修正範囲が小さくて済みます。

// src/lib/contentful.ts
import { createClient, type EntryFieldTypes, type EntrySkeletonType } from "contentful";

type BlogPostFields = {
  title: EntryFieldTypes.Symbol;
  slug: EntryFieldTypes.Symbol;
  excerpt: EntryFieldTypes.Text;
  body: EntryFieldTypes.RichText;
  heroImage: EntryFieldTypes.AssetLink;
  tags: EntryFieldTypes.Array<EntryFieldTypes.Symbol>;
  publishedAt: EntryFieldTypes.Date;
};

export type BlogPostSkeleton = EntrySkeletonType<BlogPostFields, "blogPost">;

function required(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is required`);
  return value;
}

// preview=true ならプレビュー用のhostとtokenに切り替える。ここが境界の本体
export function getContentfulClient(options: { preview?: boolean } = {}) {
  const preview = options.preview ?? false;

  return createClient({
    space: required("CONTENTFUL_SPACE_ID"),
    environment: process.env.CONTENTFUL_ENVIRONMENT ?? "master",
    accessToken: preview
      ? required("CONTENTFUL_PREVIEW_TOKEN")
      : required("CONTENTFUL_DELIVERY_TOKEN"),
    host: preview ? "preview.contentful.com" : "cdn.contentful.com",
  });
}

export async function getBlogPosts(options: { locale?: string; preview?: boolean } = {}) {
  const locale = options.locale ?? process.env.CONTENTFUL_DEFAULT_LOCALE ?? "ja-JP";
  const response = await getContentfulClient(options).getEntries<BlogPostSkeleton>({
    content_type: "blogPost",
    order: ["-fields.publishedAt"],
    include: 2,
    locale,
  });

  return response.items;
}

export async function getBlogPostBySlug(
  slug: string,
  options: { locale?: string; preview?: boolean } = {},
) {
  const locale = options.locale ?? process.env.CONTENTFUL_DEFAULT_LOCALE ?? "ja-JP";
  const response = await getContentfulClient(options).getEntries<BlogPostSkeleton>({
    content_type: "blogPost",
    "fields.slug": slug,
    limit: 1,
    include: 2,
    locale,
  });

  return response.items[0] ?? null;
}

肝は getContentfulClient 1か所でhostとtokenを切り替えていること。これをサボってNext.js側とAstro側でSDK初期化を別々に書かせると、片方だけpreview hostを書き忘れる、というズレが必ず出ます。初期化は1か所に集約。これだけでプレビュー事故の半分は消えます。

Next.js:SSG・プレビュー・再検証をつなぐ

Next.jsでは、公開ページは静的生成、下書き確認はDraft Mode、ContentfulのWebhookは revalidatePath で再検証、という分担が一番扱いやすい。1つ注意。Next.js 15以降では draftMode() がasync関数になりました。公式のNext.js draftModeにも「You must use async/await」と明記されています。14時代の同期コードをそのまま使うと動きません。

まず記事ページ。

// app/blog/[slug]/page.tsx
import { draftMode } from "next/headers";
import { notFound } from "next/navigation";
import { documentToReactComponents } from "@contentful/rich-text-react-renderer";
import { getBlogPostBySlug, getBlogPosts } from "@/lib/contentful";

export async function generateStaticParams() {
  const posts = await getBlogPosts({ locale: "ja-JP" });
  return posts.map((post) => ({ slug: post.fields.slug }));
}

export default async function BlogPostPage({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  const { isEnabled } = await draftMode(); // async。awaitを忘れない
  const post = await getBlogPostBySlug(slug, {
    locale: "ja-JP",
    preview: isEnabled, // プレビュー時だけPreview APIに切り替わる
  });

  if (!post) notFound();

  return (
    <article>
      <p>{isEnabled ? "Preview" : "Published"}</p>
      <h1>{post.fields.title}</h1>
      {post.fields.excerpt && <p>{post.fields.excerpt}</p>}
      <div>{documentToReactComponents(post.fields.body)}</div>
    </article>
  );
}

次にプレビュー突入口。secretで守らないと、誰でも下書きを覗けてしまいます。

// app/api/draft/route.ts
import { draftMode } from "next/headers";
import { redirect } from "next/navigation";

export async function GET(request: Request) {
  const url = new URL(request.url);
  const secret = url.searchParams.get("secret");
  const slug = url.searchParams.get("slug");

  // secretが合わなければ門前払い
  if (secret !== process.env.CONTENTFUL_PREVIEW_SECRET) {
    return new Response("Invalid preview secret", { status: 401 });
  }
  if (!slug) {
    return new Response("Missing slug", { status: 400 });
  }

  const draft = await draftMode();
  draft.enable();
  redirect(`/blog/${slug}`);
}

最後にWebhookでの再検証。

// app/api/revalidate/route.ts
import { revalidatePath } from "next/cache";
import type { NextRequest } from "next/server";

type ContentfulWebhookPayload = {
  fields?: {
    slug?: Record<string, string>;
  };
};

export async function POST(request: NextRequest) {
  const secret = request.headers.get("x-contentful-webhook-secret");
  if (secret !== process.env.CONTENTFUL_REVALIDATE_SECRET) {
    return Response.json({ revalidated: false }, { status: 401 });
  }

  const payload = (await request.json()) as ContentfulWebhookPayload;
  // localeごとにslugが入るので、ja-JPを優先しen-USにフォールバック
  const slug = payload.fields?.slug?.["ja-JP"] ?? payload.fields?.slug?.["en-US"];

  revalidatePath("/blog");
  if (slug) revalidatePath(`/blog/${slug}`);

  return Response.json({ revalidated: true, slug: slug ?? null });
}

ここで一番ハマるのが、Webhookを「保存時」に撃つか「公開時」に撃つか。公開ページの再検証はpublish/unpublishだけで十分です。保存のたびにrevalidateすると、下書き中の細かい編集で本番キャッシュを何十回も消すことになる。プレビューはDraft Mode + Preview token、本番はDelivery token + 公開Webhook。この2系統をはっきり分けてください。

Astro:ビルド時にSSGで取り切る

AstroはContentfulと相性が良くて、ビルド時にentryを取得して静的HTMLに焼けます。公式のAstroのContentful連携ガイドcontentful SDKと EntryFieldTypes を使う構成です。先ほどWebFetchで確認したとおり、開発時は preview.contentful.com、ビルド時は cdn.contentful.com に切り替える書き方が紹介されています。Astroで大事なのは、プレビューより「build時にどのlocaleとslugを出すか」をはっきりさせること。

---
// src/pages/blog/[slug].astro
import { documentToHtmlString } from "@contentful/rich-text-html-renderer";
import { getBlogPostBySlug, getBlogPosts } from "../../lib/contentful";

export async function getStaticPaths() {
  const posts = await getBlogPosts({ locale: "ja-JP" });

  return posts.map((post) => ({
    params: { slug: post.fields.slug },
    props: { slug: post.fields.slug },
  }));
}

const { slug } = Astro.props;
const post = await getBlogPostBySlug(slug, { locale: "ja-JP" });
if (!post) return Astro.redirect("/404");
---

<article>
  <h1>{post.fields.title}</h1>
  {post.fields.excerpt && <p>{post.fields.excerpt}</p>}
  <div set:html={documentToHtmlString(post.fields.body)} />
</article>

AstroのSSGは、ビルド後にContentfulを更新してもHTMLは変わりません。だからNetlify・Vercel・Cloudflare PagesなどでContentful Webhookから再ビルドを撃つか、頻繁に更新するページだけNext.js側のISRに寄せるかを決めます。僕の今の構成は、記事メディアはAstroで高速に焼いて、公開頻度の高いLPだけNext.jsのISR。役割で分けると運用が静かになります。

詰まりやすい失敗例を、そのままチェックリストに

Contentful連携の不具合は、コードの構文より設定のズレから来ます。Claude Codeにレビューさせるとき、この表をそのまま観点として渡すと早い。

失敗例症状原因修正
Preview tokenをDelivery API hostに投げる401、下書きが見えないhostcdn.contentful.comのままpreview時はpreview.contentful.comに切り替える
Delivery tokenで下書きを読む記事がnullになるDelivery APIは公開済みentryだけ返すDraft ModeではPreview APIを使う
locale指定を忘れる英語だけ出る、日本語が空default localeとコードの想定が違うCONTENTFUL_DEFAULT_LOCALEを置き、URLと言語を対応させる
locale=*を雑に使う型が複雑になり表示で落ちる全locale取得はfield形状が変わるページ生成では必要localeだけ取得する
CMA tokenをブラウザに出す重大な漏えいNEXT_PUBLIC_に入れた管理tokenはscripts/CIだけに限定する
画像assetをpublishし忘れる本文は出るが画像が404/空entryだけpublishしたasset処理とpublishを確認する
Webhookが保存時に走る本番cacheが頻繁に消えるevent条件が広すぎるpublish/unpublishに絞る

冒頭の「日本語が英語になる」事故、犯人はこの表の3行目でした。Contentfulのfieldがlocalizedでないと、localeを変えても同じ値が返ります。逆にlocalized fieldに日本語値が入っていなければ、fallback設定次第で英語が出る。「日本語記事を作ったつもりなのに英語が出る」ときは、コードを直す前に、Contentful側のlocale設定→fieldのlocalized設定→entry内のlocale値、の順で見てください。コードは無実なことが多いです。

API境界そのものの設計をもっと詰めたい人はClaude Code API開発、ブログCMS全体の運用像はClaude CodeブログCMS構築、公開後に収益へつなぐ導線はコンテンツファネル監査も合わせてどうぞ。

型生成とレビューを運用に乗せる

content modelが増えるほど、手書きの型はズレていきます。最初は EntryFieldTypes で十分ですが、プロダクト運用に入ったらContentfulのモデルから型を生成して、CIで差分を検知するのが安全です。Claude Codeには「型生成後の差分を見て、表示側の型エラーを直す」「content type IDとfield IDは勝手に変えない」と指示する。

実務で効いたレビュー用プロンプトがこれです。

Contentfulのcontent model変更をレビューしてください。
観点:
1. 既存のfield IDが変わっていないか
2. localized fieldの追加で既存localeが空にならないか
3. Next.jsとAstroの取得関数に型エラーが出ないか
4. Preview APIとDelivery APIのtoken/hostが混ざっていないか
5. Webhook再検証の対象pathがslugとlocaleを含んでいるか
出力:
- 問題点
- 変更してよいファイル
- 実行した検証コマンド

Claude Codeの強みは、モデル・コード・テスト・ドキュメントを同じ文脈でまとめて見られること。ただし、Contentful管理画面の状態はリポジトリには映りません。モデルID、locale、API key名、Webhook event、Preview URLは、スクリーンショットや設定メモとして渡すとレビュー精度がぐっと上がります。リポジトリの外側を言葉で補う、これが地味に効きます。

CTAは本文に埋めず、構造化フィールドに逃がす

CMS連携の記事は、実装で終わると収益につながりません。読者は「Contentfulを入れたい」だけじゃなく、「編集者が自走できる運用にしたい」「公開後に問い合わせや購入につなげたい」まで考えている。だからContentfulの構造化フィールドにCTAも持たせます。

たとえばブログ記事に relatedPostsctaKindctaLabelctaUrl を持たせる。技術記事なら無料チートシートへ、チーム導入ならClaude Code研修・導入相談へ、テンプレートを探す読者なら教材一覧へ自然につなげる。Contentful側にCTAを持たせておけば、開発者がコードを触らなくても訴求を差し替えられます。

ただし、さっき自分が踏んだ地雷の繰り返しになりますが、CTAをRich Text内に自由入力させると計測IDもデザインも揺れます。収益導線は構造化したfieldにして、本文中の自然な内部リンクとは分ける。Claude Codeには、CTA component・analytics event・Contentful fieldの対応表まで作らせると、品質改善と有料導線の改善を同時に回せます。

よくある質問

Q. Delivery tokenだけで下書きプレビューはできませんか? できません。Content Delivery APIは公開済みentryしか返さないので、下書きは必ずnullになります。プレビューはPreview token + preview.contentful.com のセットが必須です。

Q. 日本語記事を作ったのに英語が表示されます。コードのバグですか? たいていコードは無実です。まずContentful側で、そのfieldがlocalizedになっているか、entryにja-JPの値が入っているか、fallback設定がどうなっているかを確認してください。9割はlocale設定で解決します。

Q. Next.jsの draftMode() で「awaitが要る」と怒られます。 Next.js 15以降で draftMode() がasync関数に変わったためです。const { isEnabled } = await draftMode() のようにawaitを付けてください。14時代の同期コードは動きません。

Q. AstroとNext.js、どっちで作るべき? 更新頻度で分けるのが楽です。記事メディアのように一度公開したら頻繁に変えないものはAstroのSSGで高速に。公開直後から何度も差し替えるLPはNext.jsのISRに寄せる。両方使う場合も、SDK初期化は1ファイルに集約してください。

Q. Management tokenをVercelの環境変数に置いて大丈夫ですか? NEXT_PUBLIC_ を付けなければサーバー側に留まるので置けます。ただしPATはユーザー権限そのものなので、本来はローカルの移行スクリプトやCIの管理ジョブに限定するのが安全です。表示側のランタイムでManagement APIを呼ぶ設計は避けてください。

実際に試した結果

何本かContentful連携を組んでみて、一番効いたのは「Claude Codeに最初からDelivery・Preview・Managementを混ぜるな、と言い切る」ことでした。これをやると、出てくる差分が驚くほど素直になる。逆に、トークン名を曖昧にしたまま実装させると、Preview tokenを公開取得に使ったり、localeを固定値で埋めたりする差分が混ざって、レビューで毎回拾うはめになりました。

冒頭の「日本語が消える」事故も、結局はコードじゃなくlocaleとtokenの境界が原因でした。だから今は、コードを書く前に表を1枚作る。どのAPIをどこで使い、どのtokenをどこに置き、どのlocaleを既定にするか。Contentful連携は、コード量より境界設計で品質が決まります。小さなブログモデルで検証して、プレビューと再検証が動くところまで見届けてから、LP・ドキュメント・多言語へ広げる。遠回りに見えて、これが一番事故らない道でした。

同じように「AIに任せると事故る」を境界設計で防ぎたいなら、教材一覧にテンプレートをまとめています。チームで一気に整えたいときは研修・導入相談もどうぞ。

#Claude Code #Contentful #ヘッドレスCMS #Next.js #Astro
無料

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。

Masa

この記事を書いた人

Masa

Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。