AI Internal API (wf2des-api) — I/O 定義
このページは apps/internal-api/(guinness-ai-v2)内の wf2des-api ルートグループの 公式 I/O 契約 です。これは Figma プラグイン(セッション発行トークン)と バックエンド / MCP(共有サービストークン)が消費する VPC 内部 HTTP データプレーンです。エンドポイント、フィールド、enum 値、ステータスコード、path/query パラメータ、エラー形状のいかなる変更も、実装の前にここへ — そして同じ internal-api アプリを共有する姉妹ドキュメント AI Read API (mcp-api) I/O 定義 へ — 反映しなければなりません。
契約の権威。 リードルートが返し、ライトルートが変更するのは、AI WF2Des ワーカー が管轄する
design_generation_resultドキュメントおよびproject_figma_fileコレクションのブロックです。フィールドの形状 はそのワーカーの契約で定義されます。このページはそれらに対する アクセス契約 です。返却または書き込みされるブロックの形状がそちらで変わったら、このページもそれに追随します。
概要
wf2des-api はプラグインが AI プレーンに入るための唯一の入口です。DocumentDB ドキュメントと S3 アーティファクトを presign / 読み込みし、プラグインの detail-first 書き込みを受け付けます — プラグインは detail サブドキュメントをまずここに書き、その後 wf2des PostgreSQL 行を反転する対応の バックエンド フラグエンドポイントを呼び出します。wf2des-api はそれ自身では決して PG 反転を行いません。
flowchart LR
PLUGIN["Figma plugin<br/>(session token<br/>{org_id, project_id, exp})"]
BE["Backend / MCP<br/>(X-AI-Service-Token)"]
API["wf2des-api<br/>(internal-api app, VPC internal)<br/>/internal/wf2des/* · /internal/projects/*"]
DDB[("DocumentDB guinness_v2<br/>design_generation_result ·<br/>project_figma_file")]
S3[("S3<br/>result / parse artifacts")]
PLUGIN -->|"read: result / parse / figma-files<br/>write: reject / placement / feedback / figma-files"| API
BE -->|"read only (X-AI-Service-Token)"| API
API -->|"find_one / update sub-doc block"| DDB
API -->|"presign / proxy artifact"| S3
API -.->|"NEVER"| PG[("PostgreSQL")]
API -.->|"NEVER"| SQS[("SQS")]
PLUGIN -->|"detail first, flag last:<br/>after a write, call the BACKEND flag endpoint"| BE
| 項目 | 値 |
|---|---|
| ルートグループ | wf2des-api — internal-api アプリ内の /internal/wf2des/* + /internal/projects/*(Lambda Function URL / private HTTP integration、VPC 内部のみ) |
| 呼び出し元 | Figma プラグイン(セッショントークン、read + write、プロジェクトスコープ)· バックエンド / MCP(共有 X-AI-Service-Token、read のみ) |
| 読み込み | DocumentDB design_generation_result、project_figma_file + S3(result / spec / parse アーティファクト) |
| 書き込み | DocumentDB サブドキュメントブロック(parse.rejected、placement、feedback)+ project_figma_file ドキュメント。S3 書き込みなし — メディア/アーティファクトはワーカーが生成し、この API は presign / プロキシするだけ |
| RDB アクセス | なし — wf2des-api は決して PostgreSQL に接続しません。あらゆる wf2des 行のフラグ反転は、detail 書き込みの後にプラグインが呼び出す 別個の バックエンドエンドポイントです |
| キューアクセス | なし — wf2des-api は決して SQS を送信しません。これは同期的なデータプレーンであり、ジョブプロデューサではありません |
| テナンシー | あらゆるルートが org/project スコープ。あらゆる読み込みと書き込みが organization_id + project_id でフィルタリングされます |
プラットフォームの厳格ルール。 wf2des-api は DocumentDB + S3 のみ に触れます — PostgreSQL には決して触れず、SQS にも決して触れません。純粋なデータプレーンサーフェスです。wf2des PostgreSQL 行はバックエンドのみが進めます(ai-status Webhook ハンドラと confirm / placement / feedback / placement エンドポイント)。AI 管轄の wf2des-events SQS キューはバックエンドの送信専用権限によってのみ供給されます。wf2des-api はそのいずれにも関与しません。
ルートサマリー
| # | ルート | 種別 | 認証(最小) | DocDB / S3 効果 |
|---|---|---|---|---|
| 1 | GET /internal/wf2des/{wf2des_id}/result |
read | セッショントークン または X-AI-Service-Token |
design_generation_result.spec(スピル時は artifact_urls.spec を presign) |
| 2 | GET /internal/wf2des/{wf2des_id}/parse |
read | セッショントークン または X-AI-Service-Token |
design_generation_result.parse + イミュータブルな parse.json を presign |
| 3 | GET /internal/projects/{project_id}/figma-files |
read | セッショントークン または X-AI-Service-Token |
project_figma_file.find(プロジェクトスコープ) |
| 4 | POST /internal/wf2des/{wf2des_id}/reject |
write | セッショントークン のみ | design_generation_result.parse.rejected を書き込む |
| 5 | POST /internal/wf2des/{wf2des_id}/placement |
write | セッショントークン のみ | design_generation_result.placement を書き込む |
| 6 | POST /internal/wf2des/{wf2des_id}/feedback |
write | セッショントークン のみ | design_generation_result.feedback を書き込む |
| 7 | POST / PUT /internal/projects/{project_id}/figma-files |
write | セッショントークン のみ | project_figma_file ドキュメントを upsert — UNIQUE(organization_id, project_id, figma_file_key) |
認証の分岐。 リードルートはプラグインセッショントークン または 共有 X-AI-Service-Token(バックエンド / MCP 解決)のいずれかを受け付けます。ライトルートはプラグインセッショントークン のみ を受け付けます — バックエンド/MCP のサービストークンは read スコープであり、書き込んではなりません。認証 を参照。
Detail-first(ライトルート 4〜6)。 プラグインは detail サブドキュメントをまずここに書き、その後 wf2des PG 行を反転する対応の バックエンド フラグエンドポイントを呼び出します — detail が先、flag が後。ルート 7 は異なります: これはバックエンドのフラグパートナーを持たない wf2des-api への 直接 書き込みです(project_figma_file は DocumentDB コレクションであって PG フラグサーフェスではありません)。
リードルート
1. GET /internal/wf2des/{wf2des_id}/result
design_generation_result の DesignSpec — assemble フェーズが書き込んだ spec ブロック — を返します。プラグインはこの spec からネイティブ Figma ノードをマテリアライズします。
| プロパティ | 値 |
|---|---|
| Method / Path | GET /internal/wf2des/{wf2des_id}/result |
| 認証 | セッショントークン または X-AI-Service-Token(read) |
| Path params | wf2des_id — 実行 id = wf2des PG 行 id(design_generation_result._id) |
| Query params | なし |
| Request body | なし |
| DocDB read | design_generation_result.find_one({_id: wf2des_id, organization_id, project_id}) → spec ブロック |
| S3 効果 | spec がスピルした場合(spec > ~1MB)、spec はインラインに存在せず artifact_urls.spec に置かれる。API はその S3 オブジェクトを presign し、ドキュメントと共に URL を返す |
| PG / SQS | なし |
Response body — DesignSpec(spec ブロック。形状は ワーカー契約 の通り。parse_confirmed はミラー。5 つのノードタイプ layout_frame / instance / compose / text / unmatched):
{
"ok": true,
"data": {
"wf2des_id": "8f14e4...",
"spec": {
"spec_version": "…",
"parse_confirmed": true,
"style_bindings": { "token/name": "figma-style-or-variable-id" },
"root": { "…": "layout_frame / instance / compose / text / unmatched tree" }
},
"confidence": { "min": 0.71, "avg": 0.88, "flag_count": 3, "formula_version": "cf@0.2" },
"artifact_urls": {
"result": "s3://…-result.json",
"spec": "https://…presigned…-spec.json" // spec が S3 にスピルした場合にのみ存在(presign 済み)
}
},
"error": null
}
spec スピル時、data.spec はインラインで省略されることがあり、data.artifact_urls.spec がプラグインの辿る presign 済み URL を運びます。結果アーティファクトはこの presign 経路(またはバックエンド自身のロール)を介してのみ読み込み可能です。
2. GET /internal/wf2des/{wf2des_id}/parse
結果ドキュメントの parse ブロックとイミュータブルな parse.json アーティファクト — awaiting_confirm の プレビュー サーフェス — を返します。プラグインはデザイナーが confirm または reject する前に、これから roles / intent / memo influences をプレビューします。
| プロパティ | 値 |
|---|---|
| Method / Path | GET /internal/wf2des/{wf2des_id}/parse |
| 認証 | セッショントークン または X-AI-Service-Token(read) |
| Path params | wf2des_id — 実行 id(design_generation_result._id) |
| Query params | なし |
| Request body | なし |
| DocDB read | design_generation_result.find_one({_id, organization_id, project_id}) → parse ブロック + artifact_urls.parse |
| S3 効果 | イミュータブルな parse.json(artifact_urls.parse)を presign する — この実行が使った正式な parse。プレビューは この アーティファクトを読み、上書き可能な wireframe キャッシュドキュメントは決して読まない |
| PG / SQS | なし |
Response body — parse ブロック + presign 済みアーティファクトポインタ:
{
"ok": true,
"data": {
"wf2des_id": "8f14e4...",
"parse": {
"confirmed": false,
"confirmed_by": null,
"confirmed_at": null,
"rejected": null, // reject が書き込まれると構造化 {reason_code, note} になる(ルート 4)
"memo_influences": [
{ "memo_node_id": "…", "text": "…" } // TEXT スナップショット済み — wireframe 再 parse を生き延びる
]
},
"artifact_urls": {
"parse": "https://…presigned…-parse.json" // 使用されたイミュータブルな完全 WFNode ツリー + memo(roles / intent)
}
},
"error": null
}
プラグインは presign 済みの parse.json を取得し、プレビュー用に完全な parse 済み WFNode ツリー(roles、ノードごとの intent)をレンダリングします。
3. GET /internal/projects/{project_id}/figma-files
project_figma_file からプロジェクトの登録済み Figma ファイルをリストします。プラグインが org/project + ファイル解決に、また component_sweep が(バックエンド/サービストークン経由で)巡回をスコープするために使います。
| プロパティ | 値 |
|---|---|
| Method / Path | GET /internal/projects/{project_id}/figma-files |
| 認証 | セッショントークン または X-AI-Service-Token(read) |
| Path params | project_id — integer、> 0 |
| Query params | なし(path でプロジェクトスコープ) |
| Request body | なし |
| DocDB read | project_figma_file.find({organization_id, project_id}) |
| S3 効果 | なし |
| PG / SQS | なし |
Response body — 登録済みファイル(role、config_url、components_synced_at):
{
"ok": true,
"data": {
"project_id": 3,
"items": [
{
"figma_file_key": "hDDA9BNori9OTXSClduXqR",
"role": "working", // working | library
"config_url": "s3://…/1/3/wf2des/config.json",
"components_synced_at": "2026-07-06T09:30:00Z"
}
]
},
"error": null
}
role は working | library のいずれかです。sweep 管轄のフィールド(style_captures、sweep_marker、sweep_error)はワーカー内部のものであり、プラグイン向けのリスト形状には含まれません。
ライトルート
detail が先、flag が後。 ルート 4〜6 は
design_generation_resultの detail サブドキュメントをまずここに書き、その後プラグインはwf2desPG 行を反転する対応の バックエンド フラグエンドポイントを呼び出します。wf2des-apiは決して PostgreSQL に書き込みません。ルート 7 はバックエンドパートナーを持たない直接書き込みです。
4. POST /internal/wf2des/{wf2des_id}/reject
結果ドキュメントの parse.rejected — awaiting_confirm チェックポイントにおけるデザイナーの構造化された parse 却下 — を書き込みます。reject は失敗では ありません(wf2des status '3' rejected にマップされ、'2' failed ではありません)。
| プロパティ | 値 |
|---|---|
| Method / Path | POST /internal/wf2des/{wf2des_id}/reject |
| 認証 | セッショントークン のみ(write、プロジェクトスコープ) |
| Path params | wf2des_id — 実行 id(design_generation_result._id) |
| Request body | { reason_code, note } |
| DocDB write | design_generation_result.parse.rejected = { reason_code, note } をセット(organization_id + project_id でスコープ) |
| S3 / PG / SQS | S3 なし、PG なし、SQS なし |
| Detail-first パートナー | この書き込みの後、プラグインは バックエンドの confirm エンドポイント を呼び出し、wf2des 行を status '3' rejected に反転する |
Request body — reason_code は wrong_roles | wrong_memos | wrong_sections | other のいずれか:
{
"reason_code": "wrong_roles", // wrong_roles | wrong_memos | wrong_sections | other
"note": "The CTA row was parsed as a header."
}
書き込まれた parse.rejected は、ルート 2 が返す rejected 値になります。wf2des の status '3' 反転は 別個の バックエンド呼び出しです。wf2des-api は detail を記録するだけです。
5. POST /internal/wf2des/{wf2des_id}/placement
結果ドキュメントの placement — プラグインが spec からネイティブ Figma ノードを縫合した後のマテリアライズ記録 — を書き込みます。配置されたノードと、materializer のレイヤーごとの fallback/error レポートを記録します。
| プロパティ | 値 |
|---|---|
| Method / Path | POST /internal/wf2des/{wf2des_id}/placement |
| 認証 | セッショントークン のみ(write、プロジェクトスコープ) |
| Path params | wf2des_id — 実行 id(design_generation_result._id) |
| Request body | { placed_node_id, materialized_at, materializer_report[] } |
| DocDB write | design_generation_result.placement をセット(プラグインが書き込むフィールド。ワーカーは assemble 時にすでに placement.design_area を書き込み済み) |
| S3 / PG / SQS | S3 なし、PG なし、SQS なし |
| Detail-first パートナー | この書き込みの後、プラグインは バックエンドの placement エンドポイント を呼び出し、wf2des 行の materialized_at を反転する |
Request body — materializer_report[].event は name_fallback | ordinal_fallback | build_error | font_fallback | prop_rejected | unmatched | preserved のいずれか:
{
"placed_node_id": "40002029:37050",
"materialized_at": "2026-07-06T09:41:12Z",
"materializer_report": [
{
"layer_path": "root/section-1/cta",
"event": "name_fallback", // 上記 7 値のいずれか
"detail": "component_key not found; matched by name"
}
]
}
placement ブロックは、ワーカーが書き込んだ placement.design_area(解決された DESIGN エリアの矩形)と共存します。行の materialized_at 反転は 別個の バックエンド呼び出しです。
6. POST /internal/wf2des/{wf2des_id}/feedback
結果ドキュメントの feedback — マテリアライズ後のデザイナーのシグナル(採用された結果、または修正された結果)— を、変更されたノードと diff ポインタと共に書き込みます。
| プロパティ | 値 |
|---|---|
| Method / Path | POST /internal/wf2des/{wf2des_id}/feedback |
| 認証 | セッショントークン のみ(write、プロジェクトスコープ) |
| Path params | wf2des_id — 実行 id(design_generation_result._id) |
| Request body | { status, changed_nodes[], diff_url, at, by } |
| DocDB write | design_generation_result.feedback をセット |
| S3 / PG / SQS | S3 なし、PG なし、SQS なし — diff_url はワーカー/プラグインが生成した diff アーティファクトへのポインタであり、ここでは書き込まれない |
| Detail-first パートナー | この書き込みの後、プラグインは バックエンドの feedback エンドポイント を呼び出し、wf2des 行の feedback_status を反転する |
Request body — status は fixed | adopted のいずれか:
{
"status": "adopted", // fixed | adopted
"changed_nodes": ["root/section-1/cta", "root/section-2/hero"],
"diff_url": "s3://…/1/3/wf2des/8f14e4…-…-feedback.json",
"at": "2026-07-06T10:05:00Z",
"by": "designer@example.com"
}
changed_nodes は layer_path 値です(spec の layer_path アドレッシングと一致)。行の feedback_status 反転は 別個の バックエンド呼び出しです。
7. POST / PUT /internal/projects/{project_id}/figma-files
project_figma_file エントリ — ファイルの role と config_url — を登録(POST)または更新(PUT)します。これは バックエンドのフラグパートナーを持たない wf2des-api への 直接 書き込みです: project_figma_file は DocumentDB コレクションであって PG フラグサーフェスではありません。
| プロパティ | 値 |
|---|---|
| Method / Path | POST / PUT /internal/projects/{project_id}/figma-files |
| 認証 | セッショントークン のみ(write、プロジェクトスコープ) |
| Path params | project_id — integer、> 0 |
| Request body | { figma_file_key, role, config_url } |
| DocDB write | project_figma_file ドキュメントを upsert — UNIQUE(organization_id, project_id, figma_file_key)。POST は insert(既存キーでは 409)。PUT は既存ドキュメントの role / config_url を更新 |
| S3 / PG / SQS | S3 なし、PG なし、SQS なし |
| Detail-first パートナー | なし — これは直接書き込みであり、detail-then-flag のペアではない |
Request body — role は working | library のいずれか:
{
"figma_file_key": "hDDA9BNori9OTXSClduXqR",
"role": "working", // working | library
"config_url": "s3://…/1/3/wf2des/config.json"
}
プラグインの role / config_url 書き込みは、component_sweep がスタンプする sweep 管轄のフィールド(style_captures、components_synced_at、sweep_marker、sweep_error)とフィールドレベルで分離しています — 決して衝突しません。UNIQUE(organization_id, project_id, figma_file_key) で衝突する POST は 409 を返します。既存の登録を更新するには PUT を使ってください。
エラーハンドリング
エラーは姉妹リード API と同じエンベロープ({ ok, data, error }、error: { code, message })を使います。
| シナリオ | HTTP ステータス | エラーコード |
|---|---|---|
X-AI-Service-Token の欠落 / 不正 かつ 有効なセッショントークンなし |
401 | UNAUTHORIZED |
未知の wf2des_id または project_id(該当ドキュメントなし) |
404 | NOT_FOUND |
誤ったプロジェクトスコープ — トークンの {org_id, project_id} が path のスコープと一致しない、または不正/期限切れのセッショントークン |
403 | FORBIDDEN |
| ライトルートで使われたサービストークン(read スコープのトークンによる書き込み試行) | 403 | FORBIDDEN |
UNIQUE(organization_id, project_id, figma_file_key) で衝突する POST figma-file |
409 | CONFLICT |
不正な path/query/body(不正な reason_code / event / status / role enum、不正な形式の body) |
400 | BAD_REQUEST |
| DocumentDB / S3 の接続またはクエリエラー | 500 | INTERNAL_ERROR |
補足:
- 404(未知の id)。 欠落した
design_generation_result(wf2des_id)、または特定のファイルがアドレスされたのにproject_figma_fileドキュメントを持たないプロジェクトは、いずれもNOT_FOUNDを返します。空の figma-files LIST(ルート 3)は 404 では ありません —{ items: [] }を返します。 - 403(誤ったプロジェクトスコープ / 不正なセッショントークン)。 あらゆるルートが org/project スコープです。
{org_id, project_id}が要求されたproject_id/ ドキュメントのテナンシーと一致しないセッショントークン、期限切れトークン(exp経過)、またはライトルートで使われた read スコープのX-AI-Service-Token→FORBIDDEN。プロジェクト横断アクセスは決してデフォルトではありません。 - 409(figma-file の一意衝突)。 既存の
UNIQUE(organization_id, project_id, figma_file_key)にヒットするルート 7 への POST →CONFLICT。PUT が冪等な更新経路です。
エラー body:
{
"ok": false,
"data": null,
"error": { "code": "NOT_FOUND", "message": "design_generation_result not found" }
}
認証
2 つの認証情報が wf2des-api に到達します。ルートの種別がどちらを受け付けるかを決めます(ルートサマリー を参照)。
プラグインセッショントークン(read + write、プロジェクトスコープ)
Figma プラグインは {org_id, project_id, exp} を運ぶ セッション発行のデータプレーントークン を提示します:
- スコープ。 トークンは 1 つの
org_id+project_idに固定されます。あらゆるリクエストがそのスコープに対して検証されます。トークンのスコープ外の pathproject_id(またはドキュメントのテナンシー)→ 403。 - 期限。
expが強制されます。経過したexp→ 403(不正/期限切れのセッショントークン)。 - 権限。 read + write。これがライトルート(4〜7)で受け付けられる 唯一の 認証情報です。
バックエンド / MCP サービストークン(read のみ)
バックエンドと MCP は共有 X-AI-Service-Token ヘッダーを提示し、定数時間比較で設定済みシークレットと照合されます(姉妹の mcp-api と同じ):
- 権限。 read のみ。org/project + ファイル解決と result/parse 取得のため、リードルート(1〜3)で受け付けられます。ライトルートでは 拒否 されます — サービストークンによる書き込み試行 → 403(
FORBIDDEN)。 - それを必要とするルートでの欠落 / 不一致トークンで、有効なセッショントークンも存在しない場合 → 401(
UNAUTHORIZED)。
wf2des-api が決して保持しないもの。 PostgreSQL 認証情報も SQS 送信権限も持ちません。wf2des 行のフラグは、各 detail 書き込みの後にプラグインが呼び出すバックエンドエンドポイントによって反転されます。AI 管轄の wf2des-events キューはバックエンドの送信専用権限によってのみ供給されます。wf2des-api は DocumentDB + S3 のみです。
関連
- AI Read API (mcp-api) I/O 定義 — 同じ
internal-apiアプリ内の姉妹となる内部 HTTP リード API(バックエンド MCP v2 → DocumentDBdesign/code)。 - AI WF2Des I/O 定義 — これらのルートが読み(一部は書き込む)
design_generation_result、project_figma_fileドキュメントを 生成する ワーカー。正確なブロック形状の出所。