---
title: "技術構成の決定 — 何を選び、何をやめ、どうなったら見直すか"
type: operation
status: decided
version: v1（2026-08-09。2つの独立レビュー＋実測に基づく裁定。**当初案から変更している**）
gardener_generated: false
maintained_by: "手動（澤田）"
last_synced: "2026-08-09"
updated: "2026-08-09"
confidence: high
tags: [cross_border, 技術選定, 需要エンジン, 意思決定記録]
related: ["[[25-demand-engine-v2-plan]]", "[[24-benchmark-research-metoree]]", "[[08-需要エンジン-実装計画たたき台]]"]
---

> ## この資料の状態
>
> - **参考です。お急ぎではありません。**
> - §8 の確認事項のうち「GitHub の入れ物」は解決済みです（会社名義の Organization に移設済み）。残りは急ぎません
>
> いま全体で何が動いているかは、共有ページの「いま動いていること」をご覧ください。
> （この欄は共有ページと同じ内容が自動で入ります。2026/10/2時点）

---


# 技術構成の決定

> **この文書の役割**：後から参加する方が、同じ議論を最初からやり直さずに済むようにすること。
> だから「何を選んだか」だけでなく、**「何をやめたか」「なぜやめたか」「どうなったら覆すか」**まで書きます。

---

## 0. 結論

**Cloudflare は使います。ただし Next.js はやめて、静的サイト生成（Astro）に変更します。**

| 層 | 決定 | 当初案からの変更 |
|---|---|---|
| 置き場所 | **Cloudflare** | 変更なし |
| 公開ページ（入口B） | **Astro で事前に HTML を作り置き**して配信 | **変更**（Next.js のサーバー側生成をやめる） |
| 動的な処理 | **小さな Worker を3本**（検索／引合／記録） | **変更**（1つの大きなアプリをやめる） |
| 企業別リンク（入口A） | **別のホスト名・別の Worker** | **変更**（同居をやめる） |
| データベース | **Cloudflare D1**。用途ごとに分ける | 一部変更（1つに同居させない） |
| 商品マスタ | **Google スプレッドシートが正本。作り置きの時に読む** | **変更**（ページ表示のたびに読むのをやめる） |
| 監視 | **Google Apps Script で5分ごとに外から確認 → 既存の Chat へ通知** | 新規（監視サービスを契約しない） |
| 翻訳 | 機械翻訳 → **シートの status 列を人が承認** → 次の作り置きで公開 | 新規（既存の承認作法をそのまま複製） |

**費用：開発中は0円。公開時に Cloudflare の有料プラン（アカウント月5ドル）へ上げることを推奨します**（理由は §4）。

---

## 1. どうやって決めたか

**当初の案（Cloudflare + Next.js）は、実際に動くところまで作りました。** そのうえで、決定を確定させる前に**2つの独立した批評**にかけています。

| 誰が | 何を渡したか | 役割 |
|---|---|---|
| **AI-1（Fable 5）** | 要件だけ。**現在の案は伏せた** | 「制約が何もない前提で最適解を3案以上出せ」 |
| **AI-2（Codex GPT-5.6）** | 要件＋現在の案 | **「この決定を壊しに行け。擁護するな」** |

**結果、2つは独立に同じ結論へ到達しました**——「Cloudflare は維持。Next.js をやめて静的生成へ」。

片方は白紙から設計し、もう片方は現案を攻撃した結果です。**別の道から同じ場所に着いたので、採用します。**

> 補足：AI の意見が一致したことは「正しさ」の傍証にはなりますが、「唯一の正解」の証明ではありません。だから §6 に「どうなったら覆すか」を書いています。

---

## 2. なぜ Next.js をやめたのか（4つの理由）

### 理由1：無料プランの計算時間が足りない

Cloudflare の無料プランは **1リクエストあたり CPU 10ミリ秒**です（[公式](https://developers.cloudflare.com/workers/platform/limits/)）。有料プランは **30秒**——3000倍の差があります。

そして Cloudflare 自身が「**認証・サーバー側での画面生成・大きなデータの解析は通常10〜20ミリ秒を消費する**」と説明しています。**Next.js の画面生成は、無料枠の10ミリ秒に収まらない可能性が高い。**

**怖いのは壊れ方です。** 小さなテストでは正常に動くのに、**商品が増えた時や同時アクセスが重なった時だけ、企業向けカタログが断続的にエラーになる**。原因を特定しにくく、非エンジニアの一次対応では手に負えません。

**静的生成なら、閲覧時にプログラムが動きません。** この制限と無関係になります。

### 理由2：壊れ方が根本的に違う

これが決め手です。

| | Next.js（一体型） | 静的生成（分割型） |
|---|---|---|
| 失敗するタイミング | **閲覧された瞬間**（＝営業時間中） | **作り置きの時**（＝人が見ていない時） |
| 失敗したときサイトは | **落ちる** | **前回の版が出続ける** |
| 一次対応の手順書 | 「今すぐ直す」 | **「表示は生きているので翌営業日に AI と直す」** |

濱風さまの体制は「**一次対応は非エンジニア3名／実装者は平日日中に対応できない**」でした（8/5 決定 D4）。

**この条件に構造的に答えられるのは、静的生成の方だけです。**

### 理由3：「AI に読ませて直す」との相性

Next.js は AI がいちばん書き慣れたフレームワークです。**学習データの量だけなら1位。** ですが——

**2022年に設計思想が入れ替わり（Pages Router → App Router）、以後も年1回のペースで大きな更新が入っています。** AI の学習データには新旧の書き方が混在しており、**AI が混ぜて書いたコードは「動くけれど微妙に壊れている」**という、非エンジニアに最も見つけにくい壊れ方をします。エラーメッセージも専門的で、素人が読んで意味を取るのが困難です。

静的生成ツールの更新は**作り置きの時だけの関心事**で、配信されるのは素の HTML です。サーバーと違い「セキュリティ更新に追われて上げざるを得ない」圧力がないため、**バージョンを固定して年1回だけ計画的に上げる**運用が成立します。

### 理由4：「既存が Next.js だから揃える」は、実は根拠が弱かった

当初の理由の1つが「既存のサプライヤー登録フォームが Next.js だから、揃えれば系が増えない」でした。**これは検証の結果、成立しませんでした。**

- 既存フォームは**入力・検証・送信**が中心。新サイトは**公開・検索・多言語・計測**が中心。**壊れ方が違うものを、同じ籠に入れているだけ**
- しかも既存フォームは Vercel、新サイトは Cloudflare。**同じ Next.js でも、配置・環境変数・キャッシュ・障害対応が全部違う**ため、運用上は同じ系になりません
- 「package.json に Next.js と書いてある」だけでは保守の手間は下がりません

---

## 3. 検討して採らなかったもの（不採用の理由）

**「なぜそれを選んだか」より、「なぜ他をやめたか」の方が後で効きます。**

### 3-1. Vercel（当初の想定）— 不採用

**規約上、無料プランで商用利用ができません。** 公式に明記があります。

> Hobby teams are restricted to **non-commercial personal use only**. All commercial usage ... requires either a Pro or Enterprise plan（[Vercel](https://vercel.com/docs/limits/fair-use-guidelines)）

有料は **1ユーザーあたり月20ドル**。元の社内要件「月額固定費¥0」と正面から衝突します。
**これは h3yun のサプライヤーフォームにも今かかっている問題**です（同じ移行で解消します）。

### 3-2. Next.js + マネージドDB の一体型 — 不採用

§2 の4つの理由。加えて Supabase の無料プランは **500MB 上限・無操作1週間でプロジェクト停止**で、お客様に見せるものには使えません。

**ただし、この案が勝つ条件があります**（§6 に記載）。

### 3-3. 格安レンタルサーバー（VPS + Django 等）— 不採用

月650円程度と安く、フレームワーク自体は非常に安定しています。**落とした理由は体制です。**

**サーバーは「ディスクが一杯」「証明書切れ」「OS更新後に起動しない」という、リポジトリの外側で壊れます。** この壊れ方は「AI にファイルを読ませて直す」の範囲外で、SSH 接続とコマンド操作という前提スキルが要ります。**非エンジニア3名の一次対応が成立しません。**

### 3-4. Google Apps Script だけで作る — 不採用（ただし境界の確認になった）

系を1つも増やさない極限の案で、費用も0円。**しかし公開URLが `script.google.com` 配下に限られ、独自ドメインも検索エンジン対策も実質できません。**

**入口B（検索から見つけてもらう）が成立しないため失格**です。この案の意義は、「系を増やさないことを極限まで優先すると、検索流入が死ぬ」という境界を示したことにあります。

### 3-5. スプレッドシートとデータベースの双方向同期 — 不採用

同じ行を両側で直したときにどちらが勝つか、という問題（競合解決）がバグの温床になります。しかも同期のバグは「**静かにデータが食い違う**」という、AI にも人にも最も見つけにくい壊れ方をします。得られるものは片方向と大差ありません。

### 3-6. スプレッドシートをやめて管理画面を作る — 不採用（当面）

**回っている業務を止めて作り直すことになります。** スタッフの再教育、ログイン認証の新設、新しい系の追加。数百社・数千点になって「同時編集の衝突」「入力検証」「変更履歴」が実害になった時に、初めて検討します。

### 3-7. 精密な行動計測（マウスの動き・クリック座標・画面録画）— 不採用

計測は3段階あります。

| 段階 | 内容 | 採否 | 理由 |
|---|---|---|---|
| **A. サーバー側の記録** | 誰がどのページを開いたか | **採用** | 広告ブロッカーや社内プロキシで落ちない。**唯一「欠測しない」層** |
| **B. 表示秒数・スクロール深度** | 商品カードが画面に何秒映ったか | **保留（判断待ち）** | 取れるが**数割落ちる**。営業材料としては有効 |
| **C. マウス移動・クリック座標・画面録画** | 画面上の細かい動き | **不採用** | 下記3点 |

**C を採らない理由：**

1. **判断に使えないのに、管理義務だけ増えます。** 個人の行動記録に近づくため、対象地域によっては同意の取得・保存期間・削除要求への対応が必要になります。**対象地域が未確定な今、先に集めると「使えないが管理しなければならないデータ」が発生します**
2. **既に要件で禁止しています**（画面録画・無制限の自動収集はしない）
3. **A+B で「どの会社が、どの商品を、どれだけ見たか」まで分かります。営業が動くにはそれで足ります**

**そしてより本質的な理由があります。** キーエンスが強いのは計測の精度ではなく、**閲覧の記録を「誰がいつ電話をかけるか」に変換する仕組み**を持っているからです。濱風さまの要件には、まだこの変換（誰が反応を受け取り、何営業日以内に動くか）が定義されていません。

**粒度を上げるより、この変換を先に決めるほうが効きます。** 42秒見た会社が分かっても、電話する人がいなければ何も起きません。

---

## 4. 費用 — 「月0円」をどこまで守るか

### 実額（2026-08-09 に公式ページで確認）

| 項目 | 無料枠 | 超えたら |
|---|---|---|
| **静的ページの配信** | **無料・無制限**（"Requests to static assets are free and unlimited"） | — |
| 動的な処理（Worker） | 10万リクエスト/日 | 停止（エラー1027） |
| データベース（D1） | **1つあたり500MB**／読み500万行・書き10万行/日 | 停止 |
| 作り置き（GitHub Actions） | 2,000分/月 | — |
| 監視（Apps Script） | 1日90分の実行 | — |
| スプレッドシート読み取り | 300回/分 | ※**2026年後半から超過分の課金予定**という注記あり（年1回の点検対象） |
| 機械翻訳 | 50万文字/月 | 100万文字あたり20ドル |
| **合計** | **0円/月**（＋ドメイン年額の実費） | |

### 🔴 ただし、公開時は有料プラン（月5ドル）を推奨します

**理由は「止まるから」ではなく、「止まったときに誰も対応できないから」です。**

無料プランは、上限を超えると**製品ごとに違う挙動をします**——Worker は停止、D1 も停止、R2 は課金。**「全部止まる」でも「全部課金」でもないので、非エンジニアの一次対応には向きません。**

そして最悪の形はこれです——**行動ログが増えて書き込み上限を食い尽くすと、同じ枠を使っている「引合の保存」まで止まります。** 商品は見えているのに、問い合わせだけが静かに消える。

**月5ドルを節約するために、引合の受付を丸一日止める設計は、事業判断として逆転しています。**

有料にすると変わるもの：計算時間 **10ミリ秒 → 30秒**（3000倍）、データベース **500MB → 10GB**、静的ファイル数 **2万 → 10万**（数千商品×6言語だと2万に近づきます）。

**開発中は0円のまま進め、公開の直前に上げます。**

---

## 5. 決めた構成の中身

### 5-1. 全体像

```
        [ Google スプレッドシート ]  ← スタッフが status 列で承認（今までどおり）
                    │ 作り置きの時だけ読む（一方向）
                    ▼
   ┌────────────────────────────────┐
   │  1つのリポジトリ・1回の作り置き   │
   └───────┬────────────────┬───────┘
           ▼                ▼
   [ 入口B・公開面 ]     [ 入口A・企業別 ]
   www.example.com       c.example.com     ← ホスト名を分ける
   静的HTML（無料・無制限）  Worker がトークン照合
           │                │
           └───────┬────────┘
                   ▼
        [ 小さな Worker API 3本 ]
        検索 / 引合 / 記録
                   ▼
              [ D1 ]  用途ごとに分離
```

### 5-2. なぜ入口A と入口B を分けるのか

**同じ場所に置くと、4種類の事故が起きます。**

1. **企業別リンクが検索結果に載る** — 検索避けの指定は「クロール禁止」と「索引禁止」が別物で、片方だけだと URL が検索結果に残ることがあります。**ホストを分ければ、A面の全応答に機械的に検索避けヘッダを付けられる**ので、付け忘れという人為ミスが構造的に消えます
2. **需要データが濁る** — 入口A は「表示順をランダム固定して順位の影響と本当の需要を分離する」**実験装置**です。入口B の匿名アクセスと混ざると、事業の核であるデータが汚れます
3. **トークンが漏れる** — A面からメーカー公式サイトへリンクを踏むと、リンク元情報にトークン付きURLが渡ります。A面全体にリンク元を送らない指定を敷きます
4. **キャッシュの取り違え** — 設定を1つ間違えると、A社向けページが別の会社に返ります

**リポジトリは1つ、ホスト名は2つ。** これで「二重管理」と「事故」の両方を潰せます。

### 5-3. スプレッドシートを「ページ表示のたびに読む」のをやめた理由

Google のスプレッドシート読み取りは、**サービスアカウント1つあたり毎分60回**の制限があります。1ページで4回読む設計だと、**毎分15ページで上限**に達し、以降のお客様には空の商品一覧が返ります。

**作り置きの時だけ読む形に変えます。** スプレッドシートが正本であることは変わりません。作り置きに失敗しても、**前回の版が配信され続けます**（＝スプレッドシートの障害がサイトの障害に伝染しない）。

**代償**：反映が即時ではなくなります（シート内に「今すぐ反映」ボタンを置いて数分、押さなければ翌朝）。

---

## 6. どうなったら、この決定を見直すか

**この推奨は「読み物が9割・書き込みはログだけ・非エンジニアが保守」という性質に全面的に依存しています。** 次のどれかが成立したら、判断は変わります。

> ⚠ **2026-08-09 訂正**：当初この表に「**バイヤーのログイン制が v1 に入る → Next.js が妥当**」と書いていましたが、**誤りでした**。
> Astro は**ページ単位で静的と動的を切り替えられ**、さらに **Server Islands** で「静的なページの中に、その人だけの部分を後から差し込む」ことができます（[Astro 公式](https://docs.astro.build/en/guides/server-islands/)）。
> **したがって「ログインの有無」では分かれません。分かれ目は「主戦場がログイン後にあるか」です。**
> 検索から集めるのが主戦場で、ログインが価格を見るための導線なら、**Astro のままが最適**です。詳細は [[27-gating-and-identity-options]]。

| 条件 | どう変わるか |
|---|---|
| **主戦場がログイン後に移る**（会員向けの業務画面が中心になり、公開面がおまけになる） | 閲覧者ごとに画面が変わるページが大半を占めるので、静的生成の利点が消える。一体型フレームワーク（月20ドル）が妥当になる |
| ~~企業別の価格出し分けが必要になる~~ → **Astro のままで可能**（Server Islands） | 変更不要 |
| **「シートを直したら数秒で反映」が業務要件になる** | 作り置き方式が成立しない |
| **日本語の高度な全文検索が中核価値になる** | D1 だけでは苦しく、検索専用の系を足すことになる（系を増やさない原則と衝突） |
| **商品が数千点×6言語になる** | 静的ファイル数が無料枠2万に近づく。有料プラン（10万）へ |
| **決済を載せる** | Cloudflare 無料プランは「無料サービス上でのカード情報の処理・収集」を禁止しているため、要再確認 |

---

## 7. 残るリスク（構成を変えても消えないもの）

1. **メールのセキュリティ検査が需要データを汚染する** — 送信直後にスキャナが全トークンURLを開き、50社全部が「閲覧済み」になる。**サーバーへのアクセスだけで閲覧扱いにしない**設計が必須（ブラウザ側の操作確認と組み合わせ、機械アクセス疑いを別区分で保存）
2. **英語の列がない** — スプレッドシートは日本語と中国語のみ。翻訳・承認・**更新後の再承認**の工程が未設計。仕様が更新されたのに英語ページが旧訳のまま、という食い違いは本番停止条件になります
3. **引合の二重登録・消失** — 保存は成功したのに応答だけ切れると、再送で二重になるか、送らなければ消える。**重複防止番号**が必要
4. **日本語の全文検索の品質が未検証** — D1 で全文検索は使えますが、日本語の区切り方は要実測。**商品100件・外国語クエリ50件で人が採点する**必要があります
5. **対象地域が未確定** — 保存する項目・保持期間・削除手順が決められません。入口B の計測は Cookie なしの匿名から始めて判断を後ろに送れますが、解決はしません
6. **監視ログは3日で消える**（無料プラン）— 金曜の障害を月曜に調べると一部が消えています。外形監視だけでなく、上限到達・引合保存失敗をその場で Chat へ流す必要があります

---

## 8. 濱風さまに確認したいこと

| # | 確認 | なぜ |
|---|---|---|
| 1 | **会社名義の GitHub Organization を作っていただけますか** | 8/5 の D2 で「最初のリポジトリを作る直前に作る」と決定済み。**今がその時期**です |
| 2 | **Cloudflare のアカウントも会社名義で作りますか** | 同じ考え方でよければ、そのまま公開まで進めます |
| 3 | **公開時に Cloudflare 有料プラン（アカウント月5ドル）を承認いただけますか** | §4。引合が静かに止まる事故を消すための保険です |
| 4 | **既存のサプライヤー登録フォームも作り直してよいですか** | 運用開始直後の**今が最安の移行時期**です。Vercel の規約問題も同時に解消し、系が1つ減ります |
| 5 | **承認から公開まで、最大何分の遅れなら許容できますか** | ここが「即時でなければ困る」なら、構成の前提が変わります |
| 6 | 行動計測の B 段階（表示秒数・スクロール）を入れますか | §3-7 |

---

## 9. 今ある試作について（正直に書きます）

**8/9 の夜に Next.js 版の土台を作り、動作確認まで済ませています。** 今回の決定により、**この画面まわりのコードは使いません。**

ただし無駄にはなっていません。次のものはそのまま引き継ぎます。

- **データベースの設計**（検索クエリ・メーカー・カテゴリ・行動・引合の5つ）— 用途ごとの分離だけ手を入れます
- **0件検索も必ず記録する**という設計と、その動作確認手順
- **Google スプレッドシートを読む処理**（署名まわり）— 呼び出す場所が「ページ表示時」から「作り置き時」に変わるだけです
- **セッションの識別方法**（生のIPを保存しない）
- **検証のやり方**（実際に HTTP を投げて、データベースに行が入るまで確認する）

**「作ってから捨てる」のを避けるために批評にかけたので、この順序で正解でした。** 動くものがあったからこそ、批評する側も具体的に検査できました。
