Skip to content

全体構成

関連: アクセス制御 / データ / デプロイ

ブラウザは静的なクライアントを読み、同じオリジンの /api/* を Worker が処理する。 HTML と JS は Worker のアセット、永続データは D1 と R2 である。

flowchart TB
  subgraph edge [入口]
    BR[ブラウザ / PWA]
    CA[Cloudflare Access]
  end

  subgraph cf [Cloudflare]
    WK[Worker home-kitchen]
    D1[(D1 home-kitchen)]
    R2[(R2 home-kitchen-images)]
  end

  BR --> CA --> WK
  WK --> D1
  WK --> R2

/api/* だけ Worker を先に走らせる。 それ以外は SPA の index.html に落とす。設定は wrangler.jsonc の assets.run_worker_first である。

技術スタック

いま動いているものだけを書く。

層 採用 役割
ランタイム Node 22(.nvmrc は 22.23.2) ローカルと CI の Node
クライアント React 19、React Router 7、Vite 8 UI とルーティング
UI Tailwind CSS 4、shadcn、lucide 見た目と部品
API Hono 4 on Cloudflare Workers /api/*
リレーショナル Cloudflare D1(SQLite) レシピ、プロフィール、お気に入り、編集履歴
オブジェクト Cloudflare R2 写真とアバター
認証ゲート Cloudflare Access(Zero Trust) アプリ全体の入場。Google ログイン
配布 Wrangler、GitHub Actions main への push でデプロイ
インストール vite-plugin-pwa ホーム画面の recipe

クライアントと Worker で共有する型と小さな純関数は shared/ にある。 クライアント固有の状態(最近開いた ID、一覧の表示サイズ、タイマーの音設定)は localStorage である。

リクエストの流れ

  1. ブラウザが home.ntatsuya.com を開く
  2. Access が Google アカウントを確認し、通ったリクエストに Cf-Access-Authenticated-User-Email を付ける
  3. 静的アセットはそのまま返す
  4. /api/* は Worker がヘッダからメールを取り、無ければ 401 にする
  5. 以後の API はそのメールを「今の人」として使う

ローカル(localhost / 127.0.0.1)では Access が無い。 Worker は DEV_USER_EMAIL(いまは coptis923@gmail.com)を今の人にする。

コンポーネントの置き場

パス 責務
src/ 画面。API は src/lib/api.ts だけが呼ぶ
worker/index.ts /api/* の認証ミドルウェアとルート接続
worker/coffee.ts / worker/cooking.ts レシピ CRUD
worker/images.ts 画像の upload、URL 取込、取得、削除
worker/me.ts 表示名、テーマ、アバター
worker/favorites.ts お気に入り(メール単位)
worker/edits.ts 編集履歴の記録と一覧
migrations/ D1 の正本

Worker のバインディング名は DB と IMAGES である。 データベース名は home-kitchen、バケット名は home-kitchen-images である。

クライアントで完結するもの

次はサーバに無い。端末の中だけである。

  • 最近開いたレシピ(ホームの履歴)
  • 一覧のカードサイズ
  • タイマーの音と振動のオンオフ
  • ホームで最後に見ていた種別(コーヒー / 料理)

別端末では共有されない。