ai-eigyou-sample-menu

多言語QRメニュー — 技術ドキュメント

買い切り納品・納品後は店舗が自分で更新できる多言語デジタルメニュー。SaaS化しない。販売者側に月額費用・DB管理・アカウント管理が残らない構成。

システム構成

1店舗 = 1つの独立したGitHubリポジトリ = 1つの納品物

ファイル構成

/
├── menu.html          公開メニュー(誰でも閲覧、ログイン不要)。products.jsonをfetchして表示
├── admin.html          店舗スタッフ専用の管理画面(本番、GitHub REST APIで実データを更新)
├── demo-admin.html      営業デモ用の管理画面(localStorageのみ、実データには一切触れない)
├── menu-demo.html       demo-admin.htmlと連動する公開メニューのデモ版
├── qr.html              サンプル用QRコード表示ページ
├── products.json        商品データ(下記「products.json仕様」参照)
├── images/               商品写真(WebP形式)
├── README.md            このファイル(技術者向け)
└── docs/
    └── SETUP.md          店舗納品用のセットアップ手順(専門用語なし)

products.json 仕様

{
  "store_name": { "ja": "...", "en": "...", "zh": "...", "ko": "..." },
  "categories": [
    { "id": "drink", "name": { "ja": "ドリンク", "en": "Drinks", "zh": "饮品", "ko": "음료" } }
  ],
  "items": [
    {
      "id": "item-001",
      "published": true,
      "category": "drink",
      "name": { "ja": "カフェラテ", "en": "Café Latte", "zh": "拿铁咖啡", "ko": "카페라떼" },
      "description": { "ja": "...", "en": "", "zh": "", "ko": "" },
      "price": 550,
      "image": "images/item-001-a1b2c3d4.webp"
    }
  ]
}

admin.html(本番管理画面)の設計

GitHub API

GitHub Contents API (/repos/{owner}/{repo}/contents/{path}) のみを使用する。

owner/repo の自動判定

admin.htmlはコード内にリポジトリ名を一切ハードコードしていない。window.location.hostname({owner}.github.io)とwindow.location.pathnameの先頭セグメントから自動的に owner/repo を判定する。これにより、このリポジトリをテンプレートとして複製するだけで、店舗ごとに設定を書き換える必要がない。

認証情報の保存方式(重要な設計判断)

localStorageにPersonal Access Tokenを保存する方式を採用した。 判断理由:

保存処理の設計(部分失敗への対処)

GitHub Contents APIには複数ファイルにまたがる完全なトランザクションが存在しない。そのため「画像は保存できたがproducts.jsonの更新に失敗した」という状態が起こり得る。この設計では:

  1. 画像を先にアップロードする(失敗したら即座に中断・エラー表示、products.jsonには触れない)
  2. 画像アップロード成功後、products.jsonをその時点で再取得し、最新shaに対して更新する
  3. products.json更新が失敗しても、アップロード済みの画像ファイルは孤立するだけで、表示中のメニューが壊れることはない(存在しない画像パスを指すことはなく、失敗時は元のproducts.jsonのままなので実害はない)
  4. 保存ボタンは処理中disabledにし、二重送信を防ぐ

demo-admin.html / menu-demo.html(営業デモ)

見た目・操作感はadmin.htmlとほぼ同一だが、GitHub APIには一切アクセスせず、localStorage(キー: demo_menu_products_v1)だけを読み書きする。menu-demo.htmlも同じキーを参照するため、デモ管理画面での変更がその場でデモ公開画面に反映される体験を、実データに触れずに提供できる。「デモをリセット」で初期状態に戻せる。

セキュリティ

開発方法

サーバーサイドのビルドは不要。ローカルでは python -m http.server 等の静的サーバーで直接確認できる。admin.htmlの実データ確認にはGitHubのFine-grained PATが必要(テストにはPlaywright等でGitHub APIをモックする方法を推奨)。