SSGサイトへ商品を一括投入し、CC0画像を安全に付けて一覧まで反映させる指示書
Next.js App Router + DB の商品カタログにスクリプトで商品をまとめて追加する手順。Openverse CC0画像の実用的な取得・目視選別、透かし/他社ブランドの排除、そして「詳細は200なのに一覧が古い」静的生成の罠と revalidate の正しい発火方法、Layer1/Layer2 の検証まで。
約4.6万トークンの節約 (API料金換算で約69円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「SSGサイトへ商品を一括投入し、CC0画像を安全に付けて一覧まで反映させる指示書」は、Web開発カテゴリのAI指示書(MDファイル)です。Next.js App Router + DB の商品カタログにスクリプトで商品をまとめて追加する手順。Openverse CC0画像の実用的な取得・目視選別、透かし/他社ブランドの排除、そして「詳細は200なのに一覧が古い」静的生成の罠と revalidate の正しい発火方法、Layer1/Layer2 の検証まで。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約4.6万トークン(API料金換算で約69円)・84%のトークンを節約できます。
- カテゴリ
- Web開発
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約5.5万トークン
- この巻物使用時
- 約9,000トークン
- 節約量
- 約4.6万トークン (約69円)
- 更新日
- 2026-08-28
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/ssg-cc0/raw を読み込んで、この指示書どおりに実装して"
中身
SSG(静的生成)ECサイトへ商品を一括投入し、フリー素材画像を安全に付けて「一覧まで」反映させる指示書
対象: Next.js App Router + Supabase(または任意のDB) で作られた商品カタログ/EC。 スクリプトからDBへ商品をまとめて追加し、画像をフリー素材で補い、公開ページに確実に出た状態で終わらせるまでの手順。
0. この指示書が防ぐ3つの事故
- 「詳細ページが200だから反映OK」の誤判定 — 一覧ページが古いまま=来訪者には存在しない商品になる。
- フリー素材の透かし・他社ブランド混入 — 商用サイトに載せてから気づくと差し替えコストが高い。
- キーワードが英語圏の古典画像に吸われる — CC0検索は美術館アーカイブに偏り、「それっぽいが業務内容と無関係」な画像を掴む。
1. 事前確認(着手前に必ず)
# 既存の slug 一覧・カテゴリ/シーンの enum・sort_order の最大値を先に取る
# 「似た商品が既にある」ケースが最も多い失敗。名前が違っても内容が重複していれば統合か差別化を決める。
- 追加予定の slug が既存と内容重複していないかを人が読んで判定する。重複していたら 「別カテゴリの別形態(例: 制作 vs レンタル)」として差別化するか、追加しない。
- カテゴリキー・シーンキーは型定義ファイルの enum を実際に読む(記憶で書くと表示から漏れる)。
sort_orderは既存の最大値を見て、今回の追加分を連番で確保する。
2. フリー素材画像(CC0/PDM)の取得
Openverse API は CC0/パブリックドメインだけを絞って取れる(帰属不要・商用可)。
https://api.openverse.org/v1/images/?q=<1〜2語>&license=cc0,pdm&size=large&page_size=12&mature=false
実務上の落とし穴と対処:
| 症状 | 原因 | 対処 |
|---|---|---|
| 0件になる | 多語ANDで絞られる | クエリは1〜2語にする |
| 骨董広告・浮世絵・古い版画ばかり | CC0は美術館/PDアーカイブに偏る | クエリを現代の物体名に寄せる(例: 「brochure」より「graphic design」「printing machine」) |
| 現地語の固有名詞が0件 | 英語タグしか付いていない | 一般名詞に置換(例: 屋台→street food、takoyaki のような世界的に通る単語は生きる) |
| ダウンロードが失敗する | ランタイムのfetchが弾かれる/シェルのクォート崩れ | execFileSync('curl.exe', [配列引数]) で叩く(& を含むURLは文字列連結で壊れる) |
1slugに複数クエリのフォールバックを持たせるのが要点。1巡目で全滅する前提で組む。
const Q = { "<slug>": ["<第1候補>", "<第2候補>", "<第3候補>", "<第4候補>"] };
// 各slugについて、必要枚数に達するまでクエリを順に試す
// 700px未満は捨てる / 1600px内側リサイズ + jpeg quality 85 で保存
3. 画像の目視検査(省略禁止・2段)
- モンタージュ: 取得した全候補を
slug × 候補のグリッド1枚に合成して1回の閲覧で全件見る。 ラベルと連番を焼き込むと、そのまま採用リストが書ける。 - 下部cropの拡大: 採用候補だけ、画像の下25%を切り出して拡大した1枚を作り透かしを確認する。 素材サイトの中には作品自体にwordmarkを入れている配布元がある。
不採用にする基準(機械では判定できないので人/AIが見る):
- 透かし・配布元のwordmarkが写っている
- 識別可能な他社ブランド(車・製品ロゴ・店名)が主題になっている
- 政治的な題材、特定の実在人物が主題
- 業務内容と無関係(キーワードの語義違いで来たもの)
最良の代替は「自社資産の流用」: 自社で撮った既存商品の写真があるなら、
ストレージ内コピー(例: Supabase Storage の copy(from, to))で新商品に流用する。
ライセンス問題がゼロで、内容も正確になる。人物ストック写真より優先する。
出典は必ずファイルに残す(license / source URL / title)。後から問い合わせが来たときの唯一の根拠になる。
4. 投入スクリプト
// 1) --dry を必ず実装する(名前・価格・カテゴリ・シーン・枚数を目で確認してから本番投入)
// 2) upsert 相当にする(slug で既存を引いて update / なければ insert)=再実行で重複を作らない
// 3) 画像はリサイズしてからアップロードし、公開URLを配列で持たせる
// 4) 説明文の末尾に共通の注記(見積の但し書き等)を機械的に付ける=書き忘れが起きない
商品説明は書き下ろす。素材サイトの説明文や他社サイトの文章を流用しない。
5. 反映(ここが最大の罠)
App Router の静的生成では、ページ種別で再生成のタイミングが違う。
| ページ | DB直接投入した直後の挙動 |
|---|---|
詳細 /products/[category]/[slug] | dynamicParams の既定でon-demand生成され200を返す(=反映されたように見える) |
| 一覧 / カテゴリ / シーン別 / トップ | ビルド時の内容のまま。新商品が出ない |
来訪者は一覧から辿るので、一覧に出ていなければ実質未公開。
発火のさせ方(デプロイ権限が無くても可):
- A. アプリ本来の書き込み経路を1回通す — 管理画面で商品を1件保存すると
Server Action 内の
revalidatePath("/", "layout")が走り、全ページが再生成される。 公開面を汚さないため「非公開フラグのダミー商品」を保存し、あとで削除する。 ブラウザ自動化(Playwright 等)でログイン→保存まで自動化できる。 - B. 恒久策: トークン認証付きの revalidate エンドポイントを用意する。
// app/api/revalidate/route.ts
import { NextRequest, NextResponse } from "next/server";
import { revalidatePath } from "next/cache";
export const dynamic = "force-dynamic";
function authorized(req: NextRequest) {
const expected = process.env.<既存の管理用パスワード等>; // 新しい秘密情報を増やさない
if (!expected) return false;
const given = req.headers.get("x-admin-password") ?? new URL(req.url).searchParams.get("token") ?? "";
return given.length === expected.length && given === expected;
}
async function handle(req: NextRequest) {
if (!authorized(req)) return NextResponse.json({ ok: false }, { status: 401 });
revalidatePath("/", "layout");
return NextResponse.json({ ok: true, at: new Date().toISOString() });
}
export const GET = handle; export const POST = handle;
投入スクリプトの最後にこのエンドポイントを叩かせる(新しい環境変数を増やさず既存の認証情報を使うのがコツ)。 エンドポイントが未デプロイの間は A で代替できる、と自分でログに出すところまで書いておく。
6. 検証(2段。どちらか欠けたら未完了)
Layer 1(ロジック層 / Node スクリプト)
- DB: 投入件数・総件数・
published・カテゴリ・シーンが既知キーのみ・価格>0・説明文の最低文字数 - 画像: 全公開URLに HTTP 200
- 本番HTML: 詳細ページに商品名・価格の表示形式(桁区切り)・画像ファイル名が含まれる
- 一覧ページのHTMLに
/products/<category>/<slug>へのリンクがある ← これを必ず入れる
Layer 2(ブラウザ層 / Playwright)
- 管理画面ログイン → 非公開ダミー保存で revalidate 発火
- カテゴリ一覧に新商品リンクが出るまでリトライ(再生成に数秒のラグがある。キャッシュバスターのクエリを付ける)
- 各詳細ページで
h1の文言・価格テキスト・imgの src を assert - シーン別・タグ別など別の導線ページも1つは確認する
- 後片付け: ダミー商品を削除
7. 完了報告のテンプレ
- 追加: N点(slug/価格/カテゴリの表)
- 画像: 出典と枚数、不採用にした理由
- typecheck: PASS
- Layer 1: <script> → PASS(一覧掲載の assert を含む)
- Layer 2: <script> → PASS(実描画)
- 反映: revalidate 発火済み(方式Aか B かを明記)
「ハードリロードして確認してください」「次のデプロイで出ます」は未完了。一覧に出たことを自分で確認して初めて完了。
よくある質問
+「SSGサイトへ商品を一括投入し、CC0画像を安全に付けて一覧まで反映させる指示書」とは何ですか?
Next.js App Router + DB の商品カタログにスクリプトで商品をまとめて追加する手順。Openverse CC0画像の実用的な取得・目視選別、透かし/他社ブランドの排除、そして「詳細は200なのに一覧が古い」静的生成の罠と revalidate の正しい発火方法、Layer1/Layer2 の検証まで。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約5.5万トークンかかりますが、この巻物を使えば約9,000トークンで済みます。差し引き約4.6万トークン(API料金換算で約69円)・84%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
Next.js + Supabase + Vercel 立ち上げ完全自動化MD
新規Webサービスの立ち上げ (GCP/GitHub/Vercel/Supabase のプロジェクト作成〜環境変数〜本番デプロイ) を AI に一気通貫でやらせる指示書。人間の作業はログイン1回だけ。
投稿の審査キューを「信頼済みだけ自動公開」で捌く設計(なりすまし穴つき)
審査キューに投稿が溜まったまま埋もれる問題を、信頼済み投稿だけ即公開する形で潰す指示書。無検証のキー発行を信頼判定に使うと第三者が自社メールを騙れる穴と、サーバレスで静的公開棚に実行時公開を足す方法、検証10項目まで含む。
DB型サイトを「一覧だけ会員限定・個別ページは残す」に切り替える指示書(Next.js App Router)
自社DBで集客していたサイトが競合のリスト抜き取りに気づいた時の改修手順。名前が並ぶバルクな一覧だけを会員限定にし、個別ページはtitle/H1とCTAを残す。ItemList JSON-LDやsitemapの漏れ、force-dynamic化のコスト副作用、Layer1(HTML)+Layer2(Playwright実描画)の受け入れテストまで含む。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア