一键导入
database-schema-design
Design database schema for the project
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Design database schema for the project
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when creating pages under src/app/(site)/(authorized)/admin/. Covers list/detail/edit/create page patterns with DataTable/DataView/DataForm, repositories under src/repositories/, request schemas under src/requests/admin/, and AdminPageHeader breadcrumbs.
Use when modifying Better Auth + Prisma authentication: src/libraries/auth.ts, src/libraries/auth-client.ts, src/proxy.ts, src/services/auth_service.ts, auth-related actions.ts, or prisma/schema.prisma auth models (User/Session/Account/Verification). Covers session helpers, URL/secret env resolution, DB TLS, and PUBLIC_PATHS.
Use when creating or modifying files under src/repositories/, src/models/, or src/requests/. Covers BaseRepository inheritance (Prisma/API/Local/Airtable/Dify), Zod schema placement, and separation between repository and schema files.
Use when changing this template's mail delivery backend, reviewing email env setup, switching between `ses` and `smtp`, or adding a new provider such as Resend, SendGrid, Postmark, or Mailgun. Covers EMAIL_PROVIDER routing, EMAIL_FROM priority, dynamic import for Node-only SDKs, and test coverage for both email.test.ts and Better Auth callback smoke.
Use when adding or changing translations in messages/ja.json or messages/en.json, using getTranslations/useTranslations, or updating next-intl configuration under src/i18n/. Covers message key hierarchy, Server/Client Component APIs, dynamic and rich-text patterns, and JSON duplicate-key pitfalls.
Use when adding or modifying pages under src/app, or components under src/components (atoms/molecules/organisms) in this Next.js App Router project. Covers Server/Client Component boundary, Atomic Design placement, Server Actions in actions.ts, URL-based state management, sidebar active-state, and shadcn-only atoms rule.
| name | database-schema-design |
| description | Design database schema for the project |
これは、RDBのデータスキーマを設計する際に、守るべきルールを記したものである。
このようなルールを設けた理由は、ルールの統一によってメンテナンスしやすくできるから、というだけでなく、DB Schemaデザインの際に、迷ったり、哲学の違いから揉めたりすることをなくするためである。
したがって、ここに書かれているルールが、自分の哲学と違っている、と感じる開発者もいるはずである。しかし、このプロジェクトとして設計、開発するものに関しては、ここで示されたルールに則って設計を行うように。
RDB(Relational Database)として、PostgreSQLを利用することを前提とする。
data は複数形であるが、わかりづらいため利用しないプライマリーキーのカラム名は id とする。user_id のようにテーブル名の単数形をつける流儀もあるが、ここではすべて id で統一する。
プライマリーキーの形式であるが、UUID v4 あるいは BigIntの値とする。プライマリーキーの形式は、プロジェクト全体で統一する。UUID と連続する数値のどちらを使うべきかは、プロジェクトの性格によって異なるが、IDをつかって生成順にソートする必要があるテーブルが有る場合には BigIntを、そうでなければ UUIDを利用するとよい。
なお、数値を使う場合、Int (32bit) ではなく、BigInt (64bit) を利用する。これは、将来桁あふれが発生するリスクを少しでも抑えるためである。
カラム名はSnake Caseにする。user_id や access_token といった形式になる。
カラム名は、それを見ただけで何が格納されているのかがおおよそ想像できるものが望ましい。したがって、なるべく一般的な名称を用いる、プロジェクト内で同じ意味のカラムは必ず同じ名前にする。わかりやすさを最大限重要視する。
日時を表すカラムは、created_at や registered_at のように、過去形の後に _at のPrefixをつける。
データ型は BigInt を利用し、Unix Timestampで値を扱う。その理由は、parseが簡単で、タイムゾーンによる影響を受けず、ほとんどの言語の時間を扱うライブラリで標準でサポートされているからである。RDBMSはDateTimeを扱う専用の型を用意しているが、タイムゾーンの取り扱いに差異があり、またタイムゾーンの値が、そのDBの設定(やOSの設定)に依存するため、ポータビリティが下がる恐れがあるためである。
ただし、タイムゾーンの関係のない、「日付」のデータに関しては、Date型を利用する。しかしその情報が、本当に日付だけで将来に渡って事足りているのかは、よく吟味する必要がある。たとえば「登録日」を保存しておきたかった場合でも、将来時間も必要になるかもしれないので、UnixTimestamp にしておいたほうが良いかもしれない。
テキストカラムは VARCHAR ではなく、TEXTを利用する。これは、PostgreSQLにおいては、2つのタイプの違いは、VARCHAR が文字列の長さをチェックすることだけであり、それ以外は同じであるためである。
すべてのテーブルには、レコードの作成日時を表す created_at と、最終更新日時を表す updated_at を用意し、作成時、更新時に自動でその時間がセットされるようにする。
この2つのカラムに関しては、日時を表しているが UnixTimestampではなく、TIMESTAMP型を利用する。
その理由は、これらのデータがフレームワークによっては自動的に扱われるため、その仕様に合わせるためである。
なお、この2つの情報は、純粋にロギングとトラブル時の問題切り分けに利用するにとどめ、サービス、システムのビジネスロジック上において、この値を使って何かを判断してはならない。
たとえば、users の created_atを利用して、ユーザーの登録日時を判断してはならない。もしユーザーの登録日時を利用する場合は、その代わりに、registered_atという別のカラム(Int型)を用意して利用する。
それは、created_atとupdated_atのカラムが、データの移行など意図しないタイミングで変更される可能性があるからである。
フラグを表すカラムは、is_ やhas_ などのPrefixをつけることで、それがはっきりとフラグであり、boolean であることがわかるようにする。Prefixがis_ なのかhas_なのか、それ以外なのかは、フラグの意味によって適切なものを選択する。
カラムに格納するデータとして、マジックナンバーの利用は絶対に避ける。
たとえば orders というテーブルに、注文の状況を表す status というカラムがあったとする。その場合、このカラムのデータ型をIntにして、1だったら注文完了、2だったら配達処理完了、のような設計をすることは絶対にしてはならない。
なぜなら、その場合、それぞれの数値が何を表しているかを知らなければ、内容を理解することができないからであり、「テーブルだけを見ても意味がおおよそ理解できる」という原則に反することになる。
したがって、statusのカラムは文字列型として、ordered や delivered といった文字列を格納するようにする。
原則としてNULLは許容しない設計とする。NULLを許容する場合は、NULLに意味がある場合のみとする。NULLに意味がある場合とは、NULLであることで明示的に、そのカラムのデータが存在しないことを表す場合である。
などである。NULLを許容する場合は、コメントでその理由を記述する。
ビジネス要件的に明らかな初期値として設定可能な情報が存在する場合は、その値を設定する。
ただし、初期値値が不明で、明示的にレコード作成時に値を設定することがビジネス要件上必須な場合は、デフォルト値を設定しない。たとえば、医療系のシステムで、患者の体温を記録するテーブルがある場合、そのテーブルにはデフォルト値を設定すると、間違った情報が記録される恐れがあるので、記録しない。
原則として、ビジネス上の追跡可能性(トレーサビリティ)が必要なデータには論理削除を採用するが、最低限にとどめる。
論理削除を行う場合は deleted_at というカラムを用意し、そのカラムに削除が行われた日時を格納し、がNULLであれば削除されていない、とする。ただし、フレームワークによって異なる方法が取られていた場合は、それに準じた構造とする。
テーブル同士のRelationを表現する場合は、外部キーを設定するが、その名前は、例えば users テーブルの id カラムを別のテーブルから指定する場合には user_id という感じで、テーブル名の単数形にカラム名を連結して表す。
Many to many のRelationを表す場合は、Relation Tableを定義するが、その場合は、例えば users と roles の場合であれば、user_roles のように、片方の単数形に他方の複数形を連結した形として、内部には user_id と role_id が含まれるようにする。どちらを単数形にするかは、テーブル同士の関係性を考慮し、より重要と思われるデータを選択する。