データモデル
概念モデル図
erDiagram
users ||--o{ projects : "作成する"
users ||--o{ project_interviewers : "面接官として参加する"
users ||--o{ reservations : "面接を担当する"
projects ||--o{ project_candidates : "候補者を持つ"
projects ||--o{ project_interviewers : "面接官を持つ"
projects ||--o{ email_templates : "テンプレートを持つ"
projects ||--o{ import_logs : "インポート履歴を持つ"
candidates ||--o{ project_candidates : "参加する"
project_candidates ||--o| reservations : "確定予約を持つ"
project_candidates ||--o{ scheduling_tokens : "調整トークンを持つ"
project_candidates ||--o{ candidate_available_dates : "希望日程を持つ"
project_candidates ||--o{ email_logs : "送信履歴を持つ"
project_candidates ||--o{ status_histories : "ステータス履歴を持つ"
email_templates ||--o{ email_logs : "利用される"
エンティティ概要
コア
| エンティティ名 |
物理名 |
説明 |
| ユーザー |
users |
管理画面のユーザー。Google アカウントに 1 対 1 で対応し、面接官もここに含まれる |
| プロジェクト |
projects |
1 回のインタビュー企画。面接条件・スコアリングルール・アンケートインポート設定・アレンジ設定を持つ |
| 候補者 |
candidates |
個人そのもの。プロジェクトをまたいで一意(external_user_id) |
| プロジェクト候補者 |
project_candidates |
候補者のプロジェクトへの参加。ステータス・スコア・選定区分・回答内容を持つ |
| プロジェクト面接官 |
project_interviewers |
プロジェクトと面接官(ユーザー)の紐付け |
日程調整
| エンティティ名 |
物理名 |
説明 |
| 調整トークン |
scheduling_tokens |
候補者向け公開ページへのアクセストークン。有効期限を持つ |
| 候補者希望日程 |
candidate_available_dates |
候補者が送信した希望枠。送信のたびに全置換される |
| 予約 |
reservations |
確定した面接。プロジェクト候補者につき最大 1 件(UNIQUE) |
| ステータス履歴 |
status_histories |
候補者ステータスの遷移記録 |
メール
| エンティティ名 |
物理名 |
説明 |
| メールテンプレート |
email_templates |
種別つきのテンプレート。project_id が NULL ならシステム共通 |
| メール送信ログ |
email_logs |
送信済みメールの件名・本文・結果 |
インポートと調査メタキャッシュ
| エンティティ名 |
物理名 |
説明 |
| インポートログ |
import_logs |
TSV / アンケートインポートの実行履歴と件数・エラー内訳 |
| 調査メタ |
databricks_surveys |
調査のメタデータキャッシュ。日次バッチで Databricks から更新する |
主要なビジネスルール
候補者とプロジェクト候補者の分離
- 個人としての候補者(
candidates)と、プロジェクトへの参加(project_candidates)を分離している
candidates.external_user_id は全体で UNIQUE。同じ人物が複数プロジェクトに参加しても candidates は 1 レコード
project_candidates は (project_id, candidate_id) の組で UNIQUE(uk_project_candidate)。同一プロジェクトへの二重登録は不可
- 回答内容(
survey_responses)・属性(attributes)・スコア・選定区分はプロジェクトごとに持つ
予約
reservations.project_candidate_id は UNIQUE。1 人の候補者につきプロジェクト内で確定予約は最大 1 件
- キャンセルはレコード削除ではなく
status = 'cancelled' への更新
interviewer_id は users を onDelete: restrict で参照するため、予約が残るユーザーは削除できない
ステータス遷移
project_candidates.status の遷移は許可された組み合わせのみ(機能 のステータス遷移図を参照)
- 遷移のたびに
status_histories に 1 行追加される
completed と declined は終端。bounced からは contacted へ、cancelled からは not_contacted へ戻せる
カスケード削除
projects を削除すると、project_candidates / project_interviewers / email_templates / import_logs が連鎖削除される。project_candidates の削除はさらに email_logs / scheduling_tokens / candidate_available_dates / reservations / status_histories に連鎖する。
調査メタキャッシュ
databricks_surveys は外部データのキャッシュであり、アプリケーション側のテーブルとは外部キーで結ばれていない
- 回答本体は Postgres に持たない。 Databricks の
cs.cs_dm.dm_answers_<survey_id> から直接読む(Databricks 連携)
- 回答は
panel_id + 設問文で 1 行という縦持ち形式。設問 ID が存在しないため設問文そのものが識別子になる
- 候補者への取り込みは、この縦持ちデータを横持ちに畳んで
project_candidates.survey_responses に格納する
個人情報の保持
- 個人情報(
candidates の氏名・メール・電話)は保持期間(既定 3 ヶ月)超過後に pii-cleanup バッチで匿名化される
- 集計のため
project_candidates などの関連レコードは残す