Claude Code × Medical Application

【Claude Code】社内の BI ダッシュボードを AI ダッシュボードに Part4:公開と運用 — 費用とセキュリティの管理

1. はじめに — 費用と安全は、先に決める

AI ダッシュボードを人に使ってもらうとき、気になるのは費用と安全です。質問のたびに AI を呼ぶので、使われるほど費用がかかります。誰かに機械で連打されたら、どこまで膨らむのか。

Part3 までで、話しかけると動く画面ができました。Part4 は、それを公開して運用する回です。今回は誰でも使える公開のデモなので、社内で使うときより条件は厳しくなります。見る人を選べず、悪意のある使い方も想定しなければなりません。

この回の構成です。

  1. はじめに(この章)
  2. 費用を守る — 三重の上限
  3. ボット対策は入口で1回だけ
  4. 測ってから直す — スマホの初回表示
  5. 公開は2段階、人の手を決めておく
  6. 社内で使うときとの違い
  7. 今回のハーネス/まとめ

2. 費用を守る — 三重の上限

2-1. 先に天井を決める

公開のデモなので、誰が何回押しても費用が膨らまないことを、作る前に決めました。上限は三重です。

費用を守る仕組み。入口でボット対策・回数制限・月額の上限の三重と、止まっても使える画面
上から順に、自動の連打・人の使いすぎ・全体の費用を止める
  • 入口でボット対策:Cloudflare Turnstile を入口で1回だけ通す(3章)
  • 回数制限:1人あたり1時間20回・1日60回。Cloudflare の KV(キーと値の保存先)に記録する
  • 月額の上限:Anthropic に専用のワークスペースを作り、月額の上限を設ける

質問文は保存しません。何を聞かれたかを記録しないので、閲覧者の入力を預かる責任も生まれません。

2-2. 1問あたり約0.1円

モデルは Claude Haiku 5.5 で、料金は入力が100万トークンあたり0.10ドル、出力が0.50ドルです(公式の料金ページで確かめました)。1問で AI を1〜3回呼び、入力は約200〜2,000トークン(指示文はキャッシュから読むので少ない)、出力は約450〜650トークンでした。多いほうで計算しても1問あたり約0.0005ドル、約0.1円です。

  • 約0.1円1問あたりの AI の費用(実測のトークン数から)
  • 20回1人あたり1時間の回数制限(1日60回)

2-3. 止まっても、画面は使える

月額の上限に達して API が止まったときは、使用上限や残高不足のエラーを見分けて「今月は質問機能を停止中です。下の条件から選んで見られます」と出し、質問欄だけを止めます。条件を手で選ぶ部分とほかの画面は、そのまま使えます。

この表示は、本番の設定には触れずに確かめました。手で止めるための設定(ASK_PAUSED=1)をプレビュー環境だけに入れて別の枝にデプロイし、表示を確かめてから消しています。止まったときの姿も、作るものの一部です。

3. ボット対策は入口で1回だけ

3-1. 質問のたびに確認を出さない

最初の版では、質問の入力欄の下に Turnstile(ボット対策の確認)の枠を置いていました。これでは質問のたびに枠が目に入り、使いにくくなります。

そこで、入口のページで「ご利用にあたって」を読んで同意するときに、Turnstile を1回だけ通す形にしました。通った人には、サーバーが24時間の署名つきクッキーを渡します。質問の窓口(/api/ask)は、毎回このクッキーを確かめます。

ボット対策は入口で1回だけ。入口 → /api/session で署名つきクッキー → /api/ask で確かめる → アプリ
クッキーが切れたら入口に戻さず、裏で通し直して同じ質問を送り直す
  • クッキーは「期限・乱数・署名(HMAC-SHA256)」の3つをつないだもの。HttpOnly・Secure・SameSite=Lax で、送る先は /api だけ
  • 署名の比較は、かかる時間をそろえる(比べ方の差から鍵を推測されないように)
  • テストは11件。期限切れ・書き換え・別の鍵・形のおかしな値をすべて弾くことを確かめた

3-2. 入口とアプリを分ける

最初は、今のページの上に同意の画面を重ねる形にしましたが、入口のページ(/)とアプリの画面(/app)を分ける形に変えました。共有された URL から直接 /app?… に来た人も、まず入口に送り、同意したら元の条件の画面に戻します。

戻り先は /app で始まるものだけに限っています。戻り先を自由に指定できると、外のサイトへ飛ばす踏み台にされるからです。この確かめもテストを7件書いています。

3-3. 切れたら、裏で通し直す

同意はブラウザに30日残りますが、クッキーは24時間で切れます。切れたときに入口へ戻すと、送りかけた質問が消えてしまいます。そこで、質問を送ったときに 401 が返ったら、裏で Turnstile を通し直してクッキーを取り直し、同じ質問を送り直すようにしました。確認の枠が出るのは、本当に確かめが要る人だけです。

Turnstile がトークンを出せないとき、質問欄が止まったままになる弱点も見つかりました。エラーか20秒で、空のトークンのまま送る形にしています。サーバーが「ボット対策の確認ができませんでした」と返し、画面は止まりません。

4. 測ってから直す — スマホの初回表示

4-1. まず測る

社内の BI でも、外出先でスマホから見たい、という声はよく出ます。プレビュー公開のあと、スマホの初回表示を測りました。条件は、遅い4G(1.6Mbps・150ms)と4G(9Mbps・60ms)、CPU を4倍に減速、キャッシュなし、3回の中央値です。

スマホの初回表示(地図の円が出るまで)。遅い4G で 9.7秒 → 5.5秒 → 4.0秒 → 4.2秒、4G で 2.1秒 → 1.4秒 → 1.2秒 → 1.5秒
何が重かったかを内訳で見てから、効く順に直した

最初の計測では転送量が約1.7MBで、内訳はフォント 654KB、施設の一覧 312KB、JS 277KB(大半が地図の部品)、地図のタイル 226KB でした。Claude Code には、内訳と「効く順の直し案」を出させてから、人が「フォントの軽量化と、施設の一覧の最小化」を選んで頼みました。

4-2. 効いたのは「読む時期」

  • 施設の一覧を2つに分ける:初回は最小の列(id・短い名前・都道府県・医療圏・座標・区分)だけ。gzip で 312KB → 136KB。正式名称・病床・リンクは、地図が落ち着いてから読む
  • フォントを読む時期を遅らせる:使う太さを3つから2つに減らしても、転送量はほとんど変わりませんでした。効いたのは、最初の画面に要るデータがそろってからフォントを読むことでした。それまでは端末の標準フォントで描きます
  • 先読み:データの JSON を HTML の時点で先読みし、地図のタイルと Turnstile のサーバーに事前に接続する

4-3. 測り方の書き分けも直した

直したあとに測り直すと、4G で地図の円まで 2.1秒 → 1.4秒でした。ここで、目標にしていた「4G で4秒以内」は直す前から満たしていたことが分かりました。最初に報告された 9.5秒は遅い4G の値で、条件の書き分けが足りなかったのです。数字を報告させるときは、どの条件で測ったかを必ず一緒に書かせるようにしました。

直す途中で、スマホでは地図が日本全体を収められず、北海道の東と先島が切れていることにも気づきました。地図の中の状態を読むと、最小ズームが4で止まっていました。地図の部品を途中で入れ替えたとき、前の部品の感覚で決めた値が残っていたのです。最小ズームを3に直すと、全国表示の地図タイルも 226KB → 33KB に減り、遅い4G で 4.0秒、4G で 1.2秒になりました。

4-4. 安全のための更新で、少し遅くなった

公開前の総点検で、地図の部品(MapLibre)に既知の脆弱性が見つかり、直った版(4 → 6)に上げました。JS が 286KB → 366KB に増え、測り直すと地図の円まで 4G で約1.5秒、遅い4G で約4.2秒になりました。最初の画面が地図なので、地図の部品を後から読む形にしてもほとんど速くなりません。手間に見合わないと判断し、この値で公開しています。

5. 公開は2段階、人の手を決めておく

5-1. 検索に出ない仮の URL で確かめる

公開は2段階に分けました。

公開は2段階。プレビュー(検索に出ない仮の URL)で実物を確かめ、記事の公開と同じ日に本番のドメインに切り替える。人がやることを決めておく
秘密の値・ボット対策・公開の切り替えは、人がやる

段階1は、Cloudflare Pages の仮の URL(〇〇.pages.dev)への公開です。検索に出ない設定を 3重にしました。robots.txt、ページの meta robots、そしてデータの JSON も含む全ファイルに付ける X-Robots-Tag です。デプロイしたあと、3つとも効いていることを確かめています。本番と同じ設定で動かして、ここまでの章の確かめ(費用・ボット対策・スマホ)をすべて実物で行いました。

段階2は、記事の公開と同じ日です。本番のドメイン(dpc.herzleben.co.jp)を付けて検索に出ない設定を外し、記事を公開します。アプリの入口とフッターには、機能を紹介するためのデモであり、集計や名寄せに不正確な点が含まれる場合があることを、目立つ形で出しています。

5-2. 人にしか任せないこと

Claude Code には、デプロイのコマンドや Pages のプロジェクト・KV の作成まで任せました。一方で、次の3つは人がやると決めていました。

  • 秘密の値を入れる:API の鍵、クッキーの署名の鍵、Turnstile の本番の鍵は、人が自分で Cloudflare の Secrets に入れる。Claude Code の会話にも作業ログにも残らない
  • ボット対策の確認欄を押す:3章のとおり、AI は代わりに通さない
  • 公開に切り替える:本番のドメイン、検索に出ない設定を外すこと、記事の公開

どれも、間違えたときに取り返しがつかないか、AI がやると意味をなくすものです。

5-3. 運用のつまずき

手元での作業にも、小さなつまずきがありました。設定ファイルに KV を足した瞬間、手元で動かしていた開発用のサーバー2つが同時に設定を読み直し、模擬の KV のファイルを取り合って1つが落ちました(SQLITE_BUSY)。古い開発用のサーバーが6つ残っていて、新しいサーバーが404を返したこともあります。手元で何が動いているかを、区切りごとに確かめて止めるようにしました。

6. 社内で使うときとの違い

今回は公開のデモなので、社内で使うときとは前提が違います。違いを整理しておきます。

今回(公開のデモ) 社内で使うとき
見る人 誰でも 社員・関係者
入口の確かめ Turnstile と署名つきクッキー 社内の認証(シングルサインオンなど)
回数制限・月額の上限 必須 あったほうが安心(費用の見通しが立つ)
データ 公表された値だけ 権限ごとに見せる範囲を分ける
検索に出ない設定 プレビューの間だけ 常に(社内の網の中に置く)

費用の守り方と、止まっても画面が使える作りは、社内でもそのまま使えます。入口の確かめは、社内の認証に置き換わります。

7. 今回のハーネス

道具 このアプリでの実体 役割
費用の上限 回数制限(KV)・専用ワークスペースの月額上限 誰が何回押しても費用に天井がある
入口の確かめ Turnstile・署名つきクッキー・テスト18件 質問のたびに確認を出さずに守る
停止中の表示 ASK_PAUSED、エラーの見分け 止まっても画面は使える
計測 遅い4G・4G、CPU 4倍、3回の中央値 直す前に測り、条件を書き分ける
2段階の公開 noindex 3重のプレビュー → 本番 実物で確かめてから開く
人の手 秘密の値・ボット対策・公開の切り替え 取り返しがつかないこと、AI がやると意味をなくすこと

8. まとめ

  • 費用は、作る前に天井を決めた。ボット対策・回数制限・月額の上限の三重で、1問あたり約0.1円
  • ボット対策は入口で1回だけ。24時間の署名つきクッキーで、質問のたびに確認を出さない
  • スマホの初回表示は、測ってから直した。効いたのは量より「読む時期」。測った条件を書き分けることも直した
  • 公開は2段階。秘密の値・ボット対策・公開の切り替えは人がやると決めておいた

任せる範囲を広げるほど、人がやることをはっきり決めておく必要があります。

連載のおわりに

Part0〜4 で、社内の BI ダッシュボードを「話しかけると動く AI ダッシュボード」に変える過程を、DPC 公開データを題材に紹介しました。

  • Part0:全体像と設計 — 何が変わるか、どんな画面か
  • Part1:データ整備 — 年度・施設・地域の不一致をそろえる
  • Part2:数値の検証 — 照合とレビューで正しさを担保する
  • Part3:生成 AI の組み込み — AI に委ねる範囲の設計
  • Part4:公開と運用 — 費用とセキュリティの管理(この回)

アプリは dpc.herzleben.co.jp で公開しています。実際に話しかけて、AI がどの条件を選んだかを確かめてみてください。

出典

  • Anthropic「Pricing」(Claude Haiku 5.5、2026年10月24日確認)。https://www.anthropic.com/pricing
  • Cloudflare, Pages Functions / Workers KV / Turnstile のドキュメント
  • 地図:国土地理院「地理院タイル(淡色地図)」
  • 本記事の図表・画面は株式会社HerzLebenが作成したものです