ワイヤーフレームからデザイン生成(トリガー)
メソッド
このAPIはRESTメソッドを採用しています。ワイヤーフレームからデザイン生成の実行を開始するトリガーであり、クライアント向けのwf2des行を作成し、トリガー時点のワイヤーフレームスナップショットを取得し、parseメッセージをエンキューします。生成処理自体は非同期で実行され、このエンドポイントはポーリング先を返して即座に応答します。
HTTPメソッド
POST: ワイヤーフレームからデザイン生成(トリガー)
命名規則
一貫性と可読性を確保するため、リクエストとレスポンスのJSONノードにはcamelCaseを使用します。SQSペイロードのノードにはsnake_caseを使用します。
リクエストとレスポンス
ヘッダー
メタ情報はレスポンスボディではなく、HTTPヘッダーに設定されます。
リクエストヘッダー
AuthorizationContent-TypeAcceptAccept-language
レスポンスヘッダー
Content-Type
ワイヤーフレームからデザイン生成(トリガー)
URI
パスパラメータ
| 名前 | 型 | 必須 | 説明 |
|---|---|---|---|
| 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は認証されたサーフェス(0api/1plugin)からバックエンド側で導出され、呼び出し元から提供されることは決してありません。
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"cancelledphase(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"
}
処理フロー
- パスパラメータから
organization_idとproject_idを抽出する。 - Cognito JWTを認証し、ユーザーがプロジェクトへのWrite権限を持つことを検証する。認証されたサーフェスから
trigger_surface(0api/1plugin)を導出する。 - リクエストボディを抽出・検証する:
figmaFileKey、wfNodeId、screenId(必須)、prompt、placementTarget、autoConfirm。 - 最初に
wf2des行を作成する —status "0"processing、phase "0"parse、attempt = 1、figma_file_key、wf_node_id、screen_id、prompt、placement_target、auto_confirm、および導出されたtrigger_surfaceを設定する。クライアントは何かがエンキューされる前に必ずポーリング先を持つ。 - INSERTが部分ユニークインデックス
(project_id, figma_file_key, wf_node_id) WHERE status = '0'に違反した場合、既存のwf2desIdとともに409を返す(2つ目の呼び出し元は実行中の処理にアタッチする)。 - リクエストしたユーザー自身のFigmaトークンを解決する(
cognito_subをキーとするfigma_token.personal_access_token)。生成はユーザー操作であるため、スナップショットはリクエストした本人の権限で取得される — サービスアカウントのPATではない。したがってユーザーが自分で開けないファイルをスナップショットすることはできない。登録済みトークンがない場合、この段階で実行は失敗する(エラーレスポンスの注記を参照)。 - トリガー時点のワイヤーフレームスナップショット(フレーム + 囲んでいるボードセクション。memoを含む)をS3に取得し、フレームが未登録の場合は自動登録する。スナップショットの
wf_content_hashを計算する。sectionNodeIdが指定され、かつフレームがその内部に存在する場合は当該サブツリーのみを取得する。そうでない場合はファイル全体のドキュメントを走査する。 - parseメッセージをバックエンド所有の生成SQSキューに送信する(snake_caseペイロード — 下記参照)。
- 作成された
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。ピン留め用 |