部署内展開の設計と手順書 / 2026-08-21
対象: 情報システム(エンジニア側)・サービスを作る部署メンバー(非エンジニア側)
前提資産: cf-internal-app-starter(Cloudflare ネイティブの社内業務システム雛形・作成済み)
cf-internal-app-starter が既にある。
非エンジニアが自由なベースで作ったものを後から Workers に移す作業は、認証・DB・ファイル保存・ビルドの
4 箇所を全部書き直すことになり、「最低限のフォロー」には収まらない。| # | ご提示の案 | 本提案 | 変更理由 |
|---|---|---|---|
| 1 | E リポジトリを作成、pull したフォルダを (U) に共有 | E テンプレートからリポジトリ生成 → Codespace の URL を渡す | フォルダを渡すと PC 環境の差がそのまま問い合わせになる。URL 1本にする |
| 2 | U 構築テンプレート(スキル)で仕様書を作成 | 同じ(/service-spec) |
変更なし。ここが最も価値のある工程 |
| 3 | U サービス開発、ローカルで実行確認 | U Codespace 内で開発・確認 | 「ローカル」の実体を Codespace にする |
| 4 | E Cloudflare で動作するようにベース変更、社内共有化 | E 初回プロビジョニングと公開承認(ベース変更は不要) | 最大の変更点。最初から Cloudflare ネイティブで作る |
| 5 | U サービスの機能拡張 | 同じ | 変更なし |
| 6 | U 更新テンプレート(スキル)で Cloudflare に配信 | U /service-ship で試用環境へ自動配信 → 本番は申請 |
本番だけ人間の承認を挟む |
Step 0(一度きりの基盤整備)を追加します。ここを作らないと、アプリが 2 本目・3 本目に なった時点でエンジニアの手作業が線形に増えます。
Codespaces シークレットは環境変数としてコンテナに入るため、その Codespace を開ける人は
echo $VAR で値を読めます。したがって「見えないようにする」ことは原理的にできません。
デプロイ権限を持つ鍵は Codespace に置かないことだけが確実な分離になります。
| 工程 | 担当 | 所要 | 頻度 |
|---|---|---|---|
| Step 0 基盤整備(マーケットプレイス+テンプレート) | E | 半日 | 1回だけ |
| Step 1 リポジトリ生成・Cloudflare プロビジョニング | E | 30分 | アプリごと1回 |
| Step 2 仕様書作成 | U | 20〜30分 | アプリごと1回 |
| Step 3 開発・確認 | U | — | 反復 |
| Step 4 初回の社内公開(確認のみ) | E | 10分 | アプリごと1回 |
| Step 5 機能拡張 | U | — | 反復 |
| Step 6 試用環境への配信 | U | 5分 | 反復(自動) |
| Step 6' 本番公開の承認 | E | 5分 | リリースごと |
| 困りごとの一次切り分け | U | — | 随時(/service-fix) |
| 引き継がれた困りごとの解決 | E | — | 随時 |
Claude Code のスキルは、リポジトリの .claude/skills/ に置けばそのリポジトリを開いた
Claude Code が自動認識します。ただしアプリが増えるとスキルが各リポジトリに散らばるため、
プラグインとして 1 箇所にまとめ、マーケットプレイス経由で配ります。
synon/claude-plugins/ (プライベートリポジトリ)
├── .claude-plugin/marketplace.json
└── plugins/synon-internal-app/
├── .claude-plugin/plugin.json
└── skills/
├── service-spec/ ← 構築テンプレート
├── service-ship/ ← 更新テンプレート
└── service-fix/ ← 自己診断
同梱の synon-claude-code-kit.zip の plugin/ と marketplace/ をそのまま配置します。
テンプレート側の .claude/settings.json に extraKnownMarketplaces と
enabledPlugins を書いてあるので、利用者側の登録作業は不要です。
既存の cf-internal-app-starter に、キットの template/ を上書き適用します。
詳細な適用手順は template/APPLY.md。追加・差し替えるのは次の 7 ファイルです。
| ファイル | 役割 |
|---|---|
.devcontainer/devcontainer.json | Codespaces 設定。Claude Code を公式 feature で自動導入 |
.claude/settings.json | 権限の deny/ask/allow + マーケットプレイスの自動登録 |
.claude/hooks/pre-push-verify.sh | push 前に型チェックとテストを強制(exit 2 でブロック) |
START-HERE.md | 非エンジニアが最初に読む案内(Codespace 起動時に自動表示) |
CLAUDE.md(追記) | 「相手は非エンジニア」という前提を Claude に常時読ませる |
vite.config.ts(差し替え) | Codespaces の転送 URL / HMR 対応 |
.github/workflows/deploy.yml(差し替え) | main への直 push 禁止、保護ファイル検査を追加 |
そのうえで Settings → Template repository にチェックを入れます。
アカウント単位 Access を有効化する(all_workers + all_preview_workers)。
2026-08-14 に GA になった機能で、これを ON にするとアカウント内の全 Worker が既定で社内限定になり、
今後新しく作った Worker も自動的に保護対象になります。「新しいアプリを公開したら全世界に見えていた」
という最悪の事故を構造的に潰せます。ポリシーは既存の Google Workspace SSO 統合
(@synon.co.jp 限定)をそのまま使えます。
Static Assets を使う Worker では ctx.access が Worker に伝播しない仕様が明記されています。
したがって従来どおり Cf-Access-Jwt-Assertion ヘッダの JWT 検証
(src/worker/lib/access.ts。実装済み)が必要になります。
Worker 単位 Access 経由でこのヘッダが実際に付与されるかは、最初の 1 本で必ず実測してください。
付与されない場合は、自社ゾーンのカスタムドメイン(例 <app>.apps.synon.co.jp)に載せて
ホスト名ベースの Access アプリを作る方式に切り替えます。ただし synon.co.jp の NS は現在 Xserver にあり、
Cloudflare DNS への移管が前提になります(既存の移行案件と同じ依存関係)。
claude setup-token # 有効期間1年の OAuth トークンが標準出力に出る
これを Organization の Codespaces シークレット CLAUDE_CODE_OAUTH_TOKEN に登録します。
~/.claude は Codespace の stop/start では残りますがコンテナの rebuild で消えるため、
トークンをシークレットに置いておかないと利用者が再ログインを求められます。
前提として Claude Pro / Max / Team / Enterprise のシートが必要です。無料プランに Claude Code は含まれません。
gh repo create synon/<アプリ名> --private --template synon/cf-internal-app-template
gh repo clone synon/<アプリ名> && cd <アプリ名>
wrangler.jsonc の名前を 6 箇所書き換える(name / env.staging.name / D1 名 ×2 / R2 名 ×2)ai のブロックを削除する。どちらも remote: true = ローカル開発でも
Cloudflare の実リソースに接続するため、残すと Codespace に Cloudflare の鍵が必要になり、本提案の鍵分離が崩れます。
AI 検索が必要になった時点でエンジニアが個別に判断してください。npm run bootstrap(D1 / R2 / KV を作成し、ID を wrangler.jsonc に書き戻す)main に branch protection(PR 必須 / 承認1名 / バイパス禁止)
← これが本番公開の承認ゲート。GitHub Team 以上が必要(§6「GitHub のプラン要件」)staging / production を作成(環境別シークレットと監査のため)。
※ production の Required reviewers はプライベートリポジトリでは Enterprise Cloud 限定で
Team では設定できないため、承認は上の branch protection で担保するCLOUDFLARE_API_TOKEN / CLOUDFLARE_ACCOUNT_IDSTAGING_URL / PRODUCTION_URLstaging ブランチを作成して pushwrangler.jsonc の ACCESS_AUD に記入npm run deploy:staging で初回デプロイ、URL を確認利用者に渡すのは リポジトリの URL 1本だけです。
Account Settings:Read / Workers Scripts:Edit / Workers KV Storage:Edit / Workers R2 Storage:Edit / D1:Edit / Workers Routes:Edit / User Details:Read / Memberships:Read。 D1 は Workers Builds の既定トークンに含まれないため、明示的に追加する必要があります。
利用者は GitHub でリポジトリを開き、Code → Codespaces → Create codespace を押すだけ。
数分で作業環境が立ち上がり、START-HERE.md が自動で開きます。
ターミナルで claude → /service-spec。
このスキルの設計方針:
/service-ship の合格判定になる[要E確認] を立ててエンジニアに回す成果物は docs/SPEC.md。この仕様書は読み物ではなく、配信時に機械的に照合される契約である点が重要です。
仕様書の承認後、Claude が「画面が 1 枚立ち上がって動くところまで」を作ります。 全機能を一気に作らせない設計にしてあります(スキル内で明示的に禁止)。
確認は VS Code 下部の PORTS タブから 5173 を開きます。
アドレスバーに localhost:5173 と入力しても開きません。Codespace は利用者の PC ではなく
クラウド上にあるためです。START-HERE.md と /service-fix の両方でこれを案内しています。
以降は「一覧に申請日の列を足して、新しい順に並べて」のように日本語で伝えるだけです。
Step 1 で既に Cloudflare 上に出ているため、ここでやることはベース変更ではなく確認だけです。
@synon.co.jp でログインして画面が出ることを確認/cdn-cgi/access/get-identity を開き、groups が取れていることを確認Step 3 と同じ。docs/SPEC.md を更新しながら 1 機能ずつ足します。
仕様書にないことを Claude が勝手に実装しないよう、CLAUDE.md で禁止しています。
利用者が /service-ship と打つと、次が自動で走ります。
| # | 内容 | 落ちたら |
|---|---|---|
| 1 | 変更内容を日本語で要約して確認 | — |
| 2 | 型チェック / テスト / ビルド | 止まる |
| 3 | 秘密の値の混入検査 | 止まる |
| 4 | 保護ファイル(wrangler.jsonc .github/ access.ts)の変更検査 | 止まる |
| 5 | 既存マイグレーションの改変検査 | 止まる |
| 6 | 全 API が requireAccess 配下にあるか | 止まる |
| 7 | ログに個人情報が出ていないか | 止まる |
| 8 | docs/SPEC.md の受入条件との突き合わせ | 未達を提示して判断を仰ぐ |
全部通ると staging ブランチへ push → GitHub Actions が試用環境へデプロイ →
gh run watch で見守り → 試用環境の URL を利用者に提示します。
利用者が「本番に出したい」と言った場合のみ、本番公開の PR を作ります。 受入条件が全て満たされ、試用が済んでいることが条件です。Claude は PR をマージしません。
エンジニアは PR を見て、Actions の保護ファイル検査の警告を確認し、マージします。
この「マージ」が本番公開の承認そのものであり、main への push で本番デプロイが走ります。
デプロイ → スモークテスト → 失敗時は自動ロールバック。
当初は GitHub Environments の Required reviewers で承認を挟む設計にしていましたが、 プライベートリポジトリで Required reviewers を使えるのは Enterprise Cloud のみ(Team でも不可) であることが分かったため、承認を PR マージの一点に集約しました。詳細は §6。
「非エンジニアが自走する」ことの前提は、壊せないようにしておくことです。 1 層でも欠けると、いずれ必ず事故が起きます。
| Codespaces | Docker Desktop + devcontainer | ローカル Node 直接 | |
|---|---|---|---|
| 利用者 PC への導入 | ゼロ | Docker Desktop | Node / npm / git |
| 環境差分の問い合わせ | 起きない | 起きる(メモリ設定・WSL) | 頻発 |
| 壊れたときの復旧 | 作り直すだけ | 再ビルド | 手作業 |
| Claude Code の導入 | 公式 feature で自動 | 同左 | 手動 |
| 費用 | 従量(組織に無料枠なし) | 無料 | 無料 |
| Claude Desktop から使えるか | 使えない(§7) | 使える | 使える |
導入摩擦がゼロであることの価値が、月数十ドルの従量課金を上回ります。
既存の cf-internal-app-starter は Docker 前提で作られていますが、.devcontainer/ が
空のままなので、Codespaces 対応の追加は差分が小さく済みます。
「まず作らせて、あとで移す」を選ばない理由は、移す作業がエンジニアの片手間に収まらないからです。
| 非エンジニアが自由に作ったとき | Cloudflare へ移すときにやり直す作業 |
|---|---|
| 自前のログイン画面 | Cloudflare Access の JWT 検証に全面書き換え |
| SQLite / Postgres へ直接 SQL | D1 のバインディング+マイグレーション体系に移植 |
| ローカルディスクにファイル保存 | R2 + Worker 経由の権限チェックに書き換え |
| Express / Next.js のサーバ | Workers のランタイム制約(CPU 時間・Node API)に適合させる |
.env に API キー | Secrets Store に移す |
移行作業は「動くものを動かなくして直す」工程になるため、利用者からは後退に見え、 エンジニアからは終わりの見えない作業に見えます。最初から正しいベースで始めれば、この工程は消えます。
| 項目 | Free | Paid |
|---|---|---|
| D1 データベース数 | 10 | 50,000 |
| CPU 時間 / 呼び出し | 10 ms | 30 秒 |
| リクエスト | 100,000/日 | 月1,000万込み |
| Worker 数 | 100 | 500 |
| Subrequests / 呼び出し | 50 | 10,000 |
| D1 書き込み行数 | 10万行/日 | 月5,000万行込み |
一方、Static Assets のリクエストは全プランで課金対象外・無制限です。 画面(HTML / JS / CSS / 画像)の配信は一切カウントされず、課金対象は API が実行されたリクエストのみ。 社内アプリの規模では $5/月で収まります。
Codespaces 自体はプライベートリポジトリでも全プランで使えます。公開・非公開でプラン上の可否の差はありません。 個人アカウント所有のプライベートリポジトリなら、読み取り権限があれば誰でも Codespace を作れます (無料枠の残量か支払い方法の設定は必要)。問題は Organization 所有のプライベートリポジトリで 本提案の要件を満たせるかです。
| 要件 | Free for organizations | Team | Enterprise Cloud |
|---|---|---|---|
| プライベートリポジトリで Codespaces を使う | ○(各自負担・無効化もできない) | ○ | ○ |
| 組織が Codespaces 費用を支払う | × | ○ | ○ |
| 組織ポリシー(マシンタイプ / タイムアウト / ポート可視性 / 保持期間) | × | ○ | ○ |
| Codespaces の監査ログ | × | ○ | ○ |
| Codespace の組織所有(退職者の環境を stop / delete できる) | × | ○ | ○ |
| prebuild | × | ○ | ○ |
| リポジトリ / 組織レベルの Codespaces シークレット | × | ○ | ○ |
| プライベートリポジトリの branch protection / rulesets | × | ○ | ○ |
| プライベートリポジトリの Environments / 環境シークレット | × | ○ | ○ |
| Environments の Required reviewers(プライベート) | × | × | ○ |
GitHub Team($4/user/月)が最低ラインです。Free organizations では次が同時に成立せず、本提案の設計が崩れます。
CLAUDE_CODE_OAUTH_TOKEN を全員が各自の個人シークレットに手で登録することになる当初は本番デプロイの承認を GitHub Environments の Required reviewers で行う設計にしていましたが、 プライベートリポジトリで Required reviewers(および Wait timer)を使えるのは Enterprise Cloud のみ であることが分かりました(Team でも使えません)。
そのため本提案では、main への PR に承認1名を必須にする branch protection を承認ゲートとし、
「エンジニアが PR をマージする行為」が本番公開の承認そのものになる設計に統一しています。
これは Team で成立し、非エンジニアから見ても「申請 → 承認 → 公開」が1本の線で追えるため、むしろ分かりやすくなります。
Enterprise Cloud を使う場合のみ、マージ後にもう一段の承認を追加できます。
| user-owned(各自負担) | organization-owned(組織負担) | |
|---|---|---|
| 無料枠 | 各自の個人枠が効く(Free 120コア時間 / Pro 180コア時間・月) | 無料枠なし。1コア時間目から課金 |
| 組織のポリシー・監査ログ | 効かない | 効く |
| 退職者の Codespace | 組織は stop も delete もできない(ソースを含む環境が個人アカウントに残る) | 組織が停止・削除できる |
organization-owned にしてください。無料枠は失われますが、退職時にソースコードを含む作業環境を 確実に回収できることの方が重要です。有効化には支払い方法の登録と 0 以外の Spending limit 設定が必須で、 これをしないとポリシー設定画面そのものにアクセスできません。
| 項目 | 金額 | 備考 |
|---|---|---|
| Cloudflare Workers Paid | $5 | アカウント全体で1本。全アプリ共通 |
| GitHub Codespaces | $20〜40 | 2コア $0.18/h。5人 × 20〜40h。組織所有には無料枠なし(個人所有なら各自の枠が効くが管理権を失う) |
| Codespaces ストレージ | $3〜7 | $0.07/GB月。使わない Codespace は削除する |
| GitHub Team | $4/user | 必須。Free 組織ではプライベートリポジトリの branch protection・rulesets・Environments・組織支払い・ポリシー・監査ログ・組織シークレットがすべて使えない |
| Claude シート | 既存 | Pro / Max / Team のいずれかが必要 |
合計 $50〜80/月 程度。アイドルタイムアウトを既定 30 分から 15 分に縮め、 保持期間を 7 日に設定すると Codespaces の費用は半分近くまで下がります。
開発と実行の工程は完結しません。
npm install も wrangler dev も通らないため、開発サーバを立ち上げられません。ただし工程 2(仕様書作成)だけは Claude Desktop でも成立します。
仕様書はテキストの読み書きだけで完結するため、フォルダを接続して /service-spec を
実行すれば同じ成果が得られます。
迷いを生まないため、全工程を Codespace の中に統一してください。 入口が 2 つあると「どっちでやるんでしたっけ」が必ず問い合わせになります。
| 失敗モード | 兆候 | 対策(本提案での手当て) |
|---|---|---|
| 仕様書が読み物になり、実装と乖離する | SPEC.md が更新されない | 受入条件を /service-ship が機械的に照合する。乖離すると配信時に必ず露見する |
| 1つのアプリが際限なく膨らむ | 「ついでにこれも」が続く | 仕様書の「今回やらないこと」を必須にし、Claude が仕様外の実装を拒否する |
| 利用者が Codespace を放置して作業が消える | 30日後に自動削除 | START-HERE.md で「終わるときは必ず /service-ship」と明示。保持期間を明示的に設定 |
| テンプレートを改善しても既存リポジトリに反映できない | 共通コードのバグが横展開できない | テンプレートから生成したリポジトリは履歴が無関係になり PR で流し込めない。最初の3本はテンプレートが固まるまで様子見。将来は共通部分を社内 npm パッケージ化 |
| GitHub が Free 組織のまま始まる | branch protection が設定できない | Team($4/user)を先に契約する。Free 組織ではプライベートリポジトリの branch protection / rulesets / Environments / 組織シークレットがすべて使えず、層3のガードレールが機能しない |
| Zero Trust の 50 シートが枯渇し、51人目がログインできない | 突然ログイン不能 | 退職者のシート回収を運用に組み込む(既存の移行案件と同じ課題。Google Workspace は SCIM 非対応で自動解放されない) |
| D1 が 10 個上限に当たる | 6本目のアプリで bootstrap が失敗 | Workers Paid($5/月)へ。Free 前提で稟議を通さない |
| Codespaces の費用が想定を超える | 月末に請求が跳ねる | 組織の Spending limit を設定。アイドル 15 分・保持 7 日に短縮 |
| エンジニアが本番承認のボトルネックになる | PR が滞留する | 承認者を最低2名。試用環境は承認不要なので業務は止まらない |
| 利用者が「エラーが出た」としか言えない | 問い合わせが増える | /service-fix で症状から切り分け、引き継ぎメモを自動生成してから相談させる |
1本目で運用が回ることを確認してから広げてください。
| 週 | やること | 判断ポイント |
|---|---|---|
| 1週目 | Step 0(基盤整備)+ 検証用アプリを1本、エンジニア自身が通しで作る | Access の JWT ヘッダが実際に付与されるか(要実機確認)を潰す |
| 2週目 | 意欲の高い1名に1本作ってもらう。エンジニアは横で見るだけ | どこで詰まるか観察し、START-HERE.md とスキルに反映 |
| 3〜4週目 | 同じ1名が機能拡張と本番公開まで通す | エンジニアの実所要時間を実測する |
| 5週目以降 | 部署内へ展開 | テンプレートの改善が落ち着いてから量産に入る |
撤退・見直しの基準: 2週目の1名が仕様書作成まで到達できない場合、スキルの質問設計に問題があります。
展開せず /service-spec の questions.md を作り直してください。
synon-claude-code-kit.zip
plugin/ Claude Code プラグイン(スキル3本)
├── .claude-plugin/plugin.json
└── skills/
├── service-spec/ 構築テンプレート(SKILL.md / questions.md / spec-template.md)
├── service-ship/ 更新テンプレート(SKILL.md / checklist.md)
└── service-fix/ 自己診断(SKILL.md)
marketplace/ 社内マーケットプレイス定義
template/ テンプレートリポジトリへの追加・差し替えファイル
├── APPLY.md ★ 適用手順はここから
├── .devcontainer/devcontainer.json
├── .claude/settings.json
├── .claude/hooks/pre-push-verify.sh
├── .github/workflows/deploy.yml
├── START-HERE.md
├── CLAUDE.md.append.md
├── vite.config.ts
└── docs/SPEC.md
Cf-Access-Jwt-Assertion
ヘッダが実際に付与されるか。公式は「Static Assets 併用時は ctx.access が伝播しない」
としか書いておらず、ヘッダの有無は明記されていません。Step 0 で必ず実測してください。*.workers.dev を直接登録できるか。
Workers 側のドキュメントは可能と読めますが、Cloudflare One 側は「アカウント内のアクティブなゾーン」を
要求しており記述が食い違っています。Worker 単位 Access を使えば回避できます。wrangler d1 migrations apply の --remote 要否。
wrangler v4 は全コマンドが既定ローカル動作になりましたが、migrations のリファレンスには
--remote の記載がありません。同梱の deploy.yml は --remote を明示していますが、
初回デプロイで実際の挙動を確認してください。