AI Code2WF — システムワークフロー
この文書はCode2WF MVPの計画を説明します。Page captureはこのflowより前にPage Importで実行します。
ワークフロー1: 生成をトリガー
sequenceDiagram
participant P as Figma plugin
participant B as Backend
participant PG as PostgreSQL
participant Q as Code2WF SQS
P->>B: POST pageImportId + Figma fields
B->>PG: 完了済みPage Importを検証
B->>PG: INSERT code2wf (status 0, attempt 1)
B->>PG: 不変Page Import resultを解決
B->>Q: result URL/hash/capture hashを送信
B-->>P: 201 processing row
- Pluginが
pageImportId、figmaFileKey、screenId、任意のplacementTargetを送信します。 - BackendがWrite accessを確認し、同じorganization/project内の完了済みかつ未削除のPage Importを読みます。
- BackendがUUIDv7を生成し、既存
wf2des_statusenumを使うstatus = "0"、attempt = 1の最小code2wf行をinsertします。 - 不変normalized manifestを1回readして検証し、その正確なbytesからresult URL、result hash、capture hashを1つのpin setとして導出します。
- それらの正確なsource値をSQSへ送り、行を返します。
code2wf 行が保持するsource参照は page_import_id のみです。source manifest、hash、name、viewport、dispatch nonceはcopyしません。Manifest bytesがmissing/corruptならSQS dispatch前に失敗し、このreadはPostgreSQL/S3 transactionを主張しません。
有効なtriggerごとに新しいbackend生成rowとworker jobを作成します。Insert後にSQS dispatchが失敗した場合、backendは (id, attempt=1, status="0") でそのprocessing行をfailedへ変更します。別のtriggerは別のrowを作成し、failed行は再dispatchしません。
ワークフロー2: インポート済みページを変換
sequenceDiagram
participant Q as Code2WF SQS
participant W as Code2WF worker
participant S as S3
participant B as Backend webhook
participant PG as PostgreSQL
Q->>W: attempt 1 + 正確なPage Import result
W->>S: Sourceをread/hash検証
W->>W: 決定的な既存schema node tree
W->>W: 決定的なannotation text node
W->>S: Conditional PUT spec、次にterminal manifest
W->>B: succeeded + result_manifest_url
B->>PG: CAS id + attempt + processing status
Workerは変換前にtenant identity、Page Import ID、source hash、capture hash、S3 prefixを検証します。元ページを開かず、PostgreSQL/DocumentDBへ接続しません。
Structural transformとannotation wordingは決定的です。Controlとannotationは既存 layout_frame / text nodeを使い、unsupported mediaは既存の可視 unmatched placeholderを使います。Annotation専用modelやnode schemaは追加しません。
Workerはcreate-only conditional writeでclient向けresult artifactを先に、terminal manifestを最後に書きます。ResultはWF2Desと同じouter job_id、attempt、tenant、screen、status、generated_at 名を使い、Code2WFのPage Import pinは inputs に置きます。Manifestは row_effects.code2wf を持ち、webhookは result_manifest_url で参照し、backendはrow effect内側の result.json URLを保存します。SQS重複deliveryでは次の通りです。
- 既存pairが同じjob/sourceに対して有効ならmanifest URLを再利用し、同じterminal eventを再送する。
- 既存objectが無効または異なるlineageならfail closedする。
- 既存resultを上書きしない。
Webhookは (id, attempt=1, status="0") が一致するときだけPostgreSQLを更新します。Terminal row以降の重複または競合eventはno-opです。SQS/webhook nonceはtransport metadataであり、永続product stateでもrow compare-and-setの一部でもありません。
ワークフロー3: 完了済みworkを検出
sequenceDiagram
participant P as Figma plugin
participant B as Backend
participant PG as PostgreSQL
participant S as S3
loop Offset-zero pageがemptyまたはprogress不能になるまで
P->>B: List status=1, materialized=false, figmaFileKey=current, limit=50, offset=0
B->>PG: Remaining unmaterialized rowを再query
B-->>P: 最大50 rows + total
loop 返された各rowをsequentialに処理
P->>B: GET result
B->>S: row.result_url specをread/validate
B-->>P: 検証済みCode2WF result artifact
P->>P: artifact.specを共有builderでmaterialize
P->>B: POST placement (placedNodeId)
end
end
生成に開いたpluginは不要ですが、discoveryには対象Figma file内の認証済みplugin sessionが必要です。Code2WFは、current fileで materialized=false のcompleted rowを limit=50&offset=0 で繰り返しlistするopen-time flowを追加します。返された各rowではmaterialize前にimmutable resultを取得し、sequentialにbuildして成功placementを記録し、pageがemptyになるまでoffset zeroを再queryします。Placement後にfiltered setが縮むため、offsetを進めるとrowをskipし得ることから、offset zeroを再読込します。Session内でjob IDをdedupeし、どのrowも完了できない場合はbounded no-progress guardでloopを停止します。Result/build failureはunmaterializedのままuserへ通知し、他rowの処理を妨げません。Session期限切れならloginを促してdiscoveryをretryし、別fileのrowはfetch/materializeしません。
各rowについてpluginは完全なimmutable result artifactを取得し、検証済みの artifact.spec を共有materializerへ渡します。placementTarget は既存WF2Des columnとmeaningを維持します。Current pageのnodeとして解決できれば、そのnodeのabsolute page rectangleを共有placeRootへ渡し、generated rootをrectangleのx/yに配置します。Targetはreference専用でresize、replace、deleteしません。Missing/stale/nested cross-page/other-page targetは既存のviewport-center fallbackを使います。Code2WFが追加するのはdiscovery/API wiringであり、異なるplacement modelではありません。
MVPにはcross-session claimがありません。2つの認証済みplugin sessionが、どちらかがplacementを記録する前に同じrowをdiscoverする可能性は既知の制約です。各sessionは既存job-ID stamp/indexとrebuild-and-swap behaviorを使い、placementも冪等ですが、MVPはatomicなcross-session materializationを主張しません。
Server claim、lease、retry count、materialization statusはありません。検出はWF2Desと同じ行レベルの materialized_at 規約を使用します。
ワークフロー4: マテリアライズとplacement記録
sequenceDiagram
participant P as Figma plugin
participant F as Figma file
participant B as Backend Code2WF API
participant PG as PostgreSQL
P->>F: Code2WF staging rootをbuild
P->>B: POST placement (placedNodeId)
B->>PG: SET materialized_at
B-->>P: 200 existing/new timestamp
計画中のCode2WF client wiringは既存 DesignSpecModel を共有WF2Des planner/materializerとrebuild-and-swap contractへ渡します。共有builderはすでに定義済みのtext fallbackとlayout sizing fieldを適用するよう拡張し、Code2WF専用node caseやrendererは追加しません。Root key wf2des はJSON {jobId, specVersion, role: "root"} を保存し、document key wf2des_index はjob IDからroot IDへmapし、MVPは既存 wf2des · 1.0 root labelを受け入れます。Caught build failureではstaging rootを破棄しますが、abruptなplugin shutdown後のcleanupはintegration testで検証が必要です。後続sessionではimmutable resultから再buildし、replacement成功後にのみprior stamped rootを置き換えます。
画面完成後にpluginは生成画面の placedNodeId を送信します。Backendはcompleted rowを要求し、WF2Desと同じ行レベルplacement規約に従って materialized_at を設定します。
materialized_at が既に設定済みの場合、placement再送は既存timestampを含む 200 を返し、再登録や再stampを行いません。
Failureの所有者
| Failure | 所有者と挙動 |
|---|---|
| Page Import未完了またはscope外 | backendがtriggerを拒否 |
| SQS dispatch failure | backendがattempt 1をfailedへ変更 |
| Source/hash/schema invalid | workerがfailedを通知 |
| Unsupported visual/media content | workerが既存の可視 unmatched placeholderを出力してcompleted |
| 一時的S3/webhook failure | SQS retry。workerはPostgreSQLへ書かない |
| Caught plugin build failure | staging rootを破棄し、後続sessionでimmutable resultから再build |
| Abrupt plugin shutdown | rowはunmaterializedのまま。Reopen時に再buildし、integration testで識別不能なpartial unstamped nodeが残るかを記録する。reuse-safeな仕組みができるまでautomatic cleanupは主張しない |
| Placement request/backend failure | materialized_at はnullのまま。pluginが後でretry可能 |
失敗した生成は新しいjob IDで再実行します。