DB スキーマ詳細
DB Schema Details

1. Prisma スキーマ(prisma/schema.prisma
Prisma Schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")  // Prisma CLI / migrate diff 用(実行時は D1 アダプタ)
}

model Term {
  id                      Int      @id @default(autoincrement())
  name                    String   @unique
  abbreviation            String?
  category                String?
  description             String
  descriptionImageKey     String?
  descriptionImageSlimKey String?
  createdAt               DateTime @default(now())
  updatedAt               DateTime @updatedAt
}
実行時は @prisma/adapter-d1env.DB(D1Database)を使用する。provider"sqlite" のまま(D1 は SQLite 互換)。DATABASE_URL はアプリの D1 接続には使わない。

2. ER 図
ER Diagram

アプリが管理するデータは Term テーブル 1 本。画像ファイルは R2 に格納し、D1 にはキー文字列のみ保持する。

%%{init: {'theme': 'default', 'themeVariables': {'fontSize': '13px'}}}%% erDiagram Term { int id PK "AUTOINCREMENT" string name UK "NOT NULL / UNIQUE" string abbreviation "nullable" string category "nullable" string description "NOT NULL" string descriptionImageKey "nullable / R2 original key" string descriptionImageSlimKey "nullable / R2 slim key" datetime createdAt "DEFAULT CURRENT_TIMESTAMP" datetime updatedAt "Auto-updated" }

PK = Primary Key / UK = Unique Key / nullable フィールドは Prisma では String?

R2 画像キーの仕組み
R2 Image Key Structure

%%{init: {'theme': 'default', 'themeVariables': {'fontSize': '13px', 'lineColor': '#9ca3af', 'edgeLabelBackground': '#fff'}}}%% flowchart LR Upload["画像アップロード\nPOST /api/terms/:id/image"] R2O["R2\nterms/original/{key}"] Queue["Queues\naws-glossary-image-optimize"] Worker["画像最適化 Worker"] R2S["R2\nterms/slim/{key}.webp"] DB["D1 Term テーブル\ndescriptionImageKey\ndescriptionImageSlimKey"] Upload -->|"R2 put"| R2O Upload -->|"produce"| Queue Queue -->|"consume"| Worker Worker -->|"WebP 生成 → put"| R2S Worker -->|"slim-key 書き込み"| DB R2O -->|"original key 保存"| DB style R2O fill:#f0fdf4,stroke:#22c55e,color:#15803d style R2S fill:#f0fdf4,stroke:#22c55e,color:#15803d style DB fill:#eff6ff,stroke:#3b82f6,color:#1d4ed8 style Queue fill:#fdf4ff,stroke:#c026d3,color:#7e22ce

スリムキーが存在しない場合、GET /api/media/:key はオリジナルキーの URL を返す


3. テーブル定義
Table Definitions

Term テーブル
Term Table

カラム名 制約 説明
id INTEGER PK NOT NULL AUTOINCREMENT 主キー
name TEXT UNIQUE NOT NULL 用語名(重複登録防止)
abbreviation TEXT nullable 略称・略語(例: EC2, S3)
category TEXT nullable カテゴリ(例: Compute, Storage)
description TEXT NOT NULL 用語の説明文
descriptionImageKey TEXT nullable R2 オリジナル画像キー(terms/original/…
descriptionImageSlimKey TEXT nullable R2 軽量版キー(terms/slim/….webp)。Worker が生成後に書き込む
createdAt DATETIME NOT NULL DEFAULT NOW 作成日時
updatedAt DATETIME NOT NULL AUTO UPDATE 最終更新日時

4. マイグレーション管理(wrangler d1 migrations)
Migration Management

Prisma Migrate の代わりに prisma migrate diff で SQL を生成し、prisma/migrations/ に手動で配置する。適用は wrangler d1 migrations apply で行う。

マイグレーションファイル構成
Migration File Structure

prisma/
├── migrations/
│   ├── 0001_init.sql
│   ├── 0002_description_image_key.sql
│   └── 0003_description_image_slim_key.sql
└── schema.prisma

0001_init.sql

-- CreateTable
CREATE TABLE "Term" (
    "id"           INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    "name"         TEXT NOT NULL,
    "abbreviation" TEXT,
    "category"     TEXT,
    "description"  TEXT NOT NULL,
    "createdAt"    DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updatedAt"    DATETIME NOT NULL
);

-- CreateIndex
CREATE UNIQUE INDEX "Term_name_key" ON "Term"("name");

マイグレーション実行コマンド
Migration Commands

# ローカル D1 にマイグレーションを適用
pnpm wrangler d1 migrations apply aws-glossary-db --local

# 本番 D1 にマイグレーションを適用
pnpm wrangler d1 migrations apply aws-glossary-db --remote

# マイグレーション状態の確認
pnpm wrangler d1 migrations list aws-glossary-db --local

スキーマ変更時の手順
Schema Change Procedure

# 1. schema.prisma を編集

# 2. 差分 SQL を確認(新規ファイルを prisma/migrations/0004_xxx.sql で追加)
pnpm prisma migrate diff \
  --from-empty \
  --to-schema-datamodel prisma/schema.prisma \
  --script

# 3. ローカル D1 に適用して動作確認
pnpm wrangler d1 migrations apply aws-glossary-db --local

# 4. Prisma Client を再生成
pnpm prisma generate

# 5. 本番に適用
pnpm wrangler d1 migrations apply aws-glossary-db --remote

5. D1 データベースのセットアップ手順
D1 Database Setup

# 1. D1 データベースを作成
pnpm wrangler d1 create aws-glossary-db

# → 出力例(この database_id を wrangler.toml に貼り付ける):
# [[d1_databases]]
# binding = "DB"
# database_name = "aws-glossary-db"
# database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# 2. ローカルにマイグレーション適用
pnpm wrangler d1 migrations apply aws-glossary-db --local

# 3. シードデータ投入(ローカル)
pnpm wrangler d1 execute aws-glossary-db --local --file=prisma/seed.sql

6. 環境変数・バインディング設定
Environment Variables & Binding Configuration

D1 Database
env.DB
binding = "DB"
全 CRUD 操作・Prisma アダプタ経由
R2 Bucket
env.TERM_IMAGES
binding = "TERM_IMAGES"
画像アップロード・プロキシ配信
Queues Producer
env.IMAGE_OPTIMIZE_QUEUE
binding = "IMAGE_OPTIMIZE_QUEUE"
画像最適化ジョブをプロデュース
Secret
ADMIN_PASSWORD_HASH
管理者パスワードの HMAC ハッシュ
wrangler secret put で設定

wrangler.toml

name = "aws-glossary"
main = ".open-next/worker.js"
compatibility_date = "2024-09-23"
compatibility_flags = ["nodejs_compat", "global_fetch_strictly_public"]

[assets]
directory = ".open-next/assets"
binding = "ASSETS"

[[services]]
binding = "WORKER_SELF_REFERENCE"
service = "aws-glossary"

[[d1_databases]]
binding = "DB"
database_name = "aws-glossary-db"
database_id = "<D1_DATABASE_ID>"
migrations_dir = "prisma/migrations"

[[r2_buckets]]
binding = "TERM_IMAGES"
bucket_name = "aws-glossary-images"
# ローカルは Miniflare の in-memory R2(remote=true は付けない)

[[queues.producers]]
binding = "IMAGE_OPTIMIZE_QUEUE"
queue = "aws-glossary-image-optimize"

.dev.vars(ローカル開発用・gitignore 対象)

# wrangler dev が読み込む環境変数
# D1 は wrangler.toml のバインディングで管理するため DATABASE_URL は不要
# 管理者パスワードなど必要な変数をここに追記する
D1 は DATABASE_URL ではなく env.DB(D1Database オブジェクト)としてバインディング経由でアクセスする。 .envDATABASE_URL は Prisma CLI 用のみ。

7. シードデータ(prisma/seed.sql
Seed Data

マスターデータは prisma/seed-data.ts に定義し、pnpm db:seed:generateprisma/seed.sql を生成する。生成 SQL は name 一意で UPSERT(既存行の説明も更新できる)。

pnpm db:seed:generate          # seed-data.ts → seed.sql を再生成
pnpm db:seed:local             # ローカル D1 へ投入
# pnpm db:seed:remote          # リモート D1 へ投入(本番データに影響するため注意)

8. テストと D1
Testing & D1

  • Unit
    Vitestsrc/**/*.test.{ts,tsx}(ソースと同ディレクトリにコロケーション)
    スキーマ・Zod・Jotai atoms など DB に依存しない検証。tests/unit/ は使用しない。
  • Integration
    Vitest + @cloudflare/vitest-pool-workerspnpm test:integration
    wrangler.integration.toml 上の D1 に対し Prisma 経由で listTerms 等を検証する。
  • E2E
    Playwrightpnpm test:e2e
    playwright.config.tswebServerpnpm dev:e2e(マイグレーション+シード後の next dev)を起動して実行する。