コンテンツにスキップ

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
  1. Pluginが pageImportId、figmaFileKey、screenId、任意の placementTarget を送信します。
  2. BackendがWrite accessを確認し、同じorganization/project内の完了済みかつ未削除のPage Importを読みます。
  3. BackendがUUIDv7を生成し、既存 wf2des_status enumを使う status = "0"、attempt = 1 の最小 code2wf 行をinsertします。
  4. 不変normalized manifestを1回readして検証し、その正確なbytesからresult URL、result hash、capture hashを1つのpin setとして導出します。
  5. それらの正確な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で再実行します。


関連ドキュメント