AI Des2Code - I/O 定義
このページは apps/des2code/ の公式 I/O contract である。field、shape、status、failure mode を変更する場合は、実装 merge 前にこのページと テストケース設計 を更新する。
概要
flowchart LR
api[guinness-backend] -->|INSERT/UPDATE des2code status pending| RDB[(PostgreSQL)]
api -->|SendMessage| Q[(SQS des2code)]
Q --> L[AI Des2Code worker]
L -->|find_one _id=design_id| D[(DocumentDB design)]
L -->|hybrid retrieval + rerank| C[(DocumentDB code)]
L -->|PutObject result/failed artifact| S3[(S3 backend AI bucket)]
L -->|POST /v1/webhooks/ai-status| api
api -->|persist latest des2code result + artifact ref| RDB
L -->|structured logs| Logs[(CloudWatch / logs)]
| 項目 | 値 |
|---|---|
| トリガー | des2code queue 上の SQS record |
| 読み取り | DocumentDB design、DocumentDB code |
| 書き込み | S3 result artifact + guinness-backend への Webhook POST |
| RDB 書き込み | worker はなし。backend が Webhook 受信後に PostgreSQL へ書く |
| Webhook | POST /v1/webhooks/ai-status への success/failure 通知が必須 |
| LLM 呼び出し | 任意の top-candidate rerank のみ。デフォルト無効 |
空の matchedCodes |
空の matchedCodes array を持つ success |
| 結果保持 | timestamp 付き S3 artifact は 30 日 lifecycle。backend PostgreSQL は latest status/result と artifact reference を保持 |
入力
SQS メッセージ
Lambda は標準 AWS SQS event を受け取る。Records[*].body には次の field を持つ JSON string が入る。
{
"Records": [
{
"messageId": "0192a3b4-c5d6-7e8f-9a0b-1c2d3e4f5a6b",
"body": "{\"design_id\":\"42_hDDA9BNori9OTXSClduXqR_40002029:37033\",\"project_id\":42,\"organization_id\":1}"
}
]
}
| フィールド | 型 | 必須 | 検証 | 備考 |
|---|---|---|---|---|
design_id |
string | Yes | min_length=1 |
既存の design._id と一致する必要がある |
project_id |
integer | Yes | gt=0 |
vector search と backend status の scope |
organization_id |
integer | Yes | gt=0 |
design validation、vector search、backend status の tenant scope |
| Body unwrap は他 worker と同じ utility に従う。raw payload、SQS-in-SQS、API Gateway proxy shape を、flat object になるまで受け付ける。 |
DocumentDB design 読み取り
| 項目 | 値 |
|---|---|
| コレクション | DESIGN_TABLE_NAME、default design |
| 操作 | find_one({"_id": design_id}) |
| document 未存在 | failure path。ID が分かる場合は failed webhook を送り、再送出 |
| scope 不一致 | design.project_id または design.organization_id が SQS message と不一致なら failure path |
読み取る field:
| フィールド | 型 | 用途 |
|---|---|---|
_id |
string | design identity |
project_id |
integer | consistency / search scope |
organization_id |
integer | consistency / tenant scope |
visual.vector_embedding |
float[512] | visual vector-search query |
semantics.vector_embedding |
float[512] | semantic vector-search query |
structural.vector_embedding |
float[512] | structural/context retrieval query |
query_terms |
string[] | 決定的 term-overlap reranking |
figma_node |
object | reranking 用 Figma node evidence |
localized_regions |
object|null | 任意の localized visual/layout evidence |
DocumentDB code 取得
worker は CODE_TABLE_NAME(default code)に対して hybrid retrieval を実行する。
| 項目 | 値 |
|---|---|
| 検索回数 | index がある場合、record ごとに visual + semantic + context の 3 回 |
| 検索スコープ | organization_id + project_id |
| 候補プール | CANDIDATE_POOL_SIZE、default 50 |
| 最終上限 | MAX_MATCHES、default 10 |
numCandidates |
max(80, CANDIDATE_POOL_SIZE) |
| 類似度 | Cosine |
| 検索結果が空 | empty matchedCodes の success |
matched code document から project する field:
| フィールド | 型 | 用途 |
|---|---|---|
_id |
string | match identity。codeId として返却 |
name |
string | null | name として返却 |
source_code |
string | null | sourceCode として返却 |
css_code |
string | null | cssCode として返却 |
semantics.metadata.words |
string[] | semanticValue として返却 |
visual.metadata.image_url |
string | null | 将来の UI/API 用に保持可能 |
code_context |
object|null | 決定的 reranking evidence |
context.vector_embedding |
float[512]|null | context retrieval vector |
$meta score |
float | visual、semantic、context similarity の元 score |
実行時設定
| 環境変数 | 型 | デフォルト | 検証 | 用途 |
|---|---|---|---|---|
MAX_MATCHES |
integer | 10 |
gt=0 |
最終出力 cap |
CANDIDATE_POOL_SIZE |
integer | 50 |
gte=MAX_MATCHES |
reranking 前の retrieval pool |
VISUAL_SIMILARITY_WEIGHT |
float | 0.15 |
ge=0 |
visual evidence の retrieval score weight |
SEMANTIC_SIMILARITY_WEIGHT |
float | 0.35 |
ge=0 |
semantic evidence の retrieval score weight |
STRUCTURAL_SIMILARITY_WEIGHT |
float | 0.20 |
ge=0 |
structural/context evidence の retrieval score weight |
RERANK_SIGNAL_WEIGHT |
float | 0.30 |
ge=0 |
決定的 rerank evidence weight |
DES2CODE_LLM_RERANK_ENABLED |
boolean | false |
boolean | 任意の top-candidate LLM rerank を有効化 |
DES2CODE_LLM_RERANK_TOP_N |
integer | 10 |
gt=0 |
LLM 有効時に送る候補数 |
RESULT_BUCKET |
string | dev-guinness-backend |
min_length=1 |
result artifact の S3 bucket |
DES2CODE_RESULT_TTL_DAYS |
integer | 30 |
gt=0 |
expiresAt metadata と lifecycle expectation |
WEBHOOK_BASE_URL |
string | required | URL | backend webhook URL。通常 /v1/webhooks/ai-status で終わる |
WEBHOOK_API_KEY |
string | required | non-empty | service-to-service auth として X-API-Key で送る |
少なくとも 1 つの retrieval または rerank weight は 0 より大きい必要がある。
最終 score:
最終 similarity は純粋な vector similarity ではなく rank score である。欠けている signal は boost せず、side-specific field は null のままにする。
処理コントラクト
- SQS body を unwrap / validate する。
design_idでdesigndocument を取得する。- design document の scope が SQS
organization_id/project_idと一致することを検証する。 - vector と index が存在する場合、visual、semantic、structural/context retrieval を実行する。
code._idで candidate pool に merge する。design.query_terms、Figma node evidence、semantic words、code_context、import relation、family diversity、component-level compatibility、localized visual/layout evidence から決定的 rerank signal を計算する。- retrieval と決定的 signal から final rank score を計算する。
DES2CODE_LLM_RERANK_ENABLED=trueの場合、上位DES2CODE_LLM_RERANK_TOP_N候補と圧縮 evidence のみ LLM に渡す。strict structured output を必須にする。- final rank score で sort し、score/evidence field を付与して
MAX_MATCHESで cap する。 - success payload を build する。
- timestamp 付き S3 result artifact を 1 件書き込む。
- result と artifact metadata を含む success webhook を backend へ POST する。
des2code.completedを log する。
ソースコード生成はしない。生成用 image download はしない。DocumentDB des2code document は書かない。
出力
内部成功 payload
process_record() はテストとローカルスクリプト向けにこの shape を返す。Lambda handler は通常の SQS partial-batch-failure response を返す。
{
"type": "des2code",
"recordId": "42_hDDA9BNori9OTXSClduXqR_40002029:37033",
"projectId": 42,
"organizationId": 1,
"status": "success",
"result": {
"matchedCodeCount": 2,
"matchedCodes": [
{
"codeId": "0192a3b4-c5d6-4e8f-9a0b-1c2d3e4f5a6b",
"name": "Button Primary",
"semanticValue": ["button", "primary", "cta"],
"similarity": 0.92,
"visualSimilarity": 0.95,
"semanticSimilarity": 0.89,
"structuralSimilarity": 0.77,
"scoreBreakdown": {
"retrieval": 0.61,
"termOverlap": 0.12,
"rarityBoost": 0.05,
"familyDiversity": 0.04,
"relationBoost": 0.03,
"visualLayout": 0.07
},
"matchedTerms": ["button_primary", "submit", "login"],
"matchedDesignNodes": ["40002029:37101"],
"matchedCodeContext": {
"family": "button",
"variant": "primary",
"exports": ["Button"],
"referencedComponents": ["button"]
},
"llmEvidence": null,
"sourceCode": "export function Button() { ... }",
"cssCode": null
},
{
"codeId": "1192a3b4-c5d6-4e8f-9a0b-1c2d3e4f5a6c",
"name": "Input Field",
"semanticValue": ["input", "form"],
"similarity": 0.87,
"visualSimilarity": null,
"semanticSimilarity": 0.87,
"structuralSimilarity": 0.62,
"scoreBreakdown": {
"retrieval": 0.54,
"termOverlap": 0.14,
"rarityBoost": 0.03,
"familyDiversity": 0.03,
"relationBoost": 0.02,
"visualLayout": 0.04
},
"matchedTerms": ["input", "form"],
"matchedDesignNodes": ["40002029:37080"],
"matchedCodeContext": {
"family": "input",
"variant": null,
"exports": ["TextInput"],
"referencedComponents": ["input"]
},
"llmEvidence": null,
"sourceCode": "export function TextInput() { ... }",
"cssCode": ".input { ... }"
}
]
}
}
| フィールド | 型 | 備考 |
|---|---|---|
type |
string | 常に "des2code" |
recordId |
string | SQS design_id の echo |
projectId |
integer | SQS project_id の echo |
organizationId |
integer | SQS organization_id の echo |
status |
string | "success" |
result.matchedCodeCount |
integer | final cap 後の件数 |
result.matchedCodes |
object[] | ranked matches |
result.matchedCodes[].codeId |
string | code._id |
result.matchedCodes[].name |
string | null | code.name |
result.matchedCodes[].semanticValue |
string[] | code.semantics.metadata.words |
result.matchedCodes[].similarity |
float | final rank score。range は weight 設定に依存 |
result.matchedCodes[].visualSimilarity |
float | null | raw visual score、0.0 から 1.0 |
result.matchedCodes[].semanticSimilarity |
float | null | raw semantic score、0.0 から 1.0 |
result.matchedCodes[].structuralSimilarity |
float | null | raw structural/context score、0.0 から 1.0 |
result.matchedCodes[].scoreBreakdown |
object | retrieval と決定的 rerank score component |
result.matchedCodes[].matchedTerms |
string[] | code evidence と一致した design query term |
result.matchedCodes[].matchedDesignNodes |
string[] | match を裏付ける Figma node id または region id |
result.matchedCodes[].matchedCodeContext |
object|null | match を裏付ける code context evidence |
result.matchedCodes[].llmEvidence |
object|null | LLM rerank 有効時の任意 reason/confidence |
result.matchedCodes[].sourceCode |
string | null | code.source_code |
result.matchedCodes[].cssCode |
string | null | code.css_code |
Score は rank score。percent ではなく、worker 側で丸めない。
S3 result artifact の保存
Des2Code は immutable result artifact を S3 に書き込む。backend は Webhook 経由で artifact metadata を受け取り、latest artifact reference を PostgreSQL に保存する。
| 項目 | 値 |
|---|---|
| バケット | RESULT_BUCKET、default dev-guinness-backend |
| キー | {organization_id}/{project_id}/des2code/{url_encoded_design_id}-{YYYYMMDDTHHMMSSffffffZ}-result.json |
| failure キー | {organization_id}/{project_id}/des2code/{url_encoded_design_id}-{YYYYMMDDTHHMMSSffffffZ}-failed.json |
| Content-Type | application/json |
| object tag | des2code_result=true |
| 暗号化 | bucket default SSE-S3 |
| 保持期間 | des2code_result=true tag に scoped した 30 日 lifecycle |
success artifact の shape:
{
"type": "des2code",
"recordId": "42_hDDA9BNori9OTXSClduXqR_40002029:37033",
"projectId": 42,
"organizationId": 1,
"status": "success",
"generatedAt": "2026-06-28T00:00:00Z",
"expiresAt": "2026-07-28T00:00:00Z",
"result": {
"matchedCodeCount": 2,
"matchedCodes": []
}
}
Webhook - 成功
{
"type": "des2code",
"recordId": "42_hDDA9BNori9OTXSClduXqR_40002029:37033",
"projectId": 42,
"organizationId": 1,
"status": "success",
"artifact": {
"bucket": "dev-guinness-backend",
"key": "1/42/des2code/42_hDDA9BNori9OTXSClduXqR_40002029%3A37033-20260628T000000000000Z-result.json",
"contentType": "application/json",
"expiresAt": "2026-07-28T00:00:00Z"
},
"result": {
"matchedCodeCount": 2,
"matchedCodes": []
}
}
backend は PostgreSQL に最新 status/result と artifact reference を保存し、backend REST API と MCP v2 から公開する。
Webhook - 失敗
design_id、project_id、organization_id が判明した後に処理が失敗した場合、worker は original exception を再送出する前に failed webhook を送る。
{
"type": "des2code",
"recordId": "42_hDDA9BNori9OTXSClduXqR_40002029:37033",
"projectId": 42,
"organizationId": 1,
"status": "failed",
"artifact": {
"bucket": "dev-guinness-backend",
"key": "1/42/des2code/42_hDDA9BNori9OTXSClduXqR_40002029%3A37033-20260628T000000000000Z-failed.json",
"contentType": "application/json",
"expiresAt": "2026-07-28T00:00:00Z"
},
"error": {
"message": "Design not found"
}
}
Webhook delivery failure は processing failure として扱い、SQS retry で status/result を後続配送できるように再送出する。
エラーハンドリング
| シナリオ | 挙動 |
|---|---|
| SQS event envelope が不正 | raise。ID 不明なら webhook なし |
| Body を unwrap / parse できない | raise。ID 不明なら webhook なし |
| Pydantic validation 失敗 | raise。ID を安全に復元できる場合のみ failed webhook |
| design document 未存在 | failed webhook、log、再送出 |
| design scope 不一致 | failed webhook、log、再送出 |
| vector search が match を返さない | empty matchedCodes の success webhook、log、ack |
| S3 write error | log して SQS retry のため再送出 |
| Webhook POST failure | log して再送出し SQS retry |
| DocumentDB read error | 可能なら failed webhook、log、再送出 |
| batch 内に複数 record | 各 record を試行し、失敗は SQS batch item failures で返す |
冪等性
SQS delivery は at least once。成功した各 attempt は timestamp 付き S3 artifact を新規に書く。backend webhook handler は (type, recordId) に対して idempotent であり、design の最新 result と artifact reference を保存する。同じ SQS message の再処理は、その design_id に対する backend の最新 Des2Code result を置き換える。
フィールドリファレンス
| ソース | Worker での用途 | Webhook / 返却名 |
|---|---|---|
SQS design_id |
design lookup key | recordId |
SQS project_id |
search scope / design-scope validation / S3 prefix | projectId |
SQS organization_id |
tenant scope / design-scope validation / S3 prefix | organizationId |
design.visual.vector_embedding |
visual search query | emit しない |
design.semantics.vector_embedding |
semantic search query | emit しない |
design.structural.vector_embedding |
structural/context retrieval query | emit しない |
design.query_terms |
決定的 rerank input | 一致時は matchedTerms |
design.figma_node, design.localized_regions |
node/layout evidence | 一致時は matchedDesignNodes |
code._id |
match key | codeId |
code.name |
match label | name |
code.semantics.metadata.words |
semantic descriptor | semanticValue |
code.context.vector_embedding |
context retrieval target | emit しない |
code.code_context |
rerank evidence | matchedCodeContext |
code.source_code |
code implementation | sourceCode |
code.css_code |
code styling | cssCode |
| retrieval / rerank score | ranking | similarity, visualSimilarity, semanticSimilarity, structuralSimilarity, scoreBreakdown |