コンテンツにスキップ

案件 API

調査票の案件(survey)を管理するエンドポイント。

認証・レスポンス形式・エラーの扱いは API 定義 を参照。

メソッド

HTTP メソッド

メソッド URI 概要
GET /api/surveys 案件一覧取得
POST /api/surveys 案件新規作成と初期案生成
GET /api/surveys/{surveyId} 案件詳細取得
PATCH /api/surveys/{surveyId} 案件基本情報更新
DELETE /api/surveys/{surveyId} 案件削除(論理削除)
GET /api/surveys/{surveyId}/theme 案件テーマ取得
PATCH /api/surveys/{surveyId}/theme 案件テーマ更新
POST /api/theme-assists テーマ設定候補取得
POST /api/surveys/{surveyId}/save 保存して新しい版を作成
POST /api/surveys/{surveyId}/versions 同上(エイリアス)
POST /api/surveys/{surveyId}/duplicate 案件複製
POST /api/survey-copies 案件または指定版から複製
POST /api/surveys/{surveyId}/questions/renumber 設問コードの振り直し
POST /api/surveys/{surveyId}/archive 案件アーカイブ
POST /api/surveys/{surveyId}/export JSON 出力と過去質問データへの登録
POST /api/surveys/{surveyId}/exports 同上(エイリアス)
PUT /api/surveys/{surveyId}/favorite お気に入り設定・解除

命名規則

URI・JSON のノードには camelCase を使用します(API 定義)。

リソース定義

案件のステータス

ステータス 説明
下書き 初期状態。作成時に設定される
レビュー中 レビュー依頼中
出力済み JSON 出力を実行した状態。出力操作で自動的に遷移する
アーカイブ 運用を終えた案件。一覧では既定で非表示

案件スキーマ

フィールド データ型 備考
id string UUID
title string 案件タイトル
clientName string クライアント名
objective string 調査目的
deliveryArea string 配信エリア
category string カテゴリ
promptText string 自由記述
status enum 下書き / レビュー中 / 出力済み / アーカイブ
latestVersionNo number 最新版の版番号
createdBy string 作成者のユーザー ID
updatedBy string 最終更新者のユーザー ID
createdAt string ISO 8601
updatedAt string ISO 8601
sections Section[] 最新版のセクション一覧
permissions SurveyPermission[] 共有権限一覧
versions SurveyVersion[] 版履歴

認証要件

x-user-email / x-user-name ヘッダによるユーザー認証が必要です。

案件への操作は view / edit 権限で制御されます。権限がない場合も 404 Not Found を返します(案件の存在自体を秘匿するため)。例外は案件削除で、権限不足のときのみ 403 Forbidden を返します。

操作 必要な権限
一覧・詳細・テーマ取得・複製 view
更新・保存・アーカイブ・出力・お気に入り・設問コードの振り直し edit
削除 作成者本人、または管理者

案件一覧取得

概要

ログインユーザーが view または edit 権限を持つ案件の一覧を取得します(管理者は全件)。一覧項目にはセクション数とお気に入り状態が含まれ、セクション・設問の詳細は含まれません。

URI

GET /api/surveys

クエリパラメータ

パラメータ データ型 必須 備考
q string タイトル・クライアント名でのキーワード検索
status enum 下書き / レビュー中 / 出力済み / アーカイブ で絞り込み
includeArchived enum true / false。既定は false
sort enum updatedAtDesc / updatedAtAsc / titleAsc / titleDesc。既定は updatedAtDesc

レスポンス(200 OK)

{
  "ok": true,
  "data": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "title": "ブランド認知度調査",
      "clientName": "株式会社サンプル",
      "objective": "認知度の把握",
      "deliveryArea": "全国",
      "category": "ブランド",
      "promptText": "",
      "status": "下書き",
      "latestVersionNo": 3,
      "createdBy": "…",
      "updatedBy": "…",
      "createdAt": "2026-08-01T00:00:00.000Z",
      "updatedAt": "2026-08-10T00:00:00.000Z",
      "favorite": true,
      "sectionCount": 4
    }
  ]
}
フィールド データ型 備考
favorite boolean ログインユーザーがお気に入り登録しているか
sectionCount number 最新版のセクション数

例外処理

説明 ステータスコード ステータス名
認証ヘッダが欠落 401 Unauthorized

処理フロー

  1. 認証ミドルウェアがヘッダからユーザーを特定する
  2. 管理者でなければ、view / edit 権限を持つ案件に絞り込む
  3. 削除済み(deletedAt あり)の案件を除外する
  4. includeArchived が false ならアーカイブを除外する
  5. q / status で絞り込み、sort で並べ替える(お気に入りを先頭に寄せる)

案件新規作成

概要

案件を新規作成します。版 1 が同時に作られ、作成者に edit 権限が付与されます。generateInitialContent を省略するか true にすると、初期セクション・初期設問が自動生成されます。

URI

POST /api/surveys

リクエストボディ

{
  "title": "ブランド認知度調査",
  "clientName": "株式会社サンプル",
  "objective": "認知度の把握",
  "deliveryArea": "全国",
  "category": "ブランド",
  "promptText": "",
  "generateInitialContent": true
}

バリデーションルール

フィールド ルール
title 必須。文字列
clientName 必須。文字列
objective 必須。文字列
deliveryArea 必須。文字列
category 必須。文字列
promptText 任意。省略時は空文字
generateInitialContent 任意。真偽値。省略時は true

レスポンス(201 Created)

案件スキーマ(sections / permissions / versions を含む)を返します。

例外処理

説明 ステータスコード ステータス名
リクエストボディが不正 400 Bad Request
認証ヘッダが欠落 401 Unauthorized

処理フロー

シーケンス図

sequenceDiagram
    participant Client
    participant API
    participant DB

    Client->>API: POST /api/surveys
    API->>API: リクエストバリデーション
    API->>DB: トランザクション開始
    API->>DB: surveys へ案件を作成
    API->>DB: survey_versions へ版 1 を作成
    API->>DB: survey_version_pointers に最新版ポインタを作成
    API->>DB: survey_permissions に作成者の edit 権限を作成
    opt generateInitialContent = true
        API->>DB: 初期セクション・初期設問を挿入
    end
    API->>DB: コミット
    API-->>Client: 201 Created

案件詳細取得

概要

最新版のセクション・設問・分岐ルール・表示ロジックと、権限一覧・版履歴をまとめて返します。

URI

GET /api/surveys/{surveyId}
パラメータ データ型 必須 備考
surveyId string ◯ 案件の UUID

レスポンス(200 OK)

案件スキーマを返します。

例外処理

説明 ステータスコード ステータス名
案件が存在しない、または権限がない 404 Not Found

処理フロー

  1. 案件を取得し、削除済みでないことを確認する
  2. view 権限を確認する(管理者は常に許可)
  3. 最新版のスナップショット(セクション・設問・選択肢・分岐ルール・表示ロジック)を読み込む
  4. 権限一覧と版履歴を付与して返す

案件基本情報更新

概要

案件の基本情報とステータスを更新します。指定したフィールドのみが更新されます。

URI

PATCH /api/surveys/{surveyId}

リクエストボディ

{
  "title": "ブランド認知度調査",
  "status": "レビュー中"
}

バリデーションルール

フィールド ルール
title 任意。文字列
clientName 任意。文字列
objective 任意。文字列
deliveryArea 任意。文字列
category 任意。文字列
promptText 任意。文字列
status 任意。下書き / レビュー中 / 出力済み / アーカイブ のいずれか

レスポンス(200 OK)

更新後の案件スキーマを返します。

例外処理

説明 ステータスコード ステータス名
リクエストボディが不正 400 Bad Request
案件が存在しない、または edit 権限がない 404 Not Found

案件削除

概要

案件を削除します。論理削除であり、削除日時が記録されるだけでデータは残ります。実行できるのは 案件の作成者本人と管理者のみ です。

URI

DELETE /api/surveys/{surveyId}

レスポンス(200 OK)

{ "ok": true, "data": { "deleted": true } }

例外処理

説明 ステータスコード ステータス名
作成者でも管理者でもない 403 Forbidden
案件が存在しない、または削除済み 404 Not Found

処理フロー

シーケンス図

sequenceDiagram
    participant Client
    participant API
    participant DB

    Client->>API: DELETE /api/surveys/{surveyId}
    API->>DB: 案件を取得 (deleted_at IS NULL)
    alt 見つからない
        API-->>Client: 404 Not Found
    else 作成者でも管理者でもない
        API-->>Client: 403 Forbidden
    else
        API->>DB: deleted_at に現在時刻を設定
        API-->>Client: 200 OK
    end

案件テーマ取得

概要

案件のテーマを、UI の入力フォームに合わせた構造化形式で取得します。DB では調査目的・配信エリア・カテゴリを 1 つの文字列として保持していますが、この API では「プリセット選択」と「自由入力」に分解して返します。

URI

GET /api/surveys/{surveyId}/theme

レスポンス(200 OK)

{
  "ok": true,
  "data": {
    "title": "ブランド認知度調査",
    "clientName": "株式会社サンプル",
    "objective": { "presets": ["認知度の把握"], "customText": "" },
    "deliveryArea": { "preset": "全国", "customText": "" },
    "categories": { "labels": ["ブランド"], "freeText": "" },
    "promptText": "",
    "status": "下書き"
  }
}
フィールド データ型 備考
objective.presets string[] 選択済みのプリセット調査目的
objective.customText string 自由入力の調査目的
deliveryArea.preset string | null 選択済みのプリセット配信エリア
deliveryArea.customText string 自由入力の配信エリア
categories.labels string[] 選択済みのカテゴリ
categories.freeText string 自由入力のカテゴリ

例外処理

説明 ステータスコード ステータス名
案件が存在しない、または権限がない 404 Not Found

案件テーマ更新

概要

案件のテーマを構造化形式で更新します。受け取った構造は DB 保存用の文字列へ直列化されます。

URI

PATCH /api/surveys/{surveyId}/theme

リクエストボディ

{
  "title": "ブランド認知度調査",
  "clientName": "株式会社サンプル",
  "objective": { "presets": ["認知度の把握"], "customText": "" },
  "deliveryArea": { "preset": "全国", "customText": "" },
  "categories": { "labels": ["ブランド"], "freeText": "" },
  "promptText": ""
}

バリデーションルール

フィールド ルール
title 必須。文字列
clientName 必須。文字列
objective 必須。presets(文字列配列)と customText(文字列)
deliveryArea 必須。preset(文字列 or null)と customText(文字列)
categories 必須。labels(文字列配列)と freeText(文字列)
promptText 必須。文字列

レスポンス(200 OK)

更新後のテーマを返します。

例外処理

説明 ステータスコード ステータス名
リクエストボディが不正 400 Bad Request
案件が存在しない、または edit 権限がない 404 Not Found

テーマ設定候補取得

概要

入力中のテーマから、関連カテゴリ・過去の類似設問・推奨セクション構成 を提案します。案件の作成前でも呼べます。提案は、ログインユーザーが閲覧できる案件と質問ライブラリの内容をもとに算出されます。

URI

POST /api/theme-assists

リクエストボディ

{
  "title": "ブランド認知度調査",
  "clientName": "株式会社サンプル",
  "objective": "認知度の把握",
  "deliveryArea": "全国",
  "category": "ブランド",
  "promptText": "",
  "selectedCategories": ["ブランド"]
}

バリデーションルール

フィールド ルール
title 必須。文字列
clientName 必須。文字列
objective 必須。文字列または構造化形式
deliveryArea 必須。文字列または構造化形式
category 必須。文字列または構造化形式
promptText 任意。省略時は空文字
selectedCategories 任意。文字列配列。省略時は category から導出する

レスポンス(200 OK)

{
  "ok": true,
  "data": {
    "suggestedCategories": ["ブランド", "購買行動"],
    "relatedQuestions": [
      {
        "id": "…",
        "category": "ブランド",
        "sectionTitle": "認知",
        "promptText": "以下のブランドのうち、知っているものをすべてお選びください。",
        "questionType": "multi"
      }
    ],
    "recommendedSections": ["スクリーニング", "認知", "利用実態"]
  }
}

例外処理

説明 ステータスコード ステータス名
リクエストボディが不正 400 Bad Request

処理フロー

  1. 閲覧可能な案件一覧と質問ライブラリを取得する
  2. テーマの各項目を連結してキーワードに分割する
  3. ライブラリの各設問について、設問文(4 点)・カテゴリ(3 点)・セクションタイトル(2 点)の一致でスコアを算出する
  4. スコアが 1 点以上のものを降順に並べ、上位 5 件を関連設問として返す
  5. 案件とライブラリから作った候補プールをもとに関連カテゴリを提案する
  6. カテゴリと関連設問から推奨セクション構成を組み立てて返す

保存して新しい版を作成

概要

現在の最新版の内容をまるごと複製して 新しい版を作成 し、それを最新版にします。

URI

POST /api/surveys/{surveyId}/save
POST /api/surveys/{surveyId}/versions

2 つは同じ処理のエイリアスです。

レスポンス(201 Created)

{
  "ok": true,
  "data": {
    "id": "…",
    "versionNo": 4,
    "createdAt": "2026-08-18T00:00:00.000Z",
    "createdBy": "…",
    "status": "下書き",
    "snapshotSections": [],
    "sourceVersionId": "…"
  }
}

例外処理

説明 ステータスコード ステータス名
案件が存在しない、または edit 権限がない 404 Not Found

処理フロー

  1. edit 権限を確認する
  2. 最新版の ID を取得する
  3. 最新版のスナップショットを読み込む
  4. 新しい版を作成し、スナップショットを複製する。安定 ID はそのまま引き継ぐ
  5. 案件の最新版番号と最新版ポインタを更新する

安定 ID を引き継ぐ理由

版ごとに行の ID は新しく振られますが、安定 ID を引き継がないと質問ライブラリが古い版のスナップショットを指したままになり、設問の流用時に対象を見つけられなくなります。

案件複製

概要

案件を最新版の内容で複製し、新しい案件 を作成します。タイトルの末尾に「複製」が付き、共有権限も引き継がれます。

URI

POST /api/surveys/{surveyId}/duplicate

レスポンス(201 Created)

複製された案件スキーマを返します。

例外処理

説明 ステータスコード ステータス名
案件が存在しない、または view 権限がない 404 Not Found

処理フロー

  1. view 権限を確認する
  2. 複製元の案件と最新版のスナップショットを読み込む
  3. トランザクションで新しい案件(版 1)を作成する
  4. 複製元の権限をすべて引き継ぐ
  5. スナップショットのセクション・設問を挿入する

案件または指定版から複製

概要

案件、または案件の指定した版から新しい案件を複製します。sourceVersionNo を指定すると指定版から、省略すると最新版から複製します。

URI

POST /api/survey-copies

リクエストボディ

{
  "sourceSurveyId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "sourceVersionNo": 2
}

バリデーションルール

フィールド ルール
sourceSurveyId 必須。複製元の案件 UUID
sourceVersionNo 任意。1 以上の整数。省略時は最新版

レスポンス(201 Created)

複製された案件スキーマを返します。

例外処理

説明 ステータスコード ステータス名
リクエストボディが不正 400 Bad Request
案件または版が存在しない、または権限がない 404 Not Found

設問コードの振り直し

概要

案件全体の設問コードを、出現順にきれいな連番へ振り直します。

設問タイプ 振り直し後のコード
提示ステップ(intro) T1 / T2 / …
それ以外 Q1 / Q2 / …

連番はセクション単位ではなく案件全体の通し番号です。振り直しに伴い、分岐条件の参照元(sourceQuestionCode)・分岐先(destinationQuestionCode)・表示ロジックの参照元も自動で新しいコードへ付け替え られます。

frontend は設問の並びが変わる操作(並べ替え・削除・複製・流用・「その他」フォローアップ設問の自動作成)のたびに、この API を自動的に呼び出します。

URI

POST /api/surveys/{surveyId}/questions/renumber
パラメータ データ型 必須 備考
surveyId string ◯ 案件の UUID

レスポンス(200 OK)

振り直し後の案件スキーマを返します。振り直しが不要だった(すでに連番になっていた)場合も現在の案件をそのまま返します。

例外処理

説明 ステータスコード ステータス名
案件が存在しない、または edit 権限がない 404 Not Found

処理フロー

  1. edit 権限を確認する
  2. 最新版のスナップショットを読み込む
  3. セクション順・設問順に走査し、intro は T 連番、それ以外は Q 連番で次のコードを決める
  4. 変更が必要な設問だけを対象に、旧コード → 新コードの対応表を作る
  5. トランザクションで設問コードを更新する
  6. 分岐ルールの分岐先、分岐条件の参照元、表示ロジックの参照元を対応表で付け替える
  7. 振り直し後の案件を返す

シーケンス図

sequenceDiagram
    participant Client
    participant API
    participant DB

    Client->>API: POST /api/surveys/{surveyId}/questions/renumber
    API->>API: edit 権限を確認
    API->>DB: 最新版のスナップショットを読み込み
    API->>API: intro=T連番 / それ以外=Q連番 で新コードを決定
    alt 変更なし
        API-->>Client: 200 OK (現在の案件)
    else
        API->>DB: トランザクション開始
        API->>DB: 設問コードを更新
        API->>DB: 分岐先・分岐条件の参照元を付け替え
        API->>DB: 表示ロジックの参照元を付け替え
        API->>DB: コミット
        API-->>Client: 200 OK
    end

据え置きコードへの参照は付け替えない

Q2 と Q3 を入れ替えるような相互リネームでも参照が二重に置換されないよう、付け替えは振り直し前に読んだ値を基準に 1 行 1 回だけ行われます。コードが変わらなかった設問への参照はそのまま維持されます。

失敗しても元の操作は成立している

frontend はこの API の失敗を警告表示に留めます。並べ替えや削除といった元の操作自体はすでに完了しているためで、コードが連番から外れたまま残ることがあります。


案件アーカイブ

概要

案件のステータスを「アーカイブ」に変更します。PATCH /api/surveys/{surveyId} で status に アーカイブ を指定するのと同じ結果になります。

URI

POST /api/surveys/{surveyId}/archive

レスポンス(200 OK)

更新後の案件スキーマを返します。

例外処理

説明 ステータスコード ステータス名
案件が存在しない、または edit 権限がない 404 Not Found

JSON 出力

概要

案件を 調査票 JSON として出力 します。Chrome 拡張が CS へ投入する際の入力データになります。

出力は副作用を伴います。

  • 案件と最新版のステータスが「出力済み」になる
  • 案件の全設問が 質問ライブラリへ登録 される(同じ案件の既存登録は置き換えられる)

URI

POST /api/surveys/{surveyId}/export
POST /api/surveys/{surveyId}/exports

2 つは同じ処理のエイリアスです。

レスポンス(200 OK)

{
  "ok": true,
  "data": {
    "surveyId": "…",
    "title": "ブランド認知度調査",
    "status": "出力済み",
    "exportedAt": "2026-08-18T00:00:00.000Z",
    "metadata": {
      "clientName": "株式会社サンプル",
      "objective": "認知度の把握",
      "deliveryArea": "全国",
      "category": "ブランド",
      "promptText": "",
      "latestVersionNo": 3
    },
    "sections": [
      {
        "title": "スクリーニング",
        "description": "",
        "generatedBy": "manual",
        "questions": [
          {
            "code": "Q1",
            "questionType": "single",
            "promptText": "あなたの性別をお答えください。",
            "isRequired": true,
            "isLinkedToPrevious": false,
            "options": [
              { "label": "男性", "isExclusive": false, "allowOtherInput": false, "isNotApplicable": false },
              { "label": "女性", "isExclusive": false, "allowOtherInput": false, "isNotApplicable": false }
            ],
            "branchRules": [],
            "visibilityRules": []
          }
        ]
      }
    ]
  }
}
フィールド データ型 備考
exportedAt string 出力日時(ISO 8601)
metadata object 案件のテーマ情報と最新版番号
sections[].questions[] object[] 設問の全設定(選択肢・マトリクス行列・FA 欄・サブ設問・分岐ルール・表示ロジック)

例外処理

説明 ステータスコード ステータス名
案件が存在しない、または edit 権限がない 404 Not Found

処理フロー

シーケンス図

sequenceDiagram
    participant Client
    participant API
    participant DB
    participant Library as 質問ライブラリ

    Client->>API: POST /api/surveys/{surveyId}/export
    API->>API: edit 権限を確認
    API->>DB: 案件と最新版のスナップショットを読み込み
    API->>DB: トランザクション開始
    API->>DB: 案件のステータスを 出力済み に更新
    API->>DB: 最新版のステータスを 出力済み に更新
    API->>Library: この案件の登録を削除して再登録
    API->>DB: コミット
    API->>API: 調査票 JSON を組み立て
    API-->>Client: 200 OK

お気に入り設定・解除

概要

案件のお気に入り状態を設定・解除します。お気に入りは ユーザーごと に管理されます。

URI

PUT /api/surveys/{surveyId}/favorite

リクエストボディ

{ "favorite": true }

バリデーションルール

フィールド ルール
favorite 必須。真偽値。true で登録、false で解除

レスポンス(200 OK)

{ "ok": true, "data": { "favorite": true } }

例外処理

説明 ステータスコード ステータス名
リクエストボディが不正 400 Bad Request
案件が存在しない、または権限がない 404 Not Found