会社概要と問い合わせフォームを本番公開した記録:空のまま登録された秘密鍵とボット対策

開発eurekapu-nuxt4

会社概要と問い合わせフォームを本番公開した記録

最近、個人情報の漏洩がよく話題にのぼる。 その話を枕に、朝のセッションでは有料版で使う決済手段の入れ方を Claude Code に調べさせた。 続くセッションでは、会社概要ページと問い合わせフォームを本番に出した。

途中で一度、引っかかった。 メール送信APIの鍵を本番に登録したはずが、値を一度も打たないうちにコマンドが終わっていた。

QRコード決済は決済代行経由か、直接契約か

09:15 のセッションは、決済手段の問いから始まった。 有料版では決済代行サービスAを使うつもりでいる。 そこに QRコード決済B と EC系決済C も足せないか。 EC系決済Cは入れられそうな気がしていたが、QRコード決済Bは見当がつかなかった。 そこで、手順を調べてドキュメントにまとめるよう頼んだ。

Claude Code は公式情報で手数料と審査条件を確かめ、既存の商品価格も見たうえで、目次付きのドキュメントを Chrome に開いた。 結論は次の二つだった。

  • QRコード決済Bは、いまの決済代行サービスAの設定を変えるだけで入れられる
  • EC系決済Cは、決済代行サービスAでは日本向けに提供されていない。直接契約して、決済の仕組みをもう1本作る必要がある

入れられそうだと思っていたEC系決済Cのほうが、手間のかかる側だった。

本当に対応しているのか、と聞き返した。 決済代行を通さずにQRコード決済Bと直接契約したほうがよいのか、手数料は同じなのか、も気になった。 返ってきた答えでは、決済代行サービスAの公式ドキュメントにQRコード決済Bのページがあり、日本のアカウントで使えると書かれている。 手数料は同じではなく、講座のようなデジタルコンテンツなら決済代行サービスA経由のほうが少し安くなる、というのがその場の調べだった。

この比較もドキュメントに加えてもらった。 手数料、入金、審査、実装、継続課金を表で並べ、「決済代行サービスA経由で入れる」という結論と理由を添えている。 先に開いていたタブが閉じられていたため、Claude Code は開き直してから追記部分の表示を確かめていた。

申請を手伝うスキルの下調べと、名義の使い分け

09:27 のセッションでは、アプリストアへの申請まわりを先に調べた。 AIに申請の手続きを手伝わせるスキルが公開されていて、Xのブックマークのどこかに保存したはずだった。 登録してほしいのではなく、中身を確かめてほしい、と頼んだ。

Claude Code はブックマークを全件スクロールして候補を拾った。 見つかったのは、審査に落ちそうな箇所を事前に見つける道具だった。 証明書の準備、アップロード、申請といった手続きそのものはやらない。 手続きを自動化するのは別のスキル群だったので、両方ともインストールはせず、作業領域にコードを落として読ませた。

次に名義を考えた。 法人名義で出したいものと、個人で出してもよさそうなものがある。 名義が分かれれば有料の契約も別になるはずで、名義で料金が変わるのかを聞いた。 その場の調べでは、年会費は個人でも法人でも同じ99米ドルで、名義ごとに別契約になる。 両方取れば198米ドル(約2.6万〜3万円)になる。 一度両方取ってみたかったので、両方の手続きを進めることにした。 名義の方針と登録手順は、チェックリストにしてドキュメントへ足してもらった。

法人名義のアカウントに使うメールアドレスも確かめたかった。 作った覚えはあったものの、どこで何を設定したかを思い出せなかった。 調べさせると、2026年2月に設定した法人用のアドレスが見つかった。 当時の設定は、独自ドメインのメールを組んだ日の作業記録に残っていた。

会社概要ページと問い合わせフォームを足す

このサイトは法人名義でリリースしている。 それなら会社概要ページを置いておこうと考え、このセッションで簡単に足すことにした。

Claude Code は着手前に残りの判断を2つ確認し、既存の LINE 通知、D1、規約ページの作りを読んでから書き始めた。 会社概要ページのあとに、問い合わせフォームを作った。 入力チェックをし、送信されたら LINE に通知し、メール送信APIでメールを送る構成である。 フッターにリンクを足し、テスト16件を通した。 ローカルの D1 にテーブルを作り、dev サーバーで画面と送信、スマホ幅の表示まで確かめた。 この時点では、コミットも本番デプロイもしていない。

続けて、DNSレコードの設定も頼んだ。 Claude Code はブラウザでメール送信サービスAの画面を操作し、法人のドメインを登録した。 手動設定を選んで追加すべきレコードを取得し、Cloudflare に4件足した。 外部の DNS から4件とも引けることを確かめ、認証の完了を90秒待つ。 10:35 に、メール送信サービスAの画面でドメインが認証済みに変わった。

鍵を打つ前にコマンドが終わっていた

残るのは、メール送信APIの鍵を本番に登録する作業だった。 鍵の名前を相談すると、どのドメインの何のための鍵かが名前で分かるものを勧められた。 権限は送信だけに、対象は法人のドメインだけに絞る。

登録コマンドの読み方で、最初につまずいた。 取得した鍵をコマンドの中の変数名と置き換えて実行するのかと思い、確認した。 そうではなく、そこは変数の名前で、サーバーはこの名前で鍵を探す。 鍵そのものは、実行したあとで入力する。

npx wrangler pages secret put <変数名> --project-name eurekapu-nuxt4

このコマンドを、Claude Code の入力欄から ! を付けて実行した。 画面には本番向けに秘密情報を作成する旨が出て、Claude Code も「本番に登録されたことを確認した」と返してきた。 LINE 用の2件と並んで、3件になっている。 続けて、本番への反映に進んでよいかと確認を求めてきた。

待ってほしい、と止めた。 鍵をまだ打っていない。 値の入力を求められた覚えもない。

Claude Code が突き止めた原因は、! で実行したコマンドが入力を受け付けない状態で動くことだった。 そのため鍵を聞かれないまま、空の値が登録されていた。 正しい鍵で上書きすれば直る。 クリップボードを経由する方法と、いちばん確実だという普通のターミナルで実行する方法が示され、自分で上書きを済ませた。

完了を伝えると、Claude Code は登録を確かめたうえで、値が正しく入ったかどうかは Claude Code の側からは見えない、と書いてきた。 確かめるのは、デプロイ後のテスト送信になる。

一覧に名前が3件並んだことは、値が入った証拠にならなかった。 気づいたきっかけは、値の入力を求められなかったことだった。

本番への反映と、並行セッションとの交差

本番の D1 にテーブルを足し、今回の変更をコミットさせた。 コミットには Codex のレビューが走る。 別のセッションがステージした削除が混ざっていたので、Claude Code はそれに触れず、今回のファイルだけを指定してコミットした。 途中でサイト名のカタカナ表記を指摘し、ほかの箇所も含めて直させた。

デプロイの前には、作業ツリーにある別セッションの未コミットの変更が本番に混ざらないかを確かめさせている。 本番ビルドは通り、バンドルの余裕は 1,327.4 KiB から 1,321.5 KiB になった。 今回の追加分は約6 KiB である。

本番のフォームからテスト送信すると、Gmail に2通のメールが届いた。 空だった鍵を上書きした結果も、この2通で確かめられたことになる。 LINE 通知の中身は Claude Code からは見えないので、自分の側で届いているのを確かめた。

テスト送信の記録は本番の D1 から消させた。 push しようとすると、別のセッションが先に push していて、今回のコミット3件はすでに origin に入っていた。

迷惑送信と、メールアドレスを載せるかどうか

公開したあと、迷惑メールが気になった。 Claude Code の説明では、この時点の対策は「隠し項目」と「同じ接続元から1時間5件まで」の2つだけで、接続元を次々に変えてくるボットは止められない。

名前、メールアドレス、問い合わせ内容を匿名にしておいてほしいことと、Cloudflare で対策を入れることを頼んだ。 Turnstile(Cloudflare のボット対策)は入れる方向で進み、「匿名に」の意味は解釈が分かれるとして一度確認が返ってきた。 Claude Code は Turnstile のウィジェットを作り、秘密鍵は画面に出さずに本番へ登録した。 本番のセキュリティヘッダー(CSP)が外部スクリプトを制限していたので、Turnstile を許可する設定も足している。 デプロイ後、トークンのない送信が弾かれることと、ウィジェットが表示されることを本番で確かめた。 問い合わせページからは、メールアドレスの表記も消した。

プライバシーポリシーにはメールアドレスを載せるべきなのか、とも聞いた。 迷惑メールが来るので、載せない運用にしたかった。 その場の説明では、個人情報保護法が求めているのは問い合わせや苦情を受け付ける窓口を示すことで、それは問い合わせフォームで足りる。 会社概要とプライバシーポリシーからメールアドレスを消し、フォームへのリンクに置き換えた。

その後、Turnstile をすり抜けられたときの最後の歯止めとして、サイト全体で1日あたりの受付件数にも上限を入れた。

残りを翌日のタスクへ

未了を聞くと、8件残っていて、そのうち4件は自分にしかできない手続きだという。 こちらで続けられるものは全部やっておいてほしいと伝え、ドキュメントに進捗を書かせた。 マイグレーションの記録を4件足し、本番の D1 は「未適用なし」になった。 会社名の旧表記も、出典表記の27か所すべてで直った。 これらもコミットし、デプロイと push まで済ませた。

最後に、自分がやる手続きのうち3件を Google タスクに入れさせた。 期日は翌日の10月5日で、3件とも中身と期日が入っていることを Claude Code が確かめている。

学び

  • 秘密情報は、名前が一覧に並んでも値が入った証拠にはならない。入力を求めるコマンドは ! ではなく普通のターミナルで実行し、届いたメールで値を確かめる
  • 問い合わせの窓口はメールアドレスでなくてもよい。フォームを窓口にすれば、アドレスを公開せずに済む(その場の説明による)
#eurekapu-nuxt4#問い合わせフォーム#個人情報#Cloudflare Turnstile#Cloudflare D1#wrangler