データベース概要
前提
| 項目 | 内容 |
|---|---|
| DBMS | PostgreSQL 17 |
| ORM | Drizzle ORM |
| スキーマ定義 | src/db/schema.ts(単一ファイルが唯一の定義元) |
| 開発時の反映 | bun run db:push(スキーマを DB に直接反映) |
| マイグレーション | bun run db:generate でファイル生成、scripts/migrate.ts が本番で実行 |
| GUI | bun run db:studio(Drizzle Studio) |
命名は snake_case、テーブル名は複数形。主キーはすべて serial(integer の auto-increment)。日時は timestamp(タイムゾーンなし)。
論理削除は使わない
deleted_at による論理削除は採用していない。削除は物理削除で、外部キーの onDelete: cascade によって関連レコードも消える。予約のみ、キャンセルを status = 'cancelled' で表現する。
ER 図
erDiagram
users ||--o{ projects : "created_by"
users ||--o{ project_interviewers : "user_id"
users ||--o{ reservations : "interviewer_id"
users ||--o{ candidate_available_dates : "interviewer_id"
projects ||--o{ project_candidates : "project_id"
projects ||--o{ project_interviewers : "project_id"
projects ||--o{ email_templates : "project_id"
projects ||--o{ import_logs : "project_id"
candidates ||--o{ project_candidates : "candidate_id"
project_candidates ||--o| reservations : "project_candidate_id"
project_candidates ||--o{ scheduling_tokens : "project_candidate_id"
project_candidates ||--o{ candidate_available_dates : "project_candidate_id"
project_candidates ||--o{ email_logs : "project_candidate_id"
project_candidates ||--o{ status_histories : "project_candidate_id"
email_templates ||--o{ email_logs : "template_id"
調査メタキャッシュ(databricks_surveys)は上記のいずれとも外部キーで結ばれていない。回答本体は Postgres に持たず、Databricks から直接読む(Databricks 連携)。
テーブル一覧
| テーブル | 論理名 | 分類 | ページ |
|---|---|---|---|
users |
ユーザー | コア | コア |
projects |
プロジェクト | コア | コア |
candidates |
候補者 | コア | コア |
project_candidates |
プロジェクト候補者 | コア | コア |
project_interviewers |
プロジェクト面接官 | コア | コア |
scheduling_tokens |
調整トークン | 日程調整 | 日程調整 |
candidate_available_dates |
候補者希望日程 | 日程調整 | 日程調整 |
reservations |
予約 | 日程調整 | 日程調整 |
status_histories |
ステータス履歴 | 日程調整 | 日程調整 |
email_templates |
メールテンプレート | メール | メール |
email_logs |
メール送信ログ | メール | メール |
import_logs |
インポートログ | インポート | インポート・調査メタキャッシュ |
databricks_surveys |
調査メタ | インポート | インポート・調査メタキャッシュ |
enum 一覧
| enum 名 | 値 | 使用箇所 |
|---|---|---|
user_role |
admin / member / viewer |
users.role |
project_status |
draft / active / completed / archived |
projects.status |
interview_type |
online_meet / online_zoom / offline / any |
projects.interview_type |
selection_type |
primary / reserve |
project_candidates.selection_type |
pc_status |
not_contacted / contacted / waiting_response / scheduling / scheduled / interviewed / completed / declined / bounced / cancelled |
project_candidates.status |
template_type |
invitation / reminder / confirmation / cancellation |
email_templates.type |
email_status |
sent / delivered / bounced / failed |
email_logs.status |
reservation_interview_type |
online_meet / online_zoom / offline |
reservations.interview_type |
reservation_status |
confirmed / cancelled |
reservations.status |
import_type |
manual_tsv / manual_survey / auto_survey |
import_logs.import_type |
import_status |
pending / processing / completed / partial / failed |
import_logs.status |
interview_type は 2 種類ある
プロジェクトは「指定なし」を許すため any を持つが、確定した予約は形式が決まっているため reservation_interview_type には any がない。
JSON カラム
構造を持つ JSON カラムは、型が src/db/schema.ts または src/types/survey-import.ts に定義されている。
| テーブル.カラム | 型 | 内容 |
|---|---|---|
projects.scoring_rules |
ScoringRules |
スコアリングルールの配列と上限点 |
projects.survey_import_mapping |
ImportMapping |
アンケート回答からのフィールドマッピング |
projects.survey_import_filter |
ImportFilter |
アンケートインポート時の絞り込み条件 |
projects.arrange_settings |
ArrangeSettings |
アレンジフロー STEP1〜3 の設定 |
project_candidates.attributes |
Record<string, unknown> |
候補者属性(jsonb) |
project_candidates.survey_responses |
Record<string, unknown> |
アンケート回答(jsonb) |
import_logs.error_details |
ImportError[] |
インポートエラーの明細 |
import_logs.payload |
Record<string, unknown> |
インポート実行時のリクエスト内容 |
arrange_settings の型は二重定義
backend の src/db/schema.ts と frontend の src/types/arrange-settings.ts の両方に定義がある。片方を変えたらもう片方も直す。
インデックス方針
- 一覧の絞り込みに使う列に複合インデックスを張る(
idx_pc_project_status/idx_res_interviewer_scheduledなど) - 一意性制約は
unique()で明示する(uk_project_candidate/uk_project_user) - 調査メタキャッシュは更新日時(
synced_at)にインデックスを持つ