データベースのセットアップ
Postgres と Drizzle ORM を設定 — 認証、課金、ストレージ、タスク、各種アプリテーブルを支える中核です。
データベースは現代の SaaS の中心です。認証、課金、クレジット、ストレージ、利用状況の記録、さらにはデモ機能まで、すべてが DB を通ります。私たちはしばしば「CRUD エンジニア」と冗談を言いますが、作成・読み取り・更新・削除こそが日々の本質です。スキーマが大きくなるほど、DB を土台として扱うことで、アプリ全体の予測可能性が高まります。
本ガイドは DB を最優先に扱います。スキーマが機能にどう対応するか、Drizzle で型安全な CRUD をどう行うかを説明し、その後に接続・マイグレーション・検証の手順を示します。
なぜ DB が最初か
- 事実のソース: 認証・課金・ファイル・タスクは DB に永続化され、サービス/API 層で結合されます。
- スキーマ → 型 → UI:
src/db/schema.ts
の Drizzle モデルから安全な型が生成され、モデルやルートで共有されます。 - CRUD は UI そのもの: 多くの画面は読み書き可能な一覧や詳細です。テーブル設計が良ければ UI 実装は速くなります。
本テンプレートの主要ドメイン(テーブル → 機能)
- 認証:
users
、sessions
、accounts
、verifications
(Better Auth)。 - 課金とクレジット:
orders
、credits
が購入と台帳を管理。 - ストレージ:
files
が S3/R2 のメタデータとライフサイクル(uploading → active → deleted)を保持。 - 利用状況とタスク(AI):
tasks
が queued/running/completed を記録し、credits_trans_no
で台帳にひも付け。 - コンテンツ:
posts
。 - グロースとフィードバック:
affiliates
、feedbacks
。 - デモ:
reservation_services
、reservations
がスケジューリング/デポジットのパターンを提示。
コードにおける CRUD ファーストのパターン
- モデルは
src/models/*
にあり、型付きヘルパーを提供:src/models/file.ts
:insertFile
、findFileByUuid
、updateFileByUuid
、listFilesByUser
、softDeleteFile
。src/models/task.ts
:insertTask
、findTaskByUuid
、getTasksByUserUuid
、updateTaskStatus
。
- サービスや API ルートはこれらのヘルパーを呼び出します。DB アクセスは集中管理しましょう。
- 新機能の進め方:
src/db/schema.ts
でモデリング →pnpm drizzle-kit generate
→pnpm drizzle-kit migrate
→src/models/<domain>.ts
を追加 →src/services/*
とルートから利用。
1. Drizzle ORM とは?
Drizzle ORM は TypeScript と Postgres をつなぐ型安全なレイヤーです。src/db/schema.ts
に定義したスキーマが唯一の真実となり、ここから以下を行います。
drizzle-kit
でマイグレーション SQL を生成- 生成したマイグレーションを Postgres に適用
- アプリ全体で型を共有 (
users.$inferSelect
など)
SQL ファイルを手書きする必要はありません。スキーマを編集し、Drizzle にマイグレーション作成と適用を任せます。
2. データベースのシナリオを決める
状況に合わせて .env
を設定してください。
シナリオ | 推奨内容 |
---|---|
ローカル開発のみ | Docker で Postgres を起動 (docker run ... postgres:16 ) し、DATABASE_URL を postgres://postgres:postgres@localhost:5432/postgres に設定。 |
マネージド Postgres (Neon, Supabase, Railway など) | プロバイダーが発行する接続文字列を使用し、マイグレーションを実行する IP を許可。 |
環境ごとに別 DB | ローカル用は .env 、本番用はホスティング側のシークレットに設定。 |
既存 DB にテーブル追加 | Drizzle は src/db/schema.ts に定義したテーブルのみを変更します。名前の衝突がないか確認し、必要ならスキーマ (schema) を分けます。 |
メモ: Drizzle はデータベース自体を作成しません。マイグレーション前に空の DB を用意してください。
3. 環境変数を設定する
接続文字列と Better Auth のシークレットを定義します。.env
、.env.local
、.env.development
を自動で読み込みます。
DATABASE_URL="postgresql://user:password@host:5432/db?sslmode=require"
BETTER_AUTH_SECRET="$(openssl rand -base64 32)"
BETTER_AUTH_URL="http://localhost:3000"
値を変更したら pnpm dev
を再起動して反映させてください。
4. スキーマ関連のファイルを把握する
src/db/schema.ts
– Better Auth のテーブル(users
、sessions
、accounts
、verifications
)とアプリ独自テーブル:orders
、credits
、files
、tasks
、posts
、affiliates
、feedbacks
、reservation_services
、reservations
。src/db/config.ts
– drizzle-kit の設定 (スキーマパスと Postgres URL)。src/lib/auth.ts
– Better Auth のフィールドと Drizzle の列をマッピング。users
の列名を変更した場合はここも更新します。
新しい列やテーブルを追加するときは schema.ts
を編集し、必要であれば auth.ts
のマッピングも更新します。読み取り性能のため、schema.ts
で適切にインデックス(uniqueIndex
/index
)を定義することを推奨します。
5. コード変更後にマイグレーションを生成する
schema.ts
を変更したら以下を実行します。
pnpm drizzle-kit generate --config src/db/config.ts
想定される出力:
Reading config file 'src/db/config.ts'
...
[✓] Your SQL migration file ➜ src/db/migrations/0002_add_user_flag.sql 🚀
生成されるファイル:
src/db/migrations/<timestamp>_*.sql
src/db/migrations/meta/_journal.json
どちらも Git にコミットします。
6. マイグレーションを Postgres に適用する
生成済み SQL をデータベースに流します。
pnpm drizzle-kit migrate --config src/db/config.ts
成功例:
Applying migrations from src/db/migrations
Migration 0002_add_user_flag.sql executed in 380 ms
All migrations applied!
認証エラーが出る場合は DATABASE_URL
を確認してください。タイムアウトする場合は IP 制限やコンテナの起動をチェックします。
7. 結果を確認する
任意の Postgres クライアントでテーブルや列を確認します。psql
の例:
\dt
SELECT * FROM sessions LIMIT 1;
SELECT email_verified FROM users LIMIT 1;
Better Auth のテーブルに加え、アプリの主要テーブルも見えるはずです。簡単な CRUD のスモークテストとして、モデルヘルパー経由で 1 行を insert して取得してみてください(例: POST /api/storage/uploads
で最小の files
を作成後、SELECT * FROM files LIMIT 1;
)。
8. 認証フローを試す
マイグレーション適用後に pnpm dev
を再起動し、/ja/signup
(または任意のロケール) でユーザー登録をテストします。ホームへリダイレクトされ、users
と sessions
にレコードが作成されます。
9. トラブルシューティング
- Error: model "userss" not found –
src/lib/auth.ts
がusers
を参照しているか確認。古いサンプルからusePlural
をコピーしていたら削除してください。 - カラムが見つからない –
schema.ts
を変えたのにgenerate
とmigrate
を忘れている可能性があります。もう一度実行します。 - 接続できない – DB が存在するか、認証情報が正しいか、ネットワーク設定 (SSL/許可 IP) を確認します。
- ゼロからやり直したい – テーブルを手動で削除するか、drizzle-kit の SQL を利用してロールバックし、その後再度
generate
→migrate
を実施します。
常に「コードを変更 → マイグレーション生成 → 適用 → 検証」の流れを守れば、認証フローで 500 エラーが出るのを防げます。