プロダクトを構築

データベースとマイグレーション

PostgreSQL の運用先を選び、実行中のアプリを壊さず Drizzle の変更をリリースします。

スターターのコミット 2a1a04a で検証済みです。

このページを終えると、各環境で使う DB、スキーマ変更をレビュー可能な SQL にする方法、アプリのリリースとは分けて適用する方法が分かります。

スターターは複数の DB アダプターを用意せず、PostgreSQL と Drizzle を採用しています。ローカルでは pnpm setup で Docker 上の PostgreSQL を使えます。本番では、互換性のあるマネージド PostgreSQL または自社運用の PostgreSQL を選び、DATABASE_URL を設定します。src/db/schema.ts がスキーマの正本で、src/db/migrations/ にコミットされた SQL がデプロイ履歴です。db() を呼べるのは src/models/** だけです。

ローカル手順

pnpm setup は開発用とテスト用の DB を分けて作ります。テスト DB の名前には test が必要で、安全機構はそれ以外の DB の全行削除を拒否します。

スキーマ変更後:

pnpm db:generate
pnpm db:lint
pnpm db:migrate
pnpm test:db:setup
pnpm test:db

生成された SQL と meta/_journal.json をコードと一緒にコミットし、デプロイ済みのマイグレーションは編集しません。

本番手順

アプリのデプロイ時にマイグレーションは自動実行されません。DB とアプリを別々に監視し、再試行し、リリースできるようにする既定の安全策です。

pnpm db:check:prod
pnpm db:migrate:prod
pnpm db:integrity

本番用の実行処理は、非対話で PostgreSQL のアドバイザリーロックを取得し、チェックサムを検証します。先にバックアップを取り、スキーマとアプリを別々にリリースしても新旧コードの両方が動く、追加してから削除する段階的な変更にします。

データ規約

  • 数値 id は内部用、公開 API は uuid を使います。
  • 金額は最小通貨単位の整数と通貨コードで保存します。
  • テナントに属する行は org_uuid を持ち、すべてのモデルクエリで組織を限定します。
  • 冪等性キーと取引番号は、DB の一意制約で守ります。
  • Account erase が不可逆 pseudonym を使うため identity relation は論理的です。Task-ledger、job、output file の重要関係は foreign key で保護され、削除順は lifecycle service が担います。
  • 予約では PostgreSQL の排他制約も使い、仮押さえ・確定済みの時間枠が重複するのを防ぎます。

本番前に決めること

  • マイグレーションを CI のリリースジョブと運用担当者のどちらが実行するか決めます。各 Web インスタンスからは実行しません。
  • データの価値に見合うバックアップ・復元方針を決めます。マイグレーションロックはバックアップの代わりではありません。
  • Relation 変更前後に db:integrity を実行します。Migration linter は破壊的 drop、危険な rename、無制限 rewrite、blocking unique index を説明なしでは拒否します。
  • 無停止を目指す場合は、追加してから削除する段階的な変更を優先します。破壊的な一段階の名前変更は簡単ですが、スキーマとコードのリリースを結合し、ロールバックを危険にします。

pnpm db:check:prod が予想どおりの未適用一覧を示し、バックアップが最新で、ステージング環境の複製で検証済みであり、展開中に旧・新両方のアプリ版が動くなら、本番マイグレーションの準備は完了です。

本番データの契約を変える前に、スターターの docs/database.mdDEPLOYMENT.md を読んでください。コードの置き場所はアーキテクチャとエラー契約、認証用 ID と公開 ID の区別は顧客認証で確認できます。

データベースとマイグレーション · Sushi SaaS