こんにちは!世界遺産「佐渡島の金山」で有名になっちゃった佐渡島で、半農半エンジニアをやっている矢部です。前回は家庭内のお手伝い管理アプリをKiroで作った話を書きましたが、今回はもうちょっとスケールの大きい話です。
「佐渡の相川を歩いて、焼き物オブジェを撮影するだけでスタンプが集まるアプリ」 をKiroとAmazon Bedrockで作りました。
きっかけは、佐渡青年会議所が主催した紙のスタンプラリー「キンスタクエスト~ワクワク!マチの大冒険!~」です。150名以上が参加した大きなイベントで、当家も家族全員で参加して5時間かけて山の斜面に(金山だしね)広がる相川の古い道をさまよったわけです。
で、終わってから、ふと思いました。これって、開催期間中しか使えない、紙の台紙は雨に弱い、外国人観光客に対応できない……でも、スタンプ集め自体は宝探しのようで、本当に楽しかったわけです。途中、待ちの中のカフェや、雑貨屋さんで休憩してアイス食べたり、とてもいい体験だった。
「これ、デジタルにしたら通年で使えるし、AIで写真判定すれば不正もできないし、面白いんじゃね?」
Facebook(おっさん世代なので)で主催者の方に連絡いれて「つくっていいっすか?」と確認させていただいたところ「いいっすよ!」とお返事をいただけました。
で、冬のスキマ時間にちまちまとKiroでスペックを書いて実装を進めて、気づいたら本格的な観光DXアプリが出来上がっていました。
そもそも何が課題だったのか — 金山だけ見て帰っちゃう問題
2024年に「佐渡島の金山」がユネスコ世界遺産に登録されて、観光客はすごく増えました。ありがたいことです。
でも、かなりの数の観光客の皆さんは車で金山に横づけして、金山だけ見て帰っちゃうんですよね。で、佐渡つまらん、相川つまらん。となるわけです。いやいやちゃいますよ、と。
金山のお膝元の相川地区には、旧町名を冠した焼き物オブジェが20個以上点在しています。陶器製で、壁や柱に設置されていて、それぞれの町の歴史が刻まれている。地元の人間としては「こっちも見てってよ!」なわけです。(この写真のようなオブジェですね。写真に緯度経度があるのは記録用のアプリをいれて、もう一回、一人スタンプラリーを雪の中やってきたからですね。寒かった・・・・。)

紙のスタンプラリーでこのオブジェを巡るイベントは盛況でしたが、アプリを組むうえでの課題は明確でした。
- イベント期間中しか実施できない — せっかく作った仕組みが一発限り
- 不正防止が困難 — ホントに現地に行ったか確認できない
- データが取れない — どこが人気でどこがスルーされてるか分からない
- 多言語対応が難しい — 世界遺産になったら外国人も来る
作ったもの — GPS×AIの「二重認証」スタンプラリー
完成したアプリ「キンスタクエスト」の体験フローはシンプルです。

1. スマホでURLにアクセス(インストール不要!PWAなので) 2. デフォルメされたイラストマップに自分のGPS位置がリアルタイム表示 3. 焼き物オブジェの場所に近づく(10m以内) 4. スマホで焼き物オブジェをパシャリ 5. AIが「ホンモノの焼き物オブジェか?」を瞬時に判定 6. スタンプ獲得!🎉
ポイントは 二重認証 です。「近くに行く」だけでもダメ、「写真を撮る」だけでもダメ。GPSで近くにいることを確認し、さらにAIで実物を撮影したことを確認して、初めてスタンプが押される。
紙のスタンプラリーの「スタンプ台でハンコを押す」に相当する「現地訪問の証拠」を、テクノロジーで担保しています。
Amazon Bedrockで「写真を撮るだけ」を実現した話

なんでAIが要るの?
GPSだけでいいんじゃないかって思いますよね。でもGPSには弱点があります。
- 精度が環境によって数十メートルぶれる(山の中とか建物の影とか)
- 位置情報の偽装も技術的には可能(やろうと思えばできちゃう)
一方、写真だけでも不十分です。ネットで拾った画像や他人の写真を使えちゃいますから。
GPS(そこにいること)+ AI画像認証(実物を見ていること) の二重認証で、初めて「ほんとにそこに行って、ほんとに見てきた」が技術的に言えるようになります。
Amazon Bedrock × Claude Haiku 3 を選んだ理由
AI画像認証には Amazon Bedrock の Claude Haiku 3 を使いました。
選定理由をまとめるとこんな感じです。
| なぜ Bedrock? | 理由 |
|---|---|
| 速い | スタンプラリーで「撮ったら即結果が欲しい」。Haiku 3は軽量高速で、5秒タイムアウトでもほぼ問題なし |
| 日本語が読める | 焼き物オブジェには日本語の旧町名が刻まれてる。日本語テキストの読み取り必須 |
| 画像を直接理解 | 画像→日本語で判定結果、の1ステップ。OCR→テキスト判定の2段階が不要 |
| AWSにそのまま繋がる | 既存のECS、DynamoDB、CognitoとIAMロールでシームレスに統合 |
| 安い | 1判定あたりの入出力トークンが小さい。観光アプリの規模では全然いける |
前回のお手伝いアプリでもAWSをフル活用しましたが、今回はBedrockが加わったことで「AIが人間の代わりに判定する」という新しい体験が作れました。いやー、Bedrockすごいですね(ヨイショ)。
プロンプト設計 — AIに「何を判定すべきか」を教える
Bedrockに投げるプロンプトは2層構成です。
システムプロンプト(全スタンプ共通):
あなたは佐渡島相川地区のスタンプラリーの画像判定AIです。
ユーザーが撮影した写真に、相川の旧町名が刻まれた焼き物の看板オブジェが
写っているかを判定してください。
焼き物オブジェは陶器製で、町名が日本語で刻まれています。
壁や柱に設置されていることが多いです。
以下のJSON形式のみで回答してください:
{"isValid": true/false, "confidence": 0-100,
"detectedText": "読み取れた文字", "reason": "判定理由"}
ユーザーメッセージ(スタンプごとに動的):
この写真に「南沢町(みなみさわまち)」の焼き物看板オブジェが写っていますか? 関連キーワード: 南沢, 南沢町
工夫したポイントは3つ。
- 「陶器製」「壁や柱に設置」 と具体的に書いて、看板やポスターとの誤判定を防止
- 町名・読み仮名・キーワードを動的に注入 して、「どのオブジェか」をAIに明示
- JSON形式を強制 して、フロントエンドでパースしやすくする
Bedrockの5MB制限との戦い
最近のスマホカメラ、画質が良すぎて1枚10MB超えることがあるんですよね。Amazon BedrockにはBase64で約5MBの画像サイズ上限があるので、自動リサイズの仕組みを入れました。
【フロントエンド側】 撮影 → アンシャープマスク → JPEG圧縮(品質80%)→ Base64エンコード 【バックエンド側】(まだ大きい場合の段階的リサイズ) 品質85% + 最大2048px → まだ大きい? 品質70% + 最大2048px → まだ大きい? 品質55% + 最大1600px → まだ大きい? 品質40% + 最大1600px → 最終手段
フロントとバックの両方で画像サイズを制御する 二重の安全策。どんなスマホで撮っても確実にAI判定が動くようにしています。
ちなみにこのリサイズ処理、実運用でのエラーログから段階的に改善していきました(後述するKiroのスペック駆動が効いたところです)。
Kiroのスペック駆動開発がどう効いたか
前回との違い — お手伝いアプリからの進化
前回のお手伝いアプリでは「Kiro(設計)→ Claude(実装)→ 人間(PM)」の役割分担を確立しました。今回のスタンプラリーアプリでは、開発の9割をKiroのスペック駆動ワークフローで完結 させています。Claude Codeは部分的な補助として使った程度で、設計から実装までほぼKiro一本です。
Specs — AI画像認証の改善をスペックで回す
開発が進んで実際にユーザーに使ってもらうと、AI画像認証まわりの課題がポロポロ出てきました。
- 「iPhoneの写真が大きすぎてタイムアウトする」
- 「PNGで撮ると判定が遅い」
- 「data:image/jpeg;base64, のプレフィックスが付いたまま送られてくる」
こういう問題が出たとき、Kiroのスペック駆動ワークフローが効きました。
Phase 1: 要件定義(Requirements) → 「Base64が5MBを超える画像でもタイムアウトしないこと」 → 「JPEG/PNG/WebP/GIF を自動判別すること」 Phase 2: 技術設計(Design) → 段階的リサイズのアルゴリズム設計 → メディアタイプ自動検出の仕様 Phase 3: タスク分解(Tasks) → TDDでテスト先行、実装は後から Phase 4: 実装(Implementation) → スペック通りに実装 → バリデーション
特に Phase 2の技術設計 が効きました。画像リサイズって「品質を下げるか」「解像度を下げるか」「両方か」の選択肢があって、Bedrockの5MB制限とAI判定の精度(文字が読めないと困る)のトレードオフがあるんです。これを設計フェーズで明文化してレビューしてから実装に入ることで、手戻りがほぼゼロでした。
Gitのコミット履歴を見ると、段階的に改善されてるのがよく分かります。
d7a1419 fix: check base64 string length instead of decoded size for Bedrock limit 6fce233 fix: auto-resize images exceeding Bedrock 5MB limit before API call d858d03 fix: raise image limit to 10MB, suppress health check logs, auto-detect media type 85ac3d1 fix: raise body size limit to 15MB for verify and import endpoints 0152262 fix: auto-strip data URI prefix and detect image media type for Bedrock
「問題発見 → スペック更新 → 設計見直し → 実装 → テスト」のサイクルを、Kiroのおかげで高速に回せました。
AI協働開発ワークフロー
前回のブログで「人間(PM)→ Kiro(テックリード)→ Claude(開発者)」のワークフローを紹介しましたが、今回はさらにKiroでほとんど進めることができました。
| 役割 | 前回(お手伝いアプリ) | 今回(スタンプラリー) |
|---|---|---|
| 人間 | PM・プロダクトオーナー | 同じ + ドメイン知識の提供(佐渡の現地事情) |
| Kiro | テックリード・アーキテクト | 設計〜実装まで9割を担当。スペック駆動ワークフローで開発の中心 |
| Claude Code | 開発者・実装担当 | 部分的な補助(デバッグや細かい調整)で活用 |
大きな違いは、Kiroが設計だけでなく実装の中心になったことです。Specsによる機能単位の管理がKiroに組み込まれたことで、前回はClaude Codeに頼っていた実装部分もKiroのワークフロー内で完結するようになりました。
AWSアーキテクチャ — 離島の観光アプリに最適な構成
技術スタック概要
| レイヤー | 技術 |
|---|---|
| フロントエンド | React 19 + TypeScript + Vite |
| バックエンド | Python + FastAPI |
| AI | Amazon Bedrock(Claude Haiku 3) |
| データ・認証 | DynamoDB + Cognito |
| インフラ | ECS Fargate + CloudFront + AWS CDK |
AWSをフル活用した構成ですが、ここでは割愛して、この記事ではBedrockとKiroに絞ってお話しします。
AWSアーキテクチャについて、ポイントだけ触れておくと、ECS Fargate最小構成(0.25 vCPU / 0.5GB)で十分回っています。佐渡の観光アプリなので同時100万アクセスとかはないわけです(悲しいけど現実。というか、相川にいないとつかえんのですよ。そもそもが!)。インフラはAWS CDKで全リソース管理、CI/CDはGitHub Actionsで自動化しています。
おまけ — デフォルメ地図×GPSという変態的チャレンジ
AI画像認証の話とは別に、もうひとつ変わったことをやっています。
相川のスタンプラリーで使ってるイラストマップ、南北が反転してるんです。しかも距離も角度もデフォルメされてる。このグニャグニャの地図の上に、GPSの現在地をリアルタイムで正しく表示しないといけない。

普通に線形変換したら全然合わないので、区分的アフィン座標変換(Piecewise Affine Transformation) を実装しました。
1. 制御点(GPS座標とイラスト上のピクセル座標のペア)を複数定義 2. Delaunay三角形分割でメッシュ生成 3. 各三角形ごとに独立したアフィン変換行列を計算 4. ユーザーのGPS座標がどの三角形に入ってるか特定 5. その三角形のアフィン変換を適用 → イラスト上の位置が出る
Delaunay三角形分割とか、なかなかゼロから実装とかできんですよね。これもKiroのスペック駆動で設計して、fast-check(Property-Based Testing)で「GPS→ピクセル→GPSの往復変換で元に戻るか」をテストしています。合わせて管理画面で運用開始してからも微調整可能にしました。Kiroにブーブーいわれました。それデカイからさ、SPECかくよな?な? お、おう・・・・。(意訳)
地方DXの現実 — 電波が届かない場所でどうする?
オフライン対応は必須
相川地区、場所によっては携帯の電波が怪しいんです。山間部とか、古い建物の中とか。デジタルスタンプラリーなのにネットが繋がらない——致命的ですよね。
PWA(Progressive Web App)として実装して、以下のオフライン対応をしています。
- 地図画像とスタンプデータをService Workerでキャッシュ → オフラインでも地図が見える
- GPS追跡はGeolocation API → ネットワーク不要で位置追跡を継続
- スタンプ収集データをlocalStorageにキューイング → オンライン復帰時に自動同期
インストール不要が正義
観光地で「アプリをApp Storeからダウンロードしてください」って言ったら、だいたいの人は「めんどくさい」って帰っちゃいます。
PWAなのでQRコード読むだけで即スタート。これが地味に一番大事なUX判断でした。
日英2言語対応
世界遺産になったので外国人観光客も来ます。i18nextで日英2言語対応、navigator.language でブラウザの言語設定を自動判別しています。
開発を振り返って — Kiroが変えたもの
正味の開発時間
冬のスキマ時間にちまちまとやっていたので正確な時間は分かりませんが、体感では前回のお手伝いアプリ(正味4日)よりは長く、でも一人で作れる範囲でした。スタンプラリーの場所の相川まで遠いので現地テストが大変だった。真実は現場にあるので。
前回と違うのは、AI画像認証という「正解がない問題」に取り組んだことと、開発の9割をKiroで完結させたことです。AIの判定精度は撮影条件でブレるし、Bedrockの制約にもハマるし。でもKiroのスペック駆動で「問題発見 → 要件定義 → 設計 → 実装」のサイクルを回せたおかげで、場当たり的にならずに改善を進められました。Claude Codeは細かいデバッグや調整で部分的に使った程度です。
Kiroスペック駆動の3つの恩恵
1. 「何を作るか」の合意形成が速い
Steeringとスペックでプロジェクトの文脈が整理されるので、新機能を追加するときにAIが「このプロジェクトでは」を踏まえた提案をしてくれます。「Bedrockのタイムアウト時の挙動は?」「手動申告との整合性は?」みたいな論点が設計フェーズで自然に浮き上がる。
2. 反復改善のサイクルが速い
実運用で見つかった問題(画像サイズ上限、メディアタイプ判定ミス等)に対して、スペックベースで高速に改善を回せました。
3. ドメイン知識の蓄積
「佐渡の焼き物オブジェ」「旧町名」「区分的アフィン座標変換」——こういうドメイン固有の知識が蓄積されます。セッションが変わっても、AIがプロジェクトの文脈を理解した状態で開発を続けられる。これは前回のお手伝いアプリのときに感じていた課題が解決された部分です。
まとめ — 地方の観光課題にAI×クラウドは効く
| 課題 | 解決策 | AWSサービス |
|---|---|---|
| 訪問の証明 | GPS + AI画像認証の二重認証 | Amazon Bedrock (Claude Haiku 3) |
| デフォルメ地図×GPS | 区分的アフィン座標変換 | —(フロントエンドで実装) |
| オフライン対応 | PWA + Service Worker | S3 + CloudFront |
| 認証・セキュリティ | JWT + WAF + レート制限 | Cognito, WAFv2 |
| データ管理 | 14テーブル設計 | DynamoDB |
| 開発プロセス | スペック駆動開発 | Kiro |
| IaC | CDKで全リソース管理 | AWS CDK |
地方の観光DXって、最先端技術を詰め込むことが目的じゃないんです。「現地に行って、実物を見る」というシンプルな体験の価値を、テクノロジーで最大化することが本質。(えらそう)
Amazon Bedrockは「写真を撮るだけ」のシンプルなUXの裏側で訪問の信頼性を担保し、Kiroのスペック駆動開発はAI機能の設計・改善サイクルを加速してくれました。
佐渡島の小さなスタンプラリーから始まったこのプロジェクトが、同じように地方の観光課題に取り組む皆さんの参考になれば嬉しいです。
世界遺産の島から、愛を込めて。🌾⛏️