AI開発の裏側

開発統括はしてもコードは書かない町会役員が、
AIと作ったもの。

「AIに頼めばアプリができる」という話はよく聞きます。でも、実際に他人に使わせて 運用するまでには、思っていたのと違うことが山ほどありました。 うまくいったことも、失敗したことも、正直に書きます。

このアプリは、中学校でBASICのゲームを自作して以来、開発統括・プロデュースは手がけてきたものの、 コーディングそのものは長らく行っていなかった町内会の役員が、 Anthropic の Claude Code に指示を出して開発しました。 TypeScript 約1万行、データベースの変更履歴23本。 できあがったものより、そこに至る過程のほうが、記録する価値があると思っています。


01何ができたか

回覧・会館予約・会合の出欠・資料共有・写真ブログ・防災情報・多言語対応。 通知(Web Push)、メール配信、未読バッジ。管理画面では会員管理や 回覧の確認状況、入会申込の処理までひととおり動きます。

規模TypeScript 約1万行 / マイグレーション23本
開発期間約2週間(オーナーの空き時間のみ)
開発者の経験開発統括・プロデュースは手がけてきたが、コーディングは長年ブランク(直近の実装は中学校のBASIC以来)

02うまくいったこと

2-1. 「AIへの接し方」を先に決めた

最初に、AIに対する運用ルールを文書化しました。要点はこうです。

EFFECTIVE

これが一番効きました。非開発者が判断できる形に翻訳させることで、 オーナーは「決める」ことだけに集中できました。

2-2. 実機で確かめさせた

AIは「できました」と報告しがちです。画面を実際に測らせると、 報告と現実の差が見えます。

例: iOSの「ホーム画面に追加」の案内で、共有画面が開いたときに手順が隠れないよう 「画面の上から42%以内」に収める設計にしていました。ところが実機のシミュレータで測ると、 iPhone SE では 48% まで伸びていて、手順4と5が隠れていました。 文字サイズが固定pxだったためです。画面の高さに追従させて解決しました。

EFFECTIVE

測らなければ、この不具合は「完成」として世に出ていました。

2-3. 決めたことを文書に残した

AIはセッションが変わると経緯を忘れます。「なぜそうしたか」を残しておかないと、 次のセッションが善意で元に戻します。実際に効いた書き方はこれです。

⚠ この仕様を「脆弱性」として勝手に直さないこと。オーナーが承知のうえで選んでいる。

03失敗したこと

3-1. 「マニュアルを作る」という発想そのものが間違っていた

「ホーム画面に追加」の手順書を、スクリーンショット付きで丁寧に作りました。 オーナーの評価は—

20/ 100点

スマホに詳しくない層は、見たものを記憶して操作することは無理 — オーナーの一言

iOSでは操作の途中でOSの共有画面が現れ、説明が見えなくなります。 つまり従来のマニュアルは「2手順以上を暗記させる」ことを要求していました。 体裁をどれだけ磨いても、原理的に失敗する設計だったわけです。

作り直した方針は「記憶ゼロ」。押すものの写真を画面の上に出しっぱなしにして、 利用者は見比べて選ぶだけにしました(実機検証で、共有画面が開いても 画面の上から約43%は隠れないことを確認できたので成立しました)。

LESSON

AIは「指示されたものを上手に作る」。指示そのものが間違っていると、上手に失敗する。

なぜPWAにこだわったか — ネイティブアプリでも、ただのWebページでもなく

「アプリ」を作るなら、App Store/Google Playで配るネイティブアプリという 選択肢もありました。それでも今回PWA(ホーム画面に追加して使うWebアプリ)を選んだのには、 3つの実務的な理由があります。

つまりPWA化した瞬間に、「通知」「バッジ」というスマホアプリらしい体験が 追加費用ゼロで手に入ります。今回の開発で「ホーム画面に追加」の案内(インストーラー)に これほど時間をかけたのは、この入り口を確実に通ってもらうためでした。

余談 — 30年前にも同じ壁があった

「導入部が使えなければ、道具は存在しないのと同じ」という考え方は、実は今回が初めてではありません。 昔、CD-ROMのエンターテインメント作品をプロデュースしていた頃、Onetouchという 導入アプリ(当時は「ティーザーアプリ」と呼ばれるカテゴリでした)を企画・設計したことがあります。

当時はCD-ROMドライブの読み込み速度が日進月歩で、動画のコーデックには今のような スケーラビリティ(通信環境に応じて画質を変える仕組み)がありませんでした(MPEG1普及前夜の時代です)。 4倍速ドライブのユーザーはきれいな動画を見たい、2倍速のユーザーはカクついたら困る—— そこで同じ映像を解像度違いで2種類ディスクに入れておき、Onetouchが インストール時に計測用の重い動画データを実際に読み込ませて速度を実測し、 その結果に応じて見せるものを自動的に振り分けていました。

仕組みは30年前と今でまるで違います。でも「使い始める最初の一歩でつまずかせない」という 設計の勘所は、CD-ROMドライブでもiPhoneでも同じでした。

道具は「使い始められなければ意味がない」のです。 今回、PWAのインストール案内の部分だけでも、価値のあるものができたと考えています。

PWA化の技術的な格闘 — なぜここまでこだわったか

「ホーム画面に追加」は、単なる見た目の話ではありません。iOSのSafariは、 サイトがホーム画面に追加され「単独のアプリのように開かれた状態(standalone)」で なければ、Web Push通知そのものを許可しません。 つまりこの一連の操作を終えない限り、通知機能は原理的に一度も動きません。 「押すのが面倒な設定」ではなく、「機能の唯一の入口」でした。

function isStandalone() { return matchMedia("(display-mode: standalone)").matches || navigator.standalone === true; // iOS Safari 独自のプロパティ } // standalone でなければ、この時点で "need_install" として案内へ誘導する if (isIos() && !isStandalone()) return "need_install";

実装にあたって、いくつもの技術的な行き止まりにぶつかりました。順番に書きます。

試したこと分かったこと
navigator.share()でボタン一発、共有画面を開けないか 開けるが、そのメニューに「ホーム画面に追加」が存在しない(コピー・リーディングリスト等のみ)。この経路は棄却
共有画面が開いたことをblur/focus/visibilitychange/resizeで検知できないか どれも発火しない。OSの共有画面はページの外側にあるレイヤーで、Webページ側からは一切観測できない
それでも画面のどこかは見えているのでは、と実測 見えている。共有画面が開いた状態でも、画面の上から約42.7%はページのまま隠れずに残る(2機種で実測)
共有画面が開いている間、JSのタイマーは動き続けるか 動く。タイマーで数値を更新しながら共有画面を開いたままにしても、カウンタは進み続けた

この4つの実験から方針が決まりました。画面の上から42.7%以内に固定した帯を置けば、 OSの共有画面が開いていても隠れずに読める。ただし「検知できない」ため、 「いま何番目の手順か」をこちらから能動的に切り替えることはできません。 だから全手順を常に表示し、利用者が自分の画面と見比べて選ぶ方式にしました (これが前述の「記憶ゼロ」設計です)。

もうひとつ、副産物的な発見もありました。iOSの共有画面は、開いた瞬間の ページの<title>を自分のヘッダー部分にそのまま表示します。 案内を始める直前に document.title を「↓ホーム画面に追加を押す」に 書き換えておくと、OS純正の画面の中にまで指示が滲み出るという、 二重の手がかりを仕込めました(共有画面を閉じたら元のタイトルに戻します)。

CAUGHT BY MEASUREMENT

帯の文字と写真を固定pxで組んでいたところ、画面の小さい機種(iPhone SE)では 帯が画面の48%まで伸び、共有画面の推奨範囲(42.7%)を超えて 手順4・5が隠れていました。大きい機種では問題が出ないため、 気づかず「完成」として出てしまいそうな不具合でした。

.ig-band-title { font-size: clamp(17px, 2.4vh, 21px); } .ig-step-img { height: clamp(24px, 3.8vh, 38px); } /* 固定pxをやめ、画面の高さ(vh)に追従させる。 小さい機種でも自動的に縮み、42.7%以内に収まる */

画面の高さに追従する clamp() に直し、いちばん小さい画面 (iPhone SE)で撮り直したスクリーンショットで、共有画面を開いた状態でも 5手順すべてが見えることを確認して収束させました。

ANDROID は別の道

AndroidのChromeは、この苦労がまるごと要りません。beforeinstallprompt というイベントをブラウザ自身が発行してくれるので、それを横取りして ボタン1回に差し替えれば、OS純正の確認画面がそのまま出ます。 コードはこの機能が使える端末を検知すると、iOS向けの帯もろとも 丸ごと出さずに、ネイティブの1回タップへ委ねます。 見た目は「同じボタン」でも、内側の実装は機種によってまったくの別物です。

そして最後の1枚。ホーム画面への追加が完了した直後の画面は、「できました」で 終わらせず、続けて通知の許可を求める画面を出します。 ここが、設定全体の中でいちばん見返りの大きい1タップだからです。 ここを飛ばされると、その後どれだけ良い回覧を作っても、静かに届かないままになります。

3-2. 時間で自動的に進める案内は破綻した

作り直した最初の版は、8秒ごとに指示を自動で次へ進める方式でした。 実機テストで、「案内の文字」と「実際に開いている画面」が食い違いました (何も開いていないのに「白い紙の中」と表示される等)。 スマホに詳しくない方は自分のペースで進むので、時間による進行は必ずずれます。

→ 進行をやめ、全手順を常に表示する方式に変更しました。

3-3. 複数のAIセッションを並行させて事故を起こした

同じリポジトリで2つのチャットを並行作業させたところ、片方が git add -A を実行し、もう片方の作業中ファイルを巻き込んでコミット しました。逆方向の巻き込みも起きました。

→ 「自分が変更したファイルだけを指定してコミットする」というルールを文書化しました。

3-4. 検証用のファイルが本番で公開されていた

動作確認のために置いたHTMLを消し忘れ、本番で誰でも見られる状態に なっていました(内容は無害でしたが)。

→ 「検証用HTMLを本番ディレクトリに置かない」をルール化し、機械的な確認スクリプトを用意しました。

3-5. 個人情報の確認は、目視では足りなかった

公開前に、ログイン不要で見られるページの画像33枚を点検しました。 その中に氏名+住所+電話番号が並んだ管理画面の写真がありました。

目視では「テストデータらしい」としか判断できません。macOSの文字認識で全画像を読み取り、 本番データベースの氏名・電話・住所と機械的に突き合わせて、 一致0件であることを確認しました。

LESSON

「たぶん大丈夫」を「照合して0件」に変えないと、公開の判断はできない。

3-6. 公開直後、実際に競合状態のバグを踏んだ

この文章を書いている最中、デモサイトの検証で同時アクセスが重なり、 データの全消し・再投入処理が二重に走って管理者の権限が一時的に消える 不具合を、実際に自分で踏みました。

排他制御(データベースの1行をロック代わりに使う方式)を入れ、 15並列でアクセスしても壊れないことを確認して直しました。 この文書を書いている最中に起きた実話です。


04実際の運用に何が必要だったか

AIが書いたコードを動かすだけでは足りませんでした。以下は人間側の作業です。

判断電話番号だけのログインを許容するか等、リスクを引き受ける判断
実地テスト実際にスマホに詳しくない方に使ってもらい、どこで止まるかを見る
外部サービスの契約Cloudflare・Resend の登録、DNS設定
データの初期投入会員名簿の登録、既存の回覧の移行
運用ルール名簿を外に出さない、回覧本文に個人の連絡先を書かない
継続的な確認「通知が届いているか」を定期的に確かめる

自治体ごとに、防災情報の出し方がまるで違う

「防災・安全情報を町会サイトにも載せる」という、一見地味な機能のために、 実際には自治体ごとにまったく違う対応が必要でした。 RSSで機械的に読み込める自治体もあれば、そもそも機械が読める形式を 一切公開していない自治体もあります。

このアプリの元になった町会がある江東区の場合、防災・安全情報の公式な配信手段は 「安全安心メール」というメール配信サービスのみでした。 RSSのような、プログラムが定期的に読みに行ける公開の窓口は用意されていません。 そこでメールを受信し、内容を解析してアプリで読める形に変換し、 改めて配信し直す仕組みを別途つくりました。 「メールを読む」という、一見なんでもない作業のために、 受信から解析までの仕組みをまるごと1つ作る必要があったわけです。

これは江東区だけの話ではないはずです。自治体によってRSS配信・メール配信・ PDFの掲示・ウェブページへの手入力など出し方がバラバラで、 その数だけ「取り込むための工夫」を個別に作る必要があります。 町内会のような小さな団体が、同じような仕組みをそれぞれ独自に作り続けるのは、 社会全体で見ればかなり非効率です。

行政の皆様へ

防災・安全情報のような公共性の高い情報は、人が読むためのメールやウェブページに加えて、 RSSなど機械可読でオープンな形式でも、あわせて配信していただけないでしょうか。 それだけで、町内会・自治会や地域の見守りアプリなど、様々な現場でその情報を 無理なく再利用できるようになります。強くお願いしたいです。


05今後の課題


06これから同じことをする人へ

  1. 01AIに「翻訳」させる。専門用語で聞かれたら「非開発者に分かる言葉で、選択肢にして」と返す
  2. 02「できました」を信じない。画面を測らせる、実機で動かさせる、数字を出させる
  3. 03決めた理由を残させる。残さないと次のセッションが親切心で元に戻す
  4. 04公開前は機械的に確認する。目視は必ず漏れる
  5. 05一番大事なのは、誰のために作っているかを手放さないこと。今回「20点」の評価が出たのは、作り手ではなく使う人を見ていた人がいたからです
読んでいただき、ありがとうございます

続きは、コードとデモでご覧ください。

MITライセンスで公開しています。改変・商用利用ともに自由です。

この文章を書いた人

Jag Yamamoto — 商品企画・通信・Web・メディア・イベント・教育・音楽・IPなど、 複数の分野で0→1(ゼロイチ)の事業を立ち上げてきた事業開発者です。 「専門家の代わりにすべてを自分で作る人」ではなく、 「何を問題とするかを決め、必要な専門家を組み、事業として成立させる人」を志向しています。

その屋号がJag Projectです。本アプリの開発も、Jag Projectの活動の一つとして行いました。 詳しいプロフィールは jagproject.com/about をご覧ください。