面接官 API
プロジェクトへの面接官の登録と、Google Calendar を用いた空き枠算出・仮枠押さえ。共通規約は API 共通仕様 を参照。
ベースパス: /api/v1/projects/{projectId}/interviewers
| メソッド | パス | 概要 | 必要ロール |
|---|---|---|---|
| GET | / |
面接官一覧取得 | viewer |
| POST | / |
面接官追加 | member |
| DELETE | /{userId} |
面接官削除 | member |
| GET | /availability |
面接官空き状況取得 | viewer |
| POST | /tentative-slots |
仮枠カレンダーイベント作成 | member |
| DELETE | /tentative-slots |
仮枠カレンダーイベント削除 | member |
全エンドポイントで Authorization: Bearer <access_token> が必要。更新系は member 以上。
面接官一覧取得
URI
レスポンス(200 OK)
data が Interviewer の配列(ページネーションなし)。
{
"success": true,
"status": "success",
"statusCode": 200,
"data": [
{
"id": 3,
"projectId": 1,
"userId": 5,
"user": {
"id": 5,
"email": "interviewer@example.com",
"name": "末成",
"picture": null,
"role": "member",
"createdAt": "2026-01-10T09:00:00Z"
},
"createdAt": "2026-01-15T09:00:00Z"
}
],
"path": "/api/v1/projects/1/interviewers",
"method": "GET"
}
| フィールド | 型 | 説明 |
|---|---|---|
id |
integer | project_interviewers.id |
projectId |
integer | プロジェクト ID |
userId |
integer | ユーザー ID |
user |
object | ユーザー情報 |
createdAt |
string(date-time) | 追加日時 |
例外処理
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| トークンが欠落または無効 | 401 | Unauthorized |
| プロジェクトが存在しない | 404 | Not Found |
| サーバ内部エラー | 500 | Internal Server Error |
面接官追加
URI
リクエストボディ
バリデーションルール
| フィールド | ルール |
|---|---|
userId |
必須。正の整数。既存ユーザーを参照すること |
追加対象のユーザー ID は ユーザー API の一覧から取得する。
レスポンス(201 Created)
data に作成された Interviewer。
例外処理
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| バリデーションエラー | 400 | Bad Request |
| トークンが欠落または無効 | 401 | Unauthorized |
| ロール不足 | 403 | Forbidden |
| プロジェクトまたはユーザーが存在しない | 404 | Not Found |
| 既に登録済み | 409 | Conflict |
uk_project_user(project_id + user_id)により重複登録はできない。
面接官削除
URI
パスパラメータ
| フィールド | ルール |
|---|---|
projectId |
必須。正の整数 |
userId |
必須。正の整数(users.id。project_interviewers.id ではない) |
レスポンス(204 No Content)
ボディなし。
例外処理
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| トークンが欠落または無効 | 401 | Unauthorized |
| ロール不足 | 403 | Forbidden |
| 面接官が存在しない | 404 | Not Found |
面接官空き状況取得
プロジェクトに登録された面接官の Google Calendar を参照し、予約可能枠を算出する。STEP1 の「空き枠を算出」で呼ばれる。
URI
クエリパラメータ
| フィールド | 型 | 必須 | ルール | 説明 |
|---|---|---|---|---|
startDate |
string | ◯ | YYYY-MM-DD |
算出期間の開始日 |
endDate |
string | ◯ | YYYY-MM-DD |
算出期間の終了日 |
durationMinutes |
integer | - | 正の整数 | 面接の所要時間。未指定なら projects.interview_duration_minutes |
リクエスト例
GET /api/v1/projects/1/interviewers/availability?startDate=2026-02-01&endDate=2026-02-14&durationMinutes=90
durationMinutes を渡す理由
所要時間は STEP1 を保存したときにプロジェクトへ書き込まれる。画面で選んだ直後に「空き枠を算出」を押すとまだ保存されていないため、明示的に渡さないと前の値で算出されてしまう。
枠は平日 9:00〜18:00(JST)の範囲で、所要時間の倍数を開始時刻として並ぶ(90 分なら 9:00-10:30 / 10:30-12:00 / …)。枠同士は重ならず、営業時間をはみ出す枠は返さない。
レスポンス(200 OK)
data が AvailableSlot の配列。
{
"success": true,
"status": "success",
"statusCode": 200,
"data": [
{
"slotId": "slot_20260203_1000",
"interviewerId": 5,
"interviewerName": "末成",
"startAt": "2026-02-03T01:00:00Z",
"endAt": "2026-02-03T02:00:00Z"
}
],
"path": "/api/v1/projects/1/interviewers/availability",
"method": "GET"
}
| フィールド | 型 | 説明 |
|---|---|---|
slotId |
string | 枠を識別する ID。希望日程の送信時にそのまま使う |
interviewerId |
integer | 面接官のユーザー ID |
interviewerName |
string | 面接官の表示名 |
startAt / endAt |
string(date-time) | 枠の開始/終了 |
枠の長さはプロジェクトの interview_duration_minutes に従う。
例外処理
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| 日付形式が不正 | 400 | Bad Request |
| トークンが欠落または無効 | 401 | Unauthorized |
| プロジェクトが存在しない | 404 | Not Found |
Google Calendar エラー(GOOGLE_CALENDAR_ERROR) |
502 | Bad Gateway |
仮枠カレンダーイベント作成
STEP1 で確定した枠を、面接官の Google Calendar に暫定イベントとして一括登録する。既存の仮枠は削除されてから作り直される。
URI
リクエストボディ
{
"slots": [
{
"interviewerId": 5,
"startTime": "2026-02-03T10:00:00+09:00",
"endTime": "2026-02-03T11:00:00+09:00"
},
{
"interviewerId": 5,
"startTime": "2026-02-03T11:00:00+09:00",
"endTime": "2026-02-03T12:00:00+09:00"
}
]
}
バリデーションルール
| フィールド | ルール |
|---|---|
slots |
必須。配列 |
slots[].interviewerId |
必須。整数 |
slots[].startTime |
必須。ISO 8601 形式の文字列 |
slots[].endTime |
必須。ISO 8601 形式の文字列 |
レスポンス(200 OK)
{
"success": true,
"status": "success",
"statusCode": 200,
"data": { "created": 20, "deleted": 0 },
"path": "/api/v1/projects/1/interviewers/tentative-slots",
"method": "POST"
}
| フィールド | 型 | 説明 |
|---|---|---|
created |
integer | 作成した仮枠イベント数 |
deleted |
integer | 事前に削除した既存仮枠数 |
作成されたイベント情報は projects.arrange_settings.step1.tentativeEventIds に保存される。
イベントはプロジェクトカレンダー(projects.google_calendar_id)に作られ、担当の面接官が attendee として入る。一度に多数作るため Google からの招待通知は送らない。カレンダーが未作成のプロジェクトでは、この時点で作成される。
tentativeEventIds の interviewerEmail
以前は面接官個人のカレンダーに書き込んでいたため、この項目がカレンダー ID を兼ねていた。現在は「どの面接官の枠か」を示すだけで、Calendar API のカレンダー ID としては使わない。
例外処理
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| バリデーションエラー | 400 | Bad Request |
| トークンが欠落または無効 | 401 | Unauthorized |
| ロール不足 | 403 | Forbidden |
| プロジェクトが存在しない | 404 | Not Found |
| Google Calendar エラー | 502 | Bad Gateway |
PROTOTYPE_MODE
PROTOTYPE_MODE=true の間はカレンダーへの書き込みが行われない。
仮枠カレンダーイベント削除
プロジェクトの仮枠イベントをすべて削除する。
URI
リクエスト
ボディなし。パスパラメータ projectId のみ。
レスポンス(200 OK)
{
"success": true,
"status": "success",
"statusCode": 200,
"data": { "deleted": 20 },
"path": "/api/v1/projects/1/interviewers/tentative-slots",
"method": "DELETE"
}
204 ではなく 200 と削除件数を返す点に注意。
例外処理
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| トークンが欠落または無効 | 401 | Unauthorized |
| ロール不足 | 403 | Forbidden |
| プロジェクトが存在しない | 404 | Not Found |
| Google Calendar エラー | 502 | Bad Gateway |