システム全体像
System Overview

1. システムアーキテクチャ概要
System Architecture Overview

本システムは Next.js App Router をベースとした単一アプリケーションで構成される。フロントエンドとバックエンド API は同一アプリケーション内に共存し、 Cloudflare Workers(OpenNext の Workers アセット出力)上で動作する。 データは Cloudflare D1(SQLite 互換)に永続化し、説明画像は Cloudflare R2 に保存する。 画像最適化は Cloudflare Queues + 専用 Worker で非同期処理する。

This system consists of a single application built on the Next.js App Router. The frontend and backend API coexist within the same application and run on Cloudflare Workers (via OpenNext's Workers asset output). Data is persisted in Cloudflare D1 (SQLite-compatible), and description images are stored in Cloudflare R2. Image optimization is handled asynchronously via Cloudflare Queues and a dedicated Worker.

システムアーキテクチャ概要図
システム全体のアーキテクチャ概要

2. レイヤー構成
Layer Structure

レイヤー技術役割
プレゼンテーション層React (RSC + Client Components)UI の描画・ユーザーインタラクション
状態管理層Jotai検索キーワード・モード・カテゴリ・ページ・表示形式のグローバル管理
データフェッチ層TanStack QueryAPI キャッシュ・ローディング・エラー状態管理
認証層HMAC セッション(Cookie)管理者セッション発行・検証(requireAdminSession
API 層Next.js Route Handlers(OpenNext Workers 上で実行)REST API エンドポイントの提供
DB アクセス層Prisma + @prisma/adapter-d1型安全な D1 操作(リクエストごとにクライアント生成)
データ永続化層Cloudflare D1用語データの永続化(SQLite 互換)
ストレージ層Cloudflare R2説明画像の保存・配信
キュー層Cloudflare Queues + 画像最適化 Worker画像最適化の非同期処理
ホスティング層Cloudflare Workers([assets] で静的アセット配信)OpenNext が生成する Worker で Next.js を提供

3. データフロー
Data Flow

3-1. 検索・カテゴリフィルターフロー

UI
ユーザー入力
SearchBar / SearchModeToggle / CategoryChipFilter
Jotai atoms 更新
searchQueryAtom / searchModeAtom / categoryFilterAtom / currentPageAtom
useTermList hook(デバウンス 300ms)
useQuery(["terms", "list", {q, searchBy, category, page}])
🗄
TanStack Query キャッシュ確認
キャッシュヒット → 即返却 / ミス → fetch へ
GET /api/terms
?q=ec2&searchBy=name&category=Compute&page=1&limit=20
🔷
Route Handler → Prisma → Cloudflare D1
getCloudflareContext() → env.DB → prisma.term.findMany(…)
JSON Response → キャッシュ保存 → 再レンダリング
{ terms: [...], pagination: {...} } → TermTable / TermCardGrid

3-2. CRUD フロー(追加・編集・削除)

UI
フォーム送信 / 削除確認
AddTermDialog / EditTermDialog / DeleteConfirmDialog
🔒
requireAdminSession 検証
認証 NG → 401 Unauthorized → エラートースト表示
useMutation → POST / PUT / DELETE /api/terms
Route Handler → createPrismaClient(env.DB) → D1
キャッシュ無効化 → テーブル・カード自動更新
queryClient.invalidateQueries(["terms"])

3-3. 画像アップロードフロー

UI
TermForm で画像ファイルを選択
JPEG / PNG / GIF / WebP、5MB 以下
POST /api/terms/upload-image
requireAdminSession 検証 → MIME / サイズバリデーション
🗂
R2 PUT + Queue SEND(同期)
terms/original/<uuid>.<ext> を R2 に保存 → IMAGE_OPTIMIZE_QUEUE へメッセージ送信
image-optimize-consumer Worker(非同期)
R2 GET → @jsquash で WebP 変換 → terms/slim/<uuid>.webp を R2 に保存 → D1 UPDATE
次回アクセスで slim 画像を優先表示
descriptionImageSlimKey が存在する場合は軽量版 URL を使用

3-4. 認証フロー
Authentication Flow

UI
管理者ログインダイアログでメール / パスワードを入力
AdminLoginDialog → AdminLoginControls
POST /api/auth/login
ADMIN_EMAIL / ADMIN_PASSWORD と照合(タイミング安全比較)
🔒
HMAC-SHA256 セッション発行(有効期限 7 日)
Set-Cookie: admin_session=<token>; HttpOnly; SameSite=Lax
ゲスト → 管理者ステータスに変化
CRUD ボタン・「+用語を追加」ボタン表示 / 「管理者ログイン」→「ログアウト」に変化

4. 画面構成
Screen Structure

localhost:3000
⌘K 管理者ログイン + 用語を追加
AWS 用語集
AWS サービスの用語・略称を素早く調べられるリファレンス
No.用語名略称カテゴリ説明操作
1Amazon EC2EC2 Compute スケーラブルな仮想サーバーをクラウドで提供✏️ 🗑️
2Amazon S3S3 Storage 高耐久性のオブジェクトストレージ✏️ 🗑️
3Amazon RDSRDS Database マネージド型リレーショナルデータベース✏️ 🗑️
… 57 件 …
1 2 3 全 60 件 / 3 ページ

5. デプロイ構成
Deployment Configuration

最終形態の公開先Cloudflare Workers(OpenNext の Workers アセット方式)を想定する。Node サーバーで next start する運用は採用しない。

🟠 Cloudflare Workers(メインアプリ)
name = "aws-glossary"
📄.open-next/worker.js — OpenNext が生成する Worker 本体
📁.open-next/assets/ — 静的アセット配信(binding: ASSETS)
🔗WORKER_SELF_REFERENCE — 自 Worker への参照
🔷D1 Database: aws-glossary-db env.DB
🗂R2 Bucket: aws-glossary-images env.TERM_IMAGES
Queues Producer: aws-glossary-image-optimize env.IMAGE_OPTIMIZE_QUEUE
🟣 画像最適化 Worker(別 Worker)
wrangler.image-optimizer.toml
📄image-optimize-consumer.ts
Queues Consumer: IMAGE_OPTIMIZE_QUEUE
🗂R2 バインディング: env.TERM_IMAGES
🔧@jsquash で WebP 軽量変換 → terms/slim/
💻 ローカル開発
next devinitOpenNextCloudflareForDev()
🔷Miniflare の D1 → .wrangler/state/ の SQLite ファイル
🗂Miniflare の in-memory R2
📋マイグレーション: pnpm db:migrate:local
🌱シード: pnpm db:seed:local
🚀E2E 用: pnpm dev:e2e

本番デプロイの一般的な流れ

  1. opennextjs-cloudflare build.open-next/worker.js + .open-next/assets/ を生成
  2. opennextjs-cloudflare deploy — 内部で wrangler deploy を呼び出して Workers にアップロード(pnpm deploy に集約)
  3. 画像最適化 Worker のデプロイ: pnpm deploy:image-workerwrangler deploy -c wrangler.image-optimizer.toml

ローカル開発と本番の差異

項目ローカル開発本番(Cloudflare)
DB.wrangler/state/ の SQLite ファイルCloudflare D1
R2Miniflare の in-memory R2Cloudflare R2
キュー送信は走るが Consumer が存在しなければ消費されないCloudflare Queues + 画像最適化 Worker
ランタイムMiniflare(workerd ベース)Workers Runtime
起動コマンドnext devinitOpenNextCloudflareForDev()opennextjs-cloudflare deploy
バインディングwrangler.toml の設定CF ダッシュボード / wrangler.toml の設定