コンテンツにスキップ

ワイヤーフレームからデザイン生成(トリガー)

メソッド

このAPIはRESTメソッドを採用しています。ワイヤーフレームからデザイン生成の実行を開始するトリガーであり、クライアント向けのwf2des行を作成し、トリガー時点のワイヤーフレームスナップショットを取得し、parseメッセージをエンキューします。生成処理自体は非同期で実行され、このエンドポイントはポーリング先を返して即座に応答します。

HTTPメソッド

POST: ワイヤーフレームからデザイン生成(トリガー)

命名規則

一貫性と可読性を確保するため、リクエストとレスポンスのJSONノードにはcamelCaseを使用します。SQSペイロードのノードにはsnake_caseを使用します。

リクエストとレスポンス

ヘッダー

メタ情報はレスポンスボディではなく、HTTPヘッダーに設定されます。

リクエストヘッダー

  • Authorization
  • Content-Type
  • Accept
  • Accept-language

レスポンスヘッダー

  • Content-Type

ワイヤーフレームからデザイン生成(トリガー)

URI

POST /api/v1/organizations/{organization_id}/projects/{project_id}/wf2des

パスパラメータ

名前 型 必須 説明
organization_id integer Required 組織ID
project_id integer Required プロジェクトID

リクエストボディ

リクエストボディはJSONです。

{
  "figmaFileKey": "aBc1DeFg2HiJ3kLmNoPqRs",
  "wfNodeId": "128:4567",
  "sectionNodeId": "128:4000",
  "screenId": "MEM_REG_TOP",
  "prompt": "Emphasize the primary CTA and keep the form compact",
  "placementTarget": "128:9001",
  "autoConfirm": false
}

リクエストパラメータ

名前 型 必須 説明
figmaFileKey string Required ワイヤーフレームフレームが存在する対象のFigmaファイルキー(Figmaの表記をそのまま使用。英数字、アンダースコアなし)
wfNodeId string Required 対象のワイヤーフレームフレームのノードID(FigmaノードID、:を使用)
sectionNodeId string Optional フレームを内包するボード/SECTION。呼び出し元が解決し、スナップショット取得範囲の絞り込みに使用される。省略した場合、バックエンドはファイル全体のドキュメントを走査して範囲を自ら解決する。サーバー側で検証され、決して無条件に信頼されない。フレームがこのサブツリー内に存在しない場合、バックエンドはwf2desSnapshot.scopeRejectedをログ出力し、全体走査にフォールバックする。
screenId string Required 画面ID。フレーム名から事前入力され、ユーザーによって確認される
prompt string Optional 生成プロンプト(選択入力。memoの意図より低い優先度)
placementTarget string Optional 配置ノードID。結果ドキュメントのrequestブロックにそのまま反映される
autoConfirm boolean Required falseは通常(parse → confirmステップ)/trueは自動確認(1回のワーカー呼び出しでparse + assemble)

trigger_surfaceは認証されたサーフェス(0 api/1 plugin)からバックエンド側で導出され、呼び出し元から提供されることは決してありません。

sectionNodeIdを送信すべき理由。スナップショットにはフレームを内包するボードが必要ですが、Figma REST APIはノードの祖先を返せません(/nodesはサブツリーのみを返し、祖先は含まれません)。このフィールドがない場合、バックエンドはGET /files/{key}でファイル全体を取得せざるを得ません。31ページの本番ファイルでの実測では、そのレスポンスは255MB・67.5秒であり、あるトリガーは140秒後に"socket connection was closed unexpectedly"で失敗し、500として表面化しました。同じ範囲をサブツリーとして取得した場合は0.38MBです。Figmaプラグインは祖先情報をコストなしで取得できるため、プラグインクライアントは常にこのフィールドを送信します。

レスポンス

レスポンスはJSONです(HTTPステータス: 201 Created)。

{
  "wf2desId": "8f14e45f-ceea-467d-9a3e-1b2c3d4e5f60",
  "status": "0",
  "phase": "0",
  "figmaFileKey": "aBc1DeFg2HiJ3kLmNoPqRs",
  "wfNodeId": "128:4567",
  "screenId": "MEM_REG_TOP",
  "autoConfirm": false,
  "triggerSurface": "0",
  "attempt": 1,
  "createdAt": "2026-07-10T09:30:00Z"
}

レスポンスフィールド

名前 型 説明
wf2desId string wf2des UUID — クライアント向けのリクエストID(GETのポーリングキー。ワーカーにはjob_idとして反映される)
status string (enum) 生成ステータス。作成時は常に"0" processing(例外処理/タイプコードを参照)
phase string (enum) status "0"内のオーケストレーションフェーズ。作成時は常に"0" parse
figmaFileKey string 対象のFigmaファイルキー
wfNodeId string 対象のワイヤーフレームフレームのノードID
screenId string 画面ID
autoConfirm boolean リクエストされた自動確認モードのエコー
triggerSurface string (enum) "0" api/"1" plugin — バックエンド側で導出され、呼び出し元から提供されることはない
attempt integer 単調増加のフェンシングカウンター — 作成時は1。バックエンドの再エンキュー時にのみインクリメントされる
createdAt string 行の作成タイムスタンプ(ISO 8601)

status/phase enum(wf2des行):

  • status: "0" processing · "1" completed · "2" failed · "3" rejected · "4" cancelled
  • phase(status "0"内。終了状態になるとnull): "0" parse · "1" awaiting_confirm · "2" assemble

認証

認証はAmazon Cognitoから発行されるJSON Web Tokens (JWT)を使用して行われます。認証されたサーフェスによってtrigger_surface(0 api/1 plugin)が決定され、バックエンドがこれを行に記録します。リクエストボディから受け付けることはありません。

例外処理

例外処理のステータスコードは以下の通りです。

説明 ステータスコード ステータス名
必須フィールドの欠落、またはfigmaFileKey/wfNodeIdの形式が無効 400 Bad Request
認証情報の欠落 401 Unauthorized
権限不足 403 Forbidden
組織またはプロジェクトが見つかりません 404 Not Found
生成の重複 — この(figmaFileKey, wfNodeId)に対して実行中の処理が既に存在する 409 Conflict
内部サーバーエラー(例: スナップショット取得またはSQS送信の失敗) 500 Internal Server Error

Figmaトークン未登録は4xxではなく500として表面化する。行の作成からエンキューまでの間に発生するすべての失敗("no Figma token registered for this user"を含む)は、上流のFigmaステータスを呼び出し元に漏らさないよう意図的に正規化され、行は失敗状態にされる(これによりノードを再トリガーできる)。対処はPOST /v1/figma/tokenで先にトークンを登録すること。クライアントはGenerateを提示する前にGET /v1/figma/tokenを確認し、不透明な500をデザイナーに見せる代わりにトークン入力を促すべきである。

409 — 生成の重複

wf2des行は(project_id, figma_file_key, wf_node_id) WHERE status = '0'に対して部分ユニークインデックスを強制します。つまり、1つのワイヤーフレームノードにつき実行中(処理中)の生成は最大1件です。重複したトリガーは2つ目の行を作成せず、既存のwf2desIdとともに409 Conflictを返します。これにより2つ目の呼び出し元は既に実行中の処理にアタッチします。

{
  "error": "duplicate_open_generation",
  "message": "A generation is already in progress for this wireframe node.",
  "wf2desId": "8f14e45f-ceea-467d-9a3e-1b2c3d4e5f60"
}

処理フロー

  1. パスパラメータからorganization_idとproject_idを抽出する。
  2. Cognito JWTを認証し、ユーザーがプロジェクトへのWrite権限を持つことを検証する。認証されたサーフェスからtrigger_surface(0 api/1 plugin)を導出する。
  3. リクエストボディを抽出・検証する: figmaFileKey、wfNodeId、screenId(必須)、prompt、placementTarget、autoConfirm。
  4. 最初にwf2des行を作成する — status "0" processing、phase "0" parse、attempt = 1、figma_file_key、wf_node_id、screen_id、prompt、placement_target、auto_confirm、および導出されたtrigger_surfaceを設定する。クライアントは何かがエンキューされる前に必ずポーリング先を持つ。
  5. INSERTが部分ユニークインデックス(project_id, figma_file_key, wf_node_id) WHERE status = '0'に違反した場合、既存のwf2desIdとともに409を返す(2つ目の呼び出し元は実行中の処理にアタッチする)。
  6. リクエストしたユーザー自身のFigmaトークンを解決する(cognito_subをキーとするfigma_token.personal_access_token)。生成はユーザー操作であるため、スナップショットはリクエストした本人の権限で取得される — サービスアカウントのPATではない。したがってユーザーが自分で開けないファイルをスナップショットすることはできない。登録済みトークンがない場合、この段階で実行は失敗する(エラーレスポンスの注記を参照)。
  7. トリガー時点のワイヤーフレームスナップショット(フレーム + 囲んでいるボードセクション。memoを含む)をS3に取得し、フレームが未登録の場合は自動登録する。スナップショットのwf_content_hashを計算する。 sectionNodeIdが指定され、かつフレームがその内部に存在する場合は当該サブツリーのみを取得する。そうでない場合はファイル全体のドキュメントを走査する。
  8. parseメッセージをバックエンド所有の生成SQSキューに送信する(snake_caseペイロード — 下記参照)。
  9. 作成されたwf2desId、status "0"、phase "0"、およびエコーされたリクエストフィールドとともに201 Createdを返す。

その後ワーカーはスナップショットをparseし、ai-statuswebhookをポストする。バックエンドは行を進める(インタラクティブなparse完了時はphase "1" awaiting_confirm、autoConfirmの場合は直接assembleへ)。ワーカーがPostgreSQLに書き込むことはなく、すべての行遷移はバックエンド側で行われる。

詳細フローチャート

flowchart TD
    Start([POST Request]) --> Route[Route Handler]
    Route --> Auth[Auth & Parameter Extraction<br/>derive trigger_surface 0 api / 1 plugin]
    Auth --> AccessCheck[Access Check]

    AccessCheck --> HasAccess{Write Access?}
    HasAccess -->|No| Err403[403 Forbidden]
    HasAccess -->|Yes| VerifyScope[Verify Organization & Project]

    VerifyScope --> ScopeExists{Exists?}
    ScopeExists -->|No| Err404[404 Not Found]
    ScopeExists -->|Yes| Validate[Validate Body<br/>figmaFileKey / wfNodeId / screenId]

    Validate --> BodyValid{Valid?}
    BodyValid -->|No| Err400[400 Bad Request]
    BodyValid -->|Yes| CreateRow[Create wf2des Row FIRST<br/>status=0 processing, phase=0 parse<br/>attempt=1]

    CreateRow --> Dedupe{Open generation exists?<br/>partial unique figma_file_key + wf_node_id<br/>WHERE status='0'}
    Dedupe -->|Yes| Err409[409 Conflict<br/>+ existing wf2desId]
    Dedupe -->|No| Snapshot[Capture trigger-time WF snapshot<br/>auto-register unregistered frame<br/>compute wf_content_hash]

    Snapshot --> SnapResult{Success?}
    SnapResult -->|No| Err500[500 Internal Server Error]
    SnapResult -->|Yes| SendSQS[SendMessage parse payload<br/>to generation SQS queue]

    SendSQS --> SQSResult{Success?}
    SQSResult -->|No| Err500
    SQSResult -->|Yes| Success[201 Created<br/>wf2desId, status=0, phase=0]

非同期処理

デザインはwf2desワーカーによって非同期で生成されます。行を進めるのはバックエンドであり、ワーカーではありません:

  • status "0" processing、phase "0" parse(作成時)
  • → phase "1" awaiting_confirm(インタラクティブなparse完了。ai-statuswebhook経由)、またはautoConfirmの場合は直接phase "2" assembleへ
  • → 終了状態のstatus "1" completed/"2" failed(ai-statuswebhook経由)、または"3" rejected(parse拒否)/"4" cancelled(cancelエンドポイント)

出力はネイティブFigmaのDesignSpecであり、design_generation_result DocumentDBコレクション(wf2desIdをキーとする)に書き込まれ、wf2desデータプレーンAPI経由で取得され、Figmaプラグインによってマテリアライズされます。行が終了状態に達するとphaseはクリアされます(null)。

SQS ペイロード

トリガー時、バックエンドはparseメッセージをバックエンド所有の生成SQSキューに送信します。メッセージはsnake_caseです。

{
  "wf2des_id": "8f14e45f-ceea-467d-9a3e-1b2c3d4e5f60",
  "attempt": 1,
  "nonce": "9c2b7f1a-0e44-4b8f-9d2a-77c1e0a3b512",
  "wireframe_img_url": "s3://bucket-name/1/3/wf2des/snapshots/aBc1DeFg2HiJ3kLmNoPqRs/128:4567.png",
  "wireframe_json_url": "s3://bucket-name/1/42/wf2des/snapshots/aBc1DeFg2HiJ3kLmNoPqRs/128-4567.<content_hash>.json",
  "snapshot_scope": {
    "frame_node_id": "128:4567",
    "section_node_id": "128:4000"
  },
  "wf_content_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
  "screen_id": "MEM_REG_TOP",
  "prompt": "Emphasize the primary CTA and keep the form compact",
  "placement_target": "128:9001",
  "auto_confirm": false,
  "design_rule_file_url": "s3://bucket-name/1/3/wf2des/rules/rule.json",
  "structure_file_url": null,
  "detail_design_file_url": null,
  "design_file_url": null
}

SQS ペイロードフィールド

名前 型 必須 説明
wf2des_id string (uuid) Required = wf2des行のID。webhookではjob_idとしてエコーされる。実行の識別/フェンシングペアの構成要素
attempt integer Required 単調増加のフェンシングカウンター。DocDBコミットをフェンスする((_id, attempt)のCAS)。トリガー時は1
nonce string Required エンキューごとに新規生成。(job_id, attempt, nonce)webhook重複排除キーの一部
wireframe_img_url string (s3://) Required トリガー時点のワイヤーフレーム画像スナップショット。バックエンドが事前に収集
wireframe_json_url string (s3://) Required トリガー時点のワイヤーフレームJSONスナップショット(フレーム + 囲んでいるボードセクション。memoを含む)
snapshot_scope object Required {frame_node_id, section_node_id} — フレームとそれを囲んでいるボードセクション
wf_content_hash string (sha256) Required 取得時に計算されたスナップショットのコンテンツハッシュ。parseキャッシュのキー
screen_id string Required 画面ID。リクエストから取得
prompt string | null Optional 生成プロンプト(選択入力。memoの意図より低い優先度)
placement_target string | null Optional 配置ノードID。結果ドキュメントのrequestブロックにそのまま反映される
auto_confirm boolean Required falseは通常/trueは自動 → 1回のワーカー呼び出しでparse + assemble
design_rule_file_url string (s3://) Optional 事前収集されたデザインルールファイルのURL。ピン留め用
structure_file_url string (s3://) Optional 事前収集されたストラクチャーファイルのURL。ピン留め用
detail_design_file_url string (s3://) Optional 事前収集された詳細設計ファイルのURL。ピン留め用
design_file_url string (s3://) Optional 事前収集された参照デザインファイルのURL。ピン留め用